@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/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { join, dirname, relative, basename } from 'path';
|
|
|
4
4
|
import { config } from 'dotenv';
|
|
5
5
|
import postgres from 'postgres';
|
|
6
6
|
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
7
|
-
import {
|
|
7
|
+
import { timestamp, bigserial, pgSchema } from 'drizzle-orm/pg-core';
|
|
8
8
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
9
9
|
import { randomUUID, randomBytes } from 'crypto';
|
|
10
10
|
import { createMiddleware } from 'hono/factory';
|
|
@@ -12,7 +12,6 @@ import { eq, and } from 'drizzle-orm';
|
|
|
12
12
|
import { Hono } from 'hono';
|
|
13
13
|
import { cors } from 'hono/cors';
|
|
14
14
|
import { readdir, stat } from 'fs/promises';
|
|
15
|
-
import { Value } from '@sinclair/typebox/value';
|
|
16
15
|
import { serve } from '@hono/node-server';
|
|
17
16
|
import { networkInterfaces } from 'os';
|
|
18
17
|
|
|
@@ -129,11 +128,11 @@ function formatTimestampHuman(date) {
|
|
|
129
128
|
const ms = String(date.getMilliseconds()).padStart(3, "0");
|
|
130
129
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;
|
|
131
130
|
}
|
|
132
|
-
function formatError(
|
|
131
|
+
function formatError(error2) {
|
|
133
132
|
const lines = [];
|
|
134
|
-
lines.push(`${
|
|
135
|
-
if (
|
|
136
|
-
const stackLines =
|
|
133
|
+
lines.push(`${error2.name}: ${error2.message}`);
|
|
134
|
+
if (error2.stack) {
|
|
135
|
+
const stackLines = error2.stack.split("\n").slice(1);
|
|
137
136
|
lines.push(...stackLines);
|
|
138
137
|
}
|
|
139
138
|
return lines.join("\n");
|
|
@@ -319,7 +318,7 @@ var init_logger = __esm({
|
|
|
319
318
|
/**
|
|
320
319
|
* Log processing (internal)
|
|
321
320
|
*/
|
|
322
|
-
log(level, message,
|
|
321
|
+
log(level, message, error2, context) {
|
|
323
322
|
if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.config.level]) {
|
|
324
323
|
return;
|
|
325
324
|
}
|
|
@@ -328,7 +327,7 @@ var init_logger = __esm({
|
|
|
328
327
|
level,
|
|
329
328
|
message,
|
|
330
329
|
module: this.module,
|
|
331
|
-
error,
|
|
330
|
+
error: error2,
|
|
332
331
|
// Mask sensitive information in context to prevent credential leaks
|
|
333
332
|
context: context ? maskSensitiveData(context) : void 0
|
|
334
333
|
};
|
|
@@ -339,8 +338,8 @@ var init_logger = __esm({
|
|
|
339
338
|
*/
|
|
340
339
|
processTransports(metadata) {
|
|
341
340
|
const promises = this.config.transports.filter((transport) => transport.enabled).map((transport) => this.safeTransportLog(transport, metadata));
|
|
342
|
-
Promise.all(promises).catch((
|
|
343
|
-
const errorMessage =
|
|
341
|
+
Promise.all(promises).catch((error2) => {
|
|
342
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
344
343
|
process.stderr.write(`[Logger] Transport error: ${errorMessage}
|
|
345
344
|
`);
|
|
346
345
|
});
|
|
@@ -351,8 +350,8 @@ var init_logger = __esm({
|
|
|
351
350
|
async safeTransportLog(transport, metadata) {
|
|
352
351
|
try {
|
|
353
352
|
await transport.log(metadata);
|
|
354
|
-
} catch (
|
|
355
|
-
const errorMessage =
|
|
353
|
+
} catch (error2) {
|
|
354
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
356
355
|
process.stderr.write(`[Logger] Transport "${transport.name}" failed: ${errorMessage}
|
|
357
356
|
`);
|
|
358
357
|
}
|
|
@@ -442,11 +441,11 @@ var init_file = __esm({
|
|
|
442
441
|
}
|
|
443
442
|
if (this.currentStream) {
|
|
444
443
|
return new Promise((resolve, reject) => {
|
|
445
|
-
this.currentStream.write(message + "\n", "utf-8", (
|
|
446
|
-
if (
|
|
447
|
-
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}
|
|
448
447
|
`);
|
|
449
|
-
reject(
|
|
448
|
+
reject(error2);
|
|
450
449
|
} else {
|
|
451
450
|
resolve();
|
|
452
451
|
}
|
|
@@ -468,8 +467,8 @@ var init_file = __esm({
|
|
|
468
467
|
encoding: "utf-8"
|
|
469
468
|
});
|
|
470
469
|
this.currentFilename = filename;
|
|
471
|
-
this.currentStream.on("error", (
|
|
472
|
-
process.stderr.write(`[FileTransport] Stream error: ${
|
|
470
|
+
this.currentStream.on("error", (error2) => {
|
|
471
|
+
process.stderr.write(`[FileTransport] Stream error: ${error2.message}
|
|
473
472
|
`);
|
|
474
473
|
this.currentStream = null;
|
|
475
474
|
this.currentFilename = null;
|
|
@@ -483,9 +482,9 @@ var init_file = __esm({
|
|
|
483
482
|
return;
|
|
484
483
|
}
|
|
485
484
|
return new Promise((resolve, reject) => {
|
|
486
|
-
this.currentStream.end((
|
|
487
|
-
if (
|
|
488
|
-
reject(
|
|
485
|
+
this.currentStream.end((error2) => {
|
|
486
|
+
if (error2) {
|
|
487
|
+
reject(error2);
|
|
489
488
|
} else {
|
|
490
489
|
this.currentStream = null;
|
|
491
490
|
this.currentFilename = null;
|
|
@@ -510,8 +509,8 @@ var init_file = __esm({
|
|
|
510
509
|
if (stats.size >= this.maxFileSize) {
|
|
511
510
|
await this.rotateBySize();
|
|
512
511
|
}
|
|
513
|
-
} catch (
|
|
514
|
-
const errorMessage =
|
|
512
|
+
} catch (error2) {
|
|
513
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
515
514
|
process.stderr.write(`[FileTransport] Failed to check file size: ${errorMessage}
|
|
516
515
|
`);
|
|
517
516
|
}
|
|
@@ -537,8 +536,8 @@ var init_file = __esm({
|
|
|
537
536
|
const newPath2 = join(this.logDir, `${baseName}.${newNum}.log`);
|
|
538
537
|
try {
|
|
539
538
|
renameSync(oldPath, newPath2);
|
|
540
|
-
} catch (
|
|
541
|
-
const errorMessage =
|
|
539
|
+
} catch (error2) {
|
|
540
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
542
541
|
process.stderr.write(`[FileTransport] Failed to rotate file: ${errorMessage}
|
|
543
542
|
`);
|
|
544
543
|
}
|
|
@@ -550,8 +549,8 @@ var init_file = __esm({
|
|
|
550
549
|
if (existsSync(currentPath)) {
|
|
551
550
|
renameSync(currentPath, newPath);
|
|
552
551
|
}
|
|
553
|
-
} catch (
|
|
554
|
-
const errorMessage =
|
|
552
|
+
} catch (error2) {
|
|
553
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
555
554
|
process.stderr.write(`[FileTransport] Failed to rotate current file: ${errorMessage}
|
|
556
555
|
`);
|
|
557
556
|
}
|
|
@@ -578,15 +577,15 @@ var init_file = __esm({
|
|
|
578
577
|
const filepath = join(this.logDir, file);
|
|
579
578
|
try {
|
|
580
579
|
unlinkSync(filepath);
|
|
581
|
-
} catch (
|
|
582
|
-
const errorMessage =
|
|
580
|
+
} catch (error2) {
|
|
581
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
583
582
|
process.stderr.write(`[FileTransport] Failed to delete old file "${file}": ${errorMessage}
|
|
584
583
|
`);
|
|
585
584
|
}
|
|
586
585
|
}
|
|
587
586
|
}
|
|
588
|
-
} catch (
|
|
589
|
-
const errorMessage =
|
|
587
|
+
} catch (error2) {
|
|
588
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
590
589
|
process.stderr.write(`[FileTransport] Failed to clean old files: ${errorMessage}
|
|
591
590
|
`);
|
|
592
591
|
}
|
|
@@ -645,8 +644,8 @@ function validateDirectoryWritable(dirPath) {
|
|
|
645
644
|
if (!existsSync(dirPath)) {
|
|
646
645
|
try {
|
|
647
646
|
mkdirSync(dirPath, { recursive: true });
|
|
648
|
-
} catch (
|
|
649
|
-
const errorMessage =
|
|
647
|
+
} catch (error2) {
|
|
648
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
650
649
|
throw new Error(`Failed to create log directory "${dirPath}": ${errorMessage}`);
|
|
651
650
|
}
|
|
652
651
|
}
|
|
@@ -659,8 +658,8 @@ function validateDirectoryWritable(dirPath) {
|
|
|
659
658
|
try {
|
|
660
659
|
writeFileSync(testFile, "test", "utf-8");
|
|
661
660
|
unlinkSync(testFile);
|
|
662
|
-
} catch (
|
|
663
|
-
const errorMessage =
|
|
661
|
+
} catch (error2) {
|
|
662
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
664
663
|
throw new Error(`Cannot write to log directory "${dirPath}": ${errorMessage}`);
|
|
665
664
|
}
|
|
666
665
|
}
|
|
@@ -737,11 +736,11 @@ function validateConfig() {
|
|
|
737
736
|
validateFileConfig();
|
|
738
737
|
validateSlackConfig();
|
|
739
738
|
validateEmailConfig();
|
|
740
|
-
} catch (
|
|
741
|
-
if (
|
|
742
|
-
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}`);
|
|
743
742
|
}
|
|
744
|
-
throw
|
|
743
|
+
throw error2;
|
|
745
744
|
}
|
|
746
745
|
}
|
|
747
746
|
var init_config = __esm({
|
|
@@ -879,24 +878,28 @@ function discoverFunctionRoutes(cwd = process.cwd()) {
|
|
|
879
878
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
880
879
|
if (pkg.spfn?.routes?.dir) {
|
|
881
880
|
const { dir } = pkg.spfn.routes;
|
|
881
|
+
const prefix = pkg.spfn.prefix;
|
|
882
882
|
const packagePath = dirname(pkgPath);
|
|
883
883
|
const routesDir = join(packagePath, dir);
|
|
884
884
|
functions.push({
|
|
885
885
|
packageName,
|
|
886
886
|
routesDir,
|
|
887
|
-
packagePath
|
|
887
|
+
packagePath,
|
|
888
|
+
prefix
|
|
889
|
+
// Include prefix in function info
|
|
888
890
|
});
|
|
889
891
|
routeLogger.debug("Discovered function routes", {
|
|
890
892
|
package: packageName,
|
|
891
|
-
dir
|
|
893
|
+
dir,
|
|
894
|
+
prefix: prefix || "(none)"
|
|
892
895
|
});
|
|
893
896
|
}
|
|
894
|
-
} catch (
|
|
897
|
+
} catch (error2) {
|
|
895
898
|
}
|
|
896
899
|
}
|
|
897
|
-
} catch (
|
|
900
|
+
} catch (error2) {
|
|
898
901
|
routeLogger.warn("Failed to discover function routes", {
|
|
899
|
-
error:
|
|
902
|
+
error: error2 instanceof Error ? error2.message : "Unknown error"
|
|
900
903
|
});
|
|
901
904
|
}
|
|
902
905
|
return functions;
|
|
@@ -910,7 +913,7 @@ var init_function_routes = __esm({
|
|
|
910
913
|
});
|
|
911
914
|
|
|
912
915
|
// src/errors/database-errors.ts
|
|
913
|
-
var DatabaseError, ConnectionError, QueryError,
|
|
916
|
+
var DatabaseError, ConnectionError, QueryError, ConstraintViolationError, TransactionError, DeadlockError, DuplicateEntryError;
|
|
914
917
|
var init_database_errors = __esm({
|
|
915
918
|
"src/errors/database-errors.ts"() {
|
|
916
919
|
DatabaseError = class extends Error {
|
|
@@ -950,16 +953,10 @@ var init_database_errors = __esm({
|
|
|
950
953
|
this.name = "QueryError";
|
|
951
954
|
}
|
|
952
955
|
};
|
|
953
|
-
|
|
954
|
-
constructor(resource, id2) {
|
|
955
|
-
super(`${resource} with id ${id2} not found`, 404, { resource, id: id2 });
|
|
956
|
-
this.name = "NotFoundError";
|
|
957
|
-
}
|
|
958
|
-
};
|
|
959
|
-
ValidationError = class extends QueryError {
|
|
956
|
+
ConstraintViolationError = class extends QueryError {
|
|
960
957
|
constructor(message, details) {
|
|
961
958
|
super(message, 400, details);
|
|
962
|
-
this.name = "
|
|
959
|
+
this.name = "ConstraintViolationError";
|
|
963
960
|
}
|
|
964
961
|
};
|
|
965
962
|
TransactionError = class extends DatabaseError {
|
|
@@ -990,9 +987,6 @@ var init_http_errors = __esm({
|
|
|
990
987
|
});
|
|
991
988
|
|
|
992
989
|
// src/errors/error-utils.ts
|
|
993
|
-
function isDatabaseError(error) {
|
|
994
|
-
return error instanceof DatabaseError;
|
|
995
|
-
}
|
|
996
990
|
var init_error_utils = __esm({
|
|
997
991
|
"src/errors/error-utils.ts"() {
|
|
998
992
|
init_database_errors();
|
|
@@ -1082,8 +1076,8 @@ function loadSingleFile(filePath, debug) {
|
|
|
1082
1076
|
});
|
|
1083
1077
|
}
|
|
1084
1078
|
return { success: true, parsed };
|
|
1085
|
-
} catch (
|
|
1086
|
-
const message =
|
|
1079
|
+
} catch (error2) {
|
|
1080
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1087
1081
|
envLogger.error("Error loading environment file", {
|
|
1088
1082
|
path: filePath,
|
|
1089
1083
|
error: message
|
|
@@ -1099,12 +1093,12 @@ function validateRequiredVars(required, debug) {
|
|
|
1099
1093
|
}
|
|
1100
1094
|
}
|
|
1101
1095
|
if (missing.length > 0) {
|
|
1102
|
-
const
|
|
1096
|
+
const error2 = `Required environment variables missing: ${missing.join(", ")}`;
|
|
1103
1097
|
envLogger.error("Environment validation failed", {
|
|
1104
1098
|
missing,
|
|
1105
1099
|
required
|
|
1106
1100
|
});
|
|
1107
|
-
throw new Error(
|
|
1101
|
+
throw new Error(error2);
|
|
1108
1102
|
}
|
|
1109
1103
|
if (debug) {
|
|
1110
1104
|
envLogger.debug("Required environment variables validated", {
|
|
@@ -1185,12 +1179,12 @@ function loadEnvironment(options = {}) {
|
|
|
1185
1179
|
if (required.length > 0) {
|
|
1186
1180
|
try {
|
|
1187
1181
|
validateRequiredVars(required, debug);
|
|
1188
|
-
} catch (
|
|
1182
|
+
} catch (error2) {
|
|
1189
1183
|
result.success = false;
|
|
1190
1184
|
result.errors = [
|
|
1191
|
-
|
|
1185
|
+
error2 instanceof Error ? error2.message : "Validation failed"
|
|
1192
1186
|
];
|
|
1193
|
-
throw
|
|
1187
|
+
throw error2;
|
|
1194
1188
|
}
|
|
1195
1189
|
}
|
|
1196
1190
|
if (result.warnings.length > 0) {
|
|
@@ -1247,9 +1241,9 @@ function parseUniqueViolation(message) {
|
|
|
1247
1241
|
}
|
|
1248
1242
|
return null;
|
|
1249
1243
|
}
|
|
1250
|
-
function fromPostgresError(
|
|
1251
|
-
const code =
|
|
1252
|
-
const message =
|
|
1244
|
+
function fromPostgresError(error2) {
|
|
1245
|
+
const code = error2?.code;
|
|
1246
|
+
const message = error2?.message || "Database error occurred";
|
|
1253
1247
|
switch (code) {
|
|
1254
1248
|
// Class 08 — Connection Exception
|
|
1255
1249
|
case "08000":
|
|
@@ -1270,11 +1264,11 @@ function fromPostgresError(error) {
|
|
|
1270
1264
|
case "23000":
|
|
1271
1265
|
// integrity_constraint_violation
|
|
1272
1266
|
case "23001":
|
|
1273
|
-
return new
|
|
1267
|
+
return new ConstraintViolationError(message, { code, constraint: "integrity" });
|
|
1274
1268
|
case "23502":
|
|
1275
|
-
return new
|
|
1269
|
+
return new ConstraintViolationError(message, { code, constraint: "not_null" });
|
|
1276
1270
|
case "23503":
|
|
1277
|
-
return new
|
|
1271
|
+
return new ConstraintViolationError(message, { code, constraint: "foreign_key" });
|
|
1278
1272
|
case "23505":
|
|
1279
1273
|
const parsed = parseUniqueViolation(message);
|
|
1280
1274
|
if (parsed) {
|
|
@@ -1282,7 +1276,7 @@ function fromPostgresError(error) {
|
|
|
1282
1276
|
}
|
|
1283
1277
|
return new DuplicateEntryError("field", "value");
|
|
1284
1278
|
case "23514":
|
|
1285
|
-
return new
|
|
1279
|
+
return new ConstraintViolationError(message, { code, constraint: "check" });
|
|
1286
1280
|
// Class 40 — Transaction Rollback
|
|
1287
1281
|
case "40000":
|
|
1288
1282
|
// transaction_rollback
|
|
@@ -1365,8 +1359,8 @@ async function createDatabaseConnection(connectionString, poolConfig, retryConfi
|
|
|
1365
1359
|
dbLogger.info("Database connected successfully");
|
|
1366
1360
|
}
|
|
1367
1361
|
return client;
|
|
1368
|
-
} catch (
|
|
1369
|
-
lastError = fromPostgresError(
|
|
1362
|
+
} catch (error2) {
|
|
1363
|
+
lastError = fromPostgresError(error2);
|
|
1370
1364
|
if (attempt < retryConfig.maxRetries) {
|
|
1371
1365
|
const delayMs = Math.min(
|
|
1372
1366
|
retryConfig.initialDelay * Math.pow(retryConfig.factor, attempt),
|
|
@@ -1392,8 +1386,8 @@ async function checkConnection(client) {
|
|
|
1392
1386
|
try {
|
|
1393
1387
|
await client`SELECT 1 as health_check`;
|
|
1394
1388
|
return true;
|
|
1395
|
-
} catch (
|
|
1396
|
-
dbLogger.error("Database health check failed",
|
|
1389
|
+
} catch (error2) {
|
|
1390
|
+
dbLogger.error("Database health check failed", error2);
|
|
1397
1391
|
return false;
|
|
1398
1392
|
}
|
|
1399
1393
|
}
|
|
@@ -1563,8 +1557,8 @@ async function createDatabaseFromEnv(options) {
|
|
|
1563
1557
|
dbLogger2.warn("No database pattern detected");
|
|
1564
1558
|
return { write: void 0, read: void 0 };
|
|
1565
1559
|
}
|
|
1566
|
-
} catch (
|
|
1567
|
-
const message =
|
|
1560
|
+
} catch (error2) {
|
|
1561
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1568
1562
|
dbLogger2.error("Failed to create database connection", {
|
|
1569
1563
|
error: message,
|
|
1570
1564
|
stage: "initialization",
|
|
@@ -1573,7 +1567,7 @@ async function createDatabaseFromEnv(options) {
|
|
|
1573
1567
|
hasUrl: !!process.env.DATABASE_URL,
|
|
1574
1568
|
hasReplicaUrl: !!process.env.DATABASE_REPLICA_URL
|
|
1575
1569
|
});
|
|
1576
|
-
throw new Error(`Database connection failed: ${message}`, { cause:
|
|
1570
|
+
throw new Error(`Database connection failed: ${message}`, { cause: error2 });
|
|
1577
1571
|
}
|
|
1578
1572
|
}
|
|
1579
1573
|
var dbLogger2;
|
|
@@ -1638,8 +1632,8 @@ function startHealthCheck(config, options, getDatabase2, closeDatabase2) {
|
|
|
1638
1632
|
if (read && read !== write) {
|
|
1639
1633
|
await read.execute("SELECT 1");
|
|
1640
1634
|
}
|
|
1641
|
-
} catch (
|
|
1642
|
-
const message =
|
|
1635
|
+
} catch (error2) {
|
|
1636
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1643
1637
|
dbLogger3.error("Database health check failed", { error: message });
|
|
1644
1638
|
if (config.reconnect) {
|
|
1645
1639
|
await attemptReconnection(config, options, closeDatabase2);
|
|
@@ -1668,8 +1662,8 @@ async function attemptReconnection(config, options, closeDatabase2) {
|
|
|
1668
1662
|
dbLogger3.info("Database reconnection successful", { attempt });
|
|
1669
1663
|
return;
|
|
1670
1664
|
}
|
|
1671
|
-
} catch (
|
|
1672
|
-
const message =
|
|
1665
|
+
} catch (error2) {
|
|
1666
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1673
1667
|
dbLogger3.error(`Reconnection attempt ${attempt} failed`, {
|
|
1674
1668
|
error: message,
|
|
1675
1669
|
attempt,
|
|
@@ -1746,11 +1740,11 @@ async function initDatabase(options) {
|
|
|
1746
1740
|
logQueries: monConfig.logQueries
|
|
1747
1741
|
});
|
|
1748
1742
|
}
|
|
1749
|
-
} catch (
|
|
1750
|
-
const message =
|
|
1743
|
+
} catch (error2) {
|
|
1744
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1751
1745
|
dbLogger4.error("Database connection failed", { error: message });
|
|
1752
1746
|
await closeDatabase();
|
|
1753
|
-
throw new Error(`Database connection test failed: ${message}`, { cause:
|
|
1747
|
+
throw new Error(`Database connection test failed: ${message}`, { cause: error2 });
|
|
1754
1748
|
}
|
|
1755
1749
|
} else {
|
|
1756
1750
|
dbLogger4.warn("No database configuration found");
|
|
@@ -1784,9 +1778,9 @@ async function closeDatabase() {
|
|
|
1784
1778
|
}
|
|
1785
1779
|
await Promise.all(closePromises);
|
|
1786
1780
|
dbLogger4.info("All database connections closed");
|
|
1787
|
-
} catch (
|
|
1788
|
-
dbLogger4.error("Error during database cleanup",
|
|
1789
|
-
throw
|
|
1781
|
+
} catch (error2) {
|
|
1782
|
+
dbLogger4.error("Error during database cleanup", error2);
|
|
1783
|
+
throw error2;
|
|
1790
1784
|
} finally {
|
|
1791
1785
|
setWriteInstance(void 0);
|
|
1792
1786
|
setReadInstance(void 0);
|
|
@@ -1892,7 +1886,7 @@ function discoverPackageSchemas(cwd) {
|
|
|
1892
1886
|
...Object.keys(projectPkg.dependencies || {}),
|
|
1893
1887
|
...Object.keys(projectPkg.devDependencies || {})
|
|
1894
1888
|
]);
|
|
1895
|
-
} catch (
|
|
1889
|
+
} catch (error2) {
|
|
1896
1890
|
}
|
|
1897
1891
|
}
|
|
1898
1892
|
const checkPackage = (_pkgName, pkgPath) => {
|
|
@@ -1911,7 +1905,7 @@ function discoverPackageSchemas(cwd) {
|
|
|
1911
1905
|
schemas.push(...schemaFiles);
|
|
1912
1906
|
}
|
|
1913
1907
|
}
|
|
1914
|
-
} catch (
|
|
1908
|
+
} catch (error2) {
|
|
1915
1909
|
}
|
|
1916
1910
|
};
|
|
1917
1911
|
const spfnDir = join(nodeModulesPath, "@spfn");
|
|
@@ -1921,7 +1915,7 @@ function discoverPackageSchemas(cwd) {
|
|
|
1921
1915
|
for (const pkg of spfnPackages) {
|
|
1922
1916
|
checkPackage(`@spfn/${pkg}`, join(spfnDir, pkg));
|
|
1923
1917
|
}
|
|
1924
|
-
} catch (
|
|
1918
|
+
} catch (error2) {
|
|
1925
1919
|
}
|
|
1926
1920
|
}
|
|
1927
1921
|
for (const depName of directDeps) {
|
|
@@ -2165,9 +2159,9 @@ function Transactional(options = {}) {
|
|
|
2165
2159
|
});
|
|
2166
2160
|
}
|
|
2167
2161
|
}
|
|
2168
|
-
} catch (
|
|
2162
|
+
} catch (error2) {
|
|
2169
2163
|
const duration = Date.now() - startTime;
|
|
2170
|
-
const customError =
|
|
2164
|
+
const customError = error2 instanceof TransactionError ? error2 : fromPostgresError(error2);
|
|
2171
2165
|
if (enableLogging) {
|
|
2172
2166
|
txLogger2.error("Transaction rolled back", {
|
|
2173
2167
|
txId,
|
|
@@ -2389,110 +2383,149 @@ var init_db = __esm({
|
|
|
2389
2383
|
}
|
|
2390
2384
|
});
|
|
2391
2385
|
|
|
2392
|
-
// src/cache/
|
|
2393
|
-
function
|
|
2394
|
-
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];
|
|
2395
2394
|
}
|
|
2396
2395
|
function createClient(RedisClient, url) {
|
|
2397
2396
|
const options = {};
|
|
2398
|
-
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
|
+
);
|
|
2399
2403
|
options.tls = {
|
|
2400
|
-
rejectUnauthorized:
|
|
2404
|
+
rejectUnauthorized: rejectUnauthorized !== "false"
|
|
2401
2405
|
};
|
|
2402
2406
|
}
|
|
2403
2407
|
return new RedisClient(url, options);
|
|
2404
2408
|
}
|
|
2405
|
-
async function
|
|
2406
|
-
if (!
|
|
2409
|
+
async function createCacheFromEnv() {
|
|
2410
|
+
if (!hasCacheConfig()) {
|
|
2411
|
+
cacheLogger.info("No cache configuration found - running without cache");
|
|
2407
2412
|
return { write: void 0, read: void 0 };
|
|
2408
2413
|
}
|
|
2409
2414
|
try {
|
|
2410
2415
|
const ioredis = await import('ioredis');
|
|
2411
2416
|
const RedisClient = ioredis.default;
|
|
2412
|
-
|
|
2413
|
-
|
|
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(/:[^:@]+@/, ":***@") });
|
|
2414
2427
|
return { write: client, read: client };
|
|
2415
2428
|
}
|
|
2416
|
-
if (
|
|
2417
|
-
const write = createClient(RedisClient,
|
|
2418
|
-
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");
|
|
2419
2433
|
return { write, read };
|
|
2420
2434
|
}
|
|
2421
|
-
if (
|
|
2422
|
-
const sentinels =
|
|
2435
|
+
if (sentinelHosts && masterName) {
|
|
2436
|
+
const sentinels = sentinelHosts.split(",").map((host) => {
|
|
2423
2437
|
const [hostname, port] = host.trim().split(":");
|
|
2424
2438
|
return { host: hostname, port: Number(port) || 26379 };
|
|
2425
2439
|
});
|
|
2426
2440
|
const options = {
|
|
2427
2441
|
sentinels,
|
|
2428
|
-
name:
|
|
2429
|
-
password
|
|
2442
|
+
name: masterName,
|
|
2443
|
+
password
|
|
2430
2444
|
};
|
|
2431
2445
|
const client = new RedisClient(options);
|
|
2446
|
+
cacheLogger.debug("Created sentinel cache instance", { masterName, sentinels: sentinels.length });
|
|
2432
2447
|
return { write: client, read: client };
|
|
2433
2448
|
}
|
|
2434
|
-
if (
|
|
2435
|
-
const nodes =
|
|
2449
|
+
if (clusterNodes) {
|
|
2450
|
+
const nodes = clusterNodes.split(",").map((node) => {
|
|
2436
2451
|
const [host, port] = node.trim().split(":");
|
|
2437
2452
|
return { host, port: Number(port) || 6379 };
|
|
2438
2453
|
});
|
|
2439
2454
|
const clusterOptions = {
|
|
2440
2455
|
redisOptions: {
|
|
2441
|
-
password
|
|
2456
|
+
password
|
|
2442
2457
|
}
|
|
2443
2458
|
};
|
|
2444
2459
|
const cluster = new RedisClient.Cluster(nodes, clusterOptions);
|
|
2460
|
+
cacheLogger.debug("Created cluster cache instance", { nodes: nodes.length });
|
|
2445
2461
|
return { write: cluster, read: cluster };
|
|
2446
2462
|
}
|
|
2447
|
-
if (
|
|
2448
|
-
const client = createClient(RedisClient,
|
|
2463
|
+
if (singleUrl) {
|
|
2464
|
+
const client = createClient(RedisClient, singleUrl);
|
|
2465
|
+
cacheLogger.debug("Created cache instance (fallback)", { url: singleUrl.replace(/:[^:@]+@/, ":***@") });
|
|
2449
2466
|
return { write: client, read: client };
|
|
2450
2467
|
}
|
|
2468
|
+
cacheLogger.info("No valid cache configuration found - running without cache");
|
|
2451
2469
|
return { write: void 0, read: void 0 };
|
|
2452
|
-
} catch (
|
|
2453
|
-
if (
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
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
|
+
}
|
|
2459
2488
|
} else {
|
|
2460
2489
|
cacheLogger.warn(
|
|
2461
|
-
"Failed to create
|
|
2462
|
-
{ error: String(
|
|
2490
|
+
"Failed to create cache client",
|
|
2491
|
+
{ error: String(error2), mode: "disabled" }
|
|
2463
2492
|
);
|
|
2464
2493
|
}
|
|
2465
2494
|
return { write: void 0, read: void 0 };
|
|
2466
2495
|
}
|
|
2467
2496
|
}
|
|
2468
|
-
async function
|
|
2469
|
-
const { write } = await
|
|
2497
|
+
async function createSingleCacheFromEnv() {
|
|
2498
|
+
const { write } = await createCacheFromEnv();
|
|
2470
2499
|
return write;
|
|
2471
2500
|
}
|
|
2472
2501
|
var cacheLogger;
|
|
2473
|
-
var
|
|
2474
|
-
"src/cache/
|
|
2502
|
+
var init_cache_factory = __esm({
|
|
2503
|
+
"src/cache/cache-factory.ts"() {
|
|
2475
2504
|
init_logger2();
|
|
2476
2505
|
cacheLogger = logger.child("cache");
|
|
2477
2506
|
}
|
|
2478
2507
|
});
|
|
2479
2508
|
|
|
2480
|
-
// src/cache/
|
|
2481
|
-
function
|
|
2509
|
+
// src/cache/cache-manager.ts
|
|
2510
|
+
function getCache() {
|
|
2482
2511
|
return writeInstance;
|
|
2483
2512
|
}
|
|
2484
|
-
function
|
|
2513
|
+
function getCacheRead() {
|
|
2485
2514
|
return readInstance ?? writeInstance;
|
|
2486
2515
|
}
|
|
2487
|
-
function
|
|
2516
|
+
function isCacheDisabled() {
|
|
2517
|
+
return isDisabled;
|
|
2518
|
+
}
|
|
2519
|
+
function setCache(write, read) {
|
|
2488
2520
|
writeInstance = write;
|
|
2489
2521
|
readInstance = read ?? write;
|
|
2522
|
+
isDisabled = !write;
|
|
2490
2523
|
}
|
|
2491
|
-
async function
|
|
2524
|
+
async function initCache() {
|
|
2492
2525
|
if (writeInstance) {
|
|
2493
|
-
return { write: writeInstance, read: readInstance };
|
|
2526
|
+
return { write: writeInstance, read: readInstance, disabled: isDisabled };
|
|
2494
2527
|
}
|
|
2495
|
-
const { write, read } = await
|
|
2528
|
+
const { write, read } = await createCacheFromEnv();
|
|
2496
2529
|
if (write) {
|
|
2497
2530
|
try {
|
|
2498
2531
|
await write.ping();
|
|
@@ -2501,14 +2534,18 @@ async function initRedis() {
|
|
|
2501
2534
|
}
|
|
2502
2535
|
writeInstance = write;
|
|
2503
2536
|
readInstance = read;
|
|
2537
|
+
isDisabled = false;
|
|
2504
2538
|
const hasReplica = read && read !== write;
|
|
2505
2539
|
cacheLogger2.info(
|
|
2506
|
-
hasReplica ? "
|
|
2540
|
+
hasReplica ? "Cache connected (Master-Replica)" : "Cache connected",
|
|
2541
|
+
{ mode: "enabled" }
|
|
2507
2542
|
);
|
|
2508
|
-
|
|
2543
|
+
return { write: writeInstance, read: readInstance, disabled: false };
|
|
2544
|
+
} catch (error2) {
|
|
2509
2545
|
cacheLogger2.error(
|
|
2510
|
-
"
|
|
2511
|
-
|
|
2546
|
+
"Cache connection failed - running in disabled mode",
|
|
2547
|
+
error2 instanceof Error ? error2 : new Error(String(error2)),
|
|
2548
|
+
{ mode: "disabled" }
|
|
2512
2549
|
);
|
|
2513
2550
|
try {
|
|
2514
2551
|
await write.quit();
|
|
@@ -2517,64 +2554,91 @@ async function initRedis() {
|
|
|
2517
2554
|
}
|
|
2518
2555
|
} catch {
|
|
2519
2556
|
}
|
|
2520
|
-
|
|
2557
|
+
isDisabled = true;
|
|
2558
|
+
return { write: void 0, read: void 0, disabled: true };
|
|
2521
2559
|
}
|
|
2522
2560
|
}
|
|
2523
|
-
|
|
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 };
|
|
2524
2564
|
}
|
|
2525
|
-
async function
|
|
2565
|
+
async function closeCache() {
|
|
2566
|
+
if (isDisabled) {
|
|
2567
|
+
cacheLogger2.debug("Cache already disabled, nothing to close");
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2526
2570
|
const closePromises = [];
|
|
2527
2571
|
if (writeInstance) {
|
|
2528
2572
|
closePromises.push(
|
|
2529
2573
|
writeInstance.quit().catch((err) => {
|
|
2530
|
-
cacheLogger2.error("Error closing
|
|
2574
|
+
cacheLogger2.error("Error closing cache write instance", err);
|
|
2531
2575
|
})
|
|
2532
2576
|
);
|
|
2533
2577
|
}
|
|
2534
2578
|
if (readInstance && readInstance !== writeInstance) {
|
|
2535
2579
|
closePromises.push(
|
|
2536
2580
|
readInstance.quit().catch((err) => {
|
|
2537
|
-
cacheLogger2.error("Error closing
|
|
2581
|
+
cacheLogger2.error("Error closing cache read instance", err);
|
|
2538
2582
|
})
|
|
2539
2583
|
);
|
|
2540
2584
|
}
|
|
2541
2585
|
await Promise.all(closePromises);
|
|
2542
2586
|
writeInstance = void 0;
|
|
2543
2587
|
readInstance = void 0;
|
|
2544
|
-
|
|
2588
|
+
isDisabled = true;
|
|
2589
|
+
cacheLogger2.info("Cache connections closed", { mode: "disabled" });
|
|
2545
2590
|
}
|
|
2546
|
-
function
|
|
2591
|
+
function getCacheInfo() {
|
|
2547
2592
|
return {
|
|
2548
2593
|
hasWrite: !!writeInstance,
|
|
2549
2594
|
hasRead: !!readInstance,
|
|
2550
|
-
isReplica: !!(readInstance && readInstance !== writeInstance)
|
|
2595
|
+
isReplica: !!(readInstance && readInstance !== writeInstance),
|
|
2596
|
+
disabled: isDisabled
|
|
2551
2597
|
};
|
|
2552
2598
|
}
|
|
2553
|
-
var cacheLogger2, writeInstance, readInstance;
|
|
2554
|
-
var
|
|
2555
|
-
"src/cache/
|
|
2556
|
-
|
|
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();
|
|
2557
2603
|
init_logger2();
|
|
2558
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;
|
|
2559
2612
|
}
|
|
2560
2613
|
});
|
|
2561
2614
|
|
|
2562
2615
|
// src/cache/index.ts
|
|
2563
2616
|
var cache_exports = {};
|
|
2564
2617
|
__export(cache_exports, {
|
|
2618
|
+
closeCache: () => closeCache,
|
|
2565
2619
|
closeRedis: () => closeRedis,
|
|
2566
|
-
|
|
2567
|
-
|
|
2620
|
+
createCacheFromEnv: () => createCacheFromEnv,
|
|
2621
|
+
createRedisFromEnv: () => createCacheFromEnv,
|
|
2622
|
+
createSingleCacheFromEnv: () => createSingleCacheFromEnv,
|
|
2623
|
+
createSingleRedisFromEnv: () => createSingleCacheFromEnv,
|
|
2624
|
+
getCache: () => getCache,
|
|
2625
|
+
getCacheInfo: () => getCacheInfo,
|
|
2626
|
+
getCacheRead: () => getCacheRead,
|
|
2568
2627
|
getRedis: () => getRedis,
|
|
2569
2628
|
getRedisInfo: () => getRedisInfo,
|
|
2570
2629
|
getRedisRead: () => getRedisRead,
|
|
2630
|
+
initCache: () => initCache,
|
|
2571
2631
|
initRedis: () => initRedis,
|
|
2632
|
+
isCacheDisabled: () => isCacheDisabled,
|
|
2633
|
+
setCache: () => setCache,
|
|
2572
2634
|
setRedis: () => setRedis
|
|
2573
2635
|
});
|
|
2574
2636
|
var init_cache = __esm({
|
|
2575
2637
|
"src/cache/index.ts"() {
|
|
2576
|
-
|
|
2577
|
-
|
|
2638
|
+
init_cache_factory();
|
|
2639
|
+
init_cache_manager();
|
|
2640
|
+
init_cache_manager();
|
|
2641
|
+
init_cache_factory();
|
|
2578
2642
|
}
|
|
2579
2643
|
});
|
|
2580
2644
|
|
|
@@ -2599,8 +2663,8 @@ var AutoRouteLoader = class {
|
|
|
2599
2663
|
}
|
|
2600
2664
|
let failureCount = 0;
|
|
2601
2665
|
for (const file of files) {
|
|
2602
|
-
const
|
|
2603
|
-
if (
|
|
2666
|
+
const success2 = await this.loadRoute(app, file);
|
|
2667
|
+
if (success2) ; else {
|
|
2604
2668
|
failureCount++;
|
|
2605
2669
|
}
|
|
2606
2670
|
}
|
|
@@ -2616,14 +2680,15 @@ var AutoRouteLoader = class {
|
|
|
2616
2680
|
}
|
|
2617
2681
|
/**
|
|
2618
2682
|
* Load routes from an external directory (e.g., from SPFN function packages)
|
|
2619
|
-
*
|
|
2683
|
+
* Reads package.json spfn.prefix and mounts routes under that prefix
|
|
2620
2684
|
*
|
|
2621
2685
|
* @param app - Hono app instance
|
|
2622
2686
|
* @param routesDir - Directory containing route handlers
|
|
2623
2687
|
* @param packageName - Name of the package (for logging)
|
|
2688
|
+
* @param prefix - Optional prefix to mount routes under (from package.json spfn.prefix)
|
|
2624
2689
|
* @returns Route statistics
|
|
2625
2690
|
*/
|
|
2626
|
-
async loadExternalRoutes(app, routesDir, packageName) {
|
|
2691
|
+
async loadExternalRoutes(app, routesDir, packageName, prefix) {
|
|
2627
2692
|
const startTime = Date.now();
|
|
2628
2693
|
const tempRoutesDir = this.routesDir;
|
|
2629
2694
|
this.routesDir = routesDir;
|
|
@@ -2636,8 +2701,8 @@ var AutoRouteLoader = class {
|
|
|
2636
2701
|
let successCount = 0;
|
|
2637
2702
|
let failureCount = 0;
|
|
2638
2703
|
for (const file of files) {
|
|
2639
|
-
const
|
|
2640
|
-
if (
|
|
2704
|
+
const success2 = await this.loadRoute(app, file, prefix);
|
|
2705
|
+
if (success2) {
|
|
2641
2706
|
successCount++;
|
|
2642
2707
|
} else {
|
|
2643
2708
|
failureCount++;
|
|
@@ -2647,6 +2712,7 @@ var AutoRouteLoader = class {
|
|
|
2647
2712
|
if (this.debug) {
|
|
2648
2713
|
routeLogger2.info("External routes loaded", {
|
|
2649
2714
|
package: packageName,
|
|
2715
|
+
prefix: prefix || "/",
|
|
2650
2716
|
total: successCount,
|
|
2651
2717
|
failed: failureCount,
|
|
2652
2718
|
elapsed: `${elapsed}ms`
|
|
@@ -2690,7 +2756,7 @@ var AutoRouteLoader = class {
|
|
|
2690
2756
|
isValidRouteFile(fileName) {
|
|
2691
2757
|
return fileName === "index.ts" || fileName === "index.js" || fileName === "index.mjs";
|
|
2692
2758
|
}
|
|
2693
|
-
async loadRoute(app, absolutePath) {
|
|
2759
|
+
async loadRoute(app, absolutePath, prefix) {
|
|
2694
2760
|
const relativePath = relative(this.routesDir, absolutePath);
|
|
2695
2761
|
try {
|
|
2696
2762
|
const module = await import(absolutePath);
|
|
@@ -2706,11 +2772,24 @@ var AutoRouteLoader = class {
|
|
|
2706
2772
|
return false;
|
|
2707
2773
|
}
|
|
2708
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
|
+
}
|
|
2709
2787
|
this.registerContractBasedMiddlewares(app, contractPaths, module);
|
|
2710
2788
|
app.route("/", module.default);
|
|
2711
2789
|
contractPaths.forEach((path) => {
|
|
2712
2790
|
this.routes.push({
|
|
2713
2791
|
path,
|
|
2792
|
+
// Use contract path as-is (already includes prefix)
|
|
2714
2793
|
file: relativePath,
|
|
2715
2794
|
meta: module.meta,
|
|
2716
2795
|
priority: this.calculateContractPriority(path)
|
|
@@ -2721,8 +2800,8 @@ var AutoRouteLoader = class {
|
|
|
2721
2800
|
}
|
|
2722
2801
|
});
|
|
2723
2802
|
return true;
|
|
2724
|
-
} catch (
|
|
2725
|
-
this.categorizeAndLogError(
|
|
2803
|
+
} catch (error2) {
|
|
2804
|
+
this.categorizeAndLogError(error2, relativePath);
|
|
2726
2805
|
return false;
|
|
2727
2806
|
}
|
|
2728
2807
|
}
|
|
@@ -2778,9 +2857,9 @@ var AutoRouteLoader = class {
|
|
|
2778
2857
|
}
|
|
2779
2858
|
}
|
|
2780
2859
|
}
|
|
2781
|
-
categorizeAndLogError(
|
|
2782
|
-
const message =
|
|
2783
|
-
const stack =
|
|
2860
|
+
categorizeAndLogError(error2, relativePath) {
|
|
2861
|
+
const message = error2.message;
|
|
2862
|
+
const stack = error2.stack;
|
|
2784
2863
|
if (message.includes("Cannot find module") || message.includes("MODULE_NOT_FOUND")) {
|
|
2785
2864
|
routeLogger2.error("Missing dependency", {
|
|
2786
2865
|
file: relativePath,
|
|
@@ -2837,15 +2916,16 @@ async function loadRoutes(app, options) {
|
|
|
2837
2916
|
routeLogger2.info("Loading function routes", { count: functionRoutes.length });
|
|
2838
2917
|
for (const func of functionRoutes) {
|
|
2839
2918
|
try {
|
|
2840
|
-
await loader.loadExternalRoutes(app, func.routesDir, func.packageName);
|
|
2919
|
+
await loader.loadExternalRoutes(app, func.routesDir, func.packageName, func.prefix);
|
|
2841
2920
|
routeLogger2.info("Function routes loaded", {
|
|
2842
2921
|
package: func.packageName,
|
|
2843
|
-
routesDir: func.routesDir
|
|
2922
|
+
routesDir: func.routesDir,
|
|
2923
|
+
prefix: func.prefix || "/"
|
|
2844
2924
|
});
|
|
2845
|
-
} catch (
|
|
2925
|
+
} catch (error2) {
|
|
2846
2926
|
routeLogger2.error("Failed to load function routes", {
|
|
2847
2927
|
package: func.packageName,
|
|
2848
|
-
error:
|
|
2928
|
+
error: error2 instanceof Error ? error2.message : "Unknown error"
|
|
2849
2929
|
});
|
|
2850
2930
|
}
|
|
2851
2931
|
}
|
|
@@ -2856,87 +2936,6 @@ async function loadRoutes(app, options) {
|
|
|
2856
2936
|
|
|
2857
2937
|
// src/route/bind.ts
|
|
2858
2938
|
init_errors();
|
|
2859
|
-
function bind(contract, handler) {
|
|
2860
|
-
return async (rawContext) => {
|
|
2861
|
-
let params = rawContext.req.param();
|
|
2862
|
-
if (contract.params) {
|
|
2863
|
-
params = Value.Convert(contract.params, params);
|
|
2864
|
-
const errors = [...Value.Errors(contract.params, params)];
|
|
2865
|
-
if (errors.length > 0) {
|
|
2866
|
-
throw new ValidationError(
|
|
2867
|
-
"Invalid path parameters",
|
|
2868
|
-
{
|
|
2869
|
-
fields: errors.map((e) => ({
|
|
2870
|
-
path: e.path,
|
|
2871
|
-
message: e.message,
|
|
2872
|
-
value: e.value
|
|
2873
|
-
}))
|
|
2874
|
-
}
|
|
2875
|
-
);
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
const url = new URL(rawContext.req.url);
|
|
2879
|
-
let query = {};
|
|
2880
|
-
url.searchParams.forEach((v, k) => {
|
|
2881
|
-
const existing = query[k];
|
|
2882
|
-
if (existing) {
|
|
2883
|
-
query[k] = Array.isArray(existing) ? [...existing, v] : [existing, v];
|
|
2884
|
-
} else {
|
|
2885
|
-
query[k] = v;
|
|
2886
|
-
}
|
|
2887
|
-
});
|
|
2888
|
-
if (contract.query) {
|
|
2889
|
-
query = Value.Convert(contract.query, query);
|
|
2890
|
-
const errors = [...Value.Errors(contract.query, query)];
|
|
2891
|
-
if (errors.length > 0) {
|
|
2892
|
-
throw new ValidationError(
|
|
2893
|
-
"Invalid query parameters",
|
|
2894
|
-
{
|
|
2895
|
-
fields: errors.map((e) => ({
|
|
2896
|
-
path: e.path,
|
|
2897
|
-
message: e.message,
|
|
2898
|
-
value: e.value
|
|
2899
|
-
}))
|
|
2900
|
-
}
|
|
2901
|
-
);
|
|
2902
|
-
}
|
|
2903
|
-
}
|
|
2904
|
-
const routeContext = {
|
|
2905
|
-
params,
|
|
2906
|
-
query,
|
|
2907
|
-
data: async () => {
|
|
2908
|
-
let body = await rawContext.req.json();
|
|
2909
|
-
if (contract.body) {
|
|
2910
|
-
body = Value.Convert(contract.body, body);
|
|
2911
|
-
const errors = [...Value.Errors(contract.body, body)];
|
|
2912
|
-
if (errors.length > 0) {
|
|
2913
|
-
throw new ValidationError(
|
|
2914
|
-
"Invalid request body",
|
|
2915
|
-
{
|
|
2916
|
-
fields: errors.map((e) => ({
|
|
2917
|
-
path: e.path,
|
|
2918
|
-
message: e.message,
|
|
2919
|
-
value: e.value
|
|
2920
|
-
}))
|
|
2921
|
-
}
|
|
2922
|
-
);
|
|
2923
|
-
}
|
|
2924
|
-
}
|
|
2925
|
-
return body;
|
|
2926
|
-
},
|
|
2927
|
-
json: (data, status, headers) => {
|
|
2928
|
-
return rawContext.json(data, status, headers);
|
|
2929
|
-
},
|
|
2930
|
-
raw: rawContext
|
|
2931
|
-
};
|
|
2932
|
-
return handler(routeContext);
|
|
2933
|
-
};
|
|
2934
|
-
}
|
|
2935
|
-
|
|
2936
|
-
// src/route/types.ts
|
|
2937
|
-
function isHttpMethod(value) {
|
|
2938
|
-
return typeof value === "string" && ["GET", "POST", "PUT", "PATCH", "DELETE"].includes(value);
|
|
2939
|
-
}
|
|
2940
2939
|
|
|
2941
2940
|
// src/middleware/error-handler.ts
|
|
2942
2941
|
init_logger2();
|
|
@@ -2961,6 +2960,7 @@ function ErrorHandler(options = {}) {
|
|
|
2961
2960
|
});
|
|
2962
2961
|
}
|
|
2963
2962
|
const response = {
|
|
2963
|
+
success: false,
|
|
2964
2964
|
error: {
|
|
2965
2965
|
message: err.message || "Internal Server Error",
|
|
2966
2966
|
type: errorType,
|
|
@@ -2989,22 +2989,6 @@ function generateRequestId() {
|
|
|
2989
2989
|
const randomPart = randomBytes(6).toString("hex");
|
|
2990
2990
|
return `req_${timestamp2}_${randomPart}`;
|
|
2991
2991
|
}
|
|
2992
|
-
function maskSensitiveData2(obj, sensitiveFields, seen = /* @__PURE__ */ new WeakSet()) {
|
|
2993
|
-
if (!obj || typeof obj !== "object") return obj;
|
|
2994
|
-
if (seen.has(obj)) return "[Circular]";
|
|
2995
|
-
seen.add(obj);
|
|
2996
|
-
const lowerFields = sensitiveFields.map((f) => f.toLowerCase());
|
|
2997
|
-
const masked = Array.isArray(obj) ? [...obj] : { ...obj };
|
|
2998
|
-
for (const key in masked) {
|
|
2999
|
-
const lowerKey = key.toLowerCase();
|
|
3000
|
-
if (lowerFields.some((field) => lowerKey.includes(field))) {
|
|
3001
|
-
masked[key] = "***MASKED***";
|
|
3002
|
-
} else if (typeof masked[key] === "object" && masked[key] !== null) {
|
|
3003
|
-
masked[key] = maskSensitiveData2(masked[key], sensitiveFields, seen);
|
|
3004
|
-
}
|
|
3005
|
-
}
|
|
3006
|
-
return masked;
|
|
3007
|
-
}
|
|
3008
2992
|
function RequestLogger(config) {
|
|
3009
2993
|
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
3010
2994
|
const apiLogger = logger.child("api");
|
|
@@ -3043,19 +3027,24 @@ function RequestLogger(config) {
|
|
|
3043
3027
|
logData.slow = true;
|
|
3044
3028
|
}
|
|
3045
3029
|
apiLogger[logLevel]("Request completed", logData);
|
|
3046
|
-
} catch (
|
|
3030
|
+
} catch (error2) {
|
|
3047
3031
|
const duration = Date.now() - startTime;
|
|
3048
|
-
apiLogger.error("Request failed",
|
|
3032
|
+
apiLogger.error("Request failed", error2, {
|
|
3049
3033
|
requestId,
|
|
3050
3034
|
method,
|
|
3051
3035
|
path,
|
|
3052
3036
|
duration
|
|
3053
3037
|
});
|
|
3054
|
-
throw
|
|
3038
|
+
throw error2;
|
|
3055
3039
|
}
|
|
3056
3040
|
};
|
|
3057
3041
|
}
|
|
3058
3042
|
|
|
3043
|
+
// src/route/types.ts
|
|
3044
|
+
function isHttpMethod(value) {
|
|
3045
|
+
return typeof value === "string" && ["GET", "POST", "PUT", "PATCH", "DELETE"].includes(value);
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3059
3048
|
// src/server/create-server.ts
|
|
3060
3049
|
init_logger2();
|
|
3061
3050
|
|
|
@@ -3076,9 +3065,9 @@ function createHealthCheckHandler(detailed) {
|
|
|
3076
3065
|
try {
|
|
3077
3066
|
await db.execute("SELECT 1");
|
|
3078
3067
|
dbStatus = "connected";
|
|
3079
|
-
} catch (
|
|
3068
|
+
} catch (error2) {
|
|
3080
3069
|
dbStatus = "error";
|
|
3081
|
-
dbError =
|
|
3070
|
+
dbError = error2 instanceof Error ? error2.message : String(error2);
|
|
3082
3071
|
}
|
|
3083
3072
|
}
|
|
3084
3073
|
const redis = getRedis2();
|
|
@@ -3088,9 +3077,9 @@ function createHealthCheckHandler(detailed) {
|
|
|
3088
3077
|
try {
|
|
3089
3078
|
await redis.ping();
|
|
3090
3079
|
redisStatus = "connected";
|
|
3091
|
-
} catch (
|
|
3080
|
+
} catch (error2) {
|
|
3092
3081
|
redisStatus = "error";
|
|
3093
|
-
redisError =
|
|
3082
|
+
redisError = error2 instanceof Error ? error2.message : String(error2);
|
|
3094
3083
|
}
|
|
3095
3084
|
}
|
|
3096
3085
|
response.services = {
|
|
@@ -3238,8 +3227,8 @@ async function executeBeforeRoutesHook(app, config) {
|
|
|
3238
3227
|
}
|
|
3239
3228
|
try {
|
|
3240
3229
|
await config.beforeRoutes(app);
|
|
3241
|
-
} catch (
|
|
3242
|
-
serverLogger.error("beforeRoutes hook failed",
|
|
3230
|
+
} catch (error2) {
|
|
3231
|
+
serverLogger.error("beforeRoutes hook failed", error2);
|
|
3243
3232
|
throw new Error("Server initialization failed in beforeRoutes hook");
|
|
3244
3233
|
}
|
|
3245
3234
|
}
|
|
@@ -3257,8 +3246,8 @@ async function executeAfterRoutesHook(app, config) {
|
|
|
3257
3246
|
}
|
|
3258
3247
|
try {
|
|
3259
3248
|
await config.afterRoutes(app);
|
|
3260
|
-
} catch (
|
|
3261
|
-
serverLogger.error("afterRoutes hook failed",
|
|
3249
|
+
} catch (error2) {
|
|
3250
|
+
serverLogger.error("afterRoutes hook failed", error2);
|
|
3262
3251
|
throw new Error("Server initialization failed in afterRoutes hook");
|
|
3263
3252
|
}
|
|
3264
3253
|
}
|
|
@@ -3378,11 +3367,11 @@ async function startServer(config) {
|
|
|
3378
3367
|
await shutdownServer();
|
|
3379
3368
|
}
|
|
3380
3369
|
};
|
|
3381
|
-
} catch (
|
|
3382
|
-
const err =
|
|
3370
|
+
} catch (error2) {
|
|
3371
|
+
const err = error2;
|
|
3383
3372
|
serverLogger2.error("Server initialization failed", err);
|
|
3384
3373
|
await cleanupOnFailure();
|
|
3385
|
-
throw
|
|
3374
|
+
throw error2;
|
|
3386
3375
|
}
|
|
3387
3376
|
}
|
|
3388
3377
|
async function loadAndMergeConfig(config) {
|
|
@@ -3480,8 +3469,8 @@ function createGracefulShutdown(shutdownServer, config) {
|
|
|
3480
3469
|
]);
|
|
3481
3470
|
serverLogger2.info("Graceful shutdown completed successfully");
|
|
3482
3471
|
process.exit(0);
|
|
3483
|
-
} catch (
|
|
3484
|
-
const err =
|
|
3472
|
+
} catch (error2) {
|
|
3473
|
+
const err = error2;
|
|
3485
3474
|
if (err.message && err.message.includes("timeout")) {
|
|
3486
3475
|
serverLogger2.error("Graceful shutdown timeout, forcing exit", err);
|
|
3487
3476
|
} else {
|
|
@@ -3494,8 +3483,8 @@ function createGracefulShutdown(shutdownServer, config) {
|
|
|
3494
3483
|
function registerShutdownHandlers(shutdown) {
|
|
3495
3484
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
3496
3485
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
3497
|
-
process.on("uncaughtException", (
|
|
3498
|
-
serverLogger2.error("Uncaught exception",
|
|
3486
|
+
process.on("uncaughtException", (error2) => {
|
|
3487
|
+
serverLogger2.error("Uncaught exception", error2);
|
|
3499
3488
|
shutdown("UNCAUGHT_EXCEPTION");
|
|
3500
3489
|
});
|
|
3501
3490
|
process.on("unhandledRejection", (reason, promise) => {
|
|
@@ -3517,13 +3506,6 @@ async function cleanupOnFailure() {
|
|
|
3517
3506
|
}
|
|
3518
3507
|
}
|
|
3519
3508
|
|
|
3520
|
-
|
|
3521
|
-
init_db();
|
|
3522
|
-
init_cache();
|
|
3523
|
-
init_transaction();
|
|
3524
|
-
init_logger2();
|
|
3525
|
-
init_errors();
|
|
3526
|
-
|
|
3527
|
-
export { AutoRouteLoader, ConnectionError, DatabaseError, DeadlockError, DuplicateEntryError, ErrorHandler, NotFoundError, QueryError, RequestLogger, TransactionError, Transactional, ValidationError, bind, closeRedis, createRedisFromEnv, createServer, createSingleRedisFromEnv, detectDialect, foreignKey, fromPostgresError, generateDrizzleConfigFile, getDrizzleConfig, getRedis, getRedisInfo, getRedisRead, getTransaction, id, initRedis, isDatabaseError, isHttpMethod, loadRoutes, logger, maskSensitiveData2 as maskSensitiveData, optionalForeignKey, runWithTransaction, setRedis, startServer, timestamps };
|
|
3509
|
+
export { createServer, isHttpMethod, startServer };
|
|
3528
3510
|
//# sourceMappingURL=index.js.map
|
|
3529
3511
|
//# sourceMappingURL=index.js.map
|