@spfn/core 0.1.0-alpha.64 → 0.1.0-alpha.68
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/README.md +5 -5
- package/dist/{auto-loader-CdsxOceW.d.ts → auto-loader-JFaZ9gON.d.ts} +3 -2
- package/dist/cache/index.d.ts +211 -0
- package/dist/cache/index.js +992 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/codegen/generators/index.d.ts +7 -6
- package/dist/codegen/generators/index.js +208 -27
- package/dist/codegen/generators/index.js.map +1 -1
- package/dist/codegen/index.d.ts +67 -118
- package/dist/codegen/index.js +1419 -1295
- package/dist/codegen/index.js.map +1 -1
- package/dist/database-errors-CoPrcOpq.d.ts +86 -0
- package/dist/db/index.d.ts +316 -9
- package/dist/db/index.js +6 -6
- package/dist/db/index.js.map +1 -1
- package/dist/error-handler-wjLL3v-a.d.ts +44 -0
- package/dist/errors/index.d.ts +119 -0
- package/dist/errors/index.js +160 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index-DHiAqhKv.d.ts +101 -0
- package/dist/index.d.ts +2 -228
- package/dist/index.js +274 -292
- package/dist/index.js.map +1 -1
- package/dist/middleware/index.d.ts +33 -0
- package/dist/middleware/index.js +890 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/route/index.d.ts +172 -7
- package/dist/route/index.js +209 -70
- package/dist/route/index.js.map +1 -1
- package/dist/server/index.js +267 -176
- package/dist/server/index.js.map +1 -1
- package/dist/{types-Bd8YsFSU.d.ts → types-CAON3Mmg.d.ts} +1 -1
- package/package.json +19 -2
- package/dist/bind-CSzshBtm.d.ts +0 -17
- package/dist/contract-generator-CqKsfsNE.d.ts +0 -52
- package/dist/postgres-errors-lw1aRUFe.d.ts +0 -397
package/dist/server/index.js
CHANGED
|
@@ -128,11 +128,11 @@ function formatTimestampHuman(date) {
|
|
|
128
128
|
const ms = String(date.getMilliseconds()).padStart(3, "0");
|
|
129
129
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;
|
|
130
130
|
}
|
|
131
|
-
function formatError(
|
|
131
|
+
function formatError(error2) {
|
|
132
132
|
const lines = [];
|
|
133
|
-
lines.push(`${
|
|
134
|
-
if (
|
|
135
|
-
const stackLines =
|
|
133
|
+
lines.push(`${error2.name}: ${error2.message}`);
|
|
134
|
+
if (error2.stack) {
|
|
135
|
+
const stackLines = error2.stack.split("\n").slice(1);
|
|
136
136
|
lines.push(...stackLines);
|
|
137
137
|
}
|
|
138
138
|
return lines.join("\n");
|
|
@@ -318,7 +318,7 @@ var init_logger = __esm({
|
|
|
318
318
|
/**
|
|
319
319
|
* Log processing (internal)
|
|
320
320
|
*/
|
|
321
|
-
log(level, message,
|
|
321
|
+
log(level, message, error2, context) {
|
|
322
322
|
if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.config.level]) {
|
|
323
323
|
return;
|
|
324
324
|
}
|
|
@@ -327,7 +327,7 @@ var init_logger = __esm({
|
|
|
327
327
|
level,
|
|
328
328
|
message,
|
|
329
329
|
module: this.module,
|
|
330
|
-
error,
|
|
330
|
+
error: error2,
|
|
331
331
|
// Mask sensitive information in context to prevent credential leaks
|
|
332
332
|
context: context ? maskSensitiveData(context) : void 0
|
|
333
333
|
};
|
|
@@ -338,8 +338,8 @@ var init_logger = __esm({
|
|
|
338
338
|
*/
|
|
339
339
|
processTransports(metadata) {
|
|
340
340
|
const promises = this.config.transports.filter((transport) => transport.enabled).map((transport) => this.safeTransportLog(transport, metadata));
|
|
341
|
-
Promise.all(promises).catch((
|
|
342
|
-
const errorMessage =
|
|
341
|
+
Promise.all(promises).catch((error2) => {
|
|
342
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
343
343
|
process.stderr.write(`[Logger] Transport error: ${errorMessage}
|
|
344
344
|
`);
|
|
345
345
|
});
|
|
@@ -350,8 +350,8 @@ var init_logger = __esm({
|
|
|
350
350
|
async safeTransportLog(transport, metadata) {
|
|
351
351
|
try {
|
|
352
352
|
await transport.log(metadata);
|
|
353
|
-
} catch (
|
|
354
|
-
const errorMessage =
|
|
353
|
+
} catch (error2) {
|
|
354
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
355
355
|
process.stderr.write(`[Logger] Transport "${transport.name}" failed: ${errorMessage}
|
|
356
356
|
`);
|
|
357
357
|
}
|
|
@@ -441,11 +441,11 @@ var init_file = __esm({
|
|
|
441
441
|
}
|
|
442
442
|
if (this.currentStream) {
|
|
443
443
|
return new Promise((resolve, reject) => {
|
|
444
|
-
this.currentStream.write(message + "\n", "utf-8", (
|
|
445
|
-
if (
|
|
446
|
-
process.stderr.write(`[FileTransport] Failed to write log: ${
|
|
444
|
+
this.currentStream.write(message + "\n", "utf-8", (error2) => {
|
|
445
|
+
if (error2) {
|
|
446
|
+
process.stderr.write(`[FileTransport] Failed to write log: ${error2.message}
|
|
447
447
|
`);
|
|
448
|
-
reject(
|
|
448
|
+
reject(error2);
|
|
449
449
|
} else {
|
|
450
450
|
resolve();
|
|
451
451
|
}
|
|
@@ -467,8 +467,8 @@ var init_file = __esm({
|
|
|
467
467
|
encoding: "utf-8"
|
|
468
468
|
});
|
|
469
469
|
this.currentFilename = filename;
|
|
470
|
-
this.currentStream.on("error", (
|
|
471
|
-
process.stderr.write(`[FileTransport] Stream error: ${
|
|
470
|
+
this.currentStream.on("error", (error2) => {
|
|
471
|
+
process.stderr.write(`[FileTransport] Stream error: ${error2.message}
|
|
472
472
|
`);
|
|
473
473
|
this.currentStream = null;
|
|
474
474
|
this.currentFilename = null;
|
|
@@ -482,9 +482,9 @@ var init_file = __esm({
|
|
|
482
482
|
return;
|
|
483
483
|
}
|
|
484
484
|
return new Promise((resolve, reject) => {
|
|
485
|
-
this.currentStream.end((
|
|
486
|
-
if (
|
|
487
|
-
reject(
|
|
485
|
+
this.currentStream.end((error2) => {
|
|
486
|
+
if (error2) {
|
|
487
|
+
reject(error2);
|
|
488
488
|
} else {
|
|
489
489
|
this.currentStream = null;
|
|
490
490
|
this.currentFilename = null;
|
|
@@ -509,8 +509,8 @@ var init_file = __esm({
|
|
|
509
509
|
if (stats.size >= this.maxFileSize) {
|
|
510
510
|
await this.rotateBySize();
|
|
511
511
|
}
|
|
512
|
-
} catch (
|
|
513
|
-
const errorMessage =
|
|
512
|
+
} catch (error2) {
|
|
513
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
514
514
|
process.stderr.write(`[FileTransport] Failed to check file size: ${errorMessage}
|
|
515
515
|
`);
|
|
516
516
|
}
|
|
@@ -536,8 +536,8 @@ var init_file = __esm({
|
|
|
536
536
|
const newPath2 = join(this.logDir, `${baseName}.${newNum}.log`);
|
|
537
537
|
try {
|
|
538
538
|
renameSync(oldPath, newPath2);
|
|
539
|
-
} catch (
|
|
540
|
-
const errorMessage =
|
|
539
|
+
} catch (error2) {
|
|
540
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
541
541
|
process.stderr.write(`[FileTransport] Failed to rotate file: ${errorMessage}
|
|
542
542
|
`);
|
|
543
543
|
}
|
|
@@ -549,8 +549,8 @@ var init_file = __esm({
|
|
|
549
549
|
if (existsSync(currentPath)) {
|
|
550
550
|
renameSync(currentPath, newPath);
|
|
551
551
|
}
|
|
552
|
-
} catch (
|
|
553
|
-
const errorMessage =
|
|
552
|
+
} catch (error2) {
|
|
553
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
554
554
|
process.stderr.write(`[FileTransport] Failed to rotate current file: ${errorMessage}
|
|
555
555
|
`);
|
|
556
556
|
}
|
|
@@ -577,15 +577,15 @@ var init_file = __esm({
|
|
|
577
577
|
const filepath = join(this.logDir, file);
|
|
578
578
|
try {
|
|
579
579
|
unlinkSync(filepath);
|
|
580
|
-
} catch (
|
|
581
|
-
const errorMessage =
|
|
580
|
+
} catch (error2) {
|
|
581
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
582
582
|
process.stderr.write(`[FileTransport] Failed to delete old file "${file}": ${errorMessage}
|
|
583
583
|
`);
|
|
584
584
|
}
|
|
585
585
|
}
|
|
586
586
|
}
|
|
587
|
-
} catch (
|
|
588
|
-
const errorMessage =
|
|
587
|
+
} catch (error2) {
|
|
588
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
589
589
|
process.stderr.write(`[FileTransport] Failed to clean old files: ${errorMessage}
|
|
590
590
|
`);
|
|
591
591
|
}
|
|
@@ -644,8 +644,8 @@ function validateDirectoryWritable(dirPath) {
|
|
|
644
644
|
if (!existsSync(dirPath)) {
|
|
645
645
|
try {
|
|
646
646
|
mkdirSync(dirPath, { recursive: true });
|
|
647
|
-
} catch (
|
|
648
|
-
const errorMessage =
|
|
647
|
+
} catch (error2) {
|
|
648
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
649
649
|
throw new Error(`Failed to create log directory "${dirPath}": ${errorMessage}`);
|
|
650
650
|
}
|
|
651
651
|
}
|
|
@@ -658,8 +658,8 @@ function validateDirectoryWritable(dirPath) {
|
|
|
658
658
|
try {
|
|
659
659
|
writeFileSync(testFile, "test", "utf-8");
|
|
660
660
|
unlinkSync(testFile);
|
|
661
|
-
} catch (
|
|
662
|
-
const errorMessage =
|
|
661
|
+
} catch (error2) {
|
|
662
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
663
663
|
throw new Error(`Cannot write to log directory "${dirPath}": ${errorMessage}`);
|
|
664
664
|
}
|
|
665
665
|
}
|
|
@@ -736,11 +736,11 @@ function validateConfig() {
|
|
|
736
736
|
validateFileConfig();
|
|
737
737
|
validateSlackConfig();
|
|
738
738
|
validateEmailConfig();
|
|
739
|
-
} catch (
|
|
740
|
-
if (
|
|
741
|
-
throw new Error(`[Logger] Configuration validation failed: ${
|
|
739
|
+
} catch (error2) {
|
|
740
|
+
if (error2 instanceof Error) {
|
|
741
|
+
throw new Error(`[Logger] Configuration validation failed: ${error2.message}`);
|
|
742
742
|
}
|
|
743
|
-
throw
|
|
743
|
+
throw error2;
|
|
744
744
|
}
|
|
745
745
|
}
|
|
746
746
|
var init_config = __esm({
|
|
@@ -878,24 +878,28 @@ function discoverFunctionRoutes(cwd = process.cwd()) {
|
|
|
878
878
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
879
879
|
if (pkg.spfn?.routes?.dir) {
|
|
880
880
|
const { dir } = pkg.spfn.routes;
|
|
881
|
+
const prefix = pkg.spfn.prefix;
|
|
881
882
|
const packagePath = dirname(pkgPath);
|
|
882
883
|
const routesDir = join(packagePath, dir);
|
|
883
884
|
functions.push({
|
|
884
885
|
packageName,
|
|
885
886
|
routesDir,
|
|
886
|
-
packagePath
|
|
887
|
+
packagePath,
|
|
888
|
+
prefix
|
|
889
|
+
// Include prefix in function info
|
|
887
890
|
});
|
|
888
891
|
routeLogger.debug("Discovered function routes", {
|
|
889
892
|
package: packageName,
|
|
890
|
-
dir
|
|
893
|
+
dir,
|
|
894
|
+
prefix: prefix || "(none)"
|
|
891
895
|
});
|
|
892
896
|
}
|
|
893
|
-
} catch (
|
|
897
|
+
} catch (error2) {
|
|
894
898
|
}
|
|
895
899
|
}
|
|
896
|
-
} catch (
|
|
900
|
+
} catch (error2) {
|
|
897
901
|
routeLogger.warn("Failed to discover function routes", {
|
|
898
|
-
error:
|
|
902
|
+
error: error2 instanceof Error ? error2.message : "Unknown error"
|
|
899
903
|
});
|
|
900
904
|
}
|
|
901
905
|
return functions;
|
|
@@ -909,7 +913,7 @@ var init_function_routes = __esm({
|
|
|
909
913
|
});
|
|
910
914
|
|
|
911
915
|
// src/errors/database-errors.ts
|
|
912
|
-
var DatabaseError, ConnectionError, QueryError,
|
|
916
|
+
var DatabaseError, ConnectionError, QueryError, ConstraintViolationError, TransactionError, DeadlockError, DuplicateEntryError;
|
|
913
917
|
var init_database_errors = __esm({
|
|
914
918
|
"src/errors/database-errors.ts"() {
|
|
915
919
|
DatabaseError = class extends Error {
|
|
@@ -949,10 +953,10 @@ var init_database_errors = __esm({
|
|
|
949
953
|
this.name = "QueryError";
|
|
950
954
|
}
|
|
951
955
|
};
|
|
952
|
-
|
|
956
|
+
ConstraintViolationError = class extends QueryError {
|
|
953
957
|
constructor(message, details) {
|
|
954
958
|
super(message, 400, details);
|
|
955
|
-
this.name = "
|
|
959
|
+
this.name = "ConstraintViolationError";
|
|
956
960
|
}
|
|
957
961
|
};
|
|
958
962
|
TransactionError = class extends DatabaseError {
|
|
@@ -1072,8 +1076,8 @@ function loadSingleFile(filePath, debug) {
|
|
|
1072
1076
|
});
|
|
1073
1077
|
}
|
|
1074
1078
|
return { success: true, parsed };
|
|
1075
|
-
} catch (
|
|
1076
|
-
const message =
|
|
1079
|
+
} catch (error2) {
|
|
1080
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1077
1081
|
envLogger.error("Error loading environment file", {
|
|
1078
1082
|
path: filePath,
|
|
1079
1083
|
error: message
|
|
@@ -1089,12 +1093,12 @@ function validateRequiredVars(required, debug) {
|
|
|
1089
1093
|
}
|
|
1090
1094
|
}
|
|
1091
1095
|
if (missing.length > 0) {
|
|
1092
|
-
const
|
|
1096
|
+
const error2 = `Required environment variables missing: ${missing.join(", ")}`;
|
|
1093
1097
|
envLogger.error("Environment validation failed", {
|
|
1094
1098
|
missing,
|
|
1095
1099
|
required
|
|
1096
1100
|
});
|
|
1097
|
-
throw new Error(
|
|
1101
|
+
throw new Error(error2);
|
|
1098
1102
|
}
|
|
1099
1103
|
if (debug) {
|
|
1100
1104
|
envLogger.debug("Required environment variables validated", {
|
|
@@ -1175,12 +1179,12 @@ function loadEnvironment(options = {}) {
|
|
|
1175
1179
|
if (required.length > 0) {
|
|
1176
1180
|
try {
|
|
1177
1181
|
validateRequiredVars(required, debug);
|
|
1178
|
-
} catch (
|
|
1182
|
+
} catch (error2) {
|
|
1179
1183
|
result.success = false;
|
|
1180
1184
|
result.errors = [
|
|
1181
|
-
|
|
1185
|
+
error2 instanceof Error ? error2.message : "Validation failed"
|
|
1182
1186
|
];
|
|
1183
|
-
throw
|
|
1187
|
+
throw error2;
|
|
1184
1188
|
}
|
|
1185
1189
|
}
|
|
1186
1190
|
if (result.warnings.length > 0) {
|
|
@@ -1237,9 +1241,9 @@ function parseUniqueViolation(message) {
|
|
|
1237
1241
|
}
|
|
1238
1242
|
return null;
|
|
1239
1243
|
}
|
|
1240
|
-
function fromPostgresError(
|
|
1241
|
-
const code =
|
|
1242
|
-
const message =
|
|
1244
|
+
function fromPostgresError(error2) {
|
|
1245
|
+
const code = error2?.code;
|
|
1246
|
+
const message = error2?.message || "Database error occurred";
|
|
1243
1247
|
switch (code) {
|
|
1244
1248
|
// Class 08 — Connection Exception
|
|
1245
1249
|
case "08000":
|
|
@@ -1260,11 +1264,11 @@ function fromPostgresError(error) {
|
|
|
1260
1264
|
case "23000":
|
|
1261
1265
|
// integrity_constraint_violation
|
|
1262
1266
|
case "23001":
|
|
1263
|
-
return new
|
|
1267
|
+
return new ConstraintViolationError(message, { code, constraint: "integrity" });
|
|
1264
1268
|
case "23502":
|
|
1265
|
-
return new
|
|
1269
|
+
return new ConstraintViolationError(message, { code, constraint: "not_null" });
|
|
1266
1270
|
case "23503":
|
|
1267
|
-
return new
|
|
1271
|
+
return new ConstraintViolationError(message, { code, constraint: "foreign_key" });
|
|
1268
1272
|
case "23505":
|
|
1269
1273
|
const parsed = parseUniqueViolation(message);
|
|
1270
1274
|
if (parsed) {
|
|
@@ -1272,7 +1276,7 @@ function fromPostgresError(error) {
|
|
|
1272
1276
|
}
|
|
1273
1277
|
return new DuplicateEntryError("field", "value");
|
|
1274
1278
|
case "23514":
|
|
1275
|
-
return new
|
|
1279
|
+
return new ConstraintViolationError(message, { code, constraint: "check" });
|
|
1276
1280
|
// Class 40 — Transaction Rollback
|
|
1277
1281
|
case "40000":
|
|
1278
1282
|
// transaction_rollback
|
|
@@ -1355,8 +1359,8 @@ async function createDatabaseConnection(connectionString, poolConfig, retryConfi
|
|
|
1355
1359
|
dbLogger.info("Database connected successfully");
|
|
1356
1360
|
}
|
|
1357
1361
|
return client;
|
|
1358
|
-
} catch (
|
|
1359
|
-
lastError = fromPostgresError(
|
|
1362
|
+
} catch (error2) {
|
|
1363
|
+
lastError = fromPostgresError(error2);
|
|
1360
1364
|
if (attempt < retryConfig.maxRetries) {
|
|
1361
1365
|
const delayMs = Math.min(
|
|
1362
1366
|
retryConfig.initialDelay * Math.pow(retryConfig.factor, attempt),
|
|
@@ -1382,8 +1386,8 @@ async function checkConnection(client) {
|
|
|
1382
1386
|
try {
|
|
1383
1387
|
await client`SELECT 1 as health_check`;
|
|
1384
1388
|
return true;
|
|
1385
|
-
} catch (
|
|
1386
|
-
dbLogger.error("Database health check failed",
|
|
1389
|
+
} catch (error2) {
|
|
1390
|
+
dbLogger.error("Database health check failed", error2);
|
|
1387
1391
|
return false;
|
|
1388
1392
|
}
|
|
1389
1393
|
}
|
|
@@ -1553,8 +1557,8 @@ async function createDatabaseFromEnv(options) {
|
|
|
1553
1557
|
dbLogger2.warn("No database pattern detected");
|
|
1554
1558
|
return { write: void 0, read: void 0 };
|
|
1555
1559
|
}
|
|
1556
|
-
} catch (
|
|
1557
|
-
const message =
|
|
1560
|
+
} catch (error2) {
|
|
1561
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1558
1562
|
dbLogger2.error("Failed to create database connection", {
|
|
1559
1563
|
error: message,
|
|
1560
1564
|
stage: "initialization",
|
|
@@ -1563,7 +1567,7 @@ async function createDatabaseFromEnv(options) {
|
|
|
1563
1567
|
hasUrl: !!process.env.DATABASE_URL,
|
|
1564
1568
|
hasReplicaUrl: !!process.env.DATABASE_REPLICA_URL
|
|
1565
1569
|
});
|
|
1566
|
-
throw new Error(`Database connection failed: ${message}`, { cause:
|
|
1570
|
+
throw new Error(`Database connection failed: ${message}`, { cause: error2 });
|
|
1567
1571
|
}
|
|
1568
1572
|
}
|
|
1569
1573
|
var dbLogger2;
|
|
@@ -1628,8 +1632,8 @@ function startHealthCheck(config, options, getDatabase2, closeDatabase2) {
|
|
|
1628
1632
|
if (read && read !== write) {
|
|
1629
1633
|
await read.execute("SELECT 1");
|
|
1630
1634
|
}
|
|
1631
|
-
} catch (
|
|
1632
|
-
const message =
|
|
1635
|
+
} catch (error2) {
|
|
1636
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1633
1637
|
dbLogger3.error("Database health check failed", { error: message });
|
|
1634
1638
|
if (config.reconnect) {
|
|
1635
1639
|
await attemptReconnection(config, options, closeDatabase2);
|
|
@@ -1658,8 +1662,8 @@ async function attemptReconnection(config, options, closeDatabase2) {
|
|
|
1658
1662
|
dbLogger3.info("Database reconnection successful", { attempt });
|
|
1659
1663
|
return;
|
|
1660
1664
|
}
|
|
1661
|
-
} catch (
|
|
1662
|
-
const message =
|
|
1665
|
+
} catch (error2) {
|
|
1666
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1663
1667
|
dbLogger3.error(`Reconnection attempt ${attempt} failed`, {
|
|
1664
1668
|
error: message,
|
|
1665
1669
|
attempt,
|
|
@@ -1736,11 +1740,11 @@ async function initDatabase(options) {
|
|
|
1736
1740
|
logQueries: monConfig.logQueries
|
|
1737
1741
|
});
|
|
1738
1742
|
}
|
|
1739
|
-
} catch (
|
|
1740
|
-
const message =
|
|
1743
|
+
} catch (error2) {
|
|
1744
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1741
1745
|
dbLogger4.error("Database connection failed", { error: message });
|
|
1742
1746
|
await closeDatabase();
|
|
1743
|
-
throw new Error(`Database connection test failed: ${message}`, { cause:
|
|
1747
|
+
throw new Error(`Database connection test failed: ${message}`, { cause: error2 });
|
|
1744
1748
|
}
|
|
1745
1749
|
} else {
|
|
1746
1750
|
dbLogger4.warn("No database configuration found");
|
|
@@ -1774,9 +1778,9 @@ async function closeDatabase() {
|
|
|
1774
1778
|
}
|
|
1775
1779
|
await Promise.all(closePromises);
|
|
1776
1780
|
dbLogger4.info("All database connections closed");
|
|
1777
|
-
} catch (
|
|
1778
|
-
dbLogger4.error("Error during database cleanup",
|
|
1779
|
-
throw
|
|
1781
|
+
} catch (error2) {
|
|
1782
|
+
dbLogger4.error("Error during database cleanup", error2);
|
|
1783
|
+
throw error2;
|
|
1780
1784
|
} finally {
|
|
1781
1785
|
setWriteInstance(void 0);
|
|
1782
1786
|
setReadInstance(void 0);
|
|
@@ -1882,7 +1886,7 @@ function discoverPackageSchemas(cwd) {
|
|
|
1882
1886
|
...Object.keys(projectPkg.dependencies || {}),
|
|
1883
1887
|
...Object.keys(projectPkg.devDependencies || {})
|
|
1884
1888
|
]);
|
|
1885
|
-
} catch (
|
|
1889
|
+
} catch (error2) {
|
|
1886
1890
|
}
|
|
1887
1891
|
}
|
|
1888
1892
|
const checkPackage = (_pkgName, pkgPath) => {
|
|
@@ -1901,7 +1905,7 @@ function discoverPackageSchemas(cwd) {
|
|
|
1901
1905
|
schemas.push(...schemaFiles);
|
|
1902
1906
|
}
|
|
1903
1907
|
}
|
|
1904
|
-
} catch (
|
|
1908
|
+
} catch (error2) {
|
|
1905
1909
|
}
|
|
1906
1910
|
};
|
|
1907
1911
|
const spfnDir = join(nodeModulesPath, "@spfn");
|
|
@@ -1911,7 +1915,7 @@ function discoverPackageSchemas(cwd) {
|
|
|
1911
1915
|
for (const pkg of spfnPackages) {
|
|
1912
1916
|
checkPackage(`@spfn/${pkg}`, join(spfnDir, pkg));
|
|
1913
1917
|
}
|
|
1914
|
-
} catch (
|
|
1918
|
+
} catch (error2) {
|
|
1915
1919
|
}
|
|
1916
1920
|
}
|
|
1917
1921
|
for (const depName of directDeps) {
|
|
@@ -2155,9 +2159,9 @@ function Transactional(options = {}) {
|
|
|
2155
2159
|
});
|
|
2156
2160
|
}
|
|
2157
2161
|
}
|
|
2158
|
-
} catch (
|
|
2162
|
+
} catch (error2) {
|
|
2159
2163
|
const duration = Date.now() - startTime;
|
|
2160
|
-
const customError =
|
|
2164
|
+
const customError = error2 instanceof TransactionError ? error2 : fromPostgresError(error2);
|
|
2161
2165
|
if (enableLogging) {
|
|
2162
2166
|
txLogger2.error("Transaction rolled back", {
|
|
2163
2167
|
txId,
|
|
@@ -2379,110 +2383,149 @@ var init_db = __esm({
|
|
|
2379
2383
|
}
|
|
2380
2384
|
});
|
|
2381
2385
|
|
|
2382
|
-
// src/cache/
|
|
2383
|
-
function
|
|
2384
|
-
return
|
|
2386
|
+
// src/cache/cache-factory.ts
|
|
2387
|
+
function hasCacheConfig() {
|
|
2388
|
+
return !!// Modern (Valkey/Cache)
|
|
2389
|
+
(process.env.VALKEY_URL || process.env.CACHE_URL || process.env.VALKEY_WRITE_URL || process.env.VALKEY_READ_URL || process.env.CACHE_WRITE_URL || process.env.CACHE_READ_URL || process.env.VALKEY_SENTINEL_HOSTS || process.env.VALKEY_CLUSTER_NODES || // Legacy (Redis - backward compatibility)
|
|
2390
|
+
process.env.REDIS_URL || process.env.REDIS_WRITE_URL || process.env.REDIS_READ_URL || process.env.REDIS_SENTINEL_HOSTS || process.env.REDIS_CLUSTER_NODES);
|
|
2391
|
+
}
|
|
2392
|
+
function getEnv(valkeyKey, cacheKey, redisKey) {
|
|
2393
|
+
return process.env[valkeyKey] || process.env[cacheKey] || process.env[redisKey];
|
|
2385
2394
|
}
|
|
2386
2395
|
function createClient(RedisClient, url) {
|
|
2387
2396
|
const options = {};
|
|
2388
|
-
if (url.startsWith("rediss://")) {
|
|
2397
|
+
if (url.startsWith("rediss://") || url.startsWith("valkeys://")) {
|
|
2398
|
+
const rejectUnauthorized = getEnv(
|
|
2399
|
+
"VALKEY_TLS_REJECT_UNAUTHORIZED",
|
|
2400
|
+
"CACHE_TLS_REJECT_UNAUTHORIZED",
|
|
2401
|
+
"REDIS_TLS_REJECT_UNAUTHORIZED"
|
|
2402
|
+
);
|
|
2389
2403
|
options.tls = {
|
|
2390
|
-
rejectUnauthorized:
|
|
2404
|
+
rejectUnauthorized: rejectUnauthorized !== "false"
|
|
2391
2405
|
};
|
|
2392
2406
|
}
|
|
2393
2407
|
return new RedisClient(url, options);
|
|
2394
2408
|
}
|
|
2395
|
-
async function
|
|
2396
|
-
if (!
|
|
2409
|
+
async function createCacheFromEnv() {
|
|
2410
|
+
if (!hasCacheConfig()) {
|
|
2411
|
+
cacheLogger.info("No cache configuration found - running without cache");
|
|
2397
2412
|
return { write: void 0, read: void 0 };
|
|
2398
2413
|
}
|
|
2399
2414
|
try {
|
|
2400
2415
|
const ioredis = await import('ioredis');
|
|
2401
2416
|
const RedisClient = ioredis.default;
|
|
2402
|
-
|
|
2403
|
-
|
|
2417
|
+
const singleUrl = getEnv("VALKEY_URL", "CACHE_URL", "REDIS_URL");
|
|
2418
|
+
const writeUrl = getEnv("VALKEY_WRITE_URL", "CACHE_WRITE_URL", "REDIS_WRITE_URL");
|
|
2419
|
+
const readUrl = getEnv("VALKEY_READ_URL", "CACHE_READ_URL", "REDIS_READ_URL");
|
|
2420
|
+
const clusterNodes = getEnv("VALKEY_CLUSTER_NODES", "CACHE_CLUSTER_NODES", "REDIS_CLUSTER_NODES");
|
|
2421
|
+
const sentinelHosts = getEnv("VALKEY_SENTINEL_HOSTS", "CACHE_SENTINEL_HOSTS", "REDIS_SENTINEL_HOSTS");
|
|
2422
|
+
const masterName = getEnv("VALKEY_MASTER_NAME", "CACHE_MASTER_NAME", "REDIS_MASTER_NAME");
|
|
2423
|
+
const password = getEnv("VALKEY_PASSWORD", "CACHE_PASSWORD", "REDIS_PASSWORD");
|
|
2424
|
+
if (singleUrl && !writeUrl && !readUrl && !clusterNodes) {
|
|
2425
|
+
const client = createClient(RedisClient, singleUrl);
|
|
2426
|
+
cacheLogger.debug("Created single cache instance", { url: singleUrl.replace(/:[^:@]+@/, ":***@") });
|
|
2404
2427
|
return { write: client, read: client };
|
|
2405
2428
|
}
|
|
2406
|
-
if (
|
|
2407
|
-
const write = createClient(RedisClient,
|
|
2408
|
-
const read = createClient(RedisClient,
|
|
2429
|
+
if (writeUrl && readUrl) {
|
|
2430
|
+
const write = createClient(RedisClient, writeUrl);
|
|
2431
|
+
const read = createClient(RedisClient, readUrl);
|
|
2432
|
+
cacheLogger.debug("Created master-replica cache instances");
|
|
2409
2433
|
return { write, read };
|
|
2410
2434
|
}
|
|
2411
|
-
if (
|
|
2412
|
-
const sentinels =
|
|
2435
|
+
if (sentinelHosts && masterName) {
|
|
2436
|
+
const sentinels = sentinelHosts.split(",").map((host) => {
|
|
2413
2437
|
const [hostname, port] = host.trim().split(":");
|
|
2414
2438
|
return { host: hostname, port: Number(port) || 26379 };
|
|
2415
2439
|
});
|
|
2416
2440
|
const options = {
|
|
2417
2441
|
sentinels,
|
|
2418
|
-
name:
|
|
2419
|
-
password
|
|
2442
|
+
name: masterName,
|
|
2443
|
+
password
|
|
2420
2444
|
};
|
|
2421
2445
|
const client = new RedisClient(options);
|
|
2446
|
+
cacheLogger.debug("Created sentinel cache instance", { masterName, sentinels: sentinels.length });
|
|
2422
2447
|
return { write: client, read: client };
|
|
2423
2448
|
}
|
|
2424
|
-
if (
|
|
2425
|
-
const nodes =
|
|
2449
|
+
if (clusterNodes) {
|
|
2450
|
+
const nodes = clusterNodes.split(",").map((node) => {
|
|
2426
2451
|
const [host, port] = node.trim().split(":");
|
|
2427
2452
|
return { host, port: Number(port) || 6379 };
|
|
2428
2453
|
});
|
|
2429
2454
|
const clusterOptions = {
|
|
2430
2455
|
redisOptions: {
|
|
2431
|
-
password
|
|
2456
|
+
password
|
|
2432
2457
|
}
|
|
2433
2458
|
};
|
|
2434
2459
|
const cluster = new RedisClient.Cluster(nodes, clusterOptions);
|
|
2460
|
+
cacheLogger.debug("Created cluster cache instance", { nodes: nodes.length });
|
|
2435
2461
|
return { write: cluster, read: cluster };
|
|
2436
2462
|
}
|
|
2437
|
-
if (
|
|
2438
|
-
const client = createClient(RedisClient,
|
|
2463
|
+
if (singleUrl) {
|
|
2464
|
+
const client = createClient(RedisClient, singleUrl);
|
|
2465
|
+
cacheLogger.debug("Created cache instance (fallback)", { url: singleUrl.replace(/:[^:@]+@/, ":***@") });
|
|
2439
2466
|
return { write: client, read: client };
|
|
2440
2467
|
}
|
|
2468
|
+
cacheLogger.info("No valid cache configuration found - running without cache");
|
|
2441
2469
|
return { write: void 0, read: void 0 };
|
|
2442
|
-
} catch (
|
|
2443
|
-
if (
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2470
|
+
} catch (error2) {
|
|
2471
|
+
if (error2 instanceof Error) {
|
|
2472
|
+
if (error2.message.includes("Cannot find module")) {
|
|
2473
|
+
cacheLogger.warn(
|
|
2474
|
+
"Cache client library not installed",
|
|
2475
|
+
error2,
|
|
2476
|
+
{
|
|
2477
|
+
suggestion: "Install ioredis to enable cache: pnpm install ioredis",
|
|
2478
|
+
mode: "disabled"
|
|
2479
|
+
}
|
|
2480
|
+
);
|
|
2481
|
+
} else {
|
|
2482
|
+
cacheLogger.warn(
|
|
2483
|
+
"Failed to create cache client",
|
|
2484
|
+
error2,
|
|
2485
|
+
{ mode: "disabled" }
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2449
2488
|
} else {
|
|
2450
2489
|
cacheLogger.warn(
|
|
2451
|
-
"Failed to create
|
|
2452
|
-
{ error: String(
|
|
2490
|
+
"Failed to create cache client",
|
|
2491
|
+
{ error: String(error2), mode: "disabled" }
|
|
2453
2492
|
);
|
|
2454
2493
|
}
|
|
2455
2494
|
return { write: void 0, read: void 0 };
|
|
2456
2495
|
}
|
|
2457
2496
|
}
|
|
2458
|
-
async function
|
|
2459
|
-
const { write } = await
|
|
2497
|
+
async function createSingleCacheFromEnv() {
|
|
2498
|
+
const { write } = await createCacheFromEnv();
|
|
2460
2499
|
return write;
|
|
2461
2500
|
}
|
|
2462
2501
|
var cacheLogger;
|
|
2463
|
-
var
|
|
2464
|
-
"src/cache/
|
|
2502
|
+
var init_cache_factory = __esm({
|
|
2503
|
+
"src/cache/cache-factory.ts"() {
|
|
2465
2504
|
init_logger2();
|
|
2466
2505
|
cacheLogger = logger.child("cache");
|
|
2467
2506
|
}
|
|
2468
2507
|
});
|
|
2469
2508
|
|
|
2470
|
-
// src/cache/
|
|
2471
|
-
function
|
|
2509
|
+
// src/cache/cache-manager.ts
|
|
2510
|
+
function getCache() {
|
|
2472
2511
|
return writeInstance;
|
|
2473
2512
|
}
|
|
2474
|
-
function
|
|
2513
|
+
function getCacheRead() {
|
|
2475
2514
|
return readInstance ?? writeInstance;
|
|
2476
2515
|
}
|
|
2477
|
-
function
|
|
2516
|
+
function isCacheDisabled() {
|
|
2517
|
+
return isDisabled;
|
|
2518
|
+
}
|
|
2519
|
+
function setCache(write, read) {
|
|
2478
2520
|
writeInstance = write;
|
|
2479
2521
|
readInstance = read ?? write;
|
|
2522
|
+
isDisabled = !write;
|
|
2480
2523
|
}
|
|
2481
|
-
async function
|
|
2524
|
+
async function initCache() {
|
|
2482
2525
|
if (writeInstance) {
|
|
2483
|
-
return { write: writeInstance, read: readInstance };
|
|
2526
|
+
return { write: writeInstance, read: readInstance, disabled: isDisabled };
|
|
2484
2527
|
}
|
|
2485
|
-
const { write, read } = await
|
|
2528
|
+
const { write, read } = await createCacheFromEnv();
|
|
2486
2529
|
if (write) {
|
|
2487
2530
|
try {
|
|
2488
2531
|
await write.ping();
|
|
@@ -2491,14 +2534,18 @@ async function initRedis() {
|
|
|
2491
2534
|
}
|
|
2492
2535
|
writeInstance = write;
|
|
2493
2536
|
readInstance = read;
|
|
2537
|
+
isDisabled = false;
|
|
2494
2538
|
const hasReplica = read && read !== write;
|
|
2495
2539
|
cacheLogger2.info(
|
|
2496
|
-
hasReplica ? "
|
|
2540
|
+
hasReplica ? "Cache connected (Master-Replica)" : "Cache connected",
|
|
2541
|
+
{ mode: "enabled" }
|
|
2497
2542
|
);
|
|
2498
|
-
|
|
2543
|
+
return { write: writeInstance, read: readInstance, disabled: false };
|
|
2544
|
+
} catch (error2) {
|
|
2499
2545
|
cacheLogger2.error(
|
|
2500
|
-
"
|
|
2501
|
-
|
|
2546
|
+
"Cache connection failed - running in disabled mode",
|
|
2547
|
+
error2 instanceof Error ? error2 : new Error(String(error2)),
|
|
2548
|
+
{ mode: "disabled" }
|
|
2502
2549
|
);
|
|
2503
2550
|
try {
|
|
2504
2551
|
await write.quit();
|
|
@@ -2507,64 +2554,91 @@ async function initRedis() {
|
|
|
2507
2554
|
}
|
|
2508
2555
|
} catch {
|
|
2509
2556
|
}
|
|
2510
|
-
|
|
2557
|
+
isDisabled = true;
|
|
2558
|
+
return { write: void 0, read: void 0, disabled: true };
|
|
2511
2559
|
}
|
|
2512
2560
|
}
|
|
2513
|
-
|
|
2561
|
+
isDisabled = true;
|
|
2562
|
+
cacheLogger2.info("Cache disabled - no configuration or library not installed", { mode: "disabled" });
|
|
2563
|
+
return { write: void 0, read: void 0, disabled: true };
|
|
2514
2564
|
}
|
|
2515
|
-
async function
|
|
2565
|
+
async function closeCache() {
|
|
2566
|
+
if (isDisabled) {
|
|
2567
|
+
cacheLogger2.debug("Cache already disabled, nothing to close");
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2516
2570
|
const closePromises = [];
|
|
2517
2571
|
if (writeInstance) {
|
|
2518
2572
|
closePromises.push(
|
|
2519
2573
|
writeInstance.quit().catch((err) => {
|
|
2520
|
-
cacheLogger2.error("Error closing
|
|
2574
|
+
cacheLogger2.error("Error closing cache write instance", err);
|
|
2521
2575
|
})
|
|
2522
2576
|
);
|
|
2523
2577
|
}
|
|
2524
2578
|
if (readInstance && readInstance !== writeInstance) {
|
|
2525
2579
|
closePromises.push(
|
|
2526
2580
|
readInstance.quit().catch((err) => {
|
|
2527
|
-
cacheLogger2.error("Error closing
|
|
2581
|
+
cacheLogger2.error("Error closing cache read instance", err);
|
|
2528
2582
|
})
|
|
2529
2583
|
);
|
|
2530
2584
|
}
|
|
2531
2585
|
await Promise.all(closePromises);
|
|
2532
2586
|
writeInstance = void 0;
|
|
2533
2587
|
readInstance = void 0;
|
|
2534
|
-
|
|
2588
|
+
isDisabled = true;
|
|
2589
|
+
cacheLogger2.info("Cache connections closed", { mode: "disabled" });
|
|
2535
2590
|
}
|
|
2536
|
-
function
|
|
2591
|
+
function getCacheInfo() {
|
|
2537
2592
|
return {
|
|
2538
2593
|
hasWrite: !!writeInstance,
|
|
2539
2594
|
hasRead: !!readInstance,
|
|
2540
|
-
isReplica: !!(readInstance && readInstance !== writeInstance)
|
|
2595
|
+
isReplica: !!(readInstance && readInstance !== writeInstance),
|
|
2596
|
+
disabled: isDisabled
|
|
2541
2597
|
};
|
|
2542
2598
|
}
|
|
2543
|
-
var cacheLogger2, writeInstance, readInstance;
|
|
2544
|
-
var
|
|
2545
|
-
"src/cache/
|
|
2546
|
-
|
|
2599
|
+
var cacheLogger2, writeInstance, readInstance, isDisabled, getRedis, getRedisRead, setRedis, initRedis, closeRedis, getRedisInfo;
|
|
2600
|
+
var init_cache_manager = __esm({
|
|
2601
|
+
"src/cache/cache-manager.ts"() {
|
|
2602
|
+
init_cache_factory();
|
|
2547
2603
|
init_logger2();
|
|
2548
2604
|
cacheLogger2 = logger.child("cache");
|
|
2605
|
+
isDisabled = false;
|
|
2606
|
+
getRedis = getCache;
|
|
2607
|
+
getRedisRead = getCacheRead;
|
|
2608
|
+
setRedis = setCache;
|
|
2609
|
+
initRedis = initCache;
|
|
2610
|
+
closeRedis = closeCache;
|
|
2611
|
+
getRedisInfo = getCacheInfo;
|
|
2549
2612
|
}
|
|
2550
2613
|
});
|
|
2551
2614
|
|
|
2552
2615
|
// src/cache/index.ts
|
|
2553
2616
|
var cache_exports = {};
|
|
2554
2617
|
__export(cache_exports, {
|
|
2618
|
+
closeCache: () => closeCache,
|
|
2555
2619
|
closeRedis: () => closeRedis,
|
|
2556
|
-
|
|
2557
|
-
|
|
2620
|
+
createCacheFromEnv: () => createCacheFromEnv,
|
|
2621
|
+
createRedisFromEnv: () => createCacheFromEnv,
|
|
2622
|
+
createSingleCacheFromEnv: () => createSingleCacheFromEnv,
|
|
2623
|
+
createSingleRedisFromEnv: () => createSingleCacheFromEnv,
|
|
2624
|
+
getCache: () => getCache,
|
|
2625
|
+
getCacheInfo: () => getCacheInfo,
|
|
2626
|
+
getCacheRead: () => getCacheRead,
|
|
2558
2627
|
getRedis: () => getRedis,
|
|
2559
2628
|
getRedisInfo: () => getRedisInfo,
|
|
2560
2629
|
getRedisRead: () => getRedisRead,
|
|
2630
|
+
initCache: () => initCache,
|
|
2561
2631
|
initRedis: () => initRedis,
|
|
2632
|
+
isCacheDisabled: () => isCacheDisabled,
|
|
2633
|
+
setCache: () => setCache,
|
|
2562
2634
|
setRedis: () => setRedis
|
|
2563
2635
|
});
|
|
2564
2636
|
var init_cache = __esm({
|
|
2565
2637
|
"src/cache/index.ts"() {
|
|
2566
|
-
|
|
2567
|
-
|
|
2638
|
+
init_cache_factory();
|
|
2639
|
+
init_cache_manager();
|
|
2640
|
+
init_cache_manager();
|
|
2641
|
+
init_cache_factory();
|
|
2568
2642
|
}
|
|
2569
2643
|
});
|
|
2570
2644
|
|
|
@@ -2589,8 +2663,8 @@ var AutoRouteLoader = class {
|
|
|
2589
2663
|
}
|
|
2590
2664
|
let failureCount = 0;
|
|
2591
2665
|
for (const file of files) {
|
|
2592
|
-
const
|
|
2593
|
-
if (
|
|
2666
|
+
const success2 = await this.loadRoute(app, file);
|
|
2667
|
+
if (success2) ; else {
|
|
2594
2668
|
failureCount++;
|
|
2595
2669
|
}
|
|
2596
2670
|
}
|
|
@@ -2606,14 +2680,15 @@ var AutoRouteLoader = class {
|
|
|
2606
2680
|
}
|
|
2607
2681
|
/**
|
|
2608
2682
|
* Load routes from an external directory (e.g., from SPFN function packages)
|
|
2609
|
-
*
|
|
2683
|
+
* Reads package.json spfn.prefix and mounts routes under that prefix
|
|
2610
2684
|
*
|
|
2611
2685
|
* @param app - Hono app instance
|
|
2612
2686
|
* @param routesDir - Directory containing route handlers
|
|
2613
2687
|
* @param packageName - Name of the package (for logging)
|
|
2688
|
+
* @param prefix - Optional prefix to mount routes under (from package.json spfn.prefix)
|
|
2614
2689
|
* @returns Route statistics
|
|
2615
2690
|
*/
|
|
2616
|
-
async loadExternalRoutes(app, routesDir, packageName) {
|
|
2691
|
+
async loadExternalRoutes(app, routesDir, packageName, prefix) {
|
|
2617
2692
|
const startTime = Date.now();
|
|
2618
2693
|
const tempRoutesDir = this.routesDir;
|
|
2619
2694
|
this.routesDir = routesDir;
|
|
@@ -2626,8 +2701,8 @@ var AutoRouteLoader = class {
|
|
|
2626
2701
|
let successCount = 0;
|
|
2627
2702
|
let failureCount = 0;
|
|
2628
2703
|
for (const file of files) {
|
|
2629
|
-
const
|
|
2630
|
-
if (
|
|
2704
|
+
const success2 = await this.loadRoute(app, file, prefix);
|
|
2705
|
+
if (success2) {
|
|
2631
2706
|
successCount++;
|
|
2632
2707
|
} else {
|
|
2633
2708
|
failureCount++;
|
|
@@ -2637,6 +2712,7 @@ var AutoRouteLoader = class {
|
|
|
2637
2712
|
if (this.debug) {
|
|
2638
2713
|
routeLogger2.info("External routes loaded", {
|
|
2639
2714
|
package: packageName,
|
|
2715
|
+
prefix: prefix || "/",
|
|
2640
2716
|
total: successCount,
|
|
2641
2717
|
failed: failureCount,
|
|
2642
2718
|
elapsed: `${elapsed}ms`
|
|
@@ -2680,7 +2756,7 @@ var AutoRouteLoader = class {
|
|
|
2680
2756
|
isValidRouteFile(fileName) {
|
|
2681
2757
|
return fileName === "index.ts" || fileName === "index.js" || fileName === "index.mjs";
|
|
2682
2758
|
}
|
|
2683
|
-
async loadRoute(app, absolutePath) {
|
|
2759
|
+
async loadRoute(app, absolutePath, prefix) {
|
|
2684
2760
|
const relativePath = relative(this.routesDir, absolutePath);
|
|
2685
2761
|
try {
|
|
2686
2762
|
const module = await import(absolutePath);
|
|
@@ -2696,11 +2772,24 @@ var AutoRouteLoader = class {
|
|
|
2696
2772
|
return false;
|
|
2697
2773
|
}
|
|
2698
2774
|
const contractPaths = this.extractContractPaths(module);
|
|
2775
|
+
if (prefix) {
|
|
2776
|
+
const invalidPaths = contractPaths.filter((path) => !path.startsWith(prefix));
|
|
2777
|
+
if (invalidPaths.length > 0) {
|
|
2778
|
+
routeLogger2.error("Contract paths must include the package prefix", {
|
|
2779
|
+
file: relativePath,
|
|
2780
|
+
prefix,
|
|
2781
|
+
invalidPaths,
|
|
2782
|
+
hint: `Contract paths should start with "${prefix}". Example: path: "${prefix}/labels"`
|
|
2783
|
+
});
|
|
2784
|
+
return false;
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2699
2787
|
this.registerContractBasedMiddlewares(app, contractPaths, module);
|
|
2700
2788
|
app.route("/", module.default);
|
|
2701
2789
|
contractPaths.forEach((path) => {
|
|
2702
2790
|
this.routes.push({
|
|
2703
2791
|
path,
|
|
2792
|
+
// Use contract path as-is (already includes prefix)
|
|
2704
2793
|
file: relativePath,
|
|
2705
2794
|
meta: module.meta,
|
|
2706
2795
|
priority: this.calculateContractPriority(path)
|
|
@@ -2711,8 +2800,8 @@ var AutoRouteLoader = class {
|
|
|
2711
2800
|
}
|
|
2712
2801
|
});
|
|
2713
2802
|
return true;
|
|
2714
|
-
} catch (
|
|
2715
|
-
this.categorizeAndLogError(
|
|
2803
|
+
} catch (error2) {
|
|
2804
|
+
this.categorizeAndLogError(error2, relativePath);
|
|
2716
2805
|
return false;
|
|
2717
2806
|
}
|
|
2718
2807
|
}
|
|
@@ -2768,9 +2857,9 @@ var AutoRouteLoader = class {
|
|
|
2768
2857
|
}
|
|
2769
2858
|
}
|
|
2770
2859
|
}
|
|
2771
|
-
categorizeAndLogError(
|
|
2772
|
-
const message =
|
|
2773
|
-
const stack =
|
|
2860
|
+
categorizeAndLogError(error2, relativePath) {
|
|
2861
|
+
const message = error2.message;
|
|
2862
|
+
const stack = error2.stack;
|
|
2774
2863
|
if (message.includes("Cannot find module") || message.includes("MODULE_NOT_FOUND")) {
|
|
2775
2864
|
routeLogger2.error("Missing dependency", {
|
|
2776
2865
|
file: relativePath,
|
|
@@ -2827,15 +2916,16 @@ async function loadRoutes(app, options) {
|
|
|
2827
2916
|
routeLogger2.info("Loading function routes", { count: functionRoutes.length });
|
|
2828
2917
|
for (const func of functionRoutes) {
|
|
2829
2918
|
try {
|
|
2830
|
-
await loader.loadExternalRoutes(app, func.routesDir, func.packageName);
|
|
2919
|
+
await loader.loadExternalRoutes(app, func.routesDir, func.packageName, func.prefix);
|
|
2831
2920
|
routeLogger2.info("Function routes loaded", {
|
|
2832
2921
|
package: func.packageName,
|
|
2833
|
-
routesDir: func.routesDir
|
|
2922
|
+
routesDir: func.routesDir,
|
|
2923
|
+
prefix: func.prefix || "/"
|
|
2834
2924
|
});
|
|
2835
|
-
} catch (
|
|
2925
|
+
} catch (error2) {
|
|
2836
2926
|
routeLogger2.error("Failed to load function routes", {
|
|
2837
2927
|
package: func.packageName,
|
|
2838
|
-
error:
|
|
2928
|
+
error: error2 instanceof Error ? error2.message : "Unknown error"
|
|
2839
2929
|
});
|
|
2840
2930
|
}
|
|
2841
2931
|
}
|
|
@@ -2870,6 +2960,7 @@ function ErrorHandler(options = {}) {
|
|
|
2870
2960
|
});
|
|
2871
2961
|
}
|
|
2872
2962
|
const response = {
|
|
2963
|
+
success: false,
|
|
2873
2964
|
error: {
|
|
2874
2965
|
message: err.message || "Internal Server Error",
|
|
2875
2966
|
type: errorType,
|
|
@@ -2936,15 +3027,15 @@ function RequestLogger(config) {
|
|
|
2936
3027
|
logData.slow = true;
|
|
2937
3028
|
}
|
|
2938
3029
|
apiLogger[logLevel]("Request completed", logData);
|
|
2939
|
-
} catch (
|
|
3030
|
+
} catch (error2) {
|
|
2940
3031
|
const duration = Date.now() - startTime;
|
|
2941
|
-
apiLogger.error("Request failed",
|
|
3032
|
+
apiLogger.error("Request failed", error2, {
|
|
2942
3033
|
requestId,
|
|
2943
3034
|
method,
|
|
2944
3035
|
path,
|
|
2945
3036
|
duration
|
|
2946
3037
|
});
|
|
2947
|
-
throw
|
|
3038
|
+
throw error2;
|
|
2948
3039
|
}
|
|
2949
3040
|
};
|
|
2950
3041
|
}
|
|
@@ -2969,9 +3060,9 @@ function createHealthCheckHandler(detailed) {
|
|
|
2969
3060
|
try {
|
|
2970
3061
|
await db.execute("SELECT 1");
|
|
2971
3062
|
dbStatus = "connected";
|
|
2972
|
-
} catch (
|
|
3063
|
+
} catch (error2) {
|
|
2973
3064
|
dbStatus = "error";
|
|
2974
|
-
dbError =
|
|
3065
|
+
dbError = error2 instanceof Error ? error2.message : String(error2);
|
|
2975
3066
|
}
|
|
2976
3067
|
}
|
|
2977
3068
|
const redis = getRedis2();
|
|
@@ -2981,9 +3072,9 @@ function createHealthCheckHandler(detailed) {
|
|
|
2981
3072
|
try {
|
|
2982
3073
|
await redis.ping();
|
|
2983
3074
|
redisStatus = "connected";
|
|
2984
|
-
} catch (
|
|
3075
|
+
} catch (error2) {
|
|
2985
3076
|
redisStatus = "error";
|
|
2986
|
-
redisError =
|
|
3077
|
+
redisError = error2 instanceof Error ? error2.message : String(error2);
|
|
2987
3078
|
}
|
|
2988
3079
|
}
|
|
2989
3080
|
response.services = {
|
|
@@ -3131,8 +3222,8 @@ async function executeBeforeRoutesHook(app, config) {
|
|
|
3131
3222
|
}
|
|
3132
3223
|
try {
|
|
3133
3224
|
await config.beforeRoutes(app);
|
|
3134
|
-
} catch (
|
|
3135
|
-
serverLogger.error("beforeRoutes hook failed",
|
|
3225
|
+
} catch (error2) {
|
|
3226
|
+
serverLogger.error("beforeRoutes hook failed", error2);
|
|
3136
3227
|
throw new Error("Server initialization failed in beforeRoutes hook");
|
|
3137
3228
|
}
|
|
3138
3229
|
}
|
|
@@ -3150,8 +3241,8 @@ async function executeAfterRoutesHook(app, config) {
|
|
|
3150
3241
|
}
|
|
3151
3242
|
try {
|
|
3152
3243
|
await config.afterRoutes(app);
|
|
3153
|
-
} catch (
|
|
3154
|
-
serverLogger.error("afterRoutes hook failed",
|
|
3244
|
+
} catch (error2) {
|
|
3245
|
+
serverLogger.error("afterRoutes hook failed", error2);
|
|
3155
3246
|
throw new Error("Server initialization failed in afterRoutes hook");
|
|
3156
3247
|
}
|
|
3157
3248
|
}
|
|
@@ -3271,11 +3362,11 @@ async function startServer(config) {
|
|
|
3271
3362
|
await shutdownServer();
|
|
3272
3363
|
}
|
|
3273
3364
|
};
|
|
3274
|
-
} catch (
|
|
3275
|
-
const err =
|
|
3365
|
+
} catch (error2) {
|
|
3366
|
+
const err = error2;
|
|
3276
3367
|
serverLogger2.error("Server initialization failed", err);
|
|
3277
3368
|
await cleanupOnFailure();
|
|
3278
|
-
throw
|
|
3369
|
+
throw error2;
|
|
3279
3370
|
}
|
|
3280
3371
|
}
|
|
3281
3372
|
async function loadAndMergeConfig(config) {
|
|
@@ -3373,8 +3464,8 @@ function createGracefulShutdown(shutdownServer, config) {
|
|
|
3373
3464
|
]);
|
|
3374
3465
|
serverLogger2.info("Graceful shutdown completed successfully");
|
|
3375
3466
|
process.exit(0);
|
|
3376
|
-
} catch (
|
|
3377
|
-
const err =
|
|
3467
|
+
} catch (error2) {
|
|
3468
|
+
const err = error2;
|
|
3378
3469
|
if (err.message && err.message.includes("timeout")) {
|
|
3379
3470
|
serverLogger2.error("Graceful shutdown timeout, forcing exit", err);
|
|
3380
3471
|
} else {
|
|
@@ -3387,8 +3478,8 @@ function createGracefulShutdown(shutdownServer, config) {
|
|
|
3387
3478
|
function registerShutdownHandlers(shutdown) {
|
|
3388
3479
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
3389
3480
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
3390
|
-
process.on("uncaughtException", (
|
|
3391
|
-
serverLogger2.error("Uncaught exception",
|
|
3481
|
+
process.on("uncaughtException", (error2) => {
|
|
3482
|
+
serverLogger2.error("Uncaught exception", error2);
|
|
3392
3483
|
shutdown("UNCAUGHT_EXCEPTION");
|
|
3393
3484
|
});
|
|
3394
3485
|
process.on("unhandledRejection", (reason, promise) => {
|