ugly-app 0.1.497 → 0.1.498
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/.pgdata/base/16384/1247 +0 -0
- package/.pgdata/base/16384/1249 +0 -0
- package/.pgdata/base/16384/1259 +0 -0
- package/.pgdata/base/16384/1259_fsm +0 -0
- package/.pgdata/base/16384/1259_vm +0 -0
- package/.pgdata/base/16384/2579 +0 -0
- package/.pgdata/base/16384/2604 +0 -0
- package/.pgdata/base/16384/2606 +0 -0
- package/.pgdata/base/16384/2608 +0 -0
- package/.pgdata/base/16384/2608_fsm +0 -0
- package/.pgdata/base/16384/2610 +0 -0
- package/.pgdata/base/16384/2619 +0 -0
- package/.pgdata/base/16384/2656 +0 -0
- package/.pgdata/base/16384/2657 +0 -0
- package/.pgdata/base/16384/2658 +0 -0
- package/.pgdata/base/16384/2659 +0 -0
- package/.pgdata/base/16384/2662 +0 -0
- package/.pgdata/base/16384/2663 +0 -0
- package/.pgdata/base/16384/2664 +0 -0
- package/.pgdata/base/16384/2665 +0 -0
- package/.pgdata/base/16384/2666 +0 -0
- package/.pgdata/base/16384/2667 +0 -0
- package/.pgdata/base/16384/2673 +0 -0
- package/.pgdata/base/16384/2674 +0 -0
- package/.pgdata/base/16384/2678 +0 -0
- package/.pgdata/base/16384/2679 +0 -0
- package/.pgdata/base/16384/2703 +0 -0
- package/.pgdata/base/16384/2704 +0 -0
- package/.pgdata/base/16384/3455 +0 -0
- package/.pgdata/global/pg_control +0 -0
- package/.pgdata/pg_wal/000000010000000000000004 +0 -0
- package/.pgdata/pg_xact/0000 +0 -0
- package/dist/cli/version.d.ts +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/server/App.d.ts.map +1 -1
- package/dist/server/App.js +147 -74
- package/dist/server/App.js.map +1 -1
- package/dist/server/Cache.d.ts.map +1 -1
- package/dist/server/Cache.js +30 -18
- package/dist/server/Cache.js.map +1 -1
- package/dist/server/EventLogAdmin.d.ts.map +1 -1
- package/dist/server/EventLogAdmin.js +7 -1
- package/dist/server/EventLogAdmin.js.map +1 -1
- package/dist/server/Logging.d.ts.map +1 -1
- package/dist/server/Logging.js +17 -3
- package/dist/server/Logging.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/version.ts +1 -1
- package/src/server/App.ts +169 -84
- package/src/server/Cache.ts +34 -22
- package/src/server/EventLogAdmin.ts +10 -1
- package/src/server/Logging.ts +20 -3
- package/.pgdata/base/16384/20519 +0 -0
- package/.pgdata/base/16384/20522 +0 -0
- package/.pgdata/base/16384/20523 +0 -0
- package/.pgdata/base/16384/20524 +0 -0
- package/.pgdata/base/16384/20526 +0 -0
- package/.pgdata/base/16384/20529 +0 -0
- package/.pgdata/base/16384/20530 +0 -0
- package/.pgdata/base/16384/20531 +0 -0
- package/.pgdata/base/16384/20533 +0 -0
- package/.pgdata/base/16384/20539 +0 -0
- package/.pgdata/base/16384/20540 +0 -0
- package/.pgdata/base/16384/20541 +0 -0
- package/.pgdata/base/16384/20543 +0 -0
package/.pgdata/base/16384/1247
CHANGED
|
Binary file
|
package/.pgdata/base/16384/1249
CHANGED
|
Binary file
|
package/.pgdata/base/16384/1259
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/.pgdata/base/16384/2579
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2604
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2606
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2608
CHANGED
|
Binary file
|
|
Binary file
|
package/.pgdata/base/16384/2610
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2619
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2656
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2657
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2658
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2659
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2662
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2663
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2664
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2665
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2666
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2667
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2673
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2674
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2678
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2679
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2703
CHANGED
|
Binary file
|
package/.pgdata/base/16384/2704
CHANGED
|
Binary file
|
package/.pgdata/base/16384/3455
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/.pgdata/pg_xact/0000
CHANGED
|
Binary file
|
package/dist/cli/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.498";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cli/version.js
CHANGED
package/dist/server/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/server/App.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AAK5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAErC,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,cAAc,EACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EACV,qBAAqB,EAErB,cAAc,EACd,OAAO,EACP,UAAU,EACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAY,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/server/App.ts"],"names":[],"mappings":"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"}
|
package/dist/server/App.js
CHANGED
|
@@ -11,24 +11,34 @@ import { parseUrl } from "../shared/Router.js";
|
|
|
11
11
|
import { getUglyBotUrl } from "../shared/uglyBotUrl.js";
|
|
12
12
|
import { oneHour } from "../shared/index.js";
|
|
13
13
|
// AI providers are now always routed through ugly.bot (proxy-only).
|
|
14
|
-
|
|
14
|
+
//
|
|
15
|
+
// Heavy server modules below are loaded LAZILY (via dynamic `import()`
|
|
16
|
+
// at call sites) and gated on env vars so a host without DATABASE_URL /
|
|
17
|
+
// NATS_URL / R2_BUCKET / any AI provider key doesn't pay the load cost.
|
|
18
|
+
// Pre-2026-06 the eager top-level imports here meant any importer of
|
|
19
|
+
// `ugly-app` paid ~600ms of cumulative module load (pg, nats.js,
|
|
20
|
+
// @aws-sdk/client-s3, @anthropic-ai/sdk, openai, …) even when no DB
|
|
21
|
+
// or AI provider was configured — that's the cost Ugly Studio's sidecar
|
|
22
|
+
// boot was eating. Lazy + env-gate cuts that to near-zero for hosts
|
|
23
|
+
// that don't use the relevant subsystem.
|
|
15
24
|
import { initEventCounter, initEventCounterApi, startEventCounterFlush, } from "./EventCounter.js";
|
|
16
25
|
import { createAuthRoutes, getRequestUser, uglyBotAuthProvider, verifyToken, } from "./Auth.js";
|
|
17
26
|
import { createTypedDB } from "./DB.js";
|
|
18
|
-
|
|
27
|
+
// ./Pg.js loaded lazily inside start() — see below.
|
|
28
|
+
// Logging.ts itself is loaded eagerly (captureServerError + init*** are
|
|
29
|
+
// always-on), but as of 2026-06 it lazy-loads Pg.js internally so this
|
|
30
|
+
// import no longer drags in the pg driver.
|
|
19
31
|
import { initLoggingApi, initServerConsoleCapture, initServerErrorCapture, recordFeedback, } from "./Logging.js";
|
|
20
|
-
|
|
32
|
+
// ./Nats.js loaded lazily inside start() — see below.
|
|
21
33
|
import { getDevNamespace, namespaceBucketName, namespaceDbUrl, namespaceNatsPrefix, } from "./DevNamespace.js";
|
|
22
34
|
import { RateLimitError } from "./RateLimit.js";
|
|
23
35
|
import { createRouter, RouterAuthError, RouterNotFoundError, } from "./Router.js";
|
|
24
36
|
import { createStoreHandlers } from "./StoreHandlers.js";
|
|
25
37
|
import { getCriticalStrings, resolveLanguage, stringsVersion, } from "./Strings.js";
|
|
26
38
|
import { initWebSocketServer } from "./Socket.js";
|
|
27
|
-
import { createStorageClient, setStoragePrefix } from "./Storage.js";
|
|
28
39
|
import { frameworkRequests } from "../shared/FrameworkRequests.js";
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
import { createWebSearchClient } from "./ai/WebSearchClient.js";
|
|
40
|
+
// AI clients (./AiText.js, ./AiImage.js, ./ai/WebSearchClient.js,
|
|
41
|
+
// ./ai/ProviderBalance.js) loaded lazily at their call sites.
|
|
32
42
|
import { eventLogCapture, eventLogServerCapture, initEventLog, initEventLogApi, } from "./EventLogAdmin.js";
|
|
33
43
|
import { getExperimentAssignments, } from "../shared/Experiment.js";
|
|
34
44
|
export { getRequestUser, verifyToken };
|
|
@@ -57,10 +67,22 @@ export function createApp(registry, requests, appDefs, configure, deleteHandlers
|
|
|
57
67
|
// Create the typed DB client merging builtins + app collections
|
|
58
68
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
69
|
const typedDb = createTypedDB(allDefs, deleteHandlers);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
// Storage (R2 / S3) is loaded LAZILY. Hosts without an R2 / S3 bucket
|
|
71
|
+
// (e.g. Ugly Studio's sidecar, which talks to ugly.bot's storage via
|
|
72
|
+
// HTTP) skip ~150ms of `@aws-sdk/client-s3` module loading. The lazy
|
|
73
|
+
// accessor below is memoized — the actual client is created on first
|
|
74
|
+
// use, and STORAGE_KEY_PREFIX is applied at that point.
|
|
75
|
+
let _lazyStorage = null;
|
|
76
|
+
const getStorage = async () => {
|
|
77
|
+
if (_lazyStorage)
|
|
78
|
+
return _lazyStorage;
|
|
79
|
+
const mod = await import("./Storage.js");
|
|
80
|
+
if (process.env["STORAGE_KEY_PREFIX"]) {
|
|
81
|
+
mod.setStoragePrefix(process.env["STORAGE_KEY_PREFIX"]);
|
|
82
|
+
}
|
|
83
|
+
_lazyStorage = mod.createStorageClient();
|
|
84
|
+
return _lazyStorage;
|
|
85
|
+
};
|
|
64
86
|
const expressApp = express();
|
|
65
87
|
// Skip JSON body parsing for S3 upload proxy routes (they use express.raw() inline)
|
|
66
88
|
expressApp.use((req, res, next) => {
|
|
@@ -291,22 +313,26 @@ export function createApp(registry, requests, appDefs, configure, deleteHandlers
|
|
|
291
313
|
return { eventId };
|
|
292
314
|
},
|
|
293
315
|
textGen: async (userId, { model, messages }) => {
|
|
316
|
+
const { createTextGenClient } = await import("./AiText.js");
|
|
294
317
|
const text = await createTextGenClient(userId).generate(messages, { model: model });
|
|
295
318
|
return { text };
|
|
296
319
|
},
|
|
297
320
|
imageGen: async (userId, { model, prompt }) => {
|
|
321
|
+
const { createImageGenClient } = await import("./AiImage.js");
|
|
298
322
|
const url = await createImageGenClient(userId).generate(prompt, {
|
|
299
323
|
model: model,
|
|
300
324
|
});
|
|
301
325
|
return { url };
|
|
302
326
|
},
|
|
303
327
|
kagiSearch: async (userId, { query, limit }) => {
|
|
328
|
+
const { createWebSearchClient } = await import("./ai/WebSearchClient.js");
|
|
304
329
|
return createWebSearchClient(userId).search({
|
|
305
330
|
query,
|
|
306
331
|
...(limit !== undefined && { limit }),
|
|
307
332
|
});
|
|
308
333
|
},
|
|
309
334
|
kagiSummarize: async (userId, { url, text }) => {
|
|
335
|
+
const { createWebSearchClient } = await import("./ai/WebSearchClient.js");
|
|
310
336
|
const summary = await createWebSearchClient(userId).summarize({
|
|
311
337
|
...(url !== undefined && { url }),
|
|
312
338
|
...(text !== undefined && { text }),
|
|
@@ -314,12 +340,15 @@ export function createApp(registry, requests, appDefs, configure, deleteHandlers
|
|
|
314
340
|
return { summary };
|
|
315
341
|
},
|
|
316
342
|
kagiEnrichWeb: async (userId, { query }) => {
|
|
343
|
+
const { createWebSearchClient } = await import("./ai/WebSearchClient.js");
|
|
317
344
|
return createWebSearchClient(userId).enrichWeb({ query });
|
|
318
345
|
},
|
|
319
346
|
kagiEnrichNews: async (userId, { query }) => {
|
|
347
|
+
const { createWebSearchClient } = await import("./ai/WebSearchClient.js");
|
|
320
348
|
return createWebSearchClient(userId).enrichNews({ query });
|
|
321
349
|
},
|
|
322
350
|
uploadUrl: async (_userId, { key }) => {
|
|
351
|
+
const storage = await getStorage();
|
|
323
352
|
return storage.presignedPut("temp", key);
|
|
324
353
|
},
|
|
325
354
|
adminGetPerfLogs: (userId, _input) => {
|
|
@@ -677,7 +706,10 @@ export function createApp(registry, requests, appDefs, configure, deleteHandlers
|
|
|
677
706
|
expressApp.use((req, res, next) => {
|
|
678
707
|
createAuthRoutes(typedDb, resolvedUserHelper, resolvedOnUserCreate, authProvider)(req, res, next);
|
|
679
708
|
});
|
|
680
|
-
const wss = initWebSocketServer(httpServer, router, allCollections,
|
|
709
|
+
const wss = initWebSocketServer(httpServer, router, allCollections,
|
|
710
|
+
// Socket.ts ignores this arg (underscore-prefixed `_storage`); pass
|
|
711
|
+
// null so we don't trigger the lazy createStorageClient at boot.
|
|
712
|
+
null, typedDb, resolvedUserHelper, wsPath, onSocketMessageHandlers.length > 0 ? onSocketMessageHandlers : undefined, undefined, onWsAuth ?? undefined);
|
|
681
713
|
function registerRoutes(fn) {
|
|
682
714
|
const customRouter = express.Router();
|
|
683
715
|
fn(customRouter);
|
|
@@ -686,7 +718,26 @@ export function createApp(registry, requests, appDefs, configure, deleteHandlers
|
|
|
686
718
|
// Capture pageOptions in a local const so TypeScript doesn't narrow it to never inside closures
|
|
687
719
|
const resolvedPageOptions = pageOptions;
|
|
688
720
|
async function start(port = 3000) {
|
|
689
|
-
|
|
721
|
+
// ProviderBalance tracks per-provider AI spend. Only meaningful when
|
|
722
|
+
// at least one provider key is configured — hosts that route all AI
|
|
723
|
+
// through ugly.bot (Ugly Studio) skip the load (~20ms + the
|
|
724
|
+
// ProviderBalance module's dep tree).
|
|
725
|
+
const anyAi = process.env["OPENAI_API_KEY"] ||
|
|
726
|
+
process.env["ANTHROPIC_API_KEY"] ||
|
|
727
|
+
process.env["GOOGLE_API_KEY"] ||
|
|
728
|
+
process.env["GROQ_API_KEY"] ||
|
|
729
|
+
process.env["TOGETHER_API_KEY"] ||
|
|
730
|
+
process.env["FIREWORKS_API_KEY"] ||
|
|
731
|
+
process.env["FAL_API_KEY"] ||
|
|
732
|
+
process.env["OPENROUTER_KEY"] ||
|
|
733
|
+
process.env["DEEPINFRA_API_KEY"] ||
|
|
734
|
+
process.env["DEEPSEEK_API_KEY"] ||
|
|
735
|
+
process.env["MINIMAX_TOKEN"] ||
|
|
736
|
+
process.env["KAGI_API_TOKEN"];
|
|
737
|
+
if (anyAi) {
|
|
738
|
+
const { initProviderBalance } = await import("./ai/ProviderBalance.js");
|
|
739
|
+
initProviderBalance(typedDb);
|
|
740
|
+
}
|
|
690
741
|
initServerConsoleCapture(typedDb);
|
|
691
742
|
initEventLog(typedDb);
|
|
692
743
|
// Forward error logs and feedback to ugly.bot API
|
|
@@ -739,6 +790,7 @@ export function createApp(registry, requests, appDefs, configure, deleteHandlers
|
|
|
739
790
|
if (dbUrl) {
|
|
740
791
|
process.env["DATABASE_URL"] = namespaceDbUrl(dbUrl);
|
|
741
792
|
}
|
|
793
|
+
const { setNatsPrefix } = await import("./Nats.js");
|
|
742
794
|
setNatsPrefix(namespaceNatsPrefix());
|
|
743
795
|
const baseBucket = process.env["R2_BUCKET"];
|
|
744
796
|
if (baseBucket && !baseBucket.endsWith(`-${ns}`)) {
|
|
@@ -746,57 +798,67 @@ export function createApp(registry, requests, appDefs, configure, deleteHandlers
|
|
|
746
798
|
}
|
|
747
799
|
console.log(`[app] UGLY_APP_DEV_MODE — namespace="${ns}" db="${process.env["DATABASE_URL"]?.split("/").pop()}" bucket="${process.env["R2_BUCKET"]}"`);
|
|
748
800
|
}
|
|
749
|
-
//
|
|
750
|
-
//
|
|
751
|
-
//
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
801
|
+
// Postgres init + schema check. Skipped entirely when neither
|
|
802
|
+
// DATABASE_URL nor POSTGRES_URL is set — hosts like Ugly Studio's
|
|
803
|
+
// sidecar route persistence through ugly.bot and don't need a local
|
|
804
|
+
// pg pool. Pre-2026-06 this block ran unconditionally and logged a
|
|
805
|
+
// "Schema check failed" warning on every Studio boot.
|
|
806
|
+
if (process.env["DATABASE_URL"] || process.env["POSTGRES_URL"]) {
|
|
807
|
+
const { initPg } = await import("./Pg.js");
|
|
808
|
+
await initPg();
|
|
809
|
+
console.log("[app] Postgres pool ready");
|
|
810
|
+
// Schema drift check + auto-migration for new collections / safe changes
|
|
811
|
+
try {
|
|
812
|
+
const { ensureSchemaSnapshotsTable, checkSchemas, formatSchemaCheckResult, } = await import("./SchemaCheck.js");
|
|
813
|
+
await ensureSchemaSnapshotsTable();
|
|
814
|
+
const schemaResult = await checkSchemas(allDefs);
|
|
815
|
+
if (schemaResult.status === "drift") {
|
|
816
|
+
if (process.env["SCHEMA_CHECK_SKIP"] === "true") {
|
|
817
|
+
console.warn("[app] WARNING: Schema drift detected but SCHEMA_CHECK_SKIP=true — proceeding anyway!");
|
|
818
|
+
console.warn("[app] This is unsafe. Fix the schema drift as soon as possible.");
|
|
819
|
+
console.warn(formatSchemaCheckResult(schemaResult));
|
|
820
|
+
}
|
|
821
|
+
else {
|
|
822
|
+
console.error("[app] Schema drift detected — cannot start.");
|
|
823
|
+
console.error(formatSchemaCheckResult(schemaResult));
|
|
824
|
+
console.error('\nRun "npm run db:schema-gen" to generate migrations, then "npm run db:migrate" to apply them.');
|
|
825
|
+
process.exit(1);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
else if (schemaResult.status === "baseline") {
|
|
829
|
+
// Auto-generate and apply migrations for new collections
|
|
830
|
+
const { autoMigrateNewCollections } = await import("./SchemaCheck.js");
|
|
831
|
+
await autoMigrateNewCollections(schemaResult, allDefs);
|
|
764
832
|
}
|
|
765
833
|
else {
|
|
766
|
-
console.
|
|
767
|
-
console.error(formatSchemaCheckResult(schemaResult));
|
|
768
|
-
console.error('\nRun "npm run db:schema-gen" to generate migrations, then "npm run db:migrate" to apply them.');
|
|
769
|
-
process.exit(1);
|
|
834
|
+
console.log("[app] Schema check passed");
|
|
770
835
|
}
|
|
771
836
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
const { autoMigrateNewCollections } = await import("./SchemaCheck.js");
|
|
775
|
-
await autoMigrateNewCollections(schemaResult, allDefs);
|
|
776
|
-
}
|
|
777
|
-
else {
|
|
778
|
-
console.log("[app] Schema check passed");
|
|
837
|
+
catch (err) {
|
|
838
|
+
console.warn("[app] Schema check failed (continuing):", err.message);
|
|
779
839
|
}
|
|
780
840
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
process.env["
|
|
789
|
-
|
|
841
|
+
// NATS init + KV buckets. Skipped entirely when NATS_URL is unset —
|
|
842
|
+
// same rationale as the Pg block above.
|
|
843
|
+
if (process.env["NATS_URL"]) {
|
|
844
|
+
try {
|
|
845
|
+
const { checkJetStream, connectNats, ensureKvBucket, setNatsPrefix, } = await import("./Nats.js");
|
|
846
|
+
await connectNats();
|
|
847
|
+
if (process.env["NATS_PREFIX"] || process.env["COMPOSE_PROJECT_NAME"]) {
|
|
848
|
+
setNatsPrefix(process.env["NATS_PREFIX"] ??
|
|
849
|
+
process.env["COMPOSE_PROJECT_NAME"] ??
|
|
850
|
+
"");
|
|
851
|
+
}
|
|
852
|
+
// Verify JetStream is healthy before creating KV buckets — a fast
|
|
853
|
+
// probe that surfaces permission/config issues instead of hanging.
|
|
854
|
+
await checkJetStream();
|
|
855
|
+
await ensureKvBucket("TTS", { max_bytes: 256 * 1024 * 1024 });
|
|
856
|
+
await ensureKvBucket("RATELIMIT", {});
|
|
857
|
+
console.log("[app] NATS KV buckets ready");
|
|
858
|
+
}
|
|
859
|
+
catch (err) {
|
|
860
|
+
console.warn(`[app] NATS connection failed (real-time updates, TTS cache, and rate-limiting disabled): ${err.message}`);
|
|
790
861
|
}
|
|
791
|
-
// Verify JetStream is healthy before creating KV buckets — a fast probe
|
|
792
|
-
// that surfaces permission/config issues instead of hanging silently.
|
|
793
|
-
await checkJetStream();
|
|
794
|
-
await ensureKvBucket("TTS", { max_bytes: 256 * 1024 * 1024 });
|
|
795
|
-
await ensureKvBucket("RATELIMIT", {});
|
|
796
|
-
console.log("[app] NATS KV buckets ready");
|
|
797
|
-
}
|
|
798
|
-
catch (err) {
|
|
799
|
-
console.warn(`[app] NATS connection failed (real-time updates, TTS cache, and rate-limiting disabled): ${err.message}`);
|
|
800
862
|
}
|
|
801
863
|
// Set up page serving (must happen before httpServer.listen)
|
|
802
864
|
console.log("[app] Page options:", resolvedPageOptions != null
|
|
@@ -1081,22 +1143,29 @@ export function createApp(registry, requests, appDefs, configure, deleteHandlers
|
|
|
1081
1143
|
// Framework-managed background services
|
|
1082
1144
|
initEventCounter(typedDb);
|
|
1083
1145
|
startEventCounterFlush();
|
|
1084
|
-
// TTL cleanup: delete expired rows from log tables every 15 minutes
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1146
|
+
// TTL cleanup: delete expired rows from log tables every 15 minutes.
|
|
1147
|
+
// Skipped when Pg isn't configured (no DATABASE_URL) — the loop has
|
|
1148
|
+
// nothing to query and the lazy pg import would error every tick.
|
|
1149
|
+
if (process.env["DATABASE_URL"] || process.env["POSTGRES_URL"]) {
|
|
1150
|
+
const ttlCollections = [
|
|
1151
|
+
{ table: "consoleLog", field: "created", seconds: 7 * 86400 },
|
|
1152
|
+
{ table: "perfLog", field: "created", seconds: 7 * 86400 },
|
|
1153
|
+
{ table: "feedbackLog", field: "created", seconds: 7 * 86400 },
|
|
1154
|
+
{ table: "errorLog", field: "created", seconds: 7 * 86400 },
|
|
1155
|
+
{ table: "aiSpend", field: "created", seconds: 2 * 3600 },
|
|
1156
|
+
];
|
|
1157
|
+
setInterval(() => {
|
|
1158
|
+
void (async () => {
|
|
1159
|
+
const { pgQuery } = await import("./Pg.js");
|
|
1160
|
+
for (const { table, field, seconds } of ttlCollections) {
|
|
1161
|
+
const cutoff = new Date(Date.now() - seconds * 1000).toISOString();
|
|
1162
|
+
pgQuery(`DELETE FROM "${table}" WHERE data->>'${field}' < $1`, [
|
|
1163
|
+
cutoff,
|
|
1164
|
+
]).catch(() => { });
|
|
1165
|
+
}
|
|
1166
|
+
})();
|
|
1167
|
+
}, 15 * 60_000);
|
|
1168
|
+
}
|
|
1100
1169
|
const clockEnabled = process.env["CLOCK_ENABLED"] === "true";
|
|
1101
1170
|
if (clockEnabled) {
|
|
1102
1171
|
if (onMinuteTick) {
|
|
@@ -1130,7 +1199,11 @@ export function createApp(registry, requests, appDefs, configure, deleteHandlers
|
|
|
1130
1199
|
await new Promise((resolve) => httpServer.close(() => resolve()));
|
|
1131
1200
|
if (workerQueue)
|
|
1132
1201
|
await workerQueue.stop();
|
|
1133
|
-
|
|
1202
|
+
// Only close pg if we actually opened it (DATABASE_URL was set).
|
|
1203
|
+
if (process.env["DATABASE_URL"] || process.env["POSTGRES_URL"]) {
|
|
1204
|
+
const { closePg } = await import("./Pg.js");
|
|
1205
|
+
closePg();
|
|
1206
|
+
}
|
|
1134
1207
|
console.log("[App] Shutdown complete");
|
|
1135
1208
|
process.exit(0);
|
|
1136
1209
|
};
|