CLI runs on Node 20+: npx storebound (bunx keeps working)
- cli/lib/rt.ts: the runtime layer on node: modules (spawn / spawnSync with Bun's defaults, exit codes and "Executable not found", which with PATHEXT, sleep, serve, Glob, hasher, gunzip, stdin, SQLite, packageRoot, config imports with a type-stripping fallback for Node 20); every Bun.* use in cli/ goes through it - tools/gen-embedded.ts -> cli/lib/embedded.ts: templates/, cli/shots/*.html and Play's Data safety form embedded (replaces Bun text imports; the bundle and the compiled sidecar carry them), checked fresh by bun run ci - package.json: bin dist/storebound.mjs (Node ESM bundle, tools/build-node.ts, prepack), engines node >=20 - bun run ci: node bundle + node smoke (real node: --version, help, check same as Bun, scan, release plan --help, init, MCP handshake + tool call); Forgejo CI sets up Node 20; tests/node-compat.test.ts guards cli/ - install writes npx MCP commands when run with Node; bin/storebound falls back to Node - docs: npx storebound init (Node 20+) or bunx storebound init
This commit is contained in:
parent
614c32bcba
commit
36a8bf9625
73 changed files with 1195 additions and 251 deletions
|
|
@ -21,6 +21,7 @@ import { STORAGE_READ_SCOPE } from './lib/google-auth';
|
|||
import { done, log, printJson, warn } from './lib/log';
|
||||
import { pct, textTable } from './lib/table';
|
||||
import { googleClient } from './play/google';
|
||||
import * as rt from './lib/rt';
|
||||
|
||||
const TAG = 'analytics';
|
||||
const day = (d: Date) => d.toISOString().slice(0, 10);
|
||||
|
|
@ -42,7 +43,7 @@ async function reportRows(c: Asc, report: J, start: string, tag: string): Promis
|
|||
const r = await fetch(seg.attributes.url);
|
||||
if (!r.ok) throw new Error(`segment ${seg.id}: HTTP ${r.status}`);
|
||||
const gz = new Uint8Array(await r.arrayBuffer());
|
||||
const raw = gz[0] === 0x1f && gz[1] === 0x8b ? Bun.gunzipSync(gz) : gz;
|
||||
const raw = gz[0] === 0x1f && gz[1] === 0x8b ? rt.gunzipSync(gz) : gz;
|
||||
// Apple documents an md5 checksum per segment without saying of which bytes: accept the file or its content.
|
||||
if (seg.attributes.checksum && !checksumOk(gz, seg.attributes.checksum) && !checksumOk(raw, seg.attributes.checksum)) throw new Error(`segment ${seg.id}: md5 checksum mismatch`);
|
||||
rows.push(...parseReport(decodeText(raw)));
|
||||
|
|
@ -145,7 +146,7 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
const series = mergeSeries(snaps);
|
||||
const first = [series.apple[0]?.date, series.play[0]?.date].filter(Boolean).sort()[0] ?? snaps[0]!.window.start;
|
||||
const paths = a.list('paths').length ? a.list('paths') : ['store', 'storebound.config.ts', ...(config.shots?.copy ? [config.shots.copy] : [])];
|
||||
const g = Bun.spawnSync(['git', 'log', `--since=${first}`, '--date=short', '--format=%x1e%h%x1f%ad%x1f%s', '--name-only', '--', ...paths], { cwd: root, stdout: 'pipe', stderr: 'pipe' });
|
||||
const g = rt.spawnSync(['git', 'log', `--since=${first}`, '--date=short', '--format=%x1e%h%x1f%ad%x1f%s', '--name-only', '--', ...paths], { cwd: root, stdout: 'pipe', stderr: 'pipe' });
|
||||
if (g.exitCode !== 0) throw new Error(`git log: ${g.stderr.toString().trim()}`);
|
||||
const events = parseGitLog(g.stdout.toString()).reverse();
|
||||
log(TAG, `${snaps.length} snapshot(s), ${series.apple.length} App Store day(s), ${series.play.length} Play day(s), ${events.length} store change(s) since ${first}`);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue