nextly 0.0.1 → 0.0.2-alpha.0

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 (268) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +122 -0
  3. package/dist/_dts-chunks/collections-handler.d-DjgO74Wt.d.ts +20540 -0
  4. package/dist/_dts-chunks/config.d-DNwsDnjs.d.ts +2589 -0
  5. package/dist/_dts-chunks/define-component.d-BUgTHmt3.d.ts +1149 -0
  6. package/dist/_dts-chunks/image-processor.d-OO1PmMrv.d.ts +335 -0
  7. package/dist/_dts-chunks/index.d-axCAzZ7m.d.ts +17842 -0
  8. package/dist/_dts-chunks/media.d-DjDOZo4B.d.ts +117 -0
  9. package/dist/_dts-chunks/on-error.d-CHIKWNxd.d.ts +38 -0
  10. package/dist/_dts-chunks/storage.d-BUhQ2we_.d.ts +404 -0
  11. package/dist/actions/index.d.ts +239 -0
  12. package/dist/actions/index.mjs +281 -0
  13. package/dist/api/auth-state.d.ts +5 -0
  14. package/dist/api/auth-state.mjs +131 -0
  15. package/dist/api/collections-schema-detail.d.ts +56 -0
  16. package/dist/api/collections-schema-detail.mjs +244 -0
  17. package/dist/api/collections-schema-export.d.ts +56 -0
  18. package/dist/api/collections-schema-export.mjs +129 -0
  19. package/dist/api/collections-schema.d.ts +59 -0
  20. package/dist/api/collections-schema.mjs +207 -0
  21. package/dist/api/components-detail.d.ts +50 -0
  22. package/dist/api/components-detail.mjs +132 -0
  23. package/dist/api/components.d.ts +69 -0
  24. package/dist/api/components.mjs +144 -0
  25. package/dist/api/email-providers-default.d.ts +40 -0
  26. package/dist/api/email-providers-default.mjs +75 -0
  27. package/dist/api/email-providers-detail.d.ts +81 -0
  28. package/dist/api/email-providers-detail.mjs +109 -0
  29. package/dist/api/email-providers-test.d.ts +43 -0
  30. package/dist/api/email-providers-test.mjs +114 -0
  31. package/dist/api/email-providers.d.ts +69 -0
  32. package/dist/api/email-providers.mjs +110 -0
  33. package/dist/api/email-send-template.d.ts +41 -0
  34. package/dist/api/email-send-template.mjs +58 -0
  35. package/dist/api/email-send.d.ts +42 -0
  36. package/dist/api/email-send.mjs +58 -0
  37. package/dist/api/email-templates-detail.d.ts +74 -0
  38. package/dist/api/email-templates-detail.mjs +112 -0
  39. package/dist/api/email-templates-layout.d.ts +55 -0
  40. package/dist/api/email-templates-layout.mjs +92 -0
  41. package/dist/api/email-templates-preview.d.ts +48 -0
  42. package/dist/api/email-templates-preview.mjs +93 -0
  43. package/dist/api/email-templates.d.ts +61 -0
  44. package/dist/api/email-templates.mjs +118 -0
  45. package/dist/api/health.d.ts +68 -0
  46. package/dist/api/health.mjs +67 -0
  47. package/dist/api/index.d.ts +54 -0
  48. package/dist/api/index.mjs +16 -0
  49. package/dist/api/media-bulk.d.ts +74 -0
  50. package/dist/api/media-bulk.mjs +196 -0
  51. package/dist/api/media-folders.d.ts +112 -0
  52. package/dist/api/media-folders.mjs +187 -0
  53. package/dist/api/media-handlers.d.ts +102 -0
  54. package/dist/api/media-handlers.mjs +437 -0
  55. package/dist/api/media.d.ts +117 -0
  56. package/dist/api/media.mjs +242 -0
  57. package/dist/api/singles-detail.d.ts +87 -0
  58. package/dist/api/singles-detail.mjs +170 -0
  59. package/dist/api/singles-schema-detail.d.ts +54 -0
  60. package/dist/api/singles-schema-detail.mjs +182 -0
  61. package/dist/api/singles.d.ts +34 -0
  62. package/dist/api/singles.mjs +94 -0
  63. package/dist/api/storage-upload-url.d.ts +48 -0
  64. package/dist/api/storage-upload-url.mjs +202 -0
  65. package/dist/api/uploads.d.ts +109 -0
  66. package/dist/api/uploads.mjs +359 -0
  67. package/dist/auth/index.d.ts +425 -0
  68. package/dist/auth/index.mjs +199 -0
  69. package/dist/boot-apply-PQSYLDIN.mjs +7 -0
  70. package/dist/chunk-2OALJTK6.mjs +489 -0
  71. package/dist/chunk-2Q2SX2CS.mjs +365 -0
  72. package/dist/chunk-2TFX4ND3.mjs +13 -0
  73. package/dist/chunk-2TWPDSYD.mjs +87 -0
  74. package/dist/chunk-2W3DVD7S.mjs +647 -0
  75. package/dist/chunk-2ZFKXPQM.mjs +88 -0
  76. package/dist/chunk-3FA7FKAV.mjs +832 -0
  77. package/dist/chunk-3NZ2KMBL.mjs +58 -0
  78. package/dist/chunk-4MJLT6PZ.mjs +0 -0
  79. package/dist/chunk-56WO4WX7.mjs +0 -0
  80. package/dist/chunk-5APFUGAD.mjs +89 -0
  81. package/dist/chunk-5HMZ644B.mjs +108 -0
  82. package/dist/chunk-67GXH6PR.mjs +32 -0
  83. package/dist/chunk-6JNEPWRW.mjs +14368 -0
  84. package/dist/chunk-6NFHQIJD.mjs +45 -0
  85. package/dist/chunk-7P6ASYW6.mjs +9 -0
  86. package/dist/chunk-A3WPLSDT.mjs +1364 -0
  87. package/dist/chunk-AGJ6F2T3.mjs +144 -0
  88. package/dist/chunk-AK6Z23OX.mjs +1464 -0
  89. package/dist/chunk-APKKRD2G.mjs +102 -0
  90. package/dist/chunk-B2GV2BWH.mjs +73 -0
  91. package/dist/chunk-D5HQBNUB.mjs +74 -0
  92. package/dist/chunk-DNNG377Z.mjs +204 -0
  93. package/dist/chunk-DP3G27G5.mjs +135 -0
  94. package/dist/chunk-DV6WVX2Q.mjs +0 -0
  95. package/dist/chunk-DXGGXIUZ.mjs +57 -0
  96. package/dist/chunk-EGXBZCGC.mjs +943 -0
  97. package/dist/chunk-ERCNLX3V.mjs +176 -0
  98. package/dist/chunk-FQULBZ53.mjs +850 -0
  99. package/dist/chunk-G2AA4QLC.mjs +262 -0
  100. package/dist/chunk-GDBJ5JCU.mjs +488 -0
  101. package/dist/chunk-GJNSJU4S.mjs +19 -0
  102. package/dist/chunk-GZ6DCQKC.mjs +69 -0
  103. package/dist/chunk-H26B4FYG.mjs +167 -0
  104. package/dist/chunk-I4JMR3UR.mjs +21 -0
  105. package/dist/chunk-INV7QKLG.mjs +508 -0
  106. package/dist/chunk-IUDOC7N7.mjs +46 -0
  107. package/dist/chunk-IZWPRDC3.mjs +206 -0
  108. package/dist/chunk-KIMNCZGV.mjs +15 -0
  109. package/dist/chunk-L6HW2DA7.mjs +15 -0
  110. package/dist/chunk-LAZXX4HR.mjs +100 -0
  111. package/dist/chunk-LDKCUMHK.mjs +95 -0
  112. package/dist/chunk-LRXMECUA.mjs +0 -0
  113. package/dist/chunk-M52VMPGA.mjs +119 -0
  114. package/dist/chunk-MGUWEEI6.mjs +160 -0
  115. package/dist/chunk-NRUWQ5Z7.mjs +419 -0
  116. package/dist/chunk-NSEFNNU4.mjs +25360 -0
  117. package/dist/chunk-NTHVDFGO.mjs +138 -0
  118. package/dist/chunk-O3QHXMOX.mjs +3166 -0
  119. package/dist/chunk-P7NH2OSC.mjs +2605 -0
  120. package/dist/chunk-PKMABBB5.mjs +184 -0
  121. package/dist/chunk-PWS6XGJK.mjs +76 -0
  122. package/dist/chunk-R6JJQHFC.mjs +20 -0
  123. package/dist/chunk-RJLLGGPG.mjs +0 -0
  124. package/dist/chunk-SBACDPNX.mjs +689 -0
  125. package/dist/chunk-TO5AFLVQ.mjs +124 -0
  126. package/dist/chunk-TS7GHTG2.mjs +5436 -0
  127. package/dist/chunk-UJ2IMJ4W.mjs +133 -0
  128. package/dist/chunk-UOP63Q54.mjs +102 -0
  129. package/dist/chunk-UUOFWCM6.mjs +78 -0
  130. package/dist/chunk-V4EQTOA4.mjs +893 -0
  131. package/dist/chunk-VJ66NCL4.mjs +193 -0
  132. package/dist/chunk-VQJQHVEV.mjs +29 -0
  133. package/dist/chunk-VTJADRO3.mjs +141 -0
  134. package/dist/chunk-VWF3JO32.mjs +0 -0
  135. package/dist/chunk-W4MGXIRR.mjs +27 -0
  136. package/dist/chunk-W5KKPZT5.mjs +1204 -0
  137. package/dist/chunk-WD34YQ6T.mjs +381 -0
  138. package/dist/chunk-WZBYMYVW.mjs +14 -0
  139. package/dist/chunk-X23WKS3Z.mjs +50 -0
  140. package/dist/chunk-X7TXCYYN.mjs +6496 -0
  141. package/dist/chunk-XGI4EMS3.mjs +140 -0
  142. package/dist/chunk-XZKLBMN6.mjs +1153 -0
  143. package/dist/chunk-YB7INWPY.mjs +0 -0
  144. package/dist/chunk-YV4Y7SDL.mjs +83 -0
  145. package/dist/chunk-YZNBLFIW.mjs +1688 -0
  146. package/dist/chunk-YZZCTONM.mjs +263 -0
  147. package/dist/chunk-ZE6A3FYH.mjs +289 -0
  148. package/dist/cli/nextly.mjs +68 -0
  149. package/dist/cli/utils/index.d.ts +449 -0
  150. package/dist/cli/utils/index.mjs +49 -0
  151. package/dist/component-schema-service-5577KVW6.mjs +11 -0
  152. package/dist/config-loader-23YEMC3Z.mjs +23 -0
  153. package/dist/config.d.ts +44 -0
  154. package/dist/config.mjs +109 -0
  155. package/dist/container-ORGFGYSZ.mjs +9 -0
  156. package/dist/database/index.d.ts +12 -0
  157. package/dist/database/index.mjs +40 -0
  158. package/dist/database/seeders/index.d.ts +93 -0
  159. package/dist/database/seeders/index.mjs +47 -0
  160. package/dist/db-sync-demote-LJGKLB3S.mjs +117 -0
  161. package/dist/db-sync-promote-B26VSYQF.mjs +113 -0
  162. package/dist/dev-reload-broadcaster-B73IQ53V.mjs +25 -0
  163. package/dist/dist-M2NOU37V.mjs +19 -0
  164. package/dist/drizzle-kit-lazy-D2M2PXR2.mjs +13 -0
  165. package/dist/dynamic-collection-schema-service-IEXTPIZ7.mjs +8 -0
  166. package/dist/errors/index.d.ts +159 -0
  167. package/dist/errors/index.mjs +10 -0
  168. package/dist/factory-IWMBKUJM.mjs +15 -0
  169. package/dist/first-run-QIVKWJIF.mjs +63 -0
  170. package/dist/fresh-push-NR67DC3R.mjs +8 -0
  171. package/dist/index.d.ts +4175 -0
  172. package/dist/index.mjs +1336 -0
  173. package/dist/local-plugin-PTET4NAT.mjs +7 -0
  174. package/dist/logger-NU46DXNY.mjs +15 -0
  175. package/dist/logger-YE4TC7ZN.mjs +9 -0
  176. package/dist/migration-journal-EP532Y4L.mjs +139 -0
  177. package/dist/migrations/mysql/0000_eager_sentry.sql +174 -0
  178. package/dist/migrations/mysql/0001_soft_giant_girl.sql +27 -0
  179. package/dist/migrations/mysql/0002_media_table.sql +24 -0
  180. package/dist/migrations/mysql/0003_dynamic_singles.sql +37 -0
  181. package/dist/migrations/mysql/0004_dynamic_components.sql +35 -0
  182. package/dist/migrations/mysql/0005_user_management_tables.sql +92 -0
  183. package/dist/migrations/mysql/0006_api_keys.sql +36 -0
  184. package/dist/migrations/mysql/0007_general_settings.sql +20 -0
  185. package/dist/migrations/mysql/0008_site_settings_logo_url.sql +9 -0
  186. package/dist/migrations/mysql/0009_activity_log.sql +30 -0
  187. package/dist/migrations/mysql/0010_site_settings_sidebar.sql +13 -0
  188. package/dist/migrations/mysql/0011_missing_tables_and_columns.sql +54 -0
  189. package/dist/migrations/mysql/0012_image_sizes_and_focal_point.sql +30 -0
  190. package/dist/migrations/mysql/0012_media_folders.sql +43 -0
  191. package/dist/migrations/mysql/0013_user_brute_force_protection.sql +31 -0
  192. package/dist/migrations/mysql/0014_email_template_attachments.sql +12 -0
  193. package/dist/migrations/mysql/0015_media_uploaded_by_nullable.sql +15 -0
  194. package/dist/migrations/mysql/20260429_000000_000_initial_journal.sql +22 -0
  195. package/dist/migrations/mysql/20260501_000000_journal_batch.sql +17 -0
  196. package/dist/migrations/mysql/20260501_000001_audit_log.sql +24 -0
  197. package/dist/migrations/mysql/20260504_000000_nextly_meta.sql +21 -0
  198. package/dist/migrations/mysql/meta/0000_snapshot.json +1005 -0
  199. package/dist/migrations/mysql/meta/0001_snapshot.json +1099 -0
  200. package/dist/migrations/mysql/meta/_journal.json +41 -0
  201. package/dist/migrations/postgresql/0000_misty_king_bedlam.sql +169 -0
  202. package/dist/migrations/postgresql/0001_perpetual_captain_marvel.sql +8 -0
  203. package/dist/migrations/postgresql/0002_sad_spectrum.sql +16 -0
  204. package/dist/migrations/postgresql/0003_hesitant_ultron.sql +17 -0
  205. package/dist/migrations/postgresql/0004_media_table.sql +24 -0
  206. package/dist/migrations/postgresql/0005_media_folders.sql +36 -0
  207. package/dist/migrations/postgresql/0006_dynamic_collections_update.sql +50 -0
  208. package/dist/migrations/postgresql/0007_dynamic_singles.sql +38 -0
  209. package/dist/migrations/postgresql/0008_dynamic_components.sql +37 -0
  210. package/dist/migrations/postgresql/0009_user_management_tables.sql +95 -0
  211. package/dist/migrations/postgresql/0010_api_keys.sql +34 -0
  212. package/dist/migrations/postgresql/0011_general_settings.sql +20 -0
  213. package/dist/migrations/postgresql/0012_site_settings_logo_url.sql +9 -0
  214. package/dist/migrations/postgresql/0013_activity_log.sql +29 -0
  215. package/dist/migrations/postgresql/0014_image_sizes_and_focal_point.sql +33 -0
  216. package/dist/migrations/postgresql/0014_site_settings_sidebar.sql +13 -0
  217. package/dist/migrations/postgresql/0015_user_brute_force_protection.sql +29 -0
  218. package/dist/migrations/postgresql/0016_email_template_attachments.sql +12 -0
  219. package/dist/migrations/postgresql/0017_media_uploaded_by_nullable.sql +15 -0
  220. package/dist/migrations/postgresql/20260429_000000_000_initial_journal.sql +24 -0
  221. package/dist/migrations/postgresql/20260501_000000_journal_batch.sql +17 -0
  222. package/dist/migrations/postgresql/20260501_000001_audit_log.sql +24 -0
  223. package/dist/migrations/postgresql/20260504_000000_nextly_meta.sql +22 -0
  224. package/dist/migrations/postgresql/meta/0000_snapshot.json +1286 -0
  225. package/dist/migrations/postgresql/meta/0001_snapshot.json +1407 -0
  226. package/dist/migrations/postgresql/meta/0002_snapshot.json +1552 -0
  227. package/dist/migrations/postgresql/meta/0003_snapshot.json +1695 -0
  228. package/dist/migrations/postgresql/meta/0010_snapshot.json +2345 -0
  229. package/dist/migrations/postgresql/meta/_journal.json +90 -0
  230. package/dist/migrations/sqlite/0000_api_keys.sql +34 -0
  231. package/dist/migrations/sqlite/0001_general_settings.sql +20 -0
  232. package/dist/migrations/sqlite/0002_site_settings_logo_url.sql +9 -0
  233. package/dist/migrations/sqlite/0003_activity_log.sql +29 -0
  234. package/dist/migrations/sqlite/0004_image_sizes_and_focal_point.sql +29 -0
  235. package/dist/migrations/sqlite/0004_site_settings_sidebar.sql +11 -0
  236. package/dist/migrations/sqlite/0005_user_brute_force_protection.sql +29 -0
  237. package/dist/migrations/sqlite/0006_email_template_attachments.sql +12 -0
  238. package/dist/migrations/sqlite/0007_media_uploaded_by_nullable.sql +111 -0
  239. package/dist/migrations/sqlite/20260429_000000_000_initial_journal.sql +24 -0
  240. package/dist/migrations/sqlite/20260501_000000_journal_batch.sql +19 -0
  241. package/dist/migrations/sqlite/20260501_000001_audit_log.sql +24 -0
  242. package/dist/migrations/sqlite/20260504_000000_nextly_meta.sql +21 -0
  243. package/dist/migrations/sqlite/20260505_000000_user_management_tables.sql +77 -0
  244. package/dist/next.d.ts +57 -0
  245. package/dist/next.mjs +55 -0
  246. package/dist/observability/index.d.ts +87 -0
  247. package/dist/observability/index.mjs +57 -0
  248. package/dist/permissions-3DZZQZMI.mjs +39 -0
  249. package/dist/pipeline-YOML7SWF.mjs +29 -0
  250. package/dist/preview-ZZTR3QGS.mjs +9 -0
  251. package/dist/program-PW6UB2ZC.mjs +5934 -0
  252. package/dist/reconcile-single-tables-7ENVXJGB.mjs +7 -0
  253. package/dist/register-SF6E6FVU.mjs +49 -0
  254. package/dist/reload-config-HWQ4G5MM.mjs +23 -0
  255. package/dist/resolve-single-table-name-JSOMUB3R.mjs +7 -0
  256. package/dist/routeHandler-UNMMJIBM.mjs +77 -0
  257. package/dist/runtime-schema-generator-NRA6A6Z6.mjs +8 -0
  258. package/dist/runtime.d.ts +120 -0
  259. package/dist/runtime.mjs +73 -0
  260. package/dist/schema-hash-FMMG6VPJ.mjs +13 -0
  261. package/dist/schema-registry-EQ36FZDP.mjs +7 -0
  262. package/dist/scripts/load-env.mjs +42 -0
  263. package/dist/storage/index.d.ts +566 -0
  264. package/dist/storage/index.mjs +45 -0
  265. package/dist/super-admin-G5ZK5F4T.mjs +39 -0
  266. package/dist/system-table-service-WGSRVEGT.mjs +17 -0
  267. package/dist/users-7KELGRYJ.mjs +38 -0
  268. package/package.json +308 -9
@@ -0,0 +1,193 @@
1
+ import {
2
+ PromptCancelledError,
3
+ TTYRequiredError
4
+ } from "./chunk-AK6Z23OX.mjs";
5
+
6
+ // src/domains/schema/pipeline/prompt-dispatcher/clack-terminal.ts
7
+ import * as clack from "@clack/prompts";
8
+ function hasTTY() {
9
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
10
+ }
11
+ var ClackTerminalPromptDispatcher = class {
12
+ async dispatch(args) {
13
+ const { candidates, events } = args;
14
+ if (candidates.length === 0 && events.length === 0) {
15
+ return { confirmedRenames: [], resolutions: [], proceed: true };
16
+ }
17
+ if (!hasTTY()) {
18
+ 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 parts = [];
23
+ if (candidates.length > 0) {
24
+ parts.push(`${candidates.length} rename candidate(s): ${renameSample}`);
25
+ }
26
+ if (events.length > 0) {
27
+ parts.push(`${events.length} resolution event(s): ${eventSample}`);
28
+ }
29
+ throw new TTYRequiredError(
30
+ // Multi-line so log readers can scan rename vs event sections
31
+ // separately without an arbitrary semicolon-join.
32
+ `Schema change needs confirmation.
33
+ ${parts.join("\n")}`
34
+ );
35
+ }
36
+ const renameResult = candidates.length > 0 ? await this.runShrinkingPoolPrompts(candidates) : {
37
+ confirmedRenames: [],
38
+ resolutions: [],
39
+ proceed: true
40
+ };
41
+ if (!renameResult.proceed) return renameResult;
42
+ const eventResult = await this.runEventPrompts(events);
43
+ return {
44
+ confirmedRenames: renameResult.confirmedRenames,
45
+ resolutions: eventResult.resolutions,
46
+ proceed: eventResult.proceed
47
+ };
48
+ }
49
+ // Walk classifier events in order. NOT-NULL kinds get a multi-step
50
+ // (select kind -> text value if provide_default -> next event); type_change
51
+ // gets a single warning + Y/N. Any abort or cancel returns proceed=false.
52
+ async runEventPrompts(events) {
53
+ if (events.length === 0) {
54
+ return { resolutions: [], proceed: true };
55
+ }
56
+ const resolutions = [];
57
+ clack.intro("Schema change requires confirmation");
58
+ for (const event of events) {
59
+ if (event.kind === "type_change") {
60
+ clack.note(
61
+ [
62
+ event.perDialectWarning.pg,
63
+ event.perDialectWarning.mysql,
64
+ event.perDialectWarning.sqlite
65
+ ].join("\n"),
66
+ `Type change on ${event.tableName}.${event.columnName}: ${event.fromType} -> ${event.toType}`
67
+ );
68
+ const proceed = await clack.confirm({
69
+ message: `Proceed with type change on ${event.tableName}.${event.columnName}?`,
70
+ initialValue: false
71
+ });
72
+ if (clack.isCancel(proceed) || proceed === false) {
73
+ clack.outro("Cancelled");
74
+ return { resolutions, proceed: false };
75
+ }
76
+ continue;
77
+ }
78
+ const headline = event.kind === "add_not_null_with_nulls" ? `Adding NOT NULL to "${event.tableName}.${event.columnName}"
79
+ ${event.nullCount} of ${event.tableRowCount} rows have NULL values.` : `New required field "${event.tableName}.${event.columnName}" on table with ${event.tableRowCount} existing rows.`;
80
+ clack.note(headline, "Resolution needed");
81
+ const labels = {
82
+ provide_default: "Provide a default value for empty rows",
83
+ make_optional: "Make the field optional (cancel the NOT NULL)",
84
+ delete_nonconforming: event.kind === "add_not_null_with_nulls" ? `Delete the ${event.nullCount} rows with empty values` : "Delete rows that violate the constraint",
85
+ abort: "Cancel everything"
86
+ };
87
+ const options = event.applicableResolutions.map((kind2) => ({
88
+ value: kind2,
89
+ label: labels[kind2]
90
+ }));
91
+ const choice = await clack.select({
92
+ message: "How do you want to handle this?",
93
+ options
94
+ });
95
+ if (clack.isCancel(choice)) {
96
+ clack.outro("Cancelled");
97
+ return { resolutions, proceed: false };
98
+ }
99
+ const kind = choice;
100
+ if (kind === "abort") {
101
+ clack.outro("Cancelled");
102
+ return { resolutions, proceed: false };
103
+ }
104
+ if (kind === "provide_default") {
105
+ const value = await clack.text({
106
+ message: `Default value for "${event.columnName}":`,
107
+ validate: (v) => !v || v.trim().length === 0 ? "Cannot be empty" : void 0
108
+ });
109
+ if (clack.isCancel(value)) {
110
+ clack.outro("Cancelled");
111
+ return { resolutions, proceed: false };
112
+ }
113
+ resolutions.push({
114
+ kind: "provide_default",
115
+ eventId: event.id,
116
+ value
117
+ });
118
+ } else {
119
+ resolutions.push({ kind, eventId: event.id });
120
+ }
121
+ }
122
+ clack.outro("Resolutions confirmed");
123
+ return { resolutions, proceed: true };
124
+ }
125
+ // Walks candidates in a shrinking-pool pattern:
126
+ // 1. Group candidates by `fromColumn` (the dropped column).
127
+ // 2. For each unique drop, ask the user to pick from its valid adds
128
+ // (filtered to those that haven't been consumed).
129
+ // 3. If user picks 'rename' with a specific add, mark both the drop
130
+ // and the add as consumed; future prompts skip them.
131
+ // 4. If user picks 'drop_and_add', drop survives as drop+add (no rename).
132
+ async runShrinkingPoolPrompts(candidates) {
133
+ const consumedDrops = /* @__PURE__ */ new Set();
134
+ const consumedAdds = /* @__PURE__ */ new Set();
135
+ const confirmed = [];
136
+ const dropToOptions = /* @__PURE__ */ new Map();
137
+ for (const c of candidates) {
138
+ const key = `${c.tableName}::${c.fromColumn}`;
139
+ const list = dropToOptions.get(key) ?? [];
140
+ list.push(c);
141
+ dropToOptions.set(key, list);
142
+ }
143
+ clack.intro("Schema rename detected");
144
+ for (const [dropKey, options] of dropToOptions) {
145
+ if (consumedDrops.has(dropKey)) continue;
146
+ const remaining = options.filter((c) => {
147
+ const addKey = `${c.tableName}::${c.toColumn}`;
148
+ return !consumedAdds.has(addKey);
149
+ });
150
+ if (remaining.length === 0) continue;
151
+ const first = remaining[0];
152
+ const selectOptions = remaining.map((c) => ({
153
+ value: `rename:${c.toColumn}`,
154
+ label: `Rename ${c.fromColumn} -> ${c.toColumn}`,
155
+ hint: c.typesCompatible ? `${c.fromType} -> ${c.toType} (data preserved)` : `${c.fromType} -> ${c.toType} (incompatible types; not recommended)`
156
+ }));
157
+ selectOptions.push({
158
+ value: "drop_and_add",
159
+ label: `Drop ${first.fromColumn} and add new column(s) (data lost)`
160
+ });
161
+ const compatible = remaining.find((c) => c.typesCompatible);
162
+ const initialValue = compatible !== void 0 ? `rename:${compatible.toColumn}` : "drop_and_add";
163
+ const choice = await clack.select({
164
+ message: `Column "${first.fromColumn}" was removed in ${first.tableName}. What should happen?`,
165
+ options: selectOptions,
166
+ initialValue
167
+ });
168
+ if (clack.isCancel(choice)) {
169
+ clack.outro("Cancelled");
170
+ throw new PromptCancelledError();
171
+ }
172
+ if (typeof choice === "string" && choice.startsWith("rename:")) {
173
+ const targetColumn = choice.slice("rename:".length);
174
+ const picked = remaining.find((c) => c.toColumn === targetColumn);
175
+ if (picked) {
176
+ confirmed.push(picked);
177
+ consumedDrops.add(dropKey);
178
+ consumedAdds.add(`${picked.tableName}::${picked.toColumn}`);
179
+ }
180
+ }
181
+ }
182
+ clack.outro("Schema renames confirmed");
183
+ return {
184
+ confirmedRenames: confirmed,
185
+ resolutions: [],
186
+ proceed: true
187
+ };
188
+ }
189
+ };
190
+
191
+ export {
192
+ ClackTerminalPromptDispatcher
193
+ };
@@ -0,0 +1,29 @@
1
+ import {
2
+ NextlyError
3
+ } from "./chunk-NRUWQ5Z7.mjs";
4
+
5
+ // src/api/read-json-body.ts
6
+ async function readJsonBody(req, extraLogContext) {
7
+ try {
8
+ return await req.json();
9
+ } catch {
10
+ throw new NextlyError({
11
+ code: "VALIDATION_ERROR",
12
+ publicMessage: "Validation failed.",
13
+ publicData: {
14
+ errors: [
15
+ {
16
+ path: "",
17
+ code: "invalid_json",
18
+ message: "Request body is not valid JSON."
19
+ }
20
+ ]
21
+ },
22
+ logContext: { reason: "invalid-json-body", ...extraLogContext }
23
+ });
24
+ }
25
+ }
26
+
27
+ export {
28
+ readJsonBody
29
+ };
@@ -0,0 +1,141 @@
1
+ // src/shared/lib/pluralization.ts
2
+ function isAlreadyPlural(word) {
3
+ const lower = word.toLowerCase();
4
+ const knownPlurals = [
5
+ "people",
6
+ "children",
7
+ "men",
8
+ "women",
9
+ "teeth",
10
+ "feet",
11
+ "mice",
12
+ "geese",
13
+ "oxen",
14
+ "sheep",
15
+ "deer",
16
+ "fish",
17
+ "species",
18
+ "series",
19
+ "crises",
20
+ "analyses",
21
+ "theses",
22
+ "phenomena",
23
+ "criteria",
24
+ "data",
25
+ "alumni",
26
+ "cacti",
27
+ "fungi",
28
+ "nuclei",
29
+ "radii"
30
+ ];
31
+ if (knownPlurals.includes(lower)) return true;
32
+ if (lower.endsWith("ies")) return true;
33
+ if (lower.endsWith("ves")) return true;
34
+ if (lower.endsWith("en")) {
35
+ const beforeEN = lower.slice(-3, -2);
36
+ if (beforeEN && !/[aeiou]/.test(beforeEN)) {
37
+ if (lower === "oxen" || lower === "children") return true;
38
+ }
39
+ }
40
+ if (lower.endsWith("i") && lower.length > 2) {
41
+ const beforeI = lower.slice(-2, -1);
42
+ if (["c", "g", "l", "r"].includes(beforeI)) {
43
+ return true;
44
+ }
45
+ }
46
+ if (lower.endsWith("a") && lower.length > 2) {
47
+ const beforeA = lower.slice(-2, -1);
48
+ if (["n", "r"].includes(beforeA)) {
49
+ return true;
50
+ }
51
+ }
52
+ if (lower.endsWith("oes")) {
53
+ return true;
54
+ }
55
+ if (lower.endsWith("s") && lower.length > 1 && !isLikelySingular(lower)) {
56
+ return true;
57
+ }
58
+ return false;
59
+ }
60
+ function isLikelySingular(word) {
61
+ const lower = word.toLowerCase();
62
+ const singularEndings = [
63
+ "ss",
64
+ "us",
65
+ "is",
66
+ "os",
67
+ "sis",
68
+ "asis",
69
+ "isis",
70
+ "ysis",
71
+ "tis",
72
+ "itis",
73
+ "esis"
74
+ ];
75
+ for (const ending of singularEndings) {
76
+ if (lower.endsWith(ending)) return true;
77
+ }
78
+ const knowSingulars = [
79
+ "glass",
80
+ "class",
81
+ "mass",
82
+ "pass",
83
+ "grass",
84
+ "status",
85
+ "atlas",
86
+ "bus",
87
+ "gas",
88
+ "lens",
89
+ "canvas",
90
+ "process",
91
+ "address",
92
+ "access",
93
+ "success",
94
+ "princess",
95
+ "actress",
96
+ "hostess",
97
+ "witness",
98
+ "fortress",
99
+ "express"
100
+ ];
101
+ if (knowSingulars.includes(lower)) return true;
102
+ return false;
103
+ }
104
+ function simplePluralize(singular) {
105
+ const normalized = singular.trim();
106
+ if (!normalized) return "";
107
+ if (isAlreadyPlural(normalized)) {
108
+ return normalized;
109
+ }
110
+ if (normalized.endsWith("s") || normalized.endsWith("x") || normalized.endsWith("z")) {
111
+ return normalized + "es";
112
+ }
113
+ if (normalized.endsWith("y") && !/[aeiou]y$/i.test(normalized)) {
114
+ return normalized.slice(0, -1) + "ies";
115
+ }
116
+ return normalized + "s";
117
+ }
118
+ function toSingularLabel(slug) {
119
+ const words = slug.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
120
+ const lastWord = words[words.length - 1];
121
+ if (lastWord.endsWith("s") && lastWord.length > 1) {
122
+ if (!isLikelySingular(lastWord)) {
123
+ words[words.length - 1] = lastWord.slice(0, -1);
124
+ }
125
+ }
126
+ return words.join(" ");
127
+ }
128
+ function toPluralLabel(slug) {
129
+ const words = slug.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
130
+ const lastWord = words[words.length - 1];
131
+ if (lastWord && !isAlreadyPlural(lastWord)) {
132
+ words[words.length - 1] = simplePluralize(lastWord);
133
+ }
134
+ return words.join(" ");
135
+ }
136
+
137
+ export {
138
+ simplePluralize,
139
+ toSingularLabel,
140
+ toPluralLabel
141
+ };
File without changes
@@ -0,0 +1,27 @@
1
+ // src/observability/logger.ts
2
+ var defaultLogger = {
3
+ error: (p) => console.error(
4
+ JSON.stringify({ level: "error", ts: (/* @__PURE__ */ new Date()).toISOString(), ...p })
5
+ ),
6
+ warn: (p) => console.warn(
7
+ JSON.stringify({ level: "warn", ts: (/* @__PURE__ */ new Date()).toISOString(), ...p })
8
+ ),
9
+ info: (p) => console.info(
10
+ JSON.stringify({ level: "info", ts: (/* @__PURE__ */ new Date()).toISOString(), ...p })
11
+ ),
12
+ debug: (p) => console.debug(
13
+ JSON.stringify({ level: "debug", ts: (/* @__PURE__ */ new Date()).toISOString(), ...p })
14
+ )
15
+ };
16
+ var currentLogger = defaultLogger;
17
+ function setNextlyLogger(logger) {
18
+ currentLogger = logger ?? defaultLogger;
19
+ }
20
+ function getNextlyLogger() {
21
+ return currentLogger;
22
+ }
23
+
24
+ export {
25
+ setNextlyLogger,
26
+ getNextlyLogger
27
+ };