tina4-nodejs 3.13.149 → 3.13.151
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 +5 -9
- package/packages/cli/dist/bin.js +1074 -521
- package/packages/core/dist/index.js +1071 -516
- package/packages/core/public/bundled-component-provenance.json +2 -2
- package/packages/core/public/js/tina4-dev-admin-split.html +202 -0
- package/packages/core/public/js/tina4-dev-admin.min.js +147 -138
- package/packages/core/src/aiClient.ts +2 -1
- package/packages/core/src/api.ts +2 -1
- package/packages/core/src/auth.ts +1 -1
- package/packages/core/src/cache.ts +6 -1
- package/packages/core/src/devAdmin.ts +209 -123
- package/packages/core/src/dispatchPipeline.ts +4 -0
- package/packages/core/src/docs.ts +5 -3
- package/packages/core/src/errorOverlay.ts +18 -9
- package/packages/core/src/index.ts +2 -1
- package/packages/core/src/mcp.ts +53 -16
- package/packages/core/src/messenger.ts +22 -30
- package/packages/core/src/metrics.ts +5 -1
- package/packages/core/src/middleware.ts +8 -1
- package/packages/core/src/optionalPackage.ts +2 -2
- package/packages/core/src/plan.ts +4 -4
- package/packages/core/src/push.ts +1 -1
- package/packages/core/src/request.ts +185 -25
- package/packages/core/src/router.ts +3 -2
- package/packages/core/src/server.ts +32 -10
- package/packages/core/src/session.ts +44 -0
- package/packages/core/src/slashTrim.ts +39 -0
- package/packages/core/src/wsdl.ts +66 -48
- package/packages/core/templates/crud/form.twig +5 -5
- package/packages/core/templates/crud/table.twig +2 -2
- package/packages/core/templates/errors/302.twig +4 -3
- package/packages/frond/dist/index.js +206 -64
- package/packages/frond/src/engine.ts +278 -69
- package/packages/frond/src/index.ts +1 -1
- package/packages/orm/dist/index.js +1055 -502
- package/packages/orm/src/crudRender.ts +5 -5
- package/packages/orm/src/crudTable.ts +1 -1
- package/packages/orm/src/database.ts +15 -29
- package/packages/orm/src/databaseResult.ts +11 -1
- package/packages/orm/src/realtime/index.ts +1 -0
- package/packages/orm/src/realtime/realtime.ts +2 -1
- package/packages/orm/src/realtime/s3Client.ts +276 -0
- package/packages/orm/src/realtime/storage.ts +19 -60
- package/packages/orm/src/sqlTranslator.ts +58 -42
- package/packages/swagger/dist/index.js +25 -4
- package/packages/swagger/src/generator.ts +7 -4
- package/packages/swagger/src/ui.ts +2 -1
- package/types/core/src/devAdmin.d.ts +40 -0
- package/types/core/src/index.d.ts +2 -1
- package/types/core/src/middleware.d.ts +1 -0
- package/types/core/src/optionalPackage.d.ts +2 -2
- package/types/core/src/request.d.ts +5 -1
- package/types/core/src/session.d.ts +25 -0
- package/types/core/src/slashTrim.d.ts +6 -0
- package/types/frond/src/engine.d.ts +11 -0
- package/types/frond/src/index.d.ts +1 -1
- package/types/orm/src/realtime/index.d.ts +1 -0
- package/types/orm/src/realtime/s3Client.d.ts +48 -0
- package/types/orm/src/realtime/storage.d.ts +9 -7
package/packages/cli/dist/bin.js
CHANGED
|
@@ -14,6 +14,30 @@ var __export = (target, all) => {
|
|
|
14
14
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
// ../core/src/slashTrim.ts
|
|
18
|
+
function rtrimSlashes(s) {
|
|
19
|
+
let end = s.length;
|
|
20
|
+
while (end > 0 && s.charCodeAt(end - 1) === SLASH) end--;
|
|
21
|
+
return end === s.length ? s : s.slice(0, end);
|
|
22
|
+
}
|
|
23
|
+
function trimChar(s, code) {
|
|
24
|
+
let start2 = 0;
|
|
25
|
+
let end = s.length;
|
|
26
|
+
while (start2 < end && s.charCodeAt(start2) === code) start2++;
|
|
27
|
+
while (end > start2 && s.charCodeAt(end - 1) === code) end--;
|
|
28
|
+
return start2 === 0 && end === s.length ? s : s.slice(start2, end);
|
|
29
|
+
}
|
|
30
|
+
function trimSlashes(s) {
|
|
31
|
+
return trimChar(s, SLASH);
|
|
32
|
+
}
|
|
33
|
+
var SLASH;
|
|
34
|
+
var init_slashTrim = __esm({
|
|
35
|
+
"../core/src/slashTrim.ts"() {
|
|
36
|
+
"use strict";
|
|
37
|
+
SLASH = 47;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
17
41
|
// ../core/src/constants.ts
|
|
18
42
|
var HTTP_OK, HTTP_CREATED, HTTP_ACCEPTED, HTTP_NO_CONTENT, HTTP_MOVED, HTTP_REDIRECT, HTTP_NOT_MODIFIED, HTTP_BAD_REQUEST, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, HTTP_NOT_FOUND, HTTP_METHOD_NOT_ALLOWED, HTTP_CONFLICT, HTTP_GONE, HTTP_UNPROCESSABLE, HTTP_TOO_MANY, HTTP_SERVER_ERROR, HTTP_BAD_GATEWAY, HTTP_UNAVAILABLE, APPLICATION_JSON, APPLICATION_XML, APPLICATION_FORM, APPLICATION_OCTET, TEXT_HTML, TEXT_PLAIN, TEXT_CSV, TEXT_XML;
|
|
19
43
|
var init_constants = __esm({
|
|
@@ -1102,7 +1126,7 @@ function resolveAlgorithm(algorithm) {
|
|
|
1102
1126
|
return chosen;
|
|
1103
1127
|
}
|
|
1104
1128
|
function base64urlEncode(data) {
|
|
1105
|
-
return data.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(
|
|
1129
|
+
return data.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/={1,2}$/, "");
|
|
1106
1130
|
}
|
|
1107
1131
|
function base64urlDecode(str) {
|
|
1108
1132
|
let s = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -1381,6 +1405,12 @@ var init_types = __esm({
|
|
|
1381
1405
|
});
|
|
1382
1406
|
|
|
1383
1407
|
// ../orm/src/databaseResult.ts
|
|
1408
|
+
function stripTypeArgs(colType) {
|
|
1409
|
+
const open = colType.indexOf("(");
|
|
1410
|
+
if (open < 0) return colType;
|
|
1411
|
+
const close = colType.indexOf(")", open);
|
|
1412
|
+
return close < 0 ? colType : colType.slice(0, open) + colType.slice(close + 1);
|
|
1413
|
+
}
|
|
1384
1414
|
var DatabaseResult;
|
|
1385
1415
|
var init_databaseResult = __esm({
|
|
1386
1416
|
"../orm/src/databaseResult.ts"() {
|
|
@@ -1563,7 +1593,7 @@ var init_databaseResult = __esm({
|
|
|
1563
1593
|
const [size, decimals] = this._parseTypeSize(colType);
|
|
1564
1594
|
return {
|
|
1565
1595
|
name: col.name,
|
|
1566
|
-
type: colType
|
|
1596
|
+
type: stripTypeArgs(colType),
|
|
1567
1597
|
size,
|
|
1568
1598
|
decimals,
|
|
1569
1599
|
nullable: col.nullable ?? true,
|
|
@@ -2120,12 +2150,49 @@ var init_point = __esm({
|
|
|
2120
2150
|
});
|
|
2121
2151
|
|
|
2122
2152
|
// ../orm/src/sqlTranslator.ts
|
|
2123
|
-
|
|
2153
|
+
function skipQuoted(sql, i, backslashEscapes) {
|
|
2154
|
+
const c = sql[i];
|
|
2155
|
+
const escapeString = c === "'" && (sql[i - 1] === "E" || sql[i - 1] === "e") && !isIdentChar(sql[i - 2]);
|
|
2156
|
+
const backslash = c !== "`" && (escapeString || backslashEscapes);
|
|
2157
|
+
const n = sql.length;
|
|
2158
|
+
i++;
|
|
2159
|
+
while (i < n) {
|
|
2160
|
+
if (backslash && sql[i] === "\\") {
|
|
2161
|
+
i += 2;
|
|
2162
|
+
continue;
|
|
2163
|
+
}
|
|
2164
|
+
if (sql[i] === c) {
|
|
2165
|
+
if (sql[i + 1] === c) {
|
|
2166
|
+
i += 2;
|
|
2167
|
+
continue;
|
|
2168
|
+
}
|
|
2169
|
+
return i + 1;
|
|
2170
|
+
}
|
|
2171
|
+
i++;
|
|
2172
|
+
}
|
|
2173
|
+
return i;
|
|
2174
|
+
}
|
|
2175
|
+
function skipLineComment(sql, i) {
|
|
2176
|
+
while (i < sql.length && sql[i] !== "\n") i++;
|
|
2177
|
+
return i;
|
|
2178
|
+
}
|
|
2179
|
+
function skipBlockComment(sql, i) {
|
|
2180
|
+
const end = sql.indexOf("*/", i + 2);
|
|
2181
|
+
return end === -1 ? sql.length : end + 2;
|
|
2182
|
+
}
|
|
2183
|
+
function skipDollarQuote(sql, i) {
|
|
2184
|
+
const tag = sql.slice(i).match(/^\$([A-Za-z_][A-Za-z0-9_]*)?\$/);
|
|
2185
|
+
if (!tag) return i;
|
|
2186
|
+
const end = sql.indexOf(tag[0], i + tag[0].length);
|
|
2187
|
+
return end === -1 ? sql.length : end + tag[0].length;
|
|
2188
|
+
}
|
|
2189
|
+
var isIdentChar, SQLTranslator, QueryCache;
|
|
2124
2190
|
var init_sqlTranslator = __esm({
|
|
2125
2191
|
"../orm/src/sqlTranslator.ts"() {
|
|
2126
2192
|
"use strict";
|
|
2127
2193
|
init_databaseUrl();
|
|
2128
2194
|
init_point();
|
|
2195
|
+
isIdentChar = (ch) => !!ch && /[A-Za-z0-9_]/.test(ch);
|
|
2129
2196
|
SQLTranslator = class _SQLTranslator {
|
|
2130
2197
|
static SPATIAL_ENGINES = /* @__PURE__ */ new Set(["postgres", "postgresql"]);
|
|
2131
2198
|
static SPATIAL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
@@ -2406,47 +2473,26 @@ var init_sqlTranslator = __esm({
|
|
|
2406
2473
|
static placeholderPositions(sql, options = {}) {
|
|
2407
2474
|
const positions = [];
|
|
2408
2475
|
const n = sql.length;
|
|
2409
|
-
const isIdent = (ch) => !!ch && /[A-Za-z0-9_]/.test(ch);
|
|
2410
2476
|
let i = 0;
|
|
2411
2477
|
while (i < n) {
|
|
2412
2478
|
const c = sql[i];
|
|
2413
2479
|
const next = sql[i + 1];
|
|
2414
2480
|
if (c === "'" || c === '"' || c === "`") {
|
|
2415
|
-
|
|
2416
|
-
const escapeString = c === "'" && (prev === "E" || prev === "e") && !isIdent(sql[i - 2]);
|
|
2417
|
-
const backslash = c !== "`" && (escapeString || options.backslashEscapes === true);
|
|
2418
|
-
i++;
|
|
2419
|
-
while (i < n) {
|
|
2420
|
-
if (backslash && sql[i] === "\\") {
|
|
2421
|
-
i += 2;
|
|
2422
|
-
continue;
|
|
2423
|
-
}
|
|
2424
|
-
if (sql[i] === c) {
|
|
2425
|
-
if (sql[i + 1] === c) {
|
|
2426
|
-
i += 2;
|
|
2427
|
-
continue;
|
|
2428
|
-
}
|
|
2429
|
-
i++;
|
|
2430
|
-
break;
|
|
2431
|
-
}
|
|
2432
|
-
i++;
|
|
2433
|
-
}
|
|
2481
|
+
i = skipQuoted(sql, i, options.backslashEscapes === true);
|
|
2434
2482
|
continue;
|
|
2435
2483
|
}
|
|
2436
2484
|
if (c === "-" && next === "-") {
|
|
2437
|
-
|
|
2485
|
+
i = skipLineComment(sql, i);
|
|
2438
2486
|
continue;
|
|
2439
2487
|
}
|
|
2440
2488
|
if (c === "/" && next === "*") {
|
|
2441
|
-
|
|
2442
|
-
i = end === -1 ? n : end + 2;
|
|
2489
|
+
i = skipBlockComment(sql, i);
|
|
2443
2490
|
continue;
|
|
2444
2491
|
}
|
|
2445
|
-
if (c === "$" && !
|
|
2446
|
-
const
|
|
2447
|
-
if (
|
|
2448
|
-
|
|
2449
|
-
i = end === -1 ? n : end + tag[0].length;
|
|
2492
|
+
if (c === "$" && !isIdentChar(sql[i - 1])) {
|
|
2493
|
+
const past = skipDollarQuote(sql, i);
|
|
2494
|
+
if (past !== i) {
|
|
2495
|
+
i = past;
|
|
2450
2496
|
continue;
|
|
2451
2497
|
}
|
|
2452
2498
|
}
|
|
@@ -2479,7 +2525,7 @@ var init_sqlTranslator = __esm({
|
|
|
2479
2525
|
* → { sql: "INSERT INTO t (x) VALUES (1)", columns: ["id", "name"] }
|
|
2480
2526
|
*/
|
|
2481
2527
|
static parseReturning(sql) {
|
|
2482
|
-
const m = sql.match(/\bRETURNING\s+(
|
|
2528
|
+
const m = sql.match(/\bRETURNING\s+(\S.*)$/i);
|
|
2483
2529
|
if (!m) return { sql, columns: [] };
|
|
2484
2530
|
const columns = m[1].split(",").map((c) => c.trim());
|
|
2485
2531
|
return {
|
|
@@ -2533,7 +2579,12 @@ var init_sqlTranslator = __esm({
|
|
|
2533
2579
|
// The `d` flag records group indices, so the head can be sliced at the exact
|
|
2534
2580
|
// start of the VALUES group rather than by hunting for a parenthesis (the
|
|
2535
2581
|
// column list has parentheses too).
|
|
2536
|
-
static INSERT_VALUES =
|
|
2582
|
+
static INSERT_VALUES = (
|
|
2583
|
+
// ReDoS-safe: the table ref matches `\S(?:[\s\S]*?\S)?` (bounded by non-space
|
|
2584
|
+
// at both ends) so the separator `\s+` before VALUES can't overlap it the way
|
|
2585
|
+
// the old `.+?\s+` did (polynomial on `INSERT INTO ` + a long space run).
|
|
2586
|
+
/^\s*INSERT\s+INTO\s+\S(?:[\s\S]*?\S)?\s+VALUES\s*\(([^()]*)\)\s*$/dis
|
|
2587
|
+
);
|
|
2537
2588
|
/**
|
|
2538
2589
|
* Engines whose lastInsertId reports the FIRST generated id of a multi-row
|
|
2539
2590
|
* INSERT rather than the last. Verified live, not assumed: a 3-row insert
|
|
@@ -7273,7 +7324,7 @@ __export(database_exports, {
|
|
|
7273
7324
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
7274
7325
|
function stripTrailingSemicolons(sql) {
|
|
7275
7326
|
if (!sql) return sql;
|
|
7276
|
-
let stripped = sql.
|
|
7327
|
+
let stripped = sql.trimEnd();
|
|
7277
7328
|
while (stripped.endsWith(";")) {
|
|
7278
7329
|
stripped = stripped.slice(0, -1).replace(/\s+$/, "");
|
|
7279
7330
|
}
|
|
@@ -7440,6 +7491,13 @@ async function createAdapterFromUrl(url, username, password) {
|
|
|
7440
7491
|
}
|
|
7441
7492
|
async function buildAdapterFromUrl(url, username, password) {
|
|
7442
7493
|
const parsed = parseDatabaseUrl(url, username, password);
|
|
7494
|
+
const serverConfig = {
|
|
7495
|
+
host: parsed.host ?? void 0,
|
|
7496
|
+
port: parsed.port ?? void 0,
|
|
7497
|
+
user: parsed.username ?? void 0,
|
|
7498
|
+
password: parsed.password ?? void 0,
|
|
7499
|
+
database: parsed.database || void 0
|
|
7500
|
+
};
|
|
7443
7501
|
switch (parsed.engine) {
|
|
7444
7502
|
case "sqlite": {
|
|
7445
7503
|
const { SQLiteAdapter: SQLiteAdapter2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
@@ -7447,49 +7505,25 @@ async function buildAdapterFromUrl(url, username, password) {
|
|
|
7447
7505
|
}
|
|
7448
7506
|
case "postgres": {
|
|
7449
7507
|
const { PostgresAdapter: PostgresAdapter2 } = await Promise.resolve().then(() => (init_postgres(), postgres_exports));
|
|
7450
|
-
const adapter = new PostgresAdapter2(
|
|
7451
|
-
host: parsed.host ?? void 0,
|
|
7452
|
-
port: parsed.port ?? void 0,
|
|
7453
|
-
user: parsed.username ?? void 0,
|
|
7454
|
-
password: parsed.password ?? void 0,
|
|
7455
|
-
database: parsed.database || void 0
|
|
7456
|
-
});
|
|
7508
|
+
const adapter = new PostgresAdapter2(serverConfig);
|
|
7457
7509
|
await adapter.connect();
|
|
7458
7510
|
return adapter;
|
|
7459
7511
|
}
|
|
7460
7512
|
case "mysql": {
|
|
7461
7513
|
const { MysqlAdapter: MysqlAdapter2 } = await Promise.resolve().then(() => (init_mysql(), mysql_exports));
|
|
7462
|
-
const adapter = new MysqlAdapter2(
|
|
7463
|
-
host: parsed.host ?? void 0,
|
|
7464
|
-
port: parsed.port ?? void 0,
|
|
7465
|
-
user: parsed.username ?? void 0,
|
|
7466
|
-
password: parsed.password ?? void 0,
|
|
7467
|
-
database: parsed.database || void 0
|
|
7468
|
-
});
|
|
7514
|
+
const adapter = new MysqlAdapter2(serverConfig);
|
|
7469
7515
|
await adapter.connect();
|
|
7470
7516
|
return adapter;
|
|
7471
7517
|
}
|
|
7472
7518
|
case "mssql": {
|
|
7473
7519
|
const { MssqlAdapter: MssqlAdapter2 } = await Promise.resolve().then(() => (init_mssql(), mssql_exports));
|
|
7474
|
-
const adapter = new MssqlAdapter2(
|
|
7475
|
-
host: parsed.host ?? void 0,
|
|
7476
|
-
port: parsed.port ?? void 0,
|
|
7477
|
-
user: parsed.username ?? void 0,
|
|
7478
|
-
password: parsed.password ?? void 0,
|
|
7479
|
-
database: parsed.database || void 0
|
|
7480
|
-
});
|
|
7520
|
+
const adapter = new MssqlAdapter2(serverConfig);
|
|
7481
7521
|
await adapter.connect();
|
|
7482
7522
|
return adapter;
|
|
7483
7523
|
}
|
|
7484
7524
|
case "firebird": {
|
|
7485
7525
|
const { FirebirdAdapter: FirebirdAdapter2 } = await Promise.resolve().then(() => (init_firebird(), firebird_exports));
|
|
7486
|
-
const adapter = new FirebirdAdapter2(
|
|
7487
|
-
host: parsed.host ?? void 0,
|
|
7488
|
-
port: parsed.port ?? void 0,
|
|
7489
|
-
user: parsed.username ?? void 0,
|
|
7490
|
-
password: parsed.password ?? void 0,
|
|
7491
|
-
database: parsed.database || void 0
|
|
7492
|
-
});
|
|
7526
|
+
const adapter = new FirebirdAdapter2(serverConfig);
|
|
7493
7527
|
await adapter.connect();
|
|
7494
7528
|
return adapter;
|
|
7495
7529
|
}
|
|
@@ -10225,9 +10259,11 @@ __export(engine_exports, {
|
|
|
10225
10259
|
escapeHtml: () => escapeHtml,
|
|
10226
10260
|
expressionFormCache: () => expressionFormCache,
|
|
10227
10261
|
filterChainCache: () => filterChainCache,
|
|
10262
|
+
frondRange: () => frondRange,
|
|
10228
10263
|
pathParseCache: () => pathParseCache,
|
|
10229
10264
|
setCspNonceProvider: () => setCspNonceProvider,
|
|
10230
|
-
setFormTokenSessionId: () => setFormTokenSessionId
|
|
10265
|
+
setFormTokenSessionId: () => setFormTokenSessionId,
|
|
10266
|
+
setFormTokenSessionProvider: () => setFormTokenSessionProvider
|
|
10231
10267
|
});
|
|
10232
10268
|
import { createHash as createHash3, createHmac as createHmac2, randomBytes as randomBytes2 } from "node:crypto";
|
|
10233
10269
|
import { readFileSync as readFileSync4, existsSync as existsSync6, statSync as statSync4, realpathSync } from "node:fs";
|
|
@@ -10312,6 +10348,14 @@ function renderDump(value) {
|
|
|
10312
10348
|
const escaped = dumped.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
10313
10349
|
return new SafeString(`<pre>${escaped}</pre>`);
|
|
10314
10350
|
}
|
|
10351
|
+
function stripTags(input) {
|
|
10352
|
+
let s = input, prev;
|
|
10353
|
+
do {
|
|
10354
|
+
prev = s;
|
|
10355
|
+
s = s.replace(STRIP_TAGS_RE, "");
|
|
10356
|
+
} while (s !== prev);
|
|
10357
|
+
return s;
|
|
10358
|
+
}
|
|
10315
10359
|
function liveAttr(value) {
|
|
10316
10360
|
return String(value).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
10317
10361
|
}
|
|
@@ -10329,35 +10373,58 @@ function sweepExpiredCache(cache) {
|
|
|
10329
10373
|
if (expiresAt2 <= now) cache.delete(key);
|
|
10330
10374
|
}
|
|
10331
10375
|
}
|
|
10332
|
-
function
|
|
10376
|
+
function extractRawBlocks(source) {
|
|
10333
10377
|
const rawBlocks = [];
|
|
10334
|
-
|
|
10378
|
+
let out = "";
|
|
10379
|
+
let pos = 0;
|
|
10380
|
+
RAW_OPEN_RE.lastIndex = 0;
|
|
10381
|
+
let om;
|
|
10382
|
+
while ((om = RAW_OPEN_RE.exec(source)) !== null) {
|
|
10383
|
+
const openStart = om.index;
|
|
10384
|
+
const openEnd = RAW_OPEN_RE.lastIndex;
|
|
10385
|
+
RAW_CLOSE_RE.lastIndex = openEnd;
|
|
10386
|
+
const cm = RAW_CLOSE_RE.exec(source);
|
|
10387
|
+
if (cm === null) break;
|
|
10335
10388
|
const idx = rawBlocks.length;
|
|
10336
|
-
rawBlocks.push(
|
|
10337
|
-
|
|
10338
|
-
|
|
10389
|
+
rawBlocks.push(source.slice(openEnd, cm.index));
|
|
10390
|
+
out += source.slice(pos, openStart) + `\0RAW_${idx}\0`;
|
|
10391
|
+
pos = RAW_CLOSE_RE.lastIndex;
|
|
10392
|
+
RAW_OPEN_RE.lastIndex = pos;
|
|
10393
|
+
}
|
|
10394
|
+
out += source.slice(pos);
|
|
10395
|
+
return { source: out, rawBlocks };
|
|
10396
|
+
}
|
|
10397
|
+
function tokenize(rawSource) {
|
|
10398
|
+
const { source, rawBlocks } = extractRawBlocks(rawSource);
|
|
10339
10399
|
const tokens = [];
|
|
10400
|
+
const n = source.length;
|
|
10340
10401
|
let pos = 0;
|
|
10341
|
-
|
|
10342
|
-
|
|
10343
|
-
while (
|
|
10344
|
-
const
|
|
10345
|
-
if (
|
|
10346
|
-
|
|
10402
|
+
let scan = 0;
|
|
10403
|
+
const exhausted = { "%}": false, "}}": false, "#}": false };
|
|
10404
|
+
while (scan < n) {
|
|
10405
|
+
const brace = source.indexOf("{", scan);
|
|
10406
|
+
if (brace === -1) break;
|
|
10407
|
+
const kind = TAG_KINDS[source[brace + 1]];
|
|
10408
|
+
if (!kind) {
|
|
10409
|
+
scan = brace + 1;
|
|
10410
|
+
continue;
|
|
10347
10411
|
}
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
|
|
10351
|
-
} else if (raw.startsWith("{{")) {
|
|
10352
|
-
tokens.push(["VAR", raw]);
|
|
10353
|
-
} else if (raw.startsWith("{%")) {
|
|
10354
|
-
tokens.push(["BLOCK", raw]);
|
|
10412
|
+
if (exhausted[kind.close]) {
|
|
10413
|
+
scan = brace + 1;
|
|
10414
|
+
continue;
|
|
10355
10415
|
}
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10416
|
+
const close = source.indexOf(kind.close, brace + 2);
|
|
10417
|
+
if (close === -1) {
|
|
10418
|
+
exhausted[kind.close] = true;
|
|
10419
|
+
scan = brace + 1;
|
|
10420
|
+
continue;
|
|
10421
|
+
}
|
|
10422
|
+
if (brace > pos) tokens.push(["TEXT", source.slice(pos, brace)]);
|
|
10423
|
+
tokens.push([kind.type, source.slice(brace, close + 2)]);
|
|
10424
|
+
pos = close + 2;
|
|
10425
|
+
scan = close + 2;
|
|
10360
10426
|
}
|
|
10427
|
+
if (pos < n) tokens.push(["TEXT", source.slice(pos)]);
|
|
10361
10428
|
if (rawBlocks.length > 0) {
|
|
10362
10429
|
for (let i = 0; i < tokens.length; i++) {
|
|
10363
10430
|
if (tokens[i][0] === "TEXT" && tokens[i][1].includes("\0RAW_")) {
|
|
@@ -10683,26 +10750,123 @@ function evalConcatOrComparison(expr, context) {
|
|
|
10683
10750
|
}
|
|
10684
10751
|
return EXPR_NOT_MATCHED;
|
|
10685
10752
|
}
|
|
10753
|
+
function topLevelPositions(expr) {
|
|
10754
|
+
const positions = [];
|
|
10755
|
+
let inQuote = null;
|
|
10756
|
+
let depth = 0;
|
|
10757
|
+
for (let pos = 0; pos < expr.length; pos++) {
|
|
10758
|
+
const ch = expr[pos];
|
|
10759
|
+
if (inQuote) {
|
|
10760
|
+
if (ch === inQuote) inQuote = null;
|
|
10761
|
+
} else if (ch === '"' || ch === "'") {
|
|
10762
|
+
inQuote = ch;
|
|
10763
|
+
} else if ("([{".includes(ch)) {
|
|
10764
|
+
depth++;
|
|
10765
|
+
} else if (")]}".includes(ch)) {
|
|
10766
|
+
depth--;
|
|
10767
|
+
} else if (depth === 0) {
|
|
10768
|
+
positions.push(pos);
|
|
10769
|
+
}
|
|
10770
|
+
}
|
|
10771
|
+
return positions;
|
|
10772
|
+
}
|
|
10773
|
+
function followsOperand(expr, pos) {
|
|
10774
|
+
return /[\w)\]'"]$/.test(expr.slice(0, pos).trimEnd());
|
|
10775
|
+
}
|
|
10776
|
+
function topLevelArithmeticOperators(expr) {
|
|
10777
|
+
const operators = [];
|
|
10778
|
+
let skipUntil = -1;
|
|
10779
|
+
for (const pos of topLevelPositions(expr)) {
|
|
10780
|
+
if (pos < skipUntil || !"+-*/%".includes(expr[pos])) continue;
|
|
10781
|
+
const pair = expr.slice(pos, pos + 2);
|
|
10782
|
+
const op = pair === "**" || pair === "//" ? pair : expr[pos];
|
|
10783
|
+
skipUntil = pos + op.length;
|
|
10784
|
+
if (followsOperand(expr, pos)) operators.push([pos, op]);
|
|
10785
|
+
}
|
|
10786
|
+
return operators;
|
|
10787
|
+
}
|
|
10788
|
+
function splitArithmetic(expr) {
|
|
10789
|
+
const operators = topLevelArithmeticOperators(expr);
|
|
10790
|
+
for (const level of ARITHMETIC_LEVELS) {
|
|
10791
|
+
const matches = operators.filter(([, op]) => level.includes(op));
|
|
10792
|
+
if (matches.length > 0) return level[0] === "**" ? matches[0] : matches[matches.length - 1];
|
|
10793
|
+
}
|
|
10794
|
+
return null;
|
|
10795
|
+
}
|
|
10686
10796
|
function evalArithmeticExpression(expr, context) {
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10797
|
+
const split = splitArithmetic(expr);
|
|
10798
|
+
if (!split) return EXPR_NOT_MATCHED;
|
|
10799
|
+
const [pos, op] = split;
|
|
10800
|
+
const lVal = evalExpr(expr.slice(0, pos).trim(), context);
|
|
10801
|
+
const rVal = evalExpr(expr.slice(pos + op.length).trim(), context);
|
|
10802
|
+
let lNum = lVal != null ? Number(lVal) : 0;
|
|
10803
|
+
let rNum = rVal != null ? Number(rVal) : 0;
|
|
10804
|
+
if (isNaN(lNum)) lNum = 0;
|
|
10805
|
+
if (isNaN(rNum)) rNum = 0;
|
|
10806
|
+
return ARITHMETIC_OPERATIONS[op](lNum, rNum);
|
|
10807
|
+
}
|
|
10808
|
+
function frondRange(start2, end, step = 1) {
|
|
10809
|
+
const numeric = (value) => typeof value === "number" || typeof value === "string" && NUMERIC_RE.test(value);
|
|
10810
|
+
if (!numeric(start2) || !numeric(end) || !numeric(step)) return [];
|
|
10811
|
+
const first = Math.trunc(Number(start2));
|
|
10812
|
+
const last = Math.trunc(Number(end));
|
|
10813
|
+
const stride = Math.abs(Math.trunc(Number(step)));
|
|
10814
|
+
if (stride === 0) return [];
|
|
10815
|
+
const values = [];
|
|
10816
|
+
if (first <= last) for (let value = first; value <= last; value += stride) values.push(value);
|
|
10817
|
+
else for (let value = first; value >= last; value -= stride) values.push(value);
|
|
10818
|
+
return values;
|
|
10819
|
+
}
|
|
10820
|
+
function findRangeOperator(expr) {
|
|
10821
|
+
let pos = findOutsideQuotes(expr, "..");
|
|
10822
|
+
while (pos >= 0) {
|
|
10823
|
+
const partOfEllipsis = expr.startsWith("...", pos) || pos > 0 && expr[pos - 1] === ".";
|
|
10824
|
+
if (pos > 0 && !partOfEllipsis) return findOutsideQuotes(expr.slice(pos + 2), "|") >= 0 ? -1 : pos;
|
|
10825
|
+
const next = findOutsideQuotes(expr.slice(pos + 2), "..");
|
|
10826
|
+
pos = next >= 0 ? pos + 2 + next : -1;
|
|
10827
|
+
}
|
|
10828
|
+
return -1;
|
|
10829
|
+
}
|
|
10830
|
+
function evalRangeExpression(expr, context) {
|
|
10831
|
+
const pos = findRangeOperator(expr);
|
|
10832
|
+
if (pos < 0) return EXPR_NOT_MATCHED;
|
|
10833
|
+
return frondRange(evalExpr(expr.slice(0, pos).trim(), context), evalExpr(expr.slice(pos + 2).trim(), context));
|
|
10834
|
+
}
|
|
10835
|
+
function closingBracketIndex(expr) {
|
|
10836
|
+
let depth = 0;
|
|
10837
|
+
let inQuote = null;
|
|
10838
|
+
for (let i = 0; i < expr.length; i++) {
|
|
10839
|
+
const ch = expr[i];
|
|
10840
|
+
if (inQuote) {
|
|
10841
|
+
if (ch === inQuote) inQuote = null;
|
|
10842
|
+
} else if (ch === '"' || ch === "'") {
|
|
10843
|
+
inQuote = ch;
|
|
10844
|
+
} else if ("([{".includes(ch)) {
|
|
10845
|
+
depth++;
|
|
10846
|
+
} else if (")]}".includes(ch) && --depth === 0) {
|
|
10847
|
+
return i;
|
|
10703
10848
|
}
|
|
10704
10849
|
}
|
|
10705
|
-
return
|
|
10850
|
+
return -1;
|
|
10851
|
+
}
|
|
10852
|
+
function mapLiteralKey(rawKey, context) {
|
|
10853
|
+
const quoted = rawKey.length >= 2 && (rawKey[0] === '"' || rawKey[0] === "'") && rawKey.endsWith(rawKey[0]);
|
|
10854
|
+
if (quoted) return rawKey.slice(1, -1);
|
|
10855
|
+
return BARE_KEY_RE.test(rawKey) ? rawKey : String(evalExpr(rawKey, context));
|
|
10856
|
+
}
|
|
10857
|
+
function evalMapLiteral(inner, context) {
|
|
10858
|
+
const map = {};
|
|
10859
|
+
for (const pair of inner === "" ? [] : splitArgs(inner)) {
|
|
10860
|
+
const colon = findOutsideQuotes(pair, ":");
|
|
10861
|
+
if (colon > 0) map[mapLiteralKey(pair.slice(0, colon).trim(), context)] = evalExpr(pair.slice(colon + 1).trim(), context);
|
|
10862
|
+
}
|
|
10863
|
+
return map;
|
|
10864
|
+
}
|
|
10865
|
+
function evalCollectionLiteral(expr, context) {
|
|
10866
|
+
if (expr[0] !== "[" && expr[0] !== "{" || closingBracketIndex(expr) !== expr.length - 1) return EXPR_NOT_MATCHED;
|
|
10867
|
+
const inner = expr.slice(1, -1).trim();
|
|
10868
|
+
if (expr[0] === "{") return evalMapLiteral(inner, context);
|
|
10869
|
+
return inner === "" ? [] : splitArgs(inner).map((item) => evalExpr(item.trim(), context));
|
|
10706
10870
|
}
|
|
10707
10871
|
function evalFilterExpression(expr, context) {
|
|
10708
10872
|
if (findOutsideQuotes(expr, "|") >= 0) {
|
|
@@ -11124,12 +11288,12 @@ function splitArgs(raw) {
|
|
|
11124
11288
|
current += ch;
|
|
11125
11289
|
continue;
|
|
11126
11290
|
}
|
|
11127
|
-
if (ch === "(" || ch === "[") {
|
|
11291
|
+
if (ch === "(" || ch === "[" || ch === "{") {
|
|
11128
11292
|
depth++;
|
|
11129
11293
|
current += ch;
|
|
11130
11294
|
continue;
|
|
11131
11295
|
}
|
|
11132
|
-
if (ch === ")" || ch === "]") {
|
|
11296
|
+
if (ch === ")" || ch === "]" || ch === "}") {
|
|
11133
11297
|
depth--;
|
|
11134
11298
|
current += ch;
|
|
11135
11299
|
continue;
|
|
@@ -11294,11 +11458,14 @@ function formatMatch(match, flags, width, prec, type2, arg) {
|
|
|
11294
11458
|
return padFormattedValue(formatValue(type2, precision, arg), flags, width);
|
|
11295
11459
|
}
|
|
11296
11460
|
function _b64url(data) {
|
|
11297
|
-
return data.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(
|
|
11461
|
+
return data.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/={1,2}$/, "");
|
|
11298
11462
|
}
|
|
11299
11463
|
function setFormTokenSessionId(sessionId) {
|
|
11300
11464
|
_formTokenSessionId = sessionId || "";
|
|
11301
11465
|
}
|
|
11466
|
+
function setFormTokenSessionProvider(fn) {
|
|
11467
|
+
_formTokenSessionProvider = fn;
|
|
11468
|
+
}
|
|
11302
11469
|
function setCspNonceProvider(fn) {
|
|
11303
11470
|
_cspNonceProvider = fn;
|
|
11304
11471
|
}
|
|
@@ -11323,8 +11490,9 @@ function _buildFormTokenJwt(descriptor = "") {
|
|
|
11323
11490
|
payload.context = descriptor;
|
|
11324
11491
|
}
|
|
11325
11492
|
}
|
|
11326
|
-
|
|
11327
|
-
|
|
11493
|
+
const sessionId = _formTokenSessionProvider() || _formTokenSessionId;
|
|
11494
|
+
if (sessionId) {
|
|
11495
|
+
payload.session_id = sessionId;
|
|
11328
11496
|
}
|
|
11329
11497
|
const h2 = _b64url(Buffer.from(JSON.stringify(header)));
|
|
11330
11498
|
const p = _b64url(Buffer.from(JSON.stringify(payload)));
|
|
@@ -11340,7 +11508,7 @@ function _generateFormToken(descriptor = "") {
|
|
|
11340
11508
|
function _generateFormTokenValue(descriptor = "") {
|
|
11341
11509
|
return new SafeString(_buildFormTokenJwt(descriptor));
|
|
11342
11510
|
}
|
|
11343
|
-
var SafeString, KNOWN_TAGS, TERMINATOR_TAGS, GATEABLE_TAGS, BLOCK_TAG_ENDS, JSON_UNSAFE_RE, JSON_UNSAFE_MAP, NUMERIC_RE, METHOD_CALL_RE, FN_CALL_RE, IS_NOT_RE, IS_RE, NOT_IN_RE, IN_RE, DIVISIBLE_BY_RE, FILTER_WITH_ARGS_RE, FILTER_COMPARISON_RE, TITLE_WORD_RE, STRIP_TAGS_RE, FAST_FILTERS, FORMAT_RE,
|
|
11511
|
+
var SafeString, KNOWN_TAGS, TERMINATOR_TAGS, GATEABLE_TAGS, BLOCK_TAG_ENDS, JSON_UNSAFE_RE, JSON_UNSAFE_MAP, NUMERIC_RE, METHOD_CALL_RE, FN_CALL_RE, IS_NOT_RE, IS_RE, NOT_IN_RE, IN_RE, DIVISIBLE_BY_RE, FILTER_WITH_ARGS_RE, FILTER_COMPARISON_RE, TITLE_WORD_RE, STRIP_TAGS_RE, FAST_FILTERS, FORMAT_RE, THOUSANDS_RE, LIVE_RE, LIVE_WS_RE, LIVE_SRC_RE, EXTENDS_RE, EXTENDS_RE_GLOBAL, filterChainCache, pathParseCache, TEMPLATE_CACHE_MAX, MEMO_CACHE_MAX, RAW_OPEN_RE, RAW_CLOSE_RE, TAG_KINDS, EXPR_NOT_MATCHED, ARITHMETIC_OPERATIONS, ARITHMETIC_LEVELS, BARE_KEY_RE, EXPR_EVALUATORS, expressionFormCache, VarRef, JS_SAFE_RE, MEDIA_TYPE_RE, SANDBOX_EXPR_KEYWORDS, SANDBOX_IDENT_RE, SANDBOX_STRING_RE, UNSAFE_KEYS, BUILTIN_FILTERS, _formTokenSessionId, _formTokenSessionProvider, _cspNonceProvider, Frond;
|
|
11344
11512
|
var init_engine = __esm({
|
|
11345
11513
|
"../frond/src/engine.ts"() {
|
|
11346
11514
|
"use strict";
|
|
@@ -11442,7 +11610,7 @@ var init_engine = __esm({
|
|
|
11442
11610
|
int: (value) => value ? parseInt(String(value), 10) || 0 : 0,
|
|
11443
11611
|
float: (value) => value ? parseFloat(String(value)) || 0 : 0,
|
|
11444
11612
|
abs: (value) => typeof value === "number" ? Math.abs(value) : value,
|
|
11445
|
-
striptags: (value) => String(value)
|
|
11613
|
+
striptags: (value) => stripTags(String(value)),
|
|
11446
11614
|
first: (value) => Array.isArray(value) ? value[0] ?? null : null,
|
|
11447
11615
|
last: (value) => Array.isArray(value) ? value[value.length - 1] ?? null : null,
|
|
11448
11616
|
keys: (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? Object.keys(value) : [],
|
|
@@ -11456,20 +11624,23 @@ var init_engine = __esm({
|
|
|
11456
11624
|
filter: (value) => Array.isArray(value) ? value.filter(Boolean) : value
|
|
11457
11625
|
};
|
|
11458
11626
|
FORMAT_RE = /%%|%([-+ 0]*)(\d+)?(?:\.(\d+))?([sdifFeEgGxXob])/g;
|
|
11459
|
-
LEADING_WS_RE = /^\s+/;
|
|
11460
|
-
TRAILING_WS_RE = /\s+$/;
|
|
11461
11627
|
THOUSANDS_RE = /\B(?=(\d{3})+(?!\d))/g;
|
|
11462
11628
|
LIVE_RE = /^live\s+["']([^"']+)["']([\s\S]*)$/;
|
|
11463
11629
|
LIVE_WS_RE = /ws\s+["']([^"']+)["']/;
|
|
11464
11630
|
LIVE_SRC_RE = /src\s+["']([^"']+)["']/;
|
|
11465
|
-
EXTENDS_RE = /\{%[-\s]*extends\s+["'](
|
|
11466
|
-
EXTENDS_RE_GLOBAL = /\{%[-\s]*extends\s+["'](
|
|
11631
|
+
EXTENDS_RE = /\{%[-\s]*extends\s+["']([^"']+)["']\s*[-]?%\}/;
|
|
11632
|
+
EXTENDS_RE_GLOBAL = /\{%[-\s]*extends\s+["']([^"']+)["']\s*[-]?%\}/g;
|
|
11467
11633
|
filterChainCache = /* @__PURE__ */ new Map();
|
|
11468
11634
|
pathParseCache = /* @__PURE__ */ new Map();
|
|
11469
11635
|
TEMPLATE_CACHE_MAX = 256;
|
|
11470
11636
|
MEMO_CACHE_MAX = 1024;
|
|
11471
|
-
|
|
11472
|
-
|
|
11637
|
+
RAW_OPEN_RE = /\{%-?\s*raw\s*-?%\}/g;
|
|
11638
|
+
RAW_CLOSE_RE = /\{%-?\s*endraw\s*-?%\}/g;
|
|
11639
|
+
TAG_KINDS = {
|
|
11640
|
+
"%": { close: "%}", type: "BLOCK" },
|
|
11641
|
+
"{": { close: "}}", type: "VAR" },
|
|
11642
|
+
"#": { close: "#}", type: "COMMENT" }
|
|
11643
|
+
};
|
|
11473
11644
|
EXPR_NOT_MATCHED = /* @__PURE__ */ Symbol("frond-expression-not-matched");
|
|
11474
11645
|
ARITHMETIC_OPERATIONS = {
|
|
11475
11646
|
"+": (left, right) => left + right,
|
|
@@ -11480,10 +11651,14 @@ var init_engine = __esm({
|
|
|
11480
11651
|
"%": (left, right) => right !== 0 ? left % right : 0,
|
|
11481
11652
|
"**": (left, right) => left ** right
|
|
11482
11653
|
};
|
|
11654
|
+
ARITHMETIC_LEVELS = [["+", "-"], ["*", "//", "/", "%"], ["**"]];
|
|
11655
|
+
BARE_KEY_RE = /^[A-Za-z_]\w*$/;
|
|
11483
11656
|
EXPR_EVALUATORS = [
|
|
11657
|
+
evalCollectionLiteral,
|
|
11484
11658
|
evalPrimary,
|
|
11485
11659
|
evalConditional,
|
|
11486
11660
|
evalConcatOrComparison,
|
|
11661
|
+
evalRangeExpression,
|
|
11487
11662
|
evalArithmeticExpression,
|
|
11488
11663
|
evalFilterExpression,
|
|
11489
11664
|
evalFunctionExpression
|
|
@@ -11539,8 +11714,8 @@ var init_engine = __esm({
|
|
|
11539
11714
|
},
|
|
11540
11715
|
title: (v) => String(v).replace(TITLE_WORD_RE, (c) => c.toUpperCase()),
|
|
11541
11716
|
trim: (v) => String(v).trim(),
|
|
11542
|
-
ltrim: (v) => String(v).
|
|
11543
|
-
rtrim: (v) => String(v).
|
|
11717
|
+
ltrim: (v) => String(v).trimStart(),
|
|
11718
|
+
rtrim: (v) => String(v).trimEnd(),
|
|
11544
11719
|
length: (v) => {
|
|
11545
11720
|
if (Array.isArray(v)) return v.length;
|
|
11546
11721
|
if (typeof v === "string") return v.length;
|
|
@@ -11581,7 +11756,7 @@ var init_engine = __esm({
|
|
|
11581
11756
|
safe: (v) => v,
|
|
11582
11757
|
escape: (v, ...a) => escapeStrategy(v, a[0] ?? "html"),
|
|
11583
11758
|
e: (v, ...a) => escapeStrategy(v, a[0] ?? "html"),
|
|
11584
|
-
striptags: (v) => String(v)
|
|
11759
|
+
striptags: (v) => stripTags(String(v)),
|
|
11585
11760
|
nl2br: (v) => new SafeString(htmlEscape(String(v)).replace(/\n/g, "<br />\n")),
|
|
11586
11761
|
abs: (v) => typeof v === "number" ? Math.abs(v) : v,
|
|
11587
11762
|
round: (v, decimals) => {
|
|
@@ -11694,6 +11869,7 @@ var init_engine = __esm({
|
|
|
11694
11869
|
js_escape: (v) => new SafeString(jsEscape(v))
|
|
11695
11870
|
};
|
|
11696
11871
|
_formTokenSessionId = "";
|
|
11872
|
+
_formTokenSessionProvider = () => "";
|
|
11697
11873
|
_cspNonceProvider = () => "";
|
|
11698
11874
|
Frond = class _Frond {
|
|
11699
11875
|
// ── Class-level registries ──────────────────────────────────
|
|
@@ -11847,6 +12023,7 @@ var init_engine = __esm({
|
|
|
11847
12023
|
this.globals.form_token = (descriptor) => _generateFormToken(descriptor || "");
|
|
11848
12024
|
this.globals.formTokenValue = (descriptor) => _generateFormTokenValue(descriptor || "");
|
|
11849
12025
|
this.globals.form_token_value = (descriptor) => _generateFormTokenValue(descriptor || "");
|
|
12026
|
+
this.globals.range = frondRange;
|
|
11850
12027
|
this.globals.dump = (value) => renderDump(value);
|
|
11851
12028
|
this.globals.csp_nonce = () => _cspNonceProvider();
|
|
11852
12029
|
for (const [k, v] of _Frond.classFilters) this.filters[k] = v;
|
|
@@ -12183,20 +12360,20 @@ var init_engine = __esm({
|
|
|
12183
12360
|
}
|
|
12184
12361
|
renderVarToken(tokens, index, context, output) {
|
|
12185
12362
|
const [content, stripB, stripA] = stripTag(tokens[index][1]);
|
|
12186
|
-
if (stripB && output.length > 0) output[output.length - 1] = output[output.length - 1].
|
|
12363
|
+
if (stripB && output.length > 0) output[output.length - 1] = output[output.length - 1].trimEnd();
|
|
12187
12364
|
const result = this.evalVar(content, context);
|
|
12188
12365
|
output.push(result !== null && result !== void 0 ? String(result) : "");
|
|
12189
12366
|
if (stripA && index + 1 < tokens.length && tokens[index + 1][0] === "TEXT") {
|
|
12190
|
-
tokens[index + 1] = ["TEXT", tokens[index + 1][1].
|
|
12367
|
+
tokens[index + 1] = ["TEXT", tokens[index + 1][1].trimStart()];
|
|
12191
12368
|
}
|
|
12192
12369
|
return index + 1;
|
|
12193
12370
|
}
|
|
12194
12371
|
renderBlockToken(tokens, index, context, output) {
|
|
12195
12372
|
const [content, stripB, stripA] = stripTag(tokens[index][1]);
|
|
12196
|
-
if (stripB && output.length > 0) output[output.length - 1] = output[output.length - 1].
|
|
12373
|
+
if (stripB && output.length > 0) output[output.length - 1] = output[output.length - 1].trimEnd();
|
|
12197
12374
|
const tag = content.split(/\s+/)[0] || "";
|
|
12198
12375
|
if (stripA && index + 1 < tokens.length && tokens[index + 1][0] === "TEXT") {
|
|
12199
|
-
tokens[index + 1] = ["TEXT", tokens[index + 1][1].
|
|
12376
|
+
tokens[index + 1] = ["TEXT", tokens[index + 1][1].trimStart()];
|
|
12200
12377
|
}
|
|
12201
12378
|
let next;
|
|
12202
12379
|
if (tag === "if" && this.tagPermitted(tag)) {
|
|
@@ -12213,7 +12390,7 @@ var init_engine = __esm({
|
|
|
12213
12390
|
next = block.next;
|
|
12214
12391
|
}
|
|
12215
12392
|
if (stripA && next < tokens.length && tokens[next][0] === "TEXT") {
|
|
12216
|
-
tokens[next] = ["TEXT", tokens[next][1].
|
|
12393
|
+
tokens[next] = ["TEXT", tokens[next][1].trimStart()];
|
|
12217
12394
|
}
|
|
12218
12395
|
return next;
|
|
12219
12396
|
}
|
|
@@ -12472,7 +12649,7 @@ var init_engine = __esm({
|
|
|
12472
12649
|
pushIfBranch(branches, condition, branchTokens, stripBefore) {
|
|
12473
12650
|
if (stripBefore && branchTokens.length > 0 && branchTokens[branchTokens.length - 1][0] === "TEXT") {
|
|
12474
12651
|
const last = branchTokens[branchTokens.length - 1];
|
|
12475
|
-
branchTokens[branchTokens.length - 1] = ["TEXT", last[1].
|
|
12652
|
+
branchTokens[branchTokens.length - 1] = ["TEXT", last[1].trimEnd()];
|
|
12476
12653
|
}
|
|
12477
12654
|
branches.push([condition, branchTokens]);
|
|
12478
12655
|
}
|
|
@@ -12500,7 +12677,7 @@ var init_engine = __esm({
|
|
|
12500
12677
|
} else if (tag === "endif") {
|
|
12501
12678
|
this.pushIfBranch(branches, currentCond, currentTokens, tagStripB);
|
|
12502
12679
|
if (tagStripA && i + 1 < tokens.length && tokens[i + 1][0] === "TEXT") {
|
|
12503
|
-
tokens[i + 1] = ["TEXT", tokens[i + 1][1].
|
|
12680
|
+
tokens[i + 1] = ["TEXT", tokens[i + 1][1].trimStart()];
|
|
12504
12681
|
}
|
|
12505
12682
|
return { branches, next: i + 1 };
|
|
12506
12683
|
} else if ((tag === "elseif" || tag === "elif") && depth === 0) {
|
|
@@ -13286,7 +13463,7 @@ function tableData(opts) {
|
|
|
13286
13463
|
readonly: !opts.editable,
|
|
13287
13464
|
inline_script: opts.inlineScript,
|
|
13288
13465
|
table_name: h(opts.tableName),
|
|
13289
|
-
|
|
13466
|
+
table_id: opts.tableId ? String(opts.tableId) : ""
|
|
13290
13467
|
};
|
|
13291
13468
|
}
|
|
13292
13469
|
var init_crudTable = __esm({
|
|
@@ -13394,13 +13571,13 @@ function renderModalForm(mode, columns, pk, edit) {
|
|
|
13394
13571
|
value: "",
|
|
13395
13572
|
placeholder: h(`Enter ${label.toLowerCase()}`),
|
|
13396
13573
|
type: "text",
|
|
13397
|
-
|
|
13574
|
+
required: false,
|
|
13398
13575
|
input: true
|
|
13399
13576
|
};
|
|
13400
13577
|
});
|
|
13401
13578
|
return renderCrudTemplate("form", {
|
|
13402
13579
|
wrap: true,
|
|
13403
|
-
|
|
13580
|
+
form_id: `form-${mode}`,
|
|
13404
13581
|
action: "",
|
|
13405
13582
|
form_method: "POST",
|
|
13406
13583
|
method_override: null,
|
|
@@ -13457,7 +13634,7 @@ function fieldInputShape(field, base) {
|
|
|
13457
13634
|
case "text":
|
|
13458
13635
|
return { ...base, textarea: true };
|
|
13459
13636
|
case "boolean":
|
|
13460
|
-
return { ...base, checkbox: true,
|
|
13637
|
+
return { ...base, checkbox: true, checked: !!value };
|
|
13461
13638
|
case "select":
|
|
13462
13639
|
return { ...base, select: true, options_html: buildOptions(field.options, value) };
|
|
13463
13640
|
case "date":
|
|
@@ -13480,7 +13657,7 @@ function buildCustomField(field) {
|
|
|
13480
13657
|
label: h(String(label)),
|
|
13481
13658
|
value: h(field.value ?? ""),
|
|
13482
13659
|
placeholder: "",
|
|
13483
|
-
|
|
13660
|
+
required: !!field.required
|
|
13484
13661
|
};
|
|
13485
13662
|
return fieldInputShape(field, base);
|
|
13486
13663
|
}
|
|
@@ -13488,7 +13665,7 @@ function generateForm(fields, options = {}) {
|
|
|
13488
13665
|
const verb = String(options.method ?? "POST").toUpperCase();
|
|
13489
13666
|
return renderCrudTemplate("form", {
|
|
13490
13667
|
wrap: true,
|
|
13491
|
-
|
|
13668
|
+
form_id: "",
|
|
13492
13669
|
action: h(options.action ?? "/"),
|
|
13493
13670
|
form_method: h(verb),
|
|
13494
13671
|
method_override: ["PUT", "PATCH", "DELETE"].includes(verb) ? verb : null,
|
|
@@ -18139,20 +18316,210 @@ var init_attachment = __esm({
|
|
|
18139
18316
|
}
|
|
18140
18317
|
});
|
|
18141
18318
|
|
|
18319
|
+
// ../orm/src/realtime/s3Client.ts
|
|
18320
|
+
import { createHash as createHash4, createHmac as createHmac3 } from "node:crypto";
|
|
18321
|
+
function retryAfterSeconds(raw) {
|
|
18322
|
+
if (raw == null) return null;
|
|
18323
|
+
const n = Number(raw);
|
|
18324
|
+
return Number.isFinite(n) ? Math.max(0, n) : null;
|
|
18325
|
+
}
|
|
18326
|
+
function uriEncode(value, isPath) {
|
|
18327
|
+
let out = "";
|
|
18328
|
+
for (const byte of Buffer.from(value, "utf8")) {
|
|
18329
|
+
const ch = String.fromCharCode(byte);
|
|
18330
|
+
if (UNRESERVED.test(ch) || isPath && ch === "/") out += ch;
|
|
18331
|
+
else out += "%" + byte.toString(16).toUpperCase().padStart(2, "0");
|
|
18332
|
+
}
|
|
18333
|
+
return out;
|
|
18334
|
+
}
|
|
18335
|
+
function sha256Hex2(data) {
|
|
18336
|
+
return createHash4("sha256").update(data).digest("hex");
|
|
18337
|
+
}
|
|
18338
|
+
function hmac(key, msg) {
|
|
18339
|
+
return createHmac3("sha256", key).update(msg, "utf8").digest();
|
|
18340
|
+
}
|
|
18341
|
+
var ALGORITHM, SERVICE, UNRESERVED, MAX_RETRIES, BACKOFF_BASE, BACKOFF_CAP, S3Error, S3ConfigError, sleep, S3Client;
|
|
18342
|
+
var init_s3Client = __esm({
|
|
18343
|
+
"../orm/src/realtime/s3Client.ts"() {
|
|
18344
|
+
"use strict";
|
|
18345
|
+
ALGORITHM = "AWS4-HMAC-SHA256";
|
|
18346
|
+
SERVICE = "s3";
|
|
18347
|
+
UNRESERVED = /[A-Za-z0-9\-_.~]/;
|
|
18348
|
+
MAX_RETRIES = 2;
|
|
18349
|
+
BACKOFF_BASE = 0.5;
|
|
18350
|
+
BACKOFF_CAP = 20;
|
|
18351
|
+
S3Error = class extends Error {
|
|
18352
|
+
constructor(status2, message) {
|
|
18353
|
+
super(message);
|
|
18354
|
+
this.status = status2;
|
|
18355
|
+
this.name = "S3Error";
|
|
18356
|
+
}
|
|
18357
|
+
status;
|
|
18358
|
+
/** Seconds from a Retry-After header in its delta-seconds form, else null. */
|
|
18359
|
+
retryAfter = null;
|
|
18360
|
+
};
|
|
18361
|
+
S3ConfigError = class extends Error {
|
|
18362
|
+
constructor(message) {
|
|
18363
|
+
super(message);
|
|
18364
|
+
this.name = "S3ConfigError";
|
|
18365
|
+
}
|
|
18366
|
+
};
|
|
18367
|
+
sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
18368
|
+
S3Client = class {
|
|
18369
|
+
scheme;
|
|
18370
|
+
host;
|
|
18371
|
+
// authority (host[:port]) — matches the Host header
|
|
18372
|
+
prefix;
|
|
18373
|
+
// path an endpoint carries (https://host/s3 -> "/s3"), "" if none
|
|
18374
|
+
region;
|
|
18375
|
+
accessKey;
|
|
18376
|
+
secretKey;
|
|
18377
|
+
timeout;
|
|
18378
|
+
constructor(opts = {}) {
|
|
18379
|
+
this.region = opts.region || "us-east-1";
|
|
18380
|
+
this.accessKey = opts.accessKey || "";
|
|
18381
|
+
this.secretKey = opts.secretKey || "";
|
|
18382
|
+
this.timeout = opts.timeout ?? 3e4;
|
|
18383
|
+
let base = opts.endpoint || `https://s3.${this.region}.amazonaws.com`;
|
|
18384
|
+
while (base.endsWith("/")) base = base.slice(0, -1);
|
|
18385
|
+
const m = /^([a-z][a-z0-9+.-]*):\/\/([^/]+)(\/.*)?$/i.exec(base);
|
|
18386
|
+
this.scheme = m ? m[1] : "https";
|
|
18387
|
+
this.host = m ? m[2] : base;
|
|
18388
|
+
let p = m && m[3] ? m[3] : "";
|
|
18389
|
+
while (p.endsWith("/")) p = p.slice(0, -1);
|
|
18390
|
+
this.prefix = p;
|
|
18391
|
+
}
|
|
18392
|
+
// -- public API (the subset S3Storage uses) --------------------------------
|
|
18393
|
+
async putObject(bucket, key, data, contentType = "application/octet-stream") {
|
|
18394
|
+
const body = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
18395
|
+
await this.request("PUT", this.canonicalUri(bucket, key), body, { "content-type": contentType });
|
|
18396
|
+
}
|
|
18397
|
+
async getObject(bucket, key) {
|
|
18398
|
+
return (await this.request("GET", this.canonicalUri(bucket, key), Buffer.alloc(0))).body;
|
|
18399
|
+
}
|
|
18400
|
+
async deleteObject(bucket, key) {
|
|
18401
|
+
await this.request("DELETE", this.canonicalUri(bucket, key), Buffer.alloc(0));
|
|
18402
|
+
}
|
|
18403
|
+
async headObject(bucket, key) {
|
|
18404
|
+
await this.request("HEAD", this.canonicalUri(bucket, key), Buffer.alloc(0));
|
|
18405
|
+
}
|
|
18406
|
+
/** Create the bucket (path-style `PUT /<bucket>`); an already-owned bucket (409) is success. */
|
|
18407
|
+
async createBucket(bucket) {
|
|
18408
|
+
try {
|
|
18409
|
+
await this.request("PUT", `${this.prefix}/${uriEncode(bucket, true)}`, Buffer.alloc(0));
|
|
18410
|
+
} catch (e) {
|
|
18411
|
+
if (!(e instanceof S3Error) || e.status !== 409) throw e;
|
|
18412
|
+
}
|
|
18413
|
+
}
|
|
18414
|
+
/** A URL that fetches the object directly, signed via SigV4 query params. */
|
|
18415
|
+
presignedGetUrl(bucket, key, expires = 3600) {
|
|
18416
|
+
this.requireCredentials();
|
|
18417
|
+
const { amzDate, dateStamp } = this.now();
|
|
18418
|
+
const uri = this.canonicalUri(bucket, key);
|
|
18419
|
+
const scope = `${dateStamp}/${this.region}/${SERVICE}/aws4_request`;
|
|
18420
|
+
const query = {
|
|
18421
|
+
"X-Amz-Algorithm": ALGORITHM,
|
|
18422
|
+
"X-Amz-Credential": `${this.accessKey}/${scope}`,
|
|
18423
|
+
"X-Amz-Date": amzDate,
|
|
18424
|
+
"X-Amz-Expires": String(expires),
|
|
18425
|
+
"X-Amz-SignedHeaders": "host"
|
|
18426
|
+
};
|
|
18427
|
+
const canonicalQs = this.canonicalQuery(query);
|
|
18428
|
+
const canonicalRequest = ["GET", uri, canonicalQs, `host:${this.host}
|
|
18429
|
+
`, "host", "UNSIGNED-PAYLOAD"].join("\n");
|
|
18430
|
+
const signature = this.sign(canonicalRequest, amzDate, dateStamp, scope);
|
|
18431
|
+
return `${this.scheme}://${this.host}${uri}?${canonicalQs}&X-Amz-Signature=${signature}`;
|
|
18432
|
+
}
|
|
18433
|
+
// -- signing + transport ----------------------------------------------------
|
|
18434
|
+
requireCredentials() {
|
|
18435
|
+
if (!this.accessKey || !this.secretKey) {
|
|
18436
|
+
throw new S3ConfigError(
|
|
18437
|
+
"S3 credentials are not set: set TINA4_STORAGE_KEY and TINA4_STORAGE_SECRET"
|
|
18438
|
+
);
|
|
18439
|
+
}
|
|
18440
|
+
}
|
|
18441
|
+
now() {
|
|
18442
|
+
const iso2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:-]|\.\d{3}/g, "");
|
|
18443
|
+
return { amzDate: iso2, dateStamp: iso2.slice(0, 8) };
|
|
18444
|
+
}
|
|
18445
|
+
canonicalUri(bucket, key) {
|
|
18446
|
+
return `${this.prefix}/${uriEncode(bucket, true)}/${uriEncode(key, true)}`;
|
|
18447
|
+
}
|
|
18448
|
+
canonicalQuery(query) {
|
|
18449
|
+
return Object.keys(query).sort().map((k) => `${uriEncode(k, false)}=${uriEncode(query[k], false)}`).join("&");
|
|
18450
|
+
}
|
|
18451
|
+
signingKey(dateStamp) {
|
|
18452
|
+
const kDate = hmac(`AWS4${this.secretKey}`, dateStamp);
|
|
18453
|
+
const kRegion = hmac(kDate, this.region);
|
|
18454
|
+
const kService = hmac(kRegion, SERVICE);
|
|
18455
|
+
return hmac(kService, "aws4_request");
|
|
18456
|
+
}
|
|
18457
|
+
sign(canonicalRequest, amzDate, dateStamp, scope) {
|
|
18458
|
+
const stringToSign = [ALGORITHM, amzDate, scope, sha256Hex2(canonicalRequest)].join("\n");
|
|
18459
|
+
return createHmac3("sha256", this.signingKey(dateStamp)).update(stringToSign, "utf8").digest("hex");
|
|
18460
|
+
}
|
|
18461
|
+
async request(method, uri, body, extraHeaders = {}) {
|
|
18462
|
+
this.requireCredentials();
|
|
18463
|
+
for (let attempt = 0; ; attempt++) {
|
|
18464
|
+
const last = attempt === MAX_RETRIES;
|
|
18465
|
+
let delay2 = null;
|
|
18466
|
+
try {
|
|
18467
|
+
return await this.send(method, uri, body, extraHeaders);
|
|
18468
|
+
} catch (e) {
|
|
18469
|
+
if (e instanceof S3Error) {
|
|
18470
|
+
if (last || !(e.status === 429 || e.status >= 500)) throw e;
|
|
18471
|
+
delay2 = e.retryAfter;
|
|
18472
|
+
} else {
|
|
18473
|
+
if (last) throw e;
|
|
18474
|
+
delay2 = null;
|
|
18475
|
+
}
|
|
18476
|
+
}
|
|
18477
|
+
if (delay2 == null) delay2 = Math.random() * (BACKOFF_BASE * 2 ** attempt);
|
|
18478
|
+
await sleep(Math.min(delay2, BACKOFF_CAP) * 1e3);
|
|
18479
|
+
}
|
|
18480
|
+
}
|
|
18481
|
+
async send(method, uri, body, extraHeaders = {}) {
|
|
18482
|
+
const { amzDate, dateStamp } = this.now();
|
|
18483
|
+
const payloadHash = sha256Hex2(body);
|
|
18484
|
+
const signed = {
|
|
18485
|
+
host: this.host,
|
|
18486
|
+
"x-amz-content-sha256": payloadHash,
|
|
18487
|
+
"x-amz-date": amzDate
|
|
18488
|
+
};
|
|
18489
|
+
const signedKeys = Object.keys(signed).sort();
|
|
18490
|
+
const canonicalHeaders = signedKeys.map((k) => `${k}:${signed[k]}
|
|
18491
|
+
`).join("");
|
|
18492
|
+
const signedHeaders = signedKeys.join(";");
|
|
18493
|
+
const canonicalRequest = [method, uri, "", canonicalHeaders, signedHeaders, payloadHash].join("\n");
|
|
18494
|
+
const scope = `${dateStamp}/${this.region}/${SERVICE}/aws4_request`;
|
|
18495
|
+
const signature = this.sign(canonicalRequest, amzDate, dateStamp, scope);
|
|
18496
|
+
const authorization = `${ALGORITHM} Credential=${this.accessKey}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
18497
|
+
const headers = {
|
|
18498
|
+
Authorization: authorization,
|
|
18499
|
+
"x-amz-content-sha256": payloadHash,
|
|
18500
|
+
"x-amz-date": amzDate,
|
|
18501
|
+
...extraHeaders
|
|
18502
|
+
};
|
|
18503
|
+
const url = `${this.scheme}://${this.host}${uri}`;
|
|
18504
|
+
const init = { method, headers, redirect: "manual" };
|
|
18505
|
+
if (method === "PUT" || method === "POST") init.body = body;
|
|
18506
|
+
if (AbortSignal.timeout) init.signal = AbortSignal.timeout(this.timeout);
|
|
18507
|
+
const response = await fetch(url, init);
|
|
18508
|
+
if (response.status < 200 || response.status >= 300) {
|
|
18509
|
+
const err = new S3Error(response.status, `${method} ${uri}: HTTP ${response.status}`);
|
|
18510
|
+
err.retryAfter = retryAfterSeconds(response.headers.get("retry-after"));
|
|
18511
|
+
throw err;
|
|
18512
|
+
}
|
|
18513
|
+
return { status: response.status, body: Buffer.from(await response.arrayBuffer()) };
|
|
18514
|
+
}
|
|
18515
|
+
};
|
|
18516
|
+
}
|
|
18517
|
+
});
|
|
18518
|
+
|
|
18142
18519
|
// ../orm/src/realtime/storage.ts
|
|
18143
18520
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
18144
18521
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, statSync as statSync5 } from "node:fs";
|
|
18145
18522
|
import { resolve as resolve7, sep as sep3 } from "node:path";
|
|
18146
|
-
import { createRequire as createRequire6 } from "node:module";
|
|
18147
|
-
function loadAwsSdk(packageName) {
|
|
18148
|
-
try {
|
|
18149
|
-
return require2(packageName);
|
|
18150
|
-
} catch (error2) {
|
|
18151
|
-
const missing = error2?.code === "MODULE_NOT_FOUND" && String(error2?.message ?? "").includes(`'${packageName}'`);
|
|
18152
|
-
if (!missing) throw error2;
|
|
18153
|
-
throw optionalPackageMissing("S3Storage", S3_PACKAGES);
|
|
18154
|
-
}
|
|
18155
|
-
}
|
|
18156
18523
|
function storageKey(filename = "") {
|
|
18157
18524
|
let ext = "";
|
|
18158
18525
|
if (filename && filename.includes(".")) {
|
|
@@ -18177,14 +18544,12 @@ function selectStorage(storage) {
|
|
|
18177
18544
|
}
|
|
18178
18545
|
return new LocalStorage();
|
|
18179
18546
|
}
|
|
18180
|
-
var
|
|
18547
|
+
var UNSAFE, LocalStorage, S3Storage;
|
|
18181
18548
|
var init_storage = __esm({
|
|
18182
18549
|
"../orm/src/realtime/storage.ts"() {
|
|
18183
18550
|
"use strict";
|
|
18184
18551
|
init_src3();
|
|
18185
|
-
|
|
18186
|
-
require2 = createRequire6(import.meta.url);
|
|
18187
|
-
S3_PACKAGES = ["@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner"];
|
|
18552
|
+
init_s3Client();
|
|
18188
18553
|
UNSAFE = /[^A-Za-z0-9]/g;
|
|
18189
18554
|
LocalStorage = class {
|
|
18190
18555
|
directory;
|
|
@@ -18234,51 +18599,36 @@ var init_storage = __esm({
|
|
|
18234
18599
|
constructor(opts = {}) {
|
|
18235
18600
|
this.bucket = opts.bucket || process.env.TINA4_STORAGE_BUCKET || "";
|
|
18236
18601
|
if (!this.bucket) throw new Error("S3Storage requires TINA4_STORAGE_BUCKET");
|
|
18237
|
-
const { S3Client } = loadAwsSdk("@aws-sdk/client-s3");
|
|
18238
|
-
loadAwsSdk("@aws-sdk/s3-request-presigner");
|
|
18239
|
-
const endpoint = opts.endpoint || process.env.TINA4_STORAGE_URL;
|
|
18240
18602
|
this.client = new S3Client({
|
|
18241
|
-
endpoint: endpoint || void 0,
|
|
18242
|
-
forcePathStyle: true,
|
|
18603
|
+
endpoint: opts.endpoint || process.env.TINA4_STORAGE_URL || void 0,
|
|
18243
18604
|
region: opts.region || process.env.TINA4_STORAGE_REGION || "us-east-1",
|
|
18244
|
-
|
|
18245
|
-
|
|
18246
|
-
secretAccessKey: opts.secret || process.env.TINA4_STORAGE_SECRET || ""
|
|
18247
|
-
}
|
|
18605
|
+
accessKey: opts.key || process.env.TINA4_STORAGE_KEY || "",
|
|
18606
|
+
secretKey: opts.secret || process.env.TINA4_STORAGE_SECRET || ""
|
|
18248
18607
|
});
|
|
18249
18608
|
}
|
|
18250
18609
|
async put(key, data, mime = "application/octet-stream") {
|
|
18251
|
-
|
|
18252
|
-
await this.client.send(new PutObjectCommand({ Bucket: this.bucket, Key: key, Body: data, ContentType: mime }));
|
|
18610
|
+
await this.client.putObject(this.bucket, key, data, mime);
|
|
18253
18611
|
}
|
|
18254
18612
|
async get(key) {
|
|
18255
18613
|
try {
|
|
18256
|
-
|
|
18257
|
-
const res = await this.client.send(new GetObjectCommand({ Bucket: this.bucket, Key: key }));
|
|
18258
|
-
const chunks = [];
|
|
18259
|
-
for await (const chunk of res.Body) chunks.push(Buffer.from(chunk));
|
|
18260
|
-
return Buffer.concat(chunks);
|
|
18614
|
+
return await this.client.getObject(this.bucket, key);
|
|
18261
18615
|
} catch {
|
|
18262
18616
|
return null;
|
|
18263
18617
|
}
|
|
18264
18618
|
}
|
|
18265
18619
|
async url(key, ttl = 3600) {
|
|
18266
|
-
|
|
18267
|
-
const { getSignedUrl } = loadAwsSdk("@aws-sdk/s3-request-presigner");
|
|
18268
|
-
return getSignedUrl(this.client, new GetObjectCommand({ Bucket: this.bucket, Key: key }), { expiresIn: ttl });
|
|
18620
|
+
return this.client.presignedGetUrl(this.bucket, key, ttl);
|
|
18269
18621
|
}
|
|
18270
18622
|
async delete(key) {
|
|
18271
18623
|
try {
|
|
18272
|
-
|
|
18273
|
-
await this.client.send(new DeleteObjectCommand({ Bucket: this.bucket, Key: key }));
|
|
18624
|
+
await this.client.deleteObject(this.bucket, key);
|
|
18274
18625
|
} catch (e) {
|
|
18275
18626
|
Log.error(`S3Storage delete failed for ${key}: ${e.message}`);
|
|
18276
18627
|
}
|
|
18277
18628
|
}
|
|
18278
18629
|
async exists(key) {
|
|
18279
18630
|
try {
|
|
18280
|
-
|
|
18281
|
-
await this.client.send(new HeadObjectCommand({ Bucket: this.bucket, Key: key }));
|
|
18631
|
+
await this.client.headObject(this.bucket, key);
|
|
18282
18632
|
return true;
|
|
18283
18633
|
} catch {
|
|
18284
18634
|
return false;
|
|
@@ -18289,7 +18639,7 @@ var init_storage = __esm({
|
|
|
18289
18639
|
});
|
|
18290
18640
|
|
|
18291
18641
|
// ../orm/src/realtime/realtime.ts
|
|
18292
|
-
import { createHmac as
|
|
18642
|
+
import { createHmac as createHmac4 } from "node:crypto";
|
|
18293
18643
|
function iceServers() {
|
|
18294
18644
|
const stun = process.env.TINA4_RTC_STUN_URLS || DEFAULT_STUN;
|
|
18295
18645
|
const servers = [{ urls: splitUrls(stun) }];
|
|
@@ -18298,14 +18648,14 @@ function iceServers() {
|
|
|
18298
18648
|
if (turnUrl && secret) {
|
|
18299
18649
|
const ttl = parseInt(process.env.TINA4_RTC_TURN_TTL || "3600", 10);
|
|
18300
18650
|
const username = String(Math.floor(Date.now() / 1e3) + ttl);
|
|
18301
|
-
const credential =
|
|
18651
|
+
const credential = createHmac4("sha1", secret).update(username).digest("base64");
|
|
18302
18652
|
servers.push({ urls: splitUrls(turnUrl), username, credential });
|
|
18303
18653
|
}
|
|
18304
18654
|
return servers;
|
|
18305
18655
|
}
|
|
18306
18656
|
async function realtime(options = {}) {
|
|
18307
18657
|
const features = options.features ?? ["calls"];
|
|
18308
|
-
const raw = (options.prefix ?? "")
|
|
18658
|
+
const raw = trimSlashes(options.prefix ?? "");
|
|
18309
18659
|
const p = raw ? `/${raw}` : "";
|
|
18310
18660
|
_authorize = options.authorize;
|
|
18311
18661
|
if (features.includes("chat") || features.includes("files")) {
|
|
@@ -18577,6 +18927,7 @@ var DEFAULT_STUN, _authorize;
|
|
|
18577
18927
|
var init_realtime = __esm({
|
|
18578
18928
|
"../orm/src/realtime/realtime.ts"() {
|
|
18579
18929
|
"use strict";
|
|
18930
|
+
init_slashTrim();
|
|
18580
18931
|
init_src3();
|
|
18581
18932
|
init_workspace();
|
|
18582
18933
|
init_channel();
|
|
@@ -18594,6 +18945,7 @@ var init_realtime2 = __esm({
|
|
|
18594
18945
|
"use strict";
|
|
18595
18946
|
init_realtime();
|
|
18596
18947
|
init_storage();
|
|
18948
|
+
init_s3Client();
|
|
18597
18949
|
init_workspace();
|
|
18598
18950
|
init_channel();
|
|
18599
18951
|
init_channelMember();
|
|
@@ -18959,6 +19311,7 @@ function mayStore(req2, vary, cacheControl, setCookie) {
|
|
|
18959
19311
|
if (requestHeader(req2, "authorization") !== void 0) return sharedCacheAllowed(cacheControl);
|
|
18960
19312
|
if (requestHeader(req2, "cookie") !== void 0) return sharedCacheAllowed(cacheControl);
|
|
18961
19313
|
if (hasSetCookie(setCookie)) return sharedCacheAllowed(cacheControl);
|
|
19314
|
+
if (req2.session?.isFresh && !req2.session.isFresh()) return sharedCacheAllowed(cacheControl);
|
|
18962
19315
|
return true;
|
|
18963
19316
|
}
|
|
18964
19317
|
function varyMatches(entry, req2) {
|
|
@@ -20311,7 +20664,7 @@ function coerceParam(raw, type2) {
|
|
|
20311
20664
|
}
|
|
20312
20665
|
function joinGroupPath(prefix, path10) {
|
|
20313
20666
|
const full = `${prefix}/${path10.replace(/^\/+/, "")}`;
|
|
20314
|
-
const trimmed = `/${full
|
|
20667
|
+
const trimmed = `/${trimSlashes(full)}`;
|
|
20315
20668
|
return trimmed.replace(/\/+/g, "/");
|
|
20316
20669
|
}
|
|
20317
20670
|
async function resolveStringMiddleware(spec) {
|
|
@@ -20376,6 +20729,7 @@ var WsRouteRef, RouteRef, Router, RouteGroup, TINA4_DEFAULT_ROUTER, globalRouter
|
|
|
20376
20729
|
var init_router = __esm({
|
|
20377
20730
|
"../core/src/router.ts"() {
|
|
20378
20731
|
"use strict";
|
|
20732
|
+
init_slashTrim();
|
|
20379
20733
|
init_dotenv();
|
|
20380
20734
|
init_middleware();
|
|
20381
20735
|
WsRouteRef = class {
|
|
@@ -20585,7 +20939,7 @@ var init_router = __esm({
|
|
|
20585
20939
|
const direct = this.matchRoute(routes, path10);
|
|
20586
20940
|
if (direct) return direct;
|
|
20587
20941
|
if (isTrailingSlashRedirectEnabled() && path10.length > 1 && path10.endsWith("/")) {
|
|
20588
|
-
const stripped = path10
|
|
20942
|
+
const stripped = rtrimSlashes(path10);
|
|
20589
20943
|
if (stripped.length > 0) {
|
|
20590
20944
|
const retry = this.matchRoute(routes, stripped);
|
|
20591
20945
|
if (retry) return retry;
|
|
@@ -22261,7 +22615,8 @@ var init_middleware = __esm({
|
|
|
22261
22615
|
"Content-Security-Policy": resolveCspHeader(currentCspNonce()),
|
|
22262
22616
|
"Referrer-Policy": process.env.TINA4_REFERRER_POLICY ?? "strict-origin-when-cross-origin",
|
|
22263
22617
|
"X-XSS-Protection": "0",
|
|
22264
|
-
"Permissions-Policy": process.env.TINA4_PERMISSIONS_POLICY ?? "camera=(), microphone=(), geolocation=()"
|
|
22618
|
+
"Permissions-Policy": process.env.TINA4_PERMISSIONS_POLICY ?? "camera=(), microphone=(), geolocation=()",
|
|
22619
|
+
"Cross-Origin-Opener-Policy": process.env.TINA4_COOP ?? "same-origin-allow-popups"
|
|
22265
22620
|
};
|
|
22266
22621
|
}
|
|
22267
22622
|
static beforeSecurity(req2, res) {
|
|
@@ -22278,7 +22633,7 @@ var init_middleware = __esm({
|
|
|
22278
22633
|
if (process.env.TINA4_CSP === void 0) {
|
|
22279
22634
|
_SecurityHeadersMiddleware.warnCspDefaultOnce();
|
|
22280
22635
|
}
|
|
22281
|
-
for (const name of ["Content-Security-Policy", "Referrer-Policy", "X-XSS-Protection", "Permissions-Policy"]) {
|
|
22636
|
+
for (const name of ["Content-Security-Policy", "Referrer-Policy", "X-XSS-Protection", "Permissions-Policy", "Cross-Origin-Opener-Policy"]) {
|
|
22282
22637
|
res.header(name, canonical[name]);
|
|
22283
22638
|
}
|
|
22284
22639
|
return [req2, res];
|
|
@@ -22362,7 +22717,7 @@ var init_middleware = __esm({
|
|
|
22362
22717
|
});
|
|
22363
22718
|
|
|
22364
22719
|
// ../core/src/request.ts
|
|
22365
|
-
import { mkdirSync as mkdirSync8, realpathSync as realpathSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
22720
|
+
import { closeSync as closeSync3, constants as constants2, fstatSync as fstatSync2, ftruncateSync, lstatSync, mkdirSync as mkdirSync8, openSync as openSync3, realpathSync as realpathSync2, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
22366
22721
|
import { dirname as dirname7, join as join12 } from "node:path";
|
|
22367
22722
|
function makeCaseInsensitiveHeaders(raw) {
|
|
22368
22723
|
return new Proxy(raw, {
|
|
@@ -22398,7 +22753,8 @@ function createRequest(req2) {
|
|
|
22398
22753
|
try {
|
|
22399
22754
|
const url = new URL(req2.url ?? "/", `${proto}://${host}`);
|
|
22400
22755
|
for (const [key, value] of url.searchParams) {
|
|
22401
|
-
|
|
22756
|
+
if (isUnsafeFieldName(key)) continue;
|
|
22757
|
+
Reflect.set(query, key, value);
|
|
22402
22758
|
}
|
|
22403
22759
|
path10 = url.pathname;
|
|
22404
22760
|
queryString = url.search.replace(/^\?/, "");
|
|
@@ -22410,7 +22766,8 @@ function createRequest(req2) {
|
|
|
22410
22766
|
queryString = questionIdx >= 0 ? rawTarget.slice(questionIdx + 1) : "";
|
|
22411
22767
|
try {
|
|
22412
22768
|
for (const [key, value] of new URLSearchParams(queryString)) {
|
|
22413
|
-
|
|
22769
|
+
if (isUnsafeFieldName(key)) continue;
|
|
22770
|
+
Reflect.set(query, key, value);
|
|
22414
22771
|
}
|
|
22415
22772
|
} catch {
|
|
22416
22773
|
}
|
|
@@ -22429,7 +22786,8 @@ function createRequest(req2) {
|
|
|
22429
22786
|
if (cookieHeader) {
|
|
22430
22787
|
for (const pair of cookieHeader.split(";")) {
|
|
22431
22788
|
const [k, ...v] = pair.trim().split("=");
|
|
22432
|
-
|
|
22789
|
+
const name = k ? k.trim() : "";
|
|
22790
|
+
if (name && !isUnsafeFieldName(name)) Reflect.set(cookies, name, v.join("=").trim());
|
|
22433
22791
|
}
|
|
22434
22792
|
}
|
|
22435
22793
|
w.cookies = cookies;
|
|
@@ -22520,13 +22878,7 @@ async function parseBody(req2) {
|
|
|
22520
22878
|
req2.body = str;
|
|
22521
22879
|
}
|
|
22522
22880
|
} else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
22523
|
-
|
|
22524
|
-
const params = new URLSearchParams(str);
|
|
22525
|
-
const obj = {};
|
|
22526
|
-
for (const [key, value] of params) {
|
|
22527
|
-
obj[key] = value;
|
|
22528
|
-
}
|
|
22529
|
-
req2.body = obj;
|
|
22881
|
+
req2.body = nestFormFields([...new URLSearchParams(raw.toString("utf-8"))]);
|
|
22530
22882
|
} else {
|
|
22531
22883
|
req2.body = raw.toString("utf-8");
|
|
22532
22884
|
}
|
|
@@ -22536,7 +22888,7 @@ function extractBoundary(contentType) {
|
|
|
22536
22888
|
return match ? match[1] ?? match[2] : null;
|
|
22537
22889
|
}
|
|
22538
22890
|
function parseMultipart(body, boundary) {
|
|
22539
|
-
const
|
|
22891
|
+
const pairs = [];
|
|
22540
22892
|
const files = {};
|
|
22541
22893
|
const delimiter4 = Buffer.from(`--${boundary}`);
|
|
22542
22894
|
const closeDelimiter = Buffer.from(`--${boundary}--`);
|
|
@@ -22544,7 +22896,7 @@ function parseMultipart(body, boundary) {
|
|
|
22544
22896
|
const doubleCrlf = Buffer.from("\r\n\r\n");
|
|
22545
22897
|
let offset = 0;
|
|
22546
22898
|
const firstIdx = bufferIndexOf(body, delimiter4, offset);
|
|
22547
|
-
if (firstIdx === -1) return { fields, files };
|
|
22899
|
+
if (firstIdx === -1) return { fields: {}, files };
|
|
22548
22900
|
offset = firstIdx + delimiter4.length;
|
|
22549
22901
|
if (body[offset] === 13 && body[offset + 1] === 10) {
|
|
22550
22902
|
offset += 2;
|
|
@@ -22568,14 +22920,15 @@ function parseMultipart(body, boundary) {
|
|
|
22568
22920
|
content: Buffer.from(content),
|
|
22569
22921
|
size: content.length
|
|
22570
22922
|
};
|
|
22571
|
-
if (
|
|
22923
|
+
if (isUnsafeFieldName(disposition.name)) {
|
|
22924
|
+
} else if (files[disposition.name]) {
|
|
22572
22925
|
const existing = files[disposition.name];
|
|
22573
|
-
files
|
|
22926
|
+
Reflect.set(files, disposition.name, Array.isArray(existing) ? [...existing, file] : [existing, file]);
|
|
22574
22927
|
} else {
|
|
22575
|
-
files
|
|
22928
|
+
Reflect.set(files, disposition.name, file);
|
|
22576
22929
|
}
|
|
22577
22930
|
} else if (disposition.name) {
|
|
22578
|
-
|
|
22931
|
+
pairs.push([disposition.name, content.toString("utf-8")]);
|
|
22579
22932
|
}
|
|
22580
22933
|
offset = nextDelimIdx + delimiter4.length;
|
|
22581
22934
|
if (body[offset] === 45 && body[offset + 1] === 45) {
|
|
@@ -22585,7 +22938,7 @@ function parseMultipart(body, boundary) {
|
|
|
22585
22938
|
offset += 2;
|
|
22586
22939
|
}
|
|
22587
22940
|
}
|
|
22588
|
-
return { fields, files };
|
|
22941
|
+
return { fields: nestFormFields(pairs), files };
|
|
22589
22942
|
}
|
|
22590
22943
|
function saveUpload(file, targetDir, filename) {
|
|
22591
22944
|
const raw = String(filename ?? file.filename ?? "");
|
|
@@ -22601,7 +22954,21 @@ function saveUpload(file, targetDir, filename) {
|
|
|
22601
22954
|
if (realParent !== realDir) {
|
|
22602
22955
|
throw new Error(`refusing to write outside ${targetDir}: ${JSON.stringify(raw)}`);
|
|
22603
22956
|
}
|
|
22604
|
-
|
|
22957
|
+
if (lstatSync(dest, { throwIfNoEntry: false })?.isSymbolicLink()) unlinkSync4(dest);
|
|
22958
|
+
const flags = constants2.O_WRONLY | constants2.O_CREAT | (constants2.O_NOFOLLOW ?? 0);
|
|
22959
|
+
let fd = openSync3(dest, flags, 384);
|
|
22960
|
+
try {
|
|
22961
|
+
if (fstatSync2(fd).nlink > 1) {
|
|
22962
|
+
closeSync3(fd);
|
|
22963
|
+
fd = -1;
|
|
22964
|
+
unlinkSync4(dest);
|
|
22965
|
+
fd = openSync3(dest, flags | constants2.O_EXCL, 384);
|
|
22966
|
+
}
|
|
22967
|
+
ftruncateSync(fd, 0);
|
|
22968
|
+
writeFileSync5(fd, file.content);
|
|
22969
|
+
} finally {
|
|
22970
|
+
if (fd >= 0) closeSync3(fd);
|
|
22971
|
+
}
|
|
22605
22972
|
return dest;
|
|
22606
22973
|
}
|
|
22607
22974
|
function bufferIndexOf(haystack, needle, offset) {
|
|
@@ -22626,10 +22993,98 @@ function parseDisposition(headers) {
|
|
|
22626
22993
|
};
|
|
22627
22994
|
}
|
|
22628
22995
|
function parsePartContentType(headers) {
|
|
22629
|
-
const match = headers.match(/Content-Type
|
|
22630
|
-
|
|
22996
|
+
const match = headers.match(/Content-Type:([^\r\n]*)/i);
|
|
22997
|
+
const value = match?.[1]?.trim();
|
|
22998
|
+
return value ? value : null;
|
|
22999
|
+
}
|
|
23000
|
+
function nestFormFields(pairs) {
|
|
23001
|
+
const kept = pairs.filter(([name]) => !/(^|[[\]])__proto__([[\]]|$)/.test(name));
|
|
23002
|
+
if (kept.length > FORM_FIELD_LIMIT) return Object.fromEntries(kept);
|
|
23003
|
+
const nested = /* @__PURE__ */ new WeakSet();
|
|
23004
|
+
const node = () => {
|
|
23005
|
+
const created = /* @__PURE__ */ Object.create(null);
|
|
23006
|
+
nested.add(created);
|
|
23007
|
+
return created;
|
|
23008
|
+
};
|
|
23009
|
+
const isNode = (value) => typeof value === "object" && value !== null && nested.has(value);
|
|
23010
|
+
const own = (params, key) => Object.prototype.hasOwnProperty.call(params, key) ? params[key] : void 0;
|
|
23011
|
+
const list = (params, key) => {
|
|
23012
|
+
let current = own(params, key);
|
|
23013
|
+
if (current === void 0) {
|
|
23014
|
+
current = [];
|
|
23015
|
+
Reflect.set(params, key, current);
|
|
23016
|
+
}
|
|
23017
|
+
if (!Array.isArray(current)) throw new RangeError(`expected an array for '${key}'`);
|
|
23018
|
+
return current;
|
|
23019
|
+
};
|
|
23020
|
+
const object = (params, key) => {
|
|
23021
|
+
let current = own(params, key);
|
|
23022
|
+
if (current === void 0) {
|
|
23023
|
+
current = node();
|
|
23024
|
+
Reflect.set(params, key, current);
|
|
23025
|
+
}
|
|
23026
|
+
if (!isNode(current)) throw new RangeError(`expected an object for '${key}'`);
|
|
23027
|
+
return current;
|
|
23028
|
+
};
|
|
23029
|
+
const hasKey = (params, key) => {
|
|
23030
|
+
if (key.includes("[]")) return false;
|
|
23031
|
+
let level = params;
|
|
23032
|
+
for (const part of key.split(/[[\]]+/).filter(Boolean)) {
|
|
23033
|
+
if (!isNode(level) || own(level, part) === void 0) return false;
|
|
23034
|
+
level = level[part];
|
|
23035
|
+
}
|
|
23036
|
+
return true;
|
|
23037
|
+
};
|
|
23038
|
+
const splitName = (name, depth) => {
|
|
23039
|
+
if (depth === 0) {
|
|
23040
|
+
const start2 = name.indexOf("[", 1);
|
|
23041
|
+
return start2 === -1 ? [name, ""] : [name.slice(0, start2), name.slice(start2)];
|
|
23042
|
+
}
|
|
23043
|
+
if (name.startsWith("[]")) return ["[]", name.slice(2)];
|
|
23044
|
+
const close = name.indexOf("]", 1);
|
|
23045
|
+
return name.startsWith("[") && close !== -1 ? [name.slice(1, close), name.slice(close + 1)] : [name, ""];
|
|
23046
|
+
};
|
|
23047
|
+
const putListItem = (items, after, value, depth) => {
|
|
23048
|
+
let childKey = after[2] === "[" && after.endsWith("]") ? after.slice(3, -1) : "";
|
|
23049
|
+
if (childKey === "" || childKey.includes("[") || childKey.includes("]")) childKey = after.slice(2);
|
|
23050
|
+
const last = items[items.length - 1];
|
|
23051
|
+
if (isNode(last) && !hasKey(last, childKey)) put2(last, childKey, value, depth + 1);
|
|
23052
|
+
else items.push(put2(node(), childKey, value, depth + 1));
|
|
23053
|
+
};
|
|
23054
|
+
const put2 = (params, name, value, depth) => {
|
|
23055
|
+
const [key, after] = splitName(name, depth);
|
|
23056
|
+
if (key === "") return void 0;
|
|
23057
|
+
if (after === "" && key === "[]" && depth !== 0) return [value];
|
|
23058
|
+
if (after === "") Reflect.set(params, key, value);
|
|
23059
|
+
else if (after === "[") Reflect.set(params, name, value);
|
|
23060
|
+
else if (after === "[]") list(params, key).push(value);
|
|
23061
|
+
else if (after.startsWith("[]")) putListItem(list(params, key), after, value, depth);
|
|
23062
|
+
else put2(object(params, key), after, value, depth + 1);
|
|
23063
|
+
return params;
|
|
23064
|
+
};
|
|
23065
|
+
const tooDeep = (name) => {
|
|
23066
|
+
let count = 0;
|
|
23067
|
+
for (let at = name.indexOf("["); at !== -1; at = name.indexOf("[", at + 1)) {
|
|
23068
|
+
if (++count >= FORM_DEPTH_LIMIT) return true;
|
|
23069
|
+
}
|
|
23070
|
+
return false;
|
|
23071
|
+
};
|
|
23072
|
+
const fields = node();
|
|
23073
|
+
for (const [name, value] of kept) {
|
|
23074
|
+
if (name.length > FORM_NAME_LIMIT || tooDeep(name)) {
|
|
23075
|
+
Reflect.set(fields, name, value);
|
|
23076
|
+
continue;
|
|
23077
|
+
}
|
|
23078
|
+
try {
|
|
23079
|
+
put2(fields, name, value, 0);
|
|
23080
|
+
} catch (error2) {
|
|
23081
|
+
if (!(error2 instanceof RangeError)) throw error2;
|
|
23082
|
+
Reflect.set(fields, name, value);
|
|
23083
|
+
}
|
|
23084
|
+
}
|
|
23085
|
+
return fields;
|
|
22631
23086
|
}
|
|
22632
|
-
var DEFAULT_MAX_UPLOAD_SIZE, warnedLimits, PayloadTooLargeError;
|
|
23087
|
+
var DEFAULT_MAX_UPLOAD_SIZE, warnedLimits, PayloadTooLargeError, FORM_DEPTH_LIMIT, FORM_FIELD_LIMIT, FORM_NAME_LIMIT, isUnsafeFieldName;
|
|
22633
23088
|
var init_request = __esm({
|
|
22634
23089
|
"../core/src/request.ts"() {
|
|
22635
23090
|
"use strict";
|
|
@@ -22644,6 +23099,10 @@ var init_request = __esm({
|
|
|
22644
23099
|
this.name = "PayloadTooLargeError";
|
|
22645
23100
|
}
|
|
22646
23101
|
};
|
|
23102
|
+
FORM_DEPTH_LIMIT = 32;
|
|
23103
|
+
FORM_FIELD_LIMIT = 4096;
|
|
23104
|
+
FORM_NAME_LIMIT = 1024;
|
|
23105
|
+
isUnsafeFieldName = (key) => key === "__proto__" || key === "constructor" || key === "prototype";
|
|
22647
23106
|
}
|
|
22648
23107
|
});
|
|
22649
23108
|
|
|
@@ -23170,7 +23629,7 @@ __export(portTakeover_exports, {
|
|
|
23170
23629
|
writePidfile: () => writePidfile
|
|
23171
23630
|
});
|
|
23172
23631
|
import { execFileSync } from "node:child_process";
|
|
23173
|
-
import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10, unlinkSync as
|
|
23632
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10, unlinkSync as unlinkSync5 } from "node:fs";
|
|
23174
23633
|
import { join as join14 } from "node:path";
|
|
23175
23634
|
function isTruthy3(value) {
|
|
23176
23635
|
return ["true", "1", "yes", "on"].includes(String(value ?? "").trim().toLowerCase());
|
|
@@ -23224,7 +23683,7 @@ function readPidfile(port, baseDir) {
|
|
|
23224
23683
|
}
|
|
23225
23684
|
function removePidfile(port, baseDir) {
|
|
23226
23685
|
try {
|
|
23227
|
-
|
|
23686
|
+
unlinkSync5(pidfilePath(port, baseDir));
|
|
23228
23687
|
} catch {
|
|
23229
23688
|
}
|
|
23230
23689
|
}
|
|
@@ -23325,21 +23784,6 @@ var init_portTakeover = __esm({
|
|
|
23325
23784
|
}
|
|
23326
23785
|
});
|
|
23327
23786
|
|
|
23328
|
-
// ../core/src/etag.ts
|
|
23329
|
-
function etagMatches(ifNoneMatch, etag) {
|
|
23330
|
-
const strip = (tag) => tag.trim().replace(/^W\//, "");
|
|
23331
|
-
const target = strip(etag);
|
|
23332
|
-
return ifNoneMatch.split(",").some((candidate) => {
|
|
23333
|
-
const trimmed = candidate.trim();
|
|
23334
|
-
return trimmed === "*" || strip(trimmed) === target;
|
|
23335
|
-
});
|
|
23336
|
-
}
|
|
23337
|
-
var init_etag = __esm({
|
|
23338
|
-
"../core/src/etag.ts"() {
|
|
23339
|
-
"use strict";
|
|
23340
|
-
}
|
|
23341
|
-
});
|
|
23342
|
-
|
|
23343
23787
|
// ../core/src/sessionHandlers/syncBridge.ts
|
|
23344
23788
|
import { Worker } from "node:worker_threads";
|
|
23345
23789
|
function getBridge(key, workerSource, workerData) {
|
|
@@ -23699,7 +24143,7 @@ var init_valkeyHandler = __esm({
|
|
|
23699
24143
|
});
|
|
23700
24144
|
|
|
23701
24145
|
// ../core/src/sessionHandlers/memcachedHandler.ts
|
|
23702
|
-
import { createHash as
|
|
24146
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
23703
24147
|
var MAX_KEY_BYTES, MAX_RELATIVE_EXPTIME, MemcachedSessionHandler;
|
|
23704
24148
|
var init_memcachedHandler = __esm({
|
|
23705
24149
|
"../core/src/sessionHandlers/memcachedHandler.ts"() {
|
|
@@ -23721,7 +24165,7 @@ var init_memcachedHandler = __esm({
|
|
|
23721
24165
|
key(sessionId) {
|
|
23722
24166
|
const candidate = `${this.prefix}${sessionId}`;
|
|
23723
24167
|
if (Buffer.byteLength(candidate) > MAX_KEY_BYTES || /[\x00-\x20\x7f]/.test(candidate)) {
|
|
23724
|
-
return `${this.prefix}${
|
|
24168
|
+
return `${this.prefix}${createHash6("sha256").update(sessionId).digest("hex")}`;
|
|
23725
24169
|
}
|
|
23726
24170
|
return candidate;
|
|
23727
24171
|
}
|
|
@@ -24187,7 +24631,7 @@ var init_mongoHandler = __esm({
|
|
|
24187
24631
|
});
|
|
24188
24632
|
|
|
24189
24633
|
// ../core/src/sessionHandlers/sqlClient.ts
|
|
24190
|
-
import { createRequire as
|
|
24634
|
+
import { createRequire as createRequire6 } from "node:module";
|
|
24191
24635
|
function driverPath(engine) {
|
|
24192
24636
|
const packageName = DRIVER_PACKAGE4[engine];
|
|
24193
24637
|
try {
|
|
@@ -24226,7 +24670,7 @@ var init_sqlClient = __esm({
|
|
|
24226
24670
|
mssql: "tedious",
|
|
24227
24671
|
firebird: "node-firebird"
|
|
24228
24672
|
};
|
|
24229
|
-
requireFromHere =
|
|
24673
|
+
requireFromHere = createRequire6(import.meta.url);
|
|
24230
24674
|
SQL_WORKER = `
|
|
24231
24675
|
const target = workerData.target;
|
|
24232
24676
|
const engine = target.engine;
|
|
@@ -24708,14 +25152,18 @@ __export(session_exports, {
|
|
|
24708
25152
|
Session: () => Session,
|
|
24709
25153
|
VALID_SESSION_BACKENDS: () => VALID_SESSION_BACKENDS,
|
|
24710
25154
|
buildSessionCookie: () => buildSessionCookie,
|
|
25155
|
+
currentFormTokenSessionId: () => currentFormTokenSessionId,
|
|
24711
25156
|
isSecureScheme: () => isSecureScheme,
|
|
24712
25157
|
isValidSessionId: () => isValidSessionId,
|
|
25158
|
+
runWithFormTokenSession: () => runWithFormTokenSession,
|
|
24713
25159
|
sessionCookieName: () => sessionCookieName,
|
|
24714
25160
|
sessionCookieToSend: () => sessionCookieToSend,
|
|
24715
|
-
sessionStrictMode: () => sessionStrictMode
|
|
25161
|
+
sessionStrictMode: () => sessionStrictMode,
|
|
25162
|
+
setFormTokenSession: () => setFormTokenSession
|
|
24716
25163
|
});
|
|
24717
|
-
import {
|
|
24718
|
-
import {
|
|
25164
|
+
import { AsyncLocalStorage as AsyncLocalStorage4 } from "node:async_hooks";
|
|
25165
|
+
import { createHash as createHash7, randomBytes as randomBytes6 } from "node:crypto";
|
|
25166
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync11, readFileSync as readFileSync8, writeFileSync as writeFileSync8, unlinkSync as unlinkSync6, readdirSync as readdirSync6 } from "node:fs";
|
|
24719
25167
|
import { join as join15 } from "node:path";
|
|
24720
25168
|
function isValidSessionId(sessionId) {
|
|
24721
25169
|
return typeof sessionId === "string" && SESSION_ID_PATTERN.test(sessionId);
|
|
@@ -24781,7 +25229,21 @@ function sessionCookieToSend(sess, existingSid, rawReq, rawRes) {
|
|
|
24781
25229
|
const socketEncrypted = rawReq.socket?.encrypted === true;
|
|
24782
25230
|
return buildSessionCookie(newSid, ttl, void 0, forwardedProto, socketEncrypted);
|
|
24783
25231
|
}
|
|
24784
|
-
|
|
25232
|
+
function runWithFormTokenSession(fn) {
|
|
25233
|
+
return sessionStore.run({ session: null }, fn);
|
|
25234
|
+
}
|
|
25235
|
+
function setFormTokenSession(session) {
|
|
25236
|
+
const store = sessionStore.getStore();
|
|
25237
|
+
if (store) store.session = session;
|
|
25238
|
+
}
|
|
25239
|
+
function currentFormTokenSessionId() {
|
|
25240
|
+
const session = sessionStore.getStore()?.session;
|
|
25241
|
+
const sid = session?.getSessionId();
|
|
25242
|
+
if (!session || !sid) return "";
|
|
25243
|
+
if (session.isFresh()) session.set("_tina4_csrf", true);
|
|
25244
|
+
return sid;
|
|
25245
|
+
}
|
|
25246
|
+
var SESSION_ID_PATTERN, VALID_SESSION_BACKENDS, CANONICAL_SESSION_BACKENDS, RETIRED_SESSION_BACKENDS, FileSessionHandler, RedisSessionHandler, FLASH_PREFIX, Session, sessionStore;
|
|
24785
25247
|
var init_session = __esm({
|
|
24786
25248
|
"../core/src/session.ts"() {
|
|
24787
25249
|
"use strict";
|
|
@@ -24855,7 +25317,7 @@ var init_session = __esm({
|
|
|
24855
25317
|
`Invalid session id ${JSON.stringify(id)} \u2014 a session id is opaque and must match ${SESSION_ID_PATTERN.source}. It is never a path, so it is refused rather than resolved to a file.`
|
|
24856
25318
|
);
|
|
24857
25319
|
}
|
|
24858
|
-
return join15(this.storagePath, `${
|
|
25320
|
+
return join15(this.storagePath, `${createHash7("sha256").update(id).digest("hex")}.json`);
|
|
24859
25321
|
}
|
|
24860
25322
|
read(sessionId) {
|
|
24861
25323
|
const filePath = this.filePath(sessionId);
|
|
@@ -24865,7 +25327,7 @@ var init_session = __esm({
|
|
|
24865
25327
|
const wrapper = JSON.parse(raw);
|
|
24866
25328
|
if (wrapper._expires && wrapper._expires > 0 && Date.now() / 1e3 > wrapper._expires) {
|
|
24867
25329
|
try {
|
|
24868
|
-
|
|
25330
|
+
unlinkSync6(filePath);
|
|
24869
25331
|
} catch {
|
|
24870
25332
|
}
|
|
24871
25333
|
return null;
|
|
@@ -24884,7 +25346,7 @@ var init_session = __esm({
|
|
|
24884
25346
|
destroy(sessionId) {
|
|
24885
25347
|
const filePath = this.filePath(sessionId);
|
|
24886
25348
|
try {
|
|
24887
|
-
if (existsSync12(filePath))
|
|
25349
|
+
if (existsSync12(filePath)) unlinkSync6(filePath);
|
|
24888
25350
|
} catch {
|
|
24889
25351
|
}
|
|
24890
25352
|
}
|
|
@@ -24900,11 +25362,11 @@ var init_session = __esm({
|
|
|
24900
25362
|
const raw = readFileSync8(fullPath, "utf-8");
|
|
24901
25363
|
const wrapper = JSON.parse(raw);
|
|
24902
25364
|
if (wrapper._expires && wrapper._expires > 0 && now > wrapper._expires) {
|
|
24903
|
-
|
|
25365
|
+
unlinkSync6(fullPath);
|
|
24904
25366
|
}
|
|
24905
25367
|
} catch {
|
|
24906
25368
|
try {
|
|
24907
|
-
|
|
25369
|
+
unlinkSync6(fullPath);
|
|
24908
25370
|
} catch {
|
|
24909
25371
|
}
|
|
24910
25372
|
}
|
|
@@ -25424,12 +25886,28 @@ var init_session = __esm({
|
|
|
25424
25886
|
this.loaded = /* @__PURE__ */ new Map();
|
|
25425
25887
|
}
|
|
25426
25888
|
};
|
|
25889
|
+
sessionStore = new AsyncLocalStorage4();
|
|
25890
|
+
}
|
|
25891
|
+
});
|
|
25892
|
+
|
|
25893
|
+
// ../core/src/etag.ts
|
|
25894
|
+
function etagMatches(ifNoneMatch, etag) {
|
|
25895
|
+
const strip = (tag) => tag.trim().replace(/^W\//, "");
|
|
25896
|
+
const target = strip(etag);
|
|
25897
|
+
return ifNoneMatch.split(",").some((candidate) => {
|
|
25898
|
+
const trimmed = candidate.trim();
|
|
25899
|
+
return trimmed === "*" || strip(trimmed) === target;
|
|
25900
|
+
});
|
|
25901
|
+
}
|
|
25902
|
+
var init_etag = __esm({
|
|
25903
|
+
"../core/src/etag.ts"() {
|
|
25904
|
+
"use strict";
|
|
25427
25905
|
}
|
|
25428
25906
|
});
|
|
25429
25907
|
|
|
25430
25908
|
// ../core/src/dispatchPipeline.ts
|
|
25431
25909
|
import { gzipSync } from "node:zlib";
|
|
25432
|
-
import { createHash as
|
|
25910
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
25433
25911
|
async function resetRequestCaches2() {
|
|
25434
25912
|
if (_resetRequestCaches === void 0) {
|
|
25435
25913
|
_resetRequestCaches = Promise.resolve().then(() => (init_src(), src_exports)).then((orm) => orm.resetRequestCaches).catch(() => null);
|
|
@@ -25502,7 +25980,7 @@ function applyResponseValidator(rawReq, rawRes, body) {
|
|
|
25502
25980
|
if ((rawRes.statusCode || 200) !== 200 || body.length === 0) return false;
|
|
25503
25981
|
let etag = rawRes.getHeader("etag");
|
|
25504
25982
|
if (!etag) {
|
|
25505
|
-
etag = `"${
|
|
25983
|
+
etag = `"${createHash8("md5").update(body).digest("hex").slice(0, 16)}"`;
|
|
25506
25984
|
rawRes.setHeader("ETag", etag);
|
|
25507
25985
|
}
|
|
25508
25986
|
if (!responseIsNotModified(rawReq, rawRes, String(etag))) return false;
|
|
@@ -25577,6 +26055,7 @@ async function sessionAutoStart(rawReq, rawRes, req2) {
|
|
|
25577
26055
|
return;
|
|
25578
26056
|
}
|
|
25579
26057
|
req2.session = sess;
|
|
26058
|
+
setFormTokenSession(sess);
|
|
25580
26059
|
const origEnd = rawRes.end.bind(rawRes);
|
|
25581
26060
|
let finalised = false;
|
|
25582
26061
|
rawRes.end = function(...args) {
|
|
@@ -25605,6 +26084,7 @@ var _resetRequestCaches, COMPRESSIBLE_PREFIXES;
|
|
|
25605
26084
|
var init_dispatchPipeline = __esm({
|
|
25606
26085
|
"../core/src/dispatchPipeline.ts"() {
|
|
25607
26086
|
"use strict";
|
|
26087
|
+
init_session();
|
|
25608
26088
|
init_logger();
|
|
25609
26089
|
init_etag();
|
|
25610
26090
|
COMPRESSIBLE_PREFIXES = [
|
|
@@ -25754,14 +26234,21 @@ function parseStack(stack) {
|
|
|
25754
26234
|
const frames = [];
|
|
25755
26235
|
const lines = stack.split("\n");
|
|
25756
26236
|
for (const line of lines) {
|
|
25757
|
-
|
|
25758
|
-
if (
|
|
25759
|
-
|
|
25760
|
-
|
|
26237
|
+
const t = line.trim();
|
|
26238
|
+
if (!t.startsWith("at ")) continue;
|
|
26239
|
+
const rest = t.slice(3);
|
|
26240
|
+
let func = "{anonymous}";
|
|
26241
|
+
let loc = rest;
|
|
26242
|
+
if (rest.endsWith(")")) {
|
|
26243
|
+
const open = rest.lastIndexOf(" (");
|
|
26244
|
+
if (open >= 0) {
|
|
26245
|
+
func = rest.slice(0, open);
|
|
26246
|
+
loc = rest.slice(open + 2, -1);
|
|
26247
|
+
}
|
|
25761
26248
|
}
|
|
25762
|
-
|
|
25763
|
-
if (
|
|
25764
|
-
frames.push({ func
|
|
26249
|
+
const lc = loc.match(/:(\d+):(\d+)$/);
|
|
26250
|
+
if (lc && lc.index !== void 0) {
|
|
26251
|
+
frames.push({ func, file: loc.slice(0, lc.index), line: parseInt(lc[1], 10), column: parseInt(lc[2], 10) });
|
|
25765
26252
|
}
|
|
25766
26253
|
}
|
|
25767
26254
|
return frames;
|
|
@@ -26086,7 +26573,7 @@ var init_rateLimiter = __esm({
|
|
|
26086
26573
|
});
|
|
26087
26574
|
|
|
26088
26575
|
// ../core/src/devMailbox.ts
|
|
26089
|
-
import { mkdirSync as mkdirSync12, readdirSync as readdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync9, unlinkSync as
|
|
26576
|
+
import { mkdirSync as mkdirSync12, readdirSync as readdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync9, unlinkSync as unlinkSync7, existsSync as existsSync13 } from "node:fs";
|
|
26090
26577
|
import { join as join17 } from "node:path";
|
|
26091
26578
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
26092
26579
|
var DevMailbox;
|
|
@@ -26218,7 +26705,7 @@ var init_devMailbox = __esm({
|
|
|
26218
26705
|
const filePath = join17(this.mailboxDir, folder, `${msgId}.json`);
|
|
26219
26706
|
if (existsSync13(filePath)) {
|
|
26220
26707
|
try {
|
|
26221
|
-
|
|
26708
|
+
unlinkSync7(filePath);
|
|
26222
26709
|
deleted = true;
|
|
26223
26710
|
} catch {
|
|
26224
26711
|
}
|
|
@@ -26237,7 +26724,7 @@ var init_devMailbox = __esm({
|
|
|
26237
26724
|
if (existsSync13(dir)) {
|
|
26238
26725
|
const files = readdirSync7(dir).filter((file) => file.endsWith(".json"));
|
|
26239
26726
|
for (const file of files) {
|
|
26240
|
-
|
|
26727
|
+
unlinkSync7(join17(dir, file));
|
|
26241
26728
|
}
|
|
26242
26729
|
}
|
|
26243
26730
|
} catch {
|
|
@@ -26381,7 +26868,7 @@ function enginePath() {
|
|
|
26381
26868
|
function runEngine(target) {
|
|
26382
26869
|
const binary = enginePath();
|
|
26383
26870
|
if (!binary) throw new MetricsEngineError(`tina4 not found on PATH - ${INSTALL_HINT}`);
|
|
26384
|
-
const processResult = spawnSync(binary, ["metrics", "--path", target, "--json"], {
|
|
26871
|
+
const processResult = spawnSync(binary, ["metrics", "--path", target, "--json", "--no-history"], {
|
|
26385
26872
|
encoding: "utf8",
|
|
26386
26873
|
timeout: 6e4,
|
|
26387
26874
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -28906,7 +29393,7 @@ import * as fs4 from "node:fs";
|
|
|
28906
29393
|
import * as path3 from "node:path";
|
|
28907
29394
|
import * as os from "node:os";
|
|
28908
29395
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
28909
|
-
import { createRequire as
|
|
29396
|
+
import { createRequire as createRequire7 } from "node:module";
|
|
28910
29397
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
28911
29398
|
function reqSibling(pkg) {
|
|
28912
29399
|
return req(`../../${pkg}/src/index.ts`);
|
|
@@ -29065,21 +29552,45 @@ function safePath(projectRoot3, relPath) {
|
|
|
29065
29552
|
if (resolved !== projectRoot3 && !resolved.startsWith(rootPrefix)) {
|
|
29066
29553
|
throw new Error(`Path escapes project directory: ${relPath}`);
|
|
29067
29554
|
}
|
|
29068
|
-
let
|
|
29555
|
+
let realRoot;
|
|
29069
29556
|
try {
|
|
29070
|
-
|
|
29557
|
+
realRoot = fs4.realpathSync(projectRoot3);
|
|
29071
29558
|
} catch {
|
|
29072
|
-
|
|
29559
|
+
return resolved;
|
|
29073
29560
|
}
|
|
29074
|
-
|
|
29075
|
-
|
|
29076
|
-
|
|
29077
|
-
|
|
29078
|
-
throw new Error(`Path escapes project directory: ${relPath}`);
|
|
29079
|
-
}
|
|
29561
|
+
const real = realPathOf(resolved);
|
|
29562
|
+
const realPrefix = realRoot.endsWith(path3.sep) ? realRoot : realRoot + path3.sep;
|
|
29563
|
+
if (real === null || real !== realRoot && !real.startsWith(realPrefix)) {
|
|
29564
|
+
throw new Error(`Path escapes project directory: ${relPath}`);
|
|
29080
29565
|
}
|
|
29081
29566
|
return resolved;
|
|
29082
29567
|
}
|
|
29568
|
+
function realPathOf(p, hops = 0) {
|
|
29569
|
+
let probe = p;
|
|
29570
|
+
while (!fs4.existsSync(probe) && !isSymlink(probe) && path3.dirname(probe) !== probe) {
|
|
29571
|
+
probe = path3.dirname(probe);
|
|
29572
|
+
}
|
|
29573
|
+
try {
|
|
29574
|
+
return fs4.realpathSync.native(probe);
|
|
29575
|
+
} catch {
|
|
29576
|
+
if (hops >= 40) return null;
|
|
29577
|
+
let target;
|
|
29578
|
+
try {
|
|
29579
|
+
target = fs4.readlinkSync(probe);
|
|
29580
|
+
} catch {
|
|
29581
|
+
return null;
|
|
29582
|
+
}
|
|
29583
|
+
const base = path3.isAbsolute(target) ? target : path3.dirname(probe) + path3.sep + target;
|
|
29584
|
+
return realPathOf(base + p.slice(probe.length), hops + 1);
|
|
29585
|
+
}
|
|
29586
|
+
}
|
|
29587
|
+
function isSymlink(p) {
|
|
29588
|
+
try {
|
|
29589
|
+
return fs4.lstatSync(p).isSymbolicLink();
|
|
29590
|
+
} catch {
|
|
29591
|
+
return false;
|
|
29592
|
+
}
|
|
29593
|
+
}
|
|
29083
29594
|
function redactEnv(key, value) {
|
|
29084
29595
|
const sensitive = ["secret", "password", "token", "key", "credential", "api_key"];
|
|
29085
29596
|
if (sensitive.some((s) => key.toLowerCase().includes(s))) {
|
|
@@ -29924,8 +30435,10 @@ function registerDevTools(server) {
|
|
|
29924
30435
|
return { error: `Invalid path ${JSON.stringify(rel)}: ${proseErr}` };
|
|
29925
30436
|
}
|
|
29926
30437
|
rel = normalizeCoderPath(projectRoot4, rel);
|
|
29927
|
-
|
|
29928
|
-
|
|
30438
|
+
let resolved;
|
|
30439
|
+
try {
|
|
30440
|
+
resolved = safePath(projectRoot4, rel);
|
|
30441
|
+
} catch {
|
|
29929
30442
|
return { error: `Path escapes project directory: ${rel}` };
|
|
29930
30443
|
}
|
|
29931
30444
|
if (!fs4.existsSync(resolved) || !fs4.statSync(resolved).isFile()) {
|
|
@@ -30222,8 +30735,9 @@ var req, PARSE_ERROR, INVALID_REQUEST, METHOD_NOT_FOUND, INVALID_PARAMS, INTERNA
|
|
|
30222
30735
|
var init_mcp = __esm({
|
|
30223
30736
|
"../core/src/mcp.ts"() {
|
|
30224
30737
|
"use strict";
|
|
30738
|
+
init_slashTrim();
|
|
30225
30739
|
init_version();
|
|
30226
|
-
req =
|
|
30740
|
+
req = createRequire7(import.meta.url);
|
|
30227
30741
|
PARSE_ERROR = -32700;
|
|
30228
30742
|
INVALID_REQUEST = -32600;
|
|
30229
30743
|
METHOD_NOT_FOUND = -32601;
|
|
@@ -30248,7 +30762,7 @@ var init_mcp = __esm({
|
|
|
30248
30762
|
// threaded, so this in-process map is the whole coordination mechanism.
|
|
30249
30763
|
_sseChannels = /* @__PURE__ */ new Map();
|
|
30250
30764
|
constructor(mcpPath, name = "Tina4 MCP", version = "1.0.0") {
|
|
30251
|
-
this.path = mcpPath
|
|
30765
|
+
this.path = rtrimSlashes(mcpPath);
|
|
30252
30766
|
this.name = name;
|
|
30253
30767
|
this.version = version;
|
|
30254
30768
|
_McpServer._instances.push(this);
|
|
@@ -32331,7 +32845,7 @@ __export(websocket_exports, {
|
|
|
32331
32845
|
wsToken: () => wsToken
|
|
32332
32846
|
});
|
|
32333
32847
|
import { createServer as createServer2 } from "node:http";
|
|
32334
|
-
import { createHash as
|
|
32848
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
32335
32849
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
32336
32850
|
function buildCloseFrame(code, reason = "") {
|
|
32337
32851
|
const reasonBytes = Buffer.from(reason, "utf-8");
|
|
@@ -32341,7 +32855,7 @@ function buildCloseFrame(code, reason = "") {
|
|
|
32341
32855
|
return buildFrame(OP_CLOSE, payload);
|
|
32342
32856
|
}
|
|
32343
32857
|
function computeAcceptKey(key) {
|
|
32344
|
-
return
|
|
32858
|
+
return createHash9("sha1").update(key + MAGIC_STRING).digest("base64");
|
|
32345
32859
|
}
|
|
32346
32860
|
function originAllowed(headers) {
|
|
32347
32861
|
const raw = (process.env.TINA4_WS_ALLOWED_ORIGINS ?? "").trim();
|
|
@@ -34032,7 +34546,7 @@ var init_job = __esm({
|
|
|
34032
34546
|
});
|
|
34033
34547
|
|
|
34034
34548
|
// ../core/src/queueBackends/liteBackend.ts
|
|
34035
|
-
import { mkdirSync as mkdirSync16, readdirSync as readdirSync12, readFileSync as readFileSync16, writeFileSync as writeFileSync12, unlinkSync as
|
|
34549
|
+
import { mkdirSync as mkdirSync16, readdirSync as readdirSync12, readFileSync as readFileSync16, writeFileSync as writeFileSync12, unlinkSync as unlinkSync8, existsSync as existsSync20 } from "node:fs";
|
|
34036
34550
|
import { join as join25 } from "node:path";
|
|
34037
34551
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
34038
34552
|
var LiteBackend;
|
|
@@ -34202,7 +34716,7 @@ var init_liteBackend = __esm({
|
|
|
34202
34716
|
}
|
|
34203
34717
|
if (record.availableAt && record.availableAt > now) continue;
|
|
34204
34718
|
try {
|
|
34205
|
-
|
|
34719
|
+
unlinkSync8(filePath);
|
|
34206
34720
|
} catch {
|
|
34207
34721
|
continue;
|
|
34208
34722
|
}
|
|
@@ -34236,10 +34750,10 @@ var init_liteBackend = __esm({
|
|
|
34236
34750
|
job.priority = job.priority ?? 0;
|
|
34237
34751
|
this.writeReserved(queue, job);
|
|
34238
34752
|
try {
|
|
34239
|
-
|
|
34753
|
+
unlinkSync8(filePath);
|
|
34240
34754
|
} catch {
|
|
34241
34755
|
try {
|
|
34242
|
-
|
|
34756
|
+
unlinkSync8(this.reservedPath(queue, job.id));
|
|
34243
34757
|
} catch {
|
|
34244
34758
|
}
|
|
34245
34759
|
continue;
|
|
@@ -34261,10 +34775,10 @@ var init_liteBackend = __esm({
|
|
|
34261
34775
|
job.priority = job.priority ?? 0;
|
|
34262
34776
|
this.writeReserved(queue, job);
|
|
34263
34777
|
try {
|
|
34264
|
-
|
|
34778
|
+
unlinkSync8(filePath);
|
|
34265
34779
|
} catch {
|
|
34266
34780
|
try {
|
|
34267
|
-
|
|
34781
|
+
unlinkSync8(this.reservedPath(queue, job.id));
|
|
34268
34782
|
} catch {
|
|
34269
34783
|
}
|
|
34270
34784
|
continue;
|
|
@@ -34279,7 +34793,7 @@ var init_liteBackend = __esm({
|
|
|
34279
34793
|
*/
|
|
34280
34794
|
clearReservation(queue, jobId) {
|
|
34281
34795
|
try {
|
|
34282
|
-
|
|
34796
|
+
unlinkSync8(this.reservedPath(queue, jobId));
|
|
34283
34797
|
} catch {
|
|
34284
34798
|
}
|
|
34285
34799
|
}
|
|
@@ -34322,7 +34836,7 @@ var init_liteBackend = __esm({
|
|
|
34322
34836
|
try {
|
|
34323
34837
|
const files = readdirSync12(dir).filter((f) => f.endsWith(".queue-data"));
|
|
34324
34838
|
for (const file of files) {
|
|
34325
|
-
|
|
34839
|
+
unlinkSync8(join25(dir, file));
|
|
34326
34840
|
count++;
|
|
34327
34841
|
}
|
|
34328
34842
|
} catch {
|
|
@@ -34332,7 +34846,7 @@ var init_liteBackend = __esm({
|
|
|
34332
34846
|
if (existsSync20(failedDir)) {
|
|
34333
34847
|
const files = readdirSync12(failedDir).filter((f) => f.endsWith(".queue-data"));
|
|
34334
34848
|
for (const file of files) {
|
|
34335
|
-
|
|
34849
|
+
unlinkSync8(join25(failedDir, file));
|
|
34336
34850
|
count++;
|
|
34337
34851
|
}
|
|
34338
34852
|
}
|
|
@@ -34343,7 +34857,7 @@ var init_liteBackend = __esm({
|
|
|
34343
34857
|
if (existsSync20(reservedDir)) {
|
|
34344
34858
|
const files = readdirSync12(reservedDir).filter((f) => f.endsWith(".queue-data"));
|
|
34345
34859
|
for (const file of files) {
|
|
34346
|
-
|
|
34860
|
+
unlinkSync8(join25(reservedDir, file));
|
|
34347
34861
|
count++;
|
|
34348
34862
|
}
|
|
34349
34863
|
}
|
|
@@ -34401,7 +34915,7 @@ var init_liteBackend = __esm({
|
|
|
34401
34915
|
const prefix = this.nextPrefix();
|
|
34402
34916
|
const queueDir = join25(this.basePath, q);
|
|
34403
34917
|
writeFileSync12(join25(queueDir, `${prefix}_${jobId}.queue-data`), JSON.stringify(job, null, 2));
|
|
34404
|
-
|
|
34918
|
+
unlinkSync8(filePath);
|
|
34405
34919
|
return true;
|
|
34406
34920
|
}
|
|
34407
34921
|
}
|
|
@@ -34437,7 +34951,7 @@ var init_liteBackend = __esm({
|
|
|
34437
34951
|
const files = readdirSync12(failedDir).filter((f) => f.endsWith(".queue-data"));
|
|
34438
34952
|
for (const file of files) {
|
|
34439
34953
|
try {
|
|
34440
|
-
|
|
34954
|
+
unlinkSync8(join25(failedDir, file));
|
|
34441
34955
|
count++;
|
|
34442
34956
|
} catch {
|
|
34443
34957
|
}
|
|
@@ -34452,7 +34966,7 @@ var init_liteBackend = __esm({
|
|
|
34452
34966
|
try {
|
|
34453
34967
|
const job = JSON.parse(readFileSync16(join25(dir, file), "utf-8"));
|
|
34454
34968
|
if (job.status === status2) {
|
|
34455
|
-
|
|
34969
|
+
unlinkSync8(join25(dir, file));
|
|
34456
34970
|
count++;
|
|
34457
34971
|
}
|
|
34458
34972
|
} catch {
|
|
@@ -34487,7 +35001,7 @@ var init_liteBackend = __esm({
|
|
|
34487
35001
|
job.delayUntil = null;
|
|
34488
35002
|
const prefix = this.nextPrefix();
|
|
34489
35003
|
writeFileSync12(join25(queueDir, `${prefix}_${job.id}.queue-data`), JSON.stringify(job, null, 2));
|
|
34490
|
-
|
|
35004
|
+
unlinkSync8(filePath);
|
|
34491
35005
|
count++;
|
|
34492
35006
|
} catch {
|
|
34493
35007
|
}
|
|
@@ -34519,10 +35033,10 @@ var init_liteBackend = __esm({
|
|
|
34519
35033
|
job.priority = job.priority ?? 0;
|
|
34520
35034
|
this.writeReserved(queue, job);
|
|
34521
35035
|
try {
|
|
34522
|
-
|
|
35036
|
+
unlinkSync8(filePath);
|
|
34523
35037
|
} catch {
|
|
34524
35038
|
try {
|
|
34525
|
-
|
|
35039
|
+
unlinkSync8(this.reservedPath(queue, job.id));
|
|
34526
35040
|
} catch {
|
|
34527
35041
|
}
|
|
34528
35042
|
continue;
|
|
@@ -34624,7 +35138,7 @@ var init_liteBackend = __esm({
|
|
|
34624
35138
|
retryJob(queue, job, delaySeconds) {
|
|
34625
35139
|
this.clearReservation(queue, job.id);
|
|
34626
35140
|
try {
|
|
34627
|
-
|
|
35141
|
+
unlinkSync8(join25(this.ensureFailedDir(queue), `${job.id}.queue-data`));
|
|
34628
35142
|
} catch {
|
|
34629
35143
|
}
|
|
34630
35144
|
job.attempts = (job.attempts || 0) + 1;
|
|
@@ -35174,7 +35688,8 @@ function archiveDir() {
|
|
|
35174
35688
|
return p;
|
|
35175
35689
|
}
|
|
35176
35690
|
function slugify(title) {
|
|
35177
|
-
const
|
|
35691
|
+
const dashed = (title || "").trim().toLowerCase().replace(/[^A-Za-z0-9_-]+/g, "-");
|
|
35692
|
+
const slug = trimChar(dashed, 45);
|
|
35178
35693
|
return slug.slice(0, 80) || `plan-${Math.floor(Date.now() / 1e3)}`;
|
|
35179
35694
|
}
|
|
35180
35695
|
function parse(text) {
|
|
@@ -35311,6 +35826,7 @@ var PLAN_DIR, CURRENT_FILE, ARCHIVE_SUBDIR, STEP_RE, Plan;
|
|
|
35311
35826
|
var init_plan = __esm({
|
|
35312
35827
|
"../core/src/plan.ts"() {
|
|
35313
35828
|
"use strict";
|
|
35829
|
+
init_slashTrim();
|
|
35314
35830
|
PLAN_DIR = "plan";
|
|
35315
35831
|
CURRENT_FILE = ".current";
|
|
35316
35832
|
ARCHIVE_SUBDIR = "done";
|
|
@@ -35582,7 +36098,7 @@ var init_plan = __esm({
|
|
|
35582
36098
|
const existing = (currentPlan.steps || []).map((s) => s.text || "");
|
|
35583
36099
|
const title = currentPlan.title || target;
|
|
35584
36100
|
const goal = currentPlan.goal || "";
|
|
35585
|
-
const aiUrl = process.env.TINA4_AI_URL || "http://localhost:
|
|
36101
|
+
const aiUrl = process.env.TINA4_AI_URL || "http://localhost:11435/api/chat";
|
|
35586
36102
|
const aiModel = process.env.TINA4_AI_MODEL || "qwen2.5-coder:14b";
|
|
35587
36103
|
const prompts = fleshPrompt(title, goal, existing, prompt);
|
|
35588
36104
|
const fetched = await fetchFleshReply(aiUrl, aiModel, prompts);
|
|
@@ -36550,7 +37066,7 @@ function relativePath(absPath, projectRoot3, frameworkRoots) {
|
|
|
36550
37066
|
}
|
|
36551
37067
|
function tokenise(text) {
|
|
36552
37068
|
if (!text) return [];
|
|
36553
|
-
const expanded = text.replace(
|
|
37069
|
+
const expanded = text.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z])(?=[A-Z][a-z])/g, "$1 ").toLowerCase();
|
|
36554
37070
|
return expanded.split(/[\s_\-./:,;()\[\]{}\\]+/).filter((p) => p.length > 0);
|
|
36555
37071
|
}
|
|
36556
37072
|
function summariseDoc(doc) {
|
|
@@ -36781,7 +37297,7 @@ function returnFromSignature(signature) {
|
|
|
36781
37297
|
const rest = signature.slice(close + 1).trim();
|
|
36782
37298
|
return rest.startsWith(":") ? rest.slice(1).trim() : "";
|
|
36783
37299
|
}
|
|
36784
|
-
var STDLIB_ALLOWLIST, _DOCS_CACHE, __FILENAME, __DIRNAME, USER_DIRS,
|
|
37300
|
+
var STDLIB_ALLOWLIST, _DOCS_CACHE, __FILENAME, __DIRNAME, USER_DIRS, FENCE_RE, CALL_RE, sharedFrameworkIndex, Docs;
|
|
36785
37301
|
var init_docs = __esm({
|
|
36786
37302
|
"../core/src/docs.ts"() {
|
|
36787
37303
|
"use strict";
|
|
@@ -36920,7 +37436,6 @@ var init_docs = __esm({
|
|
|
36920
37436
|
__FILENAME = fileURLToPath7(import.meta.url);
|
|
36921
37437
|
__DIRNAME = path8.dirname(__FILENAME);
|
|
36922
37438
|
USER_DIRS = ["src/orm", "src/routes", "src/app", "src/services", "src/models"];
|
|
36923
|
-
CAMEL_SPLIT = /([a-z0-9])([A-Z])|([A-Z]+)([A-Z][a-z])/g;
|
|
36924
37439
|
FENCE_RE = new RegExp(
|
|
36925
37440
|
String.fromCharCode(96, 96, 96) + "[a-zA-Z0-9_+-]*\\n([\\s\\S]*?)\\n" + String.fromCharCode(96, 96, 96),
|
|
36926
37441
|
"g"
|
|
@@ -37294,7 +37809,7 @@ ${end}
|
|
|
37294
37809
|
|
|
37295
37810
|
// ../core/src/devAdmin.ts
|
|
37296
37811
|
import { cpus as osCpus } from "node:os";
|
|
37297
|
-
import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, existsSync as existsSync24, readdirSync as readdirSync16, mkdirSync as mkdirSync19, copyFileSync as copyFileSync3, statSync as statSync18, openSync as
|
|
37812
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, existsSync as existsSync24, readdirSync as readdirSync16, mkdirSync as mkdirSync19, copyFileSync as copyFileSync3, statSync as statSync18, openSync as openSync5, closeSync as closeSync5, fstatSync as fstatSync3, fchmodSync as fchmodSync2, ftruncateSync as ftruncateSync2, constants as constants4, realpathSync as realpathSync6, lstatSync as lstatSync3 } from "node:fs";
|
|
37298
37813
|
import { join as join29, dirname as dirname15, resolve as resolve17, relative as relative9, sep as sep8, basename as basename6 } from "node:path";
|
|
37299
37814
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
37300
37815
|
import { timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
@@ -37493,8 +38008,41 @@ function quoteTableRef(name) {
|
|
|
37493
38008
|
}
|
|
37494
38009
|
return parts.map((p) => `"${p}"`).join(".");
|
|
37495
38010
|
}
|
|
38011
|
+
function parseSeedRequest(url, body) {
|
|
38012
|
+
const b = body ?? {};
|
|
38013
|
+
const table2 = String(url.searchParams.get("table") ?? b.table ?? "");
|
|
38014
|
+
const count = parseInt(String(url.searchParams.get("count") ?? b.count ?? "10"), 10) || 10;
|
|
38015
|
+
const seedRaw = url.searchParams.get("seed") ?? b.seed;
|
|
38016
|
+
const seed = seedRaw !== void 0 && seedRaw !== null && String(seedRaw) !== "" ? Number.isNaN(parseInt(String(seedRaw), 10)) ? void 0 : parseInt(String(seedRaw), 10) : void 0;
|
|
38017
|
+
const clear = String(url.searchParams.get("clear") ?? b.clear ?? "") === "true" || b.clear === true;
|
|
38018
|
+
const strict = String(url.searchParams.get("strict") ?? b.strict ?? "") === "true" || b.strict === true;
|
|
38019
|
+
return { table: table2, count, seed, clear, strict };
|
|
38020
|
+
}
|
|
38021
|
+
function buildSeedFieldMap(columns, fake) {
|
|
38022
|
+
const rules = [
|
|
38023
|
+
[(n) => n.includes("email"), () => fake.email()],
|
|
38024
|
+
[(n) => n.includes("name"), () => fake.name()],
|
|
38025
|
+
[(n) => n.includes("phone"), () => fake.phone()],
|
|
38026
|
+
[(n) => n.includes("address") || n.includes("city") || n.includes("country"), () => fake.address()],
|
|
38027
|
+
[(n) => n.includes("url") || n.includes("website"), () => fake.url()],
|
|
38028
|
+
[(_n, t) => t.includes("int"), () => fake.integer(1, 1e3)],
|
|
38029
|
+
[(_n, t) => /real|float|double|numeric|decimal/.test(t), () => fake.numeric(0, 1e3, 2)],
|
|
38030
|
+
[(_n, t) => t.includes("bool"), () => fake.boolean()],
|
|
38031
|
+
[(_n, t) => t.includes("date") || t.includes("time"), () => fake.date()]
|
|
38032
|
+
];
|
|
38033
|
+
const sentence = () => fake.sentence(3);
|
|
38034
|
+
const fieldMap = {};
|
|
38035
|
+
for (const col of columns) {
|
|
38036
|
+
if (col.name.toLowerCase() === "id" || col.primaryKey === true) continue;
|
|
38037
|
+
const name = col.name.toLowerCase();
|
|
38038
|
+
const type2 = col.type.toLowerCase();
|
|
38039
|
+
const rule = rules.find(([matches]) => matches(name, type2));
|
|
38040
|
+
fieldMap[col.name] = rule ? rule[1] : sentence;
|
|
38041
|
+
}
|
|
38042
|
+
return fieldMap;
|
|
38043
|
+
}
|
|
37496
38044
|
function supervisorBaseUrl() {
|
|
37497
|
-
const explicit = (process.env.TINA4_SUPERVISOR_URL ?? "")
|
|
38045
|
+
const explicit = rtrimSlashes(process.env.TINA4_SUPERVISOR_URL ?? "");
|
|
37498
38046
|
if (explicit) return explicit;
|
|
37499
38047
|
const agentPort = (process.env.TINA4_AGENT_PORT ?? "").trim();
|
|
37500
38048
|
if (/^\d+$/.test(agentPort)) return `http://127.0.0.1:${parseInt(agentPort, 10)}`;
|
|
@@ -37502,6 +38050,42 @@ function supervisorBaseUrl() {
|
|
|
37502
38050
|
if (/^\d+$/.test(fwPort)) return `http://127.0.0.1:${parseInt(fwPort, 10) + 2e3}`;
|
|
37503
38051
|
return "http://127.0.0.1:9145";
|
|
37504
38052
|
}
|
|
38053
|
+
function buildSupervisorBody(method, body) {
|
|
38054
|
+
if (method !== "POST" && method !== "PUT" && method !== "PATCH" && method !== "DELETE") return void 0;
|
|
38055
|
+
if (body === void 0 || body === null) return void 0;
|
|
38056
|
+
if (typeof body === "string") return body;
|
|
38057
|
+
if (typeof body !== "object") return void 0;
|
|
38058
|
+
let outBody = body;
|
|
38059
|
+
if (!Array.isArray(body)) {
|
|
38060
|
+
const pf = body.plan_file;
|
|
38061
|
+
if (typeof pf === "string" && pf && !pf.includes("/")) outBody = { ...body, plan_file: `plan/${pf}` };
|
|
38062
|
+
}
|
|
38063
|
+
return JSON.stringify(outBody);
|
|
38064
|
+
}
|
|
38065
|
+
async function streamEventStream(res, upstream, timer) {
|
|
38066
|
+
res.raw.writeHead(upstream.status || 200, {
|
|
38067
|
+
"Content-Type": upstream.headers.get("content-type") ?? "text/event-stream",
|
|
38068
|
+
"Cache-Control": "no-cache",
|
|
38069
|
+
Connection: "keep-alive"
|
|
38070
|
+
});
|
|
38071
|
+
if (typeof res.raw.flushHeaders === "function") res.raw.flushHeaders();
|
|
38072
|
+
if (!upstream.body) {
|
|
38073
|
+
res.raw.end();
|
|
38074
|
+
clearTimeout(timer);
|
|
38075
|
+
return;
|
|
38076
|
+
}
|
|
38077
|
+
const reader = upstream.body.getReader();
|
|
38078
|
+
try {
|
|
38079
|
+
while (true) {
|
|
38080
|
+
const { done, value } = await reader.read();
|
|
38081
|
+
if (done) break;
|
|
38082
|
+
if (value) res.raw.write(Buffer.from(value));
|
|
38083
|
+
}
|
|
38084
|
+
} finally {
|
|
38085
|
+
clearTimeout(timer);
|
|
38086
|
+
res.raw.end();
|
|
38087
|
+
}
|
|
38088
|
+
}
|
|
37505
38089
|
async function proxyToSupervisor(req2, res, downstreamPath) {
|
|
37506
38090
|
const base = supervisorBaseUrl();
|
|
37507
38091
|
let qs = "";
|
|
@@ -37512,24 +38096,7 @@ async function proxyToSupervisor(req2, res, downstreamPath) {
|
|
|
37512
38096
|
}
|
|
37513
38097
|
const target = `${base}${downstreamPath}${qs}`;
|
|
37514
38098
|
const method = (req2.method ?? "GET").toUpperCase();
|
|
37515
|
-
|
|
37516
|
-
if (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE") {
|
|
37517
|
-
const body = req2.body;
|
|
37518
|
-
if (body !== void 0 && body !== null) {
|
|
37519
|
-
if (typeof body === "string") {
|
|
37520
|
-
bodyText = body;
|
|
37521
|
-
} else if (typeof body === "object") {
|
|
37522
|
-
let outBody = body;
|
|
37523
|
-
if (!Array.isArray(body)) {
|
|
37524
|
-
const pf = body.plan_file;
|
|
37525
|
-
if (typeof pf === "string" && pf && !pf.includes("/")) {
|
|
37526
|
-
outBody = { ...body, plan_file: `plan/${pf}` };
|
|
37527
|
-
}
|
|
37528
|
-
}
|
|
37529
|
-
bodyText = JSON.stringify(outBody);
|
|
37530
|
-
}
|
|
37531
|
-
}
|
|
37532
|
-
}
|
|
38099
|
+
const bodyText = buildSupervisorBody(method, req2.body);
|
|
37533
38100
|
const timeoutMs = downstreamPath === "/execute" || downstreamPath === "/chat" ? 6e5 : 3e4;
|
|
37534
38101
|
const ctrl = new AbortController();
|
|
37535
38102
|
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
@@ -37555,30 +38122,7 @@ async function proxyToSupervisor(req2, res, downstreamPath) {
|
|
|
37555
38122
|
}
|
|
37556
38123
|
const ct = (upstream.headers.get("content-type") ?? "").toLowerCase();
|
|
37557
38124
|
if (ct.includes("text/event-stream")) {
|
|
37558
|
-
res
|
|
37559
|
-
"Content-Type": upstream.headers.get("content-type") ?? "text/event-stream",
|
|
37560
|
-
"Cache-Control": "no-cache",
|
|
37561
|
-
Connection: "keep-alive"
|
|
37562
|
-
});
|
|
37563
|
-
if (typeof res.raw.flushHeaders === "function") {
|
|
37564
|
-
res.raw.flushHeaders();
|
|
37565
|
-
}
|
|
37566
|
-
if (!upstream.body) {
|
|
37567
|
-
res.raw.end();
|
|
37568
|
-
clearTimeout(timer);
|
|
37569
|
-
return;
|
|
37570
|
-
}
|
|
37571
|
-
const reader = upstream.body.getReader();
|
|
37572
|
-
try {
|
|
37573
|
-
while (true) {
|
|
37574
|
-
const { done, value } = await reader.read();
|
|
37575
|
-
if (done) break;
|
|
37576
|
-
if (value) res.raw.write(Buffer.from(value));
|
|
37577
|
-
}
|
|
37578
|
-
} finally {
|
|
37579
|
-
clearTimeout(timer);
|
|
37580
|
-
res.raw.end();
|
|
37581
|
-
}
|
|
38125
|
+
await streamEventStream(res, upstream, timer);
|
|
37582
38126
|
return;
|
|
37583
38127
|
}
|
|
37584
38128
|
clearTimeout(timer);
|
|
@@ -37695,13 +38239,13 @@ function handleGalleryDeploy(router) {
|
|
|
37695
38239
|
res.json({ deployed: name, files: copied });
|
|
37696
38240
|
};
|
|
37697
38241
|
}
|
|
37698
|
-
function
|
|
38242
|
+
function realPathOf2(target) {
|
|
37699
38243
|
let existing = target;
|
|
37700
38244
|
const tail = [];
|
|
37701
38245
|
for (; ; ) {
|
|
37702
38246
|
let present = false;
|
|
37703
38247
|
try {
|
|
37704
|
-
|
|
38248
|
+
lstatSync3(existing);
|
|
37705
38249
|
present = true;
|
|
37706
38250
|
} catch {
|
|
37707
38251
|
}
|
|
@@ -37713,9 +38257,9 @@ function realPathOf(target) {
|
|
|
37713
38257
|
}
|
|
37714
38258
|
function safeJoin(projectRoot3, rel, extraRoots = []) {
|
|
37715
38259
|
try {
|
|
37716
|
-
const root =
|
|
37717
|
-
const resolved =
|
|
37718
|
-
const roots = [root, ...extraRoots.filter(Boolean).map((r) =>
|
|
38260
|
+
const root = realPathOf2(resolve17(projectRoot3));
|
|
38261
|
+
const resolved = realPathOf2(resolve17(root, rel));
|
|
38262
|
+
const roots = [root, ...extraRoots.filter(Boolean).map((r) => realPathOf2(resolve17(r)))];
|
|
37719
38263
|
for (const r of roots) {
|
|
37720
38264
|
if (resolved === r || resolved.startsWith(r.endsWith(sep8) ? r : r + sep8)) return resolved;
|
|
37721
38265
|
}
|
|
@@ -37724,7 +38268,7 @@ function safeJoin(projectRoot3, rel, extraRoots = []) {
|
|
|
37724
38268
|
return null;
|
|
37725
38269
|
}
|
|
37726
38270
|
function resolvedRelative(projectRoot3, resolvedPath) {
|
|
37727
|
-
return relative9(
|
|
38271
|
+
return relative9(realPathOf2(resolve17(projectRoot3)), resolvedPath);
|
|
37728
38272
|
}
|
|
37729
38273
|
function devFilesHidden(name) {
|
|
37730
38274
|
if (DEV_FILES_IGNORED.has(name)) return true;
|
|
@@ -37752,7 +38296,7 @@ async function devGitInfo(root) {
|
|
|
37752
38296
|
if (!inside || inside.trim() !== "true") return empty;
|
|
37753
38297
|
const branch = (git(["rev-parse", "--abbrev-ref", "HEAD"]) ?? "").trim();
|
|
37754
38298
|
const topRaw = git(["rev-parse", "--show-toplevel"]);
|
|
37755
|
-
const gitRoot = topRaw && topRaw.trim() !== "" ? topRaw.trim().replace(/\\/g, "/")
|
|
38299
|
+
const gitRoot = topRaw && topRaw.trim() !== "" ? rtrimSlashes(topRaw.trim().replace(/\\/g, "/")) : null;
|
|
37756
38300
|
const status2 = /* @__PURE__ */ new Map();
|
|
37757
38301
|
const porcelain = git(["status", "--porcelain", "-uall"]);
|
|
37758
38302
|
if (porcelain) {
|
|
@@ -37771,6 +38315,44 @@ async function devGitInfo(root) {
|
|
|
37771
38315
|
return empty;
|
|
37772
38316
|
}
|
|
37773
38317
|
}
|
|
38318
|
+
function devGitLabel(gitPath, isDir, gitStatus) {
|
|
38319
|
+
const code = gitStatus.get(gitPath);
|
|
38320
|
+
if (code !== void 0) return devGitStatusLabel(code);
|
|
38321
|
+
if (isDir) {
|
|
38322
|
+
const prefix = gitPath + "/";
|
|
38323
|
+
for (const [gf, gc] of gitStatus) {
|
|
38324
|
+
if (gf.startsWith(prefix)) return gc === "??" ? "untracked" : "modified";
|
|
38325
|
+
}
|
|
38326
|
+
}
|
|
38327
|
+
return "clean";
|
|
38328
|
+
}
|
|
38329
|
+
function devDirHasVisibleChild(full) {
|
|
38330
|
+
try {
|
|
38331
|
+
for (const c of readdirSync16(full)) {
|
|
38332
|
+
if (!devFilesHidden(c)) return true;
|
|
38333
|
+
}
|
|
38334
|
+
} catch {
|
|
38335
|
+
}
|
|
38336
|
+
return false;
|
|
38337
|
+
}
|
|
38338
|
+
function buildFileEntry(name, full, entryRel, cwdInGit, gitStatus) {
|
|
38339
|
+
let isDir = false;
|
|
38340
|
+
let size = null;
|
|
38341
|
+
try {
|
|
38342
|
+
const st = statSync18(full);
|
|
38343
|
+
isDir = st.isDirectory();
|
|
38344
|
+
if (!isDir) size = st.size;
|
|
38345
|
+
} catch {
|
|
38346
|
+
}
|
|
38347
|
+
return {
|
|
38348
|
+
name,
|
|
38349
|
+
path: entryRel,
|
|
38350
|
+
is_dir: isDir,
|
|
38351
|
+
has_children: isDir ? devDirHasVisibleChild(full) : null,
|
|
38352
|
+
git_status: devGitLabel(cwdInGit + entryRel, isDir, gitStatus),
|
|
38353
|
+
size
|
|
38354
|
+
};
|
|
38355
|
+
}
|
|
37774
38356
|
function devAdminLanguage(rel) {
|
|
37775
38357
|
const base = (rel.split(/[\\/]/).pop() ?? "").toLowerCase();
|
|
37776
38358
|
if (base === "dockerfile" || base === "dockerfile.dev" || base === "dockerfile.prod") {
|
|
@@ -37785,14 +38367,14 @@ function devAdminLanguage(rel) {
|
|
|
37785
38367
|
function readDevFile(target) {
|
|
37786
38368
|
let fd;
|
|
37787
38369
|
try {
|
|
37788
|
-
fd =
|
|
37789
|
-
if (!
|
|
38370
|
+
fd = openSync5(target, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
|
|
38371
|
+
if (!fstatSync3(fd).isFile()) return null;
|
|
37790
38372
|
return readFileSync20(fd);
|
|
37791
38373
|
} catch (error2) {
|
|
37792
38374
|
if (["ENOENT", "ENOTDIR", "ELOOP"].includes(error2.code ?? "")) return null;
|
|
37793
38375
|
throw error2;
|
|
37794
38376
|
} finally {
|
|
37795
|
-
if (fd !== void 0)
|
|
38377
|
+
if (fd !== void 0) closeSync5(fd);
|
|
37796
38378
|
}
|
|
37797
38379
|
}
|
|
37798
38380
|
function mcpSecureEqual(expected, provided) {
|
|
@@ -38019,10 +38601,11 @@ function toolbarJs() {
|
|
|
38019
38601
|
connect();
|
|
38020
38602
|
})();`;
|
|
38021
38603
|
}
|
|
38022
|
-
var cpuCount, DEV_MCP_PREFIXES, DEV_PUBLIC_ASSETS, DEV_SECRET_BASENAMES, DEV_SECRET_SUFFIXES, MessageLog, RequestInspector, ErrorTracker, DevMailboxStore, DevQueue, WsTracker, DevAdmin, handleDashboard, _reloadMtime, _reloadFile, handleMtime, handleReload, handleMessages, handleMessagesClear, handleRequests, handleRequestsClear, handleSystem, handleMessagesSearch, handleQueue, handleQueueTopics, handleQueueDeadLetters, handleQueueRetry, handleQueuePurge, handleQueueReplay, handleMailbox, handleMailboxRead, handleMailboxSeed, handleMailboxClear, handleTable, handleTables, handleSeed, handleQuery, handleBroken, handleBrokenResolve, handleBrokenClear, handleWebsockets, handleWebsocketsDisconnect, handleTool, DEFAULT_MCP_URL, handleGroundingStatus, handleGroundingToken, handleMigrate, handleSeedRun, handleTest, handleThreads, handleThreadsSub, handleConnections, handleConnectionsTest, handleConnectionsSave, __devAdminFilename, __devAdminDirname, handleGalleryList, handleVersionCheck, handleThoughts, handleSuperviseStub, DEV_FILES_IGNORED, handleFiles, DEV_ADMIN_LANG_MAP, handleFileRead, handleFileSave, handleFileRaw, handleFileRename, handleFileDelete, handleDepsSearch, handleDepsInstall, handleGitStatus, handleMcpTools, handleMcpCall, handleMcpStreamable, handleMcpDelete, handleMcpGet405, handleMcpLegacyMessage, handleMcpSse, handleScaffoldList, handleScaffoldRun, handlePlanCurrent, handlePlanList, handlePlanCreate, handlePlanSwitch, handlePlanCompleteStep, handlePlanAddStep, handlePlanNote, handlePlanArchive, handlePlanRead, handlePlanFlesh, handleIndexRebuild, handleIndexSearch, handleIndexFile, handleIndexOverview, handleDocsSearch, handleDocsClass, handleDocsMethod, handleDocsIndex, handleDocsWellKnown, handleDevAdminJs, handleToolbarCss, handleToolbarJs;
|
|
38604
|
+
var cpuCount, DEV_MCP_PREFIXES, DEV_PUBLIC_ASSETS, DEV_SECRET_BASENAMES, DEV_SECRET_SUFFIXES, MessageLog, RequestInspector, ErrorTracker, DevMailboxStore, DevQueue, WsTracker, DevAdmin, handleDashboard, _reloadMtime, _reloadFile, handleMtime, handleReload, handleMessages, handleMessagesClear, handleRequests, handleRequestsClear, handleSystem, handleMessagesSearch, handleQueue, handleQueueTopics, handleQueueDeadLetters, handleQueueRetry, handleQueuePurge, handleQueueReplay, handleMailbox, handleMailboxRead, handleMailboxSeed, handleMailboxClear, handleTable, handleTables, handleSeed, handleQuery, handleBroken, handleBrokenResolve, handleBrokenClear, handleWebsockets, handleWebsocketsDisconnect, handleTool, DEFAULT_MCP_URL, handleGroundingStatus, handleGroundingToken, handleMigrate, handleSeedRun, handleTest, handleThreads, handleThreadsSub, handleConnections, handleConnectionsTest, handleConnectionsSave, __devAdminFilename, __devAdminDirname, handleGalleryList, handleVersionCheck, handleThoughts, handleSuperviseStub, DEV_FILES_IGNORED, handleFiles, DEV_ADMIN_LANG_MAP, handleFileRead, handleFileSave, handleFileRaw, handleFileRename, handleFileDelete, handleDepsSearch, handleDepsInstall, handleGitStatus, handleMcpTools, handleMcpCall, handleMcpStreamable, handleMcpDelete, handleMcpGet405, handleMcpLegacyMessage, handleMcpSse, handleScaffoldList, handleScaffoldRun, handlePlanCurrent, handlePlanList, handlePlanCreate, handlePlanSwitch, handlePlanCompleteStep, handlePlanAddStep, handlePlanNote, handlePlanArchive, handlePlanRead, handlePlanFlesh, handleIndexRebuild, handleIndexSearch, handleIndexFile, handleIndexOverview, handleDocsSearch, handleDocsClass, handleDocsMethod, handleDocsIndex, handleDocsWellKnown, handleDevAdminJs, handleDevAdminSplit, handleToolbarCss, handleToolbarJs;
|
|
38023
38605
|
var init_devAdmin = __esm({
|
|
38024
38606
|
"../core/src/devAdmin.ts"() {
|
|
38025
38607
|
"use strict";
|
|
38608
|
+
init_slashTrim();
|
|
38026
38609
|
init_devMailbox();
|
|
38027
38610
|
init_upstreamResponse();
|
|
38028
38611
|
init_dotenv();
|
|
@@ -38489,6 +39072,7 @@ var init_devAdmin = __esm({
|
|
|
38489
39072
|
{ method: "GET", pattern: "/__dev/api/docs/.well-known.json", handler: handleDocsWellKnown },
|
|
38490
39073
|
// JS asset
|
|
38491
39074
|
{ method: "GET", pattern: "/__dev/js/tina4-dev-admin.min.js", handler: handleDevAdminJs },
|
|
39075
|
+
{ method: "GET", pattern: "/__dev/split", handler: handleDevAdminSplit },
|
|
38492
39076
|
// Dev-toolbar assets — served as external CSS/JS so the injected toolbar is
|
|
38493
39077
|
// CSP-clean (no inline style=, onclick=, or <script>) under a strict
|
|
38494
39078
|
// `default-src 'self'`. Parity with PHP's /__dev/toolbar.css + toolbar.js.
|
|
@@ -38855,13 +39439,7 @@ var init_devAdmin = __esm({
|
|
|
38855
39439
|
};
|
|
38856
39440
|
handleSeed = async (req2, res) => {
|
|
38857
39441
|
const url = new URL(req2.url ?? "/", "http://localhost");
|
|
38858
|
-
const
|
|
38859
|
-
const table2 = url.searchParams.get("table") ?? body?.table ?? "";
|
|
38860
|
-
const count = parseInt(String(url.searchParams.get("count") ?? body?.count ?? "10"), 10) || 10;
|
|
38861
|
-
const seedRaw = url.searchParams.get("seed") ?? body?.seed;
|
|
38862
|
-
const seed = seedRaw !== void 0 && seedRaw !== null && String(seedRaw) !== "" ? Number.isNaN(parseInt(String(seedRaw), 10)) ? void 0 : parseInt(String(seedRaw), 10) : void 0;
|
|
38863
|
-
const clear = String(url.searchParams.get("clear") ?? body?.clear ?? "") === "true" || body?.clear === true;
|
|
38864
|
-
const strict = String(url.searchParams.get("strict") ?? body?.strict ?? "") === "true" || body?.strict === true;
|
|
39442
|
+
const { table: table2, count, seed, clear, strict } = parseSeedRequest(url, req2.body);
|
|
38865
39443
|
if (!table2) {
|
|
38866
39444
|
res.json({ error: "Missing table parameter" });
|
|
38867
39445
|
return;
|
|
@@ -38876,33 +39454,7 @@ var init_devAdmin = __esm({
|
|
|
38876
39454
|
res.json({ error: `Table '${table2}' not found or has no columns` });
|
|
38877
39455
|
return;
|
|
38878
39456
|
}
|
|
38879
|
-
const fieldMap =
|
|
38880
|
-
for (const col of columns) {
|
|
38881
|
-
const name = col.name.toLowerCase();
|
|
38882
|
-
const type2 = col.type.toLowerCase();
|
|
38883
|
-
if (name === "id" || col.primaryKey === true) continue;
|
|
38884
|
-
if (name.includes("email")) {
|
|
38885
|
-
fieldMap[col.name] = () => fake.email();
|
|
38886
|
-
} else if (name.includes("name")) {
|
|
38887
|
-
fieldMap[col.name] = () => fake.name();
|
|
38888
|
-
} else if (name.includes("phone")) {
|
|
38889
|
-
fieldMap[col.name] = () => fake.phone();
|
|
38890
|
-
} else if (name.includes("address") || name.includes("city") || name.includes("country")) {
|
|
38891
|
-
fieldMap[col.name] = () => fake.address();
|
|
38892
|
-
} else if (name.includes("url") || name.includes("website")) {
|
|
38893
|
-
fieldMap[col.name] = () => fake.url();
|
|
38894
|
-
} else if (type2.includes("int")) {
|
|
38895
|
-
fieldMap[col.name] = () => fake.integer(1, 1e3);
|
|
38896
|
-
} else if (type2.includes("real") || type2.includes("float") || type2.includes("double") || type2.includes("numeric") || type2.includes("decimal")) {
|
|
38897
|
-
fieldMap[col.name] = () => fake.numeric(0, 1e3, 2);
|
|
38898
|
-
} else if (type2.includes("bool")) {
|
|
38899
|
-
fieldMap[col.name] = () => fake.boolean();
|
|
38900
|
-
} else if (type2.includes("date") || type2.includes("time")) {
|
|
38901
|
-
fieldMap[col.name] = () => fake.date();
|
|
38902
|
-
} else {
|
|
38903
|
-
fieldMap[col.name] = () => fake.sentence(3);
|
|
38904
|
-
}
|
|
38905
|
-
}
|
|
39457
|
+
const fieldMap = buildSeedFieldMap(columns, fake);
|
|
38906
39458
|
const summary = await seedTable2(db, table2, count, fieldMap, void 0, { clear, strict });
|
|
38907
39459
|
res.json({ seeded: summary.seeded, failed: summary.failed, errors: summary.errors, table: table2 });
|
|
38908
39460
|
} catch (e) {
|
|
@@ -39075,9 +39627,9 @@ var init_devAdmin = __esm({
|
|
|
39075
39627
|
};
|
|
39076
39628
|
handleTest = async (_req, res) => {
|
|
39077
39629
|
try {
|
|
39078
|
-
const { execFile } = await import("node:child_process");
|
|
39630
|
+
const { execFile: execFile2 } = await import("node:child_process");
|
|
39079
39631
|
const { promisify } = await import("node:util");
|
|
39080
|
-
const run = promisify(
|
|
39632
|
+
const run = promisify(execFile2);
|
|
39081
39633
|
try {
|
|
39082
39634
|
const { stdout, stderr } = await run("npm", ["test"], {
|
|
39083
39635
|
cwd: resolve17(process.cwd()),
|
|
@@ -39195,9 +39747,9 @@ var init_devAdmin = __esm({
|
|
|
39195
39747
|
}
|
|
39196
39748
|
try {
|
|
39197
39749
|
const envPath = join29(process.cwd(), ".env");
|
|
39198
|
-
const fd =
|
|
39750
|
+
const fd = openSync5(envPath, constants4.O_RDWR | constants4.O_APPEND | constants4.O_CREAT | (constants4.O_NOFOLLOW ?? 0) | (constants4.O_NONBLOCK ?? 0), 384);
|
|
39199
39751
|
try {
|
|
39200
|
-
const info =
|
|
39752
|
+
const info = fstatSync3(fd);
|
|
39201
39753
|
if (!info.isFile() || info.nlink !== 1) throw new Error("Refusing a non-regular or multiply-linked configuration file");
|
|
39202
39754
|
fchmodSync2(fd, 384);
|
|
39203
39755
|
const lines = readFileSync20(fd, "utf-8").split("\n");
|
|
@@ -39227,10 +39779,10 @@ var init_devAdmin = __esm({
|
|
|
39227
39779
|
for (const [key, found] of Object.entries(keysFound)) {
|
|
39228
39780
|
if (!found) newLines.push(`${key}=${values[key]}`);
|
|
39229
39781
|
}
|
|
39230
|
-
|
|
39782
|
+
ftruncateSync2(fd, 0);
|
|
39231
39783
|
writeFileSync16(fd, newLines.join("\n") + "\n");
|
|
39232
39784
|
} finally {
|
|
39233
|
-
|
|
39785
|
+
closeSync5(fd);
|
|
39234
39786
|
}
|
|
39235
39787
|
res.json({ success: true });
|
|
39236
39788
|
} catch (e) {
|
|
@@ -39353,48 +39905,7 @@ var init_devAdmin = __esm({
|
|
|
39353
39905
|
const full = join29(target, name);
|
|
39354
39906
|
const entryRel = relative9(root, full).replace(/\\/g, "/");
|
|
39355
39907
|
if (isSecretPath(entryRel)) continue;
|
|
39356
|
-
|
|
39357
|
-
let size = null;
|
|
39358
|
-
try {
|
|
39359
|
-
const st = statSync18(full);
|
|
39360
|
-
isDir = st.isDirectory();
|
|
39361
|
-
if (!isDir) size = st.size;
|
|
39362
|
-
} catch {
|
|
39363
|
-
}
|
|
39364
|
-
const gitPath = cwdInGit + entryRel;
|
|
39365
|
-
let gitLabel = "clean";
|
|
39366
|
-
const code = gitStatus.get(gitPath);
|
|
39367
|
-
if (code !== void 0) {
|
|
39368
|
-
gitLabel = devGitStatusLabel(code);
|
|
39369
|
-
} else if (isDir) {
|
|
39370
|
-
const prefix = gitPath + "/";
|
|
39371
|
-
for (const [gf, gc] of gitStatus) {
|
|
39372
|
-
if (gf.startsWith(prefix)) {
|
|
39373
|
-
gitLabel = gc === "??" ? "untracked" : "modified";
|
|
39374
|
-
break;
|
|
39375
|
-
}
|
|
39376
|
-
}
|
|
39377
|
-
}
|
|
39378
|
-
let hasChildren = null;
|
|
39379
|
-
if (isDir) {
|
|
39380
|
-
hasChildren = false;
|
|
39381
|
-
try {
|
|
39382
|
-
for (const c of readdirSync16(full)) {
|
|
39383
|
-
if (devFilesHidden(c)) continue;
|
|
39384
|
-
hasChildren = true;
|
|
39385
|
-
break;
|
|
39386
|
-
}
|
|
39387
|
-
} catch {
|
|
39388
|
-
}
|
|
39389
|
-
}
|
|
39390
|
-
entries.push({
|
|
39391
|
-
name,
|
|
39392
|
-
path: entryRel,
|
|
39393
|
-
is_dir: isDir,
|
|
39394
|
-
has_children: hasChildren,
|
|
39395
|
-
git_status: gitLabel,
|
|
39396
|
-
size
|
|
39397
|
-
});
|
|
39908
|
+
entries.push(buildFileEntry(name, full, entryRel, cwdInGit, gitStatus));
|
|
39398
39909
|
}
|
|
39399
39910
|
res.json({ path: relative9(root, target).replace(/\\/g, "/") || ".", branch, entries });
|
|
39400
39911
|
};
|
|
@@ -39927,6 +40438,31 @@ var init_devAdmin = __esm({
|
|
|
39927
40438
|
res.raw.writeHead(404, { "Content-Type": "text/plain" });
|
|
39928
40439
|
res.raw.end("tina4-dev-admin.min.js not found");
|
|
39929
40440
|
};
|
|
40441
|
+
handleDevAdminSplit = async (_req, res) => {
|
|
40442
|
+
const { readFileSync: readFileSync30, existsSync: existsSync38 } = await import("node:fs");
|
|
40443
|
+
const { dirname: dirname20, join: join41, resolve: resolve29 } = await import("node:path");
|
|
40444
|
+
const { fileURLToPath: fileURLToPath12 } = await import("node:url");
|
|
40445
|
+
const dir = dirname20(fileURLToPath12(import.meta.url));
|
|
40446
|
+
const candidates = [
|
|
40447
|
+
join41(dir, "..", "public", "js", "tina4-dev-admin-split.html"),
|
|
40448
|
+
join41(dir, "..", "..", "public", "js", "tina4-dev-admin-split.html"),
|
|
40449
|
+
resolve29(process.cwd(), "node_modules", "tina4-nodejs", "packages", "core", "public", "js", "tina4-dev-admin-split.html"),
|
|
40450
|
+
resolve29(process.cwd(), "public", "js", "tina4-dev-admin-split.html")
|
|
40451
|
+
];
|
|
40452
|
+
for (const path10 of candidates) {
|
|
40453
|
+
if (existsSync38(path10)) {
|
|
40454
|
+
try {
|
|
40455
|
+
const content = readFileSync30(path10, "utf-8");
|
|
40456
|
+
res.raw.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-cache" });
|
|
40457
|
+
res.raw.end(content);
|
|
40458
|
+
return;
|
|
40459
|
+
} catch {
|
|
40460
|
+
}
|
|
40461
|
+
}
|
|
40462
|
+
}
|
|
40463
|
+
res.raw.writeHead(404, { "Content-Type": "text/plain" });
|
|
40464
|
+
res.raw.end("tina4-dev-admin-split.html not found");
|
|
40465
|
+
};
|
|
39930
40466
|
handleToolbarCss = (_req, res) => {
|
|
39931
40467
|
res.raw.writeHead(200, { "Content-Type": "text/css; charset=utf-8", "Cache-Control": "no-cache" });
|
|
39932
40468
|
res.raw.end(toolbarCss());
|
|
@@ -40398,7 +40934,10 @@ function generate2(routes, models = []) {
|
|
|
40398
40934
|
openapi: resolveOpenApiVersion(),
|
|
40399
40935
|
info: buildInfo(),
|
|
40400
40936
|
servers: resolveServers(),
|
|
40401
|
-
|
|
40937
|
+
// Prototype-less: route paths are developer-defined, but a null prototype
|
|
40938
|
+
// makes `spec.paths[path][method] = op` structurally pollution-proof
|
|
40939
|
+
// regardless (js/prototype-polluting-assignment). Serialises to JSON the same.
|
|
40940
|
+
paths: /* @__PURE__ */ Object.create(null),
|
|
40402
40941
|
components: {
|
|
40403
40942
|
schemas: {},
|
|
40404
40943
|
// Configurable security schemes (v3.13.42): bearerFormat via env, optional
|
|
@@ -40463,7 +41002,7 @@ function buildOperation(route, spec, ctx) {
|
|
|
40463
41002
|
const openApiPath = patternToOpenAPI(route.pattern);
|
|
40464
41003
|
const method = route.method.toLowerCase();
|
|
40465
41004
|
if (!spec.paths[openApiPath]) {
|
|
40466
|
-
spec.paths[openApiPath] =
|
|
41005
|
+
spec.paths[openApiPath] = /* @__PURE__ */ Object.create(null);
|
|
40467
41006
|
}
|
|
40468
41007
|
const tags = route.meta?.tags ?? inferTags(route.pattern);
|
|
40469
41008
|
for (const t of tags) {
|
|
@@ -40769,7 +41308,7 @@ function inferModelFromPath(pattern) {
|
|
|
40769
41308
|
return null;
|
|
40770
41309
|
}
|
|
40771
41310
|
function operationIdBase(method, openApiPath) {
|
|
40772
|
-
const clean = openApiPath
|
|
41311
|
+
const clean = trimSlashes(openApiPath).replace(/\//g, "_").replace(/\.\.\./g, "").replace(/[{}]/g, "").replace(/\*/g, "wildcard");
|
|
40773
41312
|
return clean ? `${method}_${clean}` : method;
|
|
40774
41313
|
}
|
|
40775
41314
|
function uniqueOperationId(method, openApiPath, seen) {
|
|
@@ -40787,6 +41326,7 @@ var WRITE_METHODS, INTERNAL_PREFIXES, registeredSchemes, registeredSchemas, PARA
|
|
|
40787
41326
|
var init_generator = __esm({
|
|
40788
41327
|
"../swagger/src/generator.ts"() {
|
|
40789
41328
|
"use strict";
|
|
41329
|
+
init_slashTrim();
|
|
40790
41330
|
WRITE_METHODS = /* @__PURE__ */ new Set(["post", "put", "patch", "delete"]);
|
|
40791
41331
|
INTERNAL_PREFIXES = ["/swagger", "/__dev", "/__feedback", "/ai", "/rag", "/vision", "/embed", "/image"];
|
|
40792
41332
|
registeredSchemes = {};
|
|
@@ -40808,7 +41348,7 @@ var init_generator = __esm({
|
|
|
40808
41348
|
|
|
40809
41349
|
// ../swagger/src/ui.ts
|
|
40810
41350
|
function swaggerUiCdn() {
|
|
40811
|
-
return (process.env.TINA4_SWAGGER_UI_CDN ?? "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5")
|
|
41351
|
+
return rtrimSlashes(process.env.TINA4_SWAGGER_UI_CDN ?? "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5");
|
|
40812
41352
|
}
|
|
40813
41353
|
function swaggerEnabled() {
|
|
40814
41354
|
const raw = (process.env.TINA4_SWAGGER_ENABLED ?? "").trim().toLowerCase();
|
|
@@ -40864,6 +41404,7 @@ var SWAGGER_UI_HTML;
|
|
|
40864
41404
|
var init_ui = __esm({
|
|
40865
41405
|
"../swagger/src/ui.ts"() {
|
|
40866
41406
|
"use strict";
|
|
41407
|
+
init_slashTrim();
|
|
40867
41408
|
SWAGGER_UI_HTML = (specUrl, nonce) => `<!DOCTYPE html>
|
|
40868
41409
|
<html lang="en">
|
|
40869
41410
|
<head>
|
|
@@ -40918,7 +41459,7 @@ __export(sso_exports, {
|
|
|
40918
41459
|
SsoError: () => SsoError,
|
|
40919
41460
|
liveSessionIdentity: () => liveSessionIdentity
|
|
40920
41461
|
});
|
|
40921
|
-
import { createHash as
|
|
41462
|
+
import { createHash as createHash11, randomBytes as randomBytes8, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
|
|
40922
41463
|
function expiresAt(tokens) {
|
|
40923
41464
|
const lifetime = Number(tokens.expires_in ?? 0);
|
|
40924
41465
|
return lifetime > 0 ? Math.floor(Date.now() / 1e3) + lifetime : 0;
|
|
@@ -41049,7 +41590,7 @@ var init_sso = __esm({
|
|
|
41049
41590
|
const state = randomBytes8(32).toString("base64url");
|
|
41050
41591
|
const nonce = randomBytes8(32).toString("base64url");
|
|
41051
41592
|
const verifier = randomBytes8(64).toString("base64url");
|
|
41052
|
-
const challenge =
|
|
41593
|
+
const challenge = createHash11("sha256").update(verifier).digest("base64url");
|
|
41053
41594
|
session.set(_Sso.PENDING_KEY, { state, nonce, verifier, return_to: _Sso.safeReturn(returnTo), created_at: Math.floor(Date.now() / 1e3) });
|
|
41054
41595
|
const metadata = await this.discover();
|
|
41055
41596
|
const query = new URLSearchParams({
|
|
@@ -41281,7 +41822,7 @@ import { resolve as resolve20, dirname as dirname16, join as join32, relative as
|
|
|
41281
41822
|
import { existsSync as existsSync27, readdirSync as readdirSync18, readFileSync as readFileSync23, statSync as statSync19 } from "node:fs";
|
|
41282
41823
|
import { isatty } from "node:tty";
|
|
41283
41824
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
41284
|
-
import { execFileSync as execFileSync3,
|
|
41825
|
+
import { execFileSync as execFileSync3, execFile } from "node:child_process";
|
|
41285
41826
|
import cluster from "node:cluster";
|
|
41286
41827
|
import os2 from "node:os";
|
|
41287
41828
|
function isSwaggerAssetPath(pathname) {
|
|
@@ -41417,10 +41958,11 @@ function shouldOpenBrowser(isDevelopment, noBrowser = false) {
|
|
|
41417
41958
|
});
|
|
41418
41959
|
}
|
|
41419
41960
|
function openBrowser(url) {
|
|
41961
|
+
if (!/^https?:\/\/([A-Za-z0-9.-]+|\[[0-9A-Fa-f:]+\])(:\d{1,5})?\/?$/.test(url)) return;
|
|
41420
41962
|
setTimeout(() => {
|
|
41421
|
-
if (process.platform === "darwin")
|
|
41422
|
-
else if (process.platform === "win32")
|
|
41423
|
-
else
|
|
41963
|
+
if (process.platform === "darwin") execFile("open", [url]);
|
|
41964
|
+
else if (process.platform === "win32") execFile("rundll32", ["url.dll,FileProtocolHandler", url]);
|
|
41965
|
+
else execFile("xdg-open", [url]);
|
|
41424
41966
|
}, 2e3);
|
|
41425
41967
|
}
|
|
41426
41968
|
function resolvePortAndHost(config) {
|
|
@@ -41535,7 +42077,7 @@ function resetTemplateCache() {
|
|
|
41535
42077
|
}
|
|
41536
42078
|
function resolveTemplate(pathname, templatesDir) {
|
|
41537
42079
|
if (!templateAutoRoutingEnabled()) return null;
|
|
41538
|
-
const cleanPath = pathname
|
|
42080
|
+
const cleanPath = trimSlashes(pathname) || "index";
|
|
41539
42081
|
const isDev2 = (process.env.TINA4_DEBUG ?? "false").toLowerCase() === "true";
|
|
41540
42082
|
if (isDev2) {
|
|
41541
42083
|
if (cleanPath.split("/").some((seg) => seg.startsWith("_"))) return null;
|
|
@@ -41803,7 +42345,7 @@ async function runGlobalMiddlewarePass(middleware, req2, res) {
|
|
|
41803
42345
|
}
|
|
41804
42346
|
function resolveHandlerArgs(handler, req2, res, routeParams) {
|
|
41805
42347
|
const fnStr = handler.toString();
|
|
41806
|
-
const argMatch = fnStr.match(/^(?:async\s*)?(?:function
|
|
42348
|
+
const argMatch = fnStr.match(/^(?:async\s*)?(?:function(?:\s+\w+)?\s*)?\(([^)]*)\)/);
|
|
41807
42349
|
const argNames = argMatch?.[1]?.split(",").map((a) => a.trim().replace(/[:=].*/, "")) ?? [];
|
|
41808
42350
|
const filteredArgs = argNames.filter((n) => n.length > 0);
|
|
41809
42351
|
if (filteredArgs.length === 0) return [];
|
|
@@ -42039,8 +42581,9 @@ async function buildDispatchContext(router, base) {
|
|
|
42039
42581
|
const templatesDir = resolve20(root, "src/templates");
|
|
42040
42582
|
let frondEngine = null;
|
|
42041
42583
|
try {
|
|
42042
|
-
const { Frond: Frond2, setCspNonceProvider: setCspNonceProvider2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
42584
|
+
const { Frond: Frond2, setCspNonceProvider: setCspNonceProvider2, setFormTokenSessionProvider: setFormTokenSessionProvider2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
42043
42585
|
setCspNonceProvider2(currentCspNonce);
|
|
42586
|
+
setFormTokenSessionProvider2(currentFormTokenSessionId);
|
|
42044
42587
|
frondEngine = new Frond2(templatesDir);
|
|
42045
42588
|
} catch {
|
|
42046
42589
|
}
|
|
@@ -42155,7 +42698,10 @@ async function runDispatch(ctx, rawReq, rawRes) {
|
|
|
42155
42698
|
const requestNonce = generateNonce();
|
|
42156
42699
|
return Log.runWithRequestId(
|
|
42157
42700
|
requestId,
|
|
42158
|
-
() => runWithCspNonce(
|
|
42701
|
+
() => runWithCspNonce(
|
|
42702
|
+
requestNonce,
|
|
42703
|
+
() => runWithFormTokenSession(() => dispatchInner(ctx, rawReq, rawRes, requestId))
|
|
42704
|
+
)
|
|
42159
42705
|
);
|
|
42160
42706
|
}
|
|
42161
42707
|
function loopbackBindHosts(host) {
|
|
@@ -42283,8 +42829,9 @@ async function startServer(config) {
|
|
|
42283
42829
|
let frondEngine = null;
|
|
42284
42830
|
setDefaultTemplatesDir(templatesDir);
|
|
42285
42831
|
try {
|
|
42286
|
-
const { Frond: Frond2, setCspNonceProvider: setCspNonceProvider2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
42832
|
+
const { Frond: Frond2, setCspNonceProvider: setCspNonceProvider2, setFormTokenSessionProvider: setFormTokenSessionProvider2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
42287
42833
|
setCspNonceProvider2(currentCspNonce);
|
|
42834
|
+
setFormTokenSessionProvider2(currentFormTokenSessionId);
|
|
42288
42835
|
frondEngine = new Frond2(templatesDir);
|
|
42289
42836
|
router.addRoute({
|
|
42290
42837
|
method: "GET",
|
|
@@ -42633,6 +43180,7 @@ var __filename, __dirname, BUILTIN_ERROR_TEMPLATES_DIR, BUILTIN_PUBLIC_DIR, swag
|
|
|
42633
43180
|
var init_server = __esm({
|
|
42634
43181
|
"../core/src/server.ts"() {
|
|
42635
43182
|
"use strict";
|
|
43183
|
+
init_slashTrim();
|
|
42636
43184
|
init_transport();
|
|
42637
43185
|
init_router();
|
|
42638
43186
|
init_authGate();
|
|
@@ -42640,6 +43188,7 @@ var init_server = __esm({
|
|
|
42640
43188
|
init_portTakeover();
|
|
42641
43189
|
init_request();
|
|
42642
43190
|
init_dispatchPipeline();
|
|
43191
|
+
init_session();
|
|
42643
43192
|
init_response();
|
|
42644
43193
|
init_middleware();
|
|
42645
43194
|
init_static();
|
|
@@ -44255,6 +44804,7 @@ var ApiStreamError, RETRY_STATUSES, DOWNLOAD_CHUNK_SIZE, MAX_REDIRECTS, STRIP_ON
|
|
|
44255
44804
|
var init_api = __esm({
|
|
44256
44805
|
"../core/src/api.ts"() {
|
|
44257
44806
|
"use strict";
|
|
44807
|
+
init_slashTrim();
|
|
44258
44808
|
init_version();
|
|
44259
44809
|
init_ssrf();
|
|
44260
44810
|
ApiStreamError = class extends Error {
|
|
@@ -44352,7 +44902,7 @@ var init_api = __esm({
|
|
|
44352
44902
|
* turns on a per-client, in-memory cookie jar.
|
|
44353
44903
|
*/
|
|
44354
44904
|
constructor(baseUrl = "", authHeaderOrOptions = "", timeout = 30) {
|
|
44355
|
-
this.baseUrl = baseUrl
|
|
44905
|
+
this.baseUrl = rtrimSlashes(baseUrl);
|
|
44356
44906
|
this.headers = {};
|
|
44357
44907
|
this.maxRetries = 0;
|
|
44358
44908
|
this.retryBackoff = 0.5;
|
|
@@ -45118,6 +45668,23 @@ function sendCommand(socket, command) {
|
|
|
45118
45668
|
});
|
|
45119
45669
|
});
|
|
45120
45670
|
}
|
|
45671
|
+
function pushAlternativeBody(lines, altBoundary, text, body) {
|
|
45672
|
+
lines.push(`Content-Type: multipart/alternative; boundary="${altBoundary}"`);
|
|
45673
|
+
lines.push("");
|
|
45674
|
+
lines.push(`--${altBoundary}`);
|
|
45675
|
+
lines.push("Content-Type: text/plain; charset=UTF-8");
|
|
45676
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45677
|
+
lines.push("");
|
|
45678
|
+
lines.push(text);
|
|
45679
|
+
lines.push("");
|
|
45680
|
+
lines.push(`--${altBoundary}`);
|
|
45681
|
+
lines.push("Content-Type: text/html; charset=UTF-8");
|
|
45682
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45683
|
+
lines.push("");
|
|
45684
|
+
lines.push(body);
|
|
45685
|
+
lines.push("");
|
|
45686
|
+
lines.push(`--${altBoundary}--`);
|
|
45687
|
+
}
|
|
45121
45688
|
function buildMimeMessage(options) {
|
|
45122
45689
|
const boundary = `----=_Tina4_${Date.now()}_${Math.random().toString(36).substring(2)}`;
|
|
45123
45690
|
const altBoundary = `----=_Tina4Alt_${Date.now()}_${Math.random().toString(36).substring(2)}`;
|
|
@@ -45147,21 +45714,7 @@ function buildMimeMessage(options) {
|
|
|
45147
45714
|
lines.push("");
|
|
45148
45715
|
lines.push(`--${boundary}`);
|
|
45149
45716
|
if (hasTextAlt) {
|
|
45150
|
-
lines.
|
|
45151
|
-
lines.push("");
|
|
45152
|
-
lines.push(`--${altBoundary}`);
|
|
45153
|
-
lines.push("Content-Type: text/plain; charset=UTF-8");
|
|
45154
|
-
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45155
|
-
lines.push("");
|
|
45156
|
-
lines.push(options.text);
|
|
45157
|
-
lines.push("");
|
|
45158
|
-
lines.push(`--${altBoundary}`);
|
|
45159
|
-
lines.push("Content-Type: text/html; charset=UTF-8");
|
|
45160
|
-
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45161
|
-
lines.push("");
|
|
45162
|
-
lines.push(options.body);
|
|
45163
|
-
lines.push("");
|
|
45164
|
-
lines.push(`--${altBoundary}--`);
|
|
45717
|
+
pushAlternativeBody(lines, altBoundary, options.text, options.body);
|
|
45165
45718
|
} else {
|
|
45166
45719
|
const contentType = options.html ? "text/html" : "text/plain";
|
|
45167
45720
|
lines.push(`Content-Type: ${contentType}; charset=UTF-8`);
|
|
@@ -45186,21 +45739,7 @@ function buildMimeMessage(options) {
|
|
|
45186
45739
|
lines.push("");
|
|
45187
45740
|
lines.push(`--${boundary}--`);
|
|
45188
45741
|
} else if (hasTextAlt) {
|
|
45189
|
-
lines.
|
|
45190
|
-
lines.push("");
|
|
45191
|
-
lines.push(`--${altBoundary}`);
|
|
45192
|
-
lines.push("Content-Type: text/plain; charset=UTF-8");
|
|
45193
|
-
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45194
|
-
lines.push("");
|
|
45195
|
-
lines.push(options.text);
|
|
45196
|
-
lines.push("");
|
|
45197
|
-
lines.push(`--${altBoundary}`);
|
|
45198
|
-
lines.push("Content-Type: text/html; charset=UTF-8");
|
|
45199
|
-
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45200
|
-
lines.push("");
|
|
45201
|
-
lines.push(options.body);
|
|
45202
|
-
lines.push("");
|
|
45203
|
-
lines.push(`--${altBoundary}--`);
|
|
45742
|
+
pushAlternativeBody(lines, altBoundary, options.text, options.body);
|
|
45204
45743
|
} else {
|
|
45205
45744
|
const contentType = options.html ? "text/html" : "text/plain";
|
|
45206
45745
|
lines.push(`Content-Type: ${contentType}; charset=UTF-8`);
|
|
@@ -45965,61 +46504,72 @@ function decodeEntities(raw) {
|
|
|
45965
46504
|
function parseXmlDocument(xml) {
|
|
45966
46505
|
const stack = [];
|
|
45967
46506
|
let root = null;
|
|
45968
|
-
let position = 0;
|
|
45969
46507
|
const addText = (text) => {
|
|
45970
46508
|
const current = stack[stack.length - 1];
|
|
45971
46509
|
if (current.children.length === 0) current.text += text;
|
|
45972
46510
|
};
|
|
45973
|
-
|
|
45974
|
-
const
|
|
46511
|
+
const skipComment = (at) => {
|
|
46512
|
+
const close = xml.indexOf("-->", at + 4);
|
|
46513
|
+
if (close === -1) malformed();
|
|
46514
|
+
return close + 3;
|
|
46515
|
+
};
|
|
46516
|
+
const readCData = (at) => {
|
|
46517
|
+
const close = xml.indexOf("]]>", at + 9);
|
|
46518
|
+
if (close === -1 || stack.length === 0) malformed();
|
|
46519
|
+
addText(xml.slice(at + 9, close));
|
|
46520
|
+
return close + 3;
|
|
46521
|
+
};
|
|
46522
|
+
const skipProcessingInstruction = (at) => {
|
|
46523
|
+
const close = xml.indexOf("?>", at + 2);
|
|
46524
|
+
if (close === -1) malformed();
|
|
46525
|
+
const target = xml.slice(at + 2, close).split(/\s/, 1)[0];
|
|
46526
|
+
if (target.toLowerCase() === "xml" && at !== 0) malformed();
|
|
46527
|
+
return close + 2;
|
|
46528
|
+
};
|
|
46529
|
+
const closeElement = (at) => {
|
|
46530
|
+
END_TAG.lastIndex = at;
|
|
46531
|
+
const match = END_TAG.exec(xml);
|
|
46532
|
+
const open = stack.pop();
|
|
46533
|
+
if (!match || !open || open.qualifiedName !== match[1]) malformed();
|
|
46534
|
+
return END_TAG.lastIndex;
|
|
46535
|
+
};
|
|
46536
|
+
const openElement = (at) => {
|
|
46537
|
+
START_TAG.lastIndex = at;
|
|
46538
|
+
const match = START_TAG.exec(xml);
|
|
46539
|
+
if (!match || stack.length === 0 && root !== null) malformed();
|
|
46540
|
+
for (const attribute of match[2].matchAll(ATTRIBUTE_VALUE)) decodeEntities(attribute[1] ?? attribute[2]);
|
|
46541
|
+
const qualifiedName = match[1];
|
|
46542
|
+
const element = {
|
|
46543
|
+
name: qualifiedName.slice(qualifiedName.indexOf(":") + 1),
|
|
46544
|
+
qualifiedName,
|
|
46545
|
+
children: [],
|
|
46546
|
+
text: ""
|
|
46547
|
+
};
|
|
46548
|
+
if (stack.length > 0) stack[stack.length - 1].children.push(element);
|
|
46549
|
+
else root = element;
|
|
46550
|
+
if (match[3] !== "/") stack.push(element);
|
|
46551
|
+
return START_TAG.lastIndex;
|
|
46552
|
+
};
|
|
46553
|
+
const readText = (at) => {
|
|
46554
|
+
const nextTag = xml.indexOf("<", at);
|
|
45975
46555
|
const textEnd = nextTag === -1 ? xml.length : nextTag;
|
|
45976
|
-
if (textEnd >
|
|
45977
|
-
const raw = xml.slice(
|
|
46556
|
+
if (textEnd > at) {
|
|
46557
|
+
const raw = xml.slice(at, textEnd);
|
|
45978
46558
|
if (stack.length > 0) addText(decodeEntities(raw));
|
|
45979
46559
|
else if (raw.trim() !== "") malformed();
|
|
45980
|
-
position = textEnd;
|
|
45981
|
-
if (nextTag === -1) break;
|
|
45982
|
-
}
|
|
45983
|
-
if (xml.startsWith("<!--", position)) {
|
|
45984
|
-
const close = xml.indexOf("-->", position + 4);
|
|
45985
|
-
if (close === -1) malformed();
|
|
45986
|
-
position = close + 3;
|
|
45987
|
-
} else if (xml.startsWith("<![CDATA[", position)) {
|
|
45988
|
-
const close = xml.indexOf("]]>", position + 9);
|
|
45989
|
-
if (close === -1 || stack.length === 0) malformed();
|
|
45990
|
-
addText(xml.slice(position + 9, close));
|
|
45991
|
-
position = close + 3;
|
|
45992
|
-
} else if (xml.startsWith("<?", position)) {
|
|
45993
|
-
const close = xml.indexOf("?>", position + 2);
|
|
45994
|
-
if (close === -1) malformed();
|
|
45995
|
-
const target = xml.slice(position + 2, close).split(/\s/, 1)[0];
|
|
45996
|
-
if (target.toLowerCase() === "xml" && position !== 0) malformed();
|
|
45997
|
-
position = close + 2;
|
|
45998
|
-
} else if (xml.startsWith("<!", position)) {
|
|
45999
|
-
malformed();
|
|
46000
|
-
} else if (xml.startsWith("</", position)) {
|
|
46001
|
-
END_TAG.lastIndex = position;
|
|
46002
|
-
const match = END_TAG.exec(xml);
|
|
46003
|
-
const open = stack.pop();
|
|
46004
|
-
if (!match || !open || open.qualifiedName !== match[1]) malformed();
|
|
46005
|
-
position = END_TAG.lastIndex;
|
|
46006
|
-
} else {
|
|
46007
|
-
START_TAG.lastIndex = position;
|
|
46008
|
-
const match = START_TAG.exec(xml);
|
|
46009
|
-
if (!match || stack.length === 0 && root !== null) malformed();
|
|
46010
|
-
for (const attribute of match[2].matchAll(ATTRIBUTE_VALUE)) decodeEntities(attribute[1] ?? attribute[2]);
|
|
46011
|
-
const qualifiedName = match[1];
|
|
46012
|
-
const element = {
|
|
46013
|
-
name: qualifiedName.slice(qualifiedName.indexOf(":") + 1),
|
|
46014
|
-
qualifiedName,
|
|
46015
|
-
children: [],
|
|
46016
|
-
text: ""
|
|
46017
|
-
};
|
|
46018
|
-
if (stack.length > 0) stack[stack.length - 1].children.push(element);
|
|
46019
|
-
else root = element;
|
|
46020
|
-
if (match[3] !== "/") stack.push(element);
|
|
46021
|
-
position = START_TAG.lastIndex;
|
|
46022
46560
|
}
|
|
46561
|
+
return textEnd;
|
|
46562
|
+
};
|
|
46563
|
+
let position = 0;
|
|
46564
|
+
while (position < xml.length) {
|
|
46565
|
+
position = readText(position);
|
|
46566
|
+
if (position >= xml.length) break;
|
|
46567
|
+
if (xml.startsWith("<!--", position)) position = skipComment(position);
|
|
46568
|
+
else if (xml.startsWith("<![CDATA[", position)) position = readCData(position);
|
|
46569
|
+
else if (xml.startsWith("<?", position)) position = skipProcessingInstruction(position);
|
|
46570
|
+
else if (xml.startsWith("<!", position)) malformed();
|
|
46571
|
+
else if (xml.startsWith("</", position)) position = closeElement(position);
|
|
46572
|
+
else position = openElement(position);
|
|
46023
46573
|
}
|
|
46024
46574
|
if (root === null || stack.length > 0) malformed();
|
|
46025
46575
|
return root;
|
|
@@ -47521,13 +48071,13 @@ export default class User {
|
|
|
47521
48071
|
import {
|
|
47522
48072
|
createCipheriv,
|
|
47523
48073
|
createECDH,
|
|
47524
|
-
createHmac as
|
|
48074
|
+
createHmac as createHmac5,
|
|
47525
48075
|
createPrivateKey,
|
|
47526
48076
|
createSign as createSign2,
|
|
47527
48077
|
randomBytes as randomBytes12
|
|
47528
48078
|
} from "node:crypto";
|
|
47529
48079
|
function encodeBase64Url(value) {
|
|
47530
|
-
return Buffer.from(value).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(
|
|
48080
|
+
return Buffer.from(value).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/={1,2}$/, "");
|
|
47531
48081
|
}
|
|
47532
48082
|
function decodeBase64Url(value, name) {
|
|
47533
48083
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -47557,15 +48107,15 @@ function vapidPrivateKey(rawPrivate, rawPublic) {
|
|
|
47557
48107
|
format: "jwk"
|
|
47558
48108
|
});
|
|
47559
48109
|
}
|
|
47560
|
-
function
|
|
47561
|
-
return
|
|
48110
|
+
function hmac2(salt, value) {
|
|
48111
|
+
return createHmac5("sha256", salt).update(value).digest();
|
|
47562
48112
|
}
|
|
47563
48113
|
function hkdfExpand(prk, info, length) {
|
|
47564
48114
|
const chunks = [];
|
|
47565
48115
|
let previous = Buffer.alloc(0);
|
|
47566
48116
|
for (let counter = 1; Buffer.concat(chunks).length < length; counter++) {
|
|
47567
48117
|
if (counter > 255) throw new PushError("HKDF output is too large");
|
|
47568
|
-
previous =
|
|
48118
|
+
previous = hmac2(prk, Buffer.concat([previous, info, Buffer.from([counter])]));
|
|
47569
48119
|
chunks.push(previous);
|
|
47570
48120
|
}
|
|
47571
48121
|
return Buffer.concat(chunks).subarray(0, length);
|
|
@@ -47602,10 +48152,10 @@ function encryptPayload(payload, subscription) {
|
|
|
47602
48152
|
clientPublic,
|
|
47603
48153
|
serverPublic
|
|
47604
48154
|
]);
|
|
47605
|
-
const prkKey =
|
|
48155
|
+
const prkKey = hmac2(authSecret, sharedSecret);
|
|
47606
48156
|
const ikm = hkdfExpand(prkKey, keyInfo, 32);
|
|
47607
48157
|
const salt = randomBytes12(16);
|
|
47608
|
-
const contentPrk =
|
|
48158
|
+
const contentPrk = hmac2(salt, ikm);
|
|
47609
48159
|
const cek = hkdfExpand(contentPrk, Buffer.from("Content-Encoding: aes128gcm\0", "ascii"), 16);
|
|
47610
48160
|
const nonce = hkdfExpand(contentPrk, Buffer.from("Content-Encoding: nonce\0", "ascii"), 12);
|
|
47611
48161
|
const cipher = createCipheriv("aes-128-gcm", cek, nonce);
|
|
@@ -47778,6 +48328,7 @@ var AiError, AiConfigError, AiTimeoutError, AiParseError, AiHTTPError, Ai, Aggre
|
|
|
47778
48328
|
var init_aiClient = __esm({
|
|
47779
48329
|
"../core/src/aiClient.ts"() {
|
|
47780
48330
|
"use strict";
|
|
48331
|
+
init_slashTrim();
|
|
47781
48332
|
init_api();
|
|
47782
48333
|
AiError = class extends Error {
|
|
47783
48334
|
};
|
|
@@ -47982,7 +48533,7 @@ var init_aiClient = __esm({
|
|
|
47982
48533
|
throw new AiConfigError("AI URL must be an http or https URL");
|
|
47983
48534
|
}
|
|
47984
48535
|
if (url.protocol !== "http:" && url.protocol !== "https:") throw new AiConfigError("AI URL must be an http or https URL");
|
|
47985
|
-
const path10 = url.pathname
|
|
48536
|
+
const path10 = rtrimSlashes(url.pathname);
|
|
47986
48537
|
if (path10 === "" || path10 === "/v1" || path10 === "/api" || path10 === "/v1beta/openai") {
|
|
47987
48538
|
const suffix = provider === "anthropic" ? "/messages" : capability === "embed" ? "/embeddings" : "/chat/completions";
|
|
47988
48539
|
url.pathname = (path10 || "/v1") + suffix;
|
|
@@ -50352,6 +50903,7 @@ __export(src_exports3, {
|
|
|
50352
50903
|
backgroundTaskCount: () => backgroundTaskCount,
|
|
50353
50904
|
buildEnvelope: () => buildEnvelope,
|
|
50354
50905
|
buildFrame: () => buildFrame,
|
|
50906
|
+
buildSeedFieldMap: () => buildSeedFieldMap,
|
|
50355
50907
|
buildSessionCookie: () => buildSessionCookie,
|
|
50356
50908
|
cacheBackendStats: () => cacheBackendStats,
|
|
50357
50909
|
cacheClear: () => cacheClear,
|
|
@@ -50457,6 +51009,7 @@ __export(src_exports3, {
|
|
|
50457
51009
|
parseFrame: () => parseFrame,
|
|
50458
51010
|
parseLineStream: () => parseLineStream,
|
|
50459
51011
|
parseMultipart: () => parseMultipart,
|
|
51012
|
+
parseSeedRequest: () => parseSeedRequest,
|
|
50460
51013
|
parseSseStream: () => parseSseStream,
|
|
50461
51014
|
parseUpgradeHeaders: () => parseUpgradeHeaders,
|
|
50462
51015
|
patch: () => patch,
|
|
@@ -51164,7 +51717,7 @@ async function runTests(testPath) {
|
|
|
51164
51717
|
// src/commands/lint.ts
|
|
51165
51718
|
init_util();
|
|
51166
51719
|
import { existsSync as existsSync34, readdirSync as readdirSync21, readFileSync as readFileSync28, statSync as statSync22, writeFileSync as writeFileSync20 } from "node:fs";
|
|
51167
|
-
import { createRequire as
|
|
51720
|
+
import { createRequire as createRequire8 } from "node:module";
|
|
51168
51721
|
import { dirname as dirname18, join as join36, relative as relative12 } from "node:path";
|
|
51169
51722
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
51170
51723
|
var LINT_EXTENSIONS = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
|
|
@@ -51236,10 +51789,10 @@ function findEslintConfig(cwd) {
|
|
|
51236
51789
|
function resolvePackageBin(cwd, pkg, binRelative) {
|
|
51237
51790
|
const direct = join36(cwd, "node_modules", pkg, binRelative);
|
|
51238
51791
|
if (existsSync34(direct)) return direct;
|
|
51239
|
-
const
|
|
51792
|
+
const require2 = createRequire8(join36(cwd, "package.json"));
|
|
51240
51793
|
let entry;
|
|
51241
51794
|
try {
|
|
51242
|
-
entry =
|
|
51795
|
+
entry = require2.resolve(pkg);
|
|
51243
51796
|
} catch {
|
|
51244
51797
|
return null;
|
|
51245
51798
|
}
|
|
@@ -51595,7 +52148,7 @@ async function queueCommand(args = []) {
|
|
|
51595
52148
|
|
|
51596
52149
|
// src/commands/build.ts
|
|
51597
52150
|
init_util();
|
|
51598
|
-
import { accessSync as accessSync2, constants as
|
|
52151
|
+
import { accessSync as accessSync2, constants as constants5, existsSync as existsSync36, statSync as statSync24 } from "node:fs";
|
|
51599
52152
|
import { basename as basename9, delimiter as delimiter3, join as join39 } from "node:path";
|
|
51600
52153
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
51601
52154
|
function parseFlags3(args) {
|
|
@@ -51610,7 +52163,7 @@ function whichDocker() {
|
|
|
51610
52163
|
for (const ext of exts) {
|
|
51611
52164
|
const candidate = join39(dir, `docker${ext}`);
|
|
51612
52165
|
try {
|
|
51613
|
-
accessSync2(candidate,
|
|
52166
|
+
accessSync2(candidate, constants5.X_OK);
|
|
51614
52167
|
if (statSync24(candidate).isFile()) return candidate;
|
|
51615
52168
|
} catch {
|
|
51616
52169
|
}
|