@steve31415/baselib 3.39.0 → 3.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,12 +3,14 @@
3
3
  // ~/migration/research/deploy-procedure-design.md). All logic lives in
4
4
  // ../deploy/deploy.ts; configuration is the app's deploy.config.json.
5
5
  //
6
- // process.exit (not exitCode) so an in-flight Cloud Build child cannot keep
7
- // a failed deploy's process alive; the server-side build finishes on its own
8
- // and is reused by the next attempt.
6
+ // An explicit exit (not exitCode) so an in-flight Cloud Build child cannot
7
+ // keep a failed deploy's process alive; the server-side build finishes on its
8
+ // own and is reused by the next attempt. exitWhenFlushed lets the output
9
+ // already written reach a piped reader (Coder captures it) first.
10
+ import { exitWhenFlushed } from '../ops/cli.js';
9
11
  import { realRunner } from '../deploy/exec.js';
10
12
  import { runDeploy } from '../deploy/deploy.js';
11
- process.exit(await runDeploy({
13
+ await exitWhenFlushed(await runDeploy({
12
14
  repoRoot: process.cwd(),
13
15
  runner: realRunner,
14
16
  argv: process.argv.slice(2),
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // `pw-logs` — Axiom log query (OPERATIONS.md "Investigating production
3
3
  // state"). All logic lives in ../ops/logs.ts.
4
+ import { exitWhenFlushed } from '../ops/cli.js';
4
5
  import { runLogs } from '../ops/logs.js';
5
- process.exit(await runLogs({ argv: process.argv.slice(2), cwd: process.cwd() }));
6
+ await exitWhenFlushed(await runLogs({ argv: process.argv.slice(2), cwd: process.cwd() }));
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  // `pw-rollback` — one-command traffic move to a previously released build.
3
3
  // All logic lives in ../deploy/rollback.ts.
4
+ import { exitWhenFlushed } from '../ops/cli.js';
4
5
  import { realRunner } from '../deploy/exec.js';
5
6
  import { runRollback } from '../deploy/rollback.js';
6
- process.exit(await runRollback({
7
+ await exitWhenFlushed(await runRollback({
7
8
  repoRoot: process.cwd(),
8
9
  runner: realRunner,
9
10
  argv: process.argv.slice(2),
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // `pw-sql` — read-only production SQL (OPERATIONS.md "Investigating
3
3
  // production state"). All logic lives in ../ops/sql.ts.
4
+ import { exitWhenFlushed } from '../ops/cli.js';
4
5
  import { runSql } from '../ops/sql.js';
5
- process.exit(await runSql({ argv: process.argv.slice(2), cwd: process.cwd() }));
6
+ await exitWhenFlushed(await runSql({ argv: process.argv.slice(2), cwd: process.cwd() }));
@@ -2,6 +2,7 @@
2
2
  // baselib's `npm run deploy` — release the checked-out version (tag push +
3
3
  // wait for the registry; the tag-triggered workflow does the actual
4
4
  // publish). All logic lives in ../release.ts.
5
+ import { exitWhenFlushed } from '../ops/cli.js';
5
6
  import { realRunner } from '../deploy/exec.js';
6
7
  import { release } from '../release.js';
7
8
  try {
@@ -12,5 +13,5 @@ try {
12
13
  }
13
14
  catch (e) {
14
15
  console.error(e instanceof Error ? e.message : String(e));
15
- process.exit(1);
16
+ await exitWhenFlushed(1);
16
17
  }
package/dist/ops/cli.d.ts CHANGED
@@ -13,4 +13,16 @@ type Parsed<T extends Options> = ReturnType<typeof parseArgs<{
13
13
  export declare function parseCli<T extends Options>(argv: string[], options: T, usage: string, io: CliIo): Parsed<T> | {
14
14
  code: number;
15
15
  };
16
+ /**
17
+ * `process.exit(code)` once stdout and stderr have handed everything written
18
+ * to them to the OS. A plain process.exit discards what a pipe has not yet
19
+ * taken: Node writes to a pipe asynchronously once its buffer (64 KiB on
20
+ * Linux) is full, so `pw-logs … | jq` lost all but the first 64 KiB, with
21
+ * exit status 0 (2026-10-26). Files and terminals are written synchronously,
22
+ * which is why redirecting to a file never showed it. Still an explicit exit,
23
+ * not `exitCode`: nothing else the bin started (a connection pool, a Cloud
24
+ * Build child) may keep it alive. A reader that goes away (`| head`) ends the
25
+ * wait instead of crashing the bin on EPIPE.
26
+ */
27
+ export declare function exitWhenFlushed(code: number, streams?: NodeJS.WritableStream[], exit?: (code: number) => void): Promise<void>;
16
28
  export {};
package/dist/ops/cli.js CHANGED
@@ -25,3 +25,29 @@ export function parseCli(argv, options, usage, io) {
25
25
  }
26
26
  return parsed;
27
27
  }
28
+ /**
29
+ * `process.exit(code)` once stdout and stderr have handed everything written
30
+ * to them to the OS. A plain process.exit discards what a pipe has not yet
31
+ * taken: Node writes to a pipe asynchronously once its buffer (64 KiB on
32
+ * Linux) is full, so `pw-logs … | jq` lost all but the first 64 KiB, with
33
+ * exit status 0 (2026-10-26). Files and terminals are written synchronously,
34
+ * which is why redirecting to a file never showed it. Still an explicit exit,
35
+ * not `exitCode`: nothing else the bin started (a connection pool, a Cloud
36
+ * Build child) may keep it alive. A reader that goes away (`| head`) ends the
37
+ * wait instead of crashing the bin on EPIPE.
38
+ */
39
+ export async function exitWhenFlushed(code, streams = [process.stdout, process.stderr], exit = (c) => process.exit(c)) {
40
+ await Promise.all(streams.map(flushed));
41
+ exit(code);
42
+ }
43
+ function flushed(stream) {
44
+ return new Promise((resolve) => {
45
+ // A broken pipe is reported to the write callback and then, a tick
46
+ // later, as an 'error' event, which would crash the process if nothing
47
+ // listened — so the listener stays until the exit.
48
+ stream.on('error', () => resolve());
49
+ // Writes complete in order, so an empty write's callback runs only after
50
+ // everything written before it has gone out.
51
+ stream.write('', () => resolve());
52
+ });
53
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steve31415/baselib",
3
- "version": "3.39.0",
3
+ "version": "3.39.1",
4
4
  "description": "Plasticine new-world shared platform library: logging, auth, service-to-service auth, db, HTTP, sync, app updates",
5
5
  "type": "module",
6
6
  "license": "MIT",