tina4-nodejs 3.13.141 → 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.
- package/CLAUDE.md +2 -2
- package/package.json +1 -1
- package/packages/cli/dist/bin.js +438 -453
- package/packages/cli/src/bin.ts +4 -14
- package/packages/cli/src/commands/build.ts +2 -18
- package/packages/cli/src/commands/generate.ts +2 -22
- package/packages/cli/src/commands/lint.ts +3 -13
- package/packages/cli/src/commands/migrate.ts +2 -6
- package/packages/cli/src/commands/migrateRollback.ts +2 -6
- package/packages/cli/src/commands/migrateStatus.ts +2 -6
- package/packages/cli/src/commands/queue.ts +2 -30
- package/packages/cli/src/util.ts +90 -0
- package/packages/core/dist/index.js +215 -184
- package/packages/core/gallery/queue/src/lib/queueDb.ts +11 -0
- package/packages/core/gallery/queue/src/routes/api/gallery/queue/consume/post.ts +2 -5
- package/packages/core/gallery/queue/src/routes/api/gallery/queue/fail/post.ts +2 -5
- package/packages/core/src/devAdmin.ts +3 -12
- package/packages/core/src/dispatchPipeline.ts +2 -18
- package/packages/core/src/etag.ts +24 -0
- package/packages/core/src/feedback.ts +2 -11
- package/packages/core/src/session.ts +22 -66
- package/packages/core/src/sessionHandlers/respSessionHandler.ts +94 -0
- package/packages/core/src/sessionHandlers/valkeyHandler.ts +22 -73
- package/packages/core/src/static.ts +1 -13
- package/packages/core/src/upstreamResponse.ts +31 -0
- package/packages/core/src/websocket.ts +48 -7
- package/packages/orm/dist/index.js +215 -184
- package/packages/orm/src/graph/adapters/bolt.ts +8 -29
- package/packages/orm/src/graph/adapters/rowMapping.ts +57 -0
- package/packages/orm/src/graph/adapters/ultipa.ts +8 -30
- package/types/cli/src/util.d.ts +28 -0
- package/types/core/src/etag.d.ts +9 -0
- package/types/core/src/session.d.ts +2 -19
- package/types/core/src/sessionHandlers/respSessionHandler.d.ts +52 -0
- package/types/core/src/sessionHandlers/valkeyHandler.d.ts +2 -26
- package/types/core/src/upstreamResponse.d.ts +10 -0
- package/types/core/src/websocket.d.ts +21 -0
- package/types/orm/src/graph/adapters/rowMapping.d.ts +26 -0
package/packages/cli/src/bin.ts
CHANGED
|
@@ -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
|
|
24
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|