tina4-nodejs 3.13.140 → 3.13.142

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.
Files changed (38) hide show
  1. package/CLAUDE.md +2 -2
  2. package/package.json +1 -1
  3. package/packages/cli/dist/bin.js +438 -453
  4. package/packages/cli/src/bin.ts +4 -14
  5. package/packages/cli/src/commands/build.ts +2 -18
  6. package/packages/cli/src/commands/generate.ts +2 -22
  7. package/packages/cli/src/commands/lint.ts +3 -13
  8. package/packages/cli/src/commands/migrate.ts +2 -6
  9. package/packages/cli/src/commands/migrateRollback.ts +2 -6
  10. package/packages/cli/src/commands/migrateStatus.ts +2 -6
  11. package/packages/cli/src/commands/queue.ts +2 -30
  12. package/packages/cli/src/util.ts +90 -0
  13. package/packages/core/dist/index.js +215 -184
  14. package/packages/core/gallery/queue/src/lib/queueDb.ts +11 -0
  15. package/packages/core/gallery/queue/src/routes/api/gallery/queue/consume/post.ts +2 -5
  16. package/packages/core/gallery/queue/src/routes/api/gallery/queue/fail/post.ts +2 -5
  17. package/packages/core/src/devAdmin.ts +3 -12
  18. package/packages/core/src/dispatchPipeline.ts +2 -18
  19. package/packages/core/src/etag.ts +24 -0
  20. package/packages/core/src/feedback.ts +2 -11
  21. package/packages/core/src/session.ts +22 -66
  22. package/packages/core/src/sessionHandlers/respSessionHandler.ts +94 -0
  23. package/packages/core/src/sessionHandlers/valkeyHandler.ts +22 -73
  24. package/packages/core/src/static.ts +1 -13
  25. package/packages/core/src/upstreamResponse.ts +31 -0
  26. package/packages/core/src/websocket.ts +48 -7
  27. package/packages/orm/dist/index.js +215 -184
  28. package/packages/orm/src/graph/adapters/bolt.ts +8 -29
  29. package/packages/orm/src/graph/adapters/rowMapping.ts +57 -0
  30. package/packages/orm/src/graph/adapters/ultipa.ts +8 -30
  31. package/types/cli/src/util.d.ts +28 -0
  32. package/types/core/src/etag.d.ts +9 -0
  33. package/types/core/src/session.d.ts +2 -19
  34. package/types/core/src/sessionHandlers/respSessionHandler.d.ts +52 -0
  35. package/types/core/src/sessionHandlers/valkeyHandler.d.ts +2 -26
  36. package/types/core/src/upstreamResponse.d.ts +10 -0
  37. package/types/core/src/websocket.d.ts +21 -0
  38. package/types/orm/src/graph/adapters/rowMapping.d.ts +26 -0
@@ -20,8 +20,9 @@ import { runSeeds } from "./commands/seed.js";
20
20
  import { queueCommand, QUEUE_SUBCOMMAND_NAMES } from "./commands/queue.js";
21
21
  import { buildImage } from "./commands/build.js";
22
22
  import { spawnSync } from "node:child_process";
23
- import { existsSync, readFileSync, statSync } from "node:fs";
24
- import { delimiter, dirname, join } from "node:path";
23
+ import { existsSync, readFileSync } from "node:fs";
24
+ import { dirname, join } from "node:path";
25
+ import { findOnPath } from "./util.js";
25
26
  import { fileURLToPath, pathToFileURL } from "node:url";
26
27
 
27
28
  // ── Version (cheap, side-effect-free) ───────────────────────────────
@@ -496,18 +497,7 @@ function findClient(): string | null {
496
497
  const names = windows
497
498
  ? [`${CLIENT_BINARY}.exe`, `${CLIENT_BINARY}.cmd`, `${CLIENT_BINARY}.bat`]
498
499
  : [CLIENT_BINARY];
499
- for (const dir of (process.env.PATH ?? "").split(delimiter)) {
500
- if (!dir) continue;
501
- for (const name of names) {
502
- const candidate = join(dir, name);
503
- try {
504
- if (statSync(candidate).isFile()) return candidate;
505
- } catch {
506
- // not there — keep looking
507
- }
508
- }
509
- }
510
- return null;
500
+ return findOnPath(names);
511
501
  }
512
502
 
513
503
  /**
@@ -24,27 +24,11 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
24
24
  import { accessSync, constants, existsSync, statSync } from "node:fs";
25
25
  import { basename, delimiter, join } from "node:path";
26
26
  import { spawnSync } from "node:child_process";
27
+ import { parseFlags as parseFlagsShared } from "../util.js";
27
28
 
28
29
  /** Parse --key value / bare --flag (build only needs --tag and --file values). */
29
30
  function parseFlags(args: string[]): Record<string, string | boolean> {
30
- const flags: Record<string, string | boolean> = {};
31
- let i = 0;
32
- while (i < args.length) {
33
- const arg = args[i];
34
- if (arg.startsWith("--")) {
35
- const key = arg.slice(2);
36
- if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
37
- flags[key] = args[i + 1];
38
- i += 2;
39
- } else {
40
- flags[key] = true;
41
- i += 1;
42
- }
43
- } else {
44
- i += 1;
45
- }
46
- }
47
- return flags;
31
+ return parseFlagsShared(args).flags;
48
32
  }
49
33
 
50
34
  /**
@@ -42,6 +42,7 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
42
42
  */
43
43
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
44
44
  import { join, relative, resolve, sep } from "node:path";
45
+ import { parseFlags } from "../util.js";
45
46
 
46
47
  // ── Field type mapping ──────────────────────────────────────────────
47
48
  const FIELD_TYPE_MAP: Record<string, { orm: string; sql: string; defaultVal: string }> = {
@@ -558,28 +559,7 @@ export function parseCliArgs(args: string[]): { flags: Record<string, string | b
558
559
  "json", "dry-run",
559
560
  ]);
560
561
 
561
- const flags: Record<string, string | boolean> = {};
562
- const positional: string[] = [];
563
- let i = 0;
564
- while (i < args.length) {
565
- if (args[i].startsWith("--")) {
566
- const key = args[i].slice(2);
567
- if (booleanFlags.has(key)) {
568
- flags[key] = true;
569
- i += 1;
570
- } else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
571
- flags[key] = args[i + 1];
572
- i += 2;
573
- } else {
574
- flags[key] = true;
575
- i += 1;
576
- }
577
- } else {
578
- positional.push(args[i]);
579
- i += 1;
580
- }
581
- }
582
- return { flags, positional };
562
+ return parseFlags(args, booleanFlags);
583
563
  }
584
564
 
585
565
  /**
@@ -43,7 +43,8 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
43
43
  */
44
44
  import { existsSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
45
45
  import { createRequire } from "node:module";
46
- import { delimiter, dirname, join, relative } from "node:path";
46
+ import { dirname, join, relative } from "node:path";
47
+ import { findOnPath } from "../util.js";
47
48
  import { spawnSync } from "node:child_process";
48
49
 
49
50
  // Source extensions we count as lintable app code. `.d.ts` declaration files are
@@ -217,18 +218,7 @@ function hasPackage(cwd: string, pkg: string): boolean {
217
218
  function resolveNpm(): string | null {
218
219
  const windows = process.platform === "win32";
219
220
  const names = windows ? ["npm.cmd", "npm.exe", "npm"] : ["npm"];
220
- for (const dir of (process.env.PATH ?? "").split(delimiter)) {
221
- if (!dir) continue;
222
- for (const name of names) {
223
- const candidate = join(dir, name);
224
- try {
225
- if (statSync(candidate).isFile()) return candidate;
226
- } catch {
227
- // not there — keep looking
228
- }
229
- }
230
- }
231
- return null;
221
+ return findOnPath(names);
232
222
  }
233
223
 
234
224
  interface EslintSetup {
@@ -29,6 +29,7 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
29
29
  import { existsSync } from "node:fs";
30
30
  import { resolve } from "node:path";
31
31
  import { loadEnv } from "../../../core/src/dotenv.js";
32
+ import { initDatabaseOrExit } from "../util.js";
32
33
 
33
34
  export async function runMigrations(migrationDir?: string): Promise<void> {
34
35
  // Load .env before initialising the DB so DATABASE_URL/TINA4_DATABASE_URL
@@ -59,12 +60,7 @@ export async function runMigrations(migrationDir?: string): Promise<void> {
59
60
  // async — MUST be awaited, otherwise setAdapter() has not run by the time
60
61
  // migrate() asks for the adapter and the whole CLI crashes with
61
62
  // "No database adapter configured."
62
- try {
63
- await initDatabase();
64
- } catch (err) {
65
- console.error(` Error initialising database: ${err instanceof Error ? err.message : String(err)}`);
66
- process.exit(1);
67
- }
63
+ await initDatabaseOrExit(initDatabase);
68
64
 
69
65
  const result = await migrate(undefined, { migrationsDir: dir });
70
66
 
@@ -18,6 +18,7 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
18
18
  */
19
19
  import { resolve } from "node:path";
20
20
  import { loadEnv } from "../../../core/src/dotenv.js";
21
+ import { initDatabaseOrExit } from "../util.js";
21
22
 
22
23
  export async function migrateRollback(migrationDir?: string): Promise<void> {
23
24
  // .env must load before initDatabase() — otherwise DATABASE_URL from the
@@ -45,12 +46,7 @@ export async function migrateRollback(migrationDir?: string): Promise<void> {
45
46
  // Ensure database is initialised — MUST await; initDatabase() is async
46
47
  // and calls setAdapter() inside the promise. Without await, the next call
47
48
  // to getAdapter() throws "No database adapter configured."
48
- try {
49
- await initDatabase();
50
- } catch (err) {
51
- console.error(` Error initialising database: ${err instanceof Error ? err.message : String(err)}`);
52
- process.exit(1);
53
- }
49
+ await initDatabaseOrExit(initDatabase);
54
50
 
55
51
  await ensureMigrationTable();
56
52
 
@@ -15,6 +15,7 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
15
15
  */
16
16
  import { resolve } from "node:path";
17
17
  import { loadEnv } from "../../../core/src/dotenv.js";
18
+ import { initDatabaseOrExit } from "../util.js";
18
19
 
19
20
  export async function migrateStatus(migrationDir?: string): Promise<void> {
20
21
  // .env must load before initDatabase() so the project's DATABASE_URL is seen.
@@ -38,12 +39,7 @@ export async function migrateStatus(migrationDir?: string): Promise<void> {
38
39
 
39
40
  // Ensure database is initialised — MUST await; initDatabase() is async
40
41
  // and calls setAdapter() inside. Without await, getAdapter() throws.
41
- try {
42
- await initDatabase();
43
- } catch (err) {
44
- console.error(` Error initialising database: ${err instanceof Error ? err.message : String(err)}`);
45
- process.exit(1);
46
- }
42
+ await initDatabaseOrExit(initDatabase);
47
43
 
48
44
  ensureMigrationTable();
49
45
 
@@ -28,6 +28,7 @@ import { pathToFileURL } from "node:url";
28
28
  import { loadEnv } from "../../../core/src/dotenv.js";
29
29
  import { Queue } from "../../../core/src/queue.js";
30
30
  import type { QueueJob } from "../../../core/src/job.js";
31
+ import { parseFlags as parseFlagsShared } from "../util.js";
31
32
 
32
33
  // ── Flag parsing ─────────────────────────────────────────────────────
33
34
  //
@@ -36,36 +37,7 @@ import type { QueueJob } from "../../../core/src/job.js";
36
37
 
37
38
  const BOOLEAN_FLAGS = new Set(["once", "json"]);
38
39
 
39
- interface ParsedFlags {
40
- flags: Record<string, string | boolean>;
41
- positional: string[];
42
- }
43
-
44
- function parseFlags(args: string[]): ParsedFlags {
45
- const flags: Record<string, string | boolean> = {};
46
- const positional: string[] = [];
47
- let i = 0;
48
- while (i < args.length) {
49
- const arg = args[i];
50
- if (arg.startsWith("--")) {
51
- const key = arg.slice(2);
52
- if (BOOLEAN_FLAGS.has(key)) {
53
- flags[key] = true;
54
- i += 1;
55
- } else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
56
- flags[key] = args[i + 1];
57
- i += 2;
58
- } else {
59
- flags[key] = true;
60
- i += 1;
61
- }
62
- } else {
63
- positional.push(arg);
64
- i += 1;
65
- }
66
- }
67
- return { flags, positional };
68
- }
40
+ const parseFlags = (args: string[]) => parseFlagsShared(args, BOOLEAN_FLAGS);
69
41
 
70
42
  /** A per-job handler declared by a consumer module (receives the job payload). */
71
43
  export type QueueHandler = (payload: unknown) => unknown | Promise<unknown>;
@@ -0,0 +1,90 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
9
+ /**
10
+ * Shared CLI helpers — argument parsing, PATH lookup, and database bootstrap.
11
+ * Kept zero-dependency (node stdlib only) so the CLI entry path stays light.
12
+ */
13
+ import { delimiter, join } from "node:path";
14
+ import { statSync } from "node:fs";
15
+
16
+ /** Flags and positional arguments split out of a command's argv slice. */
17
+ export interface ParsedFlags {
18
+ flags: Record<string, string | boolean>;
19
+ positional: string[];
20
+ }
21
+
22
+ /**
23
+ * Parse `--key value` and bare `--flag` arguments into flags plus positionals.
24
+ *
25
+ * A name listed in `booleanFlags` never consumes the next token; every other
26
+ * `--key` takes the following token as its value unless that token is itself a
27
+ * `--flag` (or the argv ends), in which case the key is a bare boolean.
28
+ */
29
+ export function parseFlags(args: string[], booleanFlags?: ReadonlySet<string>): ParsedFlags {
30
+ const flags: Record<string, string | boolean> = {};
31
+ const positional: string[] = [];
32
+ let i = 0;
33
+ while (i < args.length) {
34
+ const arg = args[i];
35
+ if (arg.startsWith("--")) {
36
+ const key = arg.slice(2);
37
+ if (booleanFlags?.has(key)) {
38
+ flags[key] = true;
39
+ i += 1;
40
+ } else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
41
+ flags[key] = args[i + 1];
42
+ i += 2;
43
+ } else {
44
+ flags[key] = true;
45
+ i += 1;
46
+ }
47
+ } else {
48
+ positional.push(arg);
49
+ i += 1;
50
+ }
51
+ }
52
+ return { flags, positional };
53
+ }
54
+
55
+ /**
56
+ * Absolute path of the first of `names` found on PATH, or null.
57
+ *
58
+ * Scans PATH directories directly (no `which` shell-out) so it behaves the same
59
+ * on every platform and honours a deliberately emptied PATH. Callers pass the
60
+ * platform-specific candidate names (e.g. `["npm.cmd", "npm.exe", "npm"]`).
61
+ */
62
+ export function findOnPath(names: string[]): string | null {
63
+ for (const dir of (process.env.PATH ?? "").split(delimiter)) {
64
+ if (!dir) continue;
65
+ for (const name of names) {
66
+ const candidate = join(dir, name);
67
+ try {
68
+ if (statSync(candidate).isFile()) return candidate;
69
+ } catch {
70
+ // not there — keep looking
71
+ }
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+
77
+ /**
78
+ * Await the ORM's async `initDatabase()` and exit(1) with a clear message on
79
+ * failure. The await matters: initDatabase() calls setAdapter() inside the
80
+ * promise, so without it the next getAdapter() throws "No database adapter
81
+ * configured." Shared by the migrate, rollback, and status commands.
82
+ */
83
+ export async function initDatabaseOrExit(initDatabase: () => Promise<unknown>): Promise<void> {
84
+ try {
85
+ await initDatabase();
86
+ } catch (err) {
87
+ console.error(` Error initialising database: ${err instanceof Error ? err.message : String(err)}`);
88
+ process.exit(1);
89
+ }
90
+ }