nextly 0.0.1 → 0.0.2-alpha.1
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,488 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_COMPONENT_NESTING_DEPTH,
|
|
3
|
+
SQL_RESERVED_KEYWORDS
|
|
4
|
+
} from "./chunk-FQULBZ53.mjs";
|
|
5
|
+
|
|
6
|
+
// src/shared/types/config.ts
|
|
7
|
+
var DEFAULT_AUTH_CONFIG = {
|
|
8
|
+
revealRegistrationConflict: false
|
|
9
|
+
};
|
|
10
|
+
var DEFAULT_TYPESCRIPT_CONFIG = {
|
|
11
|
+
outputFile: "./src/types/generated/payload-types.ts",
|
|
12
|
+
declare: true
|
|
13
|
+
};
|
|
14
|
+
var DEFAULT_DB_CONFIG = {
|
|
15
|
+
schemasDir: "./src/db/schemas/collections",
|
|
16
|
+
migrationsDir: "./src/db/migrations"
|
|
17
|
+
};
|
|
18
|
+
var DEFAULT_RATE_LIMIT_CONFIG = {
|
|
19
|
+
readLimit: 100,
|
|
20
|
+
writeLimit: 30,
|
|
21
|
+
windowMs: 6e4
|
|
22
|
+
};
|
|
23
|
+
var DEFAULT_API_KEYS_CONFIG = {
|
|
24
|
+
requestsPerHour: 1e3,
|
|
25
|
+
windowMs: 36e5
|
|
26
|
+
};
|
|
27
|
+
function sanitizeConfig(config) {
|
|
28
|
+
if (config.apiKeys?.rateLimit?.requestsPerHour !== void 0) {
|
|
29
|
+
if (!Number.isInteger(config.apiKeys.rateLimit.requestsPerHour) || config.apiKeys.rateLimit.requestsPerHour <= 0) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`apiKeys.rateLimit.requestsPerHour must be a positive integer (got ${config.apiKeys.rateLimit.requestsPerHour})`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (config.apiKeys?.rateLimit?.windowMs !== void 0) {
|
|
36
|
+
if (typeof config.apiKeys.rateLimit.windowMs !== "number" || config.apiKeys.rateLimit.windowMs <= 0) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`apiKeys.rateLimit.windowMs must be a positive number (got ${config.apiKeys.rateLimit.windowMs})`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
let rateLimit;
|
|
43
|
+
if (config.rateLimit?.enabled !== false) {
|
|
44
|
+
rateLimit = {
|
|
45
|
+
enabled: true,
|
|
46
|
+
readLimit: config.rateLimit?.readLimit ?? DEFAULT_RATE_LIMIT_CONFIG.readLimit,
|
|
47
|
+
writeLimit: config.rateLimit?.writeLimit ?? DEFAULT_RATE_LIMIT_CONFIG.writeLimit,
|
|
48
|
+
windowMs: config.rateLimit?.windowMs ?? DEFAULT_RATE_LIMIT_CONFIG.windowMs,
|
|
49
|
+
store: config.rateLimit?.store,
|
|
50
|
+
keyGenerator: config.rateLimit?.keyGenerator,
|
|
51
|
+
skip: config.rateLimit?.skip,
|
|
52
|
+
collections: config.rateLimit?.collections
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const apiKeys = config.apiKeys ? {
|
|
56
|
+
rateLimit: {
|
|
57
|
+
requestsPerHour: config.apiKeys.rateLimit?.requestsPerHour ?? DEFAULT_API_KEYS_CONFIG.requestsPerHour,
|
|
58
|
+
windowMs: config.apiKeys.rateLimit?.windowMs ?? DEFAULT_API_KEYS_CONFIG.windowMs
|
|
59
|
+
}
|
|
60
|
+
} : void 0;
|
|
61
|
+
return {
|
|
62
|
+
collections: config.collections ?? [],
|
|
63
|
+
singles: config.singles ?? [],
|
|
64
|
+
components: config.components ?? [],
|
|
65
|
+
users: config.users,
|
|
66
|
+
email: config.email,
|
|
67
|
+
typescript: {
|
|
68
|
+
outputFile: config.typescript?.outputFile ?? DEFAULT_TYPESCRIPT_CONFIG.outputFile,
|
|
69
|
+
declare: config.typescript?.declare ?? DEFAULT_TYPESCRIPT_CONFIG.declare
|
|
70
|
+
},
|
|
71
|
+
db: {
|
|
72
|
+
schemasDir: config.db?.schemasDir ?? DEFAULT_DB_CONFIG.schemasDir,
|
|
73
|
+
migrationsDir: config.db?.migrationsDir ?? DEFAULT_DB_CONFIG.migrationsDir
|
|
74
|
+
},
|
|
75
|
+
rateLimit,
|
|
76
|
+
apiKeys,
|
|
77
|
+
// PR 5 (unified-error-system): always present after sanitization so
|
|
78
|
+
// downstream code can read `config.auth.revealRegistrationConflict`
|
|
79
|
+
// without nil checks. Defaults to silent-success per spec §13.2.
|
|
80
|
+
auth: {
|
|
81
|
+
revealRegistrationConflict: config.auth?.revealRegistrationConflict ?? DEFAULT_AUTH_CONFIG.revealRegistrationConflict
|
|
82
|
+
},
|
|
83
|
+
storage: config.storage ?? [],
|
|
84
|
+
plugins: config.plugins ?? [],
|
|
85
|
+
security: config.security,
|
|
86
|
+
admin: config.admin
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/users/config/validate-user-config.ts
|
|
91
|
+
var RESERVED_USER_FIELD_NAMES = [
|
|
92
|
+
"id",
|
|
93
|
+
"name",
|
|
94
|
+
"email",
|
|
95
|
+
"emailVerified",
|
|
96
|
+
"passwordHash",
|
|
97
|
+
"passwordUpdatedAt",
|
|
98
|
+
"image",
|
|
99
|
+
"isActive",
|
|
100
|
+
"createdAt",
|
|
101
|
+
"updatedAt",
|
|
102
|
+
"roles",
|
|
103
|
+
"accounts",
|
|
104
|
+
"password"
|
|
105
|
+
];
|
|
106
|
+
var ALLOWED_USER_FIELD_TYPES = [
|
|
107
|
+
"text",
|
|
108
|
+
"textarea",
|
|
109
|
+
"number",
|
|
110
|
+
"email",
|
|
111
|
+
"select",
|
|
112
|
+
"radio",
|
|
113
|
+
"checkbox",
|
|
114
|
+
"date"
|
|
115
|
+
];
|
|
116
|
+
var RESERVED_NAMES_SET = new Set(
|
|
117
|
+
RESERVED_USER_FIELD_NAMES.map((n) => n.toLowerCase())
|
|
118
|
+
);
|
|
119
|
+
var ALLOWED_TYPES_SET = new Set(ALLOWED_USER_FIELD_TYPES);
|
|
120
|
+
var SQL_KEYWORDS_SET = new Set(SQL_RESERVED_KEYWORDS);
|
|
121
|
+
var FIELD_NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
122
|
+
function isSQLKeyword(name) {
|
|
123
|
+
return SQL_KEYWORDS_SET.has(name.toLowerCase());
|
|
124
|
+
}
|
|
125
|
+
function isReservedUserFieldName(name) {
|
|
126
|
+
return RESERVED_NAMES_SET.has(name.toLowerCase());
|
|
127
|
+
}
|
|
128
|
+
function validateUserFieldName(name, path, errors, seenNames) {
|
|
129
|
+
if (!name) {
|
|
130
|
+
errors.push({
|
|
131
|
+
path: `${path}.name`,
|
|
132
|
+
message: "Field name is required",
|
|
133
|
+
code: "USER_FIELD_NAME_REQUIRED"
|
|
134
|
+
});
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (typeof name !== "string") {
|
|
138
|
+
errors.push({
|
|
139
|
+
path: `${path}.name`,
|
|
140
|
+
message: "Field name must be a string",
|
|
141
|
+
code: "USER_FIELD_NAME_REQUIRED"
|
|
142
|
+
});
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (!FIELD_NAME_PATTERN.test(name)) {
|
|
146
|
+
errors.push({
|
|
147
|
+
path: `${path}.name`,
|
|
148
|
+
message: `Field name '${name}' must start with a letter and contain only letters, numbers, and underscores`,
|
|
149
|
+
code: "USER_FIELD_NAME_INVALID_FORMAT"
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
if (isReservedUserFieldName(name)) {
|
|
153
|
+
errors.push({
|
|
154
|
+
path: `${path}.name`,
|
|
155
|
+
message: `Field name '${name}' conflicts with a built-in user field. Reserved names: ${RESERVED_USER_FIELD_NAMES.join(", ")}`,
|
|
156
|
+
code: "USER_FIELD_NAME_RESERVED"
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (isSQLKeyword(name)) {
|
|
160
|
+
errors.push({
|
|
161
|
+
path: `${path}.name`,
|
|
162
|
+
message: `Field name '${name}' is a SQL reserved keyword. Consider using a different name like '${name}Field' or '${name}Value'`,
|
|
163
|
+
code: "USER_FIELD_NAME_SQL_KEYWORD"
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
const nameLower = name.toLowerCase();
|
|
167
|
+
if (seenNames.has(nameLower)) {
|
|
168
|
+
errors.push({
|
|
169
|
+
path: `${path}.name`,
|
|
170
|
+
message: `Duplicate field name '${name}'`,
|
|
171
|
+
code: "USER_FIELD_NAME_DUPLICATE"
|
|
172
|
+
});
|
|
173
|
+
} else {
|
|
174
|
+
seenNames.add(nameLower);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function validateUserFieldType(field, path, errors) {
|
|
178
|
+
const fieldType = field.type;
|
|
179
|
+
if (!fieldType) {
|
|
180
|
+
errors.push({
|
|
181
|
+
path: `${path}.type`,
|
|
182
|
+
message: "Field type is required",
|
|
183
|
+
code: "USER_FIELD_TYPE_REQUIRED"
|
|
184
|
+
});
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (typeof fieldType !== "string" || !ALLOWED_TYPES_SET.has(fieldType)) {
|
|
188
|
+
errors.push({
|
|
189
|
+
path: `${path}.type`,
|
|
190
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
191
|
+
message: `User custom fields do not support type '${String(fieldType)}'. Allowed types: ${ALLOWED_USER_FIELD_TYPES.join(", ")}`,
|
|
192
|
+
code: "USER_FIELD_TYPE_NOT_ALLOWED"
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function validateUserSelectOptions(field, path, errors, fieldType) {
|
|
197
|
+
const options = field.options;
|
|
198
|
+
if (!options) {
|
|
199
|
+
errors.push({
|
|
200
|
+
path: `${path}.options`,
|
|
201
|
+
message: `${fieldType} field must have an 'options' array`,
|
|
202
|
+
code: fieldType === "select" ? "USER_SELECT_OPTIONS_REQUIRED" : "USER_RADIO_OPTIONS_REQUIRED"
|
|
203
|
+
});
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (!Array.isArray(options)) {
|
|
207
|
+
errors.push({
|
|
208
|
+
path: `${path}.options`,
|
|
209
|
+
message: `${fieldType} field 'options' must be an array`,
|
|
210
|
+
code: fieldType === "select" ? "USER_SELECT_OPTIONS_REQUIRED" : "USER_RADIO_OPTIONS_REQUIRED"
|
|
211
|
+
});
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (options.length === 0) {
|
|
215
|
+
errors.push({
|
|
216
|
+
path: `${path}.options`,
|
|
217
|
+
message: `${fieldType} field must have at least one option`,
|
|
218
|
+
code: fieldType === "select" ? "USER_SELECT_OPTIONS_EMPTY" : "USER_RADIO_OPTIONS_EMPTY"
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function validateUserFields(fields, errors) {
|
|
223
|
+
const fieldNames = /* @__PURE__ */ new Set();
|
|
224
|
+
if (fields === void 0 || fields === null) {
|
|
225
|
+
return fieldNames;
|
|
226
|
+
}
|
|
227
|
+
if (!Array.isArray(fields)) {
|
|
228
|
+
errors.push({
|
|
229
|
+
path: "fields",
|
|
230
|
+
message: "User fields must be an array",
|
|
231
|
+
code: "USER_FIELDS_INVALID_TYPE"
|
|
232
|
+
});
|
|
233
|
+
return fieldNames;
|
|
234
|
+
}
|
|
235
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
236
|
+
fields.forEach((field, index) => {
|
|
237
|
+
const fieldPath = `fields[${index}]`;
|
|
238
|
+
if (!field || typeof field !== "object") {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const f = field;
|
|
242
|
+
validateUserFieldType(f, fieldPath, errors);
|
|
243
|
+
validateUserFieldName(f.name, fieldPath, errors, seenNames);
|
|
244
|
+
const fieldType = f.type;
|
|
245
|
+
if (fieldType === "select") {
|
|
246
|
+
validateUserSelectOptions(f, fieldPath, errors, "select");
|
|
247
|
+
} else if (fieldType === "radio") {
|
|
248
|
+
validateUserSelectOptions(f, fieldPath, errors, "radio");
|
|
249
|
+
}
|
|
250
|
+
if (typeof f.name === "string" && FIELD_NAME_PATTERN.test(f.name)) {
|
|
251
|
+
fieldNames.add(f.name);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
return fieldNames;
|
|
255
|
+
}
|
|
256
|
+
function validateAdminOptions(admin, fieldNames, errors) {
|
|
257
|
+
if (admin === void 0 || admin === null) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (typeof admin !== "object" || Array.isArray(admin)) {
|
|
261
|
+
errors.push({
|
|
262
|
+
path: "admin",
|
|
263
|
+
message: "Admin options must be an object",
|
|
264
|
+
code: "USER_ADMIN_INVALID_TYPE"
|
|
265
|
+
});
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const adminObj = admin;
|
|
269
|
+
if (adminObj.listFields !== void 0) {
|
|
270
|
+
if (!Array.isArray(adminObj.listFields)) {
|
|
271
|
+
errors.push({
|
|
272
|
+
path: "admin.listFields",
|
|
273
|
+
message: "admin.listFields must be an array of field names",
|
|
274
|
+
code: "USER_ADMIN_INVALID_TYPE"
|
|
275
|
+
});
|
|
276
|
+
} else {
|
|
277
|
+
adminObj.listFields.forEach((ref, index) => {
|
|
278
|
+
if (typeof ref !== "string") {
|
|
279
|
+
errors.push({
|
|
280
|
+
path: `admin.listFields[${index}]`,
|
|
281
|
+
message: "Each listFields entry must be a string",
|
|
282
|
+
code: "USER_ADMIN_LIST_FIELD_UNKNOWN"
|
|
283
|
+
});
|
|
284
|
+
} else if (!fieldNames.has(ref)) {
|
|
285
|
+
const available = fieldNames.size > 0 ? `Available fields: ${Array.from(fieldNames).sort().join(", ")}` : "No custom fields defined";
|
|
286
|
+
errors.push({
|
|
287
|
+
path: `admin.listFields[${index}]`,
|
|
288
|
+
message: `Unknown field '${ref}' in admin.listFields. ${available}`,
|
|
289
|
+
code: "USER_ADMIN_LIST_FIELD_UNKNOWN"
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (adminObj.group !== void 0 && typeof adminObj.group !== "string") {
|
|
296
|
+
errors.push({
|
|
297
|
+
path: "admin.group",
|
|
298
|
+
message: "admin.group must be a string",
|
|
299
|
+
code: "USER_ADMIN_GROUP_INVALID_TYPE"
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function validateUserConfig(config) {
|
|
304
|
+
const errors = [];
|
|
305
|
+
const fieldNames = validateUserFields(config.fields, errors);
|
|
306
|
+
validateAdminOptions(config.admin, fieldNames, errors);
|
|
307
|
+
return {
|
|
308
|
+
valid: errors.length === 0,
|
|
309
|
+
errors
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function assertValidUserConfig(config) {
|
|
313
|
+
const result = validateUserConfig(config);
|
|
314
|
+
if (!result.valid) {
|
|
315
|
+
const errorMessages = result.errors.map((err) => ` - [${err.code}] ${err.path}: ${err.message}`).join("\n");
|
|
316
|
+
throw new Error(`Invalid user config:
|
|
317
|
+
${errorMessages}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/collections/config/define-config.ts
|
|
322
|
+
function collectComponentRefs(fields, refs) {
|
|
323
|
+
for (const field of fields) {
|
|
324
|
+
if (field.type === "component") {
|
|
325
|
+
if (typeof field.component === "string") {
|
|
326
|
+
refs.push(field.component);
|
|
327
|
+
}
|
|
328
|
+
if (Array.isArray(field.components)) {
|
|
329
|
+
for (const slug of field.components) {
|
|
330
|
+
if (typeof slug === "string") {
|
|
331
|
+
refs.push(slug);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (Array.isArray(field.fields)) {
|
|
337
|
+
collectComponentRefs(
|
|
338
|
+
field.fields,
|
|
339
|
+
refs
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
function validateComponentNesting(components) {
|
|
345
|
+
const graph = /* @__PURE__ */ new Map();
|
|
346
|
+
const slugSet = /* @__PURE__ */ new Set();
|
|
347
|
+
for (const comp of components) {
|
|
348
|
+
const slug = comp.slug.toLowerCase();
|
|
349
|
+
slugSet.add(slug);
|
|
350
|
+
const refs = [];
|
|
351
|
+
collectComponentRefs(
|
|
352
|
+
comp.fields,
|
|
353
|
+
refs
|
|
354
|
+
);
|
|
355
|
+
graph.set(
|
|
356
|
+
slug,
|
|
357
|
+
refs.filter((r) => slugSet.has(r.toLowerCase())).map((r) => r.toLowerCase())
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
for (const [slug, refs] of graph) {
|
|
361
|
+
graph.set(
|
|
362
|
+
slug,
|
|
363
|
+
refs.filter((r) => slugSet.has(r))
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
const visited = /* @__PURE__ */ new Set();
|
|
367
|
+
const inStack = /* @__PURE__ */ new Set();
|
|
368
|
+
function detectCycle(slug, path) {
|
|
369
|
+
if (inStack.has(slug)) {
|
|
370
|
+
return [...path, slug];
|
|
371
|
+
}
|
|
372
|
+
if (visited.has(slug)) return null;
|
|
373
|
+
visited.add(slug);
|
|
374
|
+
inStack.add(slug);
|
|
375
|
+
for (const ref of graph.get(slug) ?? []) {
|
|
376
|
+
const cycle = detectCycle(ref, [...path, slug]);
|
|
377
|
+
if (cycle) return cycle;
|
|
378
|
+
}
|
|
379
|
+
inStack.delete(slug);
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
for (const slug of graph.keys()) {
|
|
383
|
+
if (!visited.has(slug)) {
|
|
384
|
+
const cycle = detectCycle(slug, []);
|
|
385
|
+
if (cycle) {
|
|
386
|
+
const cycleStr = cycle.join(" \u2192 ");
|
|
387
|
+
throw new Error(
|
|
388
|
+
`Circular component reference detected: ${cycleStr}. Components cannot reference each other in a cycle.`
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
const depthCache = /* @__PURE__ */ new Map();
|
|
394
|
+
function getMaxDepth(slug) {
|
|
395
|
+
if (depthCache.has(slug)) return depthCache.get(slug);
|
|
396
|
+
const refs = graph.get(slug) ?? [];
|
|
397
|
+
let maxChildDepth = 0;
|
|
398
|
+
for (const ref of refs) {
|
|
399
|
+
maxChildDepth = Math.max(maxChildDepth, getMaxDepth(ref));
|
|
400
|
+
}
|
|
401
|
+
const depth = 1 + maxChildDepth;
|
|
402
|
+
depthCache.set(slug, depth);
|
|
403
|
+
return depth;
|
|
404
|
+
}
|
|
405
|
+
for (const slug of graph.keys()) {
|
|
406
|
+
const depth = getMaxDepth(slug);
|
|
407
|
+
if (depth > MAX_COMPONENT_NESTING_DEPTH) {
|
|
408
|
+
throw new Error(
|
|
409
|
+
`Component nesting depth exceeds maximum of ${MAX_COMPONENT_NESTING_DEPTH} levels (component '${slug}' has a nesting chain ${depth} levels deep). Simplify the component structure to reduce nesting.`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
function validateNextlyConfig(config) {
|
|
415
|
+
const collections = config.collections ?? [];
|
|
416
|
+
const slugs = /* @__PURE__ */ new Set();
|
|
417
|
+
for (const collection of collections) {
|
|
418
|
+
const slug = collection.slug.toLowerCase();
|
|
419
|
+
if (slugs.has(slug)) {
|
|
420
|
+
throw new Error(
|
|
421
|
+
`Duplicate collection slug: '${collection.slug}'. Each collection must have a unique slug.`
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
slugs.add(slug);
|
|
425
|
+
}
|
|
426
|
+
const singles = config.singles ?? [];
|
|
427
|
+
for (const single of singles) {
|
|
428
|
+
const slug = single.slug.toLowerCase();
|
|
429
|
+
if (slugs.has(slug)) {
|
|
430
|
+
const isCollectionConflict = collections.some(
|
|
431
|
+
(c) => c.slug.toLowerCase() === slug
|
|
432
|
+
);
|
|
433
|
+
if (isCollectionConflict) {
|
|
434
|
+
throw new Error(
|
|
435
|
+
`Single slug '${single.slug}' conflicts with a Collection slug. Singles and Collections must have unique slugs.`
|
|
436
|
+
);
|
|
437
|
+
} else {
|
|
438
|
+
throw new Error(
|
|
439
|
+
`Duplicate Single slug: '${single.slug}'. Each Single must have a unique slug.`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
slugs.add(slug);
|
|
444
|
+
}
|
|
445
|
+
const components = config.components ?? [];
|
|
446
|
+
for (const comp of components) {
|
|
447
|
+
const slug = comp.slug.toLowerCase();
|
|
448
|
+
if (slugs.has(slug)) {
|
|
449
|
+
const isCollectionConflict = collections.some(
|
|
450
|
+
(c) => c.slug.toLowerCase() === slug
|
|
451
|
+
);
|
|
452
|
+
const isSingleConflict = singles.some((s) => s.slug.toLowerCase() === slug);
|
|
453
|
+
if (isCollectionConflict) {
|
|
454
|
+
throw new Error(
|
|
455
|
+
`Component slug '${comp.slug}' conflicts with a Collection slug. Components, Collections, and Singles must have unique slugs.`
|
|
456
|
+
);
|
|
457
|
+
} else if (isSingleConflict) {
|
|
458
|
+
throw new Error(
|
|
459
|
+
`Component slug '${comp.slug}' conflicts with a Single slug. Components, Collections, and Singles must have unique slugs.`
|
|
460
|
+
);
|
|
461
|
+
} else {
|
|
462
|
+
throw new Error(
|
|
463
|
+
`Duplicate Component slug: '${comp.slug}'. Each Component must have a unique slug.`
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
slugs.add(slug);
|
|
468
|
+
}
|
|
469
|
+
if (components.length > 0) {
|
|
470
|
+
validateComponentNesting(components);
|
|
471
|
+
}
|
|
472
|
+
if (config.users) {
|
|
473
|
+
assertValidUserConfig(config.users);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function defineConfig(config) {
|
|
477
|
+
validateNextlyConfig(config);
|
|
478
|
+
return sanitizeConfig(config);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export {
|
|
482
|
+
sanitizeConfig,
|
|
483
|
+
RESERVED_USER_FIELD_NAMES,
|
|
484
|
+
ALLOWED_USER_FIELD_TYPES,
|
|
485
|
+
validateUserConfig,
|
|
486
|
+
assertValidUserConfig,
|
|
487
|
+
defineConfig
|
|
488
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NextlyError
|
|
3
|
+
} from "./chunk-NRUWQ5Z7.mjs";
|
|
4
|
+
|
|
5
|
+
// src/api/zod-to-nextly-error.ts
|
|
6
|
+
function nextlyValidationFromZod(err) {
|
|
7
|
+
return NextlyError.validation({
|
|
8
|
+
errors: err.issues.map((issue) => ({
|
|
9
|
+
path: issue.path.join("."),
|
|
10
|
+
code: issue.code,
|
|
11
|
+
message: issue.message
|
|
12
|
+
})),
|
|
13
|
+
logContext: { zodIssues: err.issues }
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
nextlyValidationFromZod
|
|
19
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RealClassifier,
|
|
3
|
+
RegexRenameDetector,
|
|
4
|
+
buildDesiredTableFromComponentFields,
|
|
5
|
+
buildDesiredTableFromFields,
|
|
6
|
+
countNulls,
|
|
7
|
+
countRows,
|
|
8
|
+
diffSnapshots,
|
|
9
|
+
introspectLiveSnapshot
|
|
10
|
+
} from "./chunk-SBACDPNX.mjs";
|
|
11
|
+
|
|
12
|
+
// src/domains/schema/pipeline/preview.ts
|
|
13
|
+
async function previewDesiredSchema(args, deps = {}) {
|
|
14
|
+
const { desired, db, dialect } = args;
|
|
15
|
+
const renameDetector = deps.renameDetector ?? new RegexRenameDetector();
|
|
16
|
+
const classifier = deps.classifier ?? new RealClassifier();
|
|
17
|
+
const introspect = deps.introspect ?? introspectLiveSnapshot;
|
|
18
|
+
const managedTableNames = [
|
|
19
|
+
...Object.values(desired.collections).map((c) => c.tableName),
|
|
20
|
+
...Object.values(desired.singles).map((s) => s.tableName),
|
|
21
|
+
...Object.values(desired.components).map((c) => c.tableName)
|
|
22
|
+
];
|
|
23
|
+
const liveSnapshot = await introspect(db, dialect, managedTableNames);
|
|
24
|
+
const collectionTables = Object.values(desired.collections).map(
|
|
25
|
+
(c) => buildDesiredTableFromFields(
|
|
26
|
+
c.tableName,
|
|
27
|
+
c.fields,
|
|
28
|
+
dialect
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
const singleTables = Object.values(desired.singles).map(
|
|
32
|
+
(s) => buildDesiredTableFromFields(
|
|
33
|
+
s.tableName,
|
|
34
|
+
s.fields,
|
|
35
|
+
dialect
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
const componentTables = Object.values(desired.components).map(
|
|
39
|
+
(c) => buildDesiredTableFromComponentFields(
|
|
40
|
+
c.tableName,
|
|
41
|
+
c.fields,
|
|
42
|
+
dialect
|
|
43
|
+
)
|
|
44
|
+
);
|
|
45
|
+
const desiredSnapshot = {
|
|
46
|
+
tables: [...collectionTables, ...singleTables, ...componentTables]
|
|
47
|
+
};
|
|
48
|
+
const operations = diffSnapshots(liveSnapshot, desiredSnapshot);
|
|
49
|
+
const candidates = renameDetector.detect(operations, dialect);
|
|
50
|
+
const classificationResult = await classifier.classify({
|
|
51
|
+
operations,
|
|
52
|
+
drizzleWarnings: [],
|
|
53
|
+
hasDataLoss: false,
|
|
54
|
+
countNulls: (table, column) => countNulls(db, dialect, table, column),
|
|
55
|
+
countRows: (table) => countRows(db, dialect, table),
|
|
56
|
+
dialect
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
operations,
|
|
60
|
+
events: classificationResult.events,
|
|
61
|
+
candidates,
|
|
62
|
+
classification: classificationResult.level,
|
|
63
|
+
liveSnapshot
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export {
|
|
68
|
+
previewDesiredSchema
|
|
69
|
+
};
|