tina4-nodejs 3.13.100 → 3.13.101
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 +3 -3
- package/README.md +16 -0
- package/package.json +1 -1
- package/packages/cli/dist/bin.js +455 -652
- package/packages/cli/src/bin.ts +0 -6
- package/packages/core/dist/index.js +444 -510
- package/packages/core/src/aiClient.ts +288 -0
- package/packages/core/src/devAdmin.ts +1 -2
- package/packages/core/src/index.ts +2 -0
- package/packages/core/src/metrics.ts +79 -631
- package/packages/orm/dist/index.js +445 -517
- package/types/core/src/aiClient.d.ts +66 -0
- package/types/core/src/index.d.ts +2 -0
- package/types/core/src/metrics.d.ts +0 -35
- package/packages/cli/src/commands/metrics.ts +0 -160
- package/types/cli/src/commands/metrics.d.ts +0 -6
|
@@ -8819,14 +8819,14 @@ async function discoverRoutes(routesDir) {
|
|
|
8819
8819
|
const currentMtime = statSync5(filePath).mtimeMs;
|
|
8820
8820
|
if (_seenFiles.has(filePath) && _seenMtimes.get(filePath) === currentMtime) continue;
|
|
8821
8821
|
const method = name.toUpperCase();
|
|
8822
|
-
const
|
|
8823
|
-
const pattern = filePathToPattern(
|
|
8822
|
+
const relativePath2 = relative(routesDir, filePath);
|
|
8823
|
+
const pattern = filePathToPattern(relativePath2);
|
|
8824
8824
|
try {
|
|
8825
8825
|
const moduleUrl = `file://${filePath}?t=${currentMtime}`;
|
|
8826
8826
|
const mod = await import(moduleUrl);
|
|
8827
8827
|
const handler = mod.default ?? mod.handler;
|
|
8828
8828
|
if (typeof handler !== "function") {
|
|
8829
|
-
console.warn(` Warning: ${
|
|
8829
|
+
console.warn(` Warning: ${relativePath2} does not export a handler function, skipping`);
|
|
8830
8830
|
continue;
|
|
8831
8831
|
}
|
|
8832
8832
|
const meta = mod.meta;
|
|
@@ -8838,7 +8838,7 @@ async function discoverRoutes(routesDir) {
|
|
|
8838
8838
|
_seenMtimes.set(filePath, currentMtime);
|
|
8839
8839
|
registeredFromThisScan++;
|
|
8840
8840
|
} catch (err) {
|
|
8841
|
-
console.error(` Error loading route ${
|
|
8841
|
+
console.error(` Error loading route ${relativePath2}:`, err);
|
|
8842
8842
|
recordBrokenImport(filePath, err);
|
|
8843
8843
|
}
|
|
8844
8844
|
}
|
|
@@ -8872,8 +8872,8 @@ function recordBrokenImport(filePath, error) {
|
|
|
8872
8872
|
} catch {
|
|
8873
8873
|
}
|
|
8874
8874
|
}
|
|
8875
|
-
function filePathToPattern(
|
|
8876
|
-
const parts =
|
|
8875
|
+
function filePathToPattern(relativePath2) {
|
|
8876
|
+
const parts = relativePath2.replace(/\\/g, "/").split("/").slice(0, -1);
|
|
8877
8877
|
const urlParts = parts.map((part) => {
|
|
8878
8878
|
if (part.startsWith("[...") && part.endsWith("]")) {
|
|
8879
8879
|
const name = part.slice(4, -1);
|
|
@@ -12110,489 +12110,127 @@ import * as fs3 from "node:fs";
|
|
|
12110
12110
|
import * as path2 from "node:path";
|
|
12111
12111
|
import { spawnSync } from "node:child_process";
|
|
12112
12112
|
import { fileURLToPath } from "node:url";
|
|
12113
|
-
function
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
if (entry.isDirectory()) {
|
|
12120
|
-
if (!exclude.includes(entry.name)) {
|
|
12121
|
-
results.push(...walkFiles(fullPath, extensions, exclude));
|
|
12122
|
-
}
|
|
12123
|
-
} else if (entry.isFile()) {
|
|
12124
|
-
const ext = path2.extname(entry.name);
|
|
12125
|
-
if (extensions.includes(ext) && !entry.name.endsWith(".d.ts")) {
|
|
12126
|
-
results.push(fullPath);
|
|
12127
|
-
}
|
|
12128
|
-
}
|
|
12129
|
-
}
|
|
12130
|
-
return results;
|
|
12131
|
-
}
|
|
12132
|
-
function readFileSafe(filePath) {
|
|
12133
|
-
try {
|
|
12134
|
-
return fs3.readFileSync(filePath, "utf-8");
|
|
12135
|
-
} catch {
|
|
12136
|
-
return null;
|
|
12137
|
-
}
|
|
12138
|
-
}
|
|
12139
|
-
function relativePath(filePath, root = ".") {
|
|
12140
|
-
return path2.relative(root, filePath);
|
|
12141
|
-
}
|
|
12142
|
-
function countLines(source) {
|
|
12143
|
-
const lines = source.split("\n");
|
|
12144
|
-
let loc = 0;
|
|
12145
|
-
let blank = 0;
|
|
12146
|
-
let comment = 0;
|
|
12147
|
-
let inBlockComment = false;
|
|
12148
|
-
for (const line of lines) {
|
|
12149
|
-
const stripped = line.trim();
|
|
12150
|
-
if (!stripped) {
|
|
12151
|
-
blank++;
|
|
12152
|
-
continue;
|
|
12153
|
-
}
|
|
12154
|
-
if (inBlockComment) {
|
|
12155
|
-
comment++;
|
|
12156
|
-
if (stripped.includes("*/")) {
|
|
12157
|
-
inBlockComment = false;
|
|
12158
|
-
}
|
|
12159
|
-
continue;
|
|
12160
|
-
}
|
|
12161
|
-
if (stripped.startsWith("/*")) {
|
|
12162
|
-
comment++;
|
|
12163
|
-
if (!stripped.includes("*/") || stripped.endsWith("/*")) {
|
|
12164
|
-
inBlockComment = true;
|
|
12165
|
-
}
|
|
12166
|
-
continue;
|
|
12167
|
-
}
|
|
12168
|
-
if (stripped.startsWith("//")) {
|
|
12169
|
-
comment++;
|
|
12170
|
-
continue;
|
|
12171
|
-
}
|
|
12172
|
-
loc++;
|
|
12173
|
-
}
|
|
12174
|
-
return { loc, blank, comment };
|
|
12175
|
-
}
|
|
12176
|
-
function stripLiterals(source) {
|
|
12177
|
-
const out = [];
|
|
12178
|
-
const n = source.length;
|
|
12179
|
-
let i = 0;
|
|
12180
|
-
let prevSignificant = "";
|
|
12181
|
-
let prevWord = "";
|
|
12182
|
-
const regexKeywords = /* @__PURE__ */ new Set([
|
|
12183
|
-
"return",
|
|
12184
|
-
"typeof",
|
|
12185
|
-
"instanceof",
|
|
12186
|
-
"in",
|
|
12187
|
-
"of",
|
|
12188
|
-
"new",
|
|
12189
|
-
"delete",
|
|
12190
|
-
"void",
|
|
12191
|
-
"throw",
|
|
12192
|
-
"case",
|
|
12193
|
-
"do",
|
|
12194
|
-
"else",
|
|
12195
|
-
"yield",
|
|
12196
|
-
"await"
|
|
12197
|
-
]);
|
|
12198
|
-
function prevEndsExpression() {
|
|
12199
|
-
if (prevSignificant === "") return false;
|
|
12200
|
-
if (/[A-Za-z0-9_$]/.test(prevSignificant)) {
|
|
12201
|
-
return !regexKeywords.has(prevWord);
|
|
12202
|
-
}
|
|
12203
|
-
if (prevSignificant === ")" || prevSignificant === "]") return true;
|
|
12204
|
-
if (prevSignificant === ".") return true;
|
|
12205
|
-
return false;
|
|
12113
|
+
function containsTypeScript(directory) {
|
|
12114
|
+
if (!fs3.existsSync(directory) || !fs3.statSync(directory).isDirectory()) return false;
|
|
12115
|
+
for (const entry of fs3.readdirSync(directory, { withFileTypes: true })) {
|
|
12116
|
+
if (["node_modules", ".git", "dist", "build"].includes(entry.name)) continue;
|
|
12117
|
+
const target = path2.join(directory, entry.name);
|
|
12118
|
+
if (entry.isDirectory() ? containsTypeScript(target) : /\.[cm]?[jt]sx?$/.test(entry.name)) return true;
|
|
12206
12119
|
}
|
|
12207
|
-
|
|
12208
|
-
const ch = source[i];
|
|
12209
|
-
const next = i + 1 < n ? source[i + 1] : "";
|
|
12210
|
-
if (ch === "/" && next === "/") {
|
|
12211
|
-
out.push("//");
|
|
12212
|
-
i += 2;
|
|
12213
|
-
while (i < n && source[i] !== "\n") {
|
|
12214
|
-
out.push(" ");
|
|
12215
|
-
i++;
|
|
12216
|
-
}
|
|
12217
|
-
continue;
|
|
12218
|
-
}
|
|
12219
|
-
if (ch === "/" && next === "*") {
|
|
12220
|
-
out.push("/*");
|
|
12221
|
-
i += 2;
|
|
12222
|
-
while (i < n && !(source[i] === "*" && source[i + 1] === "/")) {
|
|
12223
|
-
out.push(source[i] === "\n" ? "\n" : " ");
|
|
12224
|
-
i++;
|
|
12225
|
-
}
|
|
12226
|
-
if (i < n) {
|
|
12227
|
-
out.push("*/");
|
|
12228
|
-
i += 2;
|
|
12229
|
-
}
|
|
12230
|
-
continue;
|
|
12231
|
-
}
|
|
12232
|
-
if (ch === '"' || ch === "'") {
|
|
12233
|
-
const quote = ch;
|
|
12234
|
-
out.push(quote);
|
|
12235
|
-
i++;
|
|
12236
|
-
while (i < n && source[i] !== quote) {
|
|
12237
|
-
if (source[i] === "\\" && i + 1 < n) {
|
|
12238
|
-
out.push(" ");
|
|
12239
|
-
i += 2;
|
|
12240
|
-
continue;
|
|
12241
|
-
}
|
|
12242
|
-
if (source[i] === "\n") {
|
|
12243
|
-
out.push("\n");
|
|
12244
|
-
i++;
|
|
12245
|
-
break;
|
|
12246
|
-
}
|
|
12247
|
-
out.push(" ");
|
|
12248
|
-
i++;
|
|
12249
|
-
}
|
|
12250
|
-
if (i < n && source[i] === quote) {
|
|
12251
|
-
out.push(quote);
|
|
12252
|
-
i++;
|
|
12253
|
-
}
|
|
12254
|
-
prevSignificant = quote;
|
|
12255
|
-
prevWord = "";
|
|
12256
|
-
continue;
|
|
12257
|
-
}
|
|
12258
|
-
if (ch === "`") {
|
|
12259
|
-
out.push("`");
|
|
12260
|
-
i++;
|
|
12261
|
-
while (i < n && source[i] !== "`") {
|
|
12262
|
-
if (source[i] === "\\" && i + 1 < n) {
|
|
12263
|
-
out.push(source[i + 1] === "\n" ? " \n" : " ");
|
|
12264
|
-
i += 2;
|
|
12265
|
-
continue;
|
|
12266
|
-
}
|
|
12267
|
-
if (source[i] === "$" && source[i + 1] === "{") {
|
|
12268
|
-
out.push("${");
|
|
12269
|
-
i += 2;
|
|
12270
|
-
let depth = 1;
|
|
12271
|
-
const exprStart = i;
|
|
12272
|
-
while (i < n && depth > 0) {
|
|
12273
|
-
if (source[i] === "{") depth++;
|
|
12274
|
-
else if (source[i] === "}") depth--;
|
|
12275
|
-
if (depth === 0) break;
|
|
12276
|
-
i++;
|
|
12277
|
-
}
|
|
12278
|
-
out.push(stripLiterals(source.slice(exprStart, i)));
|
|
12279
|
-
if (i < n && source[i] === "}") {
|
|
12280
|
-
out.push("}");
|
|
12281
|
-
i++;
|
|
12282
|
-
}
|
|
12283
|
-
continue;
|
|
12284
|
-
}
|
|
12285
|
-
out.push(source[i] === "\n" ? "\n" : " ");
|
|
12286
|
-
i++;
|
|
12287
|
-
}
|
|
12288
|
-
if (i < n && source[i] === "`") {
|
|
12289
|
-
out.push("`");
|
|
12290
|
-
i++;
|
|
12291
|
-
}
|
|
12292
|
-
prevSignificant = "`";
|
|
12293
|
-
prevWord = "";
|
|
12294
|
-
continue;
|
|
12295
|
-
}
|
|
12296
|
-
if (ch === "/" && !prevEndsExpression()) {
|
|
12297
|
-
let j = i + 1;
|
|
12298
|
-
let ok = false;
|
|
12299
|
-
let inClass = false;
|
|
12300
|
-
while (j < n) {
|
|
12301
|
-
const c = source[j];
|
|
12302
|
-
if (c === "\\") {
|
|
12303
|
-
j += 2;
|
|
12304
|
-
continue;
|
|
12305
|
-
}
|
|
12306
|
-
if (c === "\n") break;
|
|
12307
|
-
if (c === "[") inClass = true;
|
|
12308
|
-
else if (c === "]") inClass = false;
|
|
12309
|
-
else if (c === "/" && !inClass) {
|
|
12310
|
-
ok = true;
|
|
12311
|
-
break;
|
|
12312
|
-
}
|
|
12313
|
-
j++;
|
|
12314
|
-
}
|
|
12315
|
-
if (ok) {
|
|
12316
|
-
out.push("/");
|
|
12317
|
-
for (let k = i + 1; k < j; k++) out.push(" ");
|
|
12318
|
-
out.push("/");
|
|
12319
|
-
i = j + 1;
|
|
12320
|
-
while (i < n && /[a-z]/i.test(source[i])) {
|
|
12321
|
-
out.push(source[i]);
|
|
12322
|
-
i++;
|
|
12323
|
-
}
|
|
12324
|
-
prevSignificant = "/";
|
|
12325
|
-
prevWord = "";
|
|
12326
|
-
continue;
|
|
12327
|
-
}
|
|
12328
|
-
}
|
|
12329
|
-
out.push(ch);
|
|
12330
|
-
if (!/\s/.test(ch)) {
|
|
12331
|
-
prevSignificant = ch;
|
|
12332
|
-
if (/[A-Za-z0-9_$]/.test(ch)) {
|
|
12333
|
-
prevWord = /[A-Za-z0-9_$]/.test(source[i - 1] ?? "") ? prevWord + ch : ch;
|
|
12334
|
-
} else {
|
|
12335
|
-
prevWord = "";
|
|
12336
|
-
}
|
|
12337
|
-
}
|
|
12338
|
-
i++;
|
|
12339
|
-
}
|
|
12340
|
-
return out.join("");
|
|
12341
|
-
}
|
|
12342
|
-
function countClassesQuick(source) {
|
|
12343
|
-
const matches = source.match(
|
|
12344
|
-
/(?:^|\n)\s*(?:export\s+)?(?:abstract\s+)?class\s+\w+/g
|
|
12345
|
-
);
|
|
12346
|
-
return matches ? matches.length : 0;
|
|
12347
|
-
}
|
|
12348
|
-
function countFunctionsQuick(source) {
|
|
12349
|
-
const clean = stripLiterals(source);
|
|
12350
|
-
let count = 0;
|
|
12351
|
-
const funcDecls = clean.match(
|
|
12352
|
-
/(?:^|\n)\s*(?:export\s+)?(?:async\s+)?function\s+\w+\s*\(/g
|
|
12353
|
-
);
|
|
12354
|
-
if (funcDecls) count += funcDecls.length;
|
|
12355
|
-
const methods = clean.match(
|
|
12356
|
-
/(?:^|\n)\s*(?:public\s+|private\s+|protected\s+)?(?:static\s+)?(?:async\s+)?(?:get\s+|set\s+)?\w+\s*\([^)]*\)\s*(?::\s*\S+)?\s*\{/g
|
|
12357
|
-
);
|
|
12358
|
-
if (methods) count += methods.length;
|
|
12359
|
-
const arrows = clean.match(
|
|
12360
|
-
/(?:^|\n)\s*(?:export\s+)?(?:const|let|var)\s+\w+\s*=\s*(?:async\s+)?\(/g
|
|
12361
|
-
);
|
|
12362
|
-
if (arrows) count += arrows.length;
|
|
12363
|
-
return count;
|
|
12364
|
-
}
|
|
12365
|
-
function resolveRoot(root = "src") {
|
|
12366
|
-
const rootPath = path2.resolve(root);
|
|
12367
|
-
if (fs3.existsSync(rootPath) && walkFiles(rootPath, [".ts", ".js"]).length > 0) {
|
|
12368
|
-
_lastScanRoot = rootPath;
|
|
12369
|
-
return root;
|
|
12370
|
-
}
|
|
12371
|
-
const fwDir = path2.resolve(path2.dirname(new URL(import.meta.url).pathname));
|
|
12372
|
-
_lastScanRoot = fwDir;
|
|
12373
|
-
return fwDir;
|
|
12374
|
-
}
|
|
12375
|
-
function quickMetrics(root = "src") {
|
|
12376
|
-
root = resolveRoot(root);
|
|
12377
|
-
const rootPath = path2.resolve(root);
|
|
12378
|
-
if (!fs3.existsSync(rootPath)) {
|
|
12379
|
-
return { error: `Directory not found: ${root}` };
|
|
12380
|
-
}
|
|
12381
|
-
const tsFiles = walkFiles(rootPath, [".ts", ".js"]);
|
|
12382
|
-
const twigFiles = walkFiles(rootPath, [".twig", ".html"]);
|
|
12383
|
-
const migrationsDir = path2.resolve("migrations");
|
|
12384
|
-
const migrationFiles = [
|
|
12385
|
-
...walkFiles(migrationsDir, [".sql"]),
|
|
12386
|
-
...walkFiles(migrationsDir, [".ts"])
|
|
12387
|
-
];
|
|
12388
|
-
const scssFiles = walkFiles(rootPath, [".scss", ".css"]);
|
|
12389
|
-
let totalLoc = 0;
|
|
12390
|
-
let totalBlank = 0;
|
|
12391
|
-
let totalComment = 0;
|
|
12392
|
-
let totalClasses = 0;
|
|
12393
|
-
let totalFunctions = 0;
|
|
12394
|
-
const fileDetails = [];
|
|
12395
|
-
for (const f of tsFiles) {
|
|
12396
|
-
const source = readFileSafe(f);
|
|
12397
|
-
if (source === null) continue;
|
|
12398
|
-
const counts = countLines(source);
|
|
12399
|
-
const classes = countClassesQuick(source);
|
|
12400
|
-
const functions = countFunctionsQuick(source);
|
|
12401
|
-
totalLoc += counts.loc;
|
|
12402
|
-
totalBlank += counts.blank;
|
|
12403
|
-
totalComment += counts.comment;
|
|
12404
|
-
totalClasses += classes;
|
|
12405
|
-
totalFunctions += functions;
|
|
12406
|
-
fileDetails.push({
|
|
12407
|
-
path: relativePath(f, rootPath),
|
|
12408
|
-
loc: counts.loc,
|
|
12409
|
-
blank: counts.blank,
|
|
12410
|
-
comment: counts.comment,
|
|
12411
|
-
classes,
|
|
12412
|
-
functions
|
|
12413
|
-
});
|
|
12414
|
-
}
|
|
12415
|
-
fileDetails.sort((a, b) => b.loc - a.loc);
|
|
12416
|
-
let routeCount = 0;
|
|
12417
|
-
let ormCount = 0;
|
|
12418
|
-
for (const f of tsFiles) {
|
|
12419
|
-
const source = readFileSafe(f);
|
|
12420
|
-
if (source === null) continue;
|
|
12421
|
-
const routes = source.match(
|
|
12422
|
-
/(?:router\s*\.\s*(?:get|post|put|delete|patch|any)\s*\(|@(?:get|post|put|delete|patch)\s*\()/g
|
|
12423
|
-
);
|
|
12424
|
-
if (routes) routeCount += routes.length;
|
|
12425
|
-
const orms = source.match(
|
|
12426
|
-
/class\s+\w+\s+extends\s+(?:ORM|Model)\b/g
|
|
12427
|
-
);
|
|
12428
|
-
if (orms) ormCount += orms.length;
|
|
12429
|
-
}
|
|
12430
|
-
const breakdown = {
|
|
12431
|
-
typescript: tsFiles.filter((f) => f.endsWith(".ts")).length,
|
|
12432
|
-
javascript: tsFiles.filter((f) => f.endsWith(".js")).length,
|
|
12433
|
-
templates: twigFiles.length,
|
|
12434
|
-
migrations: migrationFiles.length,
|
|
12435
|
-
stylesheets: scssFiles.length
|
|
12436
|
-
};
|
|
12437
|
-
return {
|
|
12438
|
-
file_count: tsFiles.length,
|
|
12439
|
-
total_loc: totalLoc,
|
|
12440
|
-
total_blank: totalBlank,
|
|
12441
|
-
total_comment: totalComment,
|
|
12442
|
-
lloc: totalLoc,
|
|
12443
|
-
classes: totalClasses,
|
|
12444
|
-
functions: totalFunctions,
|
|
12445
|
-
route_count: routeCount,
|
|
12446
|
-
orm_count: ormCount,
|
|
12447
|
-
template_count: twigFiles.length,
|
|
12448
|
-
migration_count: migrationFiles.length,
|
|
12449
|
-
avg_file_size: tsFiles.length > 0 ? Math.round(totalLoc / tsFiles.length * 10) / 10 : 0,
|
|
12450
|
-
largest_files: fileDetails.slice(0, 10),
|
|
12451
|
-
breakdown
|
|
12452
|
-
};
|
|
12120
|
+
return false;
|
|
12453
12121
|
}
|
|
12454
|
-
function
|
|
12455
|
-
const resolved =
|
|
12456
|
-
const
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
return [resolved, scanningFramework ? "framework" : "project"];
|
|
12122
|
+
function resolveTarget(root = "src") {
|
|
12123
|
+
const resolved = containsTypeScript(root) ? path2.resolve(root) : path2.dirname(fileURLToPath(import.meta.url));
|
|
12124
|
+
const mode = containsTypeScript(root) ? "project" : "framework";
|
|
12125
|
+
lastScanRoot = resolved;
|
|
12126
|
+
return [resolved, mode];
|
|
12460
12127
|
}
|
|
12461
12128
|
function enginePath() {
|
|
12462
|
-
const names = process.platform === "win32" ? ["tina4.exe", "tina4
|
|
12463
|
-
for (const
|
|
12464
|
-
if (!dir) continue;
|
|
12129
|
+
const names = process.platform === "win32" ? ["tina4.exe", "tina4"] : ["tina4"];
|
|
12130
|
+
for (const directory of (process.env.PATH || "").split(path2.delimiter)) {
|
|
12465
12131
|
for (const name of names) {
|
|
12466
|
-
const candidate = path2.join(
|
|
12132
|
+
const candidate = path2.join(directory, name);
|
|
12467
12133
|
try {
|
|
12468
|
-
if (!fs3.statSync(candidate).isFile()) continue;
|
|
12469
12134
|
fs3.accessSync(candidate, fs3.constants.X_OK);
|
|
12135
|
+
if (!fs3.statSync(candidate).isFile()) continue;
|
|
12136
|
+
const descriptor = fs3.openSync(candidate, "r");
|
|
12137
|
+
const header = Buffer.alloc(2);
|
|
12138
|
+
fs3.readSync(descriptor, header, 0, 2, 0);
|
|
12139
|
+
fs3.closeSync(descriptor);
|
|
12140
|
+
if (header.toString("latin1") !== "#!") return candidate;
|
|
12470
12141
|
} catch {
|
|
12471
12142
|
continue;
|
|
12472
12143
|
}
|
|
12473
|
-
try {
|
|
12474
|
-
const fd = fs3.openSync(candidate, "r");
|
|
12475
|
-
const buf = Buffer.alloc(2);
|
|
12476
|
-
fs3.readSync(fd, buf, 0, 2, 0);
|
|
12477
|
-
fs3.closeSync(fd);
|
|
12478
|
-
if (buf.toString("latin1") === "#!") continue;
|
|
12479
|
-
} catch {
|
|
12480
|
-
}
|
|
12481
|
-
return candidate;
|
|
12482
12144
|
}
|
|
12483
12145
|
}
|
|
12484
12146
|
return null;
|
|
12485
12147
|
}
|
|
12486
12148
|
function runEngine(target) {
|
|
12487
12149
|
const binary = enginePath();
|
|
12488
|
-
if (binary
|
|
12489
|
-
|
|
12490
|
-
}
|
|
12491
|
-
const proc = spawnSync(binary, ["metrics", "--path", target, "--json"], {
|
|
12150
|
+
if (!binary) throw new MetricsEngineError(`tina4 not found on PATH - ${INSTALL_HINT}`);
|
|
12151
|
+
const processResult = spawnSync(binary, ["metrics", "--path", target, "--json"], {
|
|
12492
12152
|
encoding: "utf8",
|
|
12493
|
-
timeout:
|
|
12153
|
+
timeout: 6e4,
|
|
12494
12154
|
maxBuffer: 64 * 1024 * 1024
|
|
12495
12155
|
});
|
|
12496
|
-
if (
|
|
12497
|
-
|
|
12498
|
-
if (err.code === "ETIMEDOUT") {
|
|
12499
|
-
throw new MetricsEngineError(`tina4 metrics timed out after ${TIMEOUT_MS / 1e3}s on ${target}`);
|
|
12500
|
-
}
|
|
12501
|
-
throw new MetricsEngineError(`could not run ${binary}: ${err.message}`);
|
|
12502
|
-
}
|
|
12503
|
-
if (proc.status !== 0) {
|
|
12504
|
-
const detail = (proc.stderr || proc.stdout || "").trim().split("\n")[0];
|
|
12505
|
-
throw new MetricsEngineError(
|
|
12506
|
-
`tina4 metrics failed on ${target}: ${detail || `exit code ${proc.status}`}`
|
|
12507
|
-
);
|
|
12156
|
+
if (processResult.error) {
|
|
12157
|
+
throw new MetricsEngineError(`could not run ${binary}: ${processResult.error.message}`);
|
|
12508
12158
|
}
|
|
12509
|
-
if (
|
|
12510
|
-
|
|
12159
|
+
if (processResult.status !== 0) {
|
|
12160
|
+
const detail = (processResult.stderr || processResult.stdout || "").trim().split("\n")[0];
|
|
12161
|
+
throw new MetricsEngineError(`tina4 metrics failed on ${target}: ${detail || processResult.status}`);
|
|
12511
12162
|
}
|
|
12512
|
-
let payload;
|
|
12513
12163
|
try {
|
|
12514
|
-
payload = JSON.parse(
|
|
12515
|
-
|
|
12516
|
-
|
|
12517
|
-
|
|
12518
|
-
|
|
12519
|
-
|
|
12164
|
+
const payload = JSON.parse(processResult.stdout);
|
|
12165
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
12166
|
+
throw new Error("non-object payload");
|
|
12167
|
+
}
|
|
12168
|
+
return payload;
|
|
12169
|
+
} catch (error) {
|
|
12170
|
+
throw new MetricsEngineError(`tina4 metrics returned unreadable JSON: ${error.message}`);
|
|
12520
12171
|
}
|
|
12521
|
-
return payload;
|
|
12522
12172
|
}
|
|
12523
|
-
function
|
|
12524
|
-
|
|
12525
|
-
|
|
12526
|
-
if (!ok) {
|
|
12527
|
-
throw new MetricsEngineError(
|
|
12528
|
-
`engine payload has no usable '${key}' - the installed tina4 CLI predates a field the dashboard renders. Update it: ${INSTALL_HINT}`
|
|
12529
|
-
);
|
|
12173
|
+
function requireArray(payload, key) {
|
|
12174
|
+
if (!Array.isArray(payload[key])) {
|
|
12175
|
+
throw new MetricsEngineError(`engine payload has no usable '${key}' - ${INSTALL_HINT}`);
|
|
12530
12176
|
}
|
|
12531
|
-
return
|
|
12177
|
+
return payload[key];
|
|
12532
12178
|
}
|
|
12533
12179
|
function fullAnalysis(root = "src") {
|
|
12534
|
-
const [resolved, scanMode] =
|
|
12180
|
+
const [resolved, scanMode] = resolveTarget(root);
|
|
12535
12181
|
const payload = runEngine(resolved);
|
|
12536
|
-
const summary =
|
|
12537
|
-
|
|
12538
|
-
|
|
12539
|
-
|
|
12540
|
-
|
|
12541
|
-
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
if (
|
|
12546
|
-
|
|
12547
|
-
|
|
12182
|
+
const summary = payload.summary;
|
|
12183
|
+
if (!summary || typeof summary !== "object" || Array.isArray(summary)) {
|
|
12184
|
+
throw new MetricsEngineError(`engine payload has no usable 'summary' - ${INSTALL_HINT}`);
|
|
12185
|
+
}
|
|
12186
|
+
const fileMetrics = requireArray(payload, "file_metrics");
|
|
12187
|
+
const functions = requireArray(payload, "most_complex_functions");
|
|
12188
|
+
const missingSummary = SUMMARY_KEYS.filter((key) => !(key in summary));
|
|
12189
|
+
if (missingSummary.length) throw new MetricsEngineError(`engine summary is missing ${missingSummary.join(", ")}`);
|
|
12190
|
+
const missingFile = fileMetrics.length ? FILE_KEYS.filter((key) => !(key in fileMetrics[0])) : [];
|
|
12191
|
+
if (missingFile.length) throw new MetricsEngineError(`engine file_metrics is missing ${missingFile.join(", ")}`);
|
|
12192
|
+
const missingFunction = functions.length ? FUNCTION_KEYS.filter((key) => !(key in functions[0])) : [];
|
|
12193
|
+
if (missingFunction.length) {
|
|
12194
|
+
throw new MetricsEngineError(`engine function metrics are missing ${missingFunction.join(", ")}`);
|
|
12548
12195
|
}
|
|
12549
|
-
|
|
12550
|
-
|
|
12551
|
-
|
|
12552
|
-
|
|
12553
|
-
|
|
12554
|
-
|
|
12555
|
-
|
|
12556
|
-
|
|
12557
|
-
|
|
12558
|
-
result.scan_mode = scanMode;
|
|
12559
|
-
result.scan_root = path2.resolve(resolved);
|
|
12560
|
-
result.engine = "tina4-cli";
|
|
12561
|
-
return result;
|
|
12196
|
+
return {
|
|
12197
|
+
...Object.fromEntries(SUMMARY_KEYS.map((key) => [key, summary[key]])),
|
|
12198
|
+
file_metrics: fileMetrics,
|
|
12199
|
+
most_complex_functions: functions.slice(0, 15),
|
|
12200
|
+
dependency_graph: payload.dependency_graph || {},
|
|
12201
|
+
scan_mode: scanMode,
|
|
12202
|
+
scan_root: resolved,
|
|
12203
|
+
engine: "tina4-cli"
|
|
12204
|
+
};
|
|
12562
12205
|
}
|
|
12563
12206
|
function fileDetail(filePath) {
|
|
12564
12207
|
if (!filePath) throw new MetricsEngineError("fileDetail needs a path");
|
|
12565
12208
|
let target = filePath;
|
|
12566
|
-
if (!fs3.existsSync(target) &&
|
|
12567
|
-
const candidate = path2.join(_lastScanRoot, filePath);
|
|
12568
|
-
if (fs3.existsSync(candidate)) target = candidate;
|
|
12569
|
-
}
|
|
12209
|
+
if (!fs3.existsSync(target) && lastScanRoot) target = path2.join(lastScanRoot, filePath);
|
|
12570
12210
|
if (!fs3.existsSync(target)) throw new MetricsEngineError(`no such file: ${filePath}`);
|
|
12571
12211
|
if (fs3.statSync(target).isDirectory()) throw new MetricsEngineError(`not a file: ${filePath}`);
|
|
12572
12212
|
const payload = runEngine(target);
|
|
12573
|
-
const
|
|
12574
|
-
if (!
|
|
12575
|
-
|
|
12576
|
-
|
|
12577
|
-
|
|
12213
|
+
const files = requireArray(payload, "file_metrics");
|
|
12214
|
+
if (!files.length) throw new MetricsEngineError(`engine reported no metrics for ${filePath}`);
|
|
12215
|
+
return {
|
|
12216
|
+
...files[0],
|
|
12217
|
+
function_count: files[0].functions || 0,
|
|
12218
|
+
functions: requireArray(payload, "most_complex_functions"),
|
|
12219
|
+
engine: "tina4-cli"
|
|
12220
|
+
};
|
|
12578
12221
|
}
|
|
12579
|
-
var
|
|
12222
|
+
var lastScanRoot, MetricsEngineError, INSTALL_HINT, SUMMARY_KEYS, FILE_KEYS, FUNCTION_KEYS;
|
|
12580
12223
|
var init_metrics = __esm({
|
|
12581
12224
|
"../core/src/metrics.ts"() {
|
|
12582
12225
|
"use strict";
|
|
12583
|
-
|
|
12226
|
+
lastScanRoot = "";
|
|
12584
12227
|
MetricsEngineError = class extends Error {
|
|
12585
12228
|
constructor(message) {
|
|
12586
12229
|
super(message);
|
|
12587
12230
|
this.name = "MetricsEngineError";
|
|
12588
12231
|
}
|
|
12589
12232
|
};
|
|
12590
|
-
|
|
12591
|
-
INSTALL_HINT = [
|
|
12592
|
-
"the tina4 CLI provides the metrics engine (ADR-0002). Install it with",
|
|
12593
|
-
" curl -fsSL https://tina4.com/install.sh | sh",
|
|
12594
|
-
"or see https://tina4.com/cli"
|
|
12595
|
-
].join("\n");
|
|
12233
|
+
INSTALL_HINT = "update the native tina4 CLI: https://tina4.com/cli";
|
|
12596
12234
|
SUMMARY_KEYS = ["files_analyzed", "total_functions", "avg_complexity", "avg_maintainability"];
|
|
12597
12235
|
FILE_KEYS = ["path", "loc", "avg_complexity", "maintainability", "has_tests"];
|
|
12598
12236
|
FUNCTION_KEYS = ["name", "file", "line", "complexity", "loc"];
|
|
@@ -12600,7 +12238,7 @@ var init_metrics = __esm({
|
|
|
12600
12238
|
});
|
|
12601
12239
|
|
|
12602
12240
|
// ../core/src/feedback.ts
|
|
12603
|
-
import { readFileSync as
|
|
12241
|
+
import { readFileSync as readFileSync10, existsSync as existsSync11 } from "node:fs";
|
|
12604
12242
|
import { dirname as dirname5, join as join13, resolve as resolve5 } from "node:path";
|
|
12605
12243
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
12606
12244
|
function feedbackEnabled() {
|
|
@@ -12741,7 +12379,7 @@ var init_feedback = __esm({
|
|
|
12741
12379
|
handleFeedbackWidgetJs = (_req, res) => {
|
|
12742
12380
|
let body;
|
|
12743
12381
|
if (existsSync11(WIDGET_BUNDLE_PATH)) {
|
|
12744
|
-
body =
|
|
12382
|
+
body = readFileSync10(WIDGET_BUNDLE_PATH);
|
|
12745
12383
|
} else {
|
|
12746
12384
|
body = "console.warn('tina4-feedback-widget bundle not built yet');";
|
|
12747
12385
|
}
|
|
@@ -12756,7 +12394,7 @@ var init_feedback = __esm({
|
|
|
12756
12394
|
});
|
|
12757
12395
|
|
|
12758
12396
|
// ../core/src/version.ts
|
|
12759
|
-
import { existsSync as existsSync12, readFileSync as
|
|
12397
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11 } from "node:fs";
|
|
12760
12398
|
import { dirname as dirname6, join as join14 } from "node:path";
|
|
12761
12399
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
12762
12400
|
function resolveFrameworkVersion() {
|
|
@@ -12765,7 +12403,7 @@ function resolveFrameworkVersion() {
|
|
|
12765
12403
|
const pkgPath = join14(dir, "package.json");
|
|
12766
12404
|
if (existsSync12(pkgPath)) {
|
|
12767
12405
|
try {
|
|
12768
|
-
const pkg = JSON.parse(
|
|
12406
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
12769
12407
|
if (typeof pkg.version === "string" && pkg.version) return pkg.version;
|
|
12770
12408
|
} catch {
|
|
12771
12409
|
}
|
|
@@ -15553,8 +15191,8 @@ __export(context_exports, {
|
|
|
15553
15191
|
fts5Supported: () => fts5Supported
|
|
15554
15192
|
});
|
|
15555
15193
|
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
15556
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as
|
|
15557
|
-
import { basename as basename4, dirname as dirname8, extname as
|
|
15194
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync13, readdirSync as readdirSync7, realpathSync as realpathSync5 } from "node:fs";
|
|
15195
|
+
import { basename as basename4, dirname as dirname8, extname as extname4, isAbsolute as isAbsolute4, join as join16, relative as relative3, resolve as resolve7 } from "node:path";
|
|
15558
15196
|
function fts5Supported() {
|
|
15559
15197
|
try {
|
|
15560
15198
|
const conn = new DatabaseSync2(":memory:");
|
|
@@ -15689,7 +15327,7 @@ var init_context = __esm({
|
|
|
15689
15327
|
}
|
|
15690
15328
|
// ── indexing ───────────────────────────────────────────────
|
|
15691
15329
|
static chunksFor(label, text) {
|
|
15692
|
-
const ext =
|
|
15330
|
+
const ext = extname4(label).toLowerCase();
|
|
15693
15331
|
const special = SPECIAL_FILES.has(basename4(label).toLowerCase());
|
|
15694
15332
|
if (CODE_EXTS.has(ext) || CONFIG_EXTS.has(ext) || special) {
|
|
15695
15333
|
return chunkCode(text, label);
|
|
@@ -15707,7 +15345,7 @@ var init_context = __esm({
|
|
|
15707
15345
|
const stored = label != null ? String(label) : String(file);
|
|
15708
15346
|
let text;
|
|
15709
15347
|
try {
|
|
15710
|
-
text =
|
|
15348
|
+
text = readFileSync13(file, "utf-8");
|
|
15711
15349
|
} catch {
|
|
15712
15350
|
return 0;
|
|
15713
15351
|
}
|
|
@@ -15728,7 +15366,7 @@ var init_context = __esm({
|
|
|
15728
15366
|
static eligible(filename) {
|
|
15729
15367
|
const fn = filename.toLowerCase();
|
|
15730
15368
|
if (fn.endsWith(".min.js")) return false;
|
|
15731
|
-
const ext =
|
|
15369
|
+
const ext = extname4(fn);
|
|
15732
15370
|
return CODE_EXTS.has(ext) || DOC_EXTS.has(ext) || CONFIG_EXTS.has(ext) || SPECIAL_FILES.has(fn);
|
|
15733
15371
|
}
|
|
15734
15372
|
/**
|
|
@@ -15757,7 +15395,7 @@ var init_context = __esm({
|
|
|
15757
15395
|
for (const fn of files) {
|
|
15758
15396
|
if (!_Context.eligible(fn)) continue;
|
|
15759
15397
|
const full = join16(dir, fn);
|
|
15760
|
-
const rel =
|
|
15398
|
+
const rel = relative3(rootAbs, full);
|
|
15761
15399
|
total += this.indexPath(full, rel);
|
|
15762
15400
|
}
|
|
15763
15401
|
for (const d of subdirs) walk2(join16(dir, d));
|
|
@@ -15778,7 +15416,7 @@ var init_context = __esm({
|
|
|
15778
15416
|
const raw = String(changedPath);
|
|
15779
15417
|
const abs = isAbsolute4(raw) ? raw : join16(process.cwd(), raw);
|
|
15780
15418
|
const resolved = realResolve(resolve7(abs));
|
|
15781
|
-
const rel =
|
|
15419
|
+
const rel = relative3(this.root, resolved);
|
|
15782
15420
|
if (rel === "" || rel.startsWith("..") || isAbsolute4(rel)) {
|
|
15783
15421
|
return -1;
|
|
15784
15422
|
}
|
|
@@ -17700,7 +17338,7 @@ var init_job = __esm({
|
|
|
17700
17338
|
});
|
|
17701
17339
|
|
|
17702
17340
|
// ../core/src/queueBackends/liteBackend.ts
|
|
17703
|
-
import { mkdirSync as mkdirSync10, readdirSync as readdirSync8, readFileSync as
|
|
17341
|
+
import { mkdirSync as mkdirSync10, readdirSync as readdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync8, unlinkSync as unlinkSync6, existsSync as existsSync15 } from "node:fs";
|
|
17704
17342
|
import { join as join17 } from "node:path";
|
|
17705
17343
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
17706
17344
|
var LiteBackend;
|
|
@@ -17800,7 +17438,7 @@ var init_liteBackend = __esm({
|
|
|
17800
17438
|
const filePath = join17(dir, filename);
|
|
17801
17439
|
let job;
|
|
17802
17440
|
try {
|
|
17803
|
-
job = JSON.parse(
|
|
17441
|
+
job = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
17804
17442
|
} catch {
|
|
17805
17443
|
continue;
|
|
17806
17444
|
}
|
|
@@ -17864,7 +17502,7 @@ var init_liteBackend = __esm({
|
|
|
17864
17502
|
const filePath = join17(reservedDir, filename);
|
|
17865
17503
|
let record;
|
|
17866
17504
|
try {
|
|
17867
|
-
record = JSON.parse(
|
|
17505
|
+
record = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
17868
17506
|
} catch {
|
|
17869
17507
|
continue;
|
|
17870
17508
|
}
|
|
@@ -17977,7 +17615,7 @@ var init_liteBackend = __esm({
|
|
|
17977
17615
|
let count = 0;
|
|
17978
17616
|
for (const file of files) {
|
|
17979
17617
|
try {
|
|
17980
|
-
const job = JSON.parse(
|
|
17618
|
+
const job = JSON.parse(readFileSync14(join17(scanDir, file), "utf-8"));
|
|
17981
17619
|
if (job.status === status2) count++;
|
|
17982
17620
|
} catch {
|
|
17983
17621
|
}
|
|
@@ -18034,7 +17672,7 @@ var init_liteBackend = __esm({
|
|
|
18034
17672
|
const files = readdirSync8(dir).filter((f) => f.endsWith(".queue-data")).sort();
|
|
18035
17673
|
for (const file of files) {
|
|
18036
17674
|
try {
|
|
18037
|
-
const job = JSON.parse(
|
|
17675
|
+
const job = JSON.parse(readFileSync14(join17(dir, file), "utf-8"));
|
|
18038
17676
|
const attempts = job.attempts || 0;
|
|
18039
17677
|
if (attempts > 0 && attempts < maxRetries) {
|
|
18040
17678
|
results.push(job);
|
|
@@ -18060,7 +17698,7 @@ var init_liteBackend = __esm({
|
|
|
18060
17698
|
const failedDir = join17(this.basePath, q, "failed");
|
|
18061
17699
|
const filePath = join17(failedDir, `${jobId}.queue-data`);
|
|
18062
17700
|
if (existsSync15(filePath)) {
|
|
18063
|
-
const job = JSON.parse(
|
|
17701
|
+
const job = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
18064
17702
|
job.status = "pending";
|
|
18065
17703
|
job.attempts = (job.attempts || 0) + 1;
|
|
18066
17704
|
job.error = void 0;
|
|
@@ -18084,7 +17722,7 @@ var init_liteBackend = __esm({
|
|
|
18084
17722
|
const files = readdirSync8(failedDir).filter((f) => f.endsWith(".queue-data")).sort();
|
|
18085
17723
|
for (const file of files) {
|
|
18086
17724
|
try {
|
|
18087
|
-
const job = JSON.parse(
|
|
17725
|
+
const job = JSON.parse(readFileSync14(join17(failedDir, file), "utf-8"));
|
|
18088
17726
|
if ((job.attempts || 0) >= maxRetries) {
|
|
18089
17727
|
job.status = "dead";
|
|
18090
17728
|
results.push(job);
|
|
@@ -18118,7 +17756,7 @@ var init_liteBackend = __esm({
|
|
|
18118
17756
|
const files = readdirSync8(dir).filter((f) => f.endsWith(".queue-data"));
|
|
18119
17757
|
for (const file of files) {
|
|
18120
17758
|
try {
|
|
18121
|
-
const job = JSON.parse(
|
|
17759
|
+
const job = JSON.parse(readFileSync14(join17(dir, file), "utf-8"));
|
|
18122
17760
|
if (job.status === status2) {
|
|
18123
17761
|
unlinkSync6(join17(dir, file));
|
|
18124
17762
|
count++;
|
|
@@ -18145,7 +17783,7 @@ var init_liteBackend = __esm({
|
|
|
18145
17783
|
for (const file of files) {
|
|
18146
17784
|
try {
|
|
18147
17785
|
const filePath = join17(failedDir, file);
|
|
18148
|
-
const job = JSON.parse(
|
|
17786
|
+
const job = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
18149
17787
|
if ((job.attempts || 0) >= maxRetries) {
|
|
18150
17788
|
continue;
|
|
18151
17789
|
}
|
|
@@ -18177,7 +17815,7 @@ var init_liteBackend = __esm({
|
|
|
18177
17815
|
const filePath = join17(dir, file);
|
|
18178
17816
|
let job;
|
|
18179
17817
|
try {
|
|
18180
|
-
job = JSON.parse(
|
|
17818
|
+
job = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
18181
17819
|
} catch {
|
|
18182
17820
|
continue;
|
|
18183
17821
|
}
|
|
@@ -19640,7 +19278,7 @@ function detectVersion(projectRoot3) {
|
|
|
19640
19278
|
}
|
|
19641
19279
|
return "0.0.0";
|
|
19642
19280
|
}
|
|
19643
|
-
function
|
|
19281
|
+
function relativePath(absPath, projectRoot3, frameworkRoots) {
|
|
19644
19282
|
const norm = path6.resolve(absPath);
|
|
19645
19283
|
for (const fw of frameworkRoots) {
|
|
19646
19284
|
const parent = path6.dirname(fw);
|
|
@@ -20105,7 +19743,7 @@ function buildEntriesForFile(absPath, source, fwRoots, projectRoot3, version, ou
|
|
|
20105
19743
|
} catch {
|
|
20106
19744
|
return;
|
|
20107
19745
|
}
|
|
20108
|
-
const rel =
|
|
19746
|
+
const rel = relativePath(absPath, projectRoot3, fwRoots);
|
|
20109
19747
|
for (const cls of parsed.classes) {
|
|
20110
19748
|
if (!cls.exported && source === "framework") {
|
|
20111
19749
|
continue;
|
|
@@ -20741,8 +20379,8 @@ ${end}
|
|
|
20741
20379
|
|
|
20742
20380
|
// ../core/src/devAdmin.ts
|
|
20743
20381
|
import { cpus as osCpus } from "node:os";
|
|
20744
|
-
import { readFileSync as
|
|
20745
|
-
import { join as join21, dirname as dirname10, resolve as resolve11, relative as
|
|
20382
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync19, readdirSync as readdirSync12, mkdirSync as mkdirSync13, copyFileSync, statSync as statSync14 } from "node:fs";
|
|
20383
|
+
import { join as join21, dirname as dirname10, resolve as resolve11, relative as relative7 } from "node:path";
|
|
20746
20384
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
20747
20385
|
import { timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
20748
20386
|
function escapeHtml(value) {
|
|
@@ -20861,7 +20499,7 @@ function readQueueDir(dir, topic, status2) {
|
|
|
20861
20499
|
for (const filename of readdirSync12(dir).sort()) {
|
|
20862
20500
|
if (!filename.endsWith(".queue-data")) continue;
|
|
20863
20501
|
try {
|
|
20864
|
-
jobs.push(mapQueueJob(JSON.parse(
|
|
20502
|
+
jobs.push(mapQueueJob(JSON.parse(readFileSync18(join21(dir, filename), "utf-8")), topic, status2));
|
|
20865
20503
|
} catch {
|
|
20866
20504
|
}
|
|
20867
20505
|
}
|
|
@@ -20980,7 +20618,7 @@ function resolveDevEnvVar(key) {
|
|
|
20980
20618
|
if (live !== void 0 && live !== "") return live;
|
|
20981
20619
|
const envPath = join21(process.cwd(), ".env");
|
|
20982
20620
|
if (!existsSync19(envPath)) return "";
|
|
20983
|
-
for (const line of
|
|
20621
|
+
for (const line of readFileSync18(envPath, "utf-8").split("\n")) {
|
|
20984
20622
|
const t = line.trim();
|
|
20985
20623
|
if (!t || t.startsWith("#") || !t.includes("=")) continue;
|
|
20986
20624
|
const eq = t.indexOf("=");
|
|
@@ -20990,7 +20628,7 @@ function resolveDevEnvVar(key) {
|
|
|
20990
20628
|
}
|
|
20991
20629
|
function upsertDevEnvVar(key, value) {
|
|
20992
20630
|
const envPath = join21(process.cwd(), ".env");
|
|
20993
|
-
const lines = existsSync19(envPath) ?
|
|
20631
|
+
const lines = existsSync19(envPath) ? readFileSync18(envPath, "utf-8").split("\n") : [];
|
|
20994
20632
|
let found = false;
|
|
20995
20633
|
const out = [];
|
|
20996
20634
|
for (const line of lines) {
|
|
@@ -21023,7 +20661,7 @@ function parseEnvFile() {
|
|
|
21023
20661
|
const envPath = join21(process.cwd(), ".env");
|
|
21024
20662
|
const result = {};
|
|
21025
20663
|
if (!existsSync19(envPath)) return result;
|
|
21026
|
-
const lines =
|
|
20664
|
+
const lines = readFileSync18(envPath, "utf-8").split("\n");
|
|
21027
20665
|
for (const line of lines) {
|
|
21028
20666
|
const trimmed = line.trim();
|
|
21029
20667
|
if (!trimmed || trimmed.startsWith("#") || !trimmed.includes("=")) continue;
|
|
@@ -21063,7 +20701,7 @@ function handleGalleryDeploy(router) {
|
|
|
21063
20701
|
const copied = [];
|
|
21064
20702
|
const allFiles = walkDirRecursive(gallerySrc);
|
|
21065
20703
|
for (const srcFile of allFiles) {
|
|
21066
|
-
const rel =
|
|
20704
|
+
const rel = relative7(gallerySrc, srcFile);
|
|
21067
20705
|
const dest = join21(projectSrc, rel);
|
|
21068
20706
|
mkdirSync13(dirname10(dest), { recursive: true });
|
|
21069
20707
|
copyFileSync(srcFile, dest);
|
|
@@ -21725,9 +21363,6 @@ var init_devAdmin = __esm({
|
|
|
21725
21363
|
{ method: "GET", pattern: "/__dev/api/gallery", handler: handleGalleryList },
|
|
21726
21364
|
{ method: "POST", pattern: "/__dev/api/gallery/deploy", handler: handleGalleryDeploy(router) },
|
|
21727
21365
|
// Metrics
|
|
21728
|
-
{ method: "GET", pattern: "/__dev/api/metrics", handler: (_req, res) => {
|
|
21729
|
-
res.json(quickMetrics());
|
|
21730
|
-
} },
|
|
21731
21366
|
// No fallback (ADR-0002): a missing or stale CLI is a 503 naming the
|
|
21732
21367
|
// install command, never zeros that read as a healthy codebase.
|
|
21733
21368
|
{ method: "GET", pattern: "/__dev/api/metrics/full", handler: (_req, res) => {
|
|
@@ -22536,7 +22171,7 @@ var init_devAdmin = __esm({
|
|
|
22536
22171
|
}
|
|
22537
22172
|
try {
|
|
22538
22173
|
const envPath = join21(process.cwd(), ".env");
|
|
22539
|
-
const lines = existsSync19(envPath) ?
|
|
22174
|
+
const lines = existsSync19(envPath) ? readFileSync18(envPath, "utf-8").split("\n") : [];
|
|
22540
22175
|
const keysFound = { TINA4_DATABASE_URL: false, TINA4_DATABASE_USERNAME: false, TINA4_DATABASE_PASSWORD: false };
|
|
22541
22176
|
const newLines = [];
|
|
22542
22177
|
for (const line of lines) {
|
|
@@ -22582,12 +22217,12 @@ var init_devAdmin = __esm({
|
|
|
22582
22217
|
const metaFile = join21(entryPath, "meta.json");
|
|
22583
22218
|
if (statSync14(entryPath).isDirectory() && existsSync19(metaFile)) {
|
|
22584
22219
|
try {
|
|
22585
|
-
const meta = JSON.parse(
|
|
22220
|
+
const meta = JSON.parse(readFileSync18(metaFile, "utf-8"));
|
|
22586
22221
|
meta.id = entry;
|
|
22587
22222
|
const srcDir = join21(entryPath, "src");
|
|
22588
22223
|
if (existsSync19(srcDir)) {
|
|
22589
22224
|
const allFiles = walkDirRecursive(srcDir);
|
|
22590
|
-
meta.files = allFiles.map((f) =>
|
|
22225
|
+
meta.files = allFiles.map((f) => relative7(srcDir, f));
|
|
22591
22226
|
}
|
|
22592
22227
|
const projectSrc = resolve11(process.cwd(), "src");
|
|
22593
22228
|
if (existsSync19(srcDir) && meta.files) {
|
|
@@ -22705,7 +22340,7 @@ var init_devAdmin = __esm({
|
|
|
22705
22340
|
for (const name of readdirSync12(target).sort()) {
|
|
22706
22341
|
if (devFilesHidden(name)) continue;
|
|
22707
22342
|
const full = join21(target, name);
|
|
22708
|
-
const entryRel =
|
|
22343
|
+
const entryRel = relative7(root, full).replace(/\\/g, "/");
|
|
22709
22344
|
if (isSecretPath(entryRel)) continue;
|
|
22710
22345
|
let isDir = false;
|
|
22711
22346
|
let size = null;
|
|
@@ -22750,7 +22385,7 @@ var init_devAdmin = __esm({
|
|
|
22750
22385
|
size
|
|
22751
22386
|
});
|
|
22752
22387
|
}
|
|
22753
|
-
res.json({ path:
|
|
22388
|
+
res.json({ path: relative7(root, target).replace(/\\/g, "/") || ".", branch, entries });
|
|
22754
22389
|
};
|
|
22755
22390
|
DEV_ADMIN_LANG_MAP = {
|
|
22756
22391
|
".py": "python",
|
|
@@ -22802,8 +22437,8 @@ var init_devAdmin = __esm({
|
|
|
22802
22437
|
return;
|
|
22803
22438
|
}
|
|
22804
22439
|
try {
|
|
22805
|
-
const content =
|
|
22806
|
-
const path8 =
|
|
22440
|
+
const content = readFileSync18(target, "utf-8");
|
|
22441
|
+
const path8 = relative7(root, target);
|
|
22807
22442
|
res.json({ path: path8, content, language: devAdminLanguage(path8), bytes: Buffer.byteLength(content, "utf-8") });
|
|
22808
22443
|
} catch (e) {
|
|
22809
22444
|
res.json({ error: e.message }, 500);
|
|
@@ -22825,10 +22460,10 @@ var init_devAdmin = __esm({
|
|
|
22825
22460
|
writeFileSync12(target, content, "utf-8");
|
|
22826
22461
|
try {
|
|
22827
22462
|
const { Plan: Plan2 } = await Promise.resolve().then(() => (init_plan(), plan_exports));
|
|
22828
|
-
Plan2.recordAction(existed ? "patched" : "created",
|
|
22463
|
+
Plan2.recordAction(existed ? "patched" : "created", relative7(root, target));
|
|
22829
22464
|
} catch {
|
|
22830
22465
|
}
|
|
22831
|
-
res.json({ ok: true, path:
|
|
22466
|
+
res.json({ ok: true, path: relative7(root, target), bytes: Buffer.byteLength(content, "utf-8") });
|
|
22832
22467
|
} catch (e) {
|
|
22833
22468
|
res.json({ error: e.message }, 500);
|
|
22834
22469
|
}
|
|
@@ -22848,7 +22483,7 @@ var init_devAdmin = __esm({
|
|
|
22848
22483
|
return;
|
|
22849
22484
|
}
|
|
22850
22485
|
try {
|
|
22851
|
-
const buf =
|
|
22486
|
+
const buf = readFileSync18(target);
|
|
22852
22487
|
const ext = target.slice(target.lastIndexOf(".") + 1).toLowerCase();
|
|
22853
22488
|
const mime = {
|
|
22854
22489
|
js: "application/javascript",
|
|
@@ -22890,7 +22525,7 @@ var init_devAdmin = __esm({
|
|
|
22890
22525
|
const { renameSync: renameSync3 } = await import("node:fs");
|
|
22891
22526
|
mkdirSync13(dirname10(dst), { recursive: true });
|
|
22892
22527
|
renameSync3(src, dst);
|
|
22893
|
-
res.json({ ok: true, from:
|
|
22528
|
+
res.json({ ok: true, from: relative7(root, src), to: relative7(root, dst) });
|
|
22894
22529
|
} catch (e) {
|
|
22895
22530
|
res.json({ error: e.message }, 500);
|
|
22896
22531
|
}
|
|
@@ -22911,7 +22546,7 @@ var init_devAdmin = __esm({
|
|
|
22911
22546
|
try {
|
|
22912
22547
|
const { rmSync } = await import("node:fs");
|
|
22913
22548
|
rmSync(target, { recursive: true, force: true });
|
|
22914
|
-
res.json({ ok: true, deleted:
|
|
22549
|
+
res.json({ ok: true, deleted: relative7(root, target) });
|
|
22915
22550
|
} catch (e) {
|
|
22916
22551
|
res.json({ error: e.message }, 500);
|
|
22917
22552
|
}
|
|
@@ -23245,7 +22880,7 @@ var init_devAdmin = __esm({
|
|
|
23245
22880
|
});
|
|
23246
22881
|
};
|
|
23247
22882
|
handleDevAdminJs = async (_req, res) => {
|
|
23248
|
-
const { readFileSync:
|
|
22883
|
+
const { readFileSync: readFileSync27, existsSync: existsSync27 } = await import("node:fs");
|
|
23249
22884
|
const { dirname: dirname15, join: join32, resolve: resolve20 } = await import("node:path");
|
|
23250
22885
|
const { fileURLToPath: fileURLToPath8 } = await import("node:url");
|
|
23251
22886
|
const dir = dirname15(fileURLToPath8(import.meta.url));
|
|
@@ -23261,7 +22896,7 @@ var init_devAdmin = __esm({
|
|
|
23261
22896
|
for (const jsPath of candidates) {
|
|
23262
22897
|
if (existsSync27(jsPath)) {
|
|
23263
22898
|
try {
|
|
23264
|
-
const content =
|
|
22899
|
+
const content = readFileSync27(jsPath, "utf-8");
|
|
23265
22900
|
res.raw.writeHead(200, { "Content-Type": "application/javascript; charset=utf-8", "Cache-Control": "no-cache" });
|
|
23266
22901
|
res.raw.end(content);
|
|
23267
22902
|
return;
|
|
@@ -23276,7 +22911,7 @@ var init_devAdmin = __esm({
|
|
|
23276
22911
|
});
|
|
23277
22912
|
|
|
23278
22913
|
// ../core/src/i18n.ts
|
|
23279
|
-
import { readFileSync as
|
|
22914
|
+
import { readFileSync as readFileSync19, readdirSync as readdirSync13, existsSync as existsSync20 } from "node:fs";
|
|
23280
22915
|
import { join as join22, resolve as resolve12 } from "node:path";
|
|
23281
22916
|
var I18n;
|
|
23282
22917
|
var init_i18n = __esm({
|
|
@@ -23373,7 +23008,7 @@ var init_i18n = __esm({
|
|
|
23373
23008
|
const filePath = join22(this._localeDir, `${locale}.json`);
|
|
23374
23009
|
if (existsSync20(filePath)) {
|
|
23375
23010
|
try {
|
|
23376
|
-
const raw =
|
|
23011
|
+
const raw = readFileSync19(filePath, "utf-8");
|
|
23377
23012
|
const data = JSON.parse(raw);
|
|
23378
23013
|
this._translations.set(locale, _I18n._flatten(data));
|
|
23379
23014
|
return;
|
|
@@ -23386,7 +23021,7 @@ var init_i18n = __esm({
|
|
|
23386
23021
|
const yamlPath = join22(this._localeDir, `${locale}${ext}`);
|
|
23387
23022
|
if (existsSync20(yamlPath)) {
|
|
23388
23023
|
try {
|
|
23389
|
-
const raw =
|
|
23024
|
+
const raw = readFileSync19(yamlPath, "utf-8");
|
|
23390
23025
|
const data = _I18n._parseSimpleYaml(raw);
|
|
23391
23026
|
this._translations.set(locale, _I18n._flatten(data));
|
|
23392
23027
|
return;
|
|
@@ -24249,8 +23884,8 @@ var init_docsAutoDiscovery = __esm({
|
|
|
24249
23884
|
// ../core/src/server.ts
|
|
24250
23885
|
import { createServer as createServer2 } from "node:http";
|
|
24251
23886
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
24252
|
-
import { resolve as resolve14, dirname as dirname11, join as join24, relative as
|
|
24253
|
-
import { existsSync as existsSync22, readdirSync as readdirSync14, readFileSync as
|
|
23887
|
+
import { resolve as resolve14, dirname as dirname11, join as join24, relative as relative8 } from "node:path";
|
|
23888
|
+
import { existsSync as existsSync22, readdirSync as readdirSync14, readFileSync as readFileSync21, statSync as statSync15 } from "node:fs";
|
|
24254
23889
|
import { isatty } from "node:tty";
|
|
24255
23890
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
24256
23891
|
import { execFileSync as execFileSync3, exec } from "node:child_process";
|
|
@@ -24474,7 +24109,7 @@ function getGalleryDeployedState() {
|
|
|
24474
24109
|
if (existsSync22(srcDir)) {
|
|
24475
24110
|
const files = walkGalleryFiles(srcDir);
|
|
24476
24111
|
const projectSrc = resolve14(process.cwd(), "src");
|
|
24477
|
-
state[entry] = files.every((f) => existsSync22(join24(projectSrc,
|
|
24112
|
+
state[entry] = files.every((f) => existsSync22(join24(projectSrc, relative8(srcDir, f))));
|
|
24478
24113
|
} else {
|
|
24479
24114
|
state[entry] = false;
|
|
24480
24115
|
}
|
|
@@ -24911,7 +24546,7 @@ function serveTemplateFallback(ctx) {
|
|
|
24911
24546
|
if ((ctx.req.method ?? "GET") !== "GET") return false;
|
|
24912
24547
|
const tplFile = resolveTemplate(ctx.pathname, ctx.templatesDir);
|
|
24913
24548
|
if (!tplFile) return false;
|
|
24914
|
-
const html = ctx.frondEngine ? ctx.frondEngine.render(tplFile, {}) :
|
|
24549
|
+
const html = ctx.frondEngine ? ctx.frondEngine.render(tplFile, {}) : readFileSync21(resolve14(ctx.templatesDir, tplFile), "utf-8");
|
|
24915
24550
|
ctx.res.raw.writeHead(200, void 0, { "Content-Type": "text/html; charset=utf-8" });
|
|
24916
24551
|
ctx.res.raw.end(html);
|
|
24917
24552
|
return true;
|
|
@@ -26206,7 +25841,7 @@ var init_mqttMessage = __esm({
|
|
|
26206
25841
|
import net2 from "node:net";
|
|
26207
25842
|
import tls from "node:tls";
|
|
26208
25843
|
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
26209
|
-
import { existsSync as existsSync24, readFileSync as
|
|
25844
|
+
import { existsSync as existsSync24, readFileSync as readFileSync22 } from "node:fs";
|
|
26210
25845
|
var MqttError, MqttTimeoutError, CONNECT, CONNACK, PUBLISH, PUBACK, SUBSCRIBE, SUBACK, PINGREQ, PINGRESP, DISCONNECT, PROTOCOL_LEVEL, DEFAULT_PORT, DEFAULT_TLS_PORT, DEFAULT_URL, DEFAULT_KEEPALIVE, SUBSCRIPTION_REFUSED, MAX_REMAINING_LENGTH, QOS2_REFUSED_MESSAGE, CONNACK_RETURN_CODES, Mqtt;
|
|
26211
25846
|
var init_mqtt = __esm({
|
|
26212
25847
|
"../core/src/mqtt.ts"() {
|
|
@@ -26671,7 +26306,7 @@ var init_mqtt = __esm({
|
|
|
26671
26306
|
servername: this.host,
|
|
26672
26307
|
rejectUnauthorized: this.tlsVerify
|
|
26673
26308
|
};
|
|
26674
|
-
if (this.tlsVerify && this.caFile) opts.ca =
|
|
26309
|
+
if (this.tlsVerify && this.caFile) opts.ca = readFileSync22(this.caFile);
|
|
26675
26310
|
sock = tls.connect(opts, () => settle(() => resolve20(sock)));
|
|
26676
26311
|
} else {
|
|
26677
26312
|
sock = net2.createConnection({ host: this.host, port: this.port }, () => settle(() => resolve20(sock)));
|
|
@@ -26892,7 +26527,7 @@ var init_mqtt = __esm({
|
|
|
26892
26527
|
|
|
26893
26528
|
// ../core/src/service.ts
|
|
26894
26529
|
import { readdirSync as readdirSync16, statSync as statSync16, watchFile, unwatchFile } from "node:fs";
|
|
26895
|
-
import { join as join26, extname as
|
|
26530
|
+
import { join as join26, extname as extname6 } from "node:path";
|
|
26896
26531
|
import { pathToFileURL } from "node:url";
|
|
26897
26532
|
function matchCronField(field, value) {
|
|
26898
26533
|
if (field === "*") return true;
|
|
@@ -27063,7 +26698,7 @@ var init_service = __esm({
|
|
|
27063
26698
|
return discovered;
|
|
27064
26699
|
}
|
|
27065
26700
|
for (const entry of entries) {
|
|
27066
|
-
const ext =
|
|
26701
|
+
const ext = extname6(entry);
|
|
27067
26702
|
if (ext !== ".ts" && ext !== ".js") continue;
|
|
27068
26703
|
const fullPath = join26(dir, entry);
|
|
27069
26704
|
const stat = statSync16(fullPath);
|
|
@@ -27179,7 +26814,7 @@ var init_service = __esm({
|
|
|
27179
26814
|
return;
|
|
27180
26815
|
}
|
|
27181
26816
|
for (const entry of entries) {
|
|
27182
|
-
const ext =
|
|
26817
|
+
const ext = extname6(entry);
|
|
27183
26818
|
if (ext !== ".ts" && ext !== ".js") continue;
|
|
27184
26819
|
const fullPath = join26(dir, entry);
|
|
27185
26820
|
if (watchedFiles.has(fullPath)) continue;
|
|
@@ -27882,7 +27517,7 @@ var init_api = __esm({
|
|
|
27882
27517
|
// ../core/src/messenger.ts
|
|
27883
27518
|
import net3 from "node:net";
|
|
27884
27519
|
import tls2 from "node:tls";
|
|
27885
|
-
import { readFileSync as
|
|
27520
|
+
import { readFileSync as readFileSync23 } from "node:fs";
|
|
27886
27521
|
import { basename as basename6 } from "node:path";
|
|
27887
27522
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
27888
27523
|
function tlsRejectUnauthorized() {
|
|
@@ -27979,7 +27614,7 @@ function buildMimeMessage(options) {
|
|
|
27979
27614
|
}
|
|
27980
27615
|
for (const filePath of options.attachments) {
|
|
27981
27616
|
const fileName = basename6(filePath);
|
|
27982
|
-
const fileData =
|
|
27617
|
+
const fileData = readFileSync23(filePath);
|
|
27983
27618
|
const base64Data = fileData.toString("base64");
|
|
27984
27619
|
lines.push("");
|
|
27985
27620
|
lines.push(`--${boundary}`);
|
|
@@ -29442,9 +29077,9 @@ var init_htmlElement = __esm({
|
|
|
29442
29077
|
});
|
|
29443
29078
|
|
|
29444
29079
|
// ../core/src/ai.ts
|
|
29445
|
-
import { existsSync as existsSync25, mkdirSync as mkdirSync16, writeFileSync as writeFileSync15, readFileSync as
|
|
29080
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync16, writeFileSync as writeFileSync15, readFileSync as readFileSync24 } from "node:fs";
|
|
29446
29081
|
import { homedir } from "node:os";
|
|
29447
|
-
import { join as join27, resolve as resolve16, relative as
|
|
29082
|
+
import { join as join27, resolve as resolve16, relative as relative9, dirname as dirname12 } from "node:path";
|
|
29448
29083
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
29449
29084
|
import { execSync, execFileSync as execFileSync4 } from "node:child_process";
|
|
29450
29085
|
import { createInterface } from "node:readline";
|
|
@@ -29452,7 +29087,7 @@ function readVersion() {
|
|
|
29452
29087
|
try {
|
|
29453
29088
|
const thisDir = dirname12(fileURLToPath7(import.meta.url));
|
|
29454
29089
|
const rootPkg = resolve16(thisDir, "..", "..", "..", "package.json");
|
|
29455
|
-
const pkg = JSON.parse(
|
|
29090
|
+
const pkg = JSON.parse(readFileSync24(rootPkg, "utf-8"));
|
|
29456
29091
|
return pkg.version ?? "0.0.0";
|
|
29457
29092
|
} catch {
|
|
29458
29093
|
return "0.0.0";
|
|
@@ -29675,7 +29310,7 @@ function writeOrMerge(contextPath, contextFile, frameworkGuide) {
|
|
|
29675
29310
|
writeFileSync15(contextPath, frameworkGuide.replace(/\s+$/, "") + "\n\n" + block + "\n", "utf-8");
|
|
29676
29311
|
return "Installed";
|
|
29677
29312
|
}
|
|
29678
|
-
const existing =
|
|
29313
|
+
const existing = readFileSync24(contextPath, "utf-8");
|
|
29679
29314
|
if (hasMarkers(existing, start2, end)) {
|
|
29680
29315
|
writeFileSync15(contextPath, replaceMarkerBlock(existing, block, start2, end), "utf-8");
|
|
29681
29316
|
return "Refreshed skill block in";
|
|
@@ -29699,7 +29334,7 @@ function installForTool(root, tool, context) {
|
|
|
29699
29334
|
const parentDir = dirname12(contextPath);
|
|
29700
29335
|
mkdirSync16(parentDir, { recursive: true });
|
|
29701
29336
|
const action = writeOrMerge(contextPath, tool.contextFile, context);
|
|
29702
|
-
const rel =
|
|
29337
|
+
const rel = relative9(root, contextPath);
|
|
29703
29338
|
created.push(rel);
|
|
29704
29339
|
console.log(` ${GREEN2}\u2713${RESET2} ${action} ${rel}`);
|
|
29705
29340
|
if (tool.name === "claude-code") {
|
|
@@ -30077,7 +29712,7 @@ function generateClaudeCodeContext() {
|
|
|
30077
29712
|
const repoRoot = resolve16(thisDir, "..", "..", "..");
|
|
30078
29713
|
const claudeMdPath = join27(repoRoot, "CLAUDE.md");
|
|
30079
29714
|
if (existsSync25(claudeMdPath)) {
|
|
30080
|
-
return
|
|
29715
|
+
return readFileSync24(claudeMdPath, "utf-8");
|
|
30081
29716
|
}
|
|
30082
29717
|
} catch {
|
|
30083
29718
|
}
|
|
@@ -30271,6 +29906,292 @@ export default class User {
|
|
|
30271
29906
|
}
|
|
30272
29907
|
});
|
|
30273
29908
|
|
|
29909
|
+
// ../core/src/aiClient.ts
|
|
29910
|
+
import http2 from "node:http";
|
|
29911
|
+
import https2 from "node:https";
|
|
29912
|
+
var AiError, AiConfigError, AiTimeoutError, AiParseError, AiHTTPError, Ai;
|
|
29913
|
+
var init_aiClient = __esm({
|
|
29914
|
+
"../core/src/aiClient.ts"() {
|
|
29915
|
+
"use strict";
|
|
29916
|
+
AiError = class extends Error {
|
|
29917
|
+
};
|
|
29918
|
+
AiConfigError = class extends AiError {
|
|
29919
|
+
};
|
|
29920
|
+
AiTimeoutError = class extends AiError {
|
|
29921
|
+
};
|
|
29922
|
+
AiParseError = class extends AiError {
|
|
29923
|
+
};
|
|
29924
|
+
AiHTTPError = class extends AiError {
|
|
29925
|
+
constructor(message, status2 = null) {
|
|
29926
|
+
super(message);
|
|
29927
|
+
this.status = status2;
|
|
29928
|
+
}
|
|
29929
|
+
};
|
|
29930
|
+
Ai = class {
|
|
29931
|
+
static chat(messages, options = {}) {
|
|
29932
|
+
this.validateMessages(messages);
|
|
29933
|
+
const config = this.config("chat", options);
|
|
29934
|
+
const body = this.chatBody(config, messages, options);
|
|
29935
|
+
const headers = this.headers(config);
|
|
29936
|
+
return options.stream ? this.streamRequest(config, headers, body) : this.chatResponse(config, headers, body);
|
|
29937
|
+
}
|
|
29938
|
+
static async complete(prompt, options = {}) {
|
|
29939
|
+
if (typeof prompt !== "string") throw new AiConfigError("AI prompt must be a string");
|
|
29940
|
+
return (await this.chat([{ role: "user", content: prompt }], { ...options, stream: false })).text;
|
|
29941
|
+
}
|
|
29942
|
+
static async embed(textOrTexts, options = {}) {
|
|
29943
|
+
const single = typeof textOrTexts === "string";
|
|
29944
|
+
if (!single && (!Array.isArray(textOrTexts) || textOrTexts.length === 0 || !textOrTexts.every((item) => typeof item === "string"))) {
|
|
29945
|
+
throw new AiConfigError("AI embedding input must be a string or a non-empty list of strings");
|
|
29946
|
+
}
|
|
29947
|
+
const config = this.config("embed", options);
|
|
29948
|
+
if (config.provider === "anthropic") throw new AiConfigError("Anthropic does not provide the embedding endpoint in this contract");
|
|
29949
|
+
const raw = await this.requestJson(config, this.headers(config), { model: config.model, input: textOrTexts });
|
|
29950
|
+
try {
|
|
29951
|
+
const data = raw.data.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
29952
|
+
const vectors = data.map((item) => item.embedding);
|
|
29953
|
+
const expected = single ? 1 : textOrTexts.length;
|
|
29954
|
+
if (vectors.length !== expected || !vectors.every((vector) => Array.isArray(vector) && vector.length > 0 && vector.every((value) => typeof value === "number" && Number.isFinite(value)))) throw new Error();
|
|
29955
|
+
return single ? vectors[0] : vectors;
|
|
29956
|
+
} catch {
|
|
29957
|
+
throw new AiParseError("AI provider returned a malformed embedding response");
|
|
29958
|
+
}
|
|
29959
|
+
}
|
|
29960
|
+
static validateMessages(messages) {
|
|
29961
|
+
if (!Array.isArray(messages) || messages.length === 0 || !messages.every((message) => message && ["system", "user", "assistant"].includes(message.role) && typeof message.content === "string")) {
|
|
29962
|
+
throw new AiConfigError("AI messages must contain supported roles and string content");
|
|
29963
|
+
}
|
|
29964
|
+
}
|
|
29965
|
+
static number(name, fallback, minimum) {
|
|
29966
|
+
const value = process.env[name] === void 0 ? fallback : Number(process.env[name]);
|
|
29967
|
+
if (!Number.isFinite(value) || value < minimum) throw new AiConfigError(`${name} must be numeric and at least ${minimum}`);
|
|
29968
|
+
return value;
|
|
29969
|
+
}
|
|
29970
|
+
static config(capability, options) {
|
|
29971
|
+
const provider = (options.provider ?? process.env.TINA4_AI_PROVIDER ?? "local").trim().toLowerCase();
|
|
29972
|
+
if (provider !== "local" && provider !== "openai" && provider !== "anthropic") throw new AiConfigError("TINA4_AI_PROVIDER must be local, openai, or anthropic");
|
|
29973
|
+
const key = process.env.TINA4_AI_KEY || null;
|
|
29974
|
+
if ((provider === "openai" || provider === "anthropic") && !key) throw new AiConfigError(`TINA4_AI_KEY is required for the ${provider} provider`);
|
|
29975
|
+
const defaults = {
|
|
29976
|
+
local: ["http://localhost:11437", "llama3.2"],
|
|
29977
|
+
openai: ["https://api.openai.com/v1", "gpt-4o-mini"],
|
|
29978
|
+
anthropic: ["https://api.anthropic.com/v1", "claude-3-5-haiku-latest"]
|
|
29979
|
+
};
|
|
29980
|
+
const rawUrl = capability === "embed" && process.env.TINA4_EMBED_URL ? process.env.TINA4_EMBED_URL : process.env.TINA4_AI_URL ?? defaults[provider][0];
|
|
29981
|
+
const model = (options.model ?? process.env.TINA4_AI_MODEL ?? defaults[provider][1]).trim();
|
|
29982
|
+
if (!model) throw new AiConfigError("AI model must be a non-empty string");
|
|
29983
|
+
const totalTimeout = options.timeout === void 0 ? this.number("TINA4_AI_TIMEOUT", 60, 1e-3) : Number(options.timeout);
|
|
29984
|
+
if (!Number.isFinite(totalTimeout) || totalTimeout <= 0) throw new AiConfigError("AI timeout must be greater than zero");
|
|
29985
|
+
return { provider, url: this.endpoint(rawUrl, capability, provider), model, key, totalTimeout, connectTimeout: this.number("TINA4_AI_CONNECT_TIMEOUT", 10, 1e-3), maxRetries: Math.trunc(this.number("TINA4_AI_MAX_RETRIES", 2, 0)) };
|
|
29986
|
+
}
|
|
29987
|
+
static endpoint(value, capability, provider) {
|
|
29988
|
+
let url;
|
|
29989
|
+
try {
|
|
29990
|
+
url = new URL(value);
|
|
29991
|
+
} catch {
|
|
29992
|
+
throw new AiConfigError("AI URL must be an http or https URL");
|
|
29993
|
+
}
|
|
29994
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") throw new AiConfigError("AI URL must be an http or https URL");
|
|
29995
|
+
const path8 = url.pathname.replace(/\/+$/, "");
|
|
29996
|
+
if (path8 === "" || path8 === "/v1" || path8 === "/api") {
|
|
29997
|
+
const suffix = provider === "anthropic" ? "/messages" : capability === "embed" ? "/embeddings" : "/chat/completions";
|
|
29998
|
+
url.pathname = (path8 || "/v1") + suffix;
|
|
29999
|
+
}
|
|
30000
|
+
return url.toString();
|
|
30001
|
+
}
|
|
30002
|
+
static headers(config) {
|
|
30003
|
+
const headers = { "content-type": "application/json", accept: "application/json" };
|
|
30004
|
+
if (config.provider === "openai") headers.authorization = `Bearer ${config.key}`;
|
|
30005
|
+
if (config.provider === "anthropic") {
|
|
30006
|
+
headers["x-api-key"] = config.key;
|
|
30007
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
30008
|
+
}
|
|
30009
|
+
return headers;
|
|
30010
|
+
}
|
|
30011
|
+
static chatBody(config, messages, options) {
|
|
30012
|
+
const body = { model: config.model, messages, stream: options.stream ?? false };
|
|
30013
|
+
if (options.temperature !== void 0) body.temperature = options.temperature;
|
|
30014
|
+
if (options.maxTokens !== void 0) body.max_tokens = options.maxTokens;
|
|
30015
|
+
if (config.provider === "anthropic") {
|
|
30016
|
+
const system = messages.filter((message) => message.role === "system").map((message) => message.content);
|
|
30017
|
+
body.messages = messages.filter((message) => message.role !== "system");
|
|
30018
|
+
body.max_tokens = options.maxTokens ?? 1024;
|
|
30019
|
+
if (system.length) body.system = system.join("\n\n");
|
|
30020
|
+
}
|
|
30021
|
+
return body;
|
|
30022
|
+
}
|
|
30023
|
+
static open(config, deadline, headers, body) {
|
|
30024
|
+
const remainingMs = deadline - performance.now();
|
|
30025
|
+
if (remainingMs <= 0) return Promise.reject(new AiTimeoutError("AI total request timeout expired"));
|
|
30026
|
+
const url = new URL(config.url);
|
|
30027
|
+
const payload = JSON.stringify(body);
|
|
30028
|
+
const controller = new AbortController();
|
|
30029
|
+
const totalTimer = setTimeout(() => controller.abort(new AiTimeoutError("AI total request timeout expired")), remainingMs);
|
|
30030
|
+
return new Promise((resolve20, reject) => {
|
|
30031
|
+
const client = url.protocol === "https:" ? https2 : http2;
|
|
30032
|
+
const request = client.request(url, { method: "POST", headers: { ...headers, "content-length": Buffer.byteLength(payload) }, signal: controller.signal }, (response) => {
|
|
30033
|
+
clearTimeout(connectTimer);
|
|
30034
|
+
resolve20({ response, cleanup: () => {
|
|
30035
|
+
clearTimeout(totalTimer);
|
|
30036
|
+
clearTimeout(connectTimer);
|
|
30037
|
+
} });
|
|
30038
|
+
});
|
|
30039
|
+
const connectTimer = setTimeout(() => request.destroy(new AiTimeoutError("AI connection timeout expired")), Math.min(config.connectTimeout * 1e3, remainingMs));
|
|
30040
|
+
request.on("socket", (socket) => {
|
|
30041
|
+
if (!socket.connecting) clearTimeout(connectTimer);
|
|
30042
|
+
socket.once(url.protocol === "https:" ? "secureConnect" : "connect", () => clearTimeout(connectTimer));
|
|
30043
|
+
});
|
|
30044
|
+
request.once("error", (error) => {
|
|
30045
|
+
clearTimeout(totalTimer);
|
|
30046
|
+
clearTimeout(connectTimer);
|
|
30047
|
+
if (error instanceof AiError) reject(error);
|
|
30048
|
+
else if (controller.signal.aborted) reject(new AiTimeoutError("AI total request timeout expired"));
|
|
30049
|
+
else reject(new AiHTTPError(`AI transport failed (${error.name})`));
|
|
30050
|
+
});
|
|
30051
|
+
request.end(payload);
|
|
30052
|
+
});
|
|
30053
|
+
}
|
|
30054
|
+
static async readBody(response) {
|
|
30055
|
+
const chunks = [];
|
|
30056
|
+
for await (const chunk of response) chunks.push(Buffer.from(chunk));
|
|
30057
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
30058
|
+
}
|
|
30059
|
+
static retryDelay(headers, deadline) {
|
|
30060
|
+
const value = Array.isArray(headers["retry-after"]) ? headers["retry-after"][0] : headers["retry-after"];
|
|
30061
|
+
const requested = value !== void 0 && Number.isFinite(Number(value)) ? Math.max(0, Number(value) * 1e3) : 100;
|
|
30062
|
+
const delay = Math.min(requested, Math.max(0, deadline - performance.now()));
|
|
30063
|
+
return new Promise((resolve20) => setTimeout(resolve20, delay));
|
|
30064
|
+
}
|
|
30065
|
+
static async requestJson(config, headers, body) {
|
|
30066
|
+
const deadline = performance.now() + config.totalTimeout * 1e3;
|
|
30067
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
30068
|
+
let opened = null;
|
|
30069
|
+
try {
|
|
30070
|
+
opened = await this.open(config, deadline, headers, body);
|
|
30071
|
+
const status2 = opened.response.statusCode ?? 0;
|
|
30072
|
+
const responseHeaders = opened.response.headers;
|
|
30073
|
+
const raw = await this.readBody(opened.response);
|
|
30074
|
+
opened.cleanup();
|
|
30075
|
+
opened = null;
|
|
30076
|
+
if (status2 < 200 || status2 >= 300) {
|
|
30077
|
+
if ((status2 === 429 || status2 >= 500) && attempt < config.maxRetries) {
|
|
30078
|
+
await this.retryDelay(responseHeaders, deadline);
|
|
30079
|
+
continue;
|
|
30080
|
+
}
|
|
30081
|
+
throw new AiHTTPError(`AI provider returned HTTP ${status2}`, status2);
|
|
30082
|
+
}
|
|
30083
|
+
let parsed;
|
|
30084
|
+
try {
|
|
30085
|
+
parsed = JSON.parse(raw);
|
|
30086
|
+
} catch {
|
|
30087
|
+
throw new AiParseError("AI provider returned malformed JSON");
|
|
30088
|
+
}
|
|
30089
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new AiParseError("AI provider returned a non-object JSON response");
|
|
30090
|
+
return parsed;
|
|
30091
|
+
} catch (error) {
|
|
30092
|
+
opened?.cleanup();
|
|
30093
|
+
if (error instanceof AiParseError || error instanceof AiHTTPError && error.status !== null) throw error;
|
|
30094
|
+
if (attempt >= config.maxRetries) throw error;
|
|
30095
|
+
}
|
|
30096
|
+
}
|
|
30097
|
+
throw new AiHTTPError("AI request failed");
|
|
30098
|
+
}
|
|
30099
|
+
static normalizeChat(provider, raw) {
|
|
30100
|
+
try {
|
|
30101
|
+
if (provider === "anthropic") {
|
|
30102
|
+
const content = raw.content;
|
|
30103
|
+
const parts = content.filter((item) => (item.type ?? "text") === "text").map((item) => item.text);
|
|
30104
|
+
if (!parts.length || !parts.every((part) => typeof part === "string")) throw new Error();
|
|
30105
|
+
const usage2 = raw.usage ?? {};
|
|
30106
|
+
const promptTokens = Number(usage2.input_tokens ?? 0);
|
|
30107
|
+
const completionTokens = Number(usage2.output_tokens ?? 0);
|
|
30108
|
+
return { text: parts.join(""), model: String(raw.model ?? ""), usage: { promptTokens, completionTokens, totalTokens: promptTokens + completionTokens }, finishReason: raw.stop_reason == null ? null : String(raw.stop_reason), raw };
|
|
30109
|
+
}
|
|
30110
|
+
const choice = raw.choices[0];
|
|
30111
|
+
const text = choice.message.content;
|
|
30112
|
+
if (typeof text !== "string") throw new Error();
|
|
30113
|
+
const usage = raw.usage ?? {};
|
|
30114
|
+
return { text, model: String(raw.model ?? ""), usage: { promptTokens: Number(usage.prompt_tokens ?? 0), completionTokens: Number(usage.completion_tokens ?? 0), totalTokens: Number(usage.total_tokens ?? 0) }, finishReason: choice.finish_reason == null ? null : String(choice.finish_reason), raw };
|
|
30115
|
+
} catch {
|
|
30116
|
+
throw new AiParseError("AI provider returned a malformed chat response");
|
|
30117
|
+
}
|
|
30118
|
+
}
|
|
30119
|
+
static async chatResponse(config, headers, body) {
|
|
30120
|
+
return this.normalizeChat(config.provider, await this.requestJson(config, headers, body));
|
|
30121
|
+
}
|
|
30122
|
+
static streamDelta(provider, data) {
|
|
30123
|
+
if (data === "[DONE]") return { completed: true };
|
|
30124
|
+
let event;
|
|
30125
|
+
try {
|
|
30126
|
+
event = JSON.parse(data);
|
|
30127
|
+
} catch {
|
|
30128
|
+
throw new AiParseError("AI provider returned malformed stream data");
|
|
30129
|
+
}
|
|
30130
|
+
const text = provider === "anthropic" ? event.type === "content_block_delta" ? event.delta?.text : void 0 : event.choices?.[0]?.delta?.content;
|
|
30131
|
+
if (text !== void 0 && text !== null && typeof text !== "string") throw new AiParseError("AI provider returned malformed stream data");
|
|
30132
|
+
return { completed: false, text };
|
|
30133
|
+
}
|
|
30134
|
+
static async *streamData(response) {
|
|
30135
|
+
let buffer = "";
|
|
30136
|
+
for await (const chunk of response) {
|
|
30137
|
+
buffer += Buffer.from(chunk).toString("utf8");
|
|
30138
|
+
let newline;
|
|
30139
|
+
while ((newline = buffer.indexOf("\n")) >= 0) {
|
|
30140
|
+
const line = buffer.slice(0, newline).trim();
|
|
30141
|
+
buffer = buffer.slice(newline + 1);
|
|
30142
|
+
if (line.startsWith("data:")) yield line.slice(5).trim();
|
|
30143
|
+
}
|
|
30144
|
+
}
|
|
30145
|
+
}
|
|
30146
|
+
static streamError(error) {
|
|
30147
|
+
if (error instanceof AiError) return error;
|
|
30148
|
+
if (error instanceof Error && error.name === "AbortError") return new AiTimeoutError("AI total request timeout expired");
|
|
30149
|
+
return new AiHTTPError(`AI transport failed (${error instanceof Error ? error.name : "Error"})`);
|
|
30150
|
+
}
|
|
30151
|
+
static async *streamRequest(config, headers, body) {
|
|
30152
|
+
const deadline = performance.now() + config.totalTimeout * 1e3;
|
|
30153
|
+
let yielded = false;
|
|
30154
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
30155
|
+
let opened = null;
|
|
30156
|
+
try {
|
|
30157
|
+
opened = await this.open(config, deadline, { ...headers, accept: "text/event-stream" }, body);
|
|
30158
|
+
const status2 = opened.response.statusCode ?? 0;
|
|
30159
|
+
if (status2 < 200 || status2 >= 300) {
|
|
30160
|
+
await this.readBody(opened.response);
|
|
30161
|
+
if ((status2 === 429 || status2 >= 500) && attempt < config.maxRetries) {
|
|
30162
|
+
await this.retryDelay(opened.response.headers, deadline);
|
|
30163
|
+
opened.cleanup();
|
|
30164
|
+
opened = null;
|
|
30165
|
+
continue;
|
|
30166
|
+
}
|
|
30167
|
+
throw new AiHTTPError(`AI provider returned HTTP ${status2}`, status2);
|
|
30168
|
+
}
|
|
30169
|
+
let completed = false;
|
|
30170
|
+
for await (const data of this.streamData(opened.response)) {
|
|
30171
|
+
const delta = this.streamDelta(config.provider, data);
|
|
30172
|
+
if (delta.completed) {
|
|
30173
|
+
completed = true;
|
|
30174
|
+
break;
|
|
30175
|
+
}
|
|
30176
|
+
if (delta.text === void 0) continue;
|
|
30177
|
+
yielded = true;
|
|
30178
|
+
yield delta.text;
|
|
30179
|
+
}
|
|
30180
|
+
opened.cleanup();
|
|
30181
|
+
opened = null;
|
|
30182
|
+
if (completed) return;
|
|
30183
|
+
throw new AiParseError("AI provider stream ended before [DONE]");
|
|
30184
|
+
} catch (error) {
|
|
30185
|
+
opened?.cleanup();
|
|
30186
|
+
const failure = this.streamError(error);
|
|
30187
|
+
if (failure instanceof AiParseError || failure instanceof AiHTTPError && failure.status !== null || yielded || attempt >= config.maxRetries) throw failure;
|
|
30188
|
+
}
|
|
30189
|
+
}
|
|
30190
|
+
}
|
|
30191
|
+
};
|
|
30192
|
+
}
|
|
30193
|
+
});
|
|
30194
|
+
|
|
30274
30195
|
// ../core/src/queueBackends/rabbitmqBackend.ts
|
|
30275
30196
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
30276
30197
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
@@ -31974,6 +31895,12 @@ __export(src_exports2, {
|
|
|
31974
31895
|
APPLICATION_JSON: () => APPLICATION_JSON,
|
|
31975
31896
|
APPLICATION_OCTET: () => APPLICATION_OCTET,
|
|
31976
31897
|
APPLICATION_XML: () => APPLICATION_XML,
|
|
31898
|
+
Ai: () => Ai,
|
|
31899
|
+
AiConfigError: () => AiConfigError,
|
|
31900
|
+
AiError: () => AiError,
|
|
31901
|
+
AiHTTPError: () => AiHTTPError,
|
|
31902
|
+
AiParseError: () => AiParseError,
|
|
31903
|
+
AiTimeoutError: () => AiTimeoutError,
|
|
31977
31904
|
Api: () => Api,
|
|
31978
31905
|
Auth: () => Auth,
|
|
31979
31906
|
CANONICAL_SESSION_BACKENDS: () => CANONICAL_SESSION_BACKENDS,
|
|
@@ -32301,6 +32228,7 @@ var init_src2 = __esm({
|
|
|
32301
32228
|
init_htmlElement();
|
|
32302
32229
|
init_errorOverlay();
|
|
32303
32230
|
init_ai();
|
|
32231
|
+
init_aiClient();
|
|
32304
32232
|
init_liteBackend();
|
|
32305
32233
|
init_rabbitmqBackend();
|
|
32306
32234
|
init_kafkaBackend();
|
|
@@ -37739,7 +37667,7 @@ var init_database = __esm({
|
|
|
37739
37667
|
|
|
37740
37668
|
// src/model.ts
|
|
37741
37669
|
import { readdirSync as readdirSync17, statSync as statSync17 } from "node:fs";
|
|
37742
|
-
import { join as join29, extname as
|
|
37670
|
+
import { join as join29, extname as extname7 } from "node:path";
|
|
37743
37671
|
async function discoverModels(modelsDir) {
|
|
37744
37672
|
const models = [];
|
|
37745
37673
|
let files;
|
|
@@ -37752,7 +37680,7 @@ async function discoverModels(modelsDir) {
|
|
|
37752
37680
|
const filePath = join29(modelsDir, file);
|
|
37753
37681
|
const stat = statSync17(filePath);
|
|
37754
37682
|
if (!stat.isFile()) continue;
|
|
37755
|
-
const ext =
|
|
37683
|
+
const ext = extname7(file);
|
|
37756
37684
|
if (ext !== ".ts" && ext !== ".js") continue;
|
|
37757
37685
|
try {
|
|
37758
37686
|
const moduleUrl = `file://${filePath}?t=${Date.now()}`;
|
|
@@ -37791,7 +37719,7 @@ var init_model = __esm({
|
|
|
37791
37719
|
});
|
|
37792
37720
|
|
|
37793
37721
|
// src/migration.ts
|
|
37794
|
-
import { existsSync as existsSync26, readdirSync as readdirSync18, readFileSync as
|
|
37722
|
+
import { existsSync as existsSync26, readdirSync as readdirSync18, readFileSync as readFileSync25, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "node:fs";
|
|
37795
37723
|
import { join as join30, resolve as resolve18 } from "node:path";
|
|
37796
37724
|
function unwrapAdapter(db) {
|
|
37797
37725
|
let cur = db;
|
|
@@ -38119,7 +38047,7 @@ async function rollback(migrationsDir, delimiter2) {
|
|
|
38119
38047
|
`Cannot rollback ${migration.migration_name}: no .down.sql file found`
|
|
38120
38048
|
);
|
|
38121
38049
|
}
|
|
38122
|
-
const sqlContent =
|
|
38050
|
+
const sqlContent = readFileSync25(downPath, "utf-8").trim();
|
|
38123
38051
|
if (sqlContent) {
|
|
38124
38052
|
const statements = splitStatements(sqlContent, delim);
|
|
38125
38053
|
try {
|
|
@@ -38317,7 +38245,7 @@ async function migrate(adapter, options) {
|
|
|
38317
38245
|
result.skipped.push(file);
|
|
38318
38246
|
continue;
|
|
38319
38247
|
}
|
|
38320
|
-
const sqlContent =
|
|
38248
|
+
const sqlContent = readFileSync25(join30(dir, file), "utf-8").trim();
|
|
38321
38249
|
if (!sqlContent) {
|
|
38322
38250
|
result.skipped.push(file);
|
|
38323
38251
|
continue;
|
|
@@ -42008,7 +41936,7 @@ var init_attachment = __esm({
|
|
|
42008
41936
|
|
|
42009
41937
|
// src/realtime/storage.ts
|
|
42010
41938
|
import { randomBytes as randomBytes9 } from "node:crypto";
|
|
42011
|
-
import { mkdirSync as mkdirSync20, readFileSync as
|
|
41939
|
+
import { mkdirSync as mkdirSync20, readFileSync as readFileSync26, writeFileSync as writeFileSync17, unlinkSync as unlinkSync8, statSync as statSync18 } from "node:fs";
|
|
42012
41940
|
import { resolve as resolve19, sep as sep5 } from "node:path";
|
|
42013
41941
|
import { createRequire as createRequire8 } from "node:module";
|
|
42014
41942
|
function storageKey(filename = "") {
|
|
@@ -42061,7 +41989,7 @@ var init_storage = __esm({
|
|
|
42061
41989
|
}
|
|
42062
41990
|
get(key) {
|
|
42063
41991
|
try {
|
|
42064
|
-
return
|
|
41992
|
+
return readFileSync26(this.pathFor(key));
|
|
42065
41993
|
} catch {
|
|
42066
41994
|
return null;
|
|
42067
41995
|
}
|