nextly 0.0.2-alpha.7 → 0.0.2-alpha.9

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 (106) hide show
  1. package/dist/_dts-chunks/{collections-handler.d-DAGa4oyr.d.ts → collections-handler.d-B3iNFGJv.d.ts} +4 -2
  2. package/dist/_dts-chunks/{config.d-gCEU-kSb.d.ts → config.d-D8eInFE5.d.ts} +1 -1
  3. package/dist/_dts-chunks/{define-component.d-B5ffJpKw.d.ts → define-component.d-COeEsUOT.d.ts} +2 -2
  4. package/dist/_dts-chunks/{index.d-CknEcQSu.d.ts → index.d-qjDq8N63.d.ts} +5 -5
  5. package/dist/actions/index.mjs +16 -16
  6. package/dist/api/auth-state.mjs +23 -23
  7. package/dist/api/collections-schema-detail.mjs +23 -23
  8. package/dist/api/collections-schema-export.mjs +23 -23
  9. package/dist/api/collections-schema.mjs +24 -24
  10. package/dist/api/components-detail.mjs +24 -24
  11. package/dist/api/components.mjs +24 -24
  12. package/dist/api/email-providers-default.mjs +24 -24
  13. package/dist/api/email-providers-detail.mjs +25 -25
  14. package/dist/api/email-providers-test.mjs +25 -25
  15. package/dist/api/email-providers.mjs +26 -26
  16. package/dist/api/email-send-template.mjs +26 -26
  17. package/dist/api/email-send.mjs +26 -26
  18. package/dist/api/email-templates-detail.mjs +25 -25
  19. package/dist/api/email-templates-layout.mjs +25 -25
  20. package/dist/api/email-templates-preview.mjs +26 -26
  21. package/dist/api/email-templates.mjs +26 -26
  22. package/dist/api/health.mjs +2 -2
  23. package/dist/api/index.mjs +2 -2
  24. package/dist/api/media-bulk.mjs +20 -20
  25. package/dist/api/media-folders.mjs +24 -24
  26. package/dist/api/media-handlers.d.ts +2 -2
  27. package/dist/api/media-handlers.mjs +25 -25
  28. package/dist/api/media.mjs +25 -25
  29. package/dist/api/singles-detail.mjs +25 -25
  30. package/dist/api/singles-schema-detail.mjs +24 -24
  31. package/dist/api/singles.mjs +23 -23
  32. package/dist/api/storage-upload-url.mjs +24 -24
  33. package/dist/api/uploads.mjs +29 -28
  34. package/dist/auth/index.mjs +7 -7
  35. package/dist/{boot-apply-5EFSWAMW.mjs → boot-apply-TDOMT356.mjs} +1 -1
  36. package/dist/{chunk-UB4CALU5.mjs → chunk-2QSGNGOB.mjs} +1 -1
  37. package/dist/{chunk-DP3G27G5.mjs → chunk-35LAHTCU.mjs} +12 -2
  38. package/dist/{chunk-L5FA2FAY.mjs → chunk-463A2UDH.mjs} +6 -3
  39. package/dist/{chunk-JXZITQPZ.mjs → chunk-4HUQNXVM.mjs} +1 -1
  40. package/dist/{chunk-CLBPXLO3.mjs → chunk-4LLOFW52.mjs} +27 -23
  41. package/dist/{chunk-NRUWQ5Z7.mjs → chunk-5WWWJCKI.mjs} +3 -5
  42. package/dist/{chunk-HVH4J6S6.mjs → chunk-7MA6UATK.mjs} +27 -25
  43. package/dist/{chunk-LP2CDTCR.mjs → chunk-A75OLKXP.mjs} +1 -1
  44. package/dist/{chunk-L3SZUFF4.mjs → chunk-AKK5Q5SX.mjs} +1 -1
  45. package/dist/{chunk-3NUAFSDX.mjs → chunk-DWV7GUKQ.mjs} +1 -1
  46. package/dist/{chunk-D72XH3BG.mjs → chunk-ERJGWWPB.mjs} +2 -2
  47. package/dist/{chunk-SSRCS4NR.mjs → chunk-FI2Z2B2J.mjs} +5 -5
  48. package/dist/{chunk-EBDAFQUX.mjs → chunk-GJIHOHY5.mjs} +2 -2
  49. package/dist/{chunk-RKXTA5KC.mjs → chunk-HLTSQIP6.mjs} +79 -50
  50. package/dist/{chunk-UJ2IMJ4W.mjs → chunk-HREB7UR4.mjs} +10 -4
  51. package/dist/{chunk-66ZNVKTF.mjs → chunk-HSIAXEYF.mjs} +274 -45
  52. package/dist/{chunk-QOH5I67F.mjs → chunk-JAOH2TTZ.mjs} +3 -3
  53. package/dist/{chunk-J4KHGYOM.mjs → chunk-JCQMC6HH.mjs} +69 -2
  54. package/dist/{chunk-LPVOTXNV.mjs → chunk-KLICUQPV.mjs} +1 -1
  55. package/dist/{chunk-ZVN3JILF.mjs → chunk-KPCSDPFQ.mjs} +103 -21
  56. package/dist/{chunk-M52VMPGA.mjs → chunk-KZFYCMBL.mjs} +1 -1
  57. package/dist/{chunk-FQH647CT.mjs → chunk-NJ3LXLSJ.mjs} +53 -4
  58. package/dist/{chunk-MWW7OUDL.mjs → chunk-OVQCDNU3.mjs} +23 -43
  59. package/dist/{chunk-INV7QKLG.mjs → chunk-PAWMG5BR.mjs} +1 -1
  60. package/dist/{chunk-2W3DVD7S.mjs → chunk-PFRMIEJ3.mjs} +1 -1
  61. package/dist/{chunk-WZBYMYVW.mjs → chunk-QPYR3TC4.mjs} +1 -1
  62. package/dist/{chunk-NAP3TDS6.mjs → chunk-SWVNFKWD.mjs} +2 -2
  63. package/dist/{chunk-KSKKIZDP.mjs → chunk-TFCPZ7PG.mjs} +4 -4
  64. package/dist/{chunk-JWAH6ROD.mjs → chunk-TVG3WU6C.mjs} +1 -1
  65. package/dist/{chunk-7YKKCBOC.mjs → chunk-V2W7G5GC.mjs} +3 -3
  66. package/dist/{chunk-RNKZALZE.mjs → chunk-VH4BX2QH.mjs} +5 -5
  67. package/dist/{chunk-TK76W55J.mjs → chunk-X3OHQBMZ.mjs} +6 -2
  68. package/dist/{chunk-TO5AFLVQ.mjs → chunk-XIKEJO27.mjs} +1 -1
  69. package/dist/{chunk-ZE6A3FYH.mjs → chunk-YG2HSZC4.mjs} +1 -1
  70. package/dist/{chunk-VQJQHVEV.mjs → chunk-YLRZTPSK.mjs} +1 -1
  71. package/dist/{chunk-TS7GHTG2.mjs → chunk-YXZH65YV.mjs} +2 -2
  72. package/dist/{chunk-GJNSJU4S.mjs → chunk-Z52OQOZH.mjs} +1 -1
  73. package/dist/cli/nextly.mjs +1 -1
  74. package/dist/cli/utils/index.d.ts +2 -2
  75. package/dist/cli/utils/index.mjs +3 -3
  76. package/dist/{component-schema-service-JOQIBQGK.mjs → component-schema-service-HUAQQ4H5.mjs} +2 -2
  77. package/dist/{config-loader-23YEMC3Z.mjs → config-loader-MUFY6UMU.mjs} +2 -2
  78. package/dist/config.d.ts +3 -3
  79. package/dist/database/index.d.ts +2 -2
  80. package/dist/database/index.mjs +4 -4
  81. package/dist/database/seeders/index.mjs +19 -19
  82. package/dist/{db-sync-demote-Z2HOXRZN.mjs → db-sync-demote-2DAQZXLD.mjs} +8 -8
  83. package/dist/{db-sync-promote-FKWZSRYC.mjs → db-sync-promote-SBTPSUEJ.mjs} +7 -7
  84. package/dist/{dynamic-collection-schema-service-KMOP5PGD.mjs → dynamic-collection-schema-service-FIRWOXZI.mjs} +2 -2
  85. package/dist/errors/index.d.ts +2 -0
  86. package/dist/errors/index.mjs +1 -1
  87. package/dist/{factory-IWMBKUJM.mjs → factory-UGJGOZZ7.mjs} +2 -2
  88. package/dist/index.d.ts +16 -11
  89. package/dist/index.mjs +25 -56
  90. package/dist/observability/index.mjs +1 -1
  91. package/dist/{permissions-YZSSFHU4.mjs → permissions-YEODB733.mjs} +17 -17
  92. package/dist/{pipeline-2DWG7LSN.mjs → pipeline-URL33V42.mjs} +11 -11
  93. package/dist/{preview-H6CJBMCP.mjs → preview-3RSMZITY.mjs} +3 -3
  94. package/dist/{program-CEFDADQM.mjs → program-TOV63II7.mjs} +29 -29
  95. package/dist/{register-G6I4N6QM.mjs → register-O2CJDFCK.mjs} +18 -18
  96. package/dist/reload-config-5P3IUF6O.mjs +23 -0
  97. package/dist/{routeHandler-ROBRMRZA.mjs → routeHandler-P2KXM7MH.mjs} +30 -30
  98. package/dist/{runtime-schema-generator-MOPQWGJP.mjs → runtime-schema-generator-NQOLDUDG.mjs} +2 -2
  99. package/dist/runtime.d.ts +2 -2
  100. package/dist/runtime.mjs +30 -30
  101. package/dist/{super-admin-WSTXAZSS.mjs → super-admin-6LWRM36J.mjs} +17 -17
  102. package/dist/{system-table-service-WGSRVEGT.mjs → system-table-service-FIX3AVKW.mjs} +6 -6
  103. package/dist/{users-NFD7IUFT.mjs → users-Q773BQCU.mjs} +16 -16
  104. package/package.json +8 -8
  105. package/dist/reload-config-VUEIQP5W.mjs +0 -23
  106. /package/dist/{first-run-QIVKWJIF.mjs → first-run-2JTNWFEG.mjs} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CollectionRegistryService
3
- } from "./chunk-D72XH3BG.mjs";
3
+ } from "./chunk-ERJGWWPB.mjs";
4
4
  import {
5
5
  getAdapterFromDI,
6
6
  getCollectionRegistryFromDI,
@@ -27,29 +27,29 @@ import {
27
27
  getProductionNotifier,
28
28
  noopMigrationJournal,
29
29
  noopPreRenameExecutor
30
- } from "./chunk-66ZNVKTF.mjs";
30
+ } from "./chunk-HSIAXEYF.mjs";
31
31
  import {
32
32
  previewDesiredSchema
33
- } from "./chunk-JWAH6ROD.mjs";
33
+ } from "./chunk-TVG3WU6C.mjs";
34
34
  import {
35
35
  RealClassifier,
36
36
  RegexRenameDetector,
37
37
  countNulls,
38
38
  countRows
39
- } from "./chunk-J4KHGYOM.mjs";
39
+ } from "./chunk-JCQMC6HH.mjs";
40
40
  import {
41
41
  ComponentSchemaService
42
- } from "./chunk-JXZITQPZ.mjs";
42
+ } from "./chunk-4HUQNXVM.mjs";
43
43
  import {
44
44
  resolveSingleTableName
45
45
  } from "./chunk-I4JMR3UR.mjs";
46
46
  import {
47
47
  DynamicCollectionSchemaService,
48
48
  DynamicCollectionValidationService
49
- } from "./chunk-LP2CDTCR.mjs";
49
+ } from "./chunk-A75OLKXP.mjs";
50
50
  import {
51
51
  generateRuntimeSchema
52
- } from "./chunk-UB4CALU5.mjs";
52
+ } from "./chunk-2QSGNGOB.mjs";
53
53
  import {
54
54
  calculateSchemaHash
55
55
  } from "./chunk-5HMZ644B.mjs";
@@ -65,11 +65,11 @@ import {
65
65
  listRoleSlugsForUser,
66
66
  validatePasswordStrength,
67
67
  verifyPassword
68
- } from "./chunk-NAP3TDS6.mjs";
68
+ } from "./chunk-SWVNFKWD.mjs";
69
69
  import {
70
70
  BaseService,
71
71
  normalizeDbTimestamp
72
- } from "./chunk-2W3DVD7S.mjs";
72
+ } from "./chunk-PFRMIEJ3.mjs";
73
73
  import {
74
74
  apiKeys,
75
75
  apiKeys2,
@@ -90,13 +90,13 @@ import {
90
90
  userRoles,
91
91
  userRoles2,
92
92
  userRoles3
93
- } from "./chunk-TS7GHTG2.mjs";
93
+ } from "./chunk-YXZH65YV.mjs";
94
94
  import {
95
95
  createAdapterFromEnv
96
- } from "./chunk-DP3G27G5.mjs";
96
+ } from "./chunk-35LAHTCU.mjs";
97
97
  import {
98
98
  env
99
- } from "./chunk-UJ2IMJ4W.mjs";
99
+ } from "./chunk-HREB7UR4.mjs";
100
100
  import {
101
101
  deleteImageSizes,
102
102
  generateImageSizes,
@@ -120,7 +120,7 @@ import {
120
120
  import {
121
121
  NextlyError,
122
122
  toDbError
123
- } from "./chunk-NRUWQ5Z7.mjs";
123
+ } from "./chunk-5WWWJCKI.mjs";
124
124
  import {
125
125
  toPluralLabel,
126
126
  toSingularLabel
@@ -288,7 +288,7 @@ var AuthService = class extends BaseService {
288
288
  }
289
289
  let newUser;
290
290
  try {
291
- const userService = new (await import("./users-NFD7IUFT.mjs")).UsersService(this.adapter, this.logger);
291
+ const userService = new (await import("./users-Q773BQCU.mjs")).UsersService(this.adapter, this.logger);
292
292
  newUser = await userService.createLocalUser({
293
293
  email: userData.email,
294
294
  name: userData.name ?? "User",
@@ -7728,7 +7728,7 @@ var CollectionMetadataService = class extends BaseService {
7728
7728
  */
7729
7729
  async registerRuntimeSchema(tableName, fields, options) {
7730
7730
  try {
7731
- const { generateRuntimeSchema: generateRuntimeSchema2 } = await import("./runtime-schema-generator-MOPQWGJP.mjs");
7731
+ const { generateRuntimeSchema: generateRuntimeSchema2 } = await import("./runtime-schema-generator-NQOLDUDG.mjs");
7732
7732
  const dialect = this.adapter.getCapabilities().dialect;
7733
7733
  const { table } = generateRuntimeSchema2(tableName, fields, dialect, {
7734
7734
  status: options?.hasStatus === true
@@ -14452,6 +14452,81 @@ var CollectionEntryService = class extends BaseService {
14452
14452
 
14453
14453
  // src/domains/collections/services/collection-relationship-service.ts
14454
14454
  import { eq as eq11, inArray as inArray6, sql as sql5 } from "drizzle-orm";
14455
+
14456
+ // src/shared/lib/get-base-url.ts
14457
+ function getBaseUrl(override) {
14458
+ const raw = override?.trim() || env.NEXT_PUBLIC_APP_URL?.trim();
14459
+ const url = raw || "http://localhost:3000";
14460
+ return url.replace(/\/+$/, "");
14461
+ }
14462
+
14463
+ // src/lib/media-variant.ts
14464
+ function getMediaVariant(media, name, options = {}) {
14465
+ if (!media) return void 0;
14466
+ const { fallback, preferThumbnail = true } = options;
14467
+ const sizes = media.sizes ?? null;
14468
+ if (sizes) {
14469
+ const direct = sizes[name];
14470
+ if (direct?.url) return direct.url;
14471
+ if (fallback) {
14472
+ const fb = sizes[fallback];
14473
+ if (fb?.url) return fb.url;
14474
+ }
14475
+ }
14476
+ if (preferThumbnail && media.thumbnailUrl) return media.thumbnailUrl;
14477
+ return media.url;
14478
+ }
14479
+ function getSmallestMediaVariant(media) {
14480
+ if (!media) return void 0;
14481
+ const sizes = media.sizes ?? null;
14482
+ if (sizes) {
14483
+ const entries = Object.values(sizes).filter(
14484
+ (v) => v?.url && v.width && v.height
14485
+ );
14486
+ if (entries.length > 0) {
14487
+ const smallest = entries.reduce(
14488
+ (acc, cur) => (cur.width ?? 0) * (cur.height ?? 0) < (acc.width ?? 0) * (acc.height ?? 0) ? cur : acc
14489
+ );
14490
+ return smallest.url;
14491
+ }
14492
+ }
14493
+ return media.thumbnailUrl ?? media.url;
14494
+ }
14495
+ function getMediaBaseUrl() {
14496
+ return getBaseUrl();
14497
+ }
14498
+ function isAbsoluteUrl(url) {
14499
+ return /^(?:[a-z][a-z0-9+.-]*:)?\/\//i.test(url);
14500
+ }
14501
+ function toAbsoluteMediaUrl(url, baseUrl = getMediaBaseUrl()) {
14502
+ if (!url) return url;
14503
+ if (isAbsoluteUrl(url)) return url;
14504
+ const path3 = url.startsWith("/") ? url : `/${url}`;
14505
+ return `${baseUrl}${path3}`;
14506
+ }
14507
+ function absolutizeMediaUrls(row, baseUrl = getMediaBaseUrl()) {
14508
+ const sizes = row.sizes;
14509
+ let absolutizedSizes = sizes ?? null;
14510
+ if (sizes && typeof sizes === "object") {
14511
+ absolutizedSizes = Object.fromEntries(
14512
+ Object.entries(sizes).map(([name, variant]) => [
14513
+ name,
14514
+ variant && typeof variant === "object" ? {
14515
+ ...variant,
14516
+ url: toAbsoluteMediaUrl(variant.url ?? null, baseUrl)
14517
+ } : variant
14518
+ ])
14519
+ );
14520
+ }
14521
+ return {
14522
+ ...row,
14523
+ url: toAbsoluteMediaUrl(row.url ?? null, baseUrl),
14524
+ thumbnailUrl: toAbsoluteMediaUrl(row.thumbnailUrl ?? null, baseUrl),
14525
+ ...sizes !== void 0 ? { sizes: absolutizedSizes } : {}
14526
+ };
14527
+ }
14528
+
14529
+ // src/domains/collections/services/collection-relationship-service.ts
14455
14530
  var DEFAULT_RELATIONSHIP_DEPTH = 2;
14456
14531
  var MAX_RELATIONSHIP_DEPTH = 5;
14457
14532
  function isRelationshipField3(field) {
@@ -15377,7 +15452,10 @@ var CollectionRelationshipService = class extends BaseService {
15377
15452
  return [];
15378
15453
  }
15379
15454
  const rows = await this.db.select().from(mediaTable).where(inArray6(mediaTable.id, ids));
15380
- return rows.map((row) => keysToCamelCase(row));
15455
+ return rows.map((row) => {
15456
+ const camel = keysToCamelCase(row);
15457
+ return absolutizeMediaUrls(camel);
15458
+ });
15381
15459
  } catch (error) {
15382
15460
  console.error("Failed to fetch media by IDs:", error);
15383
15461
  return [];
@@ -18434,8 +18512,8 @@ var MediaService2 = class {
18434
18512
  width: data.width,
18435
18513
  height: data.height,
18436
18514
  duration: data.duration,
18437
- url: data.url,
18438
- thumbnailUrl: data.thumbnailUrl,
18515
+ url: toAbsoluteMediaUrl(data.url),
18516
+ thumbnailUrl: toAbsoluteMediaUrl(data.thumbnailUrl),
18439
18517
  altText: data.altText,
18440
18518
  caption: data.caption,
18441
18519
  tags: data.tags,
@@ -20205,7 +20283,7 @@ var COLLECTIONS_METHODS = {
20205
20283
  );
20206
20284
  }
20207
20285
  try {
20208
- const { bumpSchemaVersion } = await import("./routeHandler-ROBRMRZA.mjs");
20286
+ const { bumpSchemaVersion } = await import("./routeHandler-P2KXM7MH.mjs");
20209
20287
  bumpSchemaVersion();
20210
20288
  } catch {
20211
20289
  }
@@ -21291,7 +21369,7 @@ var SINGLES_METHODS = {
21291
21369
  if (tableExists) {
21292
21370
  migrationStatus = "applied";
21293
21371
  try {
21294
- const { generateRuntimeSchema: generateRuntimeSchema2 } = await import("./runtime-schema-generator-MOPQWGJP.mjs");
21372
+ const { generateRuntimeSchema: generateRuntimeSchema2 } = await import("./runtime-schema-generator-NQOLDUDG.mjs");
21295
21373
  const dialect = adapter.getCapabilities().dialect;
21296
21374
  const { table: runtimeTable } = generateRuntimeSchema2(
21297
21375
  tableName,
@@ -21569,7 +21647,7 @@ var SINGLES_METHODS = {
21569
21647
  if (tableExistsAfter) {
21570
21648
  migrationStatus = "applied";
21571
21649
  try {
21572
- const { generateRuntimeSchema: generateRuntimeSchema2 } = await import("./runtime-schema-generator-MOPQWGJP.mjs");
21650
+ const { generateRuntimeSchema: generateRuntimeSchema2 } = await import("./runtime-schema-generator-NQOLDUDG.mjs");
21573
21651
  const dialect = adapter.getCapabilities().dialect;
21574
21652
  const { table: runtimeTable } = generateRuntimeSchema2(
21575
21653
  tableName,
@@ -25436,6 +25514,10 @@ export {
25436
25514
  transformRichTextFields,
25437
25515
  resolveStatusFilter,
25438
25516
  CollectionEntryService,
25517
+ getBaseUrl,
25518
+ getMediaVariant,
25519
+ getSmallestMediaVariant,
25520
+ toAbsoluteMediaUrl,
25439
25521
  CollectionRelationshipService,
25440
25522
  clampLimit2,
25441
25523
  parseWhereQuery,
@@ -57,7 +57,7 @@ async function createAdapter(options = {}) {
57
57
  );
58
58
  }
59
59
  logger?.debug(`Creating ${dialect} adapter...`);
60
- const { createAdapterFromEnv } = await import("./factory-IWMBKUJM.mjs");
60
+ const { createAdapterFromEnv } = await import("./factory-UGJGOZZ7.mjs");
61
61
  const originalDialect = process.env.DB_DIALECT;
62
62
  const originalUrl = process.env.DATABASE_URL;
63
63
  try {
@@ -1,13 +1,16 @@
1
1
  import {
2
2
  PromptCancelledError,
3
3
  TTYRequiredError
4
- } from "./chunk-66ZNVKTF.mjs";
4
+ } from "./chunk-HSIAXEYF.mjs";
5
5
 
6
6
  // src/domains/schema/pipeline/prompt-dispatcher/clack-terminal.ts
7
7
  import * as clack from "@clack/prompts";
8
8
  function hasTTY() {
9
9
  return Boolean(process.stdin.isTTY && process.stdout.isTTY);
10
10
  }
11
+ function shouldAutoConfirmDrops() {
12
+ return process.env.NEXTLY_ALLOW_CODE_FIRST_DROPS === "1";
13
+ }
11
14
  var ClackTerminalPromptDispatcher = class {
12
15
  async dispatch(args) {
13
16
  const { candidates, events } = args;
@@ -16,9 +19,18 @@ var ClackTerminalPromptDispatcher = class {
16
19
  }
17
20
  if (!hasTTY()) {
18
21
  const renameSample = candidates.slice(0, 3).map((c) => `${c.fromColumn} -> ${c.toColumn} on ${c.tableName}`).join(", ");
19
- const eventSample = events.slice(0, 3).map(
20
- (e) => e.kind === "type_change" ? `type change on ${e.tableName}.${e.columnName} (${e.fromType} -> ${e.toType})` : `${e.kind === "add_not_null_with_nulls" ? "NOT NULL on" : "required field"} ${e.tableName}.${e.columnName}`
21
- ).join(", ");
22
+ const eventSample = events.slice(0, 3).map((e) => {
23
+ switch (e.kind) {
24
+ case "type_change":
25
+ return `type change on ${e.tableName}.${e.columnName} (${e.fromType} -> ${e.toType})`;
26
+ case "add_not_null_with_nulls":
27
+ return `NOT NULL on ${e.tableName}.${e.columnName}`;
28
+ case "add_required_field_no_default":
29
+ return `required field ${e.tableName}.${e.columnName}`;
30
+ case "destructive_drop":
31
+ return `drop column ${e.tableName}.${e.columnName} (${e.columnType}, ${e.tableRowCount} row(s))`;
32
+ }
33
+ }).join(", ");
22
34
  const parts = [];
23
35
  if (candidates.length > 0) {
24
36
  parts.push(`${candidates.length} rename candidate(s): ${renameSample}`);
@@ -54,8 +66,40 @@ ${parts.join("\n")}`
54
66
  return { resolutions: [], proceed: true };
55
67
  }
56
68
  const resolutions = [];
69
+ const autoConfirmDrops = shouldAutoConfirmDrops();
70
+ const allDestructiveDrops = events.every(
71
+ (e) => e.kind === "destructive_drop"
72
+ );
73
+ if (autoConfirmDrops && allDestructiveDrops) {
74
+ for (const event of events) {
75
+ if (event.kind !== "destructive_drop") continue;
76
+ resolutions.push({ kind: "confirm_drop", eventId: event.id });
77
+ }
78
+ return { resolutions, proceed: true };
79
+ }
57
80
  clack.intro("Schema change requires confirmation");
58
81
  for (const event of events) {
82
+ if (event.kind === "destructive_drop") {
83
+ clack.note(
84
+ `Type: ${event.columnType}
85
+ Rows affected: ${event.tableRowCount}`,
86
+ `Drop column "${event.tableName}.${event.columnName}"`
87
+ );
88
+ if (autoConfirmDrops) {
89
+ resolutions.push({ kind: "confirm_drop", eventId: event.id });
90
+ continue;
91
+ }
92
+ const proceed = await clack.confirm({
93
+ message: `Drop "${event.columnName}" from "${event.tableName}"?`,
94
+ initialValue: false
95
+ });
96
+ if (clack.isCancel(proceed) || proceed === false) {
97
+ clack.outro("Cancelled");
98
+ return { resolutions, proceed: false };
99
+ }
100
+ resolutions.push({ kind: "confirm_drop", eventId: event.id });
101
+ continue;
102
+ }
59
103
  if (event.kind === "type_change") {
60
104
  clack.note(
61
105
  [
@@ -82,6 +126,11 @@ ${event.nullCount} of ${event.tableRowCount} rows have NULL values.` : `New requ
82
126
  provide_default: "Provide a default value for empty rows",
83
127
  make_optional: "Make the field optional (cancel the NOT NULL)",
84
128
  delete_nonconforming: event.kind === "add_not_null_with_nulls" ? `Delete the ${event.nullCount} rows with empty values` : "Delete rows that violate the constraint",
129
+ // Unreachable for NOT-NULL kinds (destructive_drop never lists
130
+ // these resolutions in applicableResolutions), but Record<K,V>
131
+ // requires every key. The label only surfaces if a future event
132
+ // erroneously includes confirm_drop in its applicableResolutions.
133
+ confirm_drop: "Confirm the drop",
85
134
  abort: "Cancel everything"
86
135
  };
87
136
  const options = event.applicableResolutions.map((kind2) => ({
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ClackTerminalPromptDispatcher
3
- } from "./chunk-FQH647CT.mjs";
3
+ } from "./chunk-NJ3LXLSJ.mjs";
4
4
  import {
5
5
  extractDatabaseNameFromUrl
6
6
  } from "./chunk-KIMNCZGV.mjs";
@@ -8,21 +8,23 @@ import {
8
8
  DrizzleStatementExecutor,
9
9
  PushSchemaPipeline,
10
10
  RealPreCleanupExecutor,
11
+ clearLiveSnapshots,
11
12
  createApplyDesiredSchema,
12
13
  getProductionNotifier,
13
14
  noopMigrationJournal,
14
- noopPreRenameExecutor
15
- } from "./chunk-66ZNVKTF.mjs";
15
+ noopPreRenameExecutor,
16
+ setLiveSnapshot
17
+ } from "./chunk-HSIAXEYF.mjs";
16
18
  import {
17
19
  RealClassifier,
18
20
  RegexRenameDetector,
19
21
  buildDesiredTableFromFields,
20
22
  diffSnapshots,
21
23
  introspectLiveSnapshot
22
- } from "./chunk-J4KHGYOM.mjs";
24
+ } from "./chunk-JCQMC6HH.mjs";
23
25
  import {
24
26
  generateRuntimeSchema
25
- } from "./chunk-UB4CALU5.mjs";
27
+ } from "./chunk-2QSGNGOB.mjs";
26
28
 
27
29
  // src/domains/schema/utils/resolve-table-name.ts
28
30
  function resolveCollectionTableName(slug, dbName) {
@@ -33,7 +35,7 @@ function resolveCollectionTableName(slug, dbName) {
33
35
 
34
36
  // src/init/reload-config.ts
35
37
  async function defaultResolver(name) {
36
- const { getService } = await import("./register-G6I4N6QM.mjs");
38
+ const { getService } = await import("./register-O2CJDFCK.mjs");
37
39
  return getService(name);
38
40
  }
39
41
  async function reloadNextlyConfig(opts) {
@@ -41,7 +43,7 @@ async function reloadNextlyConfig(opts) {
41
43
  const resolve = (name) => resolverArg ? resolverArg(name) : defaultResolver(name);
42
44
  let newConfig;
43
45
  try {
44
- const { loadConfig, clearConfigCache } = await import("./config-loader-23YEMC3Z.mjs");
46
+ const { loadConfig, clearConfigCache } = await import("./config-loader-MUFY6UMU.mjs");
45
47
  clearConfigCache();
46
48
  const result = await loadConfig();
47
49
  newConfig = result.config;
@@ -99,18 +101,17 @@ async function reloadNextlyConfig(opts) {
99
101
  fields: c.fields ?? []
100
102
  });
101
103
  }
102
- if (targets.length === 0 && singleTargets.length === 0 && componentTargets.length === 0) return;
104
+ if (targets.length === 0 && singleTargets.length === 0 && componentTargets.length === 0)
105
+ return;
106
+ const managedTableNames = [
107
+ ...targets.map((t) => t.tableName),
108
+ ...singleTargets.map((t) => t.tableName),
109
+ ...componentTargets.map((t) => t.tableName)
110
+ ];
111
+ clearLiveSnapshots();
103
112
  let liveSnapshot;
104
113
  try {
105
- liveSnapshot = await introspectLiveSnapshot(
106
- db,
107
- dialect,
108
- [
109
- ...targets.map((t) => t.tableName),
110
- ...singleTargets.map((t) => t.tableName),
111
- ...componentTargets.map((t) => t.tableName)
112
- ]
113
- );
114
+ liveSnapshot = await introspectLiveSnapshot(db, dialect, managedTableNames);
114
115
  } catch (err) {
115
116
  const msg = err instanceof Error ? err.message : String(err);
116
117
  logger?.error(
@@ -118,6 +119,7 @@ async function reloadNextlyConfig(opts) {
118
119
  );
119
120
  return;
120
121
  }
122
+ setLiveSnapshot(managedTableNames, liveSnapshot);
121
123
  const liveByTable = /* @__PURE__ */ new Map();
122
124
  for (const t of liveSnapshot.tables) liveByTable.set(t.name, t);
123
125
  let hasChanges = false;
@@ -383,7 +385,9 @@ async function reloadNextlyConfig(opts) {
383
385
  } catch {
384
386
  }
385
387
  try {
386
- const schemaReg = await resolve("schemaRegistry");
388
+ const schemaReg = await resolve(
389
+ "schemaRegistry"
390
+ );
387
391
  for (const [tableName, table] of collectionFreshTables) {
388
392
  schemaReg.registerDynamicSchema(tableName, table);
389
393
  }
@@ -413,10 +417,7 @@ async function reloadNextlyConfig(opts) {
413
417
  if (!applyResult.success) {
414
418
  const code = applyResult.error.code;
415
419
  if (code === "CONFIRMATION_REQUIRED_NO_TTY") {
416
- const detail = applyResult.error.message.replace(/^TTY required for schema confirmation\.\s*/i, "").replace(
417
- /\s*Run from an interactive terminal,.*$/i,
418
- ""
419
- ).trim();
420
+ const detail = applyResult.error.message.replace(/^TTY required for schema confirmation\.\s*/i, "").replace(/\s*Run from an interactive terminal,.*$/i, "").trim();
420
421
  console.warn(
421
422
  `
422
423
  [Nextly] Schema change needs your confirmation:
@@ -442,28 +443,7 @@ explicit confirmation.
442
443
  }
443
444
  function classifyForCodeFirst(operations, _dialect) {
444
445
  if (operations.length === 0) return { safe: true };
445
- const dropsPerTable = /* @__PURE__ */ new Map();
446
- const addsPerTable = /* @__PURE__ */ new Map();
447
- for (const op of operations) {
448
- if (op.type === "drop_column") {
449
- dropsPerTable.set(
450
- op.tableName,
451
- (dropsPerTable.get(op.tableName) ?? 0) + 1
452
- );
453
- } else if (op.type === "add_column") {
454
- addsPerTable.set(op.tableName, (addsPerTable.get(op.tableName) ?? 0) + 1);
455
- }
456
- }
457
446
  const reasons = [];
458
- for (const [t, drops] of dropsPerTable) {
459
- const adds = addsPerTable.get(t) ?? 0;
460
- if (drops > adds) {
461
- const surplus = drops - adds;
462
- reasons.push(
463
- adds === 0 ? `drops ${drops} column(s) from '${t}' with no replacement(s); ${surplus} cannot be renamed without data loss` : `drops ${drops} columns from '${t}' but only ${adds} replacement(s); at least ${surplus} cannot be renamed without data loss`
464
- );
465
- }
466
- }
467
447
  for (const op of operations) {
468
448
  if (op.type === "drop_table") {
469
449
  reasons.push(`drops table '${op.tableName}'`);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BaseService
3
- } from "./chunk-2W3DVD7S.mjs";
3
+ } from "./chunk-PFRMIEJ3.mjs";
4
4
 
5
5
  // src/services/system/system-table-service.ts
6
6
  var POSTGRES_SQL = {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDialectTables
3
- } from "./chunk-TS7GHTG2.mjs";
3
+ } from "./chunk-YXZH65YV.mjs";
4
4
  import {
5
5
  container
6
6
  } from "./chunk-D5HQBNUB.mjs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  NextlyError
3
- } from "./chunk-NRUWQ5Z7.mjs";
3
+ } from "./chunk-5WWWJCKI.mjs";
4
4
 
5
5
  // src/api/auth-header-only.ts
6
6
  function requireAuthHeader(request) {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  BaseService
3
- } from "./chunk-2W3DVD7S.mjs";
3
+ } from "./chunk-PFRMIEJ3.mjs";
4
4
  import {
5
5
  getDialectTables
6
- } from "./chunk-TS7GHTG2.mjs";
6
+ } from "./chunk-YXZH65YV.mjs";
7
7
  import {
8
8
  getAuthLogger
9
9
  } from "./chunk-LAZXX4HR.mjs";
@@ -5,11 +5,11 @@ import {
5
5
  PermissionService,
6
6
  RolePermissionService,
7
7
  SYSTEM_RESOURCES
8
- } from "./chunk-ZVN3JILF.mjs";
8
+ } from "./chunk-KPCSDPFQ.mjs";
9
9
  import {
10
10
  BaseRegistryService,
11
11
  assertGlobalResourceSlugAvailable
12
- } from "./chunk-D72XH3BG.mjs";
12
+ } from "./chunk-ERJGWWPB.mjs";
13
13
  import {
14
14
  resolveSingleTableName
15
15
  } from "./chunk-I4JMR3UR.mjs";
@@ -19,11 +19,11 @@ import {
19
19
  } from "./chunk-5HMZ644B.mjs";
20
20
  import {
21
21
  BaseService
22
- } from "./chunk-2W3DVD7S.mjs";
22
+ } from "./chunk-PFRMIEJ3.mjs";
23
23
  import {
24
24
  NextlyError,
25
25
  toDbError
26
- } from "./chunk-NRUWQ5Z7.mjs";
26
+ } from "./chunk-5WWWJCKI.mjs";
27
27
 
28
28
  // src/domains/auth/services/permission-seed-service.ts
29
29
  import { eq } from "drizzle-orm";
@@ -7,7 +7,7 @@ import {
7
7
  countRows,
8
8
  diffSnapshots,
9
9
  introspectLiveSnapshot
10
- } from "./chunk-J4KHGYOM.mjs";
10
+ } from "./chunk-JCQMC6HH.mjs";
11
11
 
12
12
  // src/domains/schema/pipeline/preview.ts
13
13
  async function previewDesiredSchema(args, deps = {}) {
@@ -7,16 +7,16 @@ import {
7
7
  import {
8
8
  hasAnyPermission,
9
9
  hasPermission
10
- } from "./chunk-NAP3TDS6.mjs";
10
+ } from "./chunk-SWVNFKWD.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";
17
17
  import {
18
18
  NextlyError
19
- } from "./chunk-NRUWQ5Z7.mjs";
19
+ } from "./chunk-5WWWJCKI.mjs";
20
20
 
21
21
  // src/auth/middleware/index.ts
22
22
  var DEFAULT_RATE_LIMIT = 1e3;
@@ -2,16 +2,16 @@ import {
2
2
  isErrorResponse,
3
3
  requireAuthentication,
4
4
  toNextlyAuthError
5
- } from "./chunk-7YKKCBOC.mjs";
5
+ } from "./chunk-V2W7G5GC.mjs";
6
6
  import {
7
7
  nextlyValidationFromZod
8
- } from "./chunk-GJNSJU4S.mjs";
8
+ } from "./chunk-Z52OQOZH.mjs";
9
9
  import {
10
10
  withErrorHandler
11
- } from "./chunk-TO5AFLVQ.mjs";
11
+ } from "./chunk-XIKEJO27.mjs";
12
12
  import {
13
13
  getCachedNextly
14
- } from "./chunk-RKXTA5KC.mjs";
14
+ } from "./chunk-HLTSQIP6.mjs";
15
15
  import {
16
16
  respondAction
17
17
  } from "./chunk-IUDOC7N7.mjs";
@@ -20,7 +20,7 @@ import {
20
20
  } from "./chunk-D5HQBNUB.mjs";
21
21
  import {
22
22
  NextlyError
23
- } from "./chunk-NRUWQ5Z7.mjs";
23
+ } from "./chunk-5WWWJCKI.mjs";
24
24
 
25
25
  // src/api/email-send-template.ts
26
26
  import { z } from "zod";
@@ -35,14 +35,14 @@ import {
35
35
  PasswordSchema,
36
36
  validatePasswordStrength,
37
37
  verifyPassword
38
- } from "./chunk-NAP3TDS6.mjs";
38
+ } from "./chunk-SWVNFKWD.mjs";
39
39
  import {
40
40
  respondAction,
41
41
  respondData
42
42
  } from "./chunk-IUDOC7N7.mjs";
43
43
  import {
44
44
  NextlyError
45
- } from "./chunk-NRUWQ5Z7.mjs";
45
+ } from "./chunk-5WWWJCKI.mjs";
46
46
 
47
47
  // src/auth/cookies/refresh-token-cookie.ts
48
48
  function setRefreshTokenCookie(token, ttlSeconds, isProduction) {
@@ -373,11 +373,15 @@ async function verifyCredentials(input, deps) {
373
373
  }
374
374
  if (deps.requireEmailVerification && !user.emailVerified) {
375
375
  throw NextlyError.invalidCredentials({
376
+ code: "AUTH_UNVERIFIED",
377
+ publicMessage: "Invalid email or password.",
376
378
  logContext: { userId: user.id, reason: "unverified" }
377
379
  });
378
380
  }
379
381
  if (!user.isActive) {
380
382
  throw NextlyError.invalidCredentials({
383
+ code: "AUTH_INACTIVE",
384
+ publicMessage: "Invalid email or password.",
381
385
  logContext: { userId: user.id, reason: "inactive" }
382
386
  });
383
387
  }
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  NextlyError,
12
12
  isDbError
13
- } from "./chunk-NRUWQ5Z7.mjs";
13
+ } from "./chunk-5WWWJCKI.mjs";
14
14
 
15
15
  // src/api/with-error-handler.ts
16
16
  import { createRequire } from "module";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-GDBJ5JCU.mjs";
4
4
  import {
5
5
  NextlyError
6
- } from "./chunk-NRUWQ5Z7.mjs";
6
+ } from "./chunk-5WWWJCKI.mjs";
7
7
 
8
8
  // src/cli/utils/config-loader.ts
9
9
  import { existsSync, watch } from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  NextlyError
3
- } from "./chunk-NRUWQ5Z7.mjs";
3
+ } from "./chunk-5WWWJCKI.mjs";
4
4
 
5
5
  // src/api/read-json-body.ts
6
6
  async function readJsonBody(req, extraLogContext) {