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
|
@@ -13,6 +13,30 @@ var __export = (target, all) => {
|
|
|
13
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
// src/slashTrim.ts
|
|
17
|
+
function rtrimSlashes(s) {
|
|
18
|
+
let end = s.length;
|
|
19
|
+
while (end > 0 && s.charCodeAt(end - 1) === SLASH) end--;
|
|
20
|
+
return end === s.length ? s : s.slice(0, end);
|
|
21
|
+
}
|
|
22
|
+
function trimChar(s, code) {
|
|
23
|
+
let start2 = 0;
|
|
24
|
+
let end = s.length;
|
|
25
|
+
while (start2 < end && s.charCodeAt(start2) === code) start2++;
|
|
26
|
+
while (end > start2 && s.charCodeAt(end - 1) === code) end--;
|
|
27
|
+
return start2 === 0 && end === s.length ? s : s.slice(start2, end);
|
|
28
|
+
}
|
|
29
|
+
function trimSlashes(s) {
|
|
30
|
+
return trimChar(s, SLASH);
|
|
31
|
+
}
|
|
32
|
+
var SLASH;
|
|
33
|
+
var init_slashTrim = __esm({
|
|
34
|
+
"src/slashTrim.ts"() {
|
|
35
|
+
"use strict";
|
|
36
|
+
SLASH = 47;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
16
40
|
// src/constants.ts
|
|
17
41
|
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;
|
|
18
42
|
var init_constants = __esm({
|
|
@@ -1101,7 +1125,7 @@ function resolveAlgorithm(algorithm) {
|
|
|
1101
1125
|
return chosen;
|
|
1102
1126
|
}
|
|
1103
1127
|
function base64urlEncode(data) {
|
|
1104
|
-
return data.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(
|
|
1128
|
+
return data.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/={1,2}$/, "");
|
|
1105
1129
|
}
|
|
1106
1130
|
function base64urlDecode(str) {
|
|
1107
1131
|
let s = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -1380,6 +1404,12 @@ var init_types = __esm({
|
|
|
1380
1404
|
});
|
|
1381
1405
|
|
|
1382
1406
|
// ../orm/src/databaseResult.ts
|
|
1407
|
+
function stripTypeArgs(colType) {
|
|
1408
|
+
const open = colType.indexOf("(");
|
|
1409
|
+
if (open < 0) return colType;
|
|
1410
|
+
const close = colType.indexOf(")", open);
|
|
1411
|
+
return close < 0 ? colType : colType.slice(0, open) + colType.slice(close + 1);
|
|
1412
|
+
}
|
|
1383
1413
|
var DatabaseResult;
|
|
1384
1414
|
var init_databaseResult = __esm({
|
|
1385
1415
|
"../orm/src/databaseResult.ts"() {
|
|
@@ -1562,7 +1592,7 @@ var init_databaseResult = __esm({
|
|
|
1562
1592
|
const [size, decimals] = this._parseTypeSize(colType);
|
|
1563
1593
|
return {
|
|
1564
1594
|
name: col.name,
|
|
1565
|
-
type: colType
|
|
1595
|
+
type: stripTypeArgs(colType),
|
|
1566
1596
|
size,
|
|
1567
1597
|
decimals,
|
|
1568
1598
|
nullable: col.nullable ?? true,
|
|
@@ -2119,12 +2149,49 @@ var init_point = __esm({
|
|
|
2119
2149
|
});
|
|
2120
2150
|
|
|
2121
2151
|
// ../orm/src/sqlTranslator.ts
|
|
2122
|
-
|
|
2152
|
+
function skipQuoted(sql, i, backslashEscapes) {
|
|
2153
|
+
const c = sql[i];
|
|
2154
|
+
const escapeString = c === "'" && (sql[i - 1] === "E" || sql[i - 1] === "e") && !isIdentChar(sql[i - 2]);
|
|
2155
|
+
const backslash = c !== "`" && (escapeString || backslashEscapes);
|
|
2156
|
+
const n = sql.length;
|
|
2157
|
+
i++;
|
|
2158
|
+
while (i < n) {
|
|
2159
|
+
if (backslash && sql[i] === "\\") {
|
|
2160
|
+
i += 2;
|
|
2161
|
+
continue;
|
|
2162
|
+
}
|
|
2163
|
+
if (sql[i] === c) {
|
|
2164
|
+
if (sql[i + 1] === c) {
|
|
2165
|
+
i += 2;
|
|
2166
|
+
continue;
|
|
2167
|
+
}
|
|
2168
|
+
return i + 1;
|
|
2169
|
+
}
|
|
2170
|
+
i++;
|
|
2171
|
+
}
|
|
2172
|
+
return i;
|
|
2173
|
+
}
|
|
2174
|
+
function skipLineComment(sql, i) {
|
|
2175
|
+
while (i < sql.length && sql[i] !== "\n") i++;
|
|
2176
|
+
return i;
|
|
2177
|
+
}
|
|
2178
|
+
function skipBlockComment(sql, i) {
|
|
2179
|
+
const end = sql.indexOf("*/", i + 2);
|
|
2180
|
+
return end === -1 ? sql.length : end + 2;
|
|
2181
|
+
}
|
|
2182
|
+
function skipDollarQuote(sql, i) {
|
|
2183
|
+
const tag = sql.slice(i).match(/^\$([A-Za-z_][A-Za-z0-9_]*)?\$/);
|
|
2184
|
+
if (!tag) return i;
|
|
2185
|
+
const end = sql.indexOf(tag[0], i + tag[0].length);
|
|
2186
|
+
return end === -1 ? sql.length : end + tag[0].length;
|
|
2187
|
+
}
|
|
2188
|
+
var isIdentChar, SQLTranslator, QueryCache;
|
|
2123
2189
|
var init_sqlTranslator = __esm({
|
|
2124
2190
|
"../orm/src/sqlTranslator.ts"() {
|
|
2125
2191
|
"use strict";
|
|
2126
2192
|
init_databaseUrl();
|
|
2127
2193
|
init_point();
|
|
2194
|
+
isIdentChar = (ch) => !!ch && /[A-Za-z0-9_]/.test(ch);
|
|
2128
2195
|
SQLTranslator = class _SQLTranslator {
|
|
2129
2196
|
static SPATIAL_ENGINES = /* @__PURE__ */ new Set(["postgres", "postgresql"]);
|
|
2130
2197
|
static SPATIAL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
@@ -2405,47 +2472,26 @@ var init_sqlTranslator = __esm({
|
|
|
2405
2472
|
static placeholderPositions(sql, options = {}) {
|
|
2406
2473
|
const positions = [];
|
|
2407
2474
|
const n = sql.length;
|
|
2408
|
-
const isIdent = (ch) => !!ch && /[A-Za-z0-9_]/.test(ch);
|
|
2409
2475
|
let i = 0;
|
|
2410
2476
|
while (i < n) {
|
|
2411
2477
|
const c = sql[i];
|
|
2412
2478
|
const next = sql[i + 1];
|
|
2413
2479
|
if (c === "'" || c === '"' || c === "`") {
|
|
2414
|
-
|
|
2415
|
-
const escapeString = c === "'" && (prev === "E" || prev === "e") && !isIdent(sql[i - 2]);
|
|
2416
|
-
const backslash = c !== "`" && (escapeString || options.backslashEscapes === true);
|
|
2417
|
-
i++;
|
|
2418
|
-
while (i < n) {
|
|
2419
|
-
if (backslash && sql[i] === "\\") {
|
|
2420
|
-
i += 2;
|
|
2421
|
-
continue;
|
|
2422
|
-
}
|
|
2423
|
-
if (sql[i] === c) {
|
|
2424
|
-
if (sql[i + 1] === c) {
|
|
2425
|
-
i += 2;
|
|
2426
|
-
continue;
|
|
2427
|
-
}
|
|
2428
|
-
i++;
|
|
2429
|
-
break;
|
|
2430
|
-
}
|
|
2431
|
-
i++;
|
|
2432
|
-
}
|
|
2480
|
+
i = skipQuoted(sql, i, options.backslashEscapes === true);
|
|
2433
2481
|
continue;
|
|
2434
2482
|
}
|
|
2435
2483
|
if (c === "-" && next === "-") {
|
|
2436
|
-
|
|
2484
|
+
i = skipLineComment(sql, i);
|
|
2437
2485
|
continue;
|
|
2438
2486
|
}
|
|
2439
2487
|
if (c === "/" && next === "*") {
|
|
2440
|
-
|
|
2441
|
-
i = end === -1 ? n : end + 2;
|
|
2488
|
+
i = skipBlockComment(sql, i);
|
|
2442
2489
|
continue;
|
|
2443
2490
|
}
|
|
2444
|
-
if (c === "$" && !
|
|
2445
|
-
const
|
|
2446
|
-
if (
|
|
2447
|
-
|
|
2448
|
-
i = end === -1 ? n : end + tag[0].length;
|
|
2491
|
+
if (c === "$" && !isIdentChar(sql[i - 1])) {
|
|
2492
|
+
const past = skipDollarQuote(sql, i);
|
|
2493
|
+
if (past !== i) {
|
|
2494
|
+
i = past;
|
|
2449
2495
|
continue;
|
|
2450
2496
|
}
|
|
2451
2497
|
}
|
|
@@ -2478,7 +2524,7 @@ var init_sqlTranslator = __esm({
|
|
|
2478
2524
|
* → { sql: "INSERT INTO t (x) VALUES (1)", columns: ["id", "name"] }
|
|
2479
2525
|
*/
|
|
2480
2526
|
static parseReturning(sql) {
|
|
2481
|
-
const m = sql.match(/\bRETURNING\s+(
|
|
2527
|
+
const m = sql.match(/\bRETURNING\s+(\S.*)$/i);
|
|
2482
2528
|
if (!m) return { sql, columns: [] };
|
|
2483
2529
|
const columns = m[1].split(",").map((c) => c.trim());
|
|
2484
2530
|
return {
|
|
@@ -2532,7 +2578,12 @@ var init_sqlTranslator = __esm({
|
|
|
2532
2578
|
// The `d` flag records group indices, so the head can be sliced at the exact
|
|
2533
2579
|
// start of the VALUES group rather than by hunting for a parenthesis (the
|
|
2534
2580
|
// column list has parentheses too).
|
|
2535
|
-
static INSERT_VALUES =
|
|
2581
|
+
static INSERT_VALUES = (
|
|
2582
|
+
// ReDoS-safe: the table ref matches `\S(?:[\s\S]*?\S)?` (bounded by non-space
|
|
2583
|
+
// at both ends) so the separator `\s+` before VALUES can't overlap it the way
|
|
2584
|
+
// the old `.+?\s+` did (polynomial on `INSERT INTO ` + a long space run).
|
|
2585
|
+
/^\s*INSERT\s+INTO\s+\S(?:[\s\S]*?\S)?\s+VALUES\s*\(([^()]*)\)\s*$/dis
|
|
2586
|
+
);
|
|
2536
2587
|
/**
|
|
2537
2588
|
* Engines whose lastInsertId reports the FIRST generated id of a multi-row
|
|
2538
2589
|
* INSERT rather than the last. Verified live, not assumed: a 3-row insert
|
|
@@ -7272,7 +7323,7 @@ __export(database_exports, {
|
|
|
7272
7323
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
7273
7324
|
function stripTrailingSemicolons(sql) {
|
|
7274
7325
|
if (!sql) return sql;
|
|
7275
|
-
let stripped = sql.
|
|
7326
|
+
let stripped = sql.trimEnd();
|
|
7276
7327
|
while (stripped.endsWith(";")) {
|
|
7277
7328
|
stripped = stripped.slice(0, -1).replace(/\s+$/, "");
|
|
7278
7329
|
}
|
|
@@ -7439,6 +7490,13 @@ async function createAdapterFromUrl(url, username, password) {
|
|
|
7439
7490
|
}
|
|
7440
7491
|
async function buildAdapterFromUrl(url, username, password) {
|
|
7441
7492
|
const parsed = parseDatabaseUrl(url, username, password);
|
|
7493
|
+
const serverConfig = {
|
|
7494
|
+
host: parsed.host ?? void 0,
|
|
7495
|
+
port: parsed.port ?? void 0,
|
|
7496
|
+
user: parsed.username ?? void 0,
|
|
7497
|
+
password: parsed.password ?? void 0,
|
|
7498
|
+
database: parsed.database || void 0
|
|
7499
|
+
};
|
|
7442
7500
|
switch (parsed.engine) {
|
|
7443
7501
|
case "sqlite": {
|
|
7444
7502
|
const { SQLiteAdapter: SQLiteAdapter2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
@@ -7446,49 +7504,25 @@ async function buildAdapterFromUrl(url, username, password) {
|
|
|
7446
7504
|
}
|
|
7447
7505
|
case "postgres": {
|
|
7448
7506
|
const { PostgresAdapter: PostgresAdapter2 } = await Promise.resolve().then(() => (init_postgres(), postgres_exports));
|
|
7449
|
-
const adapter = new PostgresAdapter2(
|
|
7450
|
-
host: parsed.host ?? void 0,
|
|
7451
|
-
port: parsed.port ?? void 0,
|
|
7452
|
-
user: parsed.username ?? void 0,
|
|
7453
|
-
password: parsed.password ?? void 0,
|
|
7454
|
-
database: parsed.database || void 0
|
|
7455
|
-
});
|
|
7507
|
+
const adapter = new PostgresAdapter2(serverConfig);
|
|
7456
7508
|
await adapter.connect();
|
|
7457
7509
|
return adapter;
|
|
7458
7510
|
}
|
|
7459
7511
|
case "mysql": {
|
|
7460
7512
|
const { MysqlAdapter: MysqlAdapter2 } = await Promise.resolve().then(() => (init_mysql(), mysql_exports));
|
|
7461
|
-
const adapter = new MysqlAdapter2(
|
|
7462
|
-
host: parsed.host ?? void 0,
|
|
7463
|
-
port: parsed.port ?? void 0,
|
|
7464
|
-
user: parsed.username ?? void 0,
|
|
7465
|
-
password: parsed.password ?? void 0,
|
|
7466
|
-
database: parsed.database || void 0
|
|
7467
|
-
});
|
|
7513
|
+
const adapter = new MysqlAdapter2(serverConfig);
|
|
7468
7514
|
await adapter.connect();
|
|
7469
7515
|
return adapter;
|
|
7470
7516
|
}
|
|
7471
7517
|
case "mssql": {
|
|
7472
7518
|
const { MssqlAdapter: MssqlAdapter2 } = await Promise.resolve().then(() => (init_mssql(), mssql_exports));
|
|
7473
|
-
const adapter = new MssqlAdapter2(
|
|
7474
|
-
host: parsed.host ?? void 0,
|
|
7475
|
-
port: parsed.port ?? void 0,
|
|
7476
|
-
user: parsed.username ?? void 0,
|
|
7477
|
-
password: parsed.password ?? void 0,
|
|
7478
|
-
database: parsed.database || void 0
|
|
7479
|
-
});
|
|
7519
|
+
const adapter = new MssqlAdapter2(serverConfig);
|
|
7480
7520
|
await adapter.connect();
|
|
7481
7521
|
return adapter;
|
|
7482
7522
|
}
|
|
7483
7523
|
case "firebird": {
|
|
7484
7524
|
const { FirebirdAdapter: FirebirdAdapter2 } = await Promise.resolve().then(() => (init_firebird(), firebird_exports));
|
|
7485
|
-
const adapter = new FirebirdAdapter2(
|
|
7486
|
-
host: parsed.host ?? void 0,
|
|
7487
|
-
port: parsed.port ?? void 0,
|
|
7488
|
-
user: parsed.username ?? void 0,
|
|
7489
|
-
password: parsed.password ?? void 0,
|
|
7490
|
-
database: parsed.database || void 0
|
|
7491
|
-
});
|
|
7525
|
+
const adapter = new FirebirdAdapter2(serverConfig);
|
|
7492
7526
|
await adapter.connect();
|
|
7493
7527
|
return adapter;
|
|
7494
7528
|
}
|
|
@@ -10224,9 +10258,11 @@ __export(engine_exports, {
|
|
|
10224
10258
|
escapeHtml: () => escapeHtml,
|
|
10225
10259
|
expressionFormCache: () => expressionFormCache,
|
|
10226
10260
|
filterChainCache: () => filterChainCache,
|
|
10261
|
+
frondRange: () => frondRange,
|
|
10227
10262
|
pathParseCache: () => pathParseCache,
|
|
10228
10263
|
setCspNonceProvider: () => setCspNonceProvider,
|
|
10229
|
-
setFormTokenSessionId: () => setFormTokenSessionId
|
|
10264
|
+
setFormTokenSessionId: () => setFormTokenSessionId,
|
|
10265
|
+
setFormTokenSessionProvider: () => setFormTokenSessionProvider
|
|
10230
10266
|
});
|
|
10231
10267
|
import { createHash as createHash3, createHmac as createHmac2, randomBytes as randomBytes2 } from "node:crypto";
|
|
10232
10268
|
import { readFileSync as readFileSync4, existsSync as existsSync5, statSync as statSync4, realpathSync } from "node:fs";
|
|
@@ -10311,6 +10347,14 @@ function renderDump(value) {
|
|
|
10311
10347
|
const escaped = dumped.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
10312
10348
|
return new SafeString(`<pre>${escaped}</pre>`);
|
|
10313
10349
|
}
|
|
10350
|
+
function stripTags(input) {
|
|
10351
|
+
let s = input, prev;
|
|
10352
|
+
do {
|
|
10353
|
+
prev = s;
|
|
10354
|
+
s = s.replace(STRIP_TAGS_RE, "");
|
|
10355
|
+
} while (s !== prev);
|
|
10356
|
+
return s;
|
|
10357
|
+
}
|
|
10314
10358
|
function liveAttr(value) {
|
|
10315
10359
|
return String(value).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
10316
10360
|
}
|
|
@@ -10328,35 +10372,58 @@ function sweepExpiredCache(cache) {
|
|
|
10328
10372
|
if (expiresAt2 <= now) cache.delete(key);
|
|
10329
10373
|
}
|
|
10330
10374
|
}
|
|
10331
|
-
function
|
|
10375
|
+
function extractRawBlocks(source) {
|
|
10332
10376
|
const rawBlocks = [];
|
|
10333
|
-
|
|
10377
|
+
let out = "";
|
|
10378
|
+
let pos = 0;
|
|
10379
|
+
RAW_OPEN_RE.lastIndex = 0;
|
|
10380
|
+
let om;
|
|
10381
|
+
while ((om = RAW_OPEN_RE.exec(source)) !== null) {
|
|
10382
|
+
const openStart = om.index;
|
|
10383
|
+
const openEnd = RAW_OPEN_RE.lastIndex;
|
|
10384
|
+
RAW_CLOSE_RE.lastIndex = openEnd;
|
|
10385
|
+
const cm = RAW_CLOSE_RE.exec(source);
|
|
10386
|
+
if (cm === null) break;
|
|
10334
10387
|
const idx = rawBlocks.length;
|
|
10335
|
-
rawBlocks.push(
|
|
10336
|
-
|
|
10337
|
-
|
|
10388
|
+
rawBlocks.push(source.slice(openEnd, cm.index));
|
|
10389
|
+
out += source.slice(pos, openStart) + `\0RAW_${idx}\0`;
|
|
10390
|
+
pos = RAW_CLOSE_RE.lastIndex;
|
|
10391
|
+
RAW_OPEN_RE.lastIndex = pos;
|
|
10392
|
+
}
|
|
10393
|
+
out += source.slice(pos);
|
|
10394
|
+
return { source: out, rawBlocks };
|
|
10395
|
+
}
|
|
10396
|
+
function tokenize(rawSource) {
|
|
10397
|
+
const { source, rawBlocks } = extractRawBlocks(rawSource);
|
|
10338
10398
|
const tokens = [];
|
|
10399
|
+
const n = source.length;
|
|
10339
10400
|
let pos = 0;
|
|
10340
|
-
|
|
10341
|
-
|
|
10342
|
-
while (
|
|
10343
|
-
const
|
|
10344
|
-
if (
|
|
10345
|
-
|
|
10401
|
+
let scan = 0;
|
|
10402
|
+
const exhausted = { "%}": false, "}}": false, "#}": false };
|
|
10403
|
+
while (scan < n) {
|
|
10404
|
+
const brace = source.indexOf("{", scan);
|
|
10405
|
+
if (brace === -1) break;
|
|
10406
|
+
const kind = TAG_KINDS[source[brace + 1]];
|
|
10407
|
+
if (!kind) {
|
|
10408
|
+
scan = brace + 1;
|
|
10409
|
+
continue;
|
|
10346
10410
|
}
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
} else if (raw.startsWith("{{")) {
|
|
10351
|
-
tokens.push(["VAR", raw]);
|
|
10352
|
-
} else if (raw.startsWith("{%")) {
|
|
10353
|
-
tokens.push(["BLOCK", raw]);
|
|
10411
|
+
if (exhausted[kind.close]) {
|
|
10412
|
+
scan = brace + 1;
|
|
10413
|
+
continue;
|
|
10354
10414
|
}
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10415
|
+
const close = source.indexOf(kind.close, brace + 2);
|
|
10416
|
+
if (close === -1) {
|
|
10417
|
+
exhausted[kind.close] = true;
|
|
10418
|
+
scan = brace + 1;
|
|
10419
|
+
continue;
|
|
10420
|
+
}
|
|
10421
|
+
if (brace > pos) tokens.push(["TEXT", source.slice(pos, brace)]);
|
|
10422
|
+
tokens.push([kind.type, source.slice(brace, close + 2)]);
|
|
10423
|
+
pos = close + 2;
|
|
10424
|
+
scan = close + 2;
|
|
10359
10425
|
}
|
|
10426
|
+
if (pos < n) tokens.push(["TEXT", source.slice(pos)]);
|
|
10360
10427
|
if (rawBlocks.length > 0) {
|
|
10361
10428
|
for (let i = 0; i < tokens.length; i++) {
|
|
10362
10429
|
if (tokens[i][0] === "TEXT" && tokens[i][1].includes("\0RAW_")) {
|
|
@@ -10682,26 +10749,123 @@ function evalConcatOrComparison(expr, context) {
|
|
|
10682
10749
|
}
|
|
10683
10750
|
return EXPR_NOT_MATCHED;
|
|
10684
10751
|
}
|
|
10752
|
+
function topLevelPositions(expr) {
|
|
10753
|
+
const positions = [];
|
|
10754
|
+
let inQuote = null;
|
|
10755
|
+
let depth = 0;
|
|
10756
|
+
for (let pos = 0; pos < expr.length; pos++) {
|
|
10757
|
+
const ch = expr[pos];
|
|
10758
|
+
if (inQuote) {
|
|
10759
|
+
if (ch === inQuote) inQuote = null;
|
|
10760
|
+
} else if (ch === '"' || ch === "'") {
|
|
10761
|
+
inQuote = ch;
|
|
10762
|
+
} else if ("([{".includes(ch)) {
|
|
10763
|
+
depth++;
|
|
10764
|
+
} else if (")]}".includes(ch)) {
|
|
10765
|
+
depth--;
|
|
10766
|
+
} else if (depth === 0) {
|
|
10767
|
+
positions.push(pos);
|
|
10768
|
+
}
|
|
10769
|
+
}
|
|
10770
|
+
return positions;
|
|
10771
|
+
}
|
|
10772
|
+
function followsOperand(expr, pos) {
|
|
10773
|
+
return /[\w)\]'"]$/.test(expr.slice(0, pos).trimEnd());
|
|
10774
|
+
}
|
|
10775
|
+
function topLevelArithmeticOperators(expr) {
|
|
10776
|
+
const operators = [];
|
|
10777
|
+
let skipUntil = -1;
|
|
10778
|
+
for (const pos of topLevelPositions(expr)) {
|
|
10779
|
+
if (pos < skipUntil || !"+-*/%".includes(expr[pos])) continue;
|
|
10780
|
+
const pair = expr.slice(pos, pos + 2);
|
|
10781
|
+
const op = pair === "**" || pair === "//" ? pair : expr[pos];
|
|
10782
|
+
skipUntil = pos + op.length;
|
|
10783
|
+
if (followsOperand(expr, pos)) operators.push([pos, op]);
|
|
10784
|
+
}
|
|
10785
|
+
return operators;
|
|
10786
|
+
}
|
|
10787
|
+
function splitArithmetic(expr) {
|
|
10788
|
+
const operators = topLevelArithmeticOperators(expr);
|
|
10789
|
+
for (const level of ARITHMETIC_LEVELS) {
|
|
10790
|
+
const matches = operators.filter(([, op]) => level.includes(op));
|
|
10791
|
+
if (matches.length > 0) return level[0] === "**" ? matches[0] : matches[matches.length - 1];
|
|
10792
|
+
}
|
|
10793
|
+
return null;
|
|
10794
|
+
}
|
|
10685
10795
|
function evalArithmeticExpression(expr, context) {
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10796
|
+
const split = splitArithmetic(expr);
|
|
10797
|
+
if (!split) return EXPR_NOT_MATCHED;
|
|
10798
|
+
const [pos, op] = split;
|
|
10799
|
+
const lVal = evalExpr(expr.slice(0, pos).trim(), context);
|
|
10800
|
+
const rVal = evalExpr(expr.slice(pos + op.length).trim(), context);
|
|
10801
|
+
let lNum = lVal != null ? Number(lVal) : 0;
|
|
10802
|
+
let rNum = rVal != null ? Number(rVal) : 0;
|
|
10803
|
+
if (isNaN(lNum)) lNum = 0;
|
|
10804
|
+
if (isNaN(rNum)) rNum = 0;
|
|
10805
|
+
return ARITHMETIC_OPERATIONS[op](lNum, rNum);
|
|
10806
|
+
}
|
|
10807
|
+
function frondRange(start2, end, step = 1) {
|
|
10808
|
+
const numeric = (value) => typeof value === "number" || typeof value === "string" && NUMERIC_RE.test(value);
|
|
10809
|
+
if (!numeric(start2) || !numeric(end) || !numeric(step)) return [];
|
|
10810
|
+
const first = Math.trunc(Number(start2));
|
|
10811
|
+
const last = Math.trunc(Number(end));
|
|
10812
|
+
const stride = Math.abs(Math.trunc(Number(step)));
|
|
10813
|
+
if (stride === 0) return [];
|
|
10814
|
+
const values = [];
|
|
10815
|
+
if (first <= last) for (let value = first; value <= last; value += stride) values.push(value);
|
|
10816
|
+
else for (let value = first; value >= last; value -= stride) values.push(value);
|
|
10817
|
+
return values;
|
|
10818
|
+
}
|
|
10819
|
+
function findRangeOperator(expr) {
|
|
10820
|
+
let pos = findOutsideQuotes(expr, "..");
|
|
10821
|
+
while (pos >= 0) {
|
|
10822
|
+
const partOfEllipsis = expr.startsWith("...", pos) || pos > 0 && expr[pos - 1] === ".";
|
|
10823
|
+
if (pos > 0 && !partOfEllipsis) return findOutsideQuotes(expr.slice(pos + 2), "|") >= 0 ? -1 : pos;
|
|
10824
|
+
const next = findOutsideQuotes(expr.slice(pos + 2), "..");
|
|
10825
|
+
pos = next >= 0 ? pos + 2 + next : -1;
|
|
10826
|
+
}
|
|
10827
|
+
return -1;
|
|
10828
|
+
}
|
|
10829
|
+
function evalRangeExpression(expr, context) {
|
|
10830
|
+
const pos = findRangeOperator(expr);
|
|
10831
|
+
if (pos < 0) return EXPR_NOT_MATCHED;
|
|
10832
|
+
return frondRange(evalExpr(expr.slice(0, pos).trim(), context), evalExpr(expr.slice(pos + 2).trim(), context));
|
|
10833
|
+
}
|
|
10834
|
+
function closingBracketIndex(expr) {
|
|
10835
|
+
let depth = 0;
|
|
10836
|
+
let inQuote = null;
|
|
10837
|
+
for (let i = 0; i < expr.length; i++) {
|
|
10838
|
+
const ch = expr[i];
|
|
10839
|
+
if (inQuote) {
|
|
10840
|
+
if (ch === inQuote) inQuote = null;
|
|
10841
|
+
} else if (ch === '"' || ch === "'") {
|
|
10842
|
+
inQuote = ch;
|
|
10843
|
+
} else if ("([{".includes(ch)) {
|
|
10844
|
+
depth++;
|
|
10845
|
+
} else if (")]}".includes(ch) && --depth === 0) {
|
|
10846
|
+
return i;
|
|
10702
10847
|
}
|
|
10703
10848
|
}
|
|
10704
|
-
return
|
|
10849
|
+
return -1;
|
|
10850
|
+
}
|
|
10851
|
+
function mapLiteralKey(rawKey, context) {
|
|
10852
|
+
const quoted = rawKey.length >= 2 && (rawKey[0] === '"' || rawKey[0] === "'") && rawKey.endsWith(rawKey[0]);
|
|
10853
|
+
if (quoted) return rawKey.slice(1, -1);
|
|
10854
|
+
return BARE_KEY_RE.test(rawKey) ? rawKey : String(evalExpr(rawKey, context));
|
|
10855
|
+
}
|
|
10856
|
+
function evalMapLiteral(inner, context) {
|
|
10857
|
+
const map = {};
|
|
10858
|
+
for (const pair of inner === "" ? [] : splitArgs(inner)) {
|
|
10859
|
+
const colon = findOutsideQuotes(pair, ":");
|
|
10860
|
+
if (colon > 0) map[mapLiteralKey(pair.slice(0, colon).trim(), context)] = evalExpr(pair.slice(colon + 1).trim(), context);
|
|
10861
|
+
}
|
|
10862
|
+
return map;
|
|
10863
|
+
}
|
|
10864
|
+
function evalCollectionLiteral(expr, context) {
|
|
10865
|
+
if (expr[0] !== "[" && expr[0] !== "{" || closingBracketIndex(expr) !== expr.length - 1) return EXPR_NOT_MATCHED;
|
|
10866
|
+
const inner = expr.slice(1, -1).trim();
|
|
10867
|
+
if (expr[0] === "{") return evalMapLiteral(inner, context);
|
|
10868
|
+
return inner === "" ? [] : splitArgs(inner).map((item) => evalExpr(item.trim(), context));
|
|
10705
10869
|
}
|
|
10706
10870
|
function evalFilterExpression(expr, context) {
|
|
10707
10871
|
if (findOutsideQuotes(expr, "|") >= 0) {
|
|
@@ -11123,12 +11287,12 @@ function splitArgs(raw) {
|
|
|
11123
11287
|
current += ch;
|
|
11124
11288
|
continue;
|
|
11125
11289
|
}
|
|
11126
|
-
if (ch === "(" || ch === "[") {
|
|
11290
|
+
if (ch === "(" || ch === "[" || ch === "{") {
|
|
11127
11291
|
depth++;
|
|
11128
11292
|
current += ch;
|
|
11129
11293
|
continue;
|
|
11130
11294
|
}
|
|
11131
|
-
if (ch === ")" || ch === "]") {
|
|
11295
|
+
if (ch === ")" || ch === "]" || ch === "}") {
|
|
11132
11296
|
depth--;
|
|
11133
11297
|
current += ch;
|
|
11134
11298
|
continue;
|
|
@@ -11293,11 +11457,14 @@ function formatMatch(match, flags, width, prec, type2, arg) {
|
|
|
11293
11457
|
return padFormattedValue(formatValue(type2, precision, arg), flags, width);
|
|
11294
11458
|
}
|
|
11295
11459
|
function _b64url(data) {
|
|
11296
|
-
return data.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(
|
|
11460
|
+
return data.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/={1,2}$/, "");
|
|
11297
11461
|
}
|
|
11298
11462
|
function setFormTokenSessionId(sessionId) {
|
|
11299
11463
|
_formTokenSessionId = sessionId || "";
|
|
11300
11464
|
}
|
|
11465
|
+
function setFormTokenSessionProvider(fn) {
|
|
11466
|
+
_formTokenSessionProvider = fn;
|
|
11467
|
+
}
|
|
11301
11468
|
function setCspNonceProvider(fn) {
|
|
11302
11469
|
_cspNonceProvider = fn;
|
|
11303
11470
|
}
|
|
@@ -11322,8 +11489,9 @@ function _buildFormTokenJwt(descriptor = "") {
|
|
|
11322
11489
|
payload.context = descriptor;
|
|
11323
11490
|
}
|
|
11324
11491
|
}
|
|
11325
|
-
|
|
11326
|
-
|
|
11492
|
+
const sessionId = _formTokenSessionProvider() || _formTokenSessionId;
|
|
11493
|
+
if (sessionId) {
|
|
11494
|
+
payload.session_id = sessionId;
|
|
11327
11495
|
}
|
|
11328
11496
|
const h2 = _b64url(Buffer.from(JSON.stringify(header)));
|
|
11329
11497
|
const p = _b64url(Buffer.from(JSON.stringify(payload)));
|
|
@@ -11339,7 +11507,7 @@ function _generateFormToken(descriptor = "") {
|
|
|
11339
11507
|
function _generateFormTokenValue(descriptor = "") {
|
|
11340
11508
|
return new SafeString(_buildFormTokenJwt(descriptor));
|
|
11341
11509
|
}
|
|
11342
|
-
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,
|
|
11510
|
+
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;
|
|
11343
11511
|
var init_engine = __esm({
|
|
11344
11512
|
"../frond/src/engine.ts"() {
|
|
11345
11513
|
"use strict";
|
|
@@ -11441,7 +11609,7 @@ var init_engine = __esm({
|
|
|
11441
11609
|
int: (value) => value ? parseInt(String(value), 10) || 0 : 0,
|
|
11442
11610
|
float: (value) => value ? parseFloat(String(value)) || 0 : 0,
|
|
11443
11611
|
abs: (value) => typeof value === "number" ? Math.abs(value) : value,
|
|
11444
|
-
striptags: (value) => String(value)
|
|
11612
|
+
striptags: (value) => stripTags(String(value)),
|
|
11445
11613
|
first: (value) => Array.isArray(value) ? value[0] ?? null : null,
|
|
11446
11614
|
last: (value) => Array.isArray(value) ? value[value.length - 1] ?? null : null,
|
|
11447
11615
|
keys: (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? Object.keys(value) : [],
|
|
@@ -11455,20 +11623,23 @@ var init_engine = __esm({
|
|
|
11455
11623
|
filter: (value) => Array.isArray(value) ? value.filter(Boolean) : value
|
|
11456
11624
|
};
|
|
11457
11625
|
FORMAT_RE = /%%|%([-+ 0]*)(\d+)?(?:\.(\d+))?([sdifFeEgGxXob])/g;
|
|
11458
|
-
LEADING_WS_RE = /^\s+/;
|
|
11459
|
-
TRAILING_WS_RE = /\s+$/;
|
|
11460
11626
|
THOUSANDS_RE = /\B(?=(\d{3})+(?!\d))/g;
|
|
11461
11627
|
LIVE_RE = /^live\s+["']([^"']+)["']([\s\S]*)$/;
|
|
11462
11628
|
LIVE_WS_RE = /ws\s+["']([^"']+)["']/;
|
|
11463
11629
|
LIVE_SRC_RE = /src\s+["']([^"']+)["']/;
|
|
11464
|
-
EXTENDS_RE = /\{%[-\s]*extends\s+["'](
|
|
11465
|
-
EXTENDS_RE_GLOBAL = /\{%[-\s]*extends\s+["'](
|
|
11630
|
+
EXTENDS_RE = /\{%[-\s]*extends\s+["']([^"']+)["']\s*[-]?%\}/;
|
|
11631
|
+
EXTENDS_RE_GLOBAL = /\{%[-\s]*extends\s+["']([^"']+)["']\s*[-]?%\}/g;
|
|
11466
11632
|
filterChainCache = /* @__PURE__ */ new Map();
|
|
11467
11633
|
pathParseCache = /* @__PURE__ */ new Map();
|
|
11468
11634
|
TEMPLATE_CACHE_MAX = 256;
|
|
11469
11635
|
MEMO_CACHE_MAX = 1024;
|
|
11470
|
-
|
|
11471
|
-
|
|
11636
|
+
RAW_OPEN_RE = /\{%-?\s*raw\s*-?%\}/g;
|
|
11637
|
+
RAW_CLOSE_RE = /\{%-?\s*endraw\s*-?%\}/g;
|
|
11638
|
+
TAG_KINDS = {
|
|
11639
|
+
"%": { close: "%}", type: "BLOCK" },
|
|
11640
|
+
"{": { close: "}}", type: "VAR" },
|
|
11641
|
+
"#": { close: "#}", type: "COMMENT" }
|
|
11642
|
+
};
|
|
11472
11643
|
EXPR_NOT_MATCHED = /* @__PURE__ */ Symbol("frond-expression-not-matched");
|
|
11473
11644
|
ARITHMETIC_OPERATIONS = {
|
|
11474
11645
|
"+": (left, right) => left + right,
|
|
@@ -11479,10 +11650,14 @@ var init_engine = __esm({
|
|
|
11479
11650
|
"%": (left, right) => right !== 0 ? left % right : 0,
|
|
11480
11651
|
"**": (left, right) => left ** right
|
|
11481
11652
|
};
|
|
11653
|
+
ARITHMETIC_LEVELS = [["+", "-"], ["*", "//", "/", "%"], ["**"]];
|
|
11654
|
+
BARE_KEY_RE = /^[A-Za-z_]\w*$/;
|
|
11482
11655
|
EXPR_EVALUATORS = [
|
|
11656
|
+
evalCollectionLiteral,
|
|
11483
11657
|
evalPrimary,
|
|
11484
11658
|
evalConditional,
|
|
11485
11659
|
evalConcatOrComparison,
|
|
11660
|
+
evalRangeExpression,
|
|
11486
11661
|
evalArithmeticExpression,
|
|
11487
11662
|
evalFilterExpression,
|
|
11488
11663
|
evalFunctionExpression
|
|
@@ -11538,8 +11713,8 @@ var init_engine = __esm({
|
|
|
11538
11713
|
},
|
|
11539
11714
|
title: (v) => String(v).replace(TITLE_WORD_RE, (c) => c.toUpperCase()),
|
|
11540
11715
|
trim: (v) => String(v).trim(),
|
|
11541
|
-
ltrim: (v) => String(v).
|
|
11542
|
-
rtrim: (v) => String(v).
|
|
11716
|
+
ltrim: (v) => String(v).trimStart(),
|
|
11717
|
+
rtrim: (v) => String(v).trimEnd(),
|
|
11543
11718
|
length: (v) => {
|
|
11544
11719
|
if (Array.isArray(v)) return v.length;
|
|
11545
11720
|
if (typeof v === "string") return v.length;
|
|
@@ -11580,7 +11755,7 @@ var init_engine = __esm({
|
|
|
11580
11755
|
safe: (v) => v,
|
|
11581
11756
|
escape: (v, ...a) => escapeStrategy(v, a[0] ?? "html"),
|
|
11582
11757
|
e: (v, ...a) => escapeStrategy(v, a[0] ?? "html"),
|
|
11583
|
-
striptags: (v) => String(v)
|
|
11758
|
+
striptags: (v) => stripTags(String(v)),
|
|
11584
11759
|
nl2br: (v) => new SafeString(htmlEscape(String(v)).replace(/\n/g, "<br />\n")),
|
|
11585
11760
|
abs: (v) => typeof v === "number" ? Math.abs(v) : v,
|
|
11586
11761
|
round: (v, decimals) => {
|
|
@@ -11693,6 +11868,7 @@ var init_engine = __esm({
|
|
|
11693
11868
|
js_escape: (v) => new SafeString(jsEscape(v))
|
|
11694
11869
|
};
|
|
11695
11870
|
_formTokenSessionId = "";
|
|
11871
|
+
_formTokenSessionProvider = () => "";
|
|
11696
11872
|
_cspNonceProvider = () => "";
|
|
11697
11873
|
Frond = class _Frond {
|
|
11698
11874
|
// ── Class-level registries ──────────────────────────────────
|
|
@@ -11846,6 +12022,7 @@ var init_engine = __esm({
|
|
|
11846
12022
|
this.globals.form_token = (descriptor) => _generateFormToken(descriptor || "");
|
|
11847
12023
|
this.globals.formTokenValue = (descriptor) => _generateFormTokenValue(descriptor || "");
|
|
11848
12024
|
this.globals.form_token_value = (descriptor) => _generateFormTokenValue(descriptor || "");
|
|
12025
|
+
this.globals.range = frondRange;
|
|
11849
12026
|
this.globals.dump = (value) => renderDump(value);
|
|
11850
12027
|
this.globals.csp_nonce = () => _cspNonceProvider();
|
|
11851
12028
|
for (const [k, v] of _Frond.classFilters) this.filters[k] = v;
|
|
@@ -12182,20 +12359,20 @@ var init_engine = __esm({
|
|
|
12182
12359
|
}
|
|
12183
12360
|
renderVarToken(tokens, index, context, output) {
|
|
12184
12361
|
const [content, stripB, stripA] = stripTag(tokens[index][1]);
|
|
12185
|
-
if (stripB && output.length > 0) output[output.length - 1] = output[output.length - 1].
|
|
12362
|
+
if (stripB && output.length > 0) output[output.length - 1] = output[output.length - 1].trimEnd();
|
|
12186
12363
|
const result = this.evalVar(content, context);
|
|
12187
12364
|
output.push(result !== null && result !== void 0 ? String(result) : "");
|
|
12188
12365
|
if (stripA && index + 1 < tokens.length && tokens[index + 1][0] === "TEXT") {
|
|
12189
|
-
tokens[index + 1] = ["TEXT", tokens[index + 1][1].
|
|
12366
|
+
tokens[index + 1] = ["TEXT", tokens[index + 1][1].trimStart()];
|
|
12190
12367
|
}
|
|
12191
12368
|
return index + 1;
|
|
12192
12369
|
}
|
|
12193
12370
|
renderBlockToken(tokens, index, context, output) {
|
|
12194
12371
|
const [content, stripB, stripA] = stripTag(tokens[index][1]);
|
|
12195
|
-
if (stripB && output.length > 0) output[output.length - 1] = output[output.length - 1].
|
|
12372
|
+
if (stripB && output.length > 0) output[output.length - 1] = output[output.length - 1].trimEnd();
|
|
12196
12373
|
const tag = content.split(/\s+/)[0] || "";
|
|
12197
12374
|
if (stripA && index + 1 < tokens.length && tokens[index + 1][0] === "TEXT") {
|
|
12198
|
-
tokens[index + 1] = ["TEXT", tokens[index + 1][1].
|
|
12375
|
+
tokens[index + 1] = ["TEXT", tokens[index + 1][1].trimStart()];
|
|
12199
12376
|
}
|
|
12200
12377
|
let next;
|
|
12201
12378
|
if (tag === "if" && this.tagPermitted(tag)) {
|
|
@@ -12212,7 +12389,7 @@ var init_engine = __esm({
|
|
|
12212
12389
|
next = block.next;
|
|
12213
12390
|
}
|
|
12214
12391
|
if (stripA && next < tokens.length && tokens[next][0] === "TEXT") {
|
|
12215
|
-
tokens[next] = ["TEXT", tokens[next][1].
|
|
12392
|
+
tokens[next] = ["TEXT", tokens[next][1].trimStart()];
|
|
12216
12393
|
}
|
|
12217
12394
|
return next;
|
|
12218
12395
|
}
|
|
@@ -12471,7 +12648,7 @@ var init_engine = __esm({
|
|
|
12471
12648
|
pushIfBranch(branches, condition, branchTokens, stripBefore) {
|
|
12472
12649
|
if (stripBefore && branchTokens.length > 0 && branchTokens[branchTokens.length - 1][0] === "TEXT") {
|
|
12473
12650
|
const last = branchTokens[branchTokens.length - 1];
|
|
12474
|
-
branchTokens[branchTokens.length - 1] = ["TEXT", last[1].
|
|
12651
|
+
branchTokens[branchTokens.length - 1] = ["TEXT", last[1].trimEnd()];
|
|
12475
12652
|
}
|
|
12476
12653
|
branches.push([condition, branchTokens]);
|
|
12477
12654
|
}
|
|
@@ -12499,7 +12676,7 @@ var init_engine = __esm({
|
|
|
12499
12676
|
} else if (tag === "endif") {
|
|
12500
12677
|
this.pushIfBranch(branches, currentCond, currentTokens, tagStripB);
|
|
12501
12678
|
if (tagStripA && i + 1 < tokens.length && tokens[i + 1][0] === "TEXT") {
|
|
12502
|
-
tokens[i + 1] = ["TEXT", tokens[i + 1][1].
|
|
12679
|
+
tokens[i + 1] = ["TEXT", tokens[i + 1][1].trimStart()];
|
|
12503
12680
|
}
|
|
12504
12681
|
return { branches, next: i + 1 };
|
|
12505
12682
|
} else if ((tag === "elseif" || tag === "elif") && depth === 0) {
|
|
@@ -13285,7 +13462,7 @@ function tableData(opts) {
|
|
|
13285
13462
|
readonly: !opts.editable,
|
|
13286
13463
|
inline_script: opts.inlineScript,
|
|
13287
13464
|
table_name: h(opts.tableName),
|
|
13288
|
-
|
|
13465
|
+
table_id: opts.tableId ? String(opts.tableId) : ""
|
|
13289
13466
|
};
|
|
13290
13467
|
}
|
|
13291
13468
|
var init_crudTable = __esm({
|
|
@@ -13393,13 +13570,13 @@ function renderModalForm(mode, columns, pk, edit) {
|
|
|
13393
13570
|
value: "",
|
|
13394
13571
|
placeholder: h(`Enter ${label.toLowerCase()}`),
|
|
13395
13572
|
type: "text",
|
|
13396
|
-
|
|
13573
|
+
required: false,
|
|
13397
13574
|
input: true
|
|
13398
13575
|
};
|
|
13399
13576
|
});
|
|
13400
13577
|
return renderCrudTemplate("form", {
|
|
13401
13578
|
wrap: true,
|
|
13402
|
-
|
|
13579
|
+
form_id: `form-${mode}`,
|
|
13403
13580
|
action: "",
|
|
13404
13581
|
form_method: "POST",
|
|
13405
13582
|
method_override: null,
|
|
@@ -13456,7 +13633,7 @@ function fieldInputShape(field, base) {
|
|
|
13456
13633
|
case "text":
|
|
13457
13634
|
return { ...base, textarea: true };
|
|
13458
13635
|
case "boolean":
|
|
13459
|
-
return { ...base, checkbox: true,
|
|
13636
|
+
return { ...base, checkbox: true, checked: !!value };
|
|
13460
13637
|
case "select":
|
|
13461
13638
|
return { ...base, select: true, options_html: buildOptions(field.options, value) };
|
|
13462
13639
|
case "date":
|
|
@@ -13479,7 +13656,7 @@ function buildCustomField(field) {
|
|
|
13479
13656
|
label: h(String(label)),
|
|
13480
13657
|
value: h(field.value ?? ""),
|
|
13481
13658
|
placeholder: "",
|
|
13482
|
-
|
|
13659
|
+
required: !!field.required
|
|
13483
13660
|
};
|
|
13484
13661
|
return fieldInputShape(field, base);
|
|
13485
13662
|
}
|
|
@@ -13487,7 +13664,7 @@ function generateForm(fields, options = {}) {
|
|
|
13487
13664
|
const verb = String(options.method ?? "POST").toUpperCase();
|
|
13488
13665
|
return renderCrudTemplate("form", {
|
|
13489
13666
|
wrap: true,
|
|
13490
|
-
|
|
13667
|
+
form_id: "",
|
|
13491
13668
|
action: h(options.action ?? "/"),
|
|
13492
13669
|
form_method: h(verb),
|
|
13493
13670
|
method_override: ["PUT", "PATCH", "DELETE"].includes(verb) ? verb : null,
|
|
@@ -18138,20 +18315,210 @@ var init_attachment = __esm({
|
|
|
18138
18315
|
}
|
|
18139
18316
|
});
|
|
18140
18317
|
|
|
18318
|
+
// ../orm/src/realtime/s3Client.ts
|
|
18319
|
+
import { createHash as createHash4, createHmac as createHmac3 } from "node:crypto";
|
|
18320
|
+
function retryAfterSeconds(raw) {
|
|
18321
|
+
if (raw == null) return null;
|
|
18322
|
+
const n = Number(raw);
|
|
18323
|
+
return Number.isFinite(n) ? Math.max(0, n) : null;
|
|
18324
|
+
}
|
|
18325
|
+
function uriEncode(value, isPath) {
|
|
18326
|
+
let out = "";
|
|
18327
|
+
for (const byte of Buffer.from(value, "utf8")) {
|
|
18328
|
+
const ch = String.fromCharCode(byte);
|
|
18329
|
+
if (UNRESERVED.test(ch) || isPath && ch === "/") out += ch;
|
|
18330
|
+
else out += "%" + byte.toString(16).toUpperCase().padStart(2, "0");
|
|
18331
|
+
}
|
|
18332
|
+
return out;
|
|
18333
|
+
}
|
|
18334
|
+
function sha256Hex2(data) {
|
|
18335
|
+
return createHash4("sha256").update(data).digest("hex");
|
|
18336
|
+
}
|
|
18337
|
+
function hmac(key, msg) {
|
|
18338
|
+
return createHmac3("sha256", key).update(msg, "utf8").digest();
|
|
18339
|
+
}
|
|
18340
|
+
var ALGORITHM, SERVICE, UNRESERVED, MAX_RETRIES, BACKOFF_BASE, BACKOFF_CAP, S3Error, S3ConfigError, sleep, S3Client;
|
|
18341
|
+
var init_s3Client = __esm({
|
|
18342
|
+
"../orm/src/realtime/s3Client.ts"() {
|
|
18343
|
+
"use strict";
|
|
18344
|
+
ALGORITHM = "AWS4-HMAC-SHA256";
|
|
18345
|
+
SERVICE = "s3";
|
|
18346
|
+
UNRESERVED = /[A-Za-z0-9\-_.~]/;
|
|
18347
|
+
MAX_RETRIES = 2;
|
|
18348
|
+
BACKOFF_BASE = 0.5;
|
|
18349
|
+
BACKOFF_CAP = 20;
|
|
18350
|
+
S3Error = class extends Error {
|
|
18351
|
+
constructor(status2, message) {
|
|
18352
|
+
super(message);
|
|
18353
|
+
this.status = status2;
|
|
18354
|
+
this.name = "S3Error";
|
|
18355
|
+
}
|
|
18356
|
+
status;
|
|
18357
|
+
/** Seconds from a Retry-After header in its delta-seconds form, else null. */
|
|
18358
|
+
retryAfter = null;
|
|
18359
|
+
};
|
|
18360
|
+
S3ConfigError = class extends Error {
|
|
18361
|
+
constructor(message) {
|
|
18362
|
+
super(message);
|
|
18363
|
+
this.name = "S3ConfigError";
|
|
18364
|
+
}
|
|
18365
|
+
};
|
|
18366
|
+
sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
18367
|
+
S3Client = class {
|
|
18368
|
+
scheme;
|
|
18369
|
+
host;
|
|
18370
|
+
// authority (host[:port]) — matches the Host header
|
|
18371
|
+
prefix;
|
|
18372
|
+
// path an endpoint carries (https://host/s3 -> "/s3"), "" if none
|
|
18373
|
+
region;
|
|
18374
|
+
accessKey;
|
|
18375
|
+
secretKey;
|
|
18376
|
+
timeout;
|
|
18377
|
+
constructor(opts = {}) {
|
|
18378
|
+
this.region = opts.region || "us-east-1";
|
|
18379
|
+
this.accessKey = opts.accessKey || "";
|
|
18380
|
+
this.secretKey = opts.secretKey || "";
|
|
18381
|
+
this.timeout = opts.timeout ?? 3e4;
|
|
18382
|
+
let base = opts.endpoint || `https://s3.${this.region}.amazonaws.com`;
|
|
18383
|
+
while (base.endsWith("/")) base = base.slice(0, -1);
|
|
18384
|
+
const m = /^([a-z][a-z0-9+.-]*):\/\/([^/]+)(\/.*)?$/i.exec(base);
|
|
18385
|
+
this.scheme = m ? m[1] : "https";
|
|
18386
|
+
this.host = m ? m[2] : base;
|
|
18387
|
+
let p = m && m[3] ? m[3] : "";
|
|
18388
|
+
while (p.endsWith("/")) p = p.slice(0, -1);
|
|
18389
|
+
this.prefix = p;
|
|
18390
|
+
}
|
|
18391
|
+
// -- public API (the subset S3Storage uses) --------------------------------
|
|
18392
|
+
async putObject(bucket, key, data, contentType = "application/octet-stream") {
|
|
18393
|
+
const body = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
18394
|
+
await this.request("PUT", this.canonicalUri(bucket, key), body, { "content-type": contentType });
|
|
18395
|
+
}
|
|
18396
|
+
async getObject(bucket, key) {
|
|
18397
|
+
return (await this.request("GET", this.canonicalUri(bucket, key), Buffer.alloc(0))).body;
|
|
18398
|
+
}
|
|
18399
|
+
async deleteObject(bucket, key) {
|
|
18400
|
+
await this.request("DELETE", this.canonicalUri(bucket, key), Buffer.alloc(0));
|
|
18401
|
+
}
|
|
18402
|
+
async headObject(bucket, key) {
|
|
18403
|
+
await this.request("HEAD", this.canonicalUri(bucket, key), Buffer.alloc(0));
|
|
18404
|
+
}
|
|
18405
|
+
/** Create the bucket (path-style `PUT /<bucket>`); an already-owned bucket (409) is success. */
|
|
18406
|
+
async createBucket(bucket) {
|
|
18407
|
+
try {
|
|
18408
|
+
await this.request("PUT", `${this.prefix}/${uriEncode(bucket, true)}`, Buffer.alloc(0));
|
|
18409
|
+
} catch (e) {
|
|
18410
|
+
if (!(e instanceof S3Error) || e.status !== 409) throw e;
|
|
18411
|
+
}
|
|
18412
|
+
}
|
|
18413
|
+
/** A URL that fetches the object directly, signed via SigV4 query params. */
|
|
18414
|
+
presignedGetUrl(bucket, key, expires = 3600) {
|
|
18415
|
+
this.requireCredentials();
|
|
18416
|
+
const { amzDate, dateStamp } = this.now();
|
|
18417
|
+
const uri = this.canonicalUri(bucket, key);
|
|
18418
|
+
const scope = `${dateStamp}/${this.region}/${SERVICE}/aws4_request`;
|
|
18419
|
+
const query = {
|
|
18420
|
+
"X-Amz-Algorithm": ALGORITHM,
|
|
18421
|
+
"X-Amz-Credential": `${this.accessKey}/${scope}`,
|
|
18422
|
+
"X-Amz-Date": amzDate,
|
|
18423
|
+
"X-Amz-Expires": String(expires),
|
|
18424
|
+
"X-Amz-SignedHeaders": "host"
|
|
18425
|
+
};
|
|
18426
|
+
const canonicalQs = this.canonicalQuery(query);
|
|
18427
|
+
const canonicalRequest = ["GET", uri, canonicalQs, `host:${this.host}
|
|
18428
|
+
`, "host", "UNSIGNED-PAYLOAD"].join("\n");
|
|
18429
|
+
const signature = this.sign(canonicalRequest, amzDate, dateStamp, scope);
|
|
18430
|
+
return `${this.scheme}://${this.host}${uri}?${canonicalQs}&X-Amz-Signature=${signature}`;
|
|
18431
|
+
}
|
|
18432
|
+
// -- signing + transport ----------------------------------------------------
|
|
18433
|
+
requireCredentials() {
|
|
18434
|
+
if (!this.accessKey || !this.secretKey) {
|
|
18435
|
+
throw new S3ConfigError(
|
|
18436
|
+
"S3 credentials are not set: set TINA4_STORAGE_KEY and TINA4_STORAGE_SECRET"
|
|
18437
|
+
);
|
|
18438
|
+
}
|
|
18439
|
+
}
|
|
18440
|
+
now() {
|
|
18441
|
+
const iso2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:-]|\.\d{3}/g, "");
|
|
18442
|
+
return { amzDate: iso2, dateStamp: iso2.slice(0, 8) };
|
|
18443
|
+
}
|
|
18444
|
+
canonicalUri(bucket, key) {
|
|
18445
|
+
return `${this.prefix}/${uriEncode(bucket, true)}/${uriEncode(key, true)}`;
|
|
18446
|
+
}
|
|
18447
|
+
canonicalQuery(query) {
|
|
18448
|
+
return Object.keys(query).sort().map((k) => `${uriEncode(k, false)}=${uriEncode(query[k], false)}`).join("&");
|
|
18449
|
+
}
|
|
18450
|
+
signingKey(dateStamp) {
|
|
18451
|
+
const kDate = hmac(`AWS4${this.secretKey}`, dateStamp);
|
|
18452
|
+
const kRegion = hmac(kDate, this.region);
|
|
18453
|
+
const kService = hmac(kRegion, SERVICE);
|
|
18454
|
+
return hmac(kService, "aws4_request");
|
|
18455
|
+
}
|
|
18456
|
+
sign(canonicalRequest, amzDate, dateStamp, scope) {
|
|
18457
|
+
const stringToSign = [ALGORITHM, amzDate, scope, sha256Hex2(canonicalRequest)].join("\n");
|
|
18458
|
+
return createHmac3("sha256", this.signingKey(dateStamp)).update(stringToSign, "utf8").digest("hex");
|
|
18459
|
+
}
|
|
18460
|
+
async request(method, uri, body, extraHeaders = {}) {
|
|
18461
|
+
this.requireCredentials();
|
|
18462
|
+
for (let attempt = 0; ; attempt++) {
|
|
18463
|
+
const last = attempt === MAX_RETRIES;
|
|
18464
|
+
let delay2 = null;
|
|
18465
|
+
try {
|
|
18466
|
+
return await this.send(method, uri, body, extraHeaders);
|
|
18467
|
+
} catch (e) {
|
|
18468
|
+
if (e instanceof S3Error) {
|
|
18469
|
+
if (last || !(e.status === 429 || e.status >= 500)) throw e;
|
|
18470
|
+
delay2 = e.retryAfter;
|
|
18471
|
+
} else {
|
|
18472
|
+
if (last) throw e;
|
|
18473
|
+
delay2 = null;
|
|
18474
|
+
}
|
|
18475
|
+
}
|
|
18476
|
+
if (delay2 == null) delay2 = Math.random() * (BACKOFF_BASE * 2 ** attempt);
|
|
18477
|
+
await sleep(Math.min(delay2, BACKOFF_CAP) * 1e3);
|
|
18478
|
+
}
|
|
18479
|
+
}
|
|
18480
|
+
async send(method, uri, body, extraHeaders = {}) {
|
|
18481
|
+
const { amzDate, dateStamp } = this.now();
|
|
18482
|
+
const payloadHash = sha256Hex2(body);
|
|
18483
|
+
const signed = {
|
|
18484
|
+
host: this.host,
|
|
18485
|
+
"x-amz-content-sha256": payloadHash,
|
|
18486
|
+
"x-amz-date": amzDate
|
|
18487
|
+
};
|
|
18488
|
+
const signedKeys = Object.keys(signed).sort();
|
|
18489
|
+
const canonicalHeaders = signedKeys.map((k) => `${k}:${signed[k]}
|
|
18490
|
+
`).join("");
|
|
18491
|
+
const signedHeaders = signedKeys.join(";");
|
|
18492
|
+
const canonicalRequest = [method, uri, "", canonicalHeaders, signedHeaders, payloadHash].join("\n");
|
|
18493
|
+
const scope = `${dateStamp}/${this.region}/${SERVICE}/aws4_request`;
|
|
18494
|
+
const signature = this.sign(canonicalRequest, amzDate, dateStamp, scope);
|
|
18495
|
+
const authorization = `${ALGORITHM} Credential=${this.accessKey}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
18496
|
+
const headers = {
|
|
18497
|
+
Authorization: authorization,
|
|
18498
|
+
"x-amz-content-sha256": payloadHash,
|
|
18499
|
+
"x-amz-date": amzDate,
|
|
18500
|
+
...extraHeaders
|
|
18501
|
+
};
|
|
18502
|
+
const url = `${this.scheme}://${this.host}${uri}`;
|
|
18503
|
+
const init = { method, headers, redirect: "manual" };
|
|
18504
|
+
if (method === "PUT" || method === "POST") init.body = body;
|
|
18505
|
+
if (AbortSignal.timeout) init.signal = AbortSignal.timeout(this.timeout);
|
|
18506
|
+
const response = await fetch(url, init);
|
|
18507
|
+
if (response.status < 200 || response.status >= 300) {
|
|
18508
|
+
const err = new S3Error(response.status, `${method} ${uri}: HTTP ${response.status}`);
|
|
18509
|
+
err.retryAfter = retryAfterSeconds(response.headers.get("retry-after"));
|
|
18510
|
+
throw err;
|
|
18511
|
+
}
|
|
18512
|
+
return { status: response.status, body: Buffer.from(await response.arrayBuffer()) };
|
|
18513
|
+
}
|
|
18514
|
+
};
|
|
18515
|
+
}
|
|
18516
|
+
});
|
|
18517
|
+
|
|
18141
18518
|
// ../orm/src/realtime/storage.ts
|
|
18142
18519
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
18143
18520
|
import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, statSync as statSync5 } from "node:fs";
|
|
18144
18521
|
import { resolve as resolve6, sep as sep3 } from "node:path";
|
|
18145
|
-
import { createRequire as createRequire6 } from "node:module";
|
|
18146
|
-
function loadAwsSdk(packageName) {
|
|
18147
|
-
try {
|
|
18148
|
-
return require2(packageName);
|
|
18149
|
-
} catch (error2) {
|
|
18150
|
-
const missing = error2?.code === "MODULE_NOT_FOUND" && String(error2?.message ?? "").includes(`'${packageName}'`);
|
|
18151
|
-
if (!missing) throw error2;
|
|
18152
|
-
throw optionalPackageMissing("S3Storage", S3_PACKAGES);
|
|
18153
|
-
}
|
|
18154
|
-
}
|
|
18155
18522
|
function storageKey(filename = "") {
|
|
18156
18523
|
let ext = "";
|
|
18157
18524
|
if (filename && filename.includes(".")) {
|
|
@@ -18176,14 +18543,12 @@ function selectStorage(storage) {
|
|
|
18176
18543
|
}
|
|
18177
18544
|
return new LocalStorage();
|
|
18178
18545
|
}
|
|
18179
|
-
var
|
|
18546
|
+
var UNSAFE, LocalStorage, S3Storage;
|
|
18180
18547
|
var init_storage = __esm({
|
|
18181
18548
|
"../orm/src/realtime/storage.ts"() {
|
|
18182
18549
|
"use strict";
|
|
18183
18550
|
init_index();
|
|
18184
|
-
|
|
18185
|
-
require2 = createRequire6(import.meta.url);
|
|
18186
|
-
S3_PACKAGES = ["@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner"];
|
|
18551
|
+
init_s3Client();
|
|
18187
18552
|
UNSAFE = /[^A-Za-z0-9]/g;
|
|
18188
18553
|
LocalStorage = class {
|
|
18189
18554
|
directory;
|
|
@@ -18233,51 +18598,36 @@ var init_storage = __esm({
|
|
|
18233
18598
|
constructor(opts = {}) {
|
|
18234
18599
|
this.bucket = opts.bucket || process.env.TINA4_STORAGE_BUCKET || "";
|
|
18235
18600
|
if (!this.bucket) throw new Error("S3Storage requires TINA4_STORAGE_BUCKET");
|
|
18236
|
-
const { S3Client } = loadAwsSdk("@aws-sdk/client-s3");
|
|
18237
|
-
loadAwsSdk("@aws-sdk/s3-request-presigner");
|
|
18238
|
-
const endpoint = opts.endpoint || process.env.TINA4_STORAGE_URL;
|
|
18239
18601
|
this.client = new S3Client({
|
|
18240
|
-
endpoint: endpoint || void 0,
|
|
18241
|
-
forcePathStyle: true,
|
|
18602
|
+
endpoint: opts.endpoint || process.env.TINA4_STORAGE_URL || void 0,
|
|
18242
18603
|
region: opts.region || process.env.TINA4_STORAGE_REGION || "us-east-1",
|
|
18243
|
-
|
|
18244
|
-
|
|
18245
|
-
secretAccessKey: opts.secret || process.env.TINA4_STORAGE_SECRET || ""
|
|
18246
|
-
}
|
|
18604
|
+
accessKey: opts.key || process.env.TINA4_STORAGE_KEY || "",
|
|
18605
|
+
secretKey: opts.secret || process.env.TINA4_STORAGE_SECRET || ""
|
|
18247
18606
|
});
|
|
18248
18607
|
}
|
|
18249
18608
|
async put(key, data, mime = "application/octet-stream") {
|
|
18250
|
-
|
|
18251
|
-
await this.client.send(new PutObjectCommand({ Bucket: this.bucket, Key: key, Body: data, ContentType: mime }));
|
|
18609
|
+
await this.client.putObject(this.bucket, key, data, mime);
|
|
18252
18610
|
}
|
|
18253
18611
|
async get(key) {
|
|
18254
18612
|
try {
|
|
18255
|
-
|
|
18256
|
-
const res = await this.client.send(new GetObjectCommand({ Bucket: this.bucket, Key: key }));
|
|
18257
|
-
const chunks = [];
|
|
18258
|
-
for await (const chunk of res.Body) chunks.push(Buffer.from(chunk));
|
|
18259
|
-
return Buffer.concat(chunks);
|
|
18613
|
+
return await this.client.getObject(this.bucket, key);
|
|
18260
18614
|
} catch {
|
|
18261
18615
|
return null;
|
|
18262
18616
|
}
|
|
18263
18617
|
}
|
|
18264
18618
|
async url(key, ttl = 3600) {
|
|
18265
|
-
|
|
18266
|
-
const { getSignedUrl } = loadAwsSdk("@aws-sdk/s3-request-presigner");
|
|
18267
|
-
return getSignedUrl(this.client, new GetObjectCommand({ Bucket: this.bucket, Key: key }), { expiresIn: ttl });
|
|
18619
|
+
return this.client.presignedGetUrl(this.bucket, key, ttl);
|
|
18268
18620
|
}
|
|
18269
18621
|
async delete(key) {
|
|
18270
18622
|
try {
|
|
18271
|
-
|
|
18272
|
-
await this.client.send(new DeleteObjectCommand({ Bucket: this.bucket, Key: key }));
|
|
18623
|
+
await this.client.deleteObject(this.bucket, key);
|
|
18273
18624
|
} catch (e) {
|
|
18274
18625
|
Log.error(`S3Storage delete failed for ${key}: ${e.message}`);
|
|
18275
18626
|
}
|
|
18276
18627
|
}
|
|
18277
18628
|
async exists(key) {
|
|
18278
18629
|
try {
|
|
18279
|
-
|
|
18280
|
-
await this.client.send(new HeadObjectCommand({ Bucket: this.bucket, Key: key }));
|
|
18630
|
+
await this.client.headObject(this.bucket, key);
|
|
18281
18631
|
return true;
|
|
18282
18632
|
} catch {
|
|
18283
18633
|
return false;
|
|
@@ -18288,7 +18638,7 @@ var init_storage = __esm({
|
|
|
18288
18638
|
});
|
|
18289
18639
|
|
|
18290
18640
|
// ../orm/src/realtime/realtime.ts
|
|
18291
|
-
import { createHmac as
|
|
18641
|
+
import { createHmac as createHmac4 } from "node:crypto";
|
|
18292
18642
|
function iceServers() {
|
|
18293
18643
|
const stun = process.env.TINA4_RTC_STUN_URLS || DEFAULT_STUN;
|
|
18294
18644
|
const servers = [{ urls: splitUrls(stun) }];
|
|
@@ -18297,14 +18647,14 @@ function iceServers() {
|
|
|
18297
18647
|
if (turnUrl && secret) {
|
|
18298
18648
|
const ttl = parseInt(process.env.TINA4_RTC_TURN_TTL || "3600", 10);
|
|
18299
18649
|
const username = String(Math.floor(Date.now() / 1e3) + ttl);
|
|
18300
|
-
const credential =
|
|
18650
|
+
const credential = createHmac4("sha1", secret).update(username).digest("base64");
|
|
18301
18651
|
servers.push({ urls: splitUrls(turnUrl), username, credential });
|
|
18302
18652
|
}
|
|
18303
18653
|
return servers;
|
|
18304
18654
|
}
|
|
18305
18655
|
async function realtime(options = {}) {
|
|
18306
18656
|
const features = options.features ?? ["calls"];
|
|
18307
|
-
const raw = (options.prefix ?? "")
|
|
18657
|
+
const raw = trimSlashes(options.prefix ?? "");
|
|
18308
18658
|
const p = raw ? `/${raw}` : "";
|
|
18309
18659
|
_authorize = options.authorize;
|
|
18310
18660
|
if (features.includes("chat") || features.includes("files")) {
|
|
@@ -18576,6 +18926,7 @@ var DEFAULT_STUN, _authorize;
|
|
|
18576
18926
|
var init_realtime = __esm({
|
|
18577
18927
|
"../orm/src/realtime/realtime.ts"() {
|
|
18578
18928
|
"use strict";
|
|
18929
|
+
init_slashTrim();
|
|
18579
18930
|
init_index();
|
|
18580
18931
|
init_workspace();
|
|
18581
18932
|
init_channel();
|
|
@@ -18593,6 +18944,7 @@ var init_realtime2 = __esm({
|
|
|
18593
18944
|
"use strict";
|
|
18594
18945
|
init_realtime();
|
|
18595
18946
|
init_storage();
|
|
18947
|
+
init_s3Client();
|
|
18596
18948
|
init_workspace();
|
|
18597
18949
|
init_channel();
|
|
18598
18950
|
init_channelMember();
|
|
@@ -18958,6 +19310,7 @@ function mayStore(req2, vary, cacheControl, setCookie) {
|
|
|
18958
19310
|
if (requestHeader(req2, "authorization") !== void 0) return sharedCacheAllowed(cacheControl);
|
|
18959
19311
|
if (requestHeader(req2, "cookie") !== void 0) return sharedCacheAllowed(cacheControl);
|
|
18960
19312
|
if (hasSetCookie(setCookie)) return sharedCacheAllowed(cacheControl);
|
|
19313
|
+
if (req2.session?.isFresh && !req2.session.isFresh()) return sharedCacheAllowed(cacheControl);
|
|
18961
19314
|
return true;
|
|
18962
19315
|
}
|
|
18963
19316
|
function varyMatches(entry, req2) {
|
|
@@ -20310,7 +20663,7 @@ function coerceParam(raw, type2) {
|
|
|
20310
20663
|
}
|
|
20311
20664
|
function joinGroupPath(prefix, path10) {
|
|
20312
20665
|
const full = `${prefix}/${path10.replace(/^\/+/, "")}`;
|
|
20313
|
-
const trimmed = `/${full
|
|
20666
|
+
const trimmed = `/${trimSlashes(full)}`;
|
|
20314
20667
|
return trimmed.replace(/\/+/g, "/");
|
|
20315
20668
|
}
|
|
20316
20669
|
async function resolveStringMiddleware(spec) {
|
|
@@ -20375,6 +20728,7 @@ var WsRouteRef, RouteRef, Router, RouteGroup, TINA4_DEFAULT_ROUTER, globalRouter
|
|
|
20375
20728
|
var init_router = __esm({
|
|
20376
20729
|
"src/router.ts"() {
|
|
20377
20730
|
"use strict";
|
|
20731
|
+
init_slashTrim();
|
|
20378
20732
|
init_dotenv();
|
|
20379
20733
|
init_middleware();
|
|
20380
20734
|
WsRouteRef = class {
|
|
@@ -20584,7 +20938,7 @@ var init_router = __esm({
|
|
|
20584
20938
|
const direct = this.matchRoute(routes, path10);
|
|
20585
20939
|
if (direct) return direct;
|
|
20586
20940
|
if (isTrailingSlashRedirectEnabled() && path10.length > 1 && path10.endsWith("/")) {
|
|
20587
|
-
const stripped = path10
|
|
20941
|
+
const stripped = rtrimSlashes(path10);
|
|
20588
20942
|
if (stripped.length > 0) {
|
|
20589
20943
|
const retry = this.matchRoute(routes, stripped);
|
|
20590
20944
|
if (retry) return retry;
|
|
@@ -22260,7 +22614,8 @@ var init_middleware = __esm({
|
|
|
22260
22614
|
"Content-Security-Policy": resolveCspHeader(currentCspNonce()),
|
|
22261
22615
|
"Referrer-Policy": process.env.TINA4_REFERRER_POLICY ?? "strict-origin-when-cross-origin",
|
|
22262
22616
|
"X-XSS-Protection": "0",
|
|
22263
|
-
"Permissions-Policy": process.env.TINA4_PERMISSIONS_POLICY ?? "camera=(), microphone=(), geolocation=()"
|
|
22617
|
+
"Permissions-Policy": process.env.TINA4_PERMISSIONS_POLICY ?? "camera=(), microphone=(), geolocation=()",
|
|
22618
|
+
"Cross-Origin-Opener-Policy": process.env.TINA4_COOP ?? "same-origin-allow-popups"
|
|
22264
22619
|
};
|
|
22265
22620
|
}
|
|
22266
22621
|
static beforeSecurity(req2, res) {
|
|
@@ -22277,7 +22632,7 @@ var init_middleware = __esm({
|
|
|
22277
22632
|
if (process.env.TINA4_CSP === void 0) {
|
|
22278
22633
|
_SecurityHeadersMiddleware.warnCspDefaultOnce();
|
|
22279
22634
|
}
|
|
22280
|
-
for (const name of ["Content-Security-Policy", "Referrer-Policy", "X-XSS-Protection", "Permissions-Policy"]) {
|
|
22635
|
+
for (const name of ["Content-Security-Policy", "Referrer-Policy", "X-XSS-Protection", "Permissions-Policy", "Cross-Origin-Opener-Policy"]) {
|
|
22281
22636
|
res.header(name, canonical[name]);
|
|
22282
22637
|
}
|
|
22283
22638
|
return [req2, res];
|
|
@@ -22361,7 +22716,7 @@ var init_middleware = __esm({
|
|
|
22361
22716
|
});
|
|
22362
22717
|
|
|
22363
22718
|
// src/request.ts
|
|
22364
|
-
import { mkdirSync as mkdirSync7, realpathSync as realpathSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
22719
|
+
import { closeSync as closeSync3, constants as constants2, fstatSync as fstatSync2, ftruncateSync, lstatSync, mkdirSync as mkdirSync7, openSync as openSync3, realpathSync as realpathSync2, unlinkSync as unlinkSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
22365
22720
|
import { dirname as dirname6, join as join11 } from "node:path";
|
|
22366
22721
|
function makeCaseInsensitiveHeaders(raw) {
|
|
22367
22722
|
return new Proxy(raw, {
|
|
@@ -22397,7 +22752,8 @@ function createRequest(req2) {
|
|
|
22397
22752
|
try {
|
|
22398
22753
|
const url = new URL(req2.url ?? "/", `${proto}://${host}`);
|
|
22399
22754
|
for (const [key, value] of url.searchParams) {
|
|
22400
|
-
|
|
22755
|
+
if (isUnsafeFieldName(key)) continue;
|
|
22756
|
+
Reflect.set(query, key, value);
|
|
22401
22757
|
}
|
|
22402
22758
|
path10 = url.pathname;
|
|
22403
22759
|
queryString = url.search.replace(/^\?/, "");
|
|
@@ -22409,7 +22765,8 @@ function createRequest(req2) {
|
|
|
22409
22765
|
queryString = questionIdx >= 0 ? rawTarget.slice(questionIdx + 1) : "";
|
|
22410
22766
|
try {
|
|
22411
22767
|
for (const [key, value] of new URLSearchParams(queryString)) {
|
|
22412
|
-
|
|
22768
|
+
if (isUnsafeFieldName(key)) continue;
|
|
22769
|
+
Reflect.set(query, key, value);
|
|
22413
22770
|
}
|
|
22414
22771
|
} catch {
|
|
22415
22772
|
}
|
|
@@ -22428,7 +22785,8 @@ function createRequest(req2) {
|
|
|
22428
22785
|
if (cookieHeader) {
|
|
22429
22786
|
for (const pair of cookieHeader.split(";")) {
|
|
22430
22787
|
const [k, ...v] = pair.trim().split("=");
|
|
22431
|
-
|
|
22788
|
+
const name = k ? k.trim() : "";
|
|
22789
|
+
if (name && !isUnsafeFieldName(name)) Reflect.set(cookies, name, v.join("=").trim());
|
|
22432
22790
|
}
|
|
22433
22791
|
}
|
|
22434
22792
|
w.cookies = cookies;
|
|
@@ -22519,13 +22877,7 @@ async function parseBody(req2) {
|
|
|
22519
22877
|
req2.body = str;
|
|
22520
22878
|
}
|
|
22521
22879
|
} else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
22522
|
-
|
|
22523
|
-
const params = new URLSearchParams(str);
|
|
22524
|
-
const obj = {};
|
|
22525
|
-
for (const [key, value] of params) {
|
|
22526
|
-
obj[key] = value;
|
|
22527
|
-
}
|
|
22528
|
-
req2.body = obj;
|
|
22880
|
+
req2.body = nestFormFields([...new URLSearchParams(raw.toString("utf-8"))]);
|
|
22529
22881
|
} else {
|
|
22530
22882
|
req2.body = raw.toString("utf-8");
|
|
22531
22883
|
}
|
|
@@ -22535,7 +22887,7 @@ function extractBoundary(contentType) {
|
|
|
22535
22887
|
return match ? match[1] ?? match[2] : null;
|
|
22536
22888
|
}
|
|
22537
22889
|
function parseMultipart(body, boundary) {
|
|
22538
|
-
const
|
|
22890
|
+
const pairs = [];
|
|
22539
22891
|
const files = {};
|
|
22540
22892
|
const delimiter2 = Buffer.from(`--${boundary}`);
|
|
22541
22893
|
const closeDelimiter = Buffer.from(`--${boundary}--`);
|
|
@@ -22543,7 +22895,7 @@ function parseMultipart(body, boundary) {
|
|
|
22543
22895
|
const doubleCrlf = Buffer.from("\r\n\r\n");
|
|
22544
22896
|
let offset = 0;
|
|
22545
22897
|
const firstIdx = bufferIndexOf(body, delimiter2, offset);
|
|
22546
|
-
if (firstIdx === -1) return { fields, files };
|
|
22898
|
+
if (firstIdx === -1) return { fields: {}, files };
|
|
22547
22899
|
offset = firstIdx + delimiter2.length;
|
|
22548
22900
|
if (body[offset] === 13 && body[offset + 1] === 10) {
|
|
22549
22901
|
offset += 2;
|
|
@@ -22567,14 +22919,15 @@ function parseMultipart(body, boundary) {
|
|
|
22567
22919
|
content: Buffer.from(content),
|
|
22568
22920
|
size: content.length
|
|
22569
22921
|
};
|
|
22570
|
-
if (
|
|
22922
|
+
if (isUnsafeFieldName(disposition.name)) {
|
|
22923
|
+
} else if (files[disposition.name]) {
|
|
22571
22924
|
const existing = files[disposition.name];
|
|
22572
|
-
files
|
|
22925
|
+
Reflect.set(files, disposition.name, Array.isArray(existing) ? [...existing, file] : [existing, file]);
|
|
22573
22926
|
} else {
|
|
22574
|
-
files
|
|
22927
|
+
Reflect.set(files, disposition.name, file);
|
|
22575
22928
|
}
|
|
22576
22929
|
} else if (disposition.name) {
|
|
22577
|
-
|
|
22930
|
+
pairs.push([disposition.name, content.toString("utf-8")]);
|
|
22578
22931
|
}
|
|
22579
22932
|
offset = nextDelimIdx + delimiter2.length;
|
|
22580
22933
|
if (body[offset] === 45 && body[offset + 1] === 45) {
|
|
@@ -22584,7 +22937,7 @@ function parseMultipart(body, boundary) {
|
|
|
22584
22937
|
offset += 2;
|
|
22585
22938
|
}
|
|
22586
22939
|
}
|
|
22587
|
-
return { fields, files };
|
|
22940
|
+
return { fields: nestFormFields(pairs), files };
|
|
22588
22941
|
}
|
|
22589
22942
|
function saveUpload(file, targetDir, filename) {
|
|
22590
22943
|
const raw = String(filename ?? file.filename ?? "");
|
|
@@ -22600,7 +22953,21 @@ function saveUpload(file, targetDir, filename) {
|
|
|
22600
22953
|
if (realParent !== realDir) {
|
|
22601
22954
|
throw new Error(`refusing to write outside ${targetDir}: ${JSON.stringify(raw)}`);
|
|
22602
22955
|
}
|
|
22603
|
-
|
|
22956
|
+
if (lstatSync(dest, { throwIfNoEntry: false })?.isSymbolicLink()) unlinkSync4(dest);
|
|
22957
|
+
const flags = constants2.O_WRONLY | constants2.O_CREAT | (constants2.O_NOFOLLOW ?? 0);
|
|
22958
|
+
let fd = openSync3(dest, flags, 384);
|
|
22959
|
+
try {
|
|
22960
|
+
if (fstatSync2(fd).nlink > 1) {
|
|
22961
|
+
closeSync3(fd);
|
|
22962
|
+
fd = -1;
|
|
22963
|
+
unlinkSync4(dest);
|
|
22964
|
+
fd = openSync3(dest, flags | constants2.O_EXCL, 384);
|
|
22965
|
+
}
|
|
22966
|
+
ftruncateSync(fd, 0);
|
|
22967
|
+
writeFileSync4(fd, file.content);
|
|
22968
|
+
} finally {
|
|
22969
|
+
if (fd >= 0) closeSync3(fd);
|
|
22970
|
+
}
|
|
22604
22971
|
return dest;
|
|
22605
22972
|
}
|
|
22606
22973
|
function bufferIndexOf(haystack, needle, offset) {
|
|
@@ -22625,10 +22992,98 @@ function parseDisposition(headers) {
|
|
|
22625
22992
|
};
|
|
22626
22993
|
}
|
|
22627
22994
|
function parsePartContentType(headers) {
|
|
22628
|
-
const match = headers.match(/Content-Type
|
|
22629
|
-
|
|
22995
|
+
const match = headers.match(/Content-Type:([^\r\n]*)/i);
|
|
22996
|
+
const value = match?.[1]?.trim();
|
|
22997
|
+
return value ? value : null;
|
|
22998
|
+
}
|
|
22999
|
+
function nestFormFields(pairs) {
|
|
23000
|
+
const kept = pairs.filter(([name]) => !/(^|[[\]])__proto__([[\]]|$)/.test(name));
|
|
23001
|
+
if (kept.length > FORM_FIELD_LIMIT) return Object.fromEntries(kept);
|
|
23002
|
+
const nested = /* @__PURE__ */ new WeakSet();
|
|
23003
|
+
const node = () => {
|
|
23004
|
+
const created = /* @__PURE__ */ Object.create(null);
|
|
23005
|
+
nested.add(created);
|
|
23006
|
+
return created;
|
|
23007
|
+
};
|
|
23008
|
+
const isNode = (value) => typeof value === "object" && value !== null && nested.has(value);
|
|
23009
|
+
const own = (params, key) => Object.prototype.hasOwnProperty.call(params, key) ? params[key] : void 0;
|
|
23010
|
+
const list = (params, key) => {
|
|
23011
|
+
let current = own(params, key);
|
|
23012
|
+
if (current === void 0) {
|
|
23013
|
+
current = [];
|
|
23014
|
+
Reflect.set(params, key, current);
|
|
23015
|
+
}
|
|
23016
|
+
if (!Array.isArray(current)) throw new RangeError(`expected an array for '${key}'`);
|
|
23017
|
+
return current;
|
|
23018
|
+
};
|
|
23019
|
+
const object = (params, key) => {
|
|
23020
|
+
let current = own(params, key);
|
|
23021
|
+
if (current === void 0) {
|
|
23022
|
+
current = node();
|
|
23023
|
+
Reflect.set(params, key, current);
|
|
23024
|
+
}
|
|
23025
|
+
if (!isNode(current)) throw new RangeError(`expected an object for '${key}'`);
|
|
23026
|
+
return current;
|
|
23027
|
+
};
|
|
23028
|
+
const hasKey = (params, key) => {
|
|
23029
|
+
if (key.includes("[]")) return false;
|
|
23030
|
+
let level = params;
|
|
23031
|
+
for (const part of key.split(/[[\]]+/).filter(Boolean)) {
|
|
23032
|
+
if (!isNode(level) || own(level, part) === void 0) return false;
|
|
23033
|
+
level = level[part];
|
|
23034
|
+
}
|
|
23035
|
+
return true;
|
|
23036
|
+
};
|
|
23037
|
+
const splitName = (name, depth) => {
|
|
23038
|
+
if (depth === 0) {
|
|
23039
|
+
const start2 = name.indexOf("[", 1);
|
|
23040
|
+
return start2 === -1 ? [name, ""] : [name.slice(0, start2), name.slice(start2)];
|
|
23041
|
+
}
|
|
23042
|
+
if (name.startsWith("[]")) return ["[]", name.slice(2)];
|
|
23043
|
+
const close = name.indexOf("]", 1);
|
|
23044
|
+
return name.startsWith("[") && close !== -1 ? [name.slice(1, close), name.slice(close + 1)] : [name, ""];
|
|
23045
|
+
};
|
|
23046
|
+
const putListItem = (items, after, value, depth) => {
|
|
23047
|
+
let childKey = after[2] === "[" && after.endsWith("]") ? after.slice(3, -1) : "";
|
|
23048
|
+
if (childKey === "" || childKey.includes("[") || childKey.includes("]")) childKey = after.slice(2);
|
|
23049
|
+
const last = items[items.length - 1];
|
|
23050
|
+
if (isNode(last) && !hasKey(last, childKey)) put2(last, childKey, value, depth + 1);
|
|
23051
|
+
else items.push(put2(node(), childKey, value, depth + 1));
|
|
23052
|
+
};
|
|
23053
|
+
const put2 = (params, name, value, depth) => {
|
|
23054
|
+
const [key, after] = splitName(name, depth);
|
|
23055
|
+
if (key === "") return void 0;
|
|
23056
|
+
if (after === "" && key === "[]" && depth !== 0) return [value];
|
|
23057
|
+
if (after === "") Reflect.set(params, key, value);
|
|
23058
|
+
else if (after === "[") Reflect.set(params, name, value);
|
|
23059
|
+
else if (after === "[]") list(params, key).push(value);
|
|
23060
|
+
else if (after.startsWith("[]")) putListItem(list(params, key), after, value, depth);
|
|
23061
|
+
else put2(object(params, key), after, value, depth + 1);
|
|
23062
|
+
return params;
|
|
23063
|
+
};
|
|
23064
|
+
const tooDeep = (name) => {
|
|
23065
|
+
let count = 0;
|
|
23066
|
+
for (let at = name.indexOf("["); at !== -1; at = name.indexOf("[", at + 1)) {
|
|
23067
|
+
if (++count >= FORM_DEPTH_LIMIT) return true;
|
|
23068
|
+
}
|
|
23069
|
+
return false;
|
|
23070
|
+
};
|
|
23071
|
+
const fields = node();
|
|
23072
|
+
for (const [name, value] of kept) {
|
|
23073
|
+
if (name.length > FORM_NAME_LIMIT || tooDeep(name)) {
|
|
23074
|
+
Reflect.set(fields, name, value);
|
|
23075
|
+
continue;
|
|
23076
|
+
}
|
|
23077
|
+
try {
|
|
23078
|
+
put2(fields, name, value, 0);
|
|
23079
|
+
} catch (error2) {
|
|
23080
|
+
if (!(error2 instanceof RangeError)) throw error2;
|
|
23081
|
+
Reflect.set(fields, name, value);
|
|
23082
|
+
}
|
|
23083
|
+
}
|
|
23084
|
+
return fields;
|
|
22630
23085
|
}
|
|
22631
|
-
var DEFAULT_MAX_UPLOAD_SIZE, warnedLimits, PayloadTooLargeError;
|
|
23086
|
+
var DEFAULT_MAX_UPLOAD_SIZE, warnedLimits, PayloadTooLargeError, FORM_DEPTH_LIMIT, FORM_FIELD_LIMIT, FORM_NAME_LIMIT, isUnsafeFieldName;
|
|
22632
23087
|
var init_request = __esm({
|
|
22633
23088
|
"src/request.ts"() {
|
|
22634
23089
|
"use strict";
|
|
@@ -22643,6 +23098,10 @@ var init_request = __esm({
|
|
|
22643
23098
|
this.name = "PayloadTooLargeError";
|
|
22644
23099
|
}
|
|
22645
23100
|
};
|
|
23101
|
+
FORM_DEPTH_LIMIT = 32;
|
|
23102
|
+
FORM_FIELD_LIMIT = 4096;
|
|
23103
|
+
FORM_NAME_LIMIT = 1024;
|
|
23104
|
+
isUnsafeFieldName = (key) => key === "__proto__" || key === "constructor" || key === "prototype";
|
|
22646
23105
|
}
|
|
22647
23106
|
});
|
|
22648
23107
|
|
|
@@ -23149,7 +23608,7 @@ var init_routeDiscovery = __esm({
|
|
|
23149
23608
|
|
|
23150
23609
|
// src/portTakeover.ts
|
|
23151
23610
|
import { execFileSync } from "node:child_process";
|
|
23152
|
-
import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync9, unlinkSync as
|
|
23611
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync9, unlinkSync as unlinkSync5 } from "node:fs";
|
|
23153
23612
|
import { join as join13 } from "node:path";
|
|
23154
23613
|
function isTruthy3(value) {
|
|
23155
23614
|
return ["true", "1", "yes", "on"].includes(String(value ?? "").trim().toLowerCase());
|
|
@@ -23203,7 +23662,7 @@ function readPidfile(port, baseDir) {
|
|
|
23203
23662
|
}
|
|
23204
23663
|
function removePidfile(port, baseDir) {
|
|
23205
23664
|
try {
|
|
23206
|
-
|
|
23665
|
+
unlinkSync5(pidfilePath(port, baseDir));
|
|
23207
23666
|
} catch {
|
|
23208
23667
|
}
|
|
23209
23668
|
}
|
|
@@ -23304,21 +23763,6 @@ var init_portTakeover = __esm({
|
|
|
23304
23763
|
}
|
|
23305
23764
|
});
|
|
23306
23765
|
|
|
23307
|
-
// src/etag.ts
|
|
23308
|
-
function etagMatches(ifNoneMatch, etag) {
|
|
23309
|
-
const strip = (tag) => tag.trim().replace(/^W\//, "");
|
|
23310
|
-
const target = strip(etag);
|
|
23311
|
-
return ifNoneMatch.split(",").some((candidate) => {
|
|
23312
|
-
const trimmed = candidate.trim();
|
|
23313
|
-
return trimmed === "*" || strip(trimmed) === target;
|
|
23314
|
-
});
|
|
23315
|
-
}
|
|
23316
|
-
var init_etag = __esm({
|
|
23317
|
-
"src/etag.ts"() {
|
|
23318
|
-
"use strict";
|
|
23319
|
-
}
|
|
23320
|
-
});
|
|
23321
|
-
|
|
23322
23766
|
// src/sessionHandlers/syncBridge.ts
|
|
23323
23767
|
import { Worker } from "node:worker_threads";
|
|
23324
23768
|
function getBridge(key, workerSource, workerData) {
|
|
@@ -23678,7 +24122,7 @@ var init_valkeyHandler = __esm({
|
|
|
23678
24122
|
});
|
|
23679
24123
|
|
|
23680
24124
|
// src/sessionHandlers/memcachedHandler.ts
|
|
23681
|
-
import { createHash as
|
|
24125
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
23682
24126
|
var MAX_KEY_BYTES, MAX_RELATIVE_EXPTIME, MemcachedSessionHandler;
|
|
23683
24127
|
var init_memcachedHandler = __esm({
|
|
23684
24128
|
"src/sessionHandlers/memcachedHandler.ts"() {
|
|
@@ -23700,7 +24144,7 @@ var init_memcachedHandler = __esm({
|
|
|
23700
24144
|
key(sessionId) {
|
|
23701
24145
|
const candidate = `${this.prefix}${sessionId}`;
|
|
23702
24146
|
if (Buffer.byteLength(candidate) > MAX_KEY_BYTES || /[\x00-\x20\x7f]/.test(candidate)) {
|
|
23703
|
-
return `${this.prefix}${
|
|
24147
|
+
return `${this.prefix}${createHash6("sha256").update(sessionId).digest("hex")}`;
|
|
23704
24148
|
}
|
|
23705
24149
|
return candidate;
|
|
23706
24150
|
}
|
|
@@ -24166,7 +24610,7 @@ var init_mongoHandler = __esm({
|
|
|
24166
24610
|
});
|
|
24167
24611
|
|
|
24168
24612
|
// src/sessionHandlers/sqlClient.ts
|
|
24169
|
-
import { createRequire as
|
|
24613
|
+
import { createRequire as createRequire6 } from "node:module";
|
|
24170
24614
|
function driverPath(engine) {
|
|
24171
24615
|
const packageName = DRIVER_PACKAGE4[engine];
|
|
24172
24616
|
try {
|
|
@@ -24205,7 +24649,7 @@ var init_sqlClient = __esm({
|
|
|
24205
24649
|
mssql: "tedious",
|
|
24206
24650
|
firebird: "node-firebird"
|
|
24207
24651
|
};
|
|
24208
|
-
requireFromHere =
|
|
24652
|
+
requireFromHere = createRequire6(import.meta.url);
|
|
24209
24653
|
SQL_WORKER = `
|
|
24210
24654
|
const target = workerData.target;
|
|
24211
24655
|
const engine = target.engine;
|
|
@@ -24687,14 +25131,18 @@ __export(session_exports, {
|
|
|
24687
25131
|
Session: () => Session,
|
|
24688
25132
|
VALID_SESSION_BACKENDS: () => VALID_SESSION_BACKENDS,
|
|
24689
25133
|
buildSessionCookie: () => buildSessionCookie,
|
|
25134
|
+
currentFormTokenSessionId: () => currentFormTokenSessionId,
|
|
24690
25135
|
isSecureScheme: () => isSecureScheme,
|
|
24691
25136
|
isValidSessionId: () => isValidSessionId,
|
|
25137
|
+
runWithFormTokenSession: () => runWithFormTokenSession,
|
|
24692
25138
|
sessionCookieName: () => sessionCookieName,
|
|
24693
25139
|
sessionCookieToSend: () => sessionCookieToSend,
|
|
24694
|
-
sessionStrictMode: () => sessionStrictMode
|
|
25140
|
+
sessionStrictMode: () => sessionStrictMode,
|
|
25141
|
+
setFormTokenSession: () => setFormTokenSession
|
|
24695
25142
|
});
|
|
24696
|
-
import {
|
|
24697
|
-
import {
|
|
25143
|
+
import { AsyncLocalStorage as AsyncLocalStorage4 } from "node:async_hooks";
|
|
25144
|
+
import { createHash as createHash7, randomBytes as randomBytes6 } from "node:crypto";
|
|
25145
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync7, unlinkSync as unlinkSync6, readdirSync as readdirSync6 } from "node:fs";
|
|
24698
25146
|
import { join as join14 } from "node:path";
|
|
24699
25147
|
function isValidSessionId(sessionId) {
|
|
24700
25148
|
return typeof sessionId === "string" && SESSION_ID_PATTERN.test(sessionId);
|
|
@@ -24760,7 +25208,21 @@ function sessionCookieToSend(sess, existingSid, rawReq, rawRes) {
|
|
|
24760
25208
|
const socketEncrypted = rawReq.socket?.encrypted === true;
|
|
24761
25209
|
return buildSessionCookie(newSid, ttl, void 0, forwardedProto, socketEncrypted);
|
|
24762
25210
|
}
|
|
24763
|
-
|
|
25211
|
+
function runWithFormTokenSession(fn) {
|
|
25212
|
+
return sessionStore.run({ session: null }, fn);
|
|
25213
|
+
}
|
|
25214
|
+
function setFormTokenSession(session) {
|
|
25215
|
+
const store = sessionStore.getStore();
|
|
25216
|
+
if (store) store.session = session;
|
|
25217
|
+
}
|
|
25218
|
+
function currentFormTokenSessionId() {
|
|
25219
|
+
const session = sessionStore.getStore()?.session;
|
|
25220
|
+
const sid = session?.getSessionId();
|
|
25221
|
+
if (!session || !sid) return "";
|
|
25222
|
+
if (session.isFresh()) session.set("_tina4_csrf", true);
|
|
25223
|
+
return sid;
|
|
25224
|
+
}
|
|
25225
|
+
var SESSION_ID_PATTERN, VALID_SESSION_BACKENDS, CANONICAL_SESSION_BACKENDS, RETIRED_SESSION_BACKENDS, FileSessionHandler, RedisSessionHandler, FLASH_PREFIX, Session, sessionStore;
|
|
24764
25226
|
var init_session = __esm({
|
|
24765
25227
|
"src/session.ts"() {
|
|
24766
25228
|
"use strict";
|
|
@@ -24834,7 +25296,7 @@ var init_session = __esm({
|
|
|
24834
25296
|
`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.`
|
|
24835
25297
|
);
|
|
24836
25298
|
}
|
|
24837
|
-
return join14(this.storagePath, `${
|
|
25299
|
+
return join14(this.storagePath, `${createHash7("sha256").update(id).digest("hex")}.json`);
|
|
24838
25300
|
}
|
|
24839
25301
|
read(sessionId) {
|
|
24840
25302
|
const filePath = this.filePath(sessionId);
|
|
@@ -24844,7 +25306,7 @@ var init_session = __esm({
|
|
|
24844
25306
|
const wrapper = JSON.parse(raw);
|
|
24845
25307
|
if (wrapper._expires && wrapper._expires > 0 && Date.now() / 1e3 > wrapper._expires) {
|
|
24846
25308
|
try {
|
|
24847
|
-
|
|
25309
|
+
unlinkSync6(filePath);
|
|
24848
25310
|
} catch {
|
|
24849
25311
|
}
|
|
24850
25312
|
return null;
|
|
@@ -24863,7 +25325,7 @@ var init_session = __esm({
|
|
|
24863
25325
|
destroy(sessionId) {
|
|
24864
25326
|
const filePath = this.filePath(sessionId);
|
|
24865
25327
|
try {
|
|
24866
|
-
if (existsSync11(filePath))
|
|
25328
|
+
if (existsSync11(filePath)) unlinkSync6(filePath);
|
|
24867
25329
|
} catch {
|
|
24868
25330
|
}
|
|
24869
25331
|
}
|
|
@@ -24879,11 +25341,11 @@ var init_session = __esm({
|
|
|
24879
25341
|
const raw = readFileSync8(fullPath, "utf-8");
|
|
24880
25342
|
const wrapper = JSON.parse(raw);
|
|
24881
25343
|
if (wrapper._expires && wrapper._expires > 0 && now > wrapper._expires) {
|
|
24882
|
-
|
|
25344
|
+
unlinkSync6(fullPath);
|
|
24883
25345
|
}
|
|
24884
25346
|
} catch {
|
|
24885
25347
|
try {
|
|
24886
|
-
|
|
25348
|
+
unlinkSync6(fullPath);
|
|
24887
25349
|
} catch {
|
|
24888
25350
|
}
|
|
24889
25351
|
}
|
|
@@ -25403,12 +25865,28 @@ var init_session = __esm({
|
|
|
25403
25865
|
this.loaded = /* @__PURE__ */ new Map();
|
|
25404
25866
|
}
|
|
25405
25867
|
};
|
|
25868
|
+
sessionStore = new AsyncLocalStorage4();
|
|
25869
|
+
}
|
|
25870
|
+
});
|
|
25871
|
+
|
|
25872
|
+
// src/etag.ts
|
|
25873
|
+
function etagMatches(ifNoneMatch, etag) {
|
|
25874
|
+
const strip = (tag) => tag.trim().replace(/^W\//, "");
|
|
25875
|
+
const target = strip(etag);
|
|
25876
|
+
return ifNoneMatch.split(",").some((candidate) => {
|
|
25877
|
+
const trimmed = candidate.trim();
|
|
25878
|
+
return trimmed === "*" || strip(trimmed) === target;
|
|
25879
|
+
});
|
|
25880
|
+
}
|
|
25881
|
+
var init_etag = __esm({
|
|
25882
|
+
"src/etag.ts"() {
|
|
25883
|
+
"use strict";
|
|
25406
25884
|
}
|
|
25407
25885
|
});
|
|
25408
25886
|
|
|
25409
25887
|
// src/dispatchPipeline.ts
|
|
25410
25888
|
import { gzipSync } from "node:zlib";
|
|
25411
|
-
import { createHash as
|
|
25889
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
25412
25890
|
async function resetRequestCaches2() {
|
|
25413
25891
|
if (_resetRequestCaches === void 0) {
|
|
25414
25892
|
_resetRequestCaches = Promise.resolve().then(() => (init_src(), src_exports)).then((orm) => orm.resetRequestCaches).catch(() => null);
|
|
@@ -25481,7 +25959,7 @@ function applyResponseValidator(rawReq, rawRes, body) {
|
|
|
25481
25959
|
if ((rawRes.statusCode || 200) !== 200 || body.length === 0) return false;
|
|
25482
25960
|
let etag = rawRes.getHeader("etag");
|
|
25483
25961
|
if (!etag) {
|
|
25484
|
-
etag = `"${
|
|
25962
|
+
etag = `"${createHash8("md5").update(body).digest("hex").slice(0, 16)}"`;
|
|
25485
25963
|
rawRes.setHeader("ETag", etag);
|
|
25486
25964
|
}
|
|
25487
25965
|
if (!responseIsNotModified(rawReq, rawRes, String(etag))) return false;
|
|
@@ -25556,6 +26034,7 @@ async function sessionAutoStart(rawReq, rawRes, req2) {
|
|
|
25556
26034
|
return;
|
|
25557
26035
|
}
|
|
25558
26036
|
req2.session = sess;
|
|
26037
|
+
setFormTokenSession(sess);
|
|
25559
26038
|
const origEnd = rawRes.end.bind(rawRes);
|
|
25560
26039
|
let finalised = false;
|
|
25561
26040
|
rawRes.end = function(...args) {
|
|
@@ -25584,6 +26063,7 @@ var _resetRequestCaches, COMPRESSIBLE_PREFIXES;
|
|
|
25584
26063
|
var init_dispatchPipeline = __esm({
|
|
25585
26064
|
"src/dispatchPipeline.ts"() {
|
|
25586
26065
|
"use strict";
|
|
26066
|
+
init_session();
|
|
25587
26067
|
init_logger();
|
|
25588
26068
|
init_etag();
|
|
25589
26069
|
COMPRESSIBLE_PREFIXES = [
|
|
@@ -25733,14 +26213,21 @@ function parseStack(stack) {
|
|
|
25733
26213
|
const frames = [];
|
|
25734
26214
|
const lines = stack.split("\n");
|
|
25735
26215
|
for (const line of lines) {
|
|
25736
|
-
|
|
25737
|
-
if (
|
|
25738
|
-
|
|
25739
|
-
|
|
26216
|
+
const t = line.trim();
|
|
26217
|
+
if (!t.startsWith("at ")) continue;
|
|
26218
|
+
const rest = t.slice(3);
|
|
26219
|
+
let func = "{anonymous}";
|
|
26220
|
+
let loc = rest;
|
|
26221
|
+
if (rest.endsWith(")")) {
|
|
26222
|
+
const open = rest.lastIndexOf(" (");
|
|
26223
|
+
if (open >= 0) {
|
|
26224
|
+
func = rest.slice(0, open);
|
|
26225
|
+
loc = rest.slice(open + 2, -1);
|
|
26226
|
+
}
|
|
25740
26227
|
}
|
|
25741
|
-
|
|
25742
|
-
if (
|
|
25743
|
-
frames.push({ func
|
|
26228
|
+
const lc = loc.match(/:(\d+):(\d+)$/);
|
|
26229
|
+
if (lc && lc.index !== void 0) {
|
|
26230
|
+
frames.push({ func, file: loc.slice(0, lc.index), line: parseInt(lc[1], 10), column: parseInt(lc[2], 10) });
|
|
25744
26231
|
}
|
|
25745
26232
|
}
|
|
25746
26233
|
return frames;
|
|
@@ -26065,7 +26552,7 @@ var init_rateLimiter = __esm({
|
|
|
26065
26552
|
});
|
|
26066
26553
|
|
|
26067
26554
|
// src/devMailbox.ts
|
|
26068
|
-
import { mkdirSync as mkdirSync11, readdirSync as readdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync8, unlinkSync as
|
|
26555
|
+
import { mkdirSync as mkdirSync11, readdirSync as readdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync8, unlinkSync as unlinkSync7, existsSync as existsSync12 } from "node:fs";
|
|
26069
26556
|
import { join as join16 } from "node:path";
|
|
26070
26557
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
26071
26558
|
var DevMailbox;
|
|
@@ -26197,7 +26684,7 @@ var init_devMailbox = __esm({
|
|
|
26197
26684
|
const filePath = join16(this.mailboxDir, folder, `${msgId}.json`);
|
|
26198
26685
|
if (existsSync12(filePath)) {
|
|
26199
26686
|
try {
|
|
26200
|
-
|
|
26687
|
+
unlinkSync7(filePath);
|
|
26201
26688
|
deleted = true;
|
|
26202
26689
|
} catch {
|
|
26203
26690
|
}
|
|
@@ -26216,7 +26703,7 @@ var init_devMailbox = __esm({
|
|
|
26216
26703
|
if (existsSync12(dir)) {
|
|
26217
26704
|
const files = readdirSync7(dir).filter((file) => file.endsWith(".json"));
|
|
26218
26705
|
for (const file of files) {
|
|
26219
|
-
|
|
26706
|
+
unlinkSync7(join16(dir, file));
|
|
26220
26707
|
}
|
|
26221
26708
|
}
|
|
26222
26709
|
} catch {
|
|
@@ -26360,7 +26847,7 @@ function enginePath() {
|
|
|
26360
26847
|
function runEngine(target) {
|
|
26361
26848
|
const binary = enginePath();
|
|
26362
26849
|
if (!binary) throw new MetricsEngineError(`tina4 not found on PATH - ${INSTALL_HINT}`);
|
|
26363
|
-
const processResult = spawnSync(binary, ["metrics", "--path", target, "--json"], {
|
|
26850
|
+
const processResult = spawnSync(binary, ["metrics", "--path", target, "--json", "--no-history"], {
|
|
26364
26851
|
encoding: "utf8",
|
|
26365
26852
|
timeout: 6e4,
|
|
26366
26853
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -28862,7 +29349,7 @@ import * as fs4 from "node:fs";
|
|
|
28862
29349
|
import * as path3 from "node:path";
|
|
28863
29350
|
import * as os from "node:os";
|
|
28864
29351
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
28865
|
-
import { createRequire as
|
|
29352
|
+
import { createRequire as createRequire7 } from "node:module";
|
|
28866
29353
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
28867
29354
|
function reqSibling(pkg) {
|
|
28868
29355
|
return req(`../../${pkg}/src/index.ts`);
|
|
@@ -29021,21 +29508,45 @@ function safePath(projectRoot3, relPath) {
|
|
|
29021
29508
|
if (resolved !== projectRoot3 && !resolved.startsWith(rootPrefix)) {
|
|
29022
29509
|
throw new Error(`Path escapes project directory: ${relPath}`);
|
|
29023
29510
|
}
|
|
29024
|
-
let
|
|
29511
|
+
let realRoot;
|
|
29025
29512
|
try {
|
|
29026
|
-
|
|
29513
|
+
realRoot = fs4.realpathSync(projectRoot3);
|
|
29027
29514
|
} catch {
|
|
29028
|
-
|
|
29515
|
+
return resolved;
|
|
29029
29516
|
}
|
|
29030
|
-
|
|
29031
|
-
|
|
29032
|
-
|
|
29033
|
-
|
|
29034
|
-
throw new Error(`Path escapes project directory: ${relPath}`);
|
|
29035
|
-
}
|
|
29517
|
+
const real = realPathOf(resolved);
|
|
29518
|
+
const realPrefix = realRoot.endsWith(path3.sep) ? realRoot : realRoot + path3.sep;
|
|
29519
|
+
if (real === null || real !== realRoot && !real.startsWith(realPrefix)) {
|
|
29520
|
+
throw new Error(`Path escapes project directory: ${relPath}`);
|
|
29036
29521
|
}
|
|
29037
29522
|
return resolved;
|
|
29038
29523
|
}
|
|
29524
|
+
function realPathOf(p, hops = 0) {
|
|
29525
|
+
let probe = p;
|
|
29526
|
+
while (!fs4.existsSync(probe) && !isSymlink(probe) && path3.dirname(probe) !== probe) {
|
|
29527
|
+
probe = path3.dirname(probe);
|
|
29528
|
+
}
|
|
29529
|
+
try {
|
|
29530
|
+
return fs4.realpathSync.native(probe);
|
|
29531
|
+
} catch {
|
|
29532
|
+
if (hops >= 40) return null;
|
|
29533
|
+
let target;
|
|
29534
|
+
try {
|
|
29535
|
+
target = fs4.readlinkSync(probe);
|
|
29536
|
+
} catch {
|
|
29537
|
+
return null;
|
|
29538
|
+
}
|
|
29539
|
+
const base = path3.isAbsolute(target) ? target : path3.dirname(probe) + path3.sep + target;
|
|
29540
|
+
return realPathOf(base + p.slice(probe.length), hops + 1);
|
|
29541
|
+
}
|
|
29542
|
+
}
|
|
29543
|
+
function isSymlink(p) {
|
|
29544
|
+
try {
|
|
29545
|
+
return fs4.lstatSync(p).isSymbolicLink();
|
|
29546
|
+
} catch {
|
|
29547
|
+
return false;
|
|
29548
|
+
}
|
|
29549
|
+
}
|
|
29039
29550
|
function redactEnv(key, value) {
|
|
29040
29551
|
const sensitive = ["secret", "password", "token", "key", "credential", "api_key"];
|
|
29041
29552
|
if (sensitive.some((s) => key.toLowerCase().includes(s))) {
|
|
@@ -29880,8 +30391,10 @@ function registerDevTools(server) {
|
|
|
29880
30391
|
return { error: `Invalid path ${JSON.stringify(rel)}: ${proseErr}` };
|
|
29881
30392
|
}
|
|
29882
30393
|
rel = normalizeCoderPath(projectRoot4, rel);
|
|
29883
|
-
|
|
29884
|
-
|
|
30394
|
+
let resolved;
|
|
30395
|
+
try {
|
|
30396
|
+
resolved = safePath(projectRoot4, rel);
|
|
30397
|
+
} catch {
|
|
29885
30398
|
return { error: `Path escapes project directory: ${rel}` };
|
|
29886
30399
|
}
|
|
29887
30400
|
if (!fs4.existsSync(resolved) || !fs4.statSync(resolved).isFile()) {
|
|
@@ -30178,8 +30691,9 @@ var req, PARSE_ERROR, INVALID_REQUEST, METHOD_NOT_FOUND, INVALID_PARAMS, INTERNA
|
|
|
30178
30691
|
var init_mcp = __esm({
|
|
30179
30692
|
"src/mcp.ts"() {
|
|
30180
30693
|
"use strict";
|
|
30694
|
+
init_slashTrim();
|
|
30181
30695
|
init_version();
|
|
30182
|
-
req =
|
|
30696
|
+
req = createRequire7(import.meta.url);
|
|
30183
30697
|
PARSE_ERROR = -32700;
|
|
30184
30698
|
INVALID_REQUEST = -32600;
|
|
30185
30699
|
METHOD_NOT_FOUND = -32601;
|
|
@@ -30204,7 +30718,7 @@ var init_mcp = __esm({
|
|
|
30204
30718
|
// threaded, so this in-process map is the whole coordination mechanism.
|
|
30205
30719
|
_sseChannels = /* @__PURE__ */ new Map();
|
|
30206
30720
|
constructor(mcpPath, name = "Tina4 MCP", version = "1.0.0") {
|
|
30207
|
-
this.path = mcpPath
|
|
30721
|
+
this.path = rtrimSlashes(mcpPath);
|
|
30208
30722
|
this.name = name;
|
|
30209
30723
|
this.version = version;
|
|
30210
30724
|
_McpServer._instances.push(this);
|
|
@@ -32287,7 +32801,7 @@ __export(websocket_exports, {
|
|
|
32287
32801
|
wsToken: () => wsToken
|
|
32288
32802
|
});
|
|
32289
32803
|
import { createServer as createServer2 } from "node:http";
|
|
32290
|
-
import { createHash as
|
|
32804
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
32291
32805
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
32292
32806
|
function buildCloseFrame(code, reason = "") {
|
|
32293
32807
|
const reasonBytes = Buffer.from(reason, "utf-8");
|
|
@@ -32297,7 +32811,7 @@ function buildCloseFrame(code, reason = "") {
|
|
|
32297
32811
|
return buildFrame(OP_CLOSE, payload);
|
|
32298
32812
|
}
|
|
32299
32813
|
function computeAcceptKey(key) {
|
|
32300
|
-
return
|
|
32814
|
+
return createHash9("sha1").update(key + MAGIC_STRING).digest("base64");
|
|
32301
32815
|
}
|
|
32302
32816
|
function originAllowed(headers) {
|
|
32303
32817
|
const raw = (process.env.TINA4_WS_ALLOWED_ORIGINS ?? "").trim();
|
|
@@ -33988,7 +34502,7 @@ var init_job = __esm({
|
|
|
33988
34502
|
});
|
|
33989
34503
|
|
|
33990
34504
|
// src/queueBackends/liteBackend.ts
|
|
33991
|
-
import { mkdirSync as mkdirSync15, readdirSync as readdirSync12, readFileSync as readFileSync16, writeFileSync as writeFileSync11, unlinkSync as
|
|
34505
|
+
import { mkdirSync as mkdirSync15, readdirSync as readdirSync12, readFileSync as readFileSync16, writeFileSync as writeFileSync11, unlinkSync as unlinkSync8, existsSync as existsSync19 } from "node:fs";
|
|
33992
34506
|
import { join as join23 } from "node:path";
|
|
33993
34507
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
33994
34508
|
var LiteBackend;
|
|
@@ -34158,7 +34672,7 @@ var init_liteBackend = __esm({
|
|
|
34158
34672
|
}
|
|
34159
34673
|
if (record.availableAt && record.availableAt > now) continue;
|
|
34160
34674
|
try {
|
|
34161
|
-
|
|
34675
|
+
unlinkSync8(filePath);
|
|
34162
34676
|
} catch {
|
|
34163
34677
|
continue;
|
|
34164
34678
|
}
|
|
@@ -34192,10 +34706,10 @@ var init_liteBackend = __esm({
|
|
|
34192
34706
|
job.priority = job.priority ?? 0;
|
|
34193
34707
|
this.writeReserved(queue, job);
|
|
34194
34708
|
try {
|
|
34195
|
-
|
|
34709
|
+
unlinkSync8(filePath);
|
|
34196
34710
|
} catch {
|
|
34197
34711
|
try {
|
|
34198
|
-
|
|
34712
|
+
unlinkSync8(this.reservedPath(queue, job.id));
|
|
34199
34713
|
} catch {
|
|
34200
34714
|
}
|
|
34201
34715
|
continue;
|
|
@@ -34217,10 +34731,10 @@ var init_liteBackend = __esm({
|
|
|
34217
34731
|
job.priority = job.priority ?? 0;
|
|
34218
34732
|
this.writeReserved(queue, job);
|
|
34219
34733
|
try {
|
|
34220
|
-
|
|
34734
|
+
unlinkSync8(filePath);
|
|
34221
34735
|
} catch {
|
|
34222
34736
|
try {
|
|
34223
|
-
|
|
34737
|
+
unlinkSync8(this.reservedPath(queue, job.id));
|
|
34224
34738
|
} catch {
|
|
34225
34739
|
}
|
|
34226
34740
|
continue;
|
|
@@ -34235,7 +34749,7 @@ var init_liteBackend = __esm({
|
|
|
34235
34749
|
*/
|
|
34236
34750
|
clearReservation(queue, jobId) {
|
|
34237
34751
|
try {
|
|
34238
|
-
|
|
34752
|
+
unlinkSync8(this.reservedPath(queue, jobId));
|
|
34239
34753
|
} catch {
|
|
34240
34754
|
}
|
|
34241
34755
|
}
|
|
@@ -34278,7 +34792,7 @@ var init_liteBackend = __esm({
|
|
|
34278
34792
|
try {
|
|
34279
34793
|
const files = readdirSync12(dir).filter((f) => f.endsWith(".queue-data"));
|
|
34280
34794
|
for (const file of files) {
|
|
34281
|
-
|
|
34795
|
+
unlinkSync8(join23(dir, file));
|
|
34282
34796
|
count++;
|
|
34283
34797
|
}
|
|
34284
34798
|
} catch {
|
|
@@ -34288,7 +34802,7 @@ var init_liteBackend = __esm({
|
|
|
34288
34802
|
if (existsSync19(failedDir)) {
|
|
34289
34803
|
const files = readdirSync12(failedDir).filter((f) => f.endsWith(".queue-data"));
|
|
34290
34804
|
for (const file of files) {
|
|
34291
|
-
|
|
34805
|
+
unlinkSync8(join23(failedDir, file));
|
|
34292
34806
|
count++;
|
|
34293
34807
|
}
|
|
34294
34808
|
}
|
|
@@ -34299,7 +34813,7 @@ var init_liteBackend = __esm({
|
|
|
34299
34813
|
if (existsSync19(reservedDir)) {
|
|
34300
34814
|
const files = readdirSync12(reservedDir).filter((f) => f.endsWith(".queue-data"));
|
|
34301
34815
|
for (const file of files) {
|
|
34302
|
-
|
|
34816
|
+
unlinkSync8(join23(reservedDir, file));
|
|
34303
34817
|
count++;
|
|
34304
34818
|
}
|
|
34305
34819
|
}
|
|
@@ -34357,7 +34871,7 @@ var init_liteBackend = __esm({
|
|
|
34357
34871
|
const prefix = this.nextPrefix();
|
|
34358
34872
|
const queueDir = join23(this.basePath, q);
|
|
34359
34873
|
writeFileSync11(join23(queueDir, `${prefix}_${jobId}.queue-data`), JSON.stringify(job, null, 2));
|
|
34360
|
-
|
|
34874
|
+
unlinkSync8(filePath);
|
|
34361
34875
|
return true;
|
|
34362
34876
|
}
|
|
34363
34877
|
}
|
|
@@ -34393,7 +34907,7 @@ var init_liteBackend = __esm({
|
|
|
34393
34907
|
const files = readdirSync12(failedDir).filter((f) => f.endsWith(".queue-data"));
|
|
34394
34908
|
for (const file of files) {
|
|
34395
34909
|
try {
|
|
34396
|
-
|
|
34910
|
+
unlinkSync8(join23(failedDir, file));
|
|
34397
34911
|
count++;
|
|
34398
34912
|
} catch {
|
|
34399
34913
|
}
|
|
@@ -34408,7 +34922,7 @@ var init_liteBackend = __esm({
|
|
|
34408
34922
|
try {
|
|
34409
34923
|
const job = JSON.parse(readFileSync16(join23(dir, file), "utf-8"));
|
|
34410
34924
|
if (job.status === status2) {
|
|
34411
|
-
|
|
34925
|
+
unlinkSync8(join23(dir, file));
|
|
34412
34926
|
count++;
|
|
34413
34927
|
}
|
|
34414
34928
|
} catch {
|
|
@@ -34443,7 +34957,7 @@ var init_liteBackend = __esm({
|
|
|
34443
34957
|
job.delayUntil = null;
|
|
34444
34958
|
const prefix = this.nextPrefix();
|
|
34445
34959
|
writeFileSync11(join23(queueDir, `${prefix}_${job.id}.queue-data`), JSON.stringify(job, null, 2));
|
|
34446
|
-
|
|
34960
|
+
unlinkSync8(filePath);
|
|
34447
34961
|
count++;
|
|
34448
34962
|
} catch {
|
|
34449
34963
|
}
|
|
@@ -34475,10 +34989,10 @@ var init_liteBackend = __esm({
|
|
|
34475
34989
|
job.priority = job.priority ?? 0;
|
|
34476
34990
|
this.writeReserved(queue, job);
|
|
34477
34991
|
try {
|
|
34478
|
-
|
|
34992
|
+
unlinkSync8(filePath);
|
|
34479
34993
|
} catch {
|
|
34480
34994
|
try {
|
|
34481
|
-
|
|
34995
|
+
unlinkSync8(this.reservedPath(queue, job.id));
|
|
34482
34996
|
} catch {
|
|
34483
34997
|
}
|
|
34484
34998
|
continue;
|
|
@@ -34580,7 +35094,7 @@ var init_liteBackend = __esm({
|
|
|
34580
35094
|
retryJob(queue, job, delaySeconds) {
|
|
34581
35095
|
this.clearReservation(queue, job.id);
|
|
34582
35096
|
try {
|
|
34583
|
-
|
|
35097
|
+
unlinkSync8(join23(this.ensureFailedDir(queue), `${job.id}.queue-data`));
|
|
34584
35098
|
} catch {
|
|
34585
35099
|
}
|
|
34586
35100
|
job.attempts = (job.attempts || 0) + 1;
|
|
@@ -35130,7 +35644,8 @@ function archiveDir() {
|
|
|
35130
35644
|
return p;
|
|
35131
35645
|
}
|
|
35132
35646
|
function slugify(title) {
|
|
35133
|
-
const
|
|
35647
|
+
const dashed = (title || "").trim().toLowerCase().replace(/[^A-Za-z0-9_-]+/g, "-");
|
|
35648
|
+
const slug = trimChar(dashed, 45);
|
|
35134
35649
|
return slug.slice(0, 80) || `plan-${Math.floor(Date.now() / 1e3)}`;
|
|
35135
35650
|
}
|
|
35136
35651
|
function parse(text) {
|
|
@@ -35267,6 +35782,7 @@ var PLAN_DIR, CURRENT_FILE, ARCHIVE_SUBDIR, STEP_RE, Plan;
|
|
|
35267
35782
|
var init_plan = __esm({
|
|
35268
35783
|
"src/plan.ts"() {
|
|
35269
35784
|
"use strict";
|
|
35785
|
+
init_slashTrim();
|
|
35270
35786
|
PLAN_DIR = "plan";
|
|
35271
35787
|
CURRENT_FILE = ".current";
|
|
35272
35788
|
ARCHIVE_SUBDIR = "done";
|
|
@@ -35538,7 +36054,7 @@ var init_plan = __esm({
|
|
|
35538
36054
|
const existing = (currentPlan.steps || []).map((s) => s.text || "");
|
|
35539
36055
|
const title = currentPlan.title || target;
|
|
35540
36056
|
const goal = currentPlan.goal || "";
|
|
35541
|
-
const aiUrl = process.env.TINA4_AI_URL || "http://localhost:
|
|
36057
|
+
const aiUrl = process.env.TINA4_AI_URL || "http://localhost:11435/api/chat";
|
|
35542
36058
|
const aiModel = process.env.TINA4_AI_MODEL || "qwen2.5-coder:14b";
|
|
35543
36059
|
const prompts = fleshPrompt(title, goal, existing, prompt);
|
|
35544
36060
|
const fetched = await fetchFleshReply(aiUrl, aiModel, prompts);
|
|
@@ -36506,7 +37022,7 @@ function relativePath(absPath, projectRoot3, frameworkRoots) {
|
|
|
36506
37022
|
}
|
|
36507
37023
|
function tokenise(text) {
|
|
36508
37024
|
if (!text) return [];
|
|
36509
|
-
const expanded = text.replace(
|
|
37025
|
+
const expanded = text.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z])(?=[A-Z][a-z])/g, "$1 ").toLowerCase();
|
|
36510
37026
|
return expanded.split(/[\s_\-./:,;()\[\]{}\\]+/).filter((p) => p.length > 0);
|
|
36511
37027
|
}
|
|
36512
37028
|
function summariseDoc(doc) {
|
|
@@ -36737,7 +37253,7 @@ function returnFromSignature(signature) {
|
|
|
36737
37253
|
const rest = signature.slice(close + 1).trim();
|
|
36738
37254
|
return rest.startsWith(":") ? rest.slice(1).trim() : "";
|
|
36739
37255
|
}
|
|
36740
|
-
var STDLIB_ALLOWLIST, _DOCS_CACHE, __FILENAME, __DIRNAME, USER_DIRS,
|
|
37256
|
+
var STDLIB_ALLOWLIST, _DOCS_CACHE, __FILENAME, __DIRNAME, USER_DIRS, FENCE_RE, CALL_RE, sharedFrameworkIndex, Docs;
|
|
36741
37257
|
var init_docs = __esm({
|
|
36742
37258
|
"src/docs.ts"() {
|
|
36743
37259
|
"use strict";
|
|
@@ -36876,7 +37392,6 @@ var init_docs = __esm({
|
|
|
36876
37392
|
__FILENAME = fileURLToPath6(import.meta.url);
|
|
36877
37393
|
__DIRNAME = path8.dirname(__FILENAME);
|
|
36878
37394
|
USER_DIRS = ["src/orm", "src/routes", "src/app", "src/services", "src/models"];
|
|
36879
|
-
CAMEL_SPLIT = /([a-z0-9])([A-Z])|([A-Z]+)([A-Z][a-z])/g;
|
|
36880
37395
|
FENCE_RE = new RegExp(
|
|
36881
37396
|
String.fromCharCode(96, 96, 96) + "[a-zA-Z0-9_+-]*\\n([\\s\\S]*?)\\n" + String.fromCharCode(96, 96, 96),
|
|
36882
37397
|
"g"
|
|
@@ -37250,7 +37765,7 @@ ${end}
|
|
|
37250
37765
|
|
|
37251
37766
|
// src/devAdmin.ts
|
|
37252
37767
|
import { cpus as osCpus } from "node:os";
|
|
37253
|
-
import { readFileSync as readFileSync20, writeFileSync as writeFileSync15, existsSync as existsSync23, readdirSync as readdirSync16, mkdirSync as mkdirSync18, copyFileSync as copyFileSync2, statSync as statSync17, openSync as
|
|
37768
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync15, existsSync as existsSync23, readdirSync as readdirSync16, mkdirSync as mkdirSync18, copyFileSync as copyFileSync2, statSync as statSync17, 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";
|
|
37254
37769
|
import { join as join27, dirname as dirname14, resolve as resolve16, relative as relative9, sep as sep8, basename as basename5 } from "node:path";
|
|
37255
37770
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
37256
37771
|
import { timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
@@ -37449,8 +37964,41 @@ function quoteTableRef(name) {
|
|
|
37449
37964
|
}
|
|
37450
37965
|
return parts.map((p) => `"${p}"`).join(".");
|
|
37451
37966
|
}
|
|
37967
|
+
function parseSeedRequest(url, body) {
|
|
37968
|
+
const b = body ?? {};
|
|
37969
|
+
const table2 = String(url.searchParams.get("table") ?? b.table ?? "");
|
|
37970
|
+
const count = parseInt(String(url.searchParams.get("count") ?? b.count ?? "10"), 10) || 10;
|
|
37971
|
+
const seedRaw = url.searchParams.get("seed") ?? b.seed;
|
|
37972
|
+
const seed = seedRaw !== void 0 && seedRaw !== null && String(seedRaw) !== "" ? Number.isNaN(parseInt(String(seedRaw), 10)) ? void 0 : parseInt(String(seedRaw), 10) : void 0;
|
|
37973
|
+
const clear = String(url.searchParams.get("clear") ?? b.clear ?? "") === "true" || b.clear === true;
|
|
37974
|
+
const strict = String(url.searchParams.get("strict") ?? b.strict ?? "") === "true" || b.strict === true;
|
|
37975
|
+
return { table: table2, count, seed, clear, strict };
|
|
37976
|
+
}
|
|
37977
|
+
function buildSeedFieldMap(columns, fake) {
|
|
37978
|
+
const rules = [
|
|
37979
|
+
[(n) => n.includes("email"), () => fake.email()],
|
|
37980
|
+
[(n) => n.includes("name"), () => fake.name()],
|
|
37981
|
+
[(n) => n.includes("phone"), () => fake.phone()],
|
|
37982
|
+
[(n) => n.includes("address") || n.includes("city") || n.includes("country"), () => fake.address()],
|
|
37983
|
+
[(n) => n.includes("url") || n.includes("website"), () => fake.url()],
|
|
37984
|
+
[(_n, t) => t.includes("int"), () => fake.integer(1, 1e3)],
|
|
37985
|
+
[(_n, t) => /real|float|double|numeric|decimal/.test(t), () => fake.numeric(0, 1e3, 2)],
|
|
37986
|
+
[(_n, t) => t.includes("bool"), () => fake.boolean()],
|
|
37987
|
+
[(_n, t) => t.includes("date") || t.includes("time"), () => fake.date()]
|
|
37988
|
+
];
|
|
37989
|
+
const sentence = () => fake.sentence(3);
|
|
37990
|
+
const fieldMap = {};
|
|
37991
|
+
for (const col of columns) {
|
|
37992
|
+
if (col.name.toLowerCase() === "id" || col.primaryKey === true) continue;
|
|
37993
|
+
const name = col.name.toLowerCase();
|
|
37994
|
+
const type2 = col.type.toLowerCase();
|
|
37995
|
+
const rule = rules.find(([matches]) => matches(name, type2));
|
|
37996
|
+
fieldMap[col.name] = rule ? rule[1] : sentence;
|
|
37997
|
+
}
|
|
37998
|
+
return fieldMap;
|
|
37999
|
+
}
|
|
37452
38000
|
function supervisorBaseUrl() {
|
|
37453
|
-
const explicit = (process.env.TINA4_SUPERVISOR_URL ?? "")
|
|
38001
|
+
const explicit = rtrimSlashes(process.env.TINA4_SUPERVISOR_URL ?? "");
|
|
37454
38002
|
if (explicit) return explicit;
|
|
37455
38003
|
const agentPort = (process.env.TINA4_AGENT_PORT ?? "").trim();
|
|
37456
38004
|
if (/^\d+$/.test(agentPort)) return `http://127.0.0.1:${parseInt(agentPort, 10)}`;
|
|
@@ -37458,6 +38006,42 @@ function supervisorBaseUrl() {
|
|
|
37458
38006
|
if (/^\d+$/.test(fwPort)) return `http://127.0.0.1:${parseInt(fwPort, 10) + 2e3}`;
|
|
37459
38007
|
return "http://127.0.0.1:9145";
|
|
37460
38008
|
}
|
|
38009
|
+
function buildSupervisorBody(method, body) {
|
|
38010
|
+
if (method !== "POST" && method !== "PUT" && method !== "PATCH" && method !== "DELETE") return void 0;
|
|
38011
|
+
if (body === void 0 || body === null) return void 0;
|
|
38012
|
+
if (typeof body === "string") return body;
|
|
38013
|
+
if (typeof body !== "object") return void 0;
|
|
38014
|
+
let outBody = body;
|
|
38015
|
+
if (!Array.isArray(body)) {
|
|
38016
|
+
const pf = body.plan_file;
|
|
38017
|
+
if (typeof pf === "string" && pf && !pf.includes("/")) outBody = { ...body, plan_file: `plan/${pf}` };
|
|
38018
|
+
}
|
|
38019
|
+
return JSON.stringify(outBody);
|
|
38020
|
+
}
|
|
38021
|
+
async function streamEventStream(res, upstream, timer) {
|
|
38022
|
+
res.raw.writeHead(upstream.status || 200, {
|
|
38023
|
+
"Content-Type": upstream.headers.get("content-type") ?? "text/event-stream",
|
|
38024
|
+
"Cache-Control": "no-cache",
|
|
38025
|
+
Connection: "keep-alive"
|
|
38026
|
+
});
|
|
38027
|
+
if (typeof res.raw.flushHeaders === "function") res.raw.flushHeaders();
|
|
38028
|
+
if (!upstream.body) {
|
|
38029
|
+
res.raw.end();
|
|
38030
|
+
clearTimeout(timer);
|
|
38031
|
+
return;
|
|
38032
|
+
}
|
|
38033
|
+
const reader = upstream.body.getReader();
|
|
38034
|
+
try {
|
|
38035
|
+
while (true) {
|
|
38036
|
+
const { done, value } = await reader.read();
|
|
38037
|
+
if (done) break;
|
|
38038
|
+
if (value) res.raw.write(Buffer.from(value));
|
|
38039
|
+
}
|
|
38040
|
+
} finally {
|
|
38041
|
+
clearTimeout(timer);
|
|
38042
|
+
res.raw.end();
|
|
38043
|
+
}
|
|
38044
|
+
}
|
|
37461
38045
|
async function proxyToSupervisor(req2, res, downstreamPath) {
|
|
37462
38046
|
const base = supervisorBaseUrl();
|
|
37463
38047
|
let qs = "";
|
|
@@ -37468,24 +38052,7 @@ async function proxyToSupervisor(req2, res, downstreamPath) {
|
|
|
37468
38052
|
}
|
|
37469
38053
|
const target = `${base}${downstreamPath}${qs}`;
|
|
37470
38054
|
const method = (req2.method ?? "GET").toUpperCase();
|
|
37471
|
-
|
|
37472
|
-
if (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE") {
|
|
37473
|
-
const body = req2.body;
|
|
37474
|
-
if (body !== void 0 && body !== null) {
|
|
37475
|
-
if (typeof body === "string") {
|
|
37476
|
-
bodyText = body;
|
|
37477
|
-
} else if (typeof body === "object") {
|
|
37478
|
-
let outBody = body;
|
|
37479
|
-
if (!Array.isArray(body)) {
|
|
37480
|
-
const pf = body.plan_file;
|
|
37481
|
-
if (typeof pf === "string" && pf && !pf.includes("/")) {
|
|
37482
|
-
outBody = { ...body, plan_file: `plan/${pf}` };
|
|
37483
|
-
}
|
|
37484
|
-
}
|
|
37485
|
-
bodyText = JSON.stringify(outBody);
|
|
37486
|
-
}
|
|
37487
|
-
}
|
|
37488
|
-
}
|
|
38055
|
+
const bodyText = buildSupervisorBody(method, req2.body);
|
|
37489
38056
|
const timeoutMs = downstreamPath === "/execute" || downstreamPath === "/chat" ? 6e5 : 3e4;
|
|
37490
38057
|
const ctrl = new AbortController();
|
|
37491
38058
|
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
@@ -37511,30 +38078,7 @@ async function proxyToSupervisor(req2, res, downstreamPath) {
|
|
|
37511
38078
|
}
|
|
37512
38079
|
const ct = (upstream.headers.get("content-type") ?? "").toLowerCase();
|
|
37513
38080
|
if (ct.includes("text/event-stream")) {
|
|
37514
|
-
res
|
|
37515
|
-
"Content-Type": upstream.headers.get("content-type") ?? "text/event-stream",
|
|
37516
|
-
"Cache-Control": "no-cache",
|
|
37517
|
-
Connection: "keep-alive"
|
|
37518
|
-
});
|
|
37519
|
-
if (typeof res.raw.flushHeaders === "function") {
|
|
37520
|
-
res.raw.flushHeaders();
|
|
37521
|
-
}
|
|
37522
|
-
if (!upstream.body) {
|
|
37523
|
-
res.raw.end();
|
|
37524
|
-
clearTimeout(timer);
|
|
37525
|
-
return;
|
|
37526
|
-
}
|
|
37527
|
-
const reader = upstream.body.getReader();
|
|
37528
|
-
try {
|
|
37529
|
-
while (true) {
|
|
37530
|
-
const { done, value } = await reader.read();
|
|
37531
|
-
if (done) break;
|
|
37532
|
-
if (value) res.raw.write(Buffer.from(value));
|
|
37533
|
-
}
|
|
37534
|
-
} finally {
|
|
37535
|
-
clearTimeout(timer);
|
|
37536
|
-
res.raw.end();
|
|
37537
|
-
}
|
|
38081
|
+
await streamEventStream(res, upstream, timer);
|
|
37538
38082
|
return;
|
|
37539
38083
|
}
|
|
37540
38084
|
clearTimeout(timer);
|
|
@@ -37651,13 +38195,13 @@ function handleGalleryDeploy(router) {
|
|
|
37651
38195
|
res.json({ deployed: name, files: copied });
|
|
37652
38196
|
};
|
|
37653
38197
|
}
|
|
37654
|
-
function
|
|
38198
|
+
function realPathOf2(target) {
|
|
37655
38199
|
let existing = target;
|
|
37656
38200
|
const tail = [];
|
|
37657
38201
|
for (; ; ) {
|
|
37658
38202
|
let present = false;
|
|
37659
38203
|
try {
|
|
37660
|
-
|
|
38204
|
+
lstatSync3(existing);
|
|
37661
38205
|
present = true;
|
|
37662
38206
|
} catch {
|
|
37663
38207
|
}
|
|
@@ -37669,9 +38213,9 @@ function realPathOf(target) {
|
|
|
37669
38213
|
}
|
|
37670
38214
|
function safeJoin(projectRoot3, rel, extraRoots = []) {
|
|
37671
38215
|
try {
|
|
37672
|
-
const root =
|
|
37673
|
-
const resolved =
|
|
37674
|
-
const roots = [root, ...extraRoots.filter(Boolean).map((r) =>
|
|
38216
|
+
const root = realPathOf2(resolve16(projectRoot3));
|
|
38217
|
+
const resolved = realPathOf2(resolve16(root, rel));
|
|
38218
|
+
const roots = [root, ...extraRoots.filter(Boolean).map((r) => realPathOf2(resolve16(r)))];
|
|
37675
38219
|
for (const r of roots) {
|
|
37676
38220
|
if (resolved === r || resolved.startsWith(r.endsWith(sep8) ? r : r + sep8)) return resolved;
|
|
37677
38221
|
}
|
|
@@ -37680,7 +38224,7 @@ function safeJoin(projectRoot3, rel, extraRoots = []) {
|
|
|
37680
38224
|
return null;
|
|
37681
38225
|
}
|
|
37682
38226
|
function resolvedRelative(projectRoot3, resolvedPath) {
|
|
37683
|
-
return relative9(
|
|
38227
|
+
return relative9(realPathOf2(resolve16(projectRoot3)), resolvedPath);
|
|
37684
38228
|
}
|
|
37685
38229
|
function devFilesHidden(name) {
|
|
37686
38230
|
if (DEV_FILES_IGNORED.has(name)) return true;
|
|
@@ -37708,7 +38252,7 @@ async function devGitInfo(root) {
|
|
|
37708
38252
|
if (!inside || inside.trim() !== "true") return empty;
|
|
37709
38253
|
const branch = (git(["rev-parse", "--abbrev-ref", "HEAD"]) ?? "").trim();
|
|
37710
38254
|
const topRaw = git(["rev-parse", "--show-toplevel"]);
|
|
37711
|
-
const gitRoot = topRaw && topRaw.trim() !== "" ? topRaw.trim().replace(/\\/g, "/")
|
|
38255
|
+
const gitRoot = topRaw && topRaw.trim() !== "" ? rtrimSlashes(topRaw.trim().replace(/\\/g, "/")) : null;
|
|
37712
38256
|
const status2 = /* @__PURE__ */ new Map();
|
|
37713
38257
|
const porcelain = git(["status", "--porcelain", "-uall"]);
|
|
37714
38258
|
if (porcelain) {
|
|
@@ -37727,6 +38271,44 @@ async function devGitInfo(root) {
|
|
|
37727
38271
|
return empty;
|
|
37728
38272
|
}
|
|
37729
38273
|
}
|
|
38274
|
+
function devGitLabel(gitPath, isDir, gitStatus) {
|
|
38275
|
+
const code = gitStatus.get(gitPath);
|
|
38276
|
+
if (code !== void 0) return devGitStatusLabel(code);
|
|
38277
|
+
if (isDir) {
|
|
38278
|
+
const prefix = gitPath + "/";
|
|
38279
|
+
for (const [gf, gc] of gitStatus) {
|
|
38280
|
+
if (gf.startsWith(prefix)) return gc === "??" ? "untracked" : "modified";
|
|
38281
|
+
}
|
|
38282
|
+
}
|
|
38283
|
+
return "clean";
|
|
38284
|
+
}
|
|
38285
|
+
function devDirHasVisibleChild(full) {
|
|
38286
|
+
try {
|
|
38287
|
+
for (const c of readdirSync16(full)) {
|
|
38288
|
+
if (!devFilesHidden(c)) return true;
|
|
38289
|
+
}
|
|
38290
|
+
} catch {
|
|
38291
|
+
}
|
|
38292
|
+
return false;
|
|
38293
|
+
}
|
|
38294
|
+
function buildFileEntry(name, full, entryRel, cwdInGit, gitStatus) {
|
|
38295
|
+
let isDir = false;
|
|
38296
|
+
let size = null;
|
|
38297
|
+
try {
|
|
38298
|
+
const st = statSync17(full);
|
|
38299
|
+
isDir = st.isDirectory();
|
|
38300
|
+
if (!isDir) size = st.size;
|
|
38301
|
+
} catch {
|
|
38302
|
+
}
|
|
38303
|
+
return {
|
|
38304
|
+
name,
|
|
38305
|
+
path: entryRel,
|
|
38306
|
+
is_dir: isDir,
|
|
38307
|
+
has_children: isDir ? devDirHasVisibleChild(full) : null,
|
|
38308
|
+
git_status: devGitLabel(cwdInGit + entryRel, isDir, gitStatus),
|
|
38309
|
+
size
|
|
38310
|
+
};
|
|
38311
|
+
}
|
|
37730
38312
|
function devAdminLanguage(rel) {
|
|
37731
38313
|
const base = (rel.split(/[\\/]/).pop() ?? "").toLowerCase();
|
|
37732
38314
|
if (base === "dockerfile" || base === "dockerfile.dev" || base === "dockerfile.prod") {
|
|
@@ -37741,14 +38323,14 @@ function devAdminLanguage(rel) {
|
|
|
37741
38323
|
function readDevFile(target) {
|
|
37742
38324
|
let fd;
|
|
37743
38325
|
try {
|
|
37744
|
-
fd =
|
|
37745
|
-
if (!
|
|
38326
|
+
fd = openSync5(target, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
|
|
38327
|
+
if (!fstatSync3(fd).isFile()) return null;
|
|
37746
38328
|
return readFileSync20(fd);
|
|
37747
38329
|
} catch (error2) {
|
|
37748
38330
|
if (["ENOENT", "ENOTDIR", "ELOOP"].includes(error2.code ?? "")) return null;
|
|
37749
38331
|
throw error2;
|
|
37750
38332
|
} finally {
|
|
37751
|
-
if (fd !== void 0)
|
|
38333
|
+
if (fd !== void 0) closeSync5(fd);
|
|
37752
38334
|
}
|
|
37753
38335
|
}
|
|
37754
38336
|
function mcpSecureEqual(expected, provided) {
|
|
@@ -37975,10 +38557,11 @@ function toolbarJs() {
|
|
|
37975
38557
|
connect();
|
|
37976
38558
|
})();`;
|
|
37977
38559
|
}
|
|
37978
|
-
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;
|
|
38560
|
+
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;
|
|
37979
38561
|
var init_devAdmin = __esm({
|
|
37980
38562
|
"src/devAdmin.ts"() {
|
|
37981
38563
|
"use strict";
|
|
38564
|
+
init_slashTrim();
|
|
37982
38565
|
init_devMailbox();
|
|
37983
38566
|
init_upstreamResponse();
|
|
37984
38567
|
init_dotenv();
|
|
@@ -38445,6 +39028,7 @@ var init_devAdmin = __esm({
|
|
|
38445
39028
|
{ method: "GET", pattern: "/__dev/api/docs/.well-known.json", handler: handleDocsWellKnown },
|
|
38446
39029
|
// JS asset
|
|
38447
39030
|
{ method: "GET", pattern: "/__dev/js/tina4-dev-admin.min.js", handler: handleDevAdminJs },
|
|
39031
|
+
{ method: "GET", pattern: "/__dev/split", handler: handleDevAdminSplit },
|
|
38448
39032
|
// Dev-toolbar assets — served as external CSS/JS so the injected toolbar is
|
|
38449
39033
|
// CSP-clean (no inline style=, onclick=, or <script>) under a strict
|
|
38450
39034
|
// `default-src 'self'`. Parity with PHP's /__dev/toolbar.css + toolbar.js.
|
|
@@ -38811,13 +39395,7 @@ var init_devAdmin = __esm({
|
|
|
38811
39395
|
};
|
|
38812
39396
|
handleSeed = async (req2, res) => {
|
|
38813
39397
|
const url = new URL(req2.url ?? "/", "http://localhost");
|
|
38814
|
-
const
|
|
38815
|
-
const table2 = url.searchParams.get("table") ?? body?.table ?? "";
|
|
38816
|
-
const count = parseInt(String(url.searchParams.get("count") ?? body?.count ?? "10"), 10) || 10;
|
|
38817
|
-
const seedRaw = url.searchParams.get("seed") ?? body?.seed;
|
|
38818
|
-
const seed = seedRaw !== void 0 && seedRaw !== null && String(seedRaw) !== "" ? Number.isNaN(parseInt(String(seedRaw), 10)) ? void 0 : parseInt(String(seedRaw), 10) : void 0;
|
|
38819
|
-
const clear = String(url.searchParams.get("clear") ?? body?.clear ?? "") === "true" || body?.clear === true;
|
|
38820
|
-
const strict = String(url.searchParams.get("strict") ?? body?.strict ?? "") === "true" || body?.strict === true;
|
|
39398
|
+
const { table: table2, count, seed, clear, strict } = parseSeedRequest(url, req2.body);
|
|
38821
39399
|
if (!table2) {
|
|
38822
39400
|
res.json({ error: "Missing table parameter" });
|
|
38823
39401
|
return;
|
|
@@ -38832,33 +39410,7 @@ var init_devAdmin = __esm({
|
|
|
38832
39410
|
res.json({ error: `Table '${table2}' not found or has no columns` });
|
|
38833
39411
|
return;
|
|
38834
39412
|
}
|
|
38835
|
-
const fieldMap =
|
|
38836
|
-
for (const col of columns) {
|
|
38837
|
-
const name = col.name.toLowerCase();
|
|
38838
|
-
const type2 = col.type.toLowerCase();
|
|
38839
|
-
if (name === "id" || col.primaryKey === true) continue;
|
|
38840
|
-
if (name.includes("email")) {
|
|
38841
|
-
fieldMap[col.name] = () => fake.email();
|
|
38842
|
-
} else if (name.includes("name")) {
|
|
38843
|
-
fieldMap[col.name] = () => fake.name();
|
|
38844
|
-
} else if (name.includes("phone")) {
|
|
38845
|
-
fieldMap[col.name] = () => fake.phone();
|
|
38846
|
-
} else if (name.includes("address") || name.includes("city") || name.includes("country")) {
|
|
38847
|
-
fieldMap[col.name] = () => fake.address();
|
|
38848
|
-
} else if (name.includes("url") || name.includes("website")) {
|
|
38849
|
-
fieldMap[col.name] = () => fake.url();
|
|
38850
|
-
} else if (type2.includes("int")) {
|
|
38851
|
-
fieldMap[col.name] = () => fake.integer(1, 1e3);
|
|
38852
|
-
} else if (type2.includes("real") || type2.includes("float") || type2.includes("double") || type2.includes("numeric") || type2.includes("decimal")) {
|
|
38853
|
-
fieldMap[col.name] = () => fake.numeric(0, 1e3, 2);
|
|
38854
|
-
} else if (type2.includes("bool")) {
|
|
38855
|
-
fieldMap[col.name] = () => fake.boolean();
|
|
38856
|
-
} else if (type2.includes("date") || type2.includes("time")) {
|
|
38857
|
-
fieldMap[col.name] = () => fake.date();
|
|
38858
|
-
} else {
|
|
38859
|
-
fieldMap[col.name] = () => fake.sentence(3);
|
|
38860
|
-
}
|
|
38861
|
-
}
|
|
39413
|
+
const fieldMap = buildSeedFieldMap(columns, fake);
|
|
38862
39414
|
const summary = await seedTable2(db, table2, count, fieldMap, void 0, { clear, strict });
|
|
38863
39415
|
res.json({ seeded: summary.seeded, failed: summary.failed, errors: summary.errors, table: table2 });
|
|
38864
39416
|
} catch (e) {
|
|
@@ -39031,9 +39583,9 @@ var init_devAdmin = __esm({
|
|
|
39031
39583
|
};
|
|
39032
39584
|
handleTest = async (_req, res) => {
|
|
39033
39585
|
try {
|
|
39034
|
-
const { execFile } = await import("node:child_process");
|
|
39586
|
+
const { execFile: execFile2 } = await import("node:child_process");
|
|
39035
39587
|
const { promisify } = await import("node:util");
|
|
39036
|
-
const run = promisify(
|
|
39588
|
+
const run = promisify(execFile2);
|
|
39037
39589
|
try {
|
|
39038
39590
|
const { stdout, stderr } = await run("npm", ["test"], {
|
|
39039
39591
|
cwd: resolve16(process.cwd()),
|
|
@@ -39151,9 +39703,9 @@ var init_devAdmin = __esm({
|
|
|
39151
39703
|
}
|
|
39152
39704
|
try {
|
|
39153
39705
|
const envPath = join27(process.cwd(), ".env");
|
|
39154
|
-
const fd =
|
|
39706
|
+
const fd = openSync5(envPath, constants4.O_RDWR | constants4.O_APPEND | constants4.O_CREAT | (constants4.O_NOFOLLOW ?? 0) | (constants4.O_NONBLOCK ?? 0), 384);
|
|
39155
39707
|
try {
|
|
39156
|
-
const info =
|
|
39708
|
+
const info = fstatSync3(fd);
|
|
39157
39709
|
if (!info.isFile() || info.nlink !== 1) throw new Error("Refusing a non-regular or multiply-linked configuration file");
|
|
39158
39710
|
fchmodSync2(fd, 384);
|
|
39159
39711
|
const lines = readFileSync20(fd, "utf-8").split("\n");
|
|
@@ -39183,10 +39735,10 @@ var init_devAdmin = __esm({
|
|
|
39183
39735
|
for (const [key, found] of Object.entries(keysFound)) {
|
|
39184
39736
|
if (!found) newLines.push(`${key}=${values[key]}`);
|
|
39185
39737
|
}
|
|
39186
|
-
|
|
39738
|
+
ftruncateSync2(fd, 0);
|
|
39187
39739
|
writeFileSync15(fd, newLines.join("\n") + "\n");
|
|
39188
39740
|
} finally {
|
|
39189
|
-
|
|
39741
|
+
closeSync5(fd);
|
|
39190
39742
|
}
|
|
39191
39743
|
res.json({ success: true });
|
|
39192
39744
|
} catch (e) {
|
|
@@ -39309,48 +39861,7 @@ var init_devAdmin = __esm({
|
|
|
39309
39861
|
const full = join27(target, name);
|
|
39310
39862
|
const entryRel = relative9(root, full).replace(/\\/g, "/");
|
|
39311
39863
|
if (isSecretPath(entryRel)) continue;
|
|
39312
|
-
|
|
39313
|
-
let size = null;
|
|
39314
|
-
try {
|
|
39315
|
-
const st = statSync17(full);
|
|
39316
|
-
isDir = st.isDirectory();
|
|
39317
|
-
if (!isDir) size = st.size;
|
|
39318
|
-
} catch {
|
|
39319
|
-
}
|
|
39320
|
-
const gitPath = cwdInGit + entryRel;
|
|
39321
|
-
let gitLabel = "clean";
|
|
39322
|
-
const code = gitStatus.get(gitPath);
|
|
39323
|
-
if (code !== void 0) {
|
|
39324
|
-
gitLabel = devGitStatusLabel(code);
|
|
39325
|
-
} else if (isDir) {
|
|
39326
|
-
const prefix = gitPath + "/";
|
|
39327
|
-
for (const [gf, gc] of gitStatus) {
|
|
39328
|
-
if (gf.startsWith(prefix)) {
|
|
39329
|
-
gitLabel = gc === "??" ? "untracked" : "modified";
|
|
39330
|
-
break;
|
|
39331
|
-
}
|
|
39332
|
-
}
|
|
39333
|
-
}
|
|
39334
|
-
let hasChildren = null;
|
|
39335
|
-
if (isDir) {
|
|
39336
|
-
hasChildren = false;
|
|
39337
|
-
try {
|
|
39338
|
-
for (const c of readdirSync16(full)) {
|
|
39339
|
-
if (devFilesHidden(c)) continue;
|
|
39340
|
-
hasChildren = true;
|
|
39341
|
-
break;
|
|
39342
|
-
}
|
|
39343
|
-
} catch {
|
|
39344
|
-
}
|
|
39345
|
-
}
|
|
39346
|
-
entries.push({
|
|
39347
|
-
name,
|
|
39348
|
-
path: entryRel,
|
|
39349
|
-
is_dir: isDir,
|
|
39350
|
-
has_children: hasChildren,
|
|
39351
|
-
git_status: gitLabel,
|
|
39352
|
-
size
|
|
39353
|
-
});
|
|
39864
|
+
entries.push(buildFileEntry(name, full, entryRel, cwdInGit, gitStatus));
|
|
39354
39865
|
}
|
|
39355
39866
|
res.json({ path: relative9(root, target).replace(/\\/g, "/") || ".", branch, entries });
|
|
39356
39867
|
};
|
|
@@ -39883,6 +40394,31 @@ var init_devAdmin = __esm({
|
|
|
39883
40394
|
res.raw.writeHead(404, { "Content-Type": "text/plain" });
|
|
39884
40395
|
res.raw.end("tina4-dev-admin.min.js not found");
|
|
39885
40396
|
};
|
|
40397
|
+
handleDevAdminSplit = async (_req, res) => {
|
|
40398
|
+
const { readFileSync: readFileSync27, existsSync: existsSync29 } = await import("node:fs");
|
|
40399
|
+
const { dirname: dirname17, join: join33, resolve: resolve21 } = await import("node:path");
|
|
40400
|
+
const { fileURLToPath: fileURLToPath10 } = await import("node:url");
|
|
40401
|
+
const dir = dirname17(fileURLToPath10(import.meta.url));
|
|
40402
|
+
const candidates = [
|
|
40403
|
+
join33(dir, "..", "public", "js", "tina4-dev-admin-split.html"),
|
|
40404
|
+
join33(dir, "..", "..", "public", "js", "tina4-dev-admin-split.html"),
|
|
40405
|
+
resolve21(process.cwd(), "node_modules", "tina4-nodejs", "packages", "core", "public", "js", "tina4-dev-admin-split.html"),
|
|
40406
|
+
resolve21(process.cwd(), "public", "js", "tina4-dev-admin-split.html")
|
|
40407
|
+
];
|
|
40408
|
+
for (const path10 of candidates) {
|
|
40409
|
+
if (existsSync29(path10)) {
|
|
40410
|
+
try {
|
|
40411
|
+
const content = readFileSync27(path10, "utf-8");
|
|
40412
|
+
res.raw.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-cache" });
|
|
40413
|
+
res.raw.end(content);
|
|
40414
|
+
return;
|
|
40415
|
+
} catch {
|
|
40416
|
+
}
|
|
40417
|
+
}
|
|
40418
|
+
}
|
|
40419
|
+
res.raw.writeHead(404, { "Content-Type": "text/plain" });
|
|
40420
|
+
res.raw.end("tina4-dev-admin-split.html not found");
|
|
40421
|
+
};
|
|
39886
40422
|
handleToolbarCss = (_req, res) => {
|
|
39887
40423
|
res.raw.writeHead(200, { "Content-Type": "text/css; charset=utf-8", "Cache-Control": "no-cache" });
|
|
39888
40424
|
res.raw.end(toolbarCss());
|
|
@@ -40354,7 +40890,10 @@ function generate2(routes, models = []) {
|
|
|
40354
40890
|
openapi: resolveOpenApiVersion(),
|
|
40355
40891
|
info: buildInfo(),
|
|
40356
40892
|
servers: resolveServers(),
|
|
40357
|
-
|
|
40893
|
+
// Prototype-less: route paths are developer-defined, but a null prototype
|
|
40894
|
+
// makes `spec.paths[path][method] = op` structurally pollution-proof
|
|
40895
|
+
// regardless (js/prototype-polluting-assignment). Serialises to JSON the same.
|
|
40896
|
+
paths: /* @__PURE__ */ Object.create(null),
|
|
40358
40897
|
components: {
|
|
40359
40898
|
schemas: {},
|
|
40360
40899
|
// Configurable security schemes (v3.13.42): bearerFormat via env, optional
|
|
@@ -40419,7 +40958,7 @@ function buildOperation(route, spec, ctx) {
|
|
|
40419
40958
|
const openApiPath = patternToOpenAPI(route.pattern);
|
|
40420
40959
|
const method = route.method.toLowerCase();
|
|
40421
40960
|
if (!spec.paths[openApiPath]) {
|
|
40422
|
-
spec.paths[openApiPath] =
|
|
40961
|
+
spec.paths[openApiPath] = /* @__PURE__ */ Object.create(null);
|
|
40423
40962
|
}
|
|
40424
40963
|
const tags = route.meta?.tags ?? inferTags(route.pattern);
|
|
40425
40964
|
for (const t of tags) {
|
|
@@ -40725,7 +41264,7 @@ function inferModelFromPath(pattern) {
|
|
|
40725
41264
|
return null;
|
|
40726
41265
|
}
|
|
40727
41266
|
function operationIdBase(method, openApiPath) {
|
|
40728
|
-
const clean = openApiPath
|
|
41267
|
+
const clean = trimSlashes(openApiPath).replace(/\//g, "_").replace(/\.\.\./g, "").replace(/[{}]/g, "").replace(/\*/g, "wildcard");
|
|
40729
41268
|
return clean ? `${method}_${clean}` : method;
|
|
40730
41269
|
}
|
|
40731
41270
|
function uniqueOperationId(method, openApiPath, seen) {
|
|
@@ -40743,6 +41282,7 @@ var WRITE_METHODS, INTERNAL_PREFIXES, registeredSchemes, registeredSchemas, PARA
|
|
|
40743
41282
|
var init_generator = __esm({
|
|
40744
41283
|
"../swagger/src/generator.ts"() {
|
|
40745
41284
|
"use strict";
|
|
41285
|
+
init_slashTrim();
|
|
40746
41286
|
WRITE_METHODS = /* @__PURE__ */ new Set(["post", "put", "patch", "delete"]);
|
|
40747
41287
|
INTERNAL_PREFIXES = ["/swagger", "/__dev", "/__feedback", "/ai", "/rag", "/vision", "/embed", "/image"];
|
|
40748
41288
|
registeredSchemes = {};
|
|
@@ -40764,7 +41304,7 @@ var init_generator = __esm({
|
|
|
40764
41304
|
|
|
40765
41305
|
// ../swagger/src/ui.ts
|
|
40766
41306
|
function swaggerUiCdn() {
|
|
40767
|
-
return (process.env.TINA4_SWAGGER_UI_CDN ?? "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5")
|
|
41307
|
+
return rtrimSlashes(process.env.TINA4_SWAGGER_UI_CDN ?? "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5");
|
|
40768
41308
|
}
|
|
40769
41309
|
function swaggerEnabled() {
|
|
40770
41310
|
const raw = (process.env.TINA4_SWAGGER_ENABLED ?? "").trim().toLowerCase();
|
|
@@ -40820,6 +41360,7 @@ var SWAGGER_UI_HTML;
|
|
|
40820
41360
|
var init_ui = __esm({
|
|
40821
41361
|
"../swagger/src/ui.ts"() {
|
|
40822
41362
|
"use strict";
|
|
41363
|
+
init_slashTrim();
|
|
40823
41364
|
SWAGGER_UI_HTML = (specUrl, nonce) => `<!DOCTYPE html>
|
|
40824
41365
|
<html lang="en">
|
|
40825
41366
|
<head>
|
|
@@ -40874,7 +41415,7 @@ __export(sso_exports, {
|
|
|
40874
41415
|
SsoError: () => SsoError,
|
|
40875
41416
|
liveSessionIdentity: () => liveSessionIdentity
|
|
40876
41417
|
});
|
|
40877
|
-
import { createHash as
|
|
41418
|
+
import { createHash as createHash11, randomBytes as randomBytes8, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
|
|
40878
41419
|
function expiresAt(tokens) {
|
|
40879
41420
|
const lifetime = Number(tokens.expires_in ?? 0);
|
|
40880
41421
|
return lifetime > 0 ? Math.floor(Date.now() / 1e3) + lifetime : 0;
|
|
@@ -41005,7 +41546,7 @@ var init_sso = __esm({
|
|
|
41005
41546
|
const state = randomBytes8(32).toString("base64url");
|
|
41006
41547
|
const nonce = randomBytes8(32).toString("base64url");
|
|
41007
41548
|
const verifier = randomBytes8(64).toString("base64url");
|
|
41008
|
-
const challenge =
|
|
41549
|
+
const challenge = createHash11("sha256").update(verifier).digest("base64url");
|
|
41009
41550
|
session.set(_Sso.PENDING_KEY, { state, nonce, verifier, return_to: _Sso.safeReturn(returnTo), created_at: Math.floor(Date.now() / 1e3) });
|
|
41010
41551
|
const metadata = await this.discover();
|
|
41011
41552
|
const query = new URLSearchParams({
|
|
@@ -41237,7 +41778,7 @@ import { resolve as resolve19, dirname as dirname15, join as join30, relative as
|
|
|
41237
41778
|
import { existsSync as existsSync26, readdirSync as readdirSync18, readFileSync as readFileSync23, statSync as statSync18 } from "node:fs";
|
|
41238
41779
|
import { isatty } from "node:tty";
|
|
41239
41780
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
41240
|
-
import { execFileSync as execFileSync3,
|
|
41781
|
+
import { execFileSync as execFileSync3, execFile } from "node:child_process";
|
|
41241
41782
|
import cluster from "node:cluster";
|
|
41242
41783
|
import os2 from "node:os";
|
|
41243
41784
|
function isSwaggerAssetPath(pathname) {
|
|
@@ -41373,10 +41914,11 @@ function shouldOpenBrowser(isDevelopment, noBrowser = false) {
|
|
|
41373
41914
|
});
|
|
41374
41915
|
}
|
|
41375
41916
|
function openBrowser(url) {
|
|
41917
|
+
if (!/^https?:\/\/([A-Za-z0-9.-]+|\[[0-9A-Fa-f:]+\])(:\d{1,5})?\/?$/.test(url)) return;
|
|
41376
41918
|
setTimeout(() => {
|
|
41377
|
-
if (process.platform === "darwin")
|
|
41378
|
-
else if (process.platform === "win32")
|
|
41379
|
-
else
|
|
41919
|
+
if (process.platform === "darwin") execFile("open", [url]);
|
|
41920
|
+
else if (process.platform === "win32") execFile("rundll32", ["url.dll,FileProtocolHandler", url]);
|
|
41921
|
+
else execFile("xdg-open", [url]);
|
|
41380
41922
|
}, 2e3);
|
|
41381
41923
|
}
|
|
41382
41924
|
function resolvePortAndHost(config) {
|
|
@@ -41491,7 +42033,7 @@ function resetTemplateCache() {
|
|
|
41491
42033
|
}
|
|
41492
42034
|
function resolveTemplate(pathname, templatesDir) {
|
|
41493
42035
|
if (!templateAutoRoutingEnabled()) return null;
|
|
41494
|
-
const cleanPath = pathname
|
|
42036
|
+
const cleanPath = trimSlashes(pathname) || "index";
|
|
41495
42037
|
const isDev2 = (process.env.TINA4_DEBUG ?? "false").toLowerCase() === "true";
|
|
41496
42038
|
if (isDev2) {
|
|
41497
42039
|
if (cleanPath.split("/").some((seg) => seg.startsWith("_"))) return null;
|
|
@@ -41759,7 +42301,7 @@ async function runGlobalMiddlewarePass(middleware, req2, res) {
|
|
|
41759
42301
|
}
|
|
41760
42302
|
function resolveHandlerArgs(handler, req2, res, routeParams) {
|
|
41761
42303
|
const fnStr = handler.toString();
|
|
41762
|
-
const argMatch = fnStr.match(/^(?:async\s*)?(?:function
|
|
42304
|
+
const argMatch = fnStr.match(/^(?:async\s*)?(?:function(?:\s+\w+)?\s*)?\(([^)]*)\)/);
|
|
41763
42305
|
const argNames = argMatch?.[1]?.split(",").map((a) => a.trim().replace(/[:=].*/, "")) ?? [];
|
|
41764
42306
|
const filteredArgs = argNames.filter((n) => n.length > 0);
|
|
41765
42307
|
if (filteredArgs.length === 0) return [];
|
|
@@ -41995,8 +42537,9 @@ async function buildDispatchContext(router, base) {
|
|
|
41995
42537
|
const templatesDir = resolve19(root, "src/templates");
|
|
41996
42538
|
let frondEngine = null;
|
|
41997
42539
|
try {
|
|
41998
|
-
const { Frond: Frond2, setCspNonceProvider: setCspNonceProvider2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
42540
|
+
const { Frond: Frond2, setCspNonceProvider: setCspNonceProvider2, setFormTokenSessionProvider: setFormTokenSessionProvider2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
41999
42541
|
setCspNonceProvider2(currentCspNonce);
|
|
42542
|
+
setFormTokenSessionProvider2(currentFormTokenSessionId);
|
|
42000
42543
|
frondEngine = new Frond2(templatesDir);
|
|
42001
42544
|
} catch {
|
|
42002
42545
|
}
|
|
@@ -42111,7 +42654,10 @@ async function runDispatch(ctx, rawReq, rawRes) {
|
|
|
42111
42654
|
const requestNonce = generateNonce();
|
|
42112
42655
|
return Log.runWithRequestId(
|
|
42113
42656
|
requestId,
|
|
42114
|
-
() => runWithCspNonce(
|
|
42657
|
+
() => runWithCspNonce(
|
|
42658
|
+
requestNonce,
|
|
42659
|
+
() => runWithFormTokenSession(() => dispatchInner(ctx, rawReq, rawRes, requestId))
|
|
42660
|
+
)
|
|
42115
42661
|
);
|
|
42116
42662
|
}
|
|
42117
42663
|
function loopbackBindHosts(host) {
|
|
@@ -42239,8 +42785,9 @@ async function startServer(config) {
|
|
|
42239
42785
|
let frondEngine = null;
|
|
42240
42786
|
setDefaultTemplatesDir(templatesDir);
|
|
42241
42787
|
try {
|
|
42242
|
-
const { Frond: Frond2, setCspNonceProvider: setCspNonceProvider2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
42788
|
+
const { Frond: Frond2, setCspNonceProvider: setCspNonceProvider2, setFormTokenSessionProvider: setFormTokenSessionProvider2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
42243
42789
|
setCspNonceProvider2(currentCspNonce);
|
|
42790
|
+
setFormTokenSessionProvider2(currentFormTokenSessionId);
|
|
42244
42791
|
frondEngine = new Frond2(templatesDir);
|
|
42245
42792
|
router.addRoute({
|
|
42246
42793
|
method: "GET",
|
|
@@ -42589,6 +43136,7 @@ var __filename, __dirname, BUILTIN_ERROR_TEMPLATES_DIR, BUILTIN_PUBLIC_DIR, swag
|
|
|
42589
43136
|
var init_server = __esm({
|
|
42590
43137
|
"src/server.ts"() {
|
|
42591
43138
|
"use strict";
|
|
43139
|
+
init_slashTrim();
|
|
42592
43140
|
init_transport();
|
|
42593
43141
|
init_router();
|
|
42594
43142
|
init_authGate();
|
|
@@ -42596,6 +43144,7 @@ var init_server = __esm({
|
|
|
42596
43144
|
init_portTakeover();
|
|
42597
43145
|
init_request();
|
|
42598
43146
|
init_dispatchPipeline();
|
|
43147
|
+
init_session();
|
|
42599
43148
|
init_response();
|
|
42600
43149
|
init_middleware();
|
|
42601
43150
|
init_static();
|
|
@@ -44211,6 +44760,7 @@ var ApiStreamError, RETRY_STATUSES, DOWNLOAD_CHUNK_SIZE, MAX_REDIRECTS, STRIP_ON
|
|
|
44211
44760
|
var init_api = __esm({
|
|
44212
44761
|
"src/api.ts"() {
|
|
44213
44762
|
"use strict";
|
|
44763
|
+
init_slashTrim();
|
|
44214
44764
|
init_version();
|
|
44215
44765
|
init_ssrf();
|
|
44216
44766
|
ApiStreamError = class extends Error {
|
|
@@ -44308,7 +44858,7 @@ var init_api = __esm({
|
|
|
44308
44858
|
* turns on a per-client, in-memory cookie jar.
|
|
44309
44859
|
*/
|
|
44310
44860
|
constructor(baseUrl = "", authHeaderOrOptions = "", timeout = 30) {
|
|
44311
|
-
this.baseUrl = baseUrl
|
|
44861
|
+
this.baseUrl = rtrimSlashes(baseUrl);
|
|
44312
44862
|
this.headers = {};
|
|
44313
44863
|
this.maxRetries = 0;
|
|
44314
44864
|
this.retryBackoff = 0.5;
|
|
@@ -45074,6 +45624,23 @@ function sendCommand(socket, command) {
|
|
|
45074
45624
|
});
|
|
45075
45625
|
});
|
|
45076
45626
|
}
|
|
45627
|
+
function pushAlternativeBody(lines, altBoundary, text, body) {
|
|
45628
|
+
lines.push(`Content-Type: multipart/alternative; boundary="${altBoundary}"`);
|
|
45629
|
+
lines.push("");
|
|
45630
|
+
lines.push(`--${altBoundary}`);
|
|
45631
|
+
lines.push("Content-Type: text/plain; charset=UTF-8");
|
|
45632
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45633
|
+
lines.push("");
|
|
45634
|
+
lines.push(text);
|
|
45635
|
+
lines.push("");
|
|
45636
|
+
lines.push(`--${altBoundary}`);
|
|
45637
|
+
lines.push("Content-Type: text/html; charset=UTF-8");
|
|
45638
|
+
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45639
|
+
lines.push("");
|
|
45640
|
+
lines.push(body);
|
|
45641
|
+
lines.push("");
|
|
45642
|
+
lines.push(`--${altBoundary}--`);
|
|
45643
|
+
}
|
|
45077
45644
|
function buildMimeMessage(options) {
|
|
45078
45645
|
const boundary = `----=_Tina4_${Date.now()}_${Math.random().toString(36).substring(2)}`;
|
|
45079
45646
|
const altBoundary = `----=_Tina4Alt_${Date.now()}_${Math.random().toString(36).substring(2)}`;
|
|
@@ -45103,21 +45670,7 @@ function buildMimeMessage(options) {
|
|
|
45103
45670
|
lines.push("");
|
|
45104
45671
|
lines.push(`--${boundary}`);
|
|
45105
45672
|
if (hasTextAlt) {
|
|
45106
|
-
lines.
|
|
45107
|
-
lines.push("");
|
|
45108
|
-
lines.push(`--${altBoundary}`);
|
|
45109
|
-
lines.push("Content-Type: text/plain; charset=UTF-8");
|
|
45110
|
-
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45111
|
-
lines.push("");
|
|
45112
|
-
lines.push(options.text);
|
|
45113
|
-
lines.push("");
|
|
45114
|
-
lines.push(`--${altBoundary}`);
|
|
45115
|
-
lines.push("Content-Type: text/html; charset=UTF-8");
|
|
45116
|
-
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45117
|
-
lines.push("");
|
|
45118
|
-
lines.push(options.body);
|
|
45119
|
-
lines.push("");
|
|
45120
|
-
lines.push(`--${altBoundary}--`);
|
|
45673
|
+
pushAlternativeBody(lines, altBoundary, options.text, options.body);
|
|
45121
45674
|
} else {
|
|
45122
45675
|
const contentType = options.html ? "text/html" : "text/plain";
|
|
45123
45676
|
lines.push(`Content-Type: ${contentType}; charset=UTF-8`);
|
|
@@ -45142,21 +45695,7 @@ function buildMimeMessage(options) {
|
|
|
45142
45695
|
lines.push("");
|
|
45143
45696
|
lines.push(`--${boundary}--`);
|
|
45144
45697
|
} else if (hasTextAlt) {
|
|
45145
|
-
lines.
|
|
45146
|
-
lines.push("");
|
|
45147
|
-
lines.push(`--${altBoundary}`);
|
|
45148
|
-
lines.push("Content-Type: text/plain; charset=UTF-8");
|
|
45149
|
-
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45150
|
-
lines.push("");
|
|
45151
|
-
lines.push(options.text);
|
|
45152
|
-
lines.push("");
|
|
45153
|
-
lines.push(`--${altBoundary}`);
|
|
45154
|
-
lines.push("Content-Type: text/html; charset=UTF-8");
|
|
45155
|
-
lines.push("Content-Transfer-Encoding: 7bit");
|
|
45156
|
-
lines.push("");
|
|
45157
|
-
lines.push(options.body);
|
|
45158
|
-
lines.push("");
|
|
45159
|
-
lines.push(`--${altBoundary}--`);
|
|
45698
|
+
pushAlternativeBody(lines, altBoundary, options.text, options.body);
|
|
45160
45699
|
} else {
|
|
45161
45700
|
const contentType = options.html ? "text/html" : "text/plain";
|
|
45162
45701
|
lines.push(`Content-Type: ${contentType}; charset=UTF-8`);
|
|
@@ -45921,61 +46460,72 @@ function decodeEntities(raw) {
|
|
|
45921
46460
|
function parseXmlDocument(xml) {
|
|
45922
46461
|
const stack = [];
|
|
45923
46462
|
let root = null;
|
|
45924
|
-
let position = 0;
|
|
45925
46463
|
const addText = (text) => {
|
|
45926
46464
|
const current = stack[stack.length - 1];
|
|
45927
46465
|
if (current.children.length === 0) current.text += text;
|
|
45928
46466
|
};
|
|
45929
|
-
|
|
45930
|
-
const
|
|
46467
|
+
const skipComment = (at) => {
|
|
46468
|
+
const close = xml.indexOf("-->", at + 4);
|
|
46469
|
+
if (close === -1) malformed();
|
|
46470
|
+
return close + 3;
|
|
46471
|
+
};
|
|
46472
|
+
const readCData = (at) => {
|
|
46473
|
+
const close = xml.indexOf("]]>", at + 9);
|
|
46474
|
+
if (close === -1 || stack.length === 0) malformed();
|
|
46475
|
+
addText(xml.slice(at + 9, close));
|
|
46476
|
+
return close + 3;
|
|
46477
|
+
};
|
|
46478
|
+
const skipProcessingInstruction = (at) => {
|
|
46479
|
+
const close = xml.indexOf("?>", at + 2);
|
|
46480
|
+
if (close === -1) malformed();
|
|
46481
|
+
const target = xml.slice(at + 2, close).split(/\s/, 1)[0];
|
|
46482
|
+
if (target.toLowerCase() === "xml" && at !== 0) malformed();
|
|
46483
|
+
return close + 2;
|
|
46484
|
+
};
|
|
46485
|
+
const closeElement = (at) => {
|
|
46486
|
+
END_TAG.lastIndex = at;
|
|
46487
|
+
const match = END_TAG.exec(xml);
|
|
46488
|
+
const open = stack.pop();
|
|
46489
|
+
if (!match || !open || open.qualifiedName !== match[1]) malformed();
|
|
46490
|
+
return END_TAG.lastIndex;
|
|
46491
|
+
};
|
|
46492
|
+
const openElement = (at) => {
|
|
46493
|
+
START_TAG.lastIndex = at;
|
|
46494
|
+
const match = START_TAG.exec(xml);
|
|
46495
|
+
if (!match || stack.length === 0 && root !== null) malformed();
|
|
46496
|
+
for (const attribute of match[2].matchAll(ATTRIBUTE_VALUE)) decodeEntities(attribute[1] ?? attribute[2]);
|
|
46497
|
+
const qualifiedName = match[1];
|
|
46498
|
+
const element = {
|
|
46499
|
+
name: qualifiedName.slice(qualifiedName.indexOf(":") + 1),
|
|
46500
|
+
qualifiedName,
|
|
46501
|
+
children: [],
|
|
46502
|
+
text: ""
|
|
46503
|
+
};
|
|
46504
|
+
if (stack.length > 0) stack[stack.length - 1].children.push(element);
|
|
46505
|
+
else root = element;
|
|
46506
|
+
if (match[3] !== "/") stack.push(element);
|
|
46507
|
+
return START_TAG.lastIndex;
|
|
46508
|
+
};
|
|
46509
|
+
const readText = (at) => {
|
|
46510
|
+
const nextTag = xml.indexOf("<", at);
|
|
45931
46511
|
const textEnd = nextTag === -1 ? xml.length : nextTag;
|
|
45932
|
-
if (textEnd >
|
|
45933
|
-
const raw = xml.slice(
|
|
46512
|
+
if (textEnd > at) {
|
|
46513
|
+
const raw = xml.slice(at, textEnd);
|
|
45934
46514
|
if (stack.length > 0) addText(decodeEntities(raw));
|
|
45935
46515
|
else if (raw.trim() !== "") malformed();
|
|
45936
|
-
position = textEnd;
|
|
45937
|
-
if (nextTag === -1) break;
|
|
45938
|
-
}
|
|
45939
|
-
if (xml.startsWith("<!--", position)) {
|
|
45940
|
-
const close = xml.indexOf("-->", position + 4);
|
|
45941
|
-
if (close === -1) malformed();
|
|
45942
|
-
position = close + 3;
|
|
45943
|
-
} else if (xml.startsWith("<![CDATA[", position)) {
|
|
45944
|
-
const close = xml.indexOf("]]>", position + 9);
|
|
45945
|
-
if (close === -1 || stack.length === 0) malformed();
|
|
45946
|
-
addText(xml.slice(position + 9, close));
|
|
45947
|
-
position = close + 3;
|
|
45948
|
-
} else if (xml.startsWith("<?", position)) {
|
|
45949
|
-
const close = xml.indexOf("?>", position + 2);
|
|
45950
|
-
if (close === -1) malformed();
|
|
45951
|
-
const target = xml.slice(position + 2, close).split(/\s/, 1)[0];
|
|
45952
|
-
if (target.toLowerCase() === "xml" && position !== 0) malformed();
|
|
45953
|
-
position = close + 2;
|
|
45954
|
-
} else if (xml.startsWith("<!", position)) {
|
|
45955
|
-
malformed();
|
|
45956
|
-
} else if (xml.startsWith("</", position)) {
|
|
45957
|
-
END_TAG.lastIndex = position;
|
|
45958
|
-
const match = END_TAG.exec(xml);
|
|
45959
|
-
const open = stack.pop();
|
|
45960
|
-
if (!match || !open || open.qualifiedName !== match[1]) malformed();
|
|
45961
|
-
position = END_TAG.lastIndex;
|
|
45962
|
-
} else {
|
|
45963
|
-
START_TAG.lastIndex = position;
|
|
45964
|
-
const match = START_TAG.exec(xml);
|
|
45965
|
-
if (!match || stack.length === 0 && root !== null) malformed();
|
|
45966
|
-
for (const attribute of match[2].matchAll(ATTRIBUTE_VALUE)) decodeEntities(attribute[1] ?? attribute[2]);
|
|
45967
|
-
const qualifiedName = match[1];
|
|
45968
|
-
const element = {
|
|
45969
|
-
name: qualifiedName.slice(qualifiedName.indexOf(":") + 1),
|
|
45970
|
-
qualifiedName,
|
|
45971
|
-
children: [],
|
|
45972
|
-
text: ""
|
|
45973
|
-
};
|
|
45974
|
-
if (stack.length > 0) stack[stack.length - 1].children.push(element);
|
|
45975
|
-
else root = element;
|
|
45976
|
-
if (match[3] !== "/") stack.push(element);
|
|
45977
|
-
position = START_TAG.lastIndex;
|
|
45978
46516
|
}
|
|
46517
|
+
return textEnd;
|
|
46518
|
+
};
|
|
46519
|
+
let position = 0;
|
|
46520
|
+
while (position < xml.length) {
|
|
46521
|
+
position = readText(position);
|
|
46522
|
+
if (position >= xml.length) break;
|
|
46523
|
+
if (xml.startsWith("<!--", position)) position = skipComment(position);
|
|
46524
|
+
else if (xml.startsWith("<![CDATA[", position)) position = readCData(position);
|
|
46525
|
+
else if (xml.startsWith("<?", position)) position = skipProcessingInstruction(position);
|
|
46526
|
+
else if (xml.startsWith("<!", position)) malformed();
|
|
46527
|
+
else if (xml.startsWith("</", position)) position = closeElement(position);
|
|
46528
|
+
else position = openElement(position);
|
|
45979
46529
|
}
|
|
45980
46530
|
if (root === null || stack.length > 0) malformed();
|
|
45981
46531
|
return root;
|
|
@@ -47459,13 +48009,13 @@ export default class User {
|
|
|
47459
48009
|
import {
|
|
47460
48010
|
createCipheriv,
|
|
47461
48011
|
createECDH,
|
|
47462
|
-
createHmac as
|
|
48012
|
+
createHmac as createHmac5,
|
|
47463
48013
|
createPrivateKey,
|
|
47464
48014
|
createSign as createSign2,
|
|
47465
48015
|
randomBytes as randomBytes12
|
|
47466
48016
|
} from "node:crypto";
|
|
47467
48017
|
function encodeBase64Url(value) {
|
|
47468
|
-
return Buffer.from(value).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(
|
|
48018
|
+
return Buffer.from(value).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/={1,2}$/, "");
|
|
47469
48019
|
}
|
|
47470
48020
|
function decodeBase64Url(value, name) {
|
|
47471
48021
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -47495,15 +48045,15 @@ function vapidPrivateKey(rawPrivate, rawPublic) {
|
|
|
47495
48045
|
format: "jwk"
|
|
47496
48046
|
});
|
|
47497
48047
|
}
|
|
47498
|
-
function
|
|
47499
|
-
return
|
|
48048
|
+
function hmac2(salt, value) {
|
|
48049
|
+
return createHmac5("sha256", salt).update(value).digest();
|
|
47500
48050
|
}
|
|
47501
48051
|
function hkdfExpand(prk, info, length) {
|
|
47502
48052
|
const chunks = [];
|
|
47503
48053
|
let previous = Buffer.alloc(0);
|
|
47504
48054
|
for (let counter = 1; Buffer.concat(chunks).length < length; counter++) {
|
|
47505
48055
|
if (counter > 255) throw new PushError("HKDF output is too large");
|
|
47506
|
-
previous =
|
|
48056
|
+
previous = hmac2(prk, Buffer.concat([previous, info, Buffer.from([counter])]));
|
|
47507
48057
|
chunks.push(previous);
|
|
47508
48058
|
}
|
|
47509
48059
|
return Buffer.concat(chunks).subarray(0, length);
|
|
@@ -47540,10 +48090,10 @@ function encryptPayload(payload, subscription) {
|
|
|
47540
48090
|
clientPublic,
|
|
47541
48091
|
serverPublic
|
|
47542
48092
|
]);
|
|
47543
|
-
const prkKey =
|
|
48093
|
+
const prkKey = hmac2(authSecret, sharedSecret);
|
|
47544
48094
|
const ikm = hkdfExpand(prkKey, keyInfo, 32);
|
|
47545
48095
|
const salt = randomBytes12(16);
|
|
47546
|
-
const contentPrk =
|
|
48096
|
+
const contentPrk = hmac2(salt, ikm);
|
|
47547
48097
|
const cek = hkdfExpand(contentPrk, Buffer.from("Content-Encoding: aes128gcm\0", "ascii"), 16);
|
|
47548
48098
|
const nonce = hkdfExpand(contentPrk, Buffer.from("Content-Encoding: nonce\0", "ascii"), 12);
|
|
47549
48099
|
const cipher = createCipheriv("aes-128-gcm", cek, nonce);
|
|
@@ -47716,6 +48266,7 @@ var AiError, AiConfigError, AiTimeoutError, AiParseError, AiHTTPError, Ai, Aggre
|
|
|
47716
48266
|
var init_aiClient = __esm({
|
|
47717
48267
|
"src/aiClient.ts"() {
|
|
47718
48268
|
"use strict";
|
|
48269
|
+
init_slashTrim();
|
|
47719
48270
|
init_api();
|
|
47720
48271
|
AiError = class extends Error {
|
|
47721
48272
|
};
|
|
@@ -47920,7 +48471,7 @@ var init_aiClient = __esm({
|
|
|
47920
48471
|
throw new AiConfigError("AI URL must be an http or https URL");
|
|
47921
48472
|
}
|
|
47922
48473
|
if (url.protocol !== "http:" && url.protocol !== "https:") throw new AiConfigError("AI URL must be an http or https URL");
|
|
47923
|
-
const path10 = url.pathname
|
|
48474
|
+
const path10 = rtrimSlashes(url.pathname);
|
|
47924
48475
|
if (path10 === "" || path10 === "/v1" || path10 === "/api" || path10 === "/v1beta/openai") {
|
|
47925
48476
|
const suffix = provider === "anthropic" ? "/messages" : capability === "embed" ? "/embeddings" : "/chat/completions";
|
|
47926
48477
|
url.pathname = (path10 || "/v1") + suffix;
|
|
@@ -50290,6 +50841,7 @@ __export(index_exports, {
|
|
|
50290
50841
|
backgroundTaskCount: () => backgroundTaskCount,
|
|
50291
50842
|
buildEnvelope: () => buildEnvelope,
|
|
50292
50843
|
buildFrame: () => buildFrame,
|
|
50844
|
+
buildSeedFieldMap: () => buildSeedFieldMap,
|
|
50293
50845
|
buildSessionCookie: () => buildSessionCookie,
|
|
50294
50846
|
cacheBackendStats: () => cacheBackendStats,
|
|
50295
50847
|
cacheClear: () => cacheClear,
|
|
@@ -50395,6 +50947,7 @@ __export(index_exports, {
|
|
|
50395
50947
|
parseFrame: () => parseFrame,
|
|
50396
50948
|
parseLineStream: () => parseLineStream,
|
|
50397
50949
|
parseMultipart: () => parseMultipart,
|
|
50950
|
+
parseSeedRequest: () => parseSeedRequest,
|
|
50398
50951
|
parseSseStream: () => parseSseStream,
|
|
50399
50952
|
parseUpgradeHeaders: () => parseUpgradeHeaders,
|
|
50400
50953
|
patch: () => patch,
|
|
@@ -50679,6 +51232,7 @@ export {
|
|
|
50679
51232
|
backgroundTaskCount,
|
|
50680
51233
|
buildEnvelope,
|
|
50681
51234
|
buildFrame,
|
|
51235
|
+
buildSeedFieldMap,
|
|
50682
51236
|
buildSessionCookie,
|
|
50683
51237
|
cacheBackendStats,
|
|
50684
51238
|
cacheClear,
|
|
@@ -50784,6 +51338,7 @@ export {
|
|
|
50784
51338
|
parseFrame,
|
|
50785
51339
|
parseLineStream,
|
|
50786
51340
|
parseMultipart,
|
|
51341
|
+
parseSeedRequest,
|
|
50787
51342
|
parseSseStream,
|
|
50788
51343
|
parseUpgradeHeaders,
|
|
50789
51344
|
patch,
|