nextly 0.0.2-alpha.1 → 0.0.2-alpha.10

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 (93) hide show
  1. package/dist/_dts-chunks/{collections-handler.d-DjgO74Wt.d.ts → collections-handler.d-B3iNFGJv.d.ts} +135 -120
  2. package/dist/_dts-chunks/{config.d-DNwsDnjs.d.ts → config.d-D8eInFE5.d.ts} +13 -1
  3. package/dist/_dts-chunks/{define-component.d-BUgTHmt3.d.ts → define-component.d-COeEsUOT.d.ts} +2 -2
  4. package/dist/_dts-chunks/{index.d-axCAzZ7m.d.ts → index.d-qjDq8N63.d.ts} +5 -5
  5. package/dist/actions/index.mjs +15 -15
  6. package/dist/api/auth-state.mjs +21 -21
  7. package/dist/api/collections-schema-detail.mjs +21 -21
  8. package/dist/api/collections-schema-export.mjs +21 -21
  9. package/dist/api/collections-schema.mjs +21 -21
  10. package/dist/api/components-detail.mjs +21 -21
  11. package/dist/api/components.mjs +21 -21
  12. package/dist/api/email-providers-default.mjs +21 -21
  13. package/dist/api/email-providers-detail.mjs +21 -21
  14. package/dist/api/email-providers-test.mjs +21 -21
  15. package/dist/api/email-providers.mjs +21 -21
  16. package/dist/api/email-send-template.mjs +23 -23
  17. package/dist/api/email-send.mjs +23 -23
  18. package/dist/api/email-templates-detail.mjs +21 -21
  19. package/dist/api/email-templates-layout.mjs +21 -21
  20. package/dist/api/email-templates-preview.mjs +21 -21
  21. package/dist/api/email-templates.mjs +21 -21
  22. package/dist/api/media-bulk.mjs +17 -17
  23. package/dist/api/media-folders.mjs +21 -21
  24. package/dist/api/media-handlers.d.ts +2 -2
  25. package/dist/api/media-handlers.mjs +21 -21
  26. package/dist/api/media.mjs +21 -21
  27. package/dist/api/singles-detail.mjs +21 -21
  28. package/dist/api/singles-schema-detail.mjs +21 -21
  29. package/dist/api/singles.mjs +21 -21
  30. package/dist/api/storage-upload-url.mjs +21 -21
  31. package/dist/api/uploads.mjs +27 -26
  32. package/dist/auth/index.mjs +6 -6
  33. package/dist/{boot-apply-PQSYLDIN.mjs → boot-apply-OE3D3KNU.mjs} +1 -1
  34. package/dist/{chunk-IZWPRDC3.mjs → chunk-2QSGNGOB.mjs} +1 -1
  35. package/dist/{chunk-DP3G27G5.mjs → chunk-35LAHTCU.mjs} +12 -2
  36. package/dist/{chunk-DNNG377Z.mjs → chunk-463A2UDH.mjs} +79 -13
  37. package/dist/{chunk-V4EQTOA4.mjs → chunk-4HUQNXVM.mjs} +2 -2
  38. package/dist/{chunk-VJ66NCL4.mjs → chunk-6C3CST4Q.mjs} +53 -4
  39. package/dist/{chunk-PKMABBB5.mjs → chunk-6GWK77EN.mjs} +1 -1
  40. package/dist/{chunk-XZKLBMN6.mjs → chunk-A75OLKXP.mjs} +44 -16
  41. package/dist/{chunk-TS7GHTG2.mjs → chunk-A7GGVOIV.mjs} +1 -1
  42. package/dist/{chunk-INV7QKLG.mjs → chunk-BZ2EOLXR.mjs} +1 -1
  43. package/dist/{chunk-X7TXCYYN.mjs → chunk-DQGQMP5F.mjs} +46 -26
  44. package/dist/{chunk-2W3DVD7S.mjs → chunk-ERTNRSP3.mjs} +1 -1
  45. package/dist/{chunk-UJ2IMJ4W.mjs → chunk-HREB7UR4.mjs} +10 -4
  46. package/dist/{chunk-NSEFNNU4.mjs → chunk-ILETUFUD.mjs} +302 -105
  47. package/dist/{chunk-A3WPLSDT.mjs → chunk-INTLFB63.mjs} +1 -1
  48. package/dist/{chunk-SBACDPNX.mjs → chunk-JCQMC6HH.mjs} +216 -27
  49. package/dist/{chunk-3FA7FKAV.mjs → chunk-JGVOZSXS.mjs} +58 -4
  50. package/dist/{chunk-M52VMPGA.mjs → chunk-KZFYCMBL.mjs} +1 -1
  51. package/dist/{chunk-W5KKPZT5.mjs → chunk-L7BXB5H3.mjs} +2 -2
  52. package/dist/{chunk-B2GV2BWH.mjs → chunk-MF4S2WSM.mjs} +2 -2
  53. package/dist/{chunk-R6JJQHFC.mjs → chunk-NXA6FD7R.mjs} +1 -1
  54. package/dist/{chunk-XGI4EMS3.mjs → chunk-OPACR7PX.mjs} +3 -3
  55. package/dist/{chunk-2OALJTK6.mjs → chunk-OV4WR3EC.mjs} +22 -42
  56. package/dist/{chunk-YZNBLFIW.mjs → chunk-RH3QV6E6.mjs} +3 -3
  57. package/dist/{chunk-LDKCUMHK.mjs → chunk-RQ3N4DIB.mjs} +2 -2
  58. package/dist/{chunk-YV4Y7SDL.mjs → chunk-TGBLNY5L.mjs} +2 -2
  59. package/dist/{chunk-GZ6DCQKC.mjs → chunk-TVG3WU6C.mjs} +5 -3
  60. package/dist/{chunk-AK6Z23OX.mjs → chunk-UGB6MLR6.mjs} +274 -45
  61. package/dist/{chunk-2Q2SX2CS.mjs → chunk-V5DUKEYT.mjs} +2 -2
  62. package/dist/{chunk-UOP63Q54.mjs → chunk-WRGCEERR.mjs} +1 -1
  63. package/dist/{chunk-O3QHXMOX.mjs → chunk-XCT6CROA.mjs} +23 -19
  64. package/dist/{chunk-P7NH2OSC.mjs → chunk-ZDNGCKSZ.mjs} +78 -49
  65. package/dist/cli/nextly.mjs +1 -1
  66. package/dist/cli/utils/index.d.ts +2 -2
  67. package/dist/cli/utils/index.mjs +1 -1
  68. package/dist/{component-schema-service-5577KVW6.mjs → component-schema-service-HUAQQ4H5.mjs} +2 -2
  69. package/dist/config.d.ts +3 -3
  70. package/dist/database/index.d.ts +2 -2
  71. package/dist/database/index.mjs +3 -3
  72. package/dist/database/seeders/index.mjs +18 -18
  73. package/dist/{db-sync-demote-LJGKLB3S.mjs → db-sync-demote-M7IEFD6N.mjs} +6 -6
  74. package/dist/{db-sync-promote-B26VSYQF.mjs → db-sync-promote-2MCB5JRZ.mjs} +6 -6
  75. package/dist/{dynamic-collection-schema-service-IEXTPIZ7.mjs → dynamic-collection-schema-service-FIRWOXZI.mjs} +2 -2
  76. package/dist/{factory-IWMBKUJM.mjs → factory-UGJGOZZ7.mjs} +2 -2
  77. package/dist/index.d.ts +16 -11
  78. package/dist/index.mjs +24 -55
  79. package/dist/{permissions-3DZZQZMI.mjs → permissions-KH3WCGAR.mjs} +16 -16
  80. package/dist/{pipeline-YOML7SWF.mjs → pipeline-JLANATHU.mjs} +10 -10
  81. package/dist/{preview-ZZTR3QGS.mjs → preview-3RSMZITY.mjs} +3 -3
  82. package/dist/{program-PW6UB2ZC.mjs → program-6V6HLEUI.mjs} +27 -27
  83. package/dist/{register-SF6E6FVU.mjs → register-FCUTHDS5.mjs} +17 -17
  84. package/dist/{reload-config-HWQ4G5MM.mjs → reload-config-52GWTPZG.mjs} +10 -10
  85. package/dist/{routeHandler-UNMMJIBM.mjs → routeHandler-FP26UQPJ.mjs} +26 -26
  86. package/dist/{runtime-schema-generator-NRA6A6Z6.mjs → runtime-schema-generator-NQOLDUDG.mjs} +2 -2
  87. package/dist/runtime.d.ts +2 -2
  88. package/dist/runtime.mjs +26 -26
  89. package/dist/{super-admin-G5ZK5F4T.mjs → super-admin-XZAU4VQM.mjs} +16 -16
  90. package/dist/{system-table-service-WGSRVEGT.mjs → system-table-service-5FIVIALU.mjs} +5 -5
  91. package/dist/{users-7KELGRYJ.mjs → users-K2NJTF55.mjs} +15 -15
  92. package/package.json +8 -8
  93. /package/dist/{first-run-QIVKWJIF.mjs → first-run-2UDWZK5X.mjs} +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  countRows,
8
8
  diffSnapshots,
9
9
  introspectLiveSnapshot
10
- } from "./chunk-SBACDPNX.mjs";
10
+ } from "./chunk-JCQMC6HH.mjs";
11
11
 
12
12
  // src/domains/schema/pipeline/preview.ts
13
13
  async function previewDesiredSchema(args, deps = {}) {
@@ -25,14 +25,16 @@ async function previewDesiredSchema(args, deps = {}) {
25
25
  (c) => buildDesiredTableFromFields(
26
26
  c.tableName,
27
27
  c.fields,
28
- dialect
28
+ dialect,
29
+ { hasStatus: c.status === true }
29
30
  )
30
31
  );
31
32
  const singleTables = Object.values(desired.singles).map(
32
33
  (s) => buildDesiredTableFromFields(
33
34
  s.tableName,
34
35
  s.fields,
35
- dialect
36
+ dialect,
37
+ { hasStatus: s.status === true }
36
38
  )
37
39
  );
38
40
  const componentTables = Object.values(desired.components).map(
@@ -5,16 +5,16 @@ import {
5
5
  countRows,
6
6
  diffSnapshots,
7
7
  introspectLiveSnapshot
8
- } from "./chunk-SBACDPNX.mjs";
8
+ } from "./chunk-JCQMC6HH.mjs";
9
9
  import {
10
10
  ComponentSchemaService
11
- } from "./chunk-V4EQTOA4.mjs";
11
+ } from "./chunk-4HUQNXVM.mjs";
12
12
  import {
13
13
  generateRuntimeSchema
14
- } from "./chunk-IZWPRDC3.mjs";
14
+ } from "./chunk-2QSGNGOB.mjs";
15
15
  import {
16
16
  getDialectTables
17
- } from "./chunk-TS7GHTG2.mjs";
17
+ } from "./chunk-A7GGVOIV.mjs";
18
18
 
19
19
  // src/domains/schema/pipeline/errors.ts
20
20
  import { UnsupportedDialectVersionError } from "@nextlyhq/adapter-drizzle/version-check";
@@ -285,9 +285,6 @@ var RealPreCleanupExecutor = class {
285
285
  }
286
286
  };
287
287
 
288
- // src/domains/schema/pipeline/pushschema-pipeline.ts
289
- import { dequal } from "dequal";
290
-
291
288
  // src/init/schema-snapshot-cache.ts
292
289
  var g = globalThis;
293
290
  function getCachedSnapshot() {
@@ -296,6 +293,27 @@ function getCachedSnapshot() {
296
293
  function setCachedSnapshot(snapshot) {
297
294
  g.__nextly_prevSchemaSnapshot = snapshot;
298
295
  }
296
+ function keyOf(tableNames) {
297
+ return [...tableNames].sort().join(" ");
298
+ }
299
+ function bag() {
300
+ return globalThis;
301
+ }
302
+ function getLiveSnapshot(managedTableNames) {
303
+ return bag().__nextly_liveSnapshots?.get(keyOf(managedTableNames));
304
+ }
305
+ function setLiveSnapshot(managedTableNames, snapshot) {
306
+ const b = bag();
307
+ if (!b.__nextly_liveSnapshots) b.__nextly_liveSnapshots = /* @__PURE__ */ new Map();
308
+ b.__nextly_liveSnapshots.set(keyOf(managedTableNames), snapshot);
309
+ }
310
+ function clearLiveSnapshots() {
311
+ const b = bag();
312
+ if (b.__nextly_liveSnapshots) b.__nextly_liveSnapshots.clear();
313
+ }
314
+
315
+ // src/domains/schema/pipeline/pushschema-pipeline.ts
316
+ import { dequal } from "dequal";
299
317
 
300
318
  // src/runtime/notifications/build-event.ts
301
319
  function buildNotificationEvent(args) {
@@ -323,6 +341,96 @@ function buildNotificationEvent(args) {
323
341
  };
324
342
  }
325
343
 
344
+ // src/domains/schema/pipeline/ddl-emitter/identifiers.ts
345
+ function quoteIdent(identifier) {
346
+ if (identifier.includes("\0")) {
347
+ throw new Error(
348
+ `Invalid identifier (contains NUL byte): ${JSON.stringify(identifier)}`
349
+ );
350
+ }
351
+ return `"${identifier.replace(/"/g, '""')}"`;
352
+ }
353
+
354
+ // src/domains/schema/pipeline/ddl-emitter/postgres.ts
355
+ function columnTail(col) {
356
+ let s = col.type;
357
+ if (col.nullable === false) s += " NOT NULL";
358
+ if (col.default !== void 0) s += ` DEFAULT ${col.default}`;
359
+ return s;
360
+ }
361
+ function createTableColumn(col) {
362
+ if (col.name === "id") {
363
+ return `${quoteIdent(col.name)} ${col.type} PRIMARY KEY NOT NULL`;
364
+ }
365
+ return `${quoteIdent(col.name)} ${columnTail(col)}`;
366
+ }
367
+ function createTableCanonicalIndexes(spec) {
368
+ const colNames = new Set(spec.columns.map((c) => c.name));
369
+ const stmts = [];
370
+ if (colNames.has("slug")) {
371
+ stmts.push(
372
+ `CREATE UNIQUE INDEX ${quoteIdent(`idx_${spec.name}_slug`)} ON ${quoteIdent(spec.name)} USING btree (${quoteIdent("slug")})`
373
+ );
374
+ }
375
+ if (colNames.has("created_at")) {
376
+ stmts.push(
377
+ `CREATE INDEX ${quoteIdent(`idx_${spec.name}_created_at`)} ON ${quoteIdent(spec.name)} USING btree (${quoteIdent("created_at")} DESC)`
378
+ );
379
+ }
380
+ return stmts;
381
+ }
382
+ function emitPostgresDdl(op) {
383
+ switch (op.type) {
384
+ case "rename_table":
385
+ case "rename_column":
386
+ case "drop_column":
387
+ case "drop_table":
388
+ return [];
389
+ case "add_column":
390
+ return [
391
+ `ALTER TABLE ${quoteIdent(op.tableName)} ADD COLUMN ${quoteIdent(op.column.name)} ${columnTail(op.column)}`
392
+ ];
393
+ case "add_table": {
394
+ const cols = op.table.columns.map(createTableColumn);
395
+ const createTable = `CREATE TABLE ${quoteIdent(op.table.name)} (
396
+ ${cols.join(",\n ")}
397
+ )`;
398
+ return [createTable, ...createTableCanonicalIndexes(op.table)];
399
+ }
400
+ case "change_column_type":
401
+ case "change_column_nullable":
402
+ case "change_column_default":
403
+ throw new Error(
404
+ `emitPostgresDdl: op type "${op.type}" not yet implemented \u2014 canEmitWithoutDrizzleKit should not have routed it here`
405
+ );
406
+ default: {
407
+ const exhaustive = op;
408
+ throw new Error(
409
+ `emitPostgresDdl: unknown op ${JSON.stringify(exhaustive)}`
410
+ );
411
+ }
412
+ }
413
+ }
414
+
415
+ // src/domains/schema/pipeline/ddl-emitter/index.ts
416
+ var FAST_PATH_OP_TYPES = /* @__PURE__ */ new Set([
417
+ "add_column",
418
+ "add_table"
419
+ ]);
420
+ function canEmitWithoutDrizzleKit(ops, dialect) {
421
+ if (dialect !== "postgresql") return false;
422
+ if (ops.length === 0) return false;
423
+ return ops.every((op) => FAST_PATH_OP_TYPES.has(op.type));
424
+ }
425
+ function emitDdl(ops, dialect) {
426
+ if (dialect !== "postgresql") {
427
+ throw new Error(
428
+ `emitDdl: unsupported dialect "${dialect}" (fast path is PostgreSQL-only)`
429
+ );
430
+ }
431
+ return ops.flatMap((op) => emitPostgresDdl(op));
432
+ }
433
+
326
434
  // src/domains/schema/pipeline/managed-tables.ts
327
435
  var MANAGED_TABLE_PREFIXES_REGEX = /^(dc_|single_|comp_)/;
328
436
  function isManagedTable(name) {
@@ -393,7 +501,7 @@ function isPreResolutionOp(op) {
393
501
  }
394
502
 
395
503
  // src/domains/schema/pipeline/sql-templates/identifier-quoting.ts
396
- function quoteIdent(name, dialect) {
504
+ function quoteIdent2(name, dialect) {
397
505
  const q4 = dialect === "mysql" ? "`" : '"';
398
506
  if (name.includes(q4)) {
399
507
  throw new Error(
@@ -404,7 +512,7 @@ function quoteIdent(name, dialect) {
404
512
  }
405
513
 
406
514
  // src/domains/schema/pipeline/sql-templates/mysql.ts
407
- var q = (n) => quoteIdent(n, "mysql");
515
+ var q = (n) => quoteIdent2(n, "mysql");
408
516
  function columnDef(c) {
409
517
  const nullable = c.nullable ? "" : " NOT NULL";
410
518
  const def = c.default !== void 0 ? ` DEFAULT ${c.default}` : "";
@@ -480,7 +588,7 @@ var MysqlUnsupportedOperationError = class extends Error {
480
588
  };
481
589
 
482
590
  // src/domains/schema/pipeline/sql-templates/postgres.ts
483
- var q2 = (n) => quoteIdent(n, "postgresql");
591
+ var q2 = (n) => quoteIdent2(n, "postgresql");
484
592
  function columnDef2(c) {
485
593
  const nullable = c.nullable ? "" : " NOT NULL";
486
594
  const def = c.default !== void 0 ? ` DEFAULT ${c.default}` : "";
@@ -547,7 +655,7 @@ function generateChangeColumnDefault2(op) {
547
655
  }
548
656
 
549
657
  // src/domains/schema/pipeline/sql-templates/sqlite.ts
550
- var q3 = (n) => quoteIdent(n, "sqlite");
658
+ var q3 = (n) => quoteIdent2(n, "sqlite");
551
659
  function columnDef3(c) {
552
660
  const nullable = c.nullable ? "" : " NOT NULL";
553
661
  const def = c.default !== void 0 ? ` DEFAULT ${c.default}` : "";
@@ -777,6 +885,29 @@ var DdlExecutionError = class extends Error {
777
885
  this.name = "DdlExecutionError";
778
886
  }
779
887
  };
888
+ var ORPHAN_DROP_PATTERNS = [
889
+ {
890
+ kind: "SEQUENCE",
891
+ re: /^DROP\s+SEQUENCE\s+(?:IF\s+EXISTS\s+)?(?:["`]?\w+["`]?\.)?["`]?(\w+)["`]?/i
892
+ },
893
+ {
894
+ kind: "INDEX",
895
+ re: /^DROP\s+INDEX\s+(?:IF\s+EXISTS\s+)?(?:["`]?\w+["`]?\.)?["`]?(\w+)["`]?/i
896
+ }
897
+ ];
898
+ function logApplyRoute(useFastPath, ops) {
899
+ if (process.env.DEBUG_SCHEMA !== "1") return;
900
+ if (useFastPath) {
901
+ console.debug(
902
+ `[nextly] schema apply: fast-path DDL emitter (${ops.length} op(s))`
903
+ );
904
+ return;
905
+ }
906
+ const nonAdditive = ops.filter((o) => o.type !== "add_column" && o.type !== "add_table").map((o) => o.type);
907
+ console.debug(
908
+ `[nextly] schema apply: drizzle-kit fallback (${ops.length} op(s); non-additive: ${nonAdditive.length === 0 ? "<none>" : nonAdditive.join(",")})`
909
+ );
910
+ }
780
911
  function computeJournalSummaryFromOperations(operations) {
781
912
  let added = 0;
782
913
  let removed = 0;
@@ -864,11 +995,17 @@ var PushSchemaPipeline = class {
864
995
  ...Object.values(desired.singles).map((s) => s.tableName),
865
996
  ...Object.values(desired.components).map((c) => c.tableName)
866
997
  ];
867
- const liveSnapshot = this.testHooks._introspectSnapshotOverride ? await this.testHooks._introspectSnapshotOverride(
868
- db,
869
- dialect,
870
- managedTableNames
871
- ) : await introspectLiveSnapshot(db, dialect, managedTableNames);
998
+ let liveSnapshot;
999
+ if (this.testHooks._introspectSnapshotOverride) {
1000
+ liveSnapshot = await this.testHooks._introspectSnapshotOverride(
1001
+ db,
1002
+ dialect,
1003
+ managedTableNames
1004
+ );
1005
+ } else {
1006
+ const cached2 = getLiveSnapshot(managedTableNames);
1007
+ liveSnapshot = cached2 !== void 0 ? cached2 : await introspectLiveSnapshot(db, dialect, managedTableNames);
1008
+ }
872
1009
  const desiredSnapshot = {
873
1010
  tables: [
874
1011
  ...Object.values(desired.collections).map(
@@ -910,9 +1047,17 @@ var PushSchemaPipeline = class {
910
1047
  countRows: (table) => countRows(db, dialect, table),
911
1048
  dialect
912
1049
  });
913
- const dispatchResult = candidates.length > 0 || classificationResult.level !== "safe" ? await this.deps.promptDispatcher.dispatch({
1050
+ const dropsCoveredByCandidates = /* @__PURE__ */ new Set();
1051
+ for (const c of candidates) {
1052
+ dropsCoveredByCandidates.add(`${c.tableName}::${c.fromColumn}`);
1053
+ }
1054
+ const dispatchEvents = classificationResult.events.filter(
1055
+ (e) => e.kind !== "destructive_drop" || !dropsCoveredByCandidates.has(`${e.tableName}::${e.columnName}`)
1056
+ );
1057
+ const needsPrompt = candidates.length > 0 || dispatchEvents.length > 0;
1058
+ const dispatchResult = needsPrompt ? await this.deps.promptDispatcher.dispatch({
914
1059
  candidates,
915
- events: classificationResult.events,
1060
+ events: dispatchEvents,
916
1061
  classification: classificationResult.level,
917
1062
  channel: promptChannel
918
1063
  }) : {
@@ -928,11 +1073,43 @@ var PushSchemaPipeline = class {
928
1073
  dispatchResult.resolutions,
929
1074
  classificationResult.events
930
1075
  );
931
- const resolvedOps = applyResolutionsToOperations(
1076
+ const resolvedOps = this.testHooks._resolvedOpsOverride ?? applyResolutionsToOperations(
932
1077
  operations,
933
1078
  toRenameResolutions(dispatchResult.confirmedRenames, candidates)
934
1079
  );
935
1080
  const drizzleSchema = this.testHooks._buildDrizzleSchemaOverride ? this.testHooks._buildDrizzleSchemaOverride(patchedDesired, dialect) : this.buildDrizzleSchema(patchedDesired, dialect);
1081
+ const affectedTableNames = /* @__PURE__ */ new Set();
1082
+ for (const op of resolvedOps) {
1083
+ switch (op.type) {
1084
+ case "add_table":
1085
+ affectedTableNames.add(op.table.name);
1086
+ break;
1087
+ case "rename_table":
1088
+ affectedTableNames.add(op.toName);
1089
+ break;
1090
+ case "drop_table":
1091
+ break;
1092
+ case "add_column":
1093
+ case "drop_column":
1094
+ case "rename_column":
1095
+ case "change_column_type":
1096
+ case "change_column_nullable":
1097
+ case "change_column_default":
1098
+ affectedTableNames.add(op.tableName);
1099
+ break;
1100
+ default: {
1101
+ const _exhaustive = op;
1102
+ void _exhaustive;
1103
+ }
1104
+ }
1105
+ }
1106
+ const scopedSchema = {};
1107
+ for (const [tableName, tableObj] of Object.entries(drizzleSchema)) {
1108
+ if (affectedTableNames.has(tableName)) {
1109
+ scopedSchema[tableName] = tableObj;
1110
+ }
1111
+ }
1112
+ const effectiveDrizzleSchema = Object.keys(scopedSchema).length > 0 ? scopedSchema : drizzleSchema;
936
1113
  const kit = this.testHooks._kitOverride ? this.testHooks._kitOverride : await this.importDrizzleKit(dialect, databaseName);
937
1114
  const isSqlite = dialect === "sqlite";
938
1115
  const runApply = async (tx) => {
@@ -970,22 +1147,30 @@ var PushSchemaPipeline = class {
970
1147
  err
971
1148
  );
972
1149
  }
973
- const desiredTableNames = Object.keys(drizzleSchema);
974
- let pushResult;
975
- try {
976
- pushResult = await withCapturedStdout(
977
- () => kit.pushSchema(drizzleSchema, tx, desiredTableNames),
978
- // eslint-disable-next-line turbo/no-undeclared-env-vars
979
- process.env.DEBUG_SCHEMA === "1" ? { debug: (msg) => console.debug(msg) } : void 0
980
- );
981
- } catch (err) {
982
- throw new PushSchemaError(
983
- err instanceof Error ? err.message : String(err),
984
- err
985
- );
1150
+ const desiredTableNames = Object.keys(effectiveDrizzleSchema);
1151
+ const useFastPath = canEmitWithoutDrizzleKit(resolvedOps, dialect);
1152
+ logApplyRoute(useFastPath, resolvedOps);
1153
+ let emittedStatements;
1154
+ if (useFastPath) {
1155
+ emittedStatements = emitDdl(resolvedOps, dialect);
1156
+ } else {
1157
+ let pushResult;
1158
+ try {
1159
+ pushResult = await withCapturedStdout(
1160
+ () => kit.pushSchema(effectiveDrizzleSchema, tx, desiredTableNames),
1161
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
1162
+ process.env.DEBUG_SCHEMA === "1" ? { debug: (msg) => console.debug(msg) } : void 0
1163
+ );
1164
+ } catch (err) {
1165
+ throw new PushSchemaError(
1166
+ err instanceof Error ? err.message : String(err),
1167
+ err
1168
+ );
1169
+ }
1170
+ emittedStatements = pushResult.statementsToExecute;
986
1171
  }
987
1172
  const safe = this.filterUnsafeStatements(
988
- pushResult.statementsToExecute,
1173
+ emittedStatements,
989
1174
  desiredTableNames
990
1175
  );
991
1176
  try {
@@ -1066,25 +1251,67 @@ var PushSchemaPipeline = class {
1066
1251
  }
1067
1252
  }
1068
1253
  filterUnsafeStatements(statements, desiredTableNames) {
1069
- const desiredSet = new Set(
1070
- desiredTableNames.map((t) => t.toLowerCase())
1071
- );
1254
+ const desiredSet = new Set(desiredTableNames.map((t) => t.toLowerCase()));
1072
1255
  return statements.filter((stmt) => {
1073
1256
  const dropMatch = stmt.match(
1074
1257
  /^DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?(?:["`]?\w+["`]?\.)?["`]?(\w+)["`]?/i
1075
1258
  );
1076
- if (!dropMatch) return true;
1077
- const tableName = dropMatch[1] ?? "<unknown>";
1078
- const isInDesired = desiredSet.has(tableName.toLowerCase());
1079
- if (isInDesired) {
1080
- return true;
1259
+ if (dropMatch) {
1260
+ const tableName = dropMatch[1] ?? "<unknown>";
1261
+ const isInDesired = desiredSet.has(tableName.toLowerCase());
1262
+ if (isInDesired) {
1263
+ return true;
1264
+ }
1265
+ console.warn(
1266
+ `[Nextly schema] Blocked DROP TABLE "${tableName}" emitted by drizzle-kit pushSchema (table not in current desired schema). If this drop was intentional, route it through the pre-resolution executor with explicit user confirmation. (managed=${isManagedTable(tableName)})`
1267
+ );
1268
+ return false;
1081
1269
  }
1082
- console.warn(
1083
- `[Nextly schema] Blocked DROP TABLE "${tableName}" emitted by drizzle-kit pushSchema (table not in current desired schema). If this drop was intentional, route it through the pre-resolution executor with explicit user confirmation. (managed=${isManagedTable(tableName)})`
1084
- );
1085
- return false;
1270
+ for (const { kind, re } of ORPHAN_DROP_PATTERNS) {
1271
+ const m = stmt.match(re);
1272
+ if (!m) continue;
1273
+ const objectName = m[1] ?? "";
1274
+ if (this.inferOwnerTableFromObjectName(objectName, desiredSet) !== null) {
1275
+ return true;
1276
+ }
1277
+ console.warn(
1278
+ `[Nextly schema] Blocked DROP ${kind} "${objectName}" emitted by drizzle-kit pushSchema (owner table not in current desired schema or name is non-conventional). If this drop was intentional, route it through the pre-resolution executor with explicit user confirmation, or drop it manually before re-running if the ${kind.toLowerCase()} name is custom.`
1279
+ );
1280
+ return false;
1281
+ }
1282
+ return true;
1086
1283
  });
1087
1284
  }
1285
+ /**
1286
+ * Infers the owner table of a sequence or index from its name using
1287
+ * Postgres's default naming conventions:
1288
+ * - SERIAL / IDENTITY sequences: `<table>_<col>_seq`
1289
+ * - Indexes: `<table>_<col(s)>_idx | _key | _pkey | _unique`
1290
+ *
1291
+ * Strategy: walk underscore-delimited prefixes from longest to shortest
1292
+ * and return the first candidate found in `desiredSet`. Longest-first
1293
+ * ensures that multi-word table names like `email_templates` are
1294
+ * preferred over the shorter prefix `email`.
1295
+ *
1296
+ * Examples:
1297
+ * accounts_id_seq → "accounts" (if in desiredSet)
1298
+ * email_templates_id_seq → "email_templates" (if in desiredSet)
1299
+ * dc_posts_title_idx → "dc_posts" (if in desiredSet)
1300
+ * idx_completely_custom → null (no prefix matches)
1301
+ *
1302
+ * Returns the matched table name (lowercased) or `null` if no prefix
1303
+ * in `desiredSet` was found. A `null` result means we can't identify
1304
+ * the owner, and the caller should treat the statement as unsafe.
1305
+ */
1306
+ inferOwnerTableFromObjectName(objectName, desiredSet) {
1307
+ const lower = objectName.toLowerCase();
1308
+ const parts = lower.split("_");
1309
+ for (let i = parts.length - 1; i > 0; i--) {
1310
+ const candidate = parts.slice(0, i).join("_");
1311
+ if (desiredSet.has(candidate)) return candidate;
1312
+ }
1313
+ return null;
1314
+ }
1088
1315
  async runSqlitePragma(db, pragma) {
1089
1316
  const { sql: sqlTag } = await import("drizzle-orm");
1090
1317
  const dbTyped = db;
@@ -1455,6 +1682,8 @@ export {
1455
1682
  TTYRequiredError,
1456
1683
  PromptCancelledError,
1457
1684
  RealPreCleanupExecutor,
1685
+ setLiveSnapshot,
1686
+ clearLiveSnapshots,
1458
1687
  generateSQL,
1459
1688
  PushSchemaPipeline,
1460
1689
  noopPreRenameExecutor,
@@ -7,10 +7,10 @@ import {
7
7
  import {
8
8
  hasAnyPermission,
9
9
  hasPermission
10
- } from "./chunk-W5KKPZT5.mjs";
10
+ } from "./chunk-L7BXB5H3.mjs";
11
11
  import {
12
12
  env
13
- } from "./chunk-UJ2IMJ4W.mjs";
13
+ } from "./chunk-HREB7UR4.mjs";
14
14
  import {
15
15
  container
16
16
  } from "./chunk-D5HQBNUB.mjs";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CreatePermissionSchema,
3
3
  ServiceContainer
4
- } from "./chunk-NSEFNNU4.mjs";
4
+ } from "./chunk-ILETUFUD.mjs";
5
5
 
6
6
  // src/database/seeders/permissions.ts
7
7
  var RESOURCES = ["users", "roles", "permissions"];
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  routeAuthRequest
3
- } from "./chunk-A3WPLSDT.mjs";
3
+ } from "./chunk-INTLFB63.mjs";
4
4
  import {
5
5
  POST
6
- } from "./chunk-YV4Y7SDL.mjs";
6
+ } from "./chunk-TGBLNY5L.mjs";
7
7
  import {
8
8
  readJsonBody
9
9
  } from "./chunk-VQJQHVEV.mjs";
10
10
  import {
11
11
  POST as POST2
12
- } from "./chunk-LDKCUMHK.mjs";
12
+ } from "./chunk-RQ3N4DIB.mjs";
13
13
  import {
14
14
  createJsonErrorResponse,
15
15
  isErrorResponse,
@@ -18,7 +18,7 @@ import {
18
18
  requireCollectionAccess,
19
19
  requirePermission,
20
20
  toNextlyAuthError
21
- } from "./chunk-2Q2SX2CS.mjs";
21
+ } from "./chunk-V5DUKEYT.mjs";
22
22
  import {
23
23
  nextlyValidationFromZod
24
24
  } from "./chunk-GJNSJU4S.mjs";
@@ -45,12 +45,12 @@ import {
45
45
  import {
46
46
  ensureHmrListener,
47
47
  getCachedNextly
48
- } from "./chunk-P7NH2OSC.mjs";
48
+ } from "./chunk-ZDNGCKSZ.mjs";
49
49
  import {
50
50
  getService,
51
51
  isServicesRegistered,
52
52
  registerServices
53
- } from "./chunk-X7TXCYYN.mjs";
53
+ } from "./chunk-DQGQMP5F.mjs";
54
54
  import {
55
55
  readOrGenerateRequestId
56
56
  } from "./chunk-67GXH6PR.mjs";
@@ -61,20 +61,20 @@ import {
61
61
  ImageSizeService,
62
62
  ServiceDispatcher,
63
63
  parseWhereQuery
64
- } from "./chunk-NSEFNNU4.mjs";
64
+ } from "./chunk-ILETUFUD.mjs";
65
65
  import {
66
66
  containsSuperAdminRole,
67
67
  hasSuperAdminExcluding,
68
68
  isSuperAdmin,
69
69
  listEffectivePermissions
70
- } from "./chunk-W5KKPZT5.mjs";
70
+ } from "./chunk-L7BXB5H3.mjs";
71
71
  import {
72
72
  BaseService,
73
73
  withTimezoneFormatting
74
- } from "./chunk-2W3DVD7S.mjs";
74
+ } from "./chunk-ERTNRSP3.mjs";
75
75
  import {
76
76
  getDialectTables
77
- } from "./chunk-TS7GHTG2.mjs";
77
+ } from "./chunk-A7GGVOIV.mjs";
78
78
  import {
79
79
  nextlyMigrationJournalMysql,
80
80
  nextlyMigrationJournalPg,
@@ -82,7 +82,7 @@ import {
82
82
  } from "./chunk-H26B4FYG.mjs";
83
83
  import {
84
84
  env
85
- } from "./chunk-UJ2IMJ4W.mjs";
85
+ } from "./chunk-HREB7UR4.mjs";
86
86
  import {
87
87
  getImageProcessor,
88
88
  getMediaStorage
@@ -2154,8 +2154,8 @@ function buildAuthRouterDeps(getService2) {
2154
2154
  }
2155
2155
  },
2156
2156
  createSuperAdmin: async (data) => {
2157
- const { seedPermissions } = await import("./permissions-3DZZQZMI.mjs");
2158
- const { seedSuperAdmin } = await import("./super-admin-G5ZK5F4T.mjs");
2157
+ const { seedPermissions } = await import("./permissions-KH3WCGAR.mjs");
2158
+ const { seedSuperAdmin } = await import("./super-admin-XZAU4VQM.mjs");
2159
2159
  const adapter = getService2("adapter");
2160
2160
  await seedPermissions(adapter, { silent: true });
2161
2161
  const result = await seedSuperAdmin(adapter, {
@@ -2180,7 +2180,7 @@ function buildAuthRouterDeps(getService2) {
2180
2180
  };
2181
2181
  },
2182
2182
  seedPermissions: async () => {
2183
- const { seedPermissions } = await import("./permissions-3DZZQZMI.mjs");
2183
+ const { seedPermissions } = await import("./permissions-KH3WCGAR.mjs");
2184
2184
  const adapter = getService2("adapter");
2185
2185
  await seedPermissions(adapter, { silent: true });
2186
2186
  },
@@ -2336,10 +2336,8 @@ async function ensureServicesInitialized() {
2336
2336
  if (nextlyConfig.users) serviceConfig.users = nextlyConfig.users;
2337
2337
  if (nextlyConfig.admin) serviceConfig.admin = nextlyConfig.admin;
2338
2338
  if (nextlyConfig.auth) serviceConfig.auth = nextlyConfig.auth;
2339
- if (nextlyConfig.security)
2340
- serviceConfig.security = nextlyConfig.security;
2341
- if (nextlyConfig.apiKeys)
2342
- serviceConfig.apiKeys = nextlyConfig.apiKeys;
2339
+ if (nextlyConfig.security) serviceConfig.security = nextlyConfig.security;
2340
+ if (nextlyConfig.apiKeys) serviceConfig.apiKeys = nextlyConfig.apiKeys;
2343
2341
  if (nextlyConfig.db) {
2344
2342
  const dbConfig = nextlyConfig.db;
2345
2343
  if (dbConfig.schemasDir) serviceConfig.schemasDir = dbConfig.schemasDir;
@@ -2347,6 +2345,12 @@ async function ensureServicesInitialized() {
2347
2345
  serviceConfig.migrationsDir = dbConfig.migrationsDir;
2348
2346
  }
2349
2347
  }
2348
+ if (process.env.NODE_ENV === "development" && // eslint-disable-next-line turbo/no-undeclared-env-vars
2349
+ process.env.NEXTLY_DISABLE_INSTRUMENTATION_WARNING !== "1") {
2350
+ console.warn(
2351
+ "[nextly] Cold-boot triggered by an incoming request \u2014 no instrumentation.ts detected. Each Next.js worker will now independently run schema introspection and permission seeding against your database, multiplying connection load. Add an `instrumentation.ts` at your project root (see https://nextly.dev/docs/getting-started/instrumentation) to fold this into a single worker-warmup. Suppress with NEXTLY_DISABLE_INSTRUMENTATION_WARNING=1."
2352
+ );
2353
+ }
2350
2354
  await registerServices(serviceConfig);
2351
2355
  try {
2352
2356
  const emailTemplateService = getService("emailTemplateService");
@@ -2392,7 +2396,7 @@ async function ensureServicesInitialized() {
2392
2396
  } else {
2393
2397
  console.log("[Auth Handler] Services auto-initialized with defaults");
2394
2398
  }
2395
- const { runBootTimeApplyIfDev } = await import("./boot-apply-PQSYLDIN.mjs");
2399
+ const { runBootTimeApplyIfDev } = await import("./boot-apply-OE3D3KNU.mjs");
2396
2400
  await runBootTimeApplyIfDev({ caller: "auth-handler" });
2397
2401
  ensureHmrListener();
2398
2402
  }