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.
- 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/dist/bin.js
CHANGED
|
@@ -1221,8 +1221,8 @@ function hashPassword(password, salt, iterations = 26e4) {
|
|
|
1221
1221
|
}
|
|
1222
1222
|
function checkPassword(password, hash) {
|
|
1223
1223
|
try {
|
|
1224
|
-
const
|
|
1225
|
-
const parts = hash.split(
|
|
1224
|
+
const delimiter4 = hash.includes("$") ? "$" : ":";
|
|
1225
|
+
const parts = hash.split(delimiter4);
|
|
1226
1226
|
if (parts.length !== 4 || parts[0] !== "pbkdf2_sha256") return false;
|
|
1227
1227
|
const iterations = parseInt(parts[1], 10);
|
|
1228
1228
|
const salt = parts[2];
|
|
@@ -8980,7 +8980,7 @@ async function removeMigrationRecord(name) {
|
|
|
8980
8980
|
[name]
|
|
8981
8981
|
);
|
|
8982
8982
|
}
|
|
8983
|
-
async function rollback(migrationsDir,
|
|
8983
|
+
async function rollback(migrationsDir, delimiter4) {
|
|
8984
8984
|
if (migrationsDir instanceof Map) {
|
|
8985
8985
|
const downFunctions = migrationsDir;
|
|
8986
8986
|
const migrations2 = await getLastBatchMigrations();
|
|
@@ -8999,7 +8999,7 @@ async function rollback(migrationsDir, delimiter5) {
|
|
|
8999
8999
|
return rolledBack2;
|
|
9000
9000
|
}
|
|
9001
9001
|
const dir = resolve4(migrationsDir ?? "migrations");
|
|
9002
|
-
const delim =
|
|
9002
|
+
const delim = delimiter4 ?? ";";
|
|
9003
9003
|
const db = getAdapter();
|
|
9004
9004
|
const migrations = await getLastBatchMigrations();
|
|
9005
9005
|
const rolledBack = [];
|
|
@@ -9115,13 +9115,13 @@ function consumeSqlDelimiter(state) {
|
|
|
9115
9115
|
}
|
|
9116
9116
|
return true;
|
|
9117
9117
|
}
|
|
9118
|
-
function splitStatements(sql,
|
|
9118
|
+
function splitStatements(sql, delimiter4 = ";") {
|
|
9119
9119
|
const state = {
|
|
9120
9120
|
sql: normalizeQuotes(sql),
|
|
9121
9121
|
statements: [],
|
|
9122
9122
|
current: "",
|
|
9123
|
-
delimiter:
|
|
9124
|
-
dlen:
|
|
9123
|
+
delimiter: delimiter4,
|
|
9124
|
+
dlen: delimiter4.length,
|
|
9125
9125
|
i: 0,
|
|
9126
9126
|
inDollarBlock: false,
|
|
9127
9127
|
inSlashBlock: false
|
|
@@ -9160,7 +9160,7 @@ function warnUnprefixedMigrations(files) {
|
|
|
9160
9160
|
async function migrate(adapter, options) {
|
|
9161
9161
|
const db = adapter ?? getAdapter();
|
|
9162
9162
|
const dir = resolve4(options?.migrationsDir ?? "migrations");
|
|
9163
|
-
const
|
|
9163
|
+
const delimiter4 = options?.delimiter ?? ";";
|
|
9164
9164
|
const result = { applied: [], skipped: [], failed: [] };
|
|
9165
9165
|
if (!existsSync5(dir)) {
|
|
9166
9166
|
return result;
|
|
@@ -9203,7 +9203,7 @@ async function migrate(adapter, options) {
|
|
|
9203
9203
|
result.skipped.push(file);
|
|
9204
9204
|
continue;
|
|
9205
9205
|
}
|
|
9206
|
-
const statements = splitStatements(sqlContent,
|
|
9206
|
+
const statements = splitStatements(sqlContent, delimiter4);
|
|
9207
9207
|
try {
|
|
9208
9208
|
await adapterStartTransaction(db);
|
|
9209
9209
|
for (const stmt of statements) {
|
|
@@ -13696,6 +13696,36 @@ var init_shapes = __esm({
|
|
|
13696
13696
|
}
|
|
13697
13697
|
});
|
|
13698
13698
|
|
|
13699
|
+
// ../orm/src/graph/adapters/rowMapping.ts
|
|
13700
|
+
function errorMessage(exc) {
|
|
13701
|
+
if (exc instanceof Error) return exc.message;
|
|
13702
|
+
return String(exc);
|
|
13703
|
+
}
|
|
13704
|
+
function nodeFromRow(row) {
|
|
13705
|
+
if (row === null || row === void 0) return null;
|
|
13706
|
+
return new GraphNode(
|
|
13707
|
+
String(row.id),
|
|
13708
|
+
row.labels ?? [],
|
|
13709
|
+
row.props ?? {}
|
|
13710
|
+
);
|
|
13711
|
+
}
|
|
13712
|
+
function edgeFromRow(row) {
|
|
13713
|
+
if (row === null || row === void 0) return null;
|
|
13714
|
+
return new GraphEdge(
|
|
13715
|
+
String(row.id),
|
|
13716
|
+
String(row.type),
|
|
13717
|
+
String(row.f),
|
|
13718
|
+
String(row.t),
|
|
13719
|
+
row.props ?? {}
|
|
13720
|
+
);
|
|
13721
|
+
}
|
|
13722
|
+
var init_rowMapping = __esm({
|
|
13723
|
+
"../orm/src/graph/adapters/rowMapping.ts"() {
|
|
13724
|
+
"use strict";
|
|
13725
|
+
init_shapes();
|
|
13726
|
+
}
|
|
13727
|
+
});
|
|
13728
|
+
|
|
13699
13729
|
// ../orm/src/graph/connectTimeout.ts
|
|
13700
13730
|
function resolveGraphConnectTimeout() {
|
|
13701
13731
|
const raw = (process.env[GRAPH_CONNECT_TIMEOUT_VARIABLE] ?? "").trim();
|
|
@@ -13735,15 +13765,12 @@ function propClause(properties) {
|
|
|
13735
13765
|
for (const key of keys) params[`p_${key}`] = props[key];
|
|
13736
13766
|
return { clause: `{${pairs}}`, params };
|
|
13737
13767
|
}
|
|
13738
|
-
function errorMessage(exc) {
|
|
13739
|
-
if (exc instanceof Error) return exc.message;
|
|
13740
|
-
return String(exc);
|
|
13741
|
-
}
|
|
13742
13768
|
var DRIVER_PACKAGE, driver, UltipaClient, UltipaConnectError, UNBOUNDED_CONNECT_SECONDS, UltipaGraphAdapter;
|
|
13743
13769
|
var init_ultipa = __esm({
|
|
13744
13770
|
async "../orm/src/graph/adapters/ultipa.ts"() {
|
|
13745
13771
|
"use strict";
|
|
13746
13772
|
init_shapes();
|
|
13773
|
+
init_rowMapping();
|
|
13747
13774
|
init_errors();
|
|
13748
13775
|
init_connectTimeout2();
|
|
13749
13776
|
DRIVER_PACKAGE = "tina4-ultipa";
|
|
@@ -13801,12 +13828,7 @@ var init_ultipa = __esm({
|
|
|
13801
13828
|
}
|
|
13802
13829
|
// -- portable node/edge/traverse core (GQL) ----------------------------
|
|
13803
13830
|
nodeFromRow(row) {
|
|
13804
|
-
|
|
13805
|
-
return new GraphNode(
|
|
13806
|
-
String(row.id),
|
|
13807
|
-
row.labels ?? [],
|
|
13808
|
-
row.props ?? {}
|
|
13809
|
-
);
|
|
13831
|
+
return nodeFromRow(row);
|
|
13810
13832
|
}
|
|
13811
13833
|
async addNode(label, properties = null) {
|
|
13812
13834
|
const { clause, params } = propClause(properties);
|
|
@@ -13820,15 +13842,7 @@ var init_ultipa = __esm({
|
|
|
13820
13842
|
params.to_id = toId;
|
|
13821
13843
|
const gql = `MATCH (a), (b) WHERE id(a) = $from_id AND id(b) = $to_id INSERT (a)-[e:\`${type2}\` ${clause}]->(b) RETURN id(e) AS id, type(e) AS type, id(a) AS f, id(b) AS t, properties(e) AS props`;
|
|
13822
13844
|
const rows = (await this.run(gql, params, false)).dicts();
|
|
13823
|
-
|
|
13824
|
-
const row = rows[0];
|
|
13825
|
-
return new GraphEdge(
|
|
13826
|
-
String(row.id),
|
|
13827
|
-
String(row.type),
|
|
13828
|
-
String(row.f),
|
|
13829
|
-
String(row.t),
|
|
13830
|
-
row.props ?? {}
|
|
13831
|
-
);
|
|
13845
|
+
return edgeFromRow(rows[0]);
|
|
13832
13846
|
}
|
|
13833
13847
|
async getNode(nodeId) {
|
|
13834
13848
|
const gql = `MATCH (n) WHERE id(n) = $id RETURN id(n) AS id, labels(n) AS labels, properties(n) AS props`;
|
|
@@ -13893,10 +13907,6 @@ var bolt_exports = {};
|
|
|
13893
13907
|
__export(bolt_exports, {
|
|
13894
13908
|
BoltGraphAdapter: () => BoltGraphAdapter
|
|
13895
13909
|
});
|
|
13896
|
-
function errorMessage2(exc) {
|
|
13897
|
-
if (exc instanceof Error) return exc.message;
|
|
13898
|
-
return String(exc);
|
|
13899
|
-
}
|
|
13900
13910
|
function boltId(id) {
|
|
13901
13911
|
const value = Number(id);
|
|
13902
13912
|
return Number.isNaN(value) ? -1 : value;
|
|
@@ -13906,6 +13916,7 @@ var init_bolt = __esm({
|
|
|
13906
13916
|
async "../orm/src/graph/adapters/bolt.ts"() {
|
|
13907
13917
|
"use strict";
|
|
13908
13918
|
init_shapes();
|
|
13919
|
+
init_rowMapping();
|
|
13909
13920
|
init_errors();
|
|
13910
13921
|
init_connectTimeout2();
|
|
13911
13922
|
DRIVER_PACKAGE2 = "neo4j-driver";
|
|
@@ -13941,7 +13952,7 @@ var init_bolt = __esm({
|
|
|
13941
13952
|
const result = await session.run(cypher, params ?? {});
|
|
13942
13953
|
return result.records.map((record) => record.toObject());
|
|
13943
13954
|
} catch (exc) {
|
|
13944
|
-
this.lastError =
|
|
13955
|
+
this.lastError = errorMessage(exc);
|
|
13945
13956
|
const code = exc?.code ?? "";
|
|
13946
13957
|
const message = this.lastError.toLowerCase();
|
|
13947
13958
|
if (code === "ServiceUnavailable" || code === neo4j.error?.SERVICE_UNAVAILABLE || message.includes("timed out") || message.includes("timeout")) {
|
|
@@ -13965,12 +13976,7 @@ var init_bolt = __esm({
|
|
|
13965
13976
|
}
|
|
13966
13977
|
// -- portable node/edge/traverse core (Cypher) -------------------------
|
|
13967
13978
|
nodeFromRow(row) {
|
|
13968
|
-
|
|
13969
|
-
return new GraphNode(
|
|
13970
|
-
String(row.id),
|
|
13971
|
-
row.labels ?? [],
|
|
13972
|
-
row.props ?? {}
|
|
13973
|
-
);
|
|
13979
|
+
return nodeFromRow(row);
|
|
13974
13980
|
}
|
|
13975
13981
|
async addNode(label, properties = null) {
|
|
13976
13982
|
const cypher = `CREATE (n:\`${label}\` $props) RETURN id(n) AS id, labels(n) AS labels, properties(n) AS props`;
|
|
@@ -13984,15 +13990,7 @@ var init_bolt = __esm({
|
|
|
13984
13990
|
to_id: boltId(toId),
|
|
13985
13991
|
props: properties ?? {}
|
|
13986
13992
|
});
|
|
13987
|
-
|
|
13988
|
-
const row = rows[0];
|
|
13989
|
-
return new GraphEdge(
|
|
13990
|
-
String(row.id),
|
|
13991
|
-
String(row.type),
|
|
13992
|
-
String(row.f),
|
|
13993
|
-
String(row.t),
|
|
13994
|
-
row.props ?? {}
|
|
13995
|
-
);
|
|
13993
|
+
return edgeFromRow(rows[0]);
|
|
13996
13994
|
}
|
|
13997
13995
|
async getNode(nodeId) {
|
|
13998
13996
|
const cypher = `MATCH (n) WHERE id(n) = $id RETURN id(n) AS id, labels(n) AS labels, properties(n) AS props`;
|
|
@@ -14058,7 +14056,7 @@ function cleanProps(doc) {
|
|
|
14058
14056
|
}
|
|
14059
14057
|
return props;
|
|
14060
14058
|
}
|
|
14061
|
-
function
|
|
14059
|
+
function errorMessage2(exc) {
|
|
14062
14060
|
if (exc instanceof Error) return exc.message;
|
|
14063
14061
|
return String(exc);
|
|
14064
14062
|
}
|
|
@@ -14097,14 +14095,14 @@ var init_arango = __esm({
|
|
|
14097
14095
|
this.db = new ArangoDatabase(config);
|
|
14098
14096
|
}
|
|
14099
14097
|
connectOrError(exc) {
|
|
14100
|
-
const text =
|
|
14098
|
+
const text = errorMessage2(exc).toLowerCase();
|
|
14101
14099
|
if (text.includes("timed out") || text.includes("timeout") || text.includes("connection") || text.includes("econnrefused") || text.includes("etimedout") || text.includes("max retries")) {
|
|
14102
14100
|
return new GraphConnectTimeout(
|
|
14103
14101
|
`Graph connect to ${this.url.host}:${this.url.port} timed out (${GRAPH_CONNECT_TIMEOUT_VARIABLE}). Raise ${GRAPH_CONNECT_TIMEOUT_VARIABLE} if the server is simply slow, or set it to 0 to wait indefinitely.`,
|
|
14104
14102
|
exc
|
|
14105
14103
|
);
|
|
14106
14104
|
}
|
|
14107
|
-
return new GraphError(
|
|
14105
|
+
return new GraphError(errorMessage2(exc), exc);
|
|
14108
14106
|
}
|
|
14109
14107
|
async ensureCollections() {
|
|
14110
14108
|
if (this.ensured) return;
|
|
@@ -14115,7 +14113,7 @@ var init_arango = __esm({
|
|
|
14115
14113
|
if (!await edges.exists()) await this.db.createEdgeCollection(EDGE_COLLECTION);
|
|
14116
14114
|
this.ensured = true;
|
|
14117
14115
|
} catch (exc) {
|
|
14118
|
-
this.lastError =
|
|
14116
|
+
this.lastError = errorMessage2(exc);
|
|
14119
14117
|
throw this.connectOrError(exc);
|
|
14120
14118
|
}
|
|
14121
14119
|
}
|
|
@@ -14125,7 +14123,7 @@ var init_arango = __esm({
|
|
|
14125
14123
|
const cursor = await this.db.query({ query, bindVars: bind2 ?? {} });
|
|
14126
14124
|
return await cursor.all();
|
|
14127
14125
|
} catch (exc) {
|
|
14128
|
-
this.lastError =
|
|
14126
|
+
this.lastError = errorMessage2(exc);
|
|
14129
14127
|
throw this.connectOrError(exc);
|
|
14130
14128
|
}
|
|
14131
14129
|
}
|
|
@@ -21621,14 +21619,14 @@ function extractBoundary(contentType) {
|
|
|
21621
21619
|
function parseMultipart(body, boundary) {
|
|
21622
21620
|
const fields = {};
|
|
21623
21621
|
const files = {};
|
|
21624
|
-
const
|
|
21622
|
+
const delimiter4 = Buffer.from(`--${boundary}`);
|
|
21625
21623
|
const closeDelimiter = Buffer.from(`--${boundary}--`);
|
|
21626
21624
|
const crlf = Buffer.from("\r\n");
|
|
21627
21625
|
const doubleCrlf = Buffer.from("\r\n\r\n");
|
|
21628
21626
|
let offset = 0;
|
|
21629
|
-
const firstIdx = bufferIndexOf(body,
|
|
21627
|
+
const firstIdx = bufferIndexOf(body, delimiter4, offset);
|
|
21630
21628
|
if (firstIdx === -1) return { fields, files };
|
|
21631
|
-
offset = firstIdx +
|
|
21629
|
+
offset = firstIdx + delimiter4.length;
|
|
21632
21630
|
if (body[offset] === 13 && body[offset + 1] === 10) {
|
|
21633
21631
|
offset += 2;
|
|
21634
21632
|
}
|
|
@@ -21637,7 +21635,7 @@ function parseMultipart(body, boundary) {
|
|
|
21637
21635
|
if (headersEnd === -1) break;
|
|
21638
21636
|
const headersStr = body.subarray(offset, headersEnd).toString("utf-8");
|
|
21639
21637
|
offset = headersEnd + doubleCrlf.length;
|
|
21640
|
-
const nextDelimIdx = bufferIndexOf(body,
|
|
21638
|
+
const nextDelimIdx = bufferIndexOf(body, delimiter4, offset);
|
|
21641
21639
|
if (nextDelimIdx === -1) break;
|
|
21642
21640
|
const contentEnd = nextDelimIdx - crlf.length;
|
|
21643
21641
|
const content = body.subarray(offset, contentEnd);
|
|
@@ -21660,7 +21658,7 @@ function parseMultipart(body, boundary) {
|
|
|
21660
21658
|
} else if (disposition.name) {
|
|
21661
21659
|
fields[disposition.name] = content.toString("utf-8");
|
|
21662
21660
|
}
|
|
21663
|
-
offset = nextDelimIdx +
|
|
21661
|
+
offset = nextDelimIdx + delimiter4.length;
|
|
21664
21662
|
if (body[offset] === 45 && body[offset + 1] === 45) {
|
|
21665
21663
|
break;
|
|
21666
21664
|
}
|
|
@@ -22408,6 +22406,21 @@ var init_portTakeover = __esm({
|
|
|
22408
22406
|
}
|
|
22409
22407
|
});
|
|
22410
22408
|
|
|
22409
|
+
// ../core/src/etag.ts
|
|
22410
|
+
function etagMatches(ifNoneMatch, etag) {
|
|
22411
|
+
const strip = (tag) => tag.trim().replace(/^W\//, "");
|
|
22412
|
+
const target = strip(etag);
|
|
22413
|
+
return ifNoneMatch.split(",").some((candidate) => {
|
|
22414
|
+
const trimmed = candidate.trim();
|
|
22415
|
+
return trimmed === "*" || strip(trimmed) === target;
|
|
22416
|
+
});
|
|
22417
|
+
}
|
|
22418
|
+
var init_etag = __esm({
|
|
22419
|
+
"../core/src/etag.ts"() {
|
|
22420
|
+
"use strict";
|
|
22421
|
+
}
|
|
22422
|
+
});
|
|
22423
|
+
|
|
22411
22424
|
// ../core/src/sessionHandlers/syncBridge.ts
|
|
22412
22425
|
import { Worker } from "node:worker_threads";
|
|
22413
22426
|
function getBridge(key, workerSource, workerData) {
|
|
@@ -22689,42 +22702,35 @@ var init_respClient = __esm({
|
|
|
22689
22702
|
}
|
|
22690
22703
|
});
|
|
22691
22704
|
|
|
22692
|
-
// ../core/src/sessionHandlers/
|
|
22693
|
-
var
|
|
22694
|
-
var
|
|
22695
|
-
"../core/src/sessionHandlers/
|
|
22705
|
+
// ../core/src/sessionHandlers/respSessionHandler.ts
|
|
22706
|
+
var RespSessionHandler;
|
|
22707
|
+
var init_respSessionHandler = __esm({
|
|
22708
|
+
"../core/src/sessionHandlers/respSessionHandler.ts"() {
|
|
22696
22709
|
"use strict";
|
|
22697
22710
|
init_respClient();
|
|
22698
|
-
|
|
22699
|
-
|
|
22700
|
-
|
|
22701
|
-
|
|
22702
|
-
prefix;
|
|
22703
|
-
db;
|
|
22704
|
-
constructor(config) {
|
|
22705
|
-
this.host = config?.host ?? process.env.TINA4_SESSION_VALKEY_HOST ?? "127.0.0.1";
|
|
22706
|
-
this.port = config?.port ?? (process.env.TINA4_SESSION_VALKEY_PORT ? parseInt(process.env.TINA4_SESSION_VALKEY_PORT, 10) : 6379);
|
|
22707
|
-
this.password = config?.password ?? process.env.TINA4_SESSION_VALKEY_PASSWORD ?? "";
|
|
22708
|
-
this.prefix = config?.prefix ?? process.env.TINA4_SESSION_VALKEY_PREFIX ?? "tina4:session:";
|
|
22709
|
-
this.db = config?.db ?? (process.env.TINA4_SESSION_VALKEY_DB ? parseInt(process.env.TINA4_SESSION_VALKEY_DB, 10) : 0);
|
|
22711
|
+
RespSessionHandler = class {
|
|
22712
|
+
constructor(conn, label) {
|
|
22713
|
+
this.conn = conn;
|
|
22714
|
+
this.label = label;
|
|
22710
22715
|
}
|
|
22716
|
+
conn;
|
|
22717
|
+
label;
|
|
22711
22718
|
/**
|
|
22712
|
-
* Execute a RESP command synchronously against the live
|
|
22719
|
+
* Execute a RESP command synchronously against the live server.
|
|
22713
22720
|
*
|
|
22714
|
-
* Delegates to the shared {@link respCommandSync} transport: a genuine key
|
|
22715
|
-
* yields `""`, and a transport/connection FAILURE
|
|
22716
|
-
*
|
|
22717
|
-
* (silent) from "backend failed" (log-loud + degrade). Backend-failure parity.
|
|
22721
|
+
* Delegates to the shared {@link respCommandSync} transport: a genuine key
|
|
22722
|
+
* miss yields `""`, and a transport/connection FAILURE THROWS so the caller
|
|
22723
|
+
* can distinguish "not found" from "backend failed". Backend-failure parity.
|
|
22718
22724
|
*/
|
|
22719
22725
|
execSync(args) {
|
|
22720
22726
|
return respCommandSync(
|
|
22721
|
-
{ host: this.host, port: this.port, password: this.password, db: this.db },
|
|
22727
|
+
{ host: this.conn.host, port: this.conn.port, password: this.conn.password, db: this.conn.db },
|
|
22722
22728
|
args,
|
|
22723
|
-
|
|
22729
|
+
this.label
|
|
22724
22730
|
);
|
|
22725
22731
|
}
|
|
22726
22732
|
key(sessionId) {
|
|
22727
|
-
return `${this.prefix}${sessionId}`;
|
|
22733
|
+
return `${this.conn.prefix}${sessionId}`;
|
|
22728
22734
|
}
|
|
22729
22735
|
read(sessionId) {
|
|
22730
22736
|
const raw = this.execSync(["GET", this.key(sessionId)]);
|
|
@@ -22735,7 +22741,7 @@ var init_valkeyHandler = __esm({
|
|
|
22735
22741
|
return null;
|
|
22736
22742
|
}
|
|
22737
22743
|
}
|
|
22738
|
-
write(sessionId, data, ttl) {
|
|
22744
|
+
write(sessionId, data, ttl = 0) {
|
|
22739
22745
|
const json = JSON.stringify(data);
|
|
22740
22746
|
if (ttl > 0) {
|
|
22741
22747
|
this.execSync(["SETEX", this.key(sessionId), String(ttl), json]);
|
|
@@ -22750,6 +22756,29 @@ var init_valkeyHandler = __esm({
|
|
|
22750
22756
|
}
|
|
22751
22757
|
});
|
|
22752
22758
|
|
|
22759
|
+
// ../core/src/sessionHandlers/valkeyHandler.ts
|
|
22760
|
+
var ValkeySessionHandler;
|
|
22761
|
+
var init_valkeyHandler = __esm({
|
|
22762
|
+
"../core/src/sessionHandlers/valkeyHandler.ts"() {
|
|
22763
|
+
"use strict";
|
|
22764
|
+
init_respSessionHandler();
|
|
22765
|
+
ValkeySessionHandler = class extends RespSessionHandler {
|
|
22766
|
+
constructor(config) {
|
|
22767
|
+
super(
|
|
22768
|
+
{
|
|
22769
|
+
host: config?.host ?? process.env.TINA4_SESSION_VALKEY_HOST ?? "127.0.0.1",
|
|
22770
|
+
port: config?.port ?? (process.env.TINA4_SESSION_VALKEY_PORT ? parseInt(process.env.TINA4_SESSION_VALKEY_PORT, 10) : 6379),
|
|
22771
|
+
password: config?.password ?? process.env.TINA4_SESSION_VALKEY_PASSWORD ?? "",
|
|
22772
|
+
prefix: config?.prefix ?? process.env.TINA4_SESSION_VALKEY_PREFIX ?? "tina4:session:",
|
|
22773
|
+
db: config?.db ?? (process.env.TINA4_SESSION_VALKEY_DB ? parseInt(process.env.TINA4_SESSION_VALKEY_DB, 10) : 0)
|
|
22774
|
+
},
|
|
22775
|
+
"Valkey"
|
|
22776
|
+
);
|
|
22777
|
+
}
|
|
22778
|
+
};
|
|
22779
|
+
}
|
|
22780
|
+
});
|
|
22781
|
+
|
|
22753
22782
|
// ../core/src/sessionHandlers/memcachedHandler.ts
|
|
22754
22783
|
import { createHash as createHash4 } from "node:crypto";
|
|
22755
22784
|
var MAX_KEY_BYTES, MAX_RELATIVE_EXPTIME, MemcachedSessionHandler;
|
|
@@ -23815,7 +23844,7 @@ var init_session = __esm({
|
|
|
23815
23844
|
"use strict";
|
|
23816
23845
|
init_logger();
|
|
23817
23846
|
init_dotenv();
|
|
23818
|
-
|
|
23847
|
+
init_respSessionHandler();
|
|
23819
23848
|
init_valkeyHandler();
|
|
23820
23849
|
init_memcachedHandler();
|
|
23821
23850
|
init_mongoHandler();
|
|
@@ -23941,57 +23970,19 @@ var init_session = __esm({
|
|
|
23941
23970
|
}
|
|
23942
23971
|
}
|
|
23943
23972
|
};
|
|
23944
|
-
RedisSessionHandler = class {
|
|
23945
|
-
host;
|
|
23946
|
-
port;
|
|
23947
|
-
password;
|
|
23948
|
-
prefix;
|
|
23949
|
-
db;
|
|
23973
|
+
RedisSessionHandler = class extends RespSessionHandler {
|
|
23950
23974
|
constructor(config) {
|
|
23951
|
-
|
|
23952
|
-
|
|
23953
|
-
|
|
23954
|
-
|
|
23955
|
-
|
|
23956
|
-
|
|
23957
|
-
|
|
23958
|
-
|
|
23959
|
-
*
|
|
23960
|
-
* Delegates to the shared {@link respCommandSync} transport: a genuine key miss
|
|
23961
|
-
* yields `""`, and a transport/connection FAILURE (server unreachable, rejected
|
|
23962
|
-
* AUTH, timeout) THROWS so the Session boundary can distinguish "not found"
|
|
23963
|
-
* (silent) from "backend failed" (log-loud + degrade). Backend-failure parity.
|
|
23964
|
-
*/
|
|
23965
|
-
execSync(args) {
|
|
23966
|
-
return respCommandSync(
|
|
23967
|
-
{ host: this.host, port: this.port, password: this.password, db: this.db },
|
|
23968
|
-
args,
|
|
23975
|
+
super(
|
|
23976
|
+
{
|
|
23977
|
+
host: config?.redisHost ?? process.env.TINA4_SESSION_REDIS_HOST ?? "127.0.0.1",
|
|
23978
|
+
port: config?.redisPort ?? (process.env.TINA4_SESSION_REDIS_PORT ? parseInt(process.env.TINA4_SESSION_REDIS_PORT, 10) : 6379),
|
|
23979
|
+
password: config?.redisPassword ?? process.env.TINA4_SESSION_REDIS_PASSWORD ?? "",
|
|
23980
|
+
prefix: config?.redisPrefix ?? process.env.TINA4_SESSION_REDIS_PREFIX ?? "tina4:session:",
|
|
23981
|
+
db: config?.redisDb ?? (process.env.TINA4_SESSION_REDIS_DB ? parseInt(process.env.TINA4_SESSION_REDIS_DB, 10) : 0)
|
|
23982
|
+
},
|
|
23969
23983
|
"Redis"
|
|
23970
23984
|
);
|
|
23971
23985
|
}
|
|
23972
|
-
key(sessionId) {
|
|
23973
|
-
return `${this.prefix}${sessionId}`;
|
|
23974
|
-
}
|
|
23975
|
-
read(sessionId) {
|
|
23976
|
-
const raw = this.execSync(["GET", this.key(sessionId)]);
|
|
23977
|
-
if (!raw) return null;
|
|
23978
|
-
try {
|
|
23979
|
-
return JSON.parse(raw);
|
|
23980
|
-
} catch {
|
|
23981
|
-
return null;
|
|
23982
|
-
}
|
|
23983
|
-
}
|
|
23984
|
-
write(sessionId, data, ttl = 0) {
|
|
23985
|
-
const json = JSON.stringify(data);
|
|
23986
|
-
if (ttl > 0) {
|
|
23987
|
-
this.execSync(["SETEX", this.key(sessionId), String(ttl), json]);
|
|
23988
|
-
} else {
|
|
23989
|
-
this.execSync(["SET", this.key(sessionId), json]);
|
|
23990
|
-
}
|
|
23991
|
-
}
|
|
23992
|
-
destroy(sessionId) {
|
|
23993
|
-
this.execSync(["DEL", this.key(sessionId)]);
|
|
23994
|
-
}
|
|
23995
23986
|
};
|
|
23996
23987
|
FLASH_PREFIX = "_flash_";
|
|
23997
23988
|
Session = class {
|
|
@@ -24401,14 +24392,6 @@ function headStripIntercept(rawReq, rawRes) {
|
|
|
24401
24392
|
function isCompressibleContentType(contentType) {
|
|
24402
24393
|
return COMPRESSIBLE_PREFIXES.some((prefix) => contentType.includes(prefix));
|
|
24403
24394
|
}
|
|
24404
|
-
function etagMatchesInm(ifNoneMatch, etag) {
|
|
24405
|
-
const strip = (tag) => tag.trim().replace(/^W\//, "");
|
|
24406
|
-
const target = strip(etag);
|
|
24407
|
-
return ifNoneMatch.split(",").some((candidate) => {
|
|
24408
|
-
const trimmed = candidate.trim();
|
|
24409
|
-
return trimmed === "*" || strip(trimmed) === target;
|
|
24410
|
-
});
|
|
24411
|
-
}
|
|
24412
24395
|
function maybeCompressResponse(body, rawReq, rawRes) {
|
|
24413
24396
|
const acceptEncoding = String(rawReq.headers["accept-encoding"] ?? "");
|
|
24414
24397
|
const contentTypeHeader = rawRes.getHeader("content-type");
|
|
@@ -24424,7 +24407,7 @@ function maybeCompressResponse(body, rawReq, rawRes) {
|
|
|
24424
24407
|
}
|
|
24425
24408
|
function responseIsNotModified(rawReq, rawRes, etag) {
|
|
24426
24409
|
const ifNoneMatch = String(rawReq.headers["if-none-match"] ?? "");
|
|
24427
|
-
if (ifNoneMatch) return
|
|
24410
|
+
if (ifNoneMatch) return etagMatches(ifNoneMatch, etag);
|
|
24428
24411
|
const lastModifiedHeader = rawRes.getHeader("last-modified");
|
|
24429
24412
|
if (typeof lastModifiedHeader !== "string") return false;
|
|
24430
24413
|
const ifModifiedSince = String(rawReq.headers["if-modified-since"] ?? "");
|
|
@@ -24552,6 +24535,7 @@ var init_dispatchPipeline = __esm({
|
|
|
24552
24535
|
"../core/src/dispatchPipeline.ts"() {
|
|
24553
24536
|
"use strict";
|
|
24554
24537
|
init_logger();
|
|
24538
|
+
init_etag();
|
|
24555
24539
|
COMPRESSIBLE_PREFIXES = [
|
|
24556
24540
|
"text/",
|
|
24557
24541
|
"application/json",
|
|
@@ -24647,18 +24631,11 @@ function isNotModified(req2, etag, stat) {
|
|
|
24647
24631
|
}
|
|
24648
24632
|
return false;
|
|
24649
24633
|
}
|
|
24650
|
-
function etagMatches(ifNoneMatch, etag) {
|
|
24651
|
-
const strip = (tag) => tag.trim().replace(/^W\//, "");
|
|
24652
|
-
const target = strip(etag);
|
|
24653
|
-
return ifNoneMatch.split(",").some((candidate) => {
|
|
24654
|
-
const trimmed = candidate.trim();
|
|
24655
|
-
return trimmed === "*" || strip(trimmed) === target;
|
|
24656
|
-
});
|
|
24657
|
-
}
|
|
24658
24634
|
var COMPRESSIBLE_PREFIXES2, MIME_TYPES;
|
|
24659
24635
|
var init_static = __esm({
|
|
24660
24636
|
"../core/src/static.ts"() {
|
|
24661
24637
|
"use strict";
|
|
24638
|
+
init_etag();
|
|
24662
24639
|
COMPRESSIBLE_PREFIXES2 = [
|
|
24663
24640
|
"text/",
|
|
24664
24641
|
"application/json",
|
|
@@ -25235,6 +25212,25 @@ Generated by DevMailbox.seed() for development purposes.`,
|
|
|
25235
25212
|
}
|
|
25236
25213
|
});
|
|
25237
25214
|
|
|
25215
|
+
// ../core/src/upstreamResponse.ts
|
|
25216
|
+
async function relayUpstreamResponse(res, upstream) {
|
|
25217
|
+
const raw = await upstream.text();
|
|
25218
|
+
const status2 = upstream.status || 200;
|
|
25219
|
+
try {
|
|
25220
|
+
res.json(JSON.parse(raw), status2);
|
|
25221
|
+
} catch {
|
|
25222
|
+
res.raw.writeHead(status2, {
|
|
25223
|
+
"Content-Type": upstream.headers.get("content-type") ?? "text/plain; charset=utf-8"
|
|
25224
|
+
});
|
|
25225
|
+
res.raw.end(raw);
|
|
25226
|
+
}
|
|
25227
|
+
}
|
|
25228
|
+
var init_upstreamResponse = __esm({
|
|
25229
|
+
"../core/src/upstreamResponse.ts"() {
|
|
25230
|
+
"use strict";
|
|
25231
|
+
}
|
|
25232
|
+
});
|
|
25233
|
+
|
|
25238
25234
|
// ../core/src/metrics.ts
|
|
25239
25235
|
import * as fs3 from "node:fs";
|
|
25240
25236
|
import * as path2 from "node:path";
|
|
@@ -25450,6 +25446,7 @@ var init_feedback = __esm({
|
|
|
25450
25446
|
"use strict";
|
|
25451
25447
|
init_auth();
|
|
25452
25448
|
init_devAdmin();
|
|
25449
|
+
init_upstreamResponse();
|
|
25453
25450
|
RATE_LIMIT_WINDOW_SEC = 3600;
|
|
25454
25451
|
RATE_LIMIT_MAX = 5;
|
|
25455
25452
|
_rateLimitHits = /* @__PURE__ */ new Map();
|
|
@@ -25496,16 +25493,7 @@ var init_feedback = __esm({
|
|
|
25496
25493
|
return;
|
|
25497
25494
|
}
|
|
25498
25495
|
clearTimeout(timer);
|
|
25499
|
-
|
|
25500
|
-
const status2 = upstream.status || 200;
|
|
25501
|
-
try {
|
|
25502
|
-
res.json(JSON.parse(raw), status2);
|
|
25503
|
-
} catch {
|
|
25504
|
-
res.raw.writeHead(status2, {
|
|
25505
|
-
"Content-Type": upstream.headers.get("content-type") ?? "text/plain; charset=utf-8"
|
|
25506
|
-
});
|
|
25507
|
-
res.raw.end(raw);
|
|
25508
|
-
}
|
|
25496
|
+
await relayUpstreamResponse(res, upstream);
|
|
25509
25497
|
};
|
|
25510
25498
|
__feedbackDirname = dirname8(fileURLToPath3(import.meta.url));
|
|
25511
25499
|
WIDGET_BUNDLE_PATH = resolve10(__feedbackDirname, "__feedback", "widget.js");
|
|
@@ -25555,6 +25543,61 @@ var init_version = __esm({
|
|
|
25555
25543
|
}
|
|
25556
25544
|
});
|
|
25557
25545
|
|
|
25546
|
+
// src/util.ts
|
|
25547
|
+
import { delimiter as delimiter2, join as join21 } from "node:path";
|
|
25548
|
+
import { statSync as statSync11 } from "node:fs";
|
|
25549
|
+
function parseFlags(args, booleanFlags) {
|
|
25550
|
+
const flags = {};
|
|
25551
|
+
const positional = [];
|
|
25552
|
+
let i = 0;
|
|
25553
|
+
while (i < args.length) {
|
|
25554
|
+
const arg = args[i];
|
|
25555
|
+
if (arg.startsWith("--")) {
|
|
25556
|
+
const key = arg.slice(2);
|
|
25557
|
+
if (booleanFlags?.has(key)) {
|
|
25558
|
+
flags[key] = true;
|
|
25559
|
+
i += 1;
|
|
25560
|
+
} else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
|
|
25561
|
+
flags[key] = args[i + 1];
|
|
25562
|
+
i += 2;
|
|
25563
|
+
} else {
|
|
25564
|
+
flags[key] = true;
|
|
25565
|
+
i += 1;
|
|
25566
|
+
}
|
|
25567
|
+
} else {
|
|
25568
|
+
positional.push(arg);
|
|
25569
|
+
i += 1;
|
|
25570
|
+
}
|
|
25571
|
+
}
|
|
25572
|
+
return { flags, positional };
|
|
25573
|
+
}
|
|
25574
|
+
function findOnPath(names) {
|
|
25575
|
+
for (const dir of (process.env.PATH ?? "").split(delimiter2)) {
|
|
25576
|
+
if (!dir) continue;
|
|
25577
|
+
for (const name of names) {
|
|
25578
|
+
const candidate = join21(dir, name);
|
|
25579
|
+
try {
|
|
25580
|
+
if (statSync11(candidate).isFile()) return candidate;
|
|
25581
|
+
} catch {
|
|
25582
|
+
}
|
|
25583
|
+
}
|
|
25584
|
+
}
|
|
25585
|
+
return null;
|
|
25586
|
+
}
|
|
25587
|
+
async function initDatabaseOrExit(initDatabase2) {
|
|
25588
|
+
try {
|
|
25589
|
+
await initDatabase2();
|
|
25590
|
+
} catch (err) {
|
|
25591
|
+
console.error(` Error initialising database: ${err instanceof Error ? err.message : String(err)}`);
|
|
25592
|
+
process.exit(1);
|
|
25593
|
+
}
|
|
25594
|
+
}
|
|
25595
|
+
var init_util = __esm({
|
|
25596
|
+
"src/util.ts"() {
|
|
25597
|
+
"use strict";
|
|
25598
|
+
}
|
|
25599
|
+
});
|
|
25600
|
+
|
|
25558
25601
|
// src/commands/generate.ts
|
|
25559
25602
|
var generate_exports = {};
|
|
25560
25603
|
__export(generate_exports, {
|
|
@@ -25579,7 +25622,7 @@ __export(generate_exports, {
|
|
|
25579
25622
|
toTableName: () => toTableName
|
|
25580
25623
|
});
|
|
25581
25624
|
import { existsSync as existsSync16, mkdirSync as mkdirSync13, writeFileSync as writeFileSync10 } from "node:fs";
|
|
25582
|
-
import { join as
|
|
25625
|
+
import { join as join22, relative as relative2, resolve as resolve11, sep as sep5 } from "node:path";
|
|
25583
25626
|
function ensureDir(dir) {
|
|
25584
25627
|
if (__resolution.dryRun) return;
|
|
25585
25628
|
if (!existsSync16(dir)) {
|
|
@@ -25819,28 +25862,7 @@ function parseCliArgs(args) {
|
|
|
25819
25862
|
"json",
|
|
25820
25863
|
"dry-run"
|
|
25821
25864
|
]);
|
|
25822
|
-
|
|
25823
|
-
const positional = [];
|
|
25824
|
-
let i = 0;
|
|
25825
|
-
while (i < args.length) {
|
|
25826
|
-
if (args[i].startsWith("--")) {
|
|
25827
|
-
const key = args[i].slice(2);
|
|
25828
|
-
if (booleanFlags.has(key)) {
|
|
25829
|
-
flags[key] = true;
|
|
25830
|
-
i += 1;
|
|
25831
|
-
} else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
|
|
25832
|
-
flags[key] = args[i + 1];
|
|
25833
|
-
i += 2;
|
|
25834
|
-
} else {
|
|
25835
|
-
flags[key] = true;
|
|
25836
|
-
i += 1;
|
|
25837
|
-
}
|
|
25838
|
-
} else {
|
|
25839
|
-
positional.push(args[i]);
|
|
25840
|
-
i += 1;
|
|
25841
|
-
}
|
|
25842
|
-
}
|
|
25843
|
-
return { flags, positional };
|
|
25865
|
+
return parseFlags(args, booleanFlags);
|
|
25844
25866
|
}
|
|
25845
25867
|
function parseEvery(every) {
|
|
25846
25868
|
if (!every || every === true) return 60;
|
|
@@ -25939,7 +25961,7 @@ function generateModel(name, flags, emitTest = true) {
|
|
|
25939
25961
|
const table2 = resolveTable(name, flags, { announce: true });
|
|
25940
25962
|
const dir = resolve11("src/models");
|
|
25941
25963
|
ensureDir(dir);
|
|
25942
|
-
const path10 =
|
|
25964
|
+
const path10 = join22(dir, `${name}.ts`);
|
|
25943
25965
|
setResolutionField("class_name", name);
|
|
25944
25966
|
setResolutionField("table_name", table2);
|
|
25945
25967
|
setResolutionField("file_path", `src/models/${name}.ts`);
|
|
@@ -25979,7 +26001,7 @@ function generateRoute(name, flags, emitTest = true) {
|
|
|
25979
26001
|
const model = flags.model;
|
|
25980
26002
|
const isPublic = Boolean(flags.public);
|
|
25981
26003
|
const base = resolve11("src/routes/api", routePath);
|
|
25982
|
-
const idDir =
|
|
26004
|
+
const idDir = join22(base, "[id]");
|
|
25983
26005
|
ensureDir(base);
|
|
25984
26006
|
ensureDir(idDir);
|
|
25985
26007
|
pushRoute(`/api/${routePath}`);
|
|
@@ -25995,7 +26017,7 @@ function generateRoute(name, flags, emitTest = true) {
|
|
|
25995
26017
|
const writeDoc = isPublic ? "Public (--public): no token required." : "Secure by default: requires a Bearer token (use --public to open).";
|
|
25996
26018
|
if (model) {
|
|
25997
26019
|
writeFileSafe(
|
|
25998
|
-
|
|
26020
|
+
join22(base, "get.ts"),
|
|
25999
26021
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26000
26022
|
${modelImportBase}
|
|
26001
26023
|
export const meta = { summary: "List all ${routePath}", tags: ["${routePath}"] };
|
|
@@ -26012,7 +26034,7 @@ export default async function (req: Tina4Request, res: Tina4Response) {
|
|
|
26012
26034
|
);
|
|
26013
26035
|
} else {
|
|
26014
26036
|
writeFileSafe(
|
|
26015
|
-
|
|
26037
|
+
join22(base, "get.ts"),
|
|
26016
26038
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26017
26039
|
|
|
26018
26040
|
export const meta = { summary: "List all ${routePath}", tags: ["${routePath}"] };
|
|
@@ -26031,7 +26053,7 @@ ${aiFill(`list_${routePath}`, {
|
|
|
26031
26053
|
}
|
|
26032
26054
|
if (model) {
|
|
26033
26055
|
writeFileSafe(
|
|
26034
|
-
|
|
26056
|
+
join22(base, "post.ts"),
|
|
26035
26057
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26036
26058
|
${modelImportBase}${secureOptOut(isPublic)}export const meta = { summary: "Create a new ${singular}", tags: ["${routePath}"] };
|
|
26037
26059
|
|
|
@@ -26054,7 +26076,7 @@ ${extend(
|
|
|
26054
26076
|
);
|
|
26055
26077
|
} else {
|
|
26056
26078
|
writeFileSafe(
|
|
26057
|
-
|
|
26079
|
+
join22(base, "post.ts"),
|
|
26058
26080
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26059
26081
|
|
|
26060
26082
|
${secureOptOut(isPublic)}export const meta = { summary: "Create a new ${singular}", tags: ["${routePath}"] };
|
|
@@ -26075,7 +26097,7 @@ ${aiFill(`create_${singular}`, {
|
|
|
26075
26097
|
}
|
|
26076
26098
|
if (model) {
|
|
26077
26099
|
writeFileSafe(
|
|
26078
|
-
|
|
26100
|
+
join22(idDir, "get.ts"),
|
|
26079
26101
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26080
26102
|
${modelImportId}
|
|
26081
26103
|
export const meta = { summary: "Get a ${singular} by ID", tags: ["${routePath}"] };
|
|
@@ -26093,7 +26115,7 @@ export default async function (req: Tina4Request, res: Tina4Response) {
|
|
|
26093
26115
|
);
|
|
26094
26116
|
} else {
|
|
26095
26117
|
writeFileSafe(
|
|
26096
|
-
|
|
26118
|
+
join22(idDir, "get.ts"),
|
|
26097
26119
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26098
26120
|
|
|
26099
26121
|
export const meta = { summary: "Get a ${singular} by ID", tags: ["${routePath}"] };
|
|
@@ -26112,7 +26134,7 @@ ${aiFill(`get_${singular}`, {
|
|
|
26112
26134
|
}
|
|
26113
26135
|
if (model) {
|
|
26114
26136
|
writeFileSafe(
|
|
26115
|
-
|
|
26137
|
+
join22(idDir, "put.ts"),
|
|
26116
26138
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26117
26139
|
${modelImportId}${secureOptOut(isPublic)}export const meta = { summary: "Update a ${singular} by ID", tags: ["${routePath}"] };
|
|
26118
26140
|
|
|
@@ -26141,7 +26163,7 @@ ${extend(
|
|
|
26141
26163
|
);
|
|
26142
26164
|
} else {
|
|
26143
26165
|
writeFileSafe(
|
|
26144
|
-
|
|
26166
|
+
join22(idDir, "put.ts"),
|
|
26145
26167
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26146
26168
|
|
|
26147
26169
|
${secureOptOut(isPublic)}export const meta = { summary: "Update a ${singular} by ID", tags: ["${routePath}"] };
|
|
@@ -26162,7 +26184,7 @@ ${aiFill(`update_${singular}`, {
|
|
|
26162
26184
|
}
|
|
26163
26185
|
if (model) {
|
|
26164
26186
|
writeFileSafe(
|
|
26165
|
-
|
|
26187
|
+
join22(idDir, "delete.ts"),
|
|
26166
26188
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26167
26189
|
${modelImportId}${secureOptOut(isPublic)}export const meta = { summary: "Delete a ${singular} by ID", tags: ["${routePath}"] };
|
|
26168
26190
|
|
|
@@ -26181,7 +26203,7 @@ export default async function (req: Tina4Request, res: Tina4Response) {
|
|
|
26181
26203
|
);
|
|
26182
26204
|
} else {
|
|
26183
26205
|
writeFileSafe(
|
|
26184
|
-
|
|
26206
|
+
join22(idDir, "delete.ts"),
|
|
26185
26207
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26186
26208
|
|
|
26187
26209
|
${secureOptOut(isPublic)}export const meta = { summary: "Delete a ${singular} by ID", tags: ["${routePath}"] };
|
|
@@ -26243,7 +26265,7 @@ function generateMigration(name, flags, fieldsOverride, tableOverride, emitTest
|
|
|
26243
26265
|
const fields = fieldsOverride || parseFields(flags.fields || "");
|
|
26244
26266
|
const isCreate = name.startsWith("create_") || fieldsOverride !== void 0;
|
|
26245
26267
|
const fileName = `${ts}_${name}.sql`;
|
|
26246
|
-
const path10 =
|
|
26268
|
+
const path10 = join22(dir, fileName);
|
|
26247
26269
|
setResolutionField("migration_path", `migrations/${fileName}`);
|
|
26248
26270
|
if (__resolution.target === "migration") {
|
|
26249
26271
|
setResolutionField("file_path", `migrations/${fileName}`);
|
|
@@ -26282,7 +26304,7 @@ ${upSql}
|
|
|
26282
26304
|
${downSql}
|
|
26283
26305
|
`;
|
|
26284
26306
|
writeFileSafe(path10, content);
|
|
26285
|
-
const downPath =
|
|
26307
|
+
const downPath = join22(dir, `${ts}_${name}.down.sql`);
|
|
26286
26308
|
const downContent = `-- Rollback: ${name}
|
|
26287
26309
|
-- Created: ${now}
|
|
26288
26310
|
|
|
@@ -26295,7 +26317,7 @@ function generateMiddleware(name, _flags) {
|
|
|
26295
26317
|
const snake = toSnake(name);
|
|
26296
26318
|
const dir = resolve11("src/middleware");
|
|
26297
26319
|
ensureDir(dir);
|
|
26298
|
-
const path10 =
|
|
26320
|
+
const path10 = join22(dir, `${snake}.ts`);
|
|
26299
26321
|
if (__resolution.target === "middleware") {
|
|
26300
26322
|
setResolutionField("class_name", name);
|
|
26301
26323
|
setResolutionField("file_path", `src/middleware/${snake}.ts`);
|
|
@@ -26342,7 +26364,7 @@ function generateTest(name, flags) {
|
|
|
26342
26364
|
const model = flags.model;
|
|
26343
26365
|
const dir = resolve11("tests");
|
|
26344
26366
|
ensureDir(dir);
|
|
26345
|
-
const path10 =
|
|
26367
|
+
const path10 = join22(dir, `${snake}.test.ts`);
|
|
26346
26368
|
if (model && flags["secure-writes"]) {
|
|
26347
26369
|
const isPublic = Boolean(flags.public);
|
|
26348
26370
|
const posture = isPublic ? "open (--public)" : "gated";
|
|
@@ -26480,7 +26502,7 @@ function generateForm(name, flags) {
|
|
|
26480
26502
|
};
|
|
26481
26503
|
const dir = resolve11("src/templates/forms");
|
|
26482
26504
|
ensureDir(dir);
|
|
26483
|
-
const path10 =
|
|
26505
|
+
const path10 = join22(dir, `${table2}.twig`);
|
|
26484
26506
|
let fieldHtml = "";
|
|
26485
26507
|
for (const [fname, ftype] of fields) {
|
|
26486
26508
|
const itype = inputTypes[ftype] || "text";
|
|
@@ -26533,7 +26555,7 @@ function generateView(name, flags) {
|
|
|
26533
26555
|
const cols = fields.map(([f]) => f);
|
|
26534
26556
|
const dir = resolve11("src/templates/pages");
|
|
26535
26557
|
ensureDir(dir);
|
|
26536
|
-
const listPath =
|
|
26558
|
+
const listPath = join22(dir, `${routeName}.twig`);
|
|
26537
26559
|
const th = cols.map((c) => ` <th>${c.replace(/_/g, " ").replace(/\b\w/g, (ch) => ch.toUpperCase())}</th>`).join("\n");
|
|
26538
26560
|
const td = cols.map((c) => ` <td>{{ item.${c} }}</td>`).join("\n");
|
|
26539
26561
|
const listContent = `{% extends "base.twig" %}
|
|
@@ -26570,7 +26592,7 @@ ${td}
|
|
|
26570
26592
|
{% endblock %}
|
|
26571
26593
|
`;
|
|
26572
26594
|
writeFileSafe(listPath, listContent);
|
|
26573
|
-
const detailPath =
|
|
26595
|
+
const detailPath = join22(dir, `${table2}.twig`);
|
|
26574
26596
|
const detailFields = cols.map((c) => ` <div class="mb-3"><strong>${c.replace(/_/g, " ").replace(/\b\w/g, (ch) => ch.toUpperCase())}:</strong> {{ item.${c} }}</div>`).join("\n");
|
|
26575
26597
|
const detailContent = `{% extends "base.twig" %}
|
|
26576
26598
|
{% block title %}${name} Detail{% endblock %}
|
|
@@ -26600,7 +26622,7 @@ function generateAuth(_flags) {
|
|
|
26600
26622
|
ensureDir(loginDir);
|
|
26601
26623
|
ensureDir(meDir);
|
|
26602
26624
|
writeFileSafe(
|
|
26603
|
-
|
|
26625
|
+
join22(registerDir, "post.ts"),
|
|
26604
26626
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26605
26627
|
import { hashPassword } from "tina4-nodejs";
|
|
26606
26628
|
import User from "../../../../models/User.js";
|
|
@@ -26632,7 +26654,7 @@ export default async function (req: Tina4Request, res: Tina4Response) {
|
|
|
26632
26654
|
`
|
|
26633
26655
|
);
|
|
26634
26656
|
writeFileSafe(
|
|
26635
|
-
|
|
26657
|
+
join22(loginDir, "post.ts"),
|
|
26636
26658
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26637
26659
|
import { checkPassword, getToken } from "tina4-nodejs";
|
|
26638
26660
|
import User from "../../../../models/User.js";
|
|
@@ -26665,7 +26687,7 @@ export default async function (req: Tina4Request, res: Tina4Response) {
|
|
|
26665
26687
|
`
|
|
26666
26688
|
);
|
|
26667
26689
|
writeFileSafe(
|
|
26668
|
-
|
|
26690
|
+
join22(meDir, "get.ts"),
|
|
26669
26691
|
`import type { Tina4Request, Tina4Response } from "tina4-nodejs";
|
|
26670
26692
|
import { authenticateRequest } from "tina4-nodejs";
|
|
26671
26693
|
|
|
@@ -26684,7 +26706,7 @@ export default async function (req: Tina4Request, res: Tina4Response) {
|
|
|
26684
26706
|
const formsDir = resolve11("src/templates/forms");
|
|
26685
26707
|
ensureDir(formsDir);
|
|
26686
26708
|
writeFileSafe(
|
|
26687
|
-
|
|
26709
|
+
join22(formsDir, "login.twig"),
|
|
26688
26710
|
`{% extends "base.twig" %}
|
|
26689
26711
|
{% block title %}Login{% endblock %}
|
|
26690
26712
|
{% block content %}
|
|
@@ -26708,7 +26730,7 @@ export default async function (req: Tina4Request, res: Tina4Response) {
|
|
|
26708
26730
|
`
|
|
26709
26731
|
);
|
|
26710
26732
|
writeFileSafe(
|
|
26711
|
-
|
|
26733
|
+
join22(formsDir, "register.twig"),
|
|
26712
26734
|
`{% extends "base.twig" %}
|
|
26713
26735
|
{% block title %}Register{% endblock %}
|
|
26714
26736
|
{% block content %}
|
|
@@ -26746,7 +26768,7 @@ function generateService(name, flags) {
|
|
|
26746
26768
|
const cron = flags.cron;
|
|
26747
26769
|
const dir = resolve11("src/services");
|
|
26748
26770
|
ensureDir(dir);
|
|
26749
|
-
const path10 =
|
|
26771
|
+
const path10 = join22(dir, `${snake}.ts`);
|
|
26750
26772
|
let scheduleField;
|
|
26751
26773
|
let note;
|
|
26752
26774
|
if (cron && cron !== true) {
|
|
@@ -26798,7 +26820,7 @@ function generateQueue(name, _flags) {
|
|
|
26798
26820
|
const pascal = toPascal(topic) || "Topic";
|
|
26799
26821
|
const dir = resolve11("src/services");
|
|
26800
26822
|
ensureDir(dir);
|
|
26801
|
-
const path10 =
|
|
26823
|
+
const path10 = join22(dir, `${slug}_consumer.ts`);
|
|
26802
26824
|
const body = aiFill(`handle${pascal}`, {
|
|
26803
26825
|
intent: `process ONE ${topic} job payload`,
|
|
26804
26826
|
given: "payload -> the produced job data (job.payload)",
|
|
@@ -26859,7 +26881,7 @@ export default {
|
|
|
26859
26881
|
function generateValidator(name, _flags) {
|
|
26860
26882
|
const dir = resolve11("src/validators");
|
|
26861
26883
|
ensureDir(dir);
|
|
26862
|
-
const path10 =
|
|
26884
|
+
const path10 = join22(dir, `${toSnake(name)}.ts`);
|
|
26863
26885
|
const rules = extend(
|
|
26864
26886
|
"add / adjust the validation rules for this payload",
|
|
26865
26887
|
`e.g. .email("email").minLength("name", 2).integer("age"); ground: tina4_context("validate request body with Validator", "nodejs")`
|
|
@@ -26887,7 +26909,7 @@ function generateSeeder(name, flags) {
|
|
|
26887
26909
|
const table2 = resolveTable(name, flags, { announce: false });
|
|
26888
26910
|
const dir = resolve11("src/seeds");
|
|
26889
26911
|
ensureDir(dir);
|
|
26890
|
-
const path10 =
|
|
26912
|
+
const path10 = join22(dir, `${table2}_seeder.ts`);
|
|
26891
26913
|
const overrides = extend(
|
|
26892
26914
|
"override fields that need a specific shape (seedOrm auto-fills the rest)",
|
|
26893
26915
|
`e.g. return { email: (f) => f.email(), status: "active" }; ground: tina4_context("seed ORM model with FakeData", "nodejs")`
|
|
@@ -26932,7 +26954,7 @@ function generateWebsocket(name, _flags) {
|
|
|
26932
26954
|
const handlerName = `${toCamel(toPascal(base))}Ws`;
|
|
26933
26955
|
const dir = resolve11("src/routes");
|
|
26934
26956
|
ensureDir(dir);
|
|
26935
|
-
const path10 =
|
|
26957
|
+
const path10 = join22(dir, `ws_${base}.ts`);
|
|
26936
26958
|
const body = aiFill(handlerName, {
|
|
26937
26959
|
intent: `handle an inbound "message" frame on ${wsPath}`,
|
|
26938
26960
|
given: "data -> the message payload (string); connection -> WebSocketConnection",
|
|
@@ -26983,7 +27005,7 @@ function generateListener(name, _flags) {
|
|
|
26983
27005
|
const handlerName = `on${toPascal(slug)}`;
|
|
26984
27006
|
const dir = resolve11("src/listeners");
|
|
26985
27007
|
ensureDir(dir);
|
|
26986
|
-
const path10 =
|
|
27008
|
+
const path10 = join22(dir, `${slug}.ts`);
|
|
26987
27009
|
const body = aiFill(handlerName, {
|
|
26988
27010
|
intent: `react to the '${event}' event`,
|
|
26989
27011
|
given: `args -> whatever Events.emit("${event}", ...args) passed`,
|
|
@@ -27015,7 +27037,7 @@ Events.on("${event}", ${handlerName});
|
|
|
27015
27037
|
function writeTest(testName, content) {
|
|
27016
27038
|
const dir = resolve11("tests");
|
|
27017
27039
|
ensureDir(dir);
|
|
27018
|
-
writeFileSafe(
|
|
27040
|
+
writeFileSafe(join22(dir, `${testName}.test.ts`), content);
|
|
27019
27041
|
}
|
|
27020
27042
|
function standaloneTest(doc, body) {
|
|
27021
27043
|
return `${doc}
|
|
@@ -27401,6 +27423,7 @@ var FIELD_TYPE_MAP, SQL_RESERVED_TABLE_NAMES, RESOLUTION_ENVELOPE_VERSION, __res
|
|
|
27401
27423
|
var init_generate = __esm({
|
|
27402
27424
|
"src/commands/generate.ts"() {
|
|
27403
27425
|
"use strict";
|
|
27426
|
+
init_util();
|
|
27404
27427
|
FIELD_TYPE_MAP = {
|
|
27405
27428
|
string: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
27406
27429
|
str: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
@@ -30459,7 +30482,7 @@ __export(context_exports, {
|
|
|
30459
30482
|
});
|
|
30460
30483
|
import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
|
|
30461
30484
|
import { existsSync as existsSync18, mkdirSync as mkdirSync15, readFileSync as readFileSync15, readdirSync as readdirSync10, realpathSync as realpathSync5 } from "node:fs";
|
|
30462
|
-
import { basename as basename5, dirname as dirname11, extname as extname5, isAbsolute as isAbsolute6, join as
|
|
30485
|
+
import { basename as basename5, dirname as dirname11, extname as extname5, isAbsolute as isAbsolute6, join as join24, relative as relative4, resolve as resolve13 } from "node:path";
|
|
30463
30486
|
function fts5Supported() {
|
|
30464
30487
|
try {
|
|
30465
30488
|
const conn = new DatabaseSync4(":memory:");
|
|
@@ -30482,13 +30505,13 @@ function realResolve(abs) {
|
|
|
30482
30505
|
} catch {
|
|
30483
30506
|
}
|
|
30484
30507
|
try {
|
|
30485
|
-
return
|
|
30508
|
+
return join24(realpathSync5(dirname11(abs)), basename5(abs));
|
|
30486
30509
|
} catch {
|
|
30487
30510
|
return abs;
|
|
30488
30511
|
}
|
|
30489
30512
|
}
|
|
30490
30513
|
function dbKey(db) {
|
|
30491
|
-
return resolve13(db ? String(db) :
|
|
30514
|
+
return resolve13(db ? String(db) : join24(process.cwd(), ".tina4", "context.db"));
|
|
30492
30515
|
}
|
|
30493
30516
|
function defaultContext(root, db) {
|
|
30494
30517
|
const key = dbKey(db);
|
|
@@ -30661,11 +30684,11 @@ var init_context = __esm({
|
|
|
30661
30684
|
files.sort();
|
|
30662
30685
|
for (const fn of files) {
|
|
30663
30686
|
if (!_Context.eligible(fn)) continue;
|
|
30664
|
-
const full =
|
|
30687
|
+
const full = join24(dir, fn);
|
|
30665
30688
|
const rel = relative4(rootAbs, full);
|
|
30666
30689
|
total += this.indexPath(full, rel);
|
|
30667
30690
|
}
|
|
30668
|
-
for (const d of subdirs) walk2(
|
|
30691
|
+
for (const d of subdirs) walk2(join24(dir, d));
|
|
30669
30692
|
};
|
|
30670
30693
|
walk2(rootAbs);
|
|
30671
30694
|
return total;
|
|
@@ -30681,7 +30704,7 @@ var init_context = __esm({
|
|
|
30681
30704
|
reindexFile(changedPath) {
|
|
30682
30705
|
if (!this.available || this.root === null) return -1;
|
|
30683
30706
|
const raw = String(changedPath);
|
|
30684
|
-
const abs = isAbsolute6(raw) ? raw :
|
|
30707
|
+
const abs = isAbsolute6(raw) ? raw : join24(process.cwd(), raw);
|
|
30685
30708
|
const resolved = realResolve(resolve13(abs));
|
|
30686
30709
|
const rel = relative4(this.root, resolved);
|
|
30687
30710
|
if (rel === "" || rel.startsWith("..") || isAbsolute6(rel)) {
|
|
@@ -31019,6 +31042,7 @@ __export(websocket_exports, {
|
|
|
31019
31042
|
CLOSE_NORMAL: () => CLOSE_NORMAL,
|
|
31020
31043
|
CLOSE_POLICY_VIOLATION: () => CLOSE_POLICY_VIOLATION,
|
|
31021
31044
|
CLOSE_PROTOCOL_ERROR: () => CLOSE_PROTOCOL_ERROR,
|
|
31045
|
+
MessageAssembler: () => MessageAssembler,
|
|
31022
31046
|
OP_BINARY: () => OP_BINARY,
|
|
31023
31047
|
OP_CLOSE: () => OP_CLOSE,
|
|
31024
31048
|
OP_CONTINUATION: () => OP_CONTINUATION,
|
|
@@ -31276,21 +31300,24 @@ function serveWebSocketRoute(req2, socket, head) {
|
|
|
31276
31300
|
state.closed = true;
|
|
31277
31301
|
void Promise.resolve().then(() => conn._onClose ? conn._onClose() : handler(conn, "close", "")).catch((e) => Log.error(`WebSocket close handler error: ${e.message}`)).finally(() => wsRouteManager.remove(conn.id));
|
|
31278
31302
|
};
|
|
31303
|
+
const assembler = new MessageAssembler();
|
|
31279
31304
|
socket.on("data", (chunk) => {
|
|
31280
31305
|
buffer = Buffer.concat([buffer, chunk]);
|
|
31281
31306
|
while (buffer.length > 0) {
|
|
31282
31307
|
const frame = parseFrame(buffer);
|
|
31283
31308
|
if (!frame) break;
|
|
31284
31309
|
buffer = buffer.subarray(frame.bytesConsumed);
|
|
31285
|
-
|
|
31310
|
+
const whole = assembler.push(frame);
|
|
31311
|
+
if (!whole) continue;
|
|
31312
|
+
switch (whole.opcode) {
|
|
31286
31313
|
case OP_TEXT: {
|
|
31287
|
-
const text =
|
|
31314
|
+
const text = whole.payload.toString("utf-8");
|
|
31288
31315
|
void Promise.resolve().then(() => conn._onMessage ? conn._onMessage(text) : handler(conn, "message", text)).catch((e) => Log.error(`WebSocket message handler error: ${e.message}`));
|
|
31289
31316
|
break;
|
|
31290
31317
|
}
|
|
31291
31318
|
case OP_PING:
|
|
31292
31319
|
try {
|
|
31293
|
-
socket.write(buildFrame(OP_PONG,
|
|
31320
|
+
socket.write(buildFrame(OP_PONG, whole.payload));
|
|
31294
31321
|
} catch {
|
|
31295
31322
|
}
|
|
31296
31323
|
break;
|
|
@@ -31309,7 +31336,7 @@ function serveWebSocketRoute(req2, socket, head) {
|
|
|
31309
31336
|
socket.on("error", fireClose);
|
|
31310
31337
|
return true;
|
|
31311
31338
|
}
|
|
31312
|
-
var MAGIC_STRING, OP_CONTINUATION, OP_TEXT, OP_BINARY, OP_CLOSE, OP_PING, OP_PONG, CLOSE_NORMAL, CLOSE_GOING_AWAY, CLOSE_PROTOCOL_ERROR, CLOSE_POLICY_VIOLATION, WebSocketServer, WsRouteManager, wsRouteManager, DevReloadWsManager, devReloadWs;
|
|
31339
|
+
var MAGIC_STRING, OP_CONTINUATION, OP_TEXT, OP_BINARY, OP_CLOSE, OP_PING, OP_PONG, CLOSE_NORMAL, CLOSE_GOING_AWAY, CLOSE_PROTOCOL_ERROR, CLOSE_POLICY_VIOLATION, MessageAssembler, WebSocketServer, WsRouteManager, wsRouteManager, DevReloadWsManager, devReloadWs;
|
|
31313
31340
|
var init_websocket = __esm({
|
|
31314
31341
|
"../core/src/websocket.ts"() {
|
|
31315
31342
|
"use strict";
|
|
@@ -31328,6 +31355,30 @@ var init_websocket = __esm({
|
|
|
31328
31355
|
CLOSE_GOING_AWAY = 1001;
|
|
31329
31356
|
CLOSE_PROTOCOL_ERROR = 1002;
|
|
31330
31357
|
CLOSE_POLICY_VIOLATION = 1008;
|
|
31358
|
+
MessageAssembler = class {
|
|
31359
|
+
parts = [];
|
|
31360
|
+
opcode = 0;
|
|
31361
|
+
push(frame) {
|
|
31362
|
+
if (frame.opcode >= 8) return { opcode: frame.opcode, payload: frame.payload };
|
|
31363
|
+
if (frame.opcode === OP_CONTINUATION) {
|
|
31364
|
+
if (!this.opcode) return null;
|
|
31365
|
+
this.parts.push(frame.payload);
|
|
31366
|
+
if (!frame.fin) return null;
|
|
31367
|
+
const whole = { opcode: this.opcode, payload: Buffer.concat(this.parts) };
|
|
31368
|
+
this.parts = [];
|
|
31369
|
+
this.opcode = 0;
|
|
31370
|
+
return whole;
|
|
31371
|
+
}
|
|
31372
|
+
if (frame.fin) {
|
|
31373
|
+
this.parts = [];
|
|
31374
|
+
this.opcode = 0;
|
|
31375
|
+
return { opcode: frame.opcode, payload: frame.payload };
|
|
31376
|
+
}
|
|
31377
|
+
this.opcode = frame.opcode;
|
|
31378
|
+
this.parts = [frame.payload];
|
|
31379
|
+
return null;
|
|
31380
|
+
}
|
|
31381
|
+
};
|
|
31331
31382
|
WebSocketServer = class {
|
|
31332
31383
|
port;
|
|
31333
31384
|
server = null;
|
|
@@ -31770,6 +31821,15 @@ var init_websocket = __esm({
|
|
|
31770
31821
|
this.emit("error", err, client);
|
|
31771
31822
|
});
|
|
31772
31823
|
}
|
|
31824
|
+
assemblers = /* @__PURE__ */ new WeakMap();
|
|
31825
|
+
assemblerFor(client) {
|
|
31826
|
+
let a = this.assemblers.get(client);
|
|
31827
|
+
if (!a) {
|
|
31828
|
+
a = new MessageAssembler();
|
|
31829
|
+
this.assemblers.set(client, a);
|
|
31830
|
+
}
|
|
31831
|
+
return a;
|
|
31832
|
+
}
|
|
31773
31833
|
processBuffer(client, buffer, setBuffer) {
|
|
31774
31834
|
let remaining = buffer;
|
|
31775
31835
|
while (remaining.length > 0) {
|
|
@@ -31777,15 +31837,17 @@ var init_websocket = __esm({
|
|
|
31777
31837
|
if (!frame) break;
|
|
31778
31838
|
remaining = remaining.subarray(frame.bytesConsumed);
|
|
31779
31839
|
client.lastActivity = Date.now();
|
|
31780
|
-
|
|
31840
|
+
const whole = this.assemblerFor(client).push(frame);
|
|
31841
|
+
if (!whole) continue;
|
|
31842
|
+
switch (whole.opcode) {
|
|
31781
31843
|
case OP_TEXT:
|
|
31782
|
-
this.emit("message", client,
|
|
31844
|
+
this.emit("message", client, whole.payload.toString("utf-8"));
|
|
31783
31845
|
break;
|
|
31784
31846
|
case OP_BINARY:
|
|
31785
|
-
this.emit("message", client,
|
|
31847
|
+
this.emit("message", client, whole.payload);
|
|
31786
31848
|
break;
|
|
31787
31849
|
case OP_PING: {
|
|
31788
|
-
const pongFrame = buildFrame(OP_PONG,
|
|
31850
|
+
const pongFrame = buildFrame(OP_PONG, whole.payload);
|
|
31789
31851
|
try {
|
|
31790
31852
|
client.socket.write(pongFrame);
|
|
31791
31853
|
} catch {
|
|
@@ -32704,7 +32766,7 @@ var init_job = __esm({
|
|
|
32704
32766
|
|
|
32705
32767
|
// ../core/src/queueBackends/liteBackend.ts
|
|
32706
32768
|
import { mkdirSync as mkdirSync16, readdirSync as readdirSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync12, unlinkSync as unlinkSync7, existsSync as existsSync19 } from "node:fs";
|
|
32707
|
-
import { join as
|
|
32769
|
+
import { join as join25 } from "node:path";
|
|
32708
32770
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
32709
32771
|
var LiteBackend;
|
|
32710
32772
|
var init_liteBackend = __esm({
|
|
@@ -32728,22 +32790,22 @@ var init_liteBackend = __esm({
|
|
|
32728
32790
|
this.visibilityTimeout = visibilityTimeout;
|
|
32729
32791
|
}
|
|
32730
32792
|
ensureDir(queue) {
|
|
32731
|
-
const dir =
|
|
32793
|
+
const dir = join25(this.basePath, queue);
|
|
32732
32794
|
mkdirSync16(dir, { recursive: true });
|
|
32733
32795
|
return dir;
|
|
32734
32796
|
}
|
|
32735
32797
|
ensureFailedDir(queue) {
|
|
32736
|
-
const dir =
|
|
32798
|
+
const dir = join25(this.basePath, queue, "failed");
|
|
32737
32799
|
mkdirSync16(dir, { recursive: true });
|
|
32738
32800
|
return dir;
|
|
32739
32801
|
}
|
|
32740
32802
|
ensureReservedDir(queue) {
|
|
32741
|
-
const dir =
|
|
32803
|
+
const dir = join25(this.basePath, queue, "reserved");
|
|
32742
32804
|
mkdirSync16(dir, { recursive: true });
|
|
32743
32805
|
return dir;
|
|
32744
32806
|
}
|
|
32745
32807
|
reservedPath(queue, jobId) {
|
|
32746
|
-
return
|
|
32808
|
+
return join25(this.ensureReservedDir(queue), `${jobId}.queue-data`);
|
|
32747
32809
|
}
|
|
32748
32810
|
nowIso() {
|
|
32749
32811
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -32781,7 +32843,7 @@ var init_liteBackend = __esm({
|
|
|
32781
32843
|
error: void 0
|
|
32782
32844
|
};
|
|
32783
32845
|
const prefix = this.nextPrefix();
|
|
32784
|
-
writeFileSync12(
|
|
32846
|
+
writeFileSync12(join25(dir, `${prefix}_${id}.queue-data`), JSON.stringify(job, null, 2));
|
|
32785
32847
|
return id;
|
|
32786
32848
|
}
|
|
32787
32849
|
/**
|
|
@@ -32800,7 +32862,7 @@ var init_liteBackend = __esm({
|
|
|
32800
32862
|
}
|
|
32801
32863
|
const candidates = [];
|
|
32802
32864
|
for (const filename of filenames) {
|
|
32803
|
-
const filePath =
|
|
32865
|
+
const filePath = join25(dir, filename);
|
|
32804
32866
|
let job;
|
|
32805
32867
|
try {
|
|
32806
32868
|
job = JSON.parse(readFileSync16(filePath, "utf-8"));
|
|
@@ -32864,7 +32926,7 @@ var init_liteBackend = __esm({
|
|
|
32864
32926
|
return;
|
|
32865
32927
|
}
|
|
32866
32928
|
for (const filename of filenames) {
|
|
32867
|
-
const filePath =
|
|
32929
|
+
const filePath = join25(reservedDir, filename);
|
|
32868
32930
|
let record;
|
|
32869
32931
|
try {
|
|
32870
32932
|
record = JSON.parse(readFileSync16(filePath, "utf-8"));
|
|
@@ -32902,7 +32964,7 @@ var init_liteBackend = __esm({
|
|
|
32902
32964
|
this.reclaimExpired(queue, bridge.getMaxRetries(), this.nowIso());
|
|
32903
32965
|
const now = this.nowIso();
|
|
32904
32966
|
for (const [filename, job] of this.availableCandidates(queue, now)) {
|
|
32905
|
-
const filePath =
|
|
32967
|
+
const filePath = join25(dir, filename);
|
|
32906
32968
|
job.topic = queue;
|
|
32907
32969
|
job.priority = job.priority ?? 0;
|
|
32908
32970
|
this.writeReserved(queue, job);
|
|
@@ -32927,7 +32989,7 @@ var init_liteBackend = __esm({
|
|
|
32927
32989
|
const results = [];
|
|
32928
32990
|
for (const [filename, job] of this.availableCandidates(queue, now)) {
|
|
32929
32991
|
if (results.length >= count) break;
|
|
32930
|
-
const filePath =
|
|
32992
|
+
const filePath = join25(dir, filename);
|
|
32931
32993
|
job.topic = queue;
|
|
32932
32994
|
job.priority = job.priority ?? 0;
|
|
32933
32995
|
this.writeReserved(queue, job);
|
|
@@ -32980,7 +33042,7 @@ var init_liteBackend = __esm({
|
|
|
32980
33042
|
let count = 0;
|
|
32981
33043
|
for (const file of files) {
|
|
32982
33044
|
try {
|
|
32983
|
-
const job = JSON.parse(readFileSync16(
|
|
33045
|
+
const job = JSON.parse(readFileSync16(join25(scanDir, file), "utf-8"));
|
|
32984
33046
|
if (job.status === status2) count++;
|
|
32985
33047
|
} catch {
|
|
32986
33048
|
}
|
|
@@ -32993,28 +33055,28 @@ var init_liteBackend = __esm({
|
|
|
32993
33055
|
try {
|
|
32994
33056
|
const files = readdirSync11(dir).filter((f) => f.endsWith(".queue-data"));
|
|
32995
33057
|
for (const file of files) {
|
|
32996
|
-
unlinkSync7(
|
|
33058
|
+
unlinkSync7(join25(dir, file));
|
|
32997
33059
|
count++;
|
|
32998
33060
|
}
|
|
32999
33061
|
} catch {
|
|
33000
33062
|
}
|
|
33001
|
-
const failedDir =
|
|
33063
|
+
const failedDir = join25(dir, "failed");
|
|
33002
33064
|
try {
|
|
33003
33065
|
if (existsSync19(failedDir)) {
|
|
33004
33066
|
const files = readdirSync11(failedDir).filter((f) => f.endsWith(".queue-data"));
|
|
33005
33067
|
for (const file of files) {
|
|
33006
|
-
unlinkSync7(
|
|
33068
|
+
unlinkSync7(join25(failedDir, file));
|
|
33007
33069
|
count++;
|
|
33008
33070
|
}
|
|
33009
33071
|
}
|
|
33010
33072
|
} catch {
|
|
33011
33073
|
}
|
|
33012
|
-
const reservedDir =
|
|
33074
|
+
const reservedDir = join25(dir, "reserved");
|
|
33013
33075
|
try {
|
|
33014
33076
|
if (existsSync19(reservedDir)) {
|
|
33015
33077
|
const files = readdirSync11(reservedDir).filter((f) => f.endsWith(".queue-data"));
|
|
33016
33078
|
for (const file of files) {
|
|
33017
|
-
unlinkSync7(
|
|
33079
|
+
unlinkSync7(join25(reservedDir, file));
|
|
33018
33080
|
count++;
|
|
33019
33081
|
}
|
|
33020
33082
|
}
|
|
@@ -33037,7 +33099,7 @@ var init_liteBackend = __esm({
|
|
|
33037
33099
|
const files = readdirSync11(dir).filter((f) => f.endsWith(".queue-data")).sort();
|
|
33038
33100
|
for (const file of files) {
|
|
33039
33101
|
try {
|
|
33040
|
-
const job = JSON.parse(readFileSync16(
|
|
33102
|
+
const job = JSON.parse(readFileSync16(join25(dir, file), "utf-8"));
|
|
33041
33103
|
const attempts = job.attempts || 0;
|
|
33042
33104
|
if (attempts > 0 && attempts < maxRetries) {
|
|
33043
33105
|
results.push(job);
|
|
@@ -33060,8 +33122,8 @@ var init_liteBackend = __esm({
|
|
|
33060
33122
|
try {
|
|
33061
33123
|
const queues = readdirSync11(this.basePath);
|
|
33062
33124
|
for (const q of queues) {
|
|
33063
|
-
const failedDir =
|
|
33064
|
-
const filePath =
|
|
33125
|
+
const failedDir = join25(this.basePath, q, "failed");
|
|
33126
|
+
const filePath = join25(failedDir, `${jobId}.queue-data`);
|
|
33065
33127
|
if (existsSync19(filePath)) {
|
|
33066
33128
|
const job = JSON.parse(readFileSync16(filePath, "utf-8"));
|
|
33067
33129
|
job.status = "pending";
|
|
@@ -33070,8 +33132,8 @@ var init_liteBackend = __esm({
|
|
|
33070
33132
|
job.createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
33071
33133
|
job.delayUntil = delaySeconds ? new Date(Date.now() + delaySeconds * 1e3).toISOString() : null;
|
|
33072
33134
|
const prefix = this.nextPrefix();
|
|
33073
|
-
const queueDir =
|
|
33074
|
-
writeFileSync12(
|
|
33135
|
+
const queueDir = join25(this.basePath, q);
|
|
33136
|
+
writeFileSync12(join25(queueDir, `${prefix}_${jobId}.queue-data`), JSON.stringify(job, null, 2));
|
|
33075
33137
|
unlinkSync7(filePath);
|
|
33076
33138
|
return true;
|
|
33077
33139
|
}
|
|
@@ -33087,7 +33149,7 @@ var init_liteBackend = __esm({
|
|
|
33087
33149
|
const files = readdirSync11(failedDir).filter((f) => f.endsWith(".queue-data")).sort();
|
|
33088
33150
|
for (const file of files) {
|
|
33089
33151
|
try {
|
|
33090
|
-
const job = JSON.parse(readFileSync16(
|
|
33152
|
+
const job = JSON.parse(readFileSync16(join25(failedDir, file), "utf-8"));
|
|
33091
33153
|
if ((job.attempts || 0) >= maxRetries) {
|
|
33092
33154
|
job.status = "dead";
|
|
33093
33155
|
results.push(job);
|
|
@@ -33108,7 +33170,7 @@ var init_liteBackend = __esm({
|
|
|
33108
33170
|
const files = readdirSync11(failedDir).filter((f) => f.endsWith(".queue-data"));
|
|
33109
33171
|
for (const file of files) {
|
|
33110
33172
|
try {
|
|
33111
|
-
unlinkSync7(
|
|
33173
|
+
unlinkSync7(join25(failedDir, file));
|
|
33112
33174
|
count++;
|
|
33113
33175
|
} catch {
|
|
33114
33176
|
}
|
|
@@ -33121,9 +33183,9 @@ var init_liteBackend = __esm({
|
|
|
33121
33183
|
const files = readdirSync11(dir).filter((f) => f.endsWith(".queue-data"));
|
|
33122
33184
|
for (const file of files) {
|
|
33123
33185
|
try {
|
|
33124
|
-
const job = JSON.parse(readFileSync16(
|
|
33186
|
+
const job = JSON.parse(readFileSync16(join25(dir, file), "utf-8"));
|
|
33125
33187
|
if (job.status === status2) {
|
|
33126
|
-
unlinkSync7(
|
|
33188
|
+
unlinkSync7(join25(dir, file));
|
|
33127
33189
|
count++;
|
|
33128
33190
|
}
|
|
33129
33191
|
} catch {
|
|
@@ -33147,7 +33209,7 @@ var init_liteBackend = __esm({
|
|
|
33147
33209
|
const files = readdirSync11(failedDir).filter((f) => f.endsWith(".queue-data"));
|
|
33148
33210
|
for (const file of files) {
|
|
33149
33211
|
try {
|
|
33150
|
-
const filePath =
|
|
33212
|
+
const filePath = join25(failedDir, file);
|
|
33151
33213
|
const job = JSON.parse(readFileSync16(filePath, "utf-8"));
|
|
33152
33214
|
if ((job.attempts || 0) >= maxRetries) {
|
|
33153
33215
|
continue;
|
|
@@ -33157,7 +33219,7 @@ var init_liteBackend = __esm({
|
|
|
33157
33219
|
job.createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
33158
33220
|
job.delayUntil = null;
|
|
33159
33221
|
const prefix = this.nextPrefix();
|
|
33160
|
-
writeFileSync12(
|
|
33222
|
+
writeFileSync12(join25(queueDir, `${prefix}_${job.id}.queue-data`), JSON.stringify(job, null, 2));
|
|
33161
33223
|
unlinkSync7(filePath);
|
|
33162
33224
|
count++;
|
|
33163
33225
|
} catch {
|
|
@@ -33177,7 +33239,7 @@ var init_liteBackend = __esm({
|
|
|
33177
33239
|
}
|
|
33178
33240
|
for (const file of files) {
|
|
33179
33241
|
if (!file.includes(id)) continue;
|
|
33180
|
-
const filePath =
|
|
33242
|
+
const filePath = join25(dir, file);
|
|
33181
33243
|
let job;
|
|
33182
33244
|
try {
|
|
33183
33245
|
job = JSON.parse(readFileSync16(filePath, "utf-8"));
|
|
@@ -33225,7 +33287,7 @@ var init_liteBackend = __esm({
|
|
|
33225
33287
|
error: error2
|
|
33226
33288
|
};
|
|
33227
33289
|
const prefix = this.nextPrefix();
|
|
33228
|
-
writeFileSync12(
|
|
33290
|
+
writeFileSync12(join25(dir, `${prefix}_${job.id}.queue-data`), JSON.stringify(jobData, null, 2));
|
|
33229
33291
|
}
|
|
33230
33292
|
/**
|
|
33231
33293
|
* Move the job to the dead-letter (failed/) directory. Terminal until a
|
|
@@ -33245,7 +33307,7 @@ var init_liteBackend = __esm({
|
|
|
33245
33307
|
error: error2,
|
|
33246
33308
|
failedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
33247
33309
|
};
|
|
33248
|
-
writeFileSync12(
|
|
33310
|
+
writeFileSync12(join25(failedDir, `${job.id}.queue-data`), JSON.stringify(jobData, null, 2));
|
|
33249
33311
|
}
|
|
33250
33312
|
/**
|
|
33251
33313
|
* Record a failed attempt.
|
|
@@ -33295,7 +33357,7 @@ var init_liteBackend = __esm({
|
|
|
33295
33357
|
retryJob(queue, job, delaySeconds) {
|
|
33296
33358
|
this.clearReservation(queue, job.id);
|
|
33297
33359
|
try {
|
|
33298
|
-
unlinkSync7(
|
|
33360
|
+
unlinkSync7(join25(this.ensureFailedDir(queue), `${job.id}.queue-data`));
|
|
33299
33361
|
} catch {
|
|
33300
33362
|
}
|
|
33301
33363
|
job.attempts = (job.attempts || 0) + 1;
|
|
@@ -35915,8 +35977,8 @@ ${end}
|
|
|
35915
35977
|
|
|
35916
35978
|
// ../core/src/devAdmin.ts
|
|
35917
35979
|
import { cpus as osCpus } from "node:os";
|
|
35918
|
-
import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, existsSync as existsSync23, readdirSync as readdirSync15, mkdirSync as mkdirSync19, copyFileSync as copyFileSync2, statSync as
|
|
35919
|
-
import { join as
|
|
35980
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, existsSync as existsSync23, readdirSync as readdirSync15, mkdirSync as mkdirSync19, copyFileSync as copyFileSync2, statSync as statSync18, openSync as openSync4, closeSync as closeSync4, fstatSync as fstatSync2, fchmodSync as fchmodSync2, ftruncateSync, constants as constants3, realpathSync as realpathSync6, lstatSync } from "node:fs";
|
|
35981
|
+
import { join as join29, dirname as dirname13, resolve as resolve17, relative as relative9, sep as sep8, basename as basename6 } from "node:path";
|
|
35920
35982
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
35921
35983
|
import { timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
35922
35984
|
function escapeHtml(value) {
|
|
@@ -36060,7 +36122,7 @@ function readQueueDir(dir, topic, status2) {
|
|
|
36060
36122
|
for (const filename of readdirSync15(dir).sort()) {
|
|
36061
36123
|
if (!filename.endsWith(".queue-data")) continue;
|
|
36062
36124
|
try {
|
|
36063
|
-
jobs.push(mapQueueJob(JSON.parse(readFileSync20(
|
|
36125
|
+
jobs.push(mapQueueJob(JSON.parse(readFileSync20(join29(dir, filename), "utf-8")), topic, status2));
|
|
36064
36126
|
} catch {
|
|
36065
36127
|
}
|
|
36066
36128
|
}
|
|
@@ -36163,21 +36225,12 @@ async function proxyToSupervisor(req2, res, downstreamPath) {
|
|
|
36163
36225
|
return;
|
|
36164
36226
|
}
|
|
36165
36227
|
clearTimeout(timer);
|
|
36166
|
-
|
|
36167
|
-
const status2 = upstream.status || 200;
|
|
36168
|
-
try {
|
|
36169
|
-
res.json(JSON.parse(raw), status2);
|
|
36170
|
-
} catch {
|
|
36171
|
-
res.raw.writeHead(status2, {
|
|
36172
|
-
"Content-Type": upstream.headers.get("content-type") ?? "text/plain; charset=utf-8"
|
|
36173
|
-
});
|
|
36174
|
-
res.raw.end(raw);
|
|
36175
|
-
}
|
|
36228
|
+
await relayUpstreamResponse(res, upstream);
|
|
36176
36229
|
}
|
|
36177
36230
|
function resolveDevEnvVar(key) {
|
|
36178
36231
|
const live = process.env[key];
|
|
36179
36232
|
if (live !== void 0 && live !== "") return live;
|
|
36180
|
-
const envPath =
|
|
36233
|
+
const envPath = join29(process.cwd(), ".env");
|
|
36181
36234
|
if (!existsSync23(envPath)) return "";
|
|
36182
36235
|
for (const line of readFileSync20(envPath, "utf-8").split("\n")) {
|
|
36183
36236
|
const t = line.trim();
|
|
@@ -36188,7 +36241,7 @@ function resolveDevEnvVar(key) {
|
|
|
36188
36241
|
return "";
|
|
36189
36242
|
}
|
|
36190
36243
|
function upsertDevEnvVar(key, value) {
|
|
36191
|
-
const envPath =
|
|
36244
|
+
const envPath = join29(process.cwd(), ".env");
|
|
36192
36245
|
const lines = existsSync23(envPath) ? readFileSync20(envPath, "utf-8").split("\n") : [];
|
|
36193
36246
|
let found = false;
|
|
36194
36247
|
const out = [];
|
|
@@ -36219,7 +36272,7 @@ function formatUptime(seconds) {
|
|
|
36219
36272
|
return parts.join(" ");
|
|
36220
36273
|
}
|
|
36221
36274
|
function parseEnvFile() {
|
|
36222
|
-
const envPath =
|
|
36275
|
+
const envPath = join29(process.cwd(), ".env");
|
|
36223
36276
|
const result = {};
|
|
36224
36277
|
if (!existsSync23(envPath)) return result;
|
|
36225
36278
|
const lines = readFileSync20(envPath, "utf-8").split("\n");
|
|
@@ -36235,8 +36288,8 @@ function walkDirRecursive(dir) {
|
|
|
36235
36288
|
const results = [];
|
|
36236
36289
|
if (!existsSync23(dir)) return results;
|
|
36237
36290
|
for (const entry of readdirSync15(dir)) {
|
|
36238
|
-
const full =
|
|
36239
|
-
if (
|
|
36291
|
+
const full = join29(dir, entry);
|
|
36292
|
+
if (statSync18(full).isDirectory()) {
|
|
36240
36293
|
results.push(...walkDirRecursive(full));
|
|
36241
36294
|
} else {
|
|
36242
36295
|
results.push(full);
|
|
@@ -36253,7 +36306,7 @@ function handleGalleryDeploy(router) {
|
|
|
36253
36306
|
return;
|
|
36254
36307
|
}
|
|
36255
36308
|
const galleryDir = resolve17(__devAdminDirname, "..", "gallery");
|
|
36256
|
-
const gallerySrc =
|
|
36309
|
+
const gallerySrc = join29(galleryDir, name, "src");
|
|
36257
36310
|
if (!existsSync23(gallerySrc)) {
|
|
36258
36311
|
res.json({ error: `Gallery item '${name}' not found` }, 404);
|
|
36259
36312
|
return;
|
|
@@ -36263,7 +36316,7 @@ function handleGalleryDeploy(router) {
|
|
|
36263
36316
|
const allFiles = walkDirRecursive(gallerySrc);
|
|
36264
36317
|
for (const srcFile of allFiles) {
|
|
36265
36318
|
const rel = relative9(gallerySrc, srcFile);
|
|
36266
|
-
const dest =
|
|
36319
|
+
const dest = join29(projectSrc, rel);
|
|
36267
36320
|
mkdirSync19(dirname13(dest), { recursive: true });
|
|
36268
36321
|
copyFileSync2(srcFile, dest);
|
|
36269
36322
|
copied.push(rel);
|
|
@@ -36299,7 +36352,7 @@ function realPathOf(target) {
|
|
|
36299
36352
|
tail.unshift(basename6(existing));
|
|
36300
36353
|
existing = dirname13(existing);
|
|
36301
36354
|
}
|
|
36302
|
-
return
|
|
36355
|
+
return join29(realpathSync6(existing), ...tail);
|
|
36303
36356
|
}
|
|
36304
36357
|
function safeJoin(projectRoot3, rel, extraRoots = []) {
|
|
36305
36358
|
try {
|
|
@@ -36614,6 +36667,7 @@ var init_devAdmin = __esm({
|
|
|
36614
36667
|
"../core/src/devAdmin.ts"() {
|
|
36615
36668
|
"use strict";
|
|
36616
36669
|
init_devMailbox();
|
|
36670
|
+
init_upstreamResponse();
|
|
36617
36671
|
init_dotenv();
|
|
36618
36672
|
init_metrics();
|
|
36619
36673
|
init_feedback();
|
|
@@ -36981,7 +37035,7 @@ var init_devAdmin = __esm({
|
|
|
36981
37035
|
const p = (url.searchParams.get("path") || "").toString();
|
|
36982
37036
|
const scanRoot = metricsScanRoot();
|
|
36983
37037
|
let target = p ? safeJoin(process.cwd(), p, [scanRoot]) : "";
|
|
36984
|
-
if (target === null && scanRoot) target = safeJoin(process.cwd(),
|
|
37038
|
+
if (target === null && scanRoot) target = safeJoin(process.cwd(), join29(scanRoot, p), [scanRoot]);
|
|
36985
37039
|
if (target === null) {
|
|
36986
37040
|
res.status(403).json({ error: "Path outside project" });
|
|
36987
37041
|
return;
|
|
@@ -37296,16 +37350,16 @@ var init_devAdmin = __esm({
|
|
|
37296
37350
|
failed: queue.size("failed"),
|
|
37297
37351
|
reserved: queue.size("reserved")
|
|
37298
37352
|
};
|
|
37299
|
-
const topicDir =
|
|
37353
|
+
const topicDir = join29(queueBasePath2(), topic);
|
|
37300
37354
|
const jobs = [];
|
|
37301
37355
|
if (!statusFilter || statusFilter === "pending") {
|
|
37302
37356
|
jobs.push(...readQueueDir(topicDir, topic, "pending"));
|
|
37303
37357
|
}
|
|
37304
37358
|
if (!statusFilter || statusFilter === "reserved") {
|
|
37305
|
-
jobs.push(...readQueueDir(
|
|
37359
|
+
jobs.push(...readQueueDir(join29(topicDir, "reserved"), topic, "reserved"));
|
|
37306
37360
|
}
|
|
37307
37361
|
if (!statusFilter || statusFilter === "failed" || statusFilter === "dead") {
|
|
37308
|
-
jobs.push(...readQueueDir(
|
|
37362
|
+
jobs.push(...readQueueDir(join29(topicDir, "failed"), topic, "dead_letter"));
|
|
37309
37363
|
}
|
|
37310
37364
|
res.json({ stats, jobs });
|
|
37311
37365
|
} catch (e) {
|
|
@@ -37324,7 +37378,7 @@ var init_devAdmin = __esm({
|
|
|
37324
37378
|
if (existsSync23(queueDir)) {
|
|
37325
37379
|
topics = readdirSync15(queueDir).filter((d) => {
|
|
37326
37380
|
try {
|
|
37327
|
-
return
|
|
37381
|
+
return statSync18(join29(queueDir, d)).isDirectory();
|
|
37328
37382
|
} catch {
|
|
37329
37383
|
return false;
|
|
37330
37384
|
}
|
|
@@ -37782,7 +37836,7 @@ var init_devAdmin = __esm({
|
|
|
37782
37836
|
return;
|
|
37783
37837
|
}
|
|
37784
37838
|
try {
|
|
37785
|
-
const envPath =
|
|
37839
|
+
const envPath = join29(process.cwd(), ".env");
|
|
37786
37840
|
const fd = openSync4(envPath, constants3.O_RDWR | constants3.O_APPEND | constants3.O_CREAT | (constants3.O_NOFOLLOW ?? 0) | (constants3.O_NONBLOCK ?? 0), 384);
|
|
37787
37841
|
try {
|
|
37788
37842
|
const info = fstatSync2(fd);
|
|
@@ -37834,13 +37888,13 @@ var init_devAdmin = __esm({
|
|
|
37834
37888
|
if (existsSync23(galleryDir)) {
|
|
37835
37889
|
const entries = readdirSync15(galleryDir).sort();
|
|
37836
37890
|
for (const entry of entries) {
|
|
37837
|
-
const entryPath =
|
|
37838
|
-
const metaFile =
|
|
37839
|
-
if (
|
|
37891
|
+
const entryPath = join29(galleryDir, entry);
|
|
37892
|
+
const metaFile = join29(entryPath, "meta.json");
|
|
37893
|
+
if (statSync18(entryPath).isDirectory() && existsSync23(metaFile)) {
|
|
37840
37894
|
try {
|
|
37841
37895
|
const meta = JSON.parse(readFileSync20(metaFile, "utf-8"));
|
|
37842
37896
|
meta.id = entry;
|
|
37843
|
-
const srcDir =
|
|
37897
|
+
const srcDir = join29(entryPath, "src");
|
|
37844
37898
|
if (existsSync23(srcDir)) {
|
|
37845
37899
|
const allFiles = walkDirRecursive(srcDir);
|
|
37846
37900
|
meta.files = allFiles.map((f) => relative9(srcDir, f));
|
|
@@ -37848,7 +37902,7 @@ var init_devAdmin = __esm({
|
|
|
37848
37902
|
const projectSrc = resolve17(process.cwd(), "src");
|
|
37849
37903
|
if (existsSync23(srcDir) && meta.files) {
|
|
37850
37904
|
meta.deployed = meta.files.every(
|
|
37851
|
-
(f) => existsSync23(
|
|
37905
|
+
(f) => existsSync23(join29(projectSrc, f))
|
|
37852
37906
|
);
|
|
37853
37907
|
} else {
|
|
37854
37908
|
meta.deployed = false;
|
|
@@ -37925,7 +37979,7 @@ var init_devAdmin = __esm({
|
|
|
37925
37979
|
const root = resolve17(process.cwd());
|
|
37926
37980
|
const target = safeJoin(root, rel);
|
|
37927
37981
|
const { branch, gitRoot, status: gitStatus } = await devGitInfo(root);
|
|
37928
|
-
if (!target || !existsSync23(target) || !
|
|
37982
|
+
if (!target || !existsSync23(target) || !statSync18(target).isDirectory()) {
|
|
37929
37983
|
res.json({ path: rel, branch, entries: [], error: "not a directory" });
|
|
37930
37984
|
return;
|
|
37931
37985
|
}
|
|
@@ -37938,13 +37992,13 @@ var init_devAdmin = __esm({
|
|
|
37938
37992
|
const entries = [];
|
|
37939
37993
|
for (const name of readdirSync15(target).sort()) {
|
|
37940
37994
|
if (devFilesHidden(name)) continue;
|
|
37941
|
-
const full =
|
|
37995
|
+
const full = join29(target, name);
|
|
37942
37996
|
const entryRel = relative9(root, full).replace(/\\/g, "/");
|
|
37943
37997
|
if (isSecretPath(entryRel)) continue;
|
|
37944
37998
|
let isDir = false;
|
|
37945
37999
|
let size = null;
|
|
37946
38000
|
try {
|
|
37947
|
-
const st =
|
|
38001
|
+
const st = statSync18(full);
|
|
37948
38002
|
isDir = st.isDirectory();
|
|
37949
38003
|
if (!isDir) size = st.size;
|
|
37950
38004
|
} catch {
|
|
@@ -38489,13 +38543,13 @@ var init_devAdmin = __esm({
|
|
|
38489
38543
|
};
|
|
38490
38544
|
handleDevAdminJs = async (_req, res) => {
|
|
38491
38545
|
const { readFileSync: readFileSync30, existsSync: existsSync37 } = await import("node:fs");
|
|
38492
|
-
const { dirname: dirname18, join:
|
|
38546
|
+
const { dirname: dirname18, join: join41, resolve: resolve29 } = await import("node:path");
|
|
38493
38547
|
const { fileURLToPath: fileURLToPath10 } = await import("node:url");
|
|
38494
38548
|
const dir = dirname18(fileURLToPath10(import.meta.url));
|
|
38495
38549
|
const candidates = [
|
|
38496
|
-
|
|
38550
|
+
join41(dir, "..", "public", "js", "tina4-dev-admin.min.js"),
|
|
38497
38551
|
// src/../public/js/
|
|
38498
|
-
|
|
38552
|
+
join41(dir, "..", "..", "public", "js", "tina4-dev-admin.min.js"),
|
|
38499
38553
|
// deeper nesting
|
|
38500
38554
|
resolve29(process.cwd(), "node_modules", "tina4-nodejs", "packages", "core", "public", "js", "tina4-dev-admin.min.js"),
|
|
38501
38555
|
resolve29(process.cwd(), "public", "js", "tina4-dev-admin.min.js")
|
|
@@ -38528,7 +38582,7 @@ var init_devAdmin = __esm({
|
|
|
38528
38582
|
|
|
38529
38583
|
// ../core/src/i18n.ts
|
|
38530
38584
|
import { readFileSync as readFileSync21, readdirSync as readdirSync16, existsSync as existsSync24 } from "node:fs";
|
|
38531
|
-
import { join as
|
|
38585
|
+
import { join as join30, resolve as resolve18 } from "node:path";
|
|
38532
38586
|
var I18n;
|
|
38533
38587
|
var init_i18n = __esm({
|
|
38534
38588
|
"../core/src/i18n.ts"() {
|
|
@@ -38621,7 +38675,7 @@ var init_i18n = __esm({
|
|
|
38621
38675
|
if (this._translations.has(locale)) {
|
|
38622
38676
|
return;
|
|
38623
38677
|
}
|
|
38624
|
-
const filePath =
|
|
38678
|
+
const filePath = join30(this._localeDir, `${locale}.json`);
|
|
38625
38679
|
if (existsSync24(filePath)) {
|
|
38626
38680
|
try {
|
|
38627
38681
|
const raw = readFileSync21(filePath, "utf-8");
|
|
@@ -38634,7 +38688,7 @@ var init_i18n = __esm({
|
|
|
38634
38688
|
}
|
|
38635
38689
|
}
|
|
38636
38690
|
for (const ext of [".yml", ".yaml"]) {
|
|
38637
|
-
const yamlPath =
|
|
38691
|
+
const yamlPath = join30(this._localeDir, `${locale}${ext}`);
|
|
38638
38692
|
if (existsSync24(yamlPath)) {
|
|
38639
38693
|
try {
|
|
38640
38694
|
const raw = readFileSync21(yamlPath, "utf-8");
|
|
@@ -39865,8 +39919,8 @@ var init_docsAutoDiscovery = __esm({
|
|
|
39865
39919
|
|
|
39866
39920
|
// ../core/src/server.ts
|
|
39867
39921
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
39868
|
-
import { resolve as resolve20, dirname as dirname14, join as
|
|
39869
|
-
import { existsSync as existsSync26, readdirSync as readdirSync17, readFileSync as readFileSync23, statSync as
|
|
39922
|
+
import { resolve as resolve20, dirname as dirname14, join as join32, relative as relative10 } from "node:path";
|
|
39923
|
+
import { existsSync as existsSync26, readdirSync as readdirSync17, readFileSync as readFileSync23, statSync as statSync19 } from "node:fs";
|
|
39870
39924
|
import { isatty } from "node:tty";
|
|
39871
39925
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
39872
39926
|
import { execFileSync as execFileSync3, exec } from "node:child_process";
|
|
@@ -40054,11 +40108,11 @@ async function renderErrorPage(code, data, templatesDir) {
|
|
|
40054
40108
|
}
|
|
40055
40109
|
return instance;
|
|
40056
40110
|
};
|
|
40057
|
-
const userTemplatePath =
|
|
40111
|
+
const userTemplatePath = join32(templatesDir, templateFile);
|
|
40058
40112
|
if (existsSync26(userTemplatePath)) {
|
|
40059
40113
|
return getCachedFrond(templatesDir).render(templateFile, data);
|
|
40060
40114
|
}
|
|
40061
|
-
const builtinTemplatePath =
|
|
40115
|
+
const builtinTemplatePath = join32(BUILTIN_ERROR_TEMPLATES_DIR, templateFile);
|
|
40062
40116
|
if (existsSync26(builtinTemplatePath)) {
|
|
40063
40117
|
return getCachedFrond(BUILTIN_ERROR_TEMPLATES_DIR).render(templateFile, data);
|
|
40064
40118
|
}
|
|
@@ -40078,8 +40132,8 @@ function walkGalleryFiles(dir) {
|
|
|
40078
40132
|
const results = [];
|
|
40079
40133
|
if (!existsSync26(dir)) return results;
|
|
40080
40134
|
for (const f of readdirSync17(dir)) {
|
|
40081
|
-
const full =
|
|
40082
|
-
if (
|
|
40135
|
+
const full = join32(dir, f);
|
|
40136
|
+
if (statSync19(full).isDirectory()) results.push(...walkGalleryFiles(full));
|
|
40083
40137
|
else results.push(full);
|
|
40084
40138
|
}
|
|
40085
40139
|
return results;
|
|
@@ -40091,14 +40145,14 @@ function getGalleryDeployedState() {
|
|
|
40091
40145
|
try {
|
|
40092
40146
|
const entries = readdirSync17(galleryDir).sort();
|
|
40093
40147
|
for (const entry of entries) {
|
|
40094
|
-
const entryPath =
|
|
40095
|
-
const metaFile =
|
|
40096
|
-
if (
|
|
40097
|
-
const srcDir =
|
|
40148
|
+
const entryPath = join32(galleryDir, entry);
|
|
40149
|
+
const metaFile = join32(entryPath, "meta.json");
|
|
40150
|
+
if (statSync19(entryPath).isDirectory() && existsSync26(metaFile)) {
|
|
40151
|
+
const srcDir = join32(entryPath, "src");
|
|
40098
40152
|
if (existsSync26(srcDir)) {
|
|
40099
40153
|
const files = walkGalleryFiles(srcDir);
|
|
40100
40154
|
const projectSrc = resolve20(process.cwd(), "src");
|
|
40101
|
-
state[entry] = files.every((f) => existsSync26(
|
|
40155
|
+
state[entry] = files.every((f) => existsSync26(join32(projectSrc, relative10(srcDir, f))));
|
|
40102
40156
|
} else {
|
|
40103
40157
|
state[entry] = false;
|
|
40104
40158
|
}
|
|
@@ -42147,8 +42201,8 @@ var init_mqtt = __esm({
|
|
|
42147
42201
|
});
|
|
42148
42202
|
|
|
42149
42203
|
// ../core/src/service.ts
|
|
42150
|
-
import { readdirSync as readdirSync18, statSync as
|
|
42151
|
-
import { join as
|
|
42204
|
+
import { readdirSync as readdirSync18, statSync as statSync20, watchFile, unwatchFile } from "node:fs";
|
|
42205
|
+
import { join as join33, extname as extname8 } from "node:path";
|
|
42152
42206
|
import { pathToFileURL } from "node:url";
|
|
42153
42207
|
function matchCronField(field, value) {
|
|
42154
42208
|
if (field === "*") return true;
|
|
@@ -42322,8 +42376,8 @@ var init_service = __esm({
|
|
|
42322
42376
|
for (const entry of entries) {
|
|
42323
42377
|
const ext = extname8(entry);
|
|
42324
42378
|
if (ext !== ".ts" && ext !== ".js") continue;
|
|
42325
|
-
const fullPath =
|
|
42326
|
-
const stat =
|
|
42379
|
+
const fullPath = join33(dir, entry);
|
|
42380
|
+
const stat = statSync20(fullPath);
|
|
42327
42381
|
if (!stat.isFile()) continue;
|
|
42328
42382
|
try {
|
|
42329
42383
|
const fileUrl = pathToFileURL(fullPath).href;
|
|
@@ -42449,7 +42503,7 @@ var init_service = __esm({
|
|
|
42449
42503
|
for (const entry of entries) {
|
|
42450
42504
|
const ext = extname8(entry);
|
|
42451
42505
|
if (ext !== ".ts" && ext !== ".js") continue;
|
|
42452
|
-
const fullPath =
|
|
42506
|
+
const fullPath = join33(dir, entry);
|
|
42453
42507
|
if (watchedFiles.has(fullPath)) continue;
|
|
42454
42508
|
watchedFiles.add(fullPath);
|
|
42455
42509
|
watchFile(fullPath, { interval: 1e3 }, async () => {
|
|
@@ -42709,23 +42763,23 @@ function guessContentType(filename) {
|
|
|
42709
42763
|
}
|
|
42710
42764
|
function buildMultipartBody(boundary, fieldName, filename, fileContent, contentType, extraFields) {
|
|
42711
42765
|
const crlf = "\r\n";
|
|
42712
|
-
const
|
|
42766
|
+
const delimiter4 = `--${boundary}`;
|
|
42713
42767
|
const parts = [];
|
|
42714
42768
|
if (extraFields) {
|
|
42715
42769
|
for (const [key, value] of Object.entries(extraFields)) {
|
|
42716
|
-
parts.push(Buffer.from(
|
|
42770
|
+
parts.push(Buffer.from(delimiter4 + crlf, "utf-8"));
|
|
42717
42771
|
parts.push(Buffer.from(`Content-Disposition: form-data; name="${key}"` + crlf + crlf, "utf-8"));
|
|
42718
42772
|
parts.push(Buffer.from(String(value) + crlf, "utf-8"));
|
|
42719
42773
|
}
|
|
42720
42774
|
}
|
|
42721
|
-
parts.push(Buffer.from(
|
|
42775
|
+
parts.push(Buffer.from(delimiter4 + crlf, "utf-8"));
|
|
42722
42776
|
parts.push(
|
|
42723
42777
|
Buffer.from(`Content-Disposition: form-data; name="${fieldName}"; filename="${filename}"` + crlf, "utf-8")
|
|
42724
42778
|
);
|
|
42725
42779
|
parts.push(Buffer.from(`Content-Type: ${contentType}` + crlf + crlf, "utf-8"));
|
|
42726
42780
|
parts.push(fileContent);
|
|
42727
42781
|
parts.push(Buffer.from(crlf, "utf-8"));
|
|
42728
|
-
parts.push(Buffer.from(
|
|
42782
|
+
parts.push(Buffer.from(delimiter4 + "--" + crlf, "utf-8"));
|
|
42729
42783
|
return Buffer.concat(parts);
|
|
42730
42784
|
}
|
|
42731
42785
|
async function* parseLineStream(chunks) {
|
|
@@ -45203,7 +45257,7 @@ __export(ai_exports, {
|
|
|
45203
45257
|
});
|
|
45204
45258
|
import { existsSync as existsSync28, mkdirSync as mkdirSync22, writeFileSync as writeFileSync19, readFileSync as readFileSync26 } from "node:fs";
|
|
45205
45259
|
import { homedir } from "node:os";
|
|
45206
|
-
import { join as
|
|
45260
|
+
import { join as join34, resolve as resolve21, relative as relative11, dirname as dirname15 } from "node:path";
|
|
45207
45261
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
45208
45262
|
import { execSync as execSync2, execFileSync as execFileSync4 } from "node:child_process";
|
|
45209
45263
|
import { createInterface } from "node:readline";
|
|
@@ -45274,8 +45328,8 @@ function downloadSkillsSync(jobs) {
|
|
|
45274
45328
|
function installSkills(root = ".", targets) {
|
|
45275
45329
|
const ref = skillsRef();
|
|
45276
45330
|
const dests = targets ?? [
|
|
45277
|
-
|
|
45278
|
-
|
|
45331
|
+
join34(resolve21(root), ".claude", "skills"),
|
|
45332
|
+
join34(homedir(), ".claude", "skills")
|
|
45279
45333
|
];
|
|
45280
45334
|
const jobs = [];
|
|
45281
45335
|
const index = /* @__PURE__ */ new Map();
|
|
@@ -45293,9 +45347,9 @@ function installSkills(root = ".", targets) {
|
|
|
45293
45347
|
const base = `https://raw.githubusercontent.com/tina4stack/${spec.repo}/${ref}/.claude/skills/${skill}`;
|
|
45294
45348
|
skillMdUrl[skill] = `${base}/SKILL.md`;
|
|
45295
45349
|
for (const dest of dests) {
|
|
45296
|
-
add(`${base}/SKILL.md`,
|
|
45350
|
+
add(`${base}/SKILL.md`, join34(dest, skill, "SKILL.md"));
|
|
45297
45351
|
for (const r of spec.references) {
|
|
45298
|
-
add(`${base}/references/${r}`,
|
|
45352
|
+
add(`${base}/references/${r}`, join34(dest, skill, "references", r));
|
|
45299
45353
|
}
|
|
45300
45354
|
}
|
|
45301
45355
|
}
|
|
@@ -45307,7 +45361,7 @@ function installSkills(root = ".", targets) {
|
|
|
45307
45361
|
return installed;
|
|
45308
45362
|
}
|
|
45309
45363
|
function isInstalled(root, tool) {
|
|
45310
|
-
return existsSync28(
|
|
45364
|
+
return existsSync28(join34(resolve21(root), tool.contextFile));
|
|
45311
45365
|
}
|
|
45312
45366
|
function showMenu(root = ".") {
|
|
45313
45367
|
const r = resolve21(root);
|
|
@@ -45451,9 +45505,9 @@ function writeOrMerge(contextPath, contextFile, frameworkGuide) {
|
|
|
45451
45505
|
}
|
|
45452
45506
|
function installForTool(root, tool, context) {
|
|
45453
45507
|
const created = [];
|
|
45454
|
-
const contextPath =
|
|
45508
|
+
const contextPath = join34(root, tool.contextFile);
|
|
45455
45509
|
if (tool.configDir) {
|
|
45456
|
-
mkdirSync22(
|
|
45510
|
+
mkdirSync22(join34(root, tool.configDir), { recursive: true });
|
|
45457
45511
|
}
|
|
45458
45512
|
const parentDir = dirname15(contextPath);
|
|
45459
45513
|
mkdirSync22(parentDir, { recursive: true });
|
|
@@ -45491,7 +45545,7 @@ function installTina4Ai() {
|
|
|
45491
45545
|
function installClaudeSkills(root) {
|
|
45492
45546
|
const created = [];
|
|
45493
45547
|
for (const skill of installSkills(root)) {
|
|
45494
|
-
created.push(
|
|
45548
|
+
created.push(join34(".claude", "skills", skill));
|
|
45495
45549
|
console.log(` ${GREEN2}\u2713${RESET2} Installed .claude/skills/${skill} (project + global)`);
|
|
45496
45550
|
}
|
|
45497
45551
|
return created;
|
|
@@ -45834,7 +45888,7 @@ function generateClaudeCodeContext() {
|
|
|
45834
45888
|
try {
|
|
45835
45889
|
const thisDir = dirname15(fileURLToPath8(import.meta.url));
|
|
45836
45890
|
const repoRoot = resolve21(thisDir, "..", "..", "..");
|
|
45837
|
-
const claudeMdPath =
|
|
45891
|
+
const claudeMdPath = join34(repoRoot, "CLAUDE.md");
|
|
45838
45892
|
if (existsSync28(claudeMdPath)) {
|
|
45839
45893
|
return readFileSync26(claudeMdPath, "utf-8");
|
|
45840
45894
|
}
|
|
@@ -49358,6 +49412,7 @@ async function serveProject(options) {
|
|
|
49358
49412
|
|
|
49359
49413
|
// src/commands/migrate.ts
|
|
49360
49414
|
init_dotenv();
|
|
49415
|
+
init_util();
|
|
49361
49416
|
import { existsSync as existsSync30 } from "node:fs";
|
|
49362
49417
|
import { resolve as resolve23 } from "node:path";
|
|
49363
49418
|
async function runMigrations(migrationDir) {
|
|
@@ -49377,12 +49432,7 @@ async function runMigrations(migrationDir) {
|
|
|
49377
49432
|
console.error(" Error: @tina4/orm is required to run migrations.");
|
|
49378
49433
|
process.exit(1);
|
|
49379
49434
|
}
|
|
49380
|
-
|
|
49381
|
-
await initDatabase2();
|
|
49382
|
-
} catch (err) {
|
|
49383
|
-
console.error(` Error initialising database: ${err instanceof Error ? err.message : String(err)}`);
|
|
49384
|
-
process.exit(1);
|
|
49385
|
-
}
|
|
49435
|
+
await initDatabaseOrExit(initDatabase2);
|
|
49386
49436
|
const result = await migrate2(void 0, { migrationsDir: dir });
|
|
49387
49437
|
if (result.applied.length === 0 && result.failed.length === 0) {
|
|
49388
49438
|
console.log(" Nothing to migrate \u2014 all migrations already applied.");
|
|
@@ -49421,6 +49471,7 @@ async function createMigration2(args = []) {
|
|
|
49421
49471
|
|
|
49422
49472
|
// src/commands/migrateStatus.ts
|
|
49423
49473
|
init_dotenv();
|
|
49474
|
+
init_util();
|
|
49424
49475
|
import { resolve as resolve24 } from "node:path";
|
|
49425
49476
|
async function migrateStatus(migrationDir) {
|
|
49426
49477
|
loadEnv();
|
|
@@ -49437,12 +49488,7 @@ async function migrateStatus(migrationDir) {
|
|
|
49437
49488
|
console.error(" Error: @tina4/orm is required to check migration status.");
|
|
49438
49489
|
process.exit(1);
|
|
49439
49490
|
}
|
|
49440
|
-
|
|
49441
|
-
await initDatabase2();
|
|
49442
|
-
} catch (err) {
|
|
49443
|
-
console.error(` Error initialising database: ${err instanceof Error ? err.message : String(err)}`);
|
|
49444
|
-
process.exit(1);
|
|
49445
|
-
}
|
|
49491
|
+
await initDatabaseOrExit(initDatabase2);
|
|
49446
49492
|
ensureMigrationTable2();
|
|
49447
49493
|
const result = await statusFn(void 0, { migrationsDir: dir });
|
|
49448
49494
|
console.log("");
|
|
@@ -49469,6 +49515,7 @@ async function migrateStatus(migrationDir) {
|
|
|
49469
49515
|
|
|
49470
49516
|
// src/commands/migrateRollback.ts
|
|
49471
49517
|
init_dotenv();
|
|
49518
|
+
init_util();
|
|
49472
49519
|
import { resolve as resolve25 } from "node:path";
|
|
49473
49520
|
async function migrateRollback(migrationDir) {
|
|
49474
49521
|
loadEnv();
|
|
@@ -49487,12 +49534,7 @@ async function migrateRollback(migrationDir) {
|
|
|
49487
49534
|
console.error(" Error: @tina4/orm is required to rollback migrations.");
|
|
49488
49535
|
process.exit(1);
|
|
49489
49536
|
}
|
|
49490
|
-
|
|
49491
|
-
await initDatabase2();
|
|
49492
|
-
} catch (err) {
|
|
49493
|
-
console.error(` Error initialising database: ${err instanceof Error ? err.message : String(err)}`);
|
|
49494
|
-
process.exit(1);
|
|
49495
|
-
}
|
|
49537
|
+
await initDatabaseOrExit(initDatabase2);
|
|
49496
49538
|
await ensureMigrationTable2();
|
|
49497
49539
|
const lastBatch = await getLastBatchMigrations2();
|
|
49498
49540
|
if (lastBatch.length === 0) {
|
|
@@ -49562,8 +49604,8 @@ async function listRoutes() {
|
|
|
49562
49604
|
}
|
|
49563
49605
|
|
|
49564
49606
|
// src/commands/test.ts
|
|
49565
|
-
import { existsSync as existsSync32, readdirSync as readdirSync19, readFileSync as readFileSync27, statSync as
|
|
49566
|
-
import { resolve as resolve27, join as
|
|
49607
|
+
import { existsSync as existsSync32, readdirSync as readdirSync19, readFileSync as readFileSync27, statSync as statSync21 } from "node:fs";
|
|
49608
|
+
import { resolve as resolve27, join as join35 } from "node:path";
|
|
49567
49609
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
49568
49610
|
import { execSync as execSync3 } from "node:child_process";
|
|
49569
49611
|
function walkSource(dir) {
|
|
@@ -49575,10 +49617,10 @@ function walkSource(dir) {
|
|
|
49575
49617
|
return out;
|
|
49576
49618
|
}
|
|
49577
49619
|
for (const name of entries) {
|
|
49578
|
-
const full =
|
|
49620
|
+
const full = join35(dir, name);
|
|
49579
49621
|
let st;
|
|
49580
49622
|
try {
|
|
49581
|
-
st =
|
|
49623
|
+
st = statSync21(full);
|
|
49582
49624
|
} catch {
|
|
49583
49625
|
continue;
|
|
49584
49626
|
}
|
|
@@ -49646,7 +49688,7 @@ async function runTests(testPath) {
|
|
|
49646
49688
|
break;
|
|
49647
49689
|
}
|
|
49648
49690
|
try {
|
|
49649
|
-
const files = readdirSync19(fullPath).filter((f) => f.endsWith(".ts")).map((f) =>
|
|
49691
|
+
const files = readdirSync19(fullPath).filter((f) => f.endsWith(".ts")).map((f) => join35(fullPath, f));
|
|
49650
49692
|
testFiles.push(...files);
|
|
49651
49693
|
} catch {
|
|
49652
49694
|
}
|
|
@@ -49675,9 +49717,10 @@ async function runTests(testPath) {
|
|
|
49675
49717
|
}
|
|
49676
49718
|
|
|
49677
49719
|
// src/commands/lint.ts
|
|
49678
|
-
|
|
49720
|
+
init_util();
|
|
49721
|
+
import { existsSync as existsSync33, readdirSync as readdirSync20, readFileSync as readFileSync28, statSync as statSync22, writeFileSync as writeFileSync20 } from "node:fs";
|
|
49679
49722
|
import { createRequire as createRequire9 } from "node:module";
|
|
49680
|
-
import {
|
|
49723
|
+
import { dirname as dirname16, join as join36, relative as relative12 } from "node:path";
|
|
49681
49724
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
49682
49725
|
var LINT_EXTENSIONS = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
|
|
49683
49726
|
var JS_EXTENSIONS = [".js", ".mjs", ".cjs"];
|
|
@@ -49695,10 +49738,10 @@ function walkSource2(dir, out) {
|
|
|
49695
49738
|
}
|
|
49696
49739
|
for (const name of entries) {
|
|
49697
49740
|
if (SKIP_DIRS3.has(name)) continue;
|
|
49698
|
-
const full =
|
|
49741
|
+
const full = join36(dir, name);
|
|
49699
49742
|
let st;
|
|
49700
49743
|
try {
|
|
49701
|
-
st =
|
|
49744
|
+
st = statSync22(full);
|
|
49702
49745
|
} catch {
|
|
49703
49746
|
continue;
|
|
49704
49747
|
}
|
|
@@ -49711,15 +49754,15 @@ function walkSource2(dir, out) {
|
|
|
49711
49754
|
}
|
|
49712
49755
|
function collectAppFiles(cwd) {
|
|
49713
49756
|
const files = [];
|
|
49714
|
-
const srcDir =
|
|
49757
|
+
const srcDir = join36(cwd, "src");
|
|
49715
49758
|
try {
|
|
49716
|
-
if (
|
|
49759
|
+
if (statSync22(srcDir).isDirectory()) walkSource2(srcDir, files);
|
|
49717
49760
|
} catch {
|
|
49718
49761
|
}
|
|
49719
49762
|
for (const entry of ["app.ts", "app.mts", "app.js", "app.mjs"]) {
|
|
49720
|
-
const p =
|
|
49763
|
+
const p = join36(cwd, entry);
|
|
49721
49764
|
try {
|
|
49722
|
-
if (
|
|
49765
|
+
if (statSync22(p).isFile()) files.push(p);
|
|
49723
49766
|
} catch {
|
|
49724
49767
|
}
|
|
49725
49768
|
}
|
|
@@ -49740,15 +49783,15 @@ export default [js.configs.recommended, ...tseslint.configs.recommended];
|
|
|
49740
49783
|
`;
|
|
49741
49784
|
function findEslintConfig(cwd) {
|
|
49742
49785
|
for (const name of ESLINT_FLAT_CONFIGS) {
|
|
49743
|
-
const p =
|
|
49786
|
+
const p = join36(cwd, name);
|
|
49744
49787
|
if (existsSync33(p)) return p;
|
|
49745
49788
|
}
|
|
49746
49789
|
return null;
|
|
49747
49790
|
}
|
|
49748
49791
|
function resolvePackageBin(cwd, pkg, binRelative) {
|
|
49749
|
-
const direct =
|
|
49792
|
+
const direct = join36(cwd, "node_modules", pkg, binRelative);
|
|
49750
49793
|
if (existsSync33(direct)) return direct;
|
|
49751
|
-
const require3 = createRequire9(
|
|
49794
|
+
const require3 = createRequire9(join36(cwd, "package.json"));
|
|
49752
49795
|
let entry;
|
|
49753
49796
|
try {
|
|
49754
49797
|
entry = require3.resolve(pkg);
|
|
@@ -49757,11 +49800,11 @@ function resolvePackageBin(cwd, pkg, binRelative) {
|
|
|
49757
49800
|
}
|
|
49758
49801
|
let dir = dirname16(entry);
|
|
49759
49802
|
for (let i = 0; i < 8; i++) {
|
|
49760
|
-
const pkgJson =
|
|
49803
|
+
const pkgJson = join36(dir, "package.json");
|
|
49761
49804
|
if (existsSync33(pkgJson)) {
|
|
49762
49805
|
try {
|
|
49763
49806
|
if (JSON.parse(readFileSync28(pkgJson, "utf-8")).name === pkg) {
|
|
49764
|
-
const bin =
|
|
49807
|
+
const bin = join36(dir, binRelative);
|
|
49765
49808
|
return existsSync33(bin) ? bin : null;
|
|
49766
49809
|
}
|
|
49767
49810
|
} catch {
|
|
@@ -49777,22 +49820,12 @@ function resolveEslintBin(cwd) {
|
|
|
49777
49820
|
return resolvePackageBin(cwd, "eslint", "bin/eslint.js");
|
|
49778
49821
|
}
|
|
49779
49822
|
function hasPackage(cwd, pkg) {
|
|
49780
|
-
return existsSync33(
|
|
49823
|
+
return existsSync33(join36(cwd, "node_modules", ...pkg.split("/"), "package.json"));
|
|
49781
49824
|
}
|
|
49782
49825
|
function resolveNpm() {
|
|
49783
49826
|
const windows = process.platform === "win32";
|
|
49784
49827
|
const names = windows ? ["npm.cmd", "npm.exe", "npm"] : ["npm"];
|
|
49785
|
-
|
|
49786
|
-
if (!dir) continue;
|
|
49787
|
-
for (const name of names) {
|
|
49788
|
-
const candidate = join35(dir, name);
|
|
49789
|
-
try {
|
|
49790
|
-
if (statSync21(candidate).isFile()) return candidate;
|
|
49791
|
-
} catch {
|
|
49792
|
-
}
|
|
49793
|
-
}
|
|
49794
|
-
}
|
|
49795
|
-
return null;
|
|
49828
|
+
return findOnPath(names);
|
|
49796
49829
|
}
|
|
49797
49830
|
function bootstrapEslint(cwd, noInstall) {
|
|
49798
49831
|
let bin = resolveEslintBin(cwd);
|
|
@@ -49810,7 +49843,7 @@ function bootstrapEslint(cwd, noInstall) {
|
|
|
49810
49843
|
else console.log(" \xB7 could not install eslint \u2014 using the zero-dependency baseline.");
|
|
49811
49844
|
}
|
|
49812
49845
|
if (bin && !config && hasPackage(cwd, "@eslint/js") && hasPackage(cwd, "typescript-eslint")) {
|
|
49813
|
-
const scaffold =
|
|
49846
|
+
const scaffold = join36(cwd, ESLINT_SCAFFOLD_FILE);
|
|
49814
49847
|
try {
|
|
49815
49848
|
writeFileSync20(scaffold, ESLINT_SCAFFOLD, "utf-8");
|
|
49816
49849
|
config = scaffold;
|
|
@@ -49879,7 +49912,7 @@ function runLint(args) {
|
|
|
49879
49912
|
if (fix) {
|
|
49880
49913
|
console.log(" \xB7 --fix needs eslint \u2014 the baseline check has no autofix.");
|
|
49881
49914
|
}
|
|
49882
|
-
if (existsSync33(
|
|
49915
|
+
if (existsSync33(join36(cwd, "tsconfig.json")) && runTypescript(cwd, files)) return;
|
|
49883
49916
|
runJavaScript(cwd, files);
|
|
49884
49917
|
}
|
|
49885
49918
|
|
|
@@ -49888,7 +49921,7 @@ init_generate();
|
|
|
49888
49921
|
|
|
49889
49922
|
// src/commands/seed.ts
|
|
49890
49923
|
import { existsSync as existsSync34, readdirSync as readdirSync21 } from "node:fs";
|
|
49891
|
-
import { resolve as resolve28, join as
|
|
49924
|
+
import { resolve as resolve28, join as join37 } from "node:path";
|
|
49892
49925
|
import { execSync as execSync4 } from "node:child_process";
|
|
49893
49926
|
async function runSeeds(seedPath) {
|
|
49894
49927
|
const cwd = process.cwd();
|
|
@@ -49915,7 +49948,7 @@ async function runSeeds(seedPath) {
|
|
|
49915
49948
|
}
|
|
49916
49949
|
let seedFiles;
|
|
49917
49950
|
try {
|
|
49918
|
-
seedFiles = readdirSync21(seedDir).filter((f) => f.endsWith(".ts")).sort().map((f) =>
|
|
49951
|
+
seedFiles = readdirSync21(seedDir).filter((f) => f.endsWith(".ts")).sort().map((f) => join37(seedDir, f));
|
|
49919
49952
|
} catch {
|
|
49920
49953
|
console.log(" Could not read src/seeds/ directory.");
|
|
49921
49954
|
return;
|
|
@@ -49946,39 +49979,16 @@ async function runSeeds(seedPath) {
|
|
|
49946
49979
|
// src/commands/queue.ts
|
|
49947
49980
|
init_dotenv();
|
|
49948
49981
|
init_queue();
|
|
49949
|
-
|
|
49950
|
-
import {
|
|
49982
|
+
init_util();
|
|
49983
|
+
import { readdirSync as readdirSync22, statSync as statSync23 } from "node:fs";
|
|
49984
|
+
import { extname as extname9, join as join38 } from "node:path";
|
|
49951
49985
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
49952
49986
|
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["once", "json"]);
|
|
49953
|
-
|
|
49954
|
-
const flags = {};
|
|
49955
|
-
const positional = [];
|
|
49956
|
-
let i = 0;
|
|
49957
|
-
while (i < args.length) {
|
|
49958
|
-
const arg = args[i];
|
|
49959
|
-
if (arg.startsWith("--")) {
|
|
49960
|
-
const key = arg.slice(2);
|
|
49961
|
-
if (BOOLEAN_FLAGS.has(key)) {
|
|
49962
|
-
flags[key] = true;
|
|
49963
|
-
i += 1;
|
|
49964
|
-
} else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
|
|
49965
|
-
flags[key] = args[i + 1];
|
|
49966
|
-
i += 2;
|
|
49967
|
-
} else {
|
|
49968
|
-
flags[key] = true;
|
|
49969
|
-
i += 1;
|
|
49970
|
-
}
|
|
49971
|
-
} else {
|
|
49972
|
-
positional.push(arg);
|
|
49973
|
-
i += 1;
|
|
49974
|
-
}
|
|
49975
|
-
}
|
|
49976
|
-
return { flags, positional };
|
|
49977
|
-
}
|
|
49987
|
+
var parseFlags2 = (args) => parseFlags(args, BOOLEAN_FLAGS);
|
|
49978
49988
|
async function resolveQueueHandler(servicesDir, topic) {
|
|
49979
49989
|
let entries;
|
|
49980
49990
|
try {
|
|
49981
|
-
if (!
|
|
49991
|
+
if (!statSync23(servicesDir).isDirectory()) return null;
|
|
49982
49992
|
entries = readdirSync22(servicesDir);
|
|
49983
49993
|
} catch {
|
|
49984
49994
|
return null;
|
|
@@ -49987,9 +49997,9 @@ async function resolveQueueHandler(servicesDir, topic) {
|
|
|
49987
49997
|
if (entry.startsWith("_")) continue;
|
|
49988
49998
|
const ext = extname9(entry);
|
|
49989
49999
|
if (ext !== ".ts" && ext !== ".js") continue;
|
|
49990
|
-
const fullPath =
|
|
50000
|
+
const fullPath = join38(servicesDir, entry);
|
|
49991
50001
|
try {
|
|
49992
|
-
if (!
|
|
50002
|
+
if (!statSync23(fullPath).isFile()) continue;
|
|
49993
50003
|
const mod = await import(pathToFileURL3(fullPath).href);
|
|
49994
50004
|
const config = mod.default ?? mod;
|
|
49995
50005
|
if (config && typeof config === "object" && config.topic === topic && typeof config.handle === "function") {
|
|
@@ -50006,7 +50016,7 @@ function firstJob(yielded) {
|
|
|
50006
50016
|
}
|
|
50007
50017
|
async function queueWork(args) {
|
|
50008
50018
|
loadEnv();
|
|
50009
|
-
const { flags, positional } =
|
|
50019
|
+
const { flags, positional } = parseFlags2(args);
|
|
50010
50020
|
const topic = positional[0] ?? "default";
|
|
50011
50021
|
const once2 = Boolean(flags.once);
|
|
50012
50022
|
let pollSeconds;
|
|
@@ -50058,7 +50068,7 @@ async function queueWork(args) {
|
|
|
50058
50068
|
}
|
|
50059
50069
|
async function queueStats(args) {
|
|
50060
50070
|
loadEnv();
|
|
50061
|
-
const { flags, positional } =
|
|
50071
|
+
const { flags, positional } = parseFlags2(args);
|
|
50062
50072
|
const topic = positional[0] ?? "default";
|
|
50063
50073
|
const queue = new Queue({ topic });
|
|
50064
50074
|
const stats = {
|
|
@@ -50089,7 +50099,7 @@ async function queueStats(args) {
|
|
|
50089
50099
|
}
|
|
50090
50100
|
async function queueRetry(args) {
|
|
50091
50101
|
loadEnv();
|
|
50092
|
-
const { positional } =
|
|
50102
|
+
const { positional } = parseFlags2(args);
|
|
50093
50103
|
const topic = positional[0] ?? "default";
|
|
50094
50104
|
const queue = new Queue({ topic });
|
|
50095
50105
|
const dead = queue.deadLetters(0);
|
|
@@ -50105,7 +50115,7 @@ async function queueRetry(args) {
|
|
|
50105
50115
|
}
|
|
50106
50116
|
async function queueClear(args) {
|
|
50107
50117
|
loadEnv();
|
|
50108
|
-
const { positional } =
|
|
50118
|
+
const { positional } = parseFlags2(args);
|
|
50109
50119
|
const status2 = positional[0] ?? "completed";
|
|
50110
50120
|
const topic = positional[1] ?? "default";
|
|
50111
50121
|
const queue = new Queue({ topic });
|
|
@@ -50139,28 +50149,12 @@ async function queueCommand(args = []) {
|
|
|
50139
50149
|
}
|
|
50140
50150
|
|
|
50141
50151
|
// src/commands/build.ts
|
|
50142
|
-
|
|
50143
|
-
import {
|
|
50152
|
+
init_util();
|
|
50153
|
+
import { accessSync as accessSync2, constants as constants4, existsSync as existsSync35, statSync as statSync24 } from "node:fs";
|
|
50154
|
+
import { basename as basename9, delimiter as delimiter3, join as join39 } from "node:path";
|
|
50144
50155
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
50145
|
-
function
|
|
50146
|
-
|
|
50147
|
-
let i = 0;
|
|
50148
|
-
while (i < args.length) {
|
|
50149
|
-
const arg = args[i];
|
|
50150
|
-
if (arg.startsWith("--")) {
|
|
50151
|
-
const key = arg.slice(2);
|
|
50152
|
-
if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
|
|
50153
|
-
flags[key] = args[i + 1];
|
|
50154
|
-
i += 2;
|
|
50155
|
-
} else {
|
|
50156
|
-
flags[key] = true;
|
|
50157
|
-
i += 1;
|
|
50158
|
-
}
|
|
50159
|
-
} else {
|
|
50160
|
-
i += 1;
|
|
50161
|
-
}
|
|
50162
|
-
}
|
|
50163
|
-
return flags;
|
|
50156
|
+
function parseFlags3(args) {
|
|
50157
|
+
return parseFlags(args).flags;
|
|
50164
50158
|
}
|
|
50165
50159
|
function whichDocker() {
|
|
50166
50160
|
const pathValue = process.env.PATH || process.env.Path || "";
|
|
@@ -50169,10 +50163,10 @@ function whichDocker() {
|
|
|
50169
50163
|
for (const dir of pathValue.split(delimiter3)) {
|
|
50170
50164
|
if (!dir) continue;
|
|
50171
50165
|
for (const ext of exts) {
|
|
50172
|
-
const candidate =
|
|
50166
|
+
const candidate = join39(dir, `docker${ext}`);
|
|
50173
50167
|
try {
|
|
50174
50168
|
accessSync2(candidate, constants4.X_OK);
|
|
50175
|
-
if (
|
|
50169
|
+
if (statSync24(candidate).isFile()) return candidate;
|
|
50176
50170
|
} catch {
|
|
50177
50171
|
}
|
|
50178
50172
|
}
|
|
@@ -50180,14 +50174,14 @@ function whichDocker() {
|
|
|
50180
50174
|
return null;
|
|
50181
50175
|
}
|
|
50182
50176
|
function buildImage(args) {
|
|
50183
|
-
const flags =
|
|
50177
|
+
const flags = parseFlags3(args);
|
|
50184
50178
|
let tag = typeof flags.tag === "string" ? flags.tag : "";
|
|
50185
50179
|
if (!tag) {
|
|
50186
50180
|
const dirName = basename9(process.cwd()).toLowerCase();
|
|
50187
50181
|
tag = `${dirName || "tina4app"}:latest`;
|
|
50188
50182
|
}
|
|
50189
50183
|
const dockerfile = typeof flags.file === "string" && flags.file ? flags.file : "Dockerfile";
|
|
50190
|
-
if (!existsSync35(dockerfile) || !
|
|
50184
|
+
if (!existsSync35(dockerfile) || !statSync24(dockerfile).isFile()) {
|
|
50191
50185
|
console.log(` \u2717 No ${dockerfile} found.`);
|
|
50192
50186
|
console.log(" A Tina4 app deploys as a container. Scaffold a Dockerfile first:");
|
|
50193
50187
|
console.log(" tina4 deploy docker (or: tina4nodejs init)");
|
|
@@ -50214,14 +50208,15 @@ function buildImage(args) {
|
|
|
50214
50208
|
}
|
|
50215
50209
|
|
|
50216
50210
|
// src/bin.ts
|
|
50211
|
+
init_util();
|
|
50217
50212
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
50218
|
-
import { existsSync as existsSync36, readFileSync as readFileSync29
|
|
50219
|
-
import {
|
|
50213
|
+
import { existsSync as existsSync36, readFileSync as readFileSync29 } from "node:fs";
|
|
50214
|
+
import { dirname as dirname17, join as join40 } from "node:path";
|
|
50220
50215
|
import { fileURLToPath as fileURLToPath9, pathToFileURL as pathToFileURL4 } from "node:url";
|
|
50221
50216
|
function readCliVersion() {
|
|
50222
50217
|
let dir = dirname17(fileURLToPath9(import.meta.url));
|
|
50223
50218
|
for (let i = 0; i < 6; i++) {
|
|
50224
|
-
const pkgPath =
|
|
50219
|
+
const pkgPath = join40(dir, "package.json");
|
|
50225
50220
|
if (existsSync36(pkgPath)) {
|
|
50226
50221
|
try {
|
|
50227
50222
|
const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
|
|
@@ -50526,17 +50521,7 @@ var CLIENT_INSTALL_HINT = " Install it: curl -fsSL https://tina4.com/install.s
|
|
|
50526
50521
|
function findClient() {
|
|
50527
50522
|
const windows = process.platform === "win32";
|
|
50528
50523
|
const names = windows ? [`${CLIENT_BINARY}.exe`, `${CLIENT_BINARY}.cmd`, `${CLIENT_BINARY}.bat`] : [CLIENT_BINARY];
|
|
50529
|
-
|
|
50530
|
-
if (!dir) continue;
|
|
50531
|
-
for (const name of names) {
|
|
50532
|
-
const candidate = join39(dir, name);
|
|
50533
|
-
try {
|
|
50534
|
-
if (statSync24(candidate).isFile()) return candidate;
|
|
50535
|
-
} catch {
|
|
50536
|
-
}
|
|
50537
|
-
}
|
|
50538
|
-
}
|
|
50539
|
-
return null;
|
|
50524
|
+
return findOnPath(names);
|
|
50540
50525
|
}
|
|
50541
50526
|
function delegateToClient(command, args) {
|
|
50542
50527
|
if (process.env[DELEGATION_GUARD_ENV] === command) {
|