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.
- package/LICENSE +22 -0
- package/README.md +122 -0
- package/dist/_dts-chunks/collections-handler.d-DjgO74Wt.d.ts +20540 -0
- package/dist/_dts-chunks/config.d-DNwsDnjs.d.ts +2589 -0
- package/dist/_dts-chunks/define-component.d-BUgTHmt3.d.ts +1149 -0
- package/dist/_dts-chunks/image-processor.d-OO1PmMrv.d.ts +335 -0
- package/dist/_dts-chunks/index.d-axCAzZ7m.d.ts +17842 -0
- package/dist/_dts-chunks/media.d-DjDOZo4B.d.ts +117 -0
- package/dist/_dts-chunks/on-error.d-CHIKWNxd.d.ts +38 -0
- package/dist/_dts-chunks/storage.d-BUhQ2we_.d.ts +404 -0
- package/dist/actions/index.d.ts +239 -0
- package/dist/actions/index.mjs +281 -0
- package/dist/api/auth-state.d.ts +5 -0
- package/dist/api/auth-state.mjs +131 -0
- package/dist/api/collections-schema-detail.d.ts +56 -0
- package/dist/api/collections-schema-detail.mjs +244 -0
- package/dist/api/collections-schema-export.d.ts +56 -0
- package/dist/api/collections-schema-export.mjs +129 -0
- package/dist/api/collections-schema.d.ts +59 -0
- package/dist/api/collections-schema.mjs +207 -0
- package/dist/api/components-detail.d.ts +50 -0
- package/dist/api/components-detail.mjs +132 -0
- package/dist/api/components.d.ts +69 -0
- package/dist/api/components.mjs +144 -0
- package/dist/api/email-providers-default.d.ts +40 -0
- package/dist/api/email-providers-default.mjs +75 -0
- package/dist/api/email-providers-detail.d.ts +81 -0
- package/dist/api/email-providers-detail.mjs +109 -0
- package/dist/api/email-providers-test.d.ts +43 -0
- package/dist/api/email-providers-test.mjs +114 -0
- package/dist/api/email-providers.d.ts +69 -0
- package/dist/api/email-providers.mjs +110 -0
- package/dist/api/email-send-template.d.ts +41 -0
- package/dist/api/email-send-template.mjs +58 -0
- package/dist/api/email-send.d.ts +42 -0
- package/dist/api/email-send.mjs +58 -0
- package/dist/api/email-templates-detail.d.ts +74 -0
- package/dist/api/email-templates-detail.mjs +112 -0
- package/dist/api/email-templates-layout.d.ts +55 -0
- package/dist/api/email-templates-layout.mjs +92 -0
- package/dist/api/email-templates-preview.d.ts +48 -0
- package/dist/api/email-templates-preview.mjs +93 -0
- package/dist/api/email-templates.d.ts +61 -0
- package/dist/api/email-templates.mjs +118 -0
- package/dist/api/health.d.ts +68 -0
- package/dist/api/health.mjs +67 -0
- package/dist/api/index.d.ts +54 -0
- package/dist/api/index.mjs +16 -0
- package/dist/api/media-bulk.d.ts +74 -0
- package/dist/api/media-bulk.mjs +196 -0
- package/dist/api/media-folders.d.ts +112 -0
- package/dist/api/media-folders.mjs +187 -0
- package/dist/api/media-handlers.d.ts +102 -0
- package/dist/api/media-handlers.mjs +437 -0
- package/dist/api/media.d.ts +117 -0
- package/dist/api/media.mjs +242 -0
- package/dist/api/singles-detail.d.ts +87 -0
- package/dist/api/singles-detail.mjs +170 -0
- package/dist/api/singles-schema-detail.d.ts +54 -0
- package/dist/api/singles-schema-detail.mjs +182 -0
- package/dist/api/singles.d.ts +34 -0
- package/dist/api/singles.mjs +94 -0
- package/dist/api/storage-upload-url.d.ts +48 -0
- package/dist/api/storage-upload-url.mjs +202 -0
- package/dist/api/uploads.d.ts +109 -0
- package/dist/api/uploads.mjs +359 -0
- package/dist/auth/index.d.ts +425 -0
- package/dist/auth/index.mjs +199 -0
- package/dist/boot-apply-PQSYLDIN.mjs +7 -0
- package/dist/chunk-2OALJTK6.mjs +489 -0
- package/dist/chunk-2Q2SX2CS.mjs +365 -0
- package/dist/chunk-2TFX4ND3.mjs +13 -0
- package/dist/chunk-2TWPDSYD.mjs +87 -0
- package/dist/chunk-2W3DVD7S.mjs +647 -0
- package/dist/chunk-2ZFKXPQM.mjs +88 -0
- package/dist/chunk-3FA7FKAV.mjs +832 -0
- package/dist/chunk-3NZ2KMBL.mjs +58 -0
- package/dist/chunk-4MJLT6PZ.mjs +0 -0
- package/dist/chunk-56WO4WX7.mjs +0 -0
- package/dist/chunk-5APFUGAD.mjs +89 -0
- package/dist/chunk-5HMZ644B.mjs +108 -0
- package/dist/chunk-67GXH6PR.mjs +32 -0
- package/dist/chunk-6JNEPWRW.mjs +14368 -0
- package/dist/chunk-6NFHQIJD.mjs +45 -0
- package/dist/chunk-7P6ASYW6.mjs +9 -0
- package/dist/chunk-A3WPLSDT.mjs +1364 -0
- package/dist/chunk-AGJ6F2T3.mjs +144 -0
- package/dist/chunk-AK6Z23OX.mjs +1464 -0
- package/dist/chunk-APKKRD2G.mjs +102 -0
- package/dist/chunk-B2GV2BWH.mjs +73 -0
- package/dist/chunk-D5HQBNUB.mjs +74 -0
- package/dist/chunk-DNNG377Z.mjs +204 -0
- package/dist/chunk-DP3G27G5.mjs +135 -0
- package/dist/chunk-DV6WVX2Q.mjs +0 -0
- package/dist/chunk-DXGGXIUZ.mjs +57 -0
- package/dist/chunk-EGXBZCGC.mjs +943 -0
- package/dist/chunk-ERCNLX3V.mjs +176 -0
- package/dist/chunk-FQULBZ53.mjs +850 -0
- package/dist/chunk-G2AA4QLC.mjs +262 -0
- package/dist/chunk-GDBJ5JCU.mjs +488 -0
- package/dist/chunk-GJNSJU4S.mjs +19 -0
- package/dist/chunk-GZ6DCQKC.mjs +69 -0
- package/dist/chunk-H26B4FYG.mjs +167 -0
- package/dist/chunk-I4JMR3UR.mjs +21 -0
- package/dist/chunk-INV7QKLG.mjs +508 -0
- package/dist/chunk-IUDOC7N7.mjs +46 -0
- package/dist/chunk-IZWPRDC3.mjs +206 -0
- package/dist/chunk-KIMNCZGV.mjs +15 -0
- package/dist/chunk-L6HW2DA7.mjs +15 -0
- package/dist/chunk-LAZXX4HR.mjs +100 -0
- package/dist/chunk-LDKCUMHK.mjs +95 -0
- package/dist/chunk-LRXMECUA.mjs +0 -0
- package/dist/chunk-M52VMPGA.mjs +119 -0
- package/dist/chunk-MGUWEEI6.mjs +160 -0
- package/dist/chunk-NRUWQ5Z7.mjs +419 -0
- package/dist/chunk-NSEFNNU4.mjs +25360 -0
- package/dist/chunk-NTHVDFGO.mjs +138 -0
- package/dist/chunk-O3QHXMOX.mjs +3166 -0
- package/dist/chunk-P7NH2OSC.mjs +2605 -0
- package/dist/chunk-PKMABBB5.mjs +184 -0
- package/dist/chunk-PWS6XGJK.mjs +76 -0
- package/dist/chunk-R6JJQHFC.mjs +20 -0
- package/dist/chunk-RJLLGGPG.mjs +0 -0
- package/dist/chunk-SBACDPNX.mjs +689 -0
- package/dist/chunk-TO5AFLVQ.mjs +124 -0
- package/dist/chunk-TS7GHTG2.mjs +5436 -0
- package/dist/chunk-UJ2IMJ4W.mjs +133 -0
- package/dist/chunk-UOP63Q54.mjs +102 -0
- package/dist/chunk-UUOFWCM6.mjs +78 -0
- package/dist/chunk-V4EQTOA4.mjs +893 -0
- package/dist/chunk-VJ66NCL4.mjs +193 -0
- package/dist/chunk-VQJQHVEV.mjs +29 -0
- package/dist/chunk-VTJADRO3.mjs +141 -0
- package/dist/chunk-VWF3JO32.mjs +0 -0
- package/dist/chunk-W4MGXIRR.mjs +27 -0
- package/dist/chunk-W5KKPZT5.mjs +1204 -0
- package/dist/chunk-WD34YQ6T.mjs +381 -0
- package/dist/chunk-WZBYMYVW.mjs +14 -0
- package/dist/chunk-X23WKS3Z.mjs +50 -0
- package/dist/chunk-X7TXCYYN.mjs +6496 -0
- package/dist/chunk-XGI4EMS3.mjs +140 -0
- package/dist/chunk-XZKLBMN6.mjs +1153 -0
- package/dist/chunk-YB7INWPY.mjs +0 -0
- package/dist/chunk-YV4Y7SDL.mjs +83 -0
- package/dist/chunk-YZNBLFIW.mjs +1688 -0
- package/dist/chunk-YZZCTONM.mjs +263 -0
- package/dist/chunk-ZE6A3FYH.mjs +289 -0
- package/dist/cli/nextly.mjs +68 -0
- package/dist/cli/utils/index.d.ts +449 -0
- package/dist/cli/utils/index.mjs +49 -0
- package/dist/component-schema-service-5577KVW6.mjs +11 -0
- package/dist/config-loader-23YEMC3Z.mjs +23 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.mjs +109 -0
- package/dist/container-ORGFGYSZ.mjs +9 -0
- package/dist/database/index.d.ts +12 -0
- package/dist/database/index.mjs +40 -0
- package/dist/database/seeders/index.d.ts +93 -0
- package/dist/database/seeders/index.mjs +47 -0
- package/dist/db-sync-demote-LJGKLB3S.mjs +117 -0
- package/dist/db-sync-promote-B26VSYQF.mjs +113 -0
- package/dist/dev-reload-broadcaster-B73IQ53V.mjs +25 -0
- package/dist/dist-M2NOU37V.mjs +19 -0
- package/dist/drizzle-kit-lazy-D2M2PXR2.mjs +13 -0
- package/dist/dynamic-collection-schema-service-IEXTPIZ7.mjs +8 -0
- package/dist/errors/index.d.ts +159 -0
- package/dist/errors/index.mjs +10 -0
- package/dist/factory-IWMBKUJM.mjs +15 -0
- package/dist/first-run-QIVKWJIF.mjs +63 -0
- package/dist/fresh-push-NR67DC3R.mjs +8 -0
- package/dist/index.d.ts +4175 -0
- package/dist/index.mjs +1336 -0
- package/dist/local-plugin-PTET4NAT.mjs +7 -0
- package/dist/logger-NU46DXNY.mjs +15 -0
- package/dist/logger-YE4TC7ZN.mjs +9 -0
- package/dist/migration-journal-EP532Y4L.mjs +139 -0
- package/dist/migrations/mysql/0000_eager_sentry.sql +174 -0
- package/dist/migrations/mysql/0001_soft_giant_girl.sql +27 -0
- package/dist/migrations/mysql/0002_media_table.sql +24 -0
- package/dist/migrations/mysql/0003_dynamic_singles.sql +37 -0
- package/dist/migrations/mysql/0004_dynamic_components.sql +35 -0
- package/dist/migrations/mysql/0005_user_management_tables.sql +92 -0
- package/dist/migrations/mysql/0006_api_keys.sql +36 -0
- package/dist/migrations/mysql/0007_general_settings.sql +20 -0
- package/dist/migrations/mysql/0008_site_settings_logo_url.sql +9 -0
- package/dist/migrations/mysql/0009_activity_log.sql +30 -0
- package/dist/migrations/mysql/0010_site_settings_sidebar.sql +13 -0
- package/dist/migrations/mysql/0011_missing_tables_and_columns.sql +54 -0
- package/dist/migrations/mysql/0012_image_sizes_and_focal_point.sql +30 -0
- package/dist/migrations/mysql/0012_media_folders.sql +43 -0
- package/dist/migrations/mysql/0013_user_brute_force_protection.sql +31 -0
- package/dist/migrations/mysql/0014_email_template_attachments.sql +12 -0
- package/dist/migrations/mysql/0015_media_uploaded_by_nullable.sql +15 -0
- package/dist/migrations/mysql/20260429_000000_000_initial_journal.sql +22 -0
- package/dist/migrations/mysql/20260501_000000_journal_batch.sql +17 -0
- package/dist/migrations/mysql/20260501_000001_audit_log.sql +24 -0
- package/dist/migrations/mysql/20260504_000000_nextly_meta.sql +21 -0
- package/dist/migrations/mysql/meta/0000_snapshot.json +1005 -0
- package/dist/migrations/mysql/meta/0001_snapshot.json +1099 -0
- package/dist/migrations/mysql/meta/_journal.json +41 -0
- package/dist/migrations/postgresql/0000_misty_king_bedlam.sql +169 -0
- package/dist/migrations/postgresql/0001_perpetual_captain_marvel.sql +8 -0
- package/dist/migrations/postgresql/0002_sad_spectrum.sql +16 -0
- package/dist/migrations/postgresql/0003_hesitant_ultron.sql +17 -0
- package/dist/migrations/postgresql/0004_media_table.sql +24 -0
- package/dist/migrations/postgresql/0005_media_folders.sql +36 -0
- package/dist/migrations/postgresql/0006_dynamic_collections_update.sql +50 -0
- package/dist/migrations/postgresql/0007_dynamic_singles.sql +38 -0
- package/dist/migrations/postgresql/0008_dynamic_components.sql +37 -0
- package/dist/migrations/postgresql/0009_user_management_tables.sql +95 -0
- package/dist/migrations/postgresql/0010_api_keys.sql +34 -0
- package/dist/migrations/postgresql/0011_general_settings.sql +20 -0
- package/dist/migrations/postgresql/0012_site_settings_logo_url.sql +9 -0
- package/dist/migrations/postgresql/0013_activity_log.sql +29 -0
- package/dist/migrations/postgresql/0014_image_sizes_and_focal_point.sql +33 -0
- package/dist/migrations/postgresql/0014_site_settings_sidebar.sql +13 -0
- package/dist/migrations/postgresql/0015_user_brute_force_protection.sql +29 -0
- package/dist/migrations/postgresql/0016_email_template_attachments.sql +12 -0
- package/dist/migrations/postgresql/0017_media_uploaded_by_nullable.sql +15 -0
- package/dist/migrations/postgresql/20260429_000000_000_initial_journal.sql +24 -0
- package/dist/migrations/postgresql/20260501_000000_journal_batch.sql +17 -0
- package/dist/migrations/postgresql/20260501_000001_audit_log.sql +24 -0
- package/dist/migrations/postgresql/20260504_000000_nextly_meta.sql +22 -0
- package/dist/migrations/postgresql/meta/0000_snapshot.json +1286 -0
- package/dist/migrations/postgresql/meta/0001_snapshot.json +1407 -0
- package/dist/migrations/postgresql/meta/0002_snapshot.json +1552 -0
- package/dist/migrations/postgresql/meta/0003_snapshot.json +1695 -0
- package/dist/migrations/postgresql/meta/0010_snapshot.json +2345 -0
- package/dist/migrations/postgresql/meta/_journal.json +90 -0
- package/dist/migrations/sqlite/0000_api_keys.sql +34 -0
- package/dist/migrations/sqlite/0001_general_settings.sql +20 -0
- package/dist/migrations/sqlite/0002_site_settings_logo_url.sql +9 -0
- package/dist/migrations/sqlite/0003_activity_log.sql +29 -0
- package/dist/migrations/sqlite/0004_image_sizes_and_focal_point.sql +29 -0
- package/dist/migrations/sqlite/0004_site_settings_sidebar.sql +11 -0
- package/dist/migrations/sqlite/0005_user_brute_force_protection.sql +29 -0
- package/dist/migrations/sqlite/0006_email_template_attachments.sql +12 -0
- package/dist/migrations/sqlite/0007_media_uploaded_by_nullable.sql +111 -0
- package/dist/migrations/sqlite/20260429_000000_000_initial_journal.sql +24 -0
- package/dist/migrations/sqlite/20260501_000000_journal_batch.sql +19 -0
- package/dist/migrations/sqlite/20260501_000001_audit_log.sql +24 -0
- package/dist/migrations/sqlite/20260504_000000_nextly_meta.sql +21 -0
- package/dist/migrations/sqlite/20260505_000000_user_management_tables.sql +77 -0
- package/dist/next.d.ts +57 -0
- package/dist/next.mjs +55 -0
- package/dist/observability/index.d.ts +87 -0
- package/dist/observability/index.mjs +57 -0
- package/dist/permissions-3DZZQZMI.mjs +39 -0
- package/dist/pipeline-YOML7SWF.mjs +29 -0
- package/dist/preview-ZZTR3QGS.mjs +9 -0
- package/dist/program-PW6UB2ZC.mjs +5934 -0
- package/dist/reconcile-single-tables-7ENVXJGB.mjs +7 -0
- package/dist/register-SF6E6FVU.mjs +49 -0
- package/dist/reload-config-HWQ4G5MM.mjs +23 -0
- package/dist/resolve-single-table-name-JSOMUB3R.mjs +7 -0
- package/dist/routeHandler-UNMMJIBM.mjs +77 -0
- package/dist/runtime-schema-generator-NRA6A6Z6.mjs +8 -0
- package/dist/runtime.d.ts +120 -0
- package/dist/runtime.mjs +73 -0
- package/dist/schema-hash-FMMG6VPJ.mjs +13 -0
- package/dist/schema-registry-EQ36FZDP.mjs +7 -0
- package/dist/scripts/load-env.mjs +42 -0
- package/dist/storage/index.d.ts +566 -0
- package/dist/storage/index.mjs +45 -0
- package/dist/super-admin-G5ZK5F4T.mjs +39 -0
- package/dist/system-table-service-WGSRVEGT.mjs +17 -0
- package/dist/users-7KELGRYJ.mjs +38 -0
- package/package.json +308 -9
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ClackTerminalPromptDispatcher
|
|
3
|
+
} from "./chunk-VJ66NCL4.mjs";
|
|
4
|
+
import {
|
|
5
|
+
extractDatabaseNameFromUrl
|
|
6
|
+
} from "./chunk-KIMNCZGV.mjs";
|
|
7
|
+
import {
|
|
8
|
+
DrizzleStatementExecutor,
|
|
9
|
+
PushSchemaPipeline,
|
|
10
|
+
RealPreCleanupExecutor,
|
|
11
|
+
createApplyDesiredSchema,
|
|
12
|
+
getProductionNotifier,
|
|
13
|
+
noopMigrationJournal,
|
|
14
|
+
noopPreRenameExecutor
|
|
15
|
+
} from "./chunk-AK6Z23OX.mjs";
|
|
16
|
+
import {
|
|
17
|
+
RealClassifier,
|
|
18
|
+
RegexRenameDetector,
|
|
19
|
+
buildDesiredTableFromFields,
|
|
20
|
+
diffSnapshots,
|
|
21
|
+
introspectLiveSnapshot
|
|
22
|
+
} from "./chunk-SBACDPNX.mjs";
|
|
23
|
+
import {
|
|
24
|
+
generateRuntimeSchema
|
|
25
|
+
} from "./chunk-IZWPRDC3.mjs";
|
|
26
|
+
|
|
27
|
+
// src/domains/schema/utils/resolve-table-name.ts
|
|
28
|
+
function resolveCollectionTableName(slug, dbName) {
|
|
29
|
+
if (dbName && dbName.startsWith("dc_")) return dbName;
|
|
30
|
+
const base = dbName ?? slug;
|
|
31
|
+
return `dc_${base.replace(/-/g, "_")}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/init/reload-config.ts
|
|
35
|
+
async function defaultResolver(name) {
|
|
36
|
+
const { getService } = await import("./register-SF6E6FVU.mjs");
|
|
37
|
+
return getService(name);
|
|
38
|
+
}
|
|
39
|
+
async function reloadNextlyConfig(opts) {
|
|
40
|
+
const resolverArg = opts?.resolver;
|
|
41
|
+
const resolve = (name) => resolverArg ? resolverArg(name) : defaultResolver(name);
|
|
42
|
+
let newConfig;
|
|
43
|
+
try {
|
|
44
|
+
const { loadConfig, clearConfigCache } = await import("./config-loader-23YEMC3Z.mjs");
|
|
45
|
+
clearConfigCache();
|
|
46
|
+
const result = await loadConfig();
|
|
47
|
+
newConfig = result.config;
|
|
48
|
+
} catch (err) {
|
|
49
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
50
|
+
const cause = err instanceof Error && err.cause instanceof Error ? err.cause.message : err instanceof Error && typeof err.cause === "string" ? err.cause : void 0;
|
|
51
|
+
const logContext = err && typeof err === "object" && "logContext" in err ? JSON.stringify(err.logContext) : void 0;
|
|
52
|
+
const detail = cause ? `${msg} (cause: ${cause})` : logContext ? `${msg} (context: ${logContext})` : msg;
|
|
53
|
+
console.warn(
|
|
54
|
+
`[Nextly HMR] Could not reload nextly.config.ts: ${detail}. Keeping the previously-loaded config. Fix the syntax error and save again to retry.`
|
|
55
|
+
);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!newConfig) return;
|
|
59
|
+
let logger;
|
|
60
|
+
let adapter;
|
|
61
|
+
let migrationJournal;
|
|
62
|
+
try {
|
|
63
|
+
logger = await resolve("logger");
|
|
64
|
+
adapter = await resolve("adapter");
|
|
65
|
+
migrationJournal = await resolve("migrationJournal");
|
|
66
|
+
} catch {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!adapter) return;
|
|
70
|
+
const dialect = adapter.dialect;
|
|
71
|
+
const db = adapter.getDrizzle();
|
|
72
|
+
const targets = [];
|
|
73
|
+
for (const c of newConfig.collections ?? []) {
|
|
74
|
+
if (!c.slug) continue;
|
|
75
|
+
targets.push({
|
|
76
|
+
slug: c.slug,
|
|
77
|
+
tableName: c.tableName ?? resolveCollectionTableName(c.slug, c.dbName),
|
|
78
|
+
fields: c.fields ?? [],
|
|
79
|
+
status: c.status === true
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const singleTargets = [];
|
|
83
|
+
for (const s of newConfig.singles ?? []) {
|
|
84
|
+
if (!s.slug) continue;
|
|
85
|
+
const { resolveSingleTableName } = await import("./resolve-single-table-name-JSOMUB3R.mjs");
|
|
86
|
+
singleTargets.push({
|
|
87
|
+
slug: s.slug,
|
|
88
|
+
tableName: resolveSingleTableName({ slug: s.slug, dbName: s.dbName }),
|
|
89
|
+
fields: s.fields ?? [],
|
|
90
|
+
status: s.status === true
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const componentTargets = [];
|
|
94
|
+
for (const c of newConfig.components ?? []) {
|
|
95
|
+
if (!c.slug) continue;
|
|
96
|
+
componentTargets.push({
|
|
97
|
+
slug: c.slug,
|
|
98
|
+
tableName: `comp_${c.slug.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "")}`,
|
|
99
|
+
fields: c.fields ?? []
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (targets.length === 0 && singleTargets.length === 0 && componentTargets.length === 0) return;
|
|
103
|
+
let liveSnapshot;
|
|
104
|
+
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
|
+
} catch (err) {
|
|
115
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
116
|
+
logger?.error(
|
|
117
|
+
`[Nextly HMR] Could not introspect live schema: ${msg}. No code-first schema changes were applied this cycle.`
|
|
118
|
+
);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const liveByTable = /* @__PURE__ */ new Map();
|
|
122
|
+
for (const t of liveSnapshot.tables) liveByTable.set(t.name, t);
|
|
123
|
+
let hasChanges = false;
|
|
124
|
+
const desiredCollections = {};
|
|
125
|
+
for (const target of targets) {
|
|
126
|
+
const entry = {
|
|
127
|
+
slug: target.slug,
|
|
128
|
+
tableName: target.tableName,
|
|
129
|
+
fields: target.fields,
|
|
130
|
+
status: target.status === true
|
|
131
|
+
};
|
|
132
|
+
try {
|
|
133
|
+
const live = liveByTable.has(target.tableName) ? { tables: [liveByTable.get(target.tableName)] } : { tables: [] };
|
|
134
|
+
const desiredTable = buildDesiredTableFromFields(
|
|
135
|
+
target.tableName,
|
|
136
|
+
target.fields,
|
|
137
|
+
dialect,
|
|
138
|
+
{ hasStatus: target.status === true }
|
|
139
|
+
);
|
|
140
|
+
const operations = diffSnapshots(live, { tables: [desiredTable] });
|
|
141
|
+
if (operations.length === 0) {
|
|
142
|
+
desiredCollections[target.slug] = entry;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const classification = classifyForCodeFirst(operations, dialect);
|
|
146
|
+
if (!classification.safe) {
|
|
147
|
+
logger?.warn(
|
|
148
|
+
`[Nextly HMR] Code-first change for '${target.slug}' needs review (${classification.reason}). Auto-apply skipped to prevent data loss without explicit resolutions. Use the admin Schema Builder to confirm with resolutions, or revert the config edit.`
|
|
149
|
+
);
|
|
150
|
+
desiredCollections[target.slug] = entry;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
hasChanges = true;
|
|
154
|
+
desiredCollections[target.slug] = entry;
|
|
155
|
+
} catch (err) {
|
|
156
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
157
|
+
logger?.warn(
|
|
158
|
+
`[Nextly HMR] Skipping '${target.slug}' due to error during diff: ${msg}`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const desiredSingles = {};
|
|
163
|
+
for (const target of singleTargets) {
|
|
164
|
+
const entry = {
|
|
165
|
+
slug: target.slug,
|
|
166
|
+
tableName: target.tableName,
|
|
167
|
+
fields: target.fields,
|
|
168
|
+
status: target.status === true
|
|
169
|
+
};
|
|
170
|
+
try {
|
|
171
|
+
const live = liveByTable.has(target.tableName) ? { tables: [liveByTable.get(target.tableName)] } : { tables: [] };
|
|
172
|
+
const desiredTable = buildDesiredTableFromFields(
|
|
173
|
+
target.tableName,
|
|
174
|
+
target.fields,
|
|
175
|
+
dialect,
|
|
176
|
+
{ hasStatus: target.status === true }
|
|
177
|
+
);
|
|
178
|
+
const operations = diffSnapshots(live, { tables: [desiredTable] });
|
|
179
|
+
if (operations.length === 0) {
|
|
180
|
+
desiredSingles[target.slug] = entry;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const classification = classifyForCodeFirst(operations, dialect);
|
|
184
|
+
if (!classification.safe) {
|
|
185
|
+
logger?.warn(
|
|
186
|
+
`[Nextly HMR] Code-first change for single '${target.slug}' needs review (${classification.reason}). Auto-apply skipped. Use the admin Schema Builder to confirm with resolutions, or revert the config edit.`
|
|
187
|
+
);
|
|
188
|
+
desiredSingles[target.slug] = entry;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
hasChanges = true;
|
|
192
|
+
desiredSingles[target.slug] = entry;
|
|
193
|
+
} catch (err) {
|
|
194
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
195
|
+
logger?.warn(
|
|
196
|
+
`[Nextly HMR] Skipping single '${target.slug}' due to error during diff: ${msg}`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const desiredComponents = {};
|
|
201
|
+
for (const target of componentTargets) {
|
|
202
|
+
const entry = {
|
|
203
|
+
slug: target.slug,
|
|
204
|
+
tableName: target.tableName,
|
|
205
|
+
fields: target.fields
|
|
206
|
+
};
|
|
207
|
+
try {
|
|
208
|
+
const live = liveByTable.has(target.tableName) ? { tables: [liveByTable.get(target.tableName)] } : { tables: [] };
|
|
209
|
+
const desiredTable = buildDesiredTableFromFields(
|
|
210
|
+
target.tableName,
|
|
211
|
+
target.fields,
|
|
212
|
+
dialect
|
|
213
|
+
);
|
|
214
|
+
const operations = diffSnapshots(live, { tables: [desiredTable] });
|
|
215
|
+
if (operations.length === 0) {
|
|
216
|
+
desiredComponents[target.slug] = entry;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const classification = classifyForCodeFirst(operations, dialect);
|
|
220
|
+
if (!classification.safe) {
|
|
221
|
+
logger?.warn(
|
|
222
|
+
`[Nextly HMR] Code-first change for component '${target.slug}' needs review (${classification.reason}). Auto-apply skipped. Use the admin Schema Builder to confirm with resolutions, or revert the config edit.`
|
|
223
|
+
);
|
|
224
|
+
desiredComponents[target.slug] = entry;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
hasChanges = true;
|
|
228
|
+
desiredComponents[target.slug] = entry;
|
|
229
|
+
} catch (err) {
|
|
230
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
231
|
+
logger?.warn(
|
|
232
|
+
`[Nextly HMR] Skipping component '${target.slug}' due to error during diff: ${msg}`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (!hasChanges) return;
|
|
237
|
+
const databaseName = dialect === "mysql" ? extractDatabaseNameFromUrl(process.env.DATABASE_URL) : void 0;
|
|
238
|
+
const desired = {
|
|
239
|
+
collections: desiredCollections,
|
|
240
|
+
singles: desiredSingles,
|
|
241
|
+
components: desiredComponents
|
|
242
|
+
};
|
|
243
|
+
const promptDispatcher = opts?.dispatcher ?? new ClackTerminalPromptDispatcher();
|
|
244
|
+
const apply = createApplyDesiredSchema({
|
|
245
|
+
applyPipeline: (desiredArg, sourceArg, channelArg) => {
|
|
246
|
+
const pipeline = new PushSchemaPipeline({
|
|
247
|
+
executor: new DrizzleStatementExecutor(dialect, db),
|
|
248
|
+
renameDetector: new RegexRenameDetector(),
|
|
249
|
+
// F5 PR 5: real classifier emits add_not_null_with_nulls,
|
|
250
|
+
// add_required_field_no_default, and type_change events from the
|
|
251
|
+
// typed Operation[] stream. ClackTerminalPromptDispatcher renders
|
|
252
|
+
// them in the terminal; RealPreCleanupExecutor runs UPDATE/DELETE.
|
|
253
|
+
classifier: new RealClassifier(),
|
|
254
|
+
promptDispatcher,
|
|
255
|
+
preRenameExecutor: noopPreRenameExecutor,
|
|
256
|
+
preCleanupExecutor: new RealPreCleanupExecutor(),
|
|
257
|
+
// F8 PR 5: real journal from DI; falls back to noop if DI
|
|
258
|
+
// hasn't registered it yet (very-early HMR cycles).
|
|
259
|
+
migrationJournal: migrationJournal ?? noopMigrationJournal,
|
|
260
|
+
// F10 PR 3: HMR applies print a terminal box + write the
|
|
261
|
+
// NDJSON line. Same singleton across HMR cycles.
|
|
262
|
+
notifier: getProductionNotifier()
|
|
263
|
+
});
|
|
264
|
+
return pipeline.apply({
|
|
265
|
+
desired: desiredArg,
|
|
266
|
+
db,
|
|
267
|
+
dialect,
|
|
268
|
+
source: sourceArg,
|
|
269
|
+
promptChannel: channelArg,
|
|
270
|
+
databaseName
|
|
271
|
+
});
|
|
272
|
+
},
|
|
273
|
+
// Unused for source='code' — HMR skips the version check.
|
|
274
|
+
readSchemaVersionForSlug: () => Promise.resolve(null),
|
|
275
|
+
// Unused for HMR — we don't surface bumped versions in the log.
|
|
276
|
+
readNewSchemaVersionsForSlugs: () => Promise.resolve({})
|
|
277
|
+
});
|
|
278
|
+
const applyResult = await apply(desired, "code", {
|
|
279
|
+
promptChannel: "terminal"
|
|
280
|
+
});
|
|
281
|
+
if (applyResult.success) {
|
|
282
|
+
try {
|
|
283
|
+
const registry = await resolve(
|
|
284
|
+
"collectionRegistryService"
|
|
285
|
+
);
|
|
286
|
+
const codeFirstConfigs = (newConfig.collections ?? []).filter((c) => !!c.slug).map((c) => ({
|
|
287
|
+
slug: c.slug,
|
|
288
|
+
labels: {
|
|
289
|
+
singular: c.labels?.singular ?? c.slug,
|
|
290
|
+
plural: c.labels?.plural ?? `${c.slug}s`
|
|
291
|
+
},
|
|
292
|
+
fields: c.fields ?? [],
|
|
293
|
+
description: c.description,
|
|
294
|
+
tableName: c.dbName,
|
|
295
|
+
timestamps: c.timestamps,
|
|
296
|
+
admin: c.admin,
|
|
297
|
+
// Forward the Draft/Published flag so a code-first toggle reaches
|
|
298
|
+
// syncCodeFirstCollections and persists to dynamic_collections.status.
|
|
299
|
+
status: c.status === true
|
|
300
|
+
}));
|
|
301
|
+
await registry.syncCodeFirstCollections(codeFirstConfigs);
|
|
302
|
+
} catch {
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
const singleReg = await resolve(
|
|
306
|
+
"singleRegistryService"
|
|
307
|
+
);
|
|
308
|
+
const codeFirstSingleConfigs = (newConfig.singles ?? []).filter((s) => !!s.slug).map((s) => {
|
|
309
|
+
const labelStr = typeof s.label === "string" ? s.label : s.label?.singular ?? s.slug.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
310
|
+
return {
|
|
311
|
+
slug: s.slug,
|
|
312
|
+
label: labelStr,
|
|
313
|
+
fields: s.fields ?? [],
|
|
314
|
+
description: s.description,
|
|
315
|
+
tableName: s.dbName,
|
|
316
|
+
admin: s.admin,
|
|
317
|
+
// Forward Draft/Published flag for code-first Singles too.
|
|
318
|
+
status: s.status === true
|
|
319
|
+
};
|
|
320
|
+
});
|
|
321
|
+
if (codeFirstSingleConfigs.length > 0) {
|
|
322
|
+
await singleReg.syncCodeFirstSingles(codeFirstSingleConfigs);
|
|
323
|
+
for (const target of singleTargets) {
|
|
324
|
+
if (!liveByTable.has(target.tableName)) {
|
|
325
|
+
try {
|
|
326
|
+
await singleReg.updateMigrationStatus(target.slug, "applied");
|
|
327
|
+
} catch {
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
} catch {
|
|
333
|
+
}
|
|
334
|
+
try {
|
|
335
|
+
const compReg = await resolve(
|
|
336
|
+
"componentRegistryService"
|
|
337
|
+
);
|
|
338
|
+
const codeFirstComponentConfigs = (newConfig.components ?? []).filter((c) => !!c.slug).map((c) => {
|
|
339
|
+
const labelStr = typeof c.label === "string" ? c.label : c.label?.singular ?? c.slug.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
340
|
+
return {
|
|
341
|
+
slug: c.slug,
|
|
342
|
+
label: labelStr,
|
|
343
|
+
fields: c.fields ?? [],
|
|
344
|
+
description: c.description,
|
|
345
|
+
admin: c.admin
|
|
346
|
+
};
|
|
347
|
+
});
|
|
348
|
+
if (codeFirstComponentConfigs.length > 0) {
|
|
349
|
+
await compReg.syncCodeFirstComponents(codeFirstComponentConfigs);
|
|
350
|
+
}
|
|
351
|
+
} catch {
|
|
352
|
+
}
|
|
353
|
+
const collectionFreshTables = /* @__PURE__ */ new Map();
|
|
354
|
+
const singleFreshTables = /* @__PURE__ */ new Map();
|
|
355
|
+
const componentFreshTables = /* @__PURE__ */ new Map();
|
|
356
|
+
try {
|
|
357
|
+
for (const c of Object.values(desiredCollections)) {
|
|
358
|
+
const { table } = generateRuntimeSchema(
|
|
359
|
+
c.tableName,
|
|
360
|
+
c.fields,
|
|
361
|
+
dialect,
|
|
362
|
+
{ status: c.status === true }
|
|
363
|
+
);
|
|
364
|
+
collectionFreshTables.set(c.tableName, table);
|
|
365
|
+
}
|
|
366
|
+
for (const s of Object.values(desiredSingles)) {
|
|
367
|
+
const { table } = generateRuntimeSchema(
|
|
368
|
+
s.tableName,
|
|
369
|
+
s.fields,
|
|
370
|
+
dialect,
|
|
371
|
+
{ status: s.status === true }
|
|
372
|
+
);
|
|
373
|
+
singleFreshTables.set(s.tableName, table);
|
|
374
|
+
}
|
|
375
|
+
for (const comp of Object.values(desiredComponents)) {
|
|
376
|
+
const { table } = generateRuntimeSchema(
|
|
377
|
+
comp.tableName,
|
|
378
|
+
comp.fields,
|
|
379
|
+
dialect
|
|
380
|
+
);
|
|
381
|
+
componentFreshTables.set(comp.tableName, table);
|
|
382
|
+
}
|
|
383
|
+
} catch {
|
|
384
|
+
}
|
|
385
|
+
try {
|
|
386
|
+
const schemaReg = await resolve("schemaRegistry");
|
|
387
|
+
for (const [tableName, table] of collectionFreshTables) {
|
|
388
|
+
schemaReg.registerDynamicSchema(tableName, table);
|
|
389
|
+
}
|
|
390
|
+
for (const [tableName, table] of singleFreshTables) {
|
|
391
|
+
schemaReg.registerDynamicSchema(tableName, table);
|
|
392
|
+
}
|
|
393
|
+
for (const [tableName, table] of componentFreshTables) {
|
|
394
|
+
schemaReg.registerDynamicSchema(tableName, table);
|
|
395
|
+
}
|
|
396
|
+
} catch {
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
const collHandler = await resolve(
|
|
400
|
+
"collectionsHandler"
|
|
401
|
+
);
|
|
402
|
+
for (const [tableName, table] of collectionFreshTables) {
|
|
403
|
+
collHandler.refreshCollectionSchema(tableName, table);
|
|
404
|
+
}
|
|
405
|
+
} catch {
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
const { broadcastDevReload } = await import("./dev-reload-broadcaster-B73IQ53V.mjs");
|
|
409
|
+
broadcastDevReload();
|
|
410
|
+
} catch {
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (!applyResult.success) {
|
|
414
|
+
const code = applyResult.error.code;
|
|
415
|
+
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
|
+
console.warn(
|
|
421
|
+
`
|
|
422
|
+
[Nextly] Schema change needs your confirmation:
|
|
423
|
+
${detail}
|
|
424
|
+
|
|
425
|
+
Renames + drops auto-apply only when you confirm them.
|
|
426
|
+
To apply, run one of:
|
|
427
|
+
\u2022 pnpm nextly db:sync (prompts in this terminal)
|
|
428
|
+
\u2022 pnpm nextly migrate:create (generates a committable migration)
|
|
429
|
+
\u2022 Use the admin UI Schema Builder at /admin
|
|
430
|
+
|
|
431
|
+
Pure-additive changes (new fields, new collections) apply
|
|
432
|
+
automatically on dev start; only structural changes need
|
|
433
|
+
explicit confirmation.
|
|
434
|
+
`
|
|
435
|
+
);
|
|
436
|
+
} else {
|
|
437
|
+
logger?.error(
|
|
438
|
+
`[Nextly HMR] Batch apply failed (${code}): ${applyResult.error.message}`
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function classifyForCodeFirst(operations, _dialect) {
|
|
444
|
+
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
|
+
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
|
+
for (const op of operations) {
|
|
468
|
+
if (op.type === "drop_table") {
|
|
469
|
+
reasons.push(`drops table '${op.tableName}'`);
|
|
470
|
+
} else if (op.type === "change_column_type") {
|
|
471
|
+
reasons.push(
|
|
472
|
+
`changes column '${op.columnName}' type from '${op.fromType}' to '${op.toType}'`
|
|
473
|
+
);
|
|
474
|
+
} else if (op.type === "change_column_nullable" && !op.toNullable) {
|
|
475
|
+
reasons.push(
|
|
476
|
+
`adds NOT NULL to column '${op.columnName}' (would fail on existing rows without a default)`
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (reasons.length > 0) {
|
|
481
|
+
return { safe: false, reason: reasons.join("; ") };
|
|
482
|
+
}
|
|
483
|
+
return { safe: true };
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export {
|
|
487
|
+
resolveCollectionTableName,
|
|
488
|
+
reloadNextlyConfig
|
|
489
|
+
};
|