mirror of
https://github.com/bulwarkmail/native.git
synced 2026-10-31 08:06:36 +00:00
CI: - .github/workflows/release-android.yml builds APK on release publish and via workflow_dispatch, attaches it to the release. - android/app/build.gradle: optional release signingConfig driven by Gradle properties (ANDROID_KEYSTORE_BASE64 secret etc.); falls back to the debug keystore when no secrets are set. - .gitignore: untrack /android so the runner can build directly; ignore build outputs (build/, .cxx/), Metro/Expo dev logs, scratch. Track android/ sources including BulwarkFcmPackage.kt and google-services.json (Firebase Android keys are public per Google's docs and intended to ship in the APK). JS sync: push notifications + background task, vacation responder (api + store), contact activity component, search utilities, settings polish, calendar/contacts/email store and screen tweaks. Tooling: scripts/poll-reload.mjs — Windows polling-watcher that hits Metro /reload on file change (workaround for unreliable fs.watch without Watchman).
49 lines
1.4 KiB
JavaScript
49 lines
1.4 KiB
JavaScript
import { readdir, stat } from 'node:fs/promises';
|
|
import { watchFile } from 'node:fs';
|
|
import { join, extname } from 'node:path';
|
|
|
|
const ROOTS = ['src', 'App.tsx', 'index.ts', 'app.json'];
|
|
const EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.json']);
|
|
const INTERVAL = 500;
|
|
const METRO = 'http://localhost:8081/reload';
|
|
|
|
async function* walk(p) {
|
|
const s = await stat(p).catch(() => null);
|
|
if (!s) return;
|
|
if (s.isFile()) { yield p; return; }
|
|
for (const e of await readdir(p, { withFileTypes: true })) {
|
|
const f = join(p, e.name);
|
|
if (e.isDirectory()) {
|
|
if (e.name === 'node_modules' || e.name.startsWith('.')) continue;
|
|
yield* walk(f);
|
|
} else if (e.isFile() && EXTS.has(extname(e.name))) {
|
|
yield f;
|
|
}
|
|
}
|
|
}
|
|
|
|
let pending = false;
|
|
async function reload(file) {
|
|
if (pending) return;
|
|
pending = true;
|
|
try {
|
|
console.log(`change: ${file}`);
|
|
const r = await fetch(METRO, { method: 'GET' });
|
|
console.log(`reload -> ${r.status}`);
|
|
} catch (e) {
|
|
console.log(`reload failed: ${e.message}`);
|
|
}
|
|
setTimeout(() => { pending = false; }, 500);
|
|
}
|
|
|
|
const files = [];
|
|
for (const r of ROOTS) {
|
|
for await (const f of walk(r)) files.push(f);
|
|
}
|
|
console.log(`watching ${files.length} files (poll ${INTERVAL}ms)`);
|
|
for (const f of files) {
|
|
watchFile(f, { interval: INTERVAL }, (curr, prev) => {
|
|
if (curr.mtimeMs !== prev.mtimeMs) reload(f);
|
|
});
|
|
}
|