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.
Files changed (65) hide show
  1. package/.pgdata/base/16384/1247 +0 -0
  2. package/.pgdata/base/16384/1249 +0 -0
  3. package/.pgdata/base/16384/1259 +0 -0
  4. package/.pgdata/base/16384/1259_fsm +0 -0
  5. package/.pgdata/base/16384/1259_vm +0 -0
  6. package/.pgdata/base/16384/2579 +0 -0
  7. package/.pgdata/base/16384/2604 +0 -0
  8. package/.pgdata/base/16384/2606 +0 -0
  9. package/.pgdata/base/16384/2608 +0 -0
  10. package/.pgdata/base/16384/2608_fsm +0 -0
  11. package/.pgdata/base/16384/2610 +0 -0
  12. package/.pgdata/base/16384/2619 +0 -0
  13. package/.pgdata/base/16384/2656 +0 -0
  14. package/.pgdata/base/16384/2657 +0 -0
  15. package/.pgdata/base/16384/2658 +0 -0
  16. package/.pgdata/base/16384/2659 +0 -0
  17. package/.pgdata/base/16384/2662 +0 -0
  18. package/.pgdata/base/16384/2663 +0 -0
  19. package/.pgdata/base/16384/2664 +0 -0
  20. package/.pgdata/base/16384/2665 +0 -0
  21. package/.pgdata/base/16384/2666 +0 -0
  22. package/.pgdata/base/16384/2667 +0 -0
  23. package/.pgdata/base/16384/2673 +0 -0
  24. package/.pgdata/base/16384/2674 +0 -0
  25. package/.pgdata/base/16384/2678 +0 -0
  26. package/.pgdata/base/16384/2679 +0 -0
  27. package/.pgdata/base/16384/2703 +0 -0
  28. package/.pgdata/base/16384/2704 +0 -0
  29. package/.pgdata/base/16384/3455 +0 -0
  30. package/.pgdata/global/pg_control +0 -0
  31. package/.pgdata/pg_wal/000000010000000000000004 +0 -0
  32. package/.pgdata/pg_xact/0000 +0 -0
  33. package/dist/cli/version.d.ts +1 -1
  34. package/dist/cli/version.js +1 -1
  35. package/dist/server/App.d.ts.map +1 -1
  36. package/dist/server/App.js +147 -74
  37. package/dist/server/App.js.map +1 -1
  38. package/dist/server/Cache.d.ts.map +1 -1
  39. package/dist/server/Cache.js +30 -18
  40. package/dist/server/Cache.js.map +1 -1
  41. package/dist/server/EventLogAdmin.d.ts.map +1 -1
  42. package/dist/server/EventLogAdmin.js +7 -1
  43. package/dist/server/EventLogAdmin.js.map +1 -1
  44. package/dist/server/Logging.d.ts.map +1 -1
  45. package/dist/server/Logging.js +17 -3
  46. package/dist/server/Logging.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/cli/version.ts +1 -1
  49. package/src/server/App.ts +169 -84
  50. package/src/server/Cache.ts +34 -22
  51. package/src/server/EventLogAdmin.ts +10 -1
  52. package/src/server/Logging.ts +20 -3
  53. package/.pgdata/base/16384/20519 +0 -0
  54. package/.pgdata/base/16384/20522 +0 -0
  55. package/.pgdata/base/16384/20523 +0 -0
  56. package/.pgdata/base/16384/20524 +0 -0
  57. package/.pgdata/base/16384/20526 +0 -0
  58. package/.pgdata/base/16384/20529 +0 -0
  59. package/.pgdata/base/16384/20530 +0 -0
  60. package/.pgdata/base/16384/20531 +0 -0
  61. package/.pgdata/base/16384/20533 +0 -0
  62. package/.pgdata/base/16384/20539 +0 -0
  63. package/.pgdata/base/16384/20540 +0 -0
  64. package/.pgdata/base/16384/20541 +0 -0
  65. package/.pgdata/base/16384/20543 +0 -0
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.497";
1
+ export declare const CLI_VERSION = "0.1.498";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.497";
2
+ export const CLI_VERSION = "0.1.498";
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/server/App.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/server/App.ts"],"names":[],"mappings":"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"}
@@ -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
- import { initProviderBalance } from "./ai/ProviderBalance.js";
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
- import { initPg, closePg, pgQuery } from "./Pg.js";
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
- import { checkJetStream, connectNats, ensureKvBucket, setNatsPrefix } from "./Nats.js";
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
- import { createTextGenClient } from "./AiText.js";
30
- import { createImageGenClient } from "./AiImage.js";
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
- if (process.env["STORAGE_KEY_PREFIX"]) {
61
- setStoragePrefix(process.env["STORAGE_KEY_PREFIX"]);
62
- }
63
- const storage = createStorageClient();
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, storage, typedDb, resolvedUserHelper, wsPath, onSocketMessageHandlers.length > 0 ? onSocketMessageHandlers : undefined, undefined, onWsAuth ?? undefined);
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
- initProviderBalance(typedDb);
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
- // Open Postgres pool (direct DATABASE_URL). In direct mode this just
750
- // primes the singleton pool so config errors surface here instead of
751
- // on the first query. Storage (R2) is lazy-initialised on first use.
752
- await initPg();
753
- console.log("[app] Postgres pool ready");
754
- // Schema drift check + auto-migration for new collections / safe changes
755
- try {
756
- const { ensureSchemaSnapshotsTable, checkSchemas, formatSchemaCheckResult, } = await import("./SchemaCheck.js");
757
- await ensureSchemaSnapshotsTable();
758
- const schemaResult = await checkSchemas(allDefs);
759
- if (schemaResult.status === "drift") {
760
- if (process.env["SCHEMA_CHECK_SKIP"] === "true") {
761
- console.warn("[app] WARNING: Schema drift detected but SCHEMA_CHECK_SKIP=true — proceeding anyway!");
762
- console.warn("[app] This is unsafe. Fix the schema drift as soon as possible.");
763
- console.warn(formatSchemaCheckResult(schemaResult));
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.error("[app] Schema drift detected — cannot start.");
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
- else if (schemaResult.status === "baseline") {
773
- // Auto-generate and apply migrations for new collections
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
- catch (err) {
782
- console.warn("[app] Schema check failed (continuing):", err.message);
783
- }
784
- try {
785
- await connectNats();
786
- if (process.env["NATS_PREFIX"] || process.env["COMPOSE_PROJECT_NAME"]) {
787
- setNatsPrefix(process.env["NATS_PREFIX"] ??
788
- process.env["COMPOSE_PROJECT_NAME"] ??
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
- const ttlCollections = [
1086
- { table: "consoleLog", field: "created", seconds: 7 * 86400 },
1087
- { table: "perfLog", field: "created", seconds: 7 * 86400 },
1088
- { table: "feedbackLog", field: "created", seconds: 7 * 86400 },
1089
- { table: "errorLog", field: "created", seconds: 7 * 86400 },
1090
- { table: "aiSpend", field: "created", seconds: 2 * 3600 },
1091
- ];
1092
- setInterval(() => {
1093
- for (const { table, field, seconds } of ttlCollections) {
1094
- const cutoff = new Date(Date.now() - seconds * 1000).toISOString();
1095
- pgQuery(`DELETE FROM "${table}" WHERE data->>'${field}' < $1`, [
1096
- cutoff,
1097
- ]).catch(() => { });
1098
- }
1099
- }, 15 * 60_000);
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
- closePg();
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
  };