@createcms/core 0.1.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.
Files changed (83) hide show
  1. package/README.md +169 -0
  2. package/dist/ab-edge/index.cjs +214 -0
  3. package/dist/ab-edge/index.d.cts +121 -0
  4. package/dist/ab-edge/index.d.ts +121 -0
  5. package/dist/ab-edge/index.js +205 -0
  6. package/dist/bin/createcms.js +3082 -0
  7. package/dist/db.cjs +496 -0
  8. package/dist/db.d.cts +128 -0
  9. package/dist/db.d.ts +128 -0
  10. package/dist/db.js +488 -0
  11. package/dist/index.cjs +13789 -0
  12. package/dist/index.d.cts +10277 -0
  13. package/dist/index.d.ts +10277 -0
  14. package/dist/index.js +13737 -0
  15. package/dist/nanoid.cjs +50 -0
  16. package/dist/nanoid.d.cts +29 -0
  17. package/dist/nanoid.d.ts +29 -0
  18. package/dist/nanoid.js +47 -0
  19. package/dist/next/index.cjs +60 -0
  20. package/dist/next/index.d.cts +141 -0
  21. package/dist/next/index.d.ts +141 -0
  22. package/dist/next/index.js +58 -0
  23. package/dist/next/middleware.cjs +113 -0
  24. package/dist/next/middleware.d.cts +77 -0
  25. package/dist/next/middleware.d.ts +77 -0
  26. package/dist/next/middleware.js +111 -0
  27. package/dist/plugins/ab-test/analytics/upstash.cjs +345 -0
  28. package/dist/plugins/ab-test/analytics/upstash.d.cts +193 -0
  29. package/dist/plugins/ab-test/analytics/upstash.d.ts +193 -0
  30. package/dist/plugins/ab-test/analytics/upstash.js +343 -0
  31. package/dist/plugins/ab-test/client.cjs +686 -0
  32. package/dist/plugins/ab-test/client.d.cts +233 -0
  33. package/dist/plugins/ab-test/client.d.ts +233 -0
  34. package/dist/plugins/ab-test/client.js +684 -0
  35. package/dist/plugins/ab-test/index.cjs +3400 -0
  36. package/dist/plugins/ab-test/index.d.cts +1131 -0
  37. package/dist/plugins/ab-test/index.d.ts +1131 -0
  38. package/dist/plugins/ab-test/index.js +3367 -0
  39. package/dist/plugins/client.cjs +20 -0
  40. package/dist/plugins/client.d.cts +3 -0
  41. package/dist/plugins/client.d.ts +3 -0
  42. package/dist/plugins/client.js +3 -0
  43. package/dist/plugins/consent/client.cjs +315 -0
  44. package/dist/plugins/consent/client.d.cts +145 -0
  45. package/dist/plugins/consent/client.d.ts +145 -0
  46. package/dist/plugins/consent/client.js +313 -0
  47. package/dist/plugins/consent/index.cjs +267 -0
  48. package/dist/plugins/consent/index.d.cts +618 -0
  49. package/dist/plugins/consent/index.d.ts +618 -0
  50. package/dist/plugins/consent/index.js +258 -0
  51. package/dist/plugins/i18n/index.cjs +2177 -0
  52. package/dist/plugins/i18n/index.d.cts +562 -0
  53. package/dist/plugins/i18n/index.d.ts +562 -0
  54. package/dist/plugins/i18n/index.js +2150 -0
  55. package/dist/plugins/media-optimize/index.cjs +315 -0
  56. package/dist/plugins/media-optimize/index.d.cts +144 -0
  57. package/dist/plugins/media-optimize/index.d.ts +144 -0
  58. package/dist/plugins/media-optimize/index.js +311 -0
  59. package/dist/plugins/multi-tenant/index.cjs +210 -0
  60. package/dist/plugins/multi-tenant/index.d.cts +431 -0
  61. package/dist/plugins/multi-tenant/index.d.ts +431 -0
  62. package/dist/plugins/multi-tenant/index.js +207 -0
  63. package/dist/plugins/server.cjs +24 -0
  64. package/dist/plugins/server.d.cts +3 -0
  65. package/dist/plugins/server.d.ts +3 -0
  66. package/dist/plugins/server.js +3 -0
  67. package/dist/react/blocks.cjs +233 -0
  68. package/dist/react/blocks.d.cts +320 -0
  69. package/dist/react/blocks.d.ts +320 -0
  70. package/dist/react/blocks.js +226 -0
  71. package/dist/react/index.cjs +901 -0
  72. package/dist/react/index.d.cts +992 -0
  73. package/dist/react/index.d.ts +992 -0
  74. package/dist/react/index.js +872 -0
  75. package/dist/react/tracking.cjs +243 -0
  76. package/dist/react/tracking.d.cts +364 -0
  77. package/dist/react/tracking.d.ts +364 -0
  78. package/dist/react/tracking.js +216 -0
  79. package/dist/react/variant.cjs +59 -0
  80. package/dist/react/variant.d.cts +26 -0
  81. package/dist/react/variant.d.ts +26 -0
  82. package/dist/react/variant.js +57 -0
  83. package/package.json +303 -0
package/dist/db.d.ts ADDED
@@ -0,0 +1,128 @@
1
+ type SchemaNamespace = 'cms';
2
+ type ColumnScalarType = 'text' | 'boolean' | 'integer' | 'timestamp' | 'jsonb' | 'tsvector';
3
+ type ColumnType<EnumTarget extends string = string> = ColumnScalarType | {
4
+ enum: EnumTarget;
5
+ };
6
+ type DefaultValue = {
7
+ kind: 'literal';
8
+ value: boolean | number | string | string[] | Record<string, unknown>;
9
+ } | {
10
+ kind: 'sql';
11
+ value: string;
12
+ };
13
+ type ForeignKeyAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default';
14
+ type IndexUsing = 'btree' | 'gin';
15
+ type ColumnDefinition<ReferenceTarget extends string = string, EnumTarget extends string = string> = {
16
+ type: ColumnType<EnumTarget>;
17
+ columnName?: string;
18
+ notNull?: boolean;
19
+ primaryKey?: boolean;
20
+ unique?: boolean;
21
+ default?: DefaultValue;
22
+ defaultId?: boolean;
23
+ defaultIdPrefix?: string;
24
+ defaultNow?: boolean;
25
+ jsonType?: string;
26
+ references?: {
27
+ table: ReferenceTarget;
28
+ column: string;
29
+ onDelete?: ForeignKeyAction;
30
+ onUpdate?: ForeignKeyAction;
31
+ };
32
+ };
33
+ type TableColumns<ReferenceTarget extends string = string, EnumTarget extends string = string> = Record<string, ColumnDefinition<ReferenceTarget, EnumTarget>>;
34
+ type IndexDefinition<ColumnName extends string> = {
35
+ columns: readonly ColumnName[];
36
+ unique?: boolean;
37
+ using?: IndexUsing;
38
+ where?: string;
39
+ };
40
+ type CompositePrimaryKey<ColumnName extends string> = {
41
+ columns: readonly ColumnName[];
42
+ };
43
+ type TableLevelForeignKey<ColumnName extends string = string> = {
44
+ columns: readonly ColumnName[];
45
+ foreignTable: string;
46
+ foreignColumns: readonly string[];
47
+ name?: string;
48
+ onDelete?: ForeignKeyAction;
49
+ onUpdate?: ForeignKeyAction;
50
+ };
51
+ type TableDefinition<Columns extends TableColumns = TableColumns, ReferenceTarget extends string = string, EnumTarget extends string = string> = {
52
+ tableName?: string;
53
+ indexPrefix?: string;
54
+ columns: Columns;
55
+ indexes?: Record<string, IndexDefinition<Extract<keyof Columns, string>>>;
56
+ compositePrimaryKey?: CompositePrimaryKey<Extract<keyof Columns, string>>;
57
+ foreignKeys?: TableLevelForeignKey<Extract<keyof Columns, string>>[];
58
+ };
59
+ type TableExtension<ExistingColumns extends TableColumns, AddedColumns extends TableColumns> = {
60
+ columns: AddedColumns;
61
+ indexes?: Record<string, IndexDefinition<Extract<keyof ExistingColumns | keyof AddedColumns, string>>>;
62
+ };
63
+ type EnumDefinition = {
64
+ values: readonly string[];
65
+ enumName?: string;
66
+ };
67
+ type EnumMap = Record<string, EnumDefinition>;
68
+ type TableMap = Record<string, TableDefinition>;
69
+ type TableColumnsOf<TTable> = TTable extends TableDefinition<infer TColumns, any, any> ? TColumns : never;
70
+ type ExtensionMap<ExistingTables extends TableMap, OwnTables extends TableMap = {}> = Partial<{
71
+ [K in keyof ExistingTables | keyof OwnTables]: TableExtension<TableColumnsOf<(ExistingTables & OwnTables)[K]>, TableColumns>;
72
+ }>;
73
+ type SchemaModule<_Namespace extends SchemaNamespace = SchemaNamespace, Tables extends TableMap = {}, Enums extends EnumMap = {}, Extensions = {}> = {
74
+ enums?: Enums;
75
+ tables?: Tables;
76
+ extend?: Extensions;
77
+ };
78
+ type ResolvedEnum = EnumDefinition & {
79
+ key: string;
80
+ dbName: string;
81
+ };
82
+ type ResolvedTable = {
83
+ key: string;
84
+ dbName: string;
85
+ indexPrefix?: string;
86
+ columns: TableColumns;
87
+ indexes: Record<string, IndexDefinition<string>>;
88
+ compositePrimaryKey?: CompositePrimaryKey<string>;
89
+ foreignKeys?: TableLevelForeignKey[];
90
+ };
91
+ type MergedSchema = {
92
+ enums: Record<string, ResolvedEnum>;
93
+ tables: Record<string, ResolvedTable>;
94
+ };
95
+
96
+ type SchemaInput<Tables extends TableMap, Enums extends EnumMap> = {
97
+ enums?: Enums;
98
+ tables: Tables;
99
+ };
100
+ declare function defineColumns<TColumns extends TableColumns>(columns: TColumns): TColumns;
101
+ declare function defineTable<TTable extends TableDefinition>(table: TTable): TTable;
102
+ declare function defineCoreSchema<Tables extends TableMap, Enums extends EnumMap = {}>(schema: SchemaInput<Tables, Enums>): SchemaModule<'cms', Tables, Enums> & {
103
+ tables: Tables;
104
+ };
105
+ declare function definePluginSchema<ExistingTables extends TableMap, _ExistingEnums extends EnumMap = {}, Tables extends TableMap = {}, Enums extends EnumMap = {}, Extensions extends ExtensionMap<ExistingTables, Tables> = {}>(schema: {
106
+ enums?: Enums;
107
+ tables?: Tables;
108
+ extend?: Extensions;
109
+ }): SchemaModule<'cms', Tables, Enums, Extensions>;
110
+
111
+ type SchemaSource = {
112
+ name: string;
113
+ schema: SchemaModule;
114
+ };
115
+ declare function toSnakeCase(value: string): string;
116
+ declare function mergeSchemaSources(sources: SchemaSource[]): MergedSchema;
117
+
118
+ type EmitOptions = {
119
+ /**
120
+ * Override the ID generation import statement.
121
+ * Defaults to `import { newId } from '@createcms/core/nanoid';`
122
+ */
123
+ nanoidImport?: string;
124
+ };
125
+ declare function emitDrizzleSchema(schema: MergedSchema, options?: EmitOptions): string;
126
+
127
+ export { defineColumns, defineCoreSchema, definePluginSchema, defineTable, emitDrizzleSchema, mergeSchemaSources, toSnakeCase };
128
+ export type { ColumnDefinition, ColumnScalarType, ColumnType, CompositePrimaryKey, DefaultValue, EmitOptions, EnumDefinition, EnumMap, ExtensionMap, ForeignKeyAction, IndexDefinition, MergedSchema, ResolvedEnum, ResolvedTable, SchemaModule, SchemaSource, TableColumns, TableDefinition, TableExtension, TableLevelForeignKey, TableMap };
package/dist/db.js ADDED
@@ -0,0 +1,488 @@
1
+ function defineColumns(columns) {
2
+ return columns;
3
+ }
4
+ function defineTable(table) {
5
+ return table;
6
+ }
7
+ function defineCoreSchema(schema) {
8
+ return {
9
+ ...schema
10
+ };
11
+ }
12
+ function definePluginSchema(schema) {
13
+ return {
14
+ ...schema
15
+ };
16
+ }
17
+
18
+ function toSnakeCase(value) {
19
+ return value.replace(/([a-z0-9])([A-Z])/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase();
20
+ }
21
+ function cloneColumns(columns) {
22
+ return Object.fromEntries(Object.entries(columns).map(([key, value])=>[
23
+ key,
24
+ {
25
+ ...value
26
+ }
27
+ ]));
28
+ }
29
+ function cloneIndexes(indexes) {
30
+ return Object.fromEntries(Object.entries(indexes).map(([key, value])=>[
31
+ key,
32
+ {
33
+ ...value,
34
+ columns: [
35
+ ...value.columns
36
+ ]
37
+ }
38
+ ]));
39
+ }
40
+ function cloneEnum(enumDef) {
41
+ return {
42
+ ...enumDef,
43
+ key: '',
44
+ dbName: '',
45
+ values: [
46
+ ...enumDef.values
47
+ ]
48
+ };
49
+ }
50
+ function mergeSchemaSources(sources) {
51
+ const enums = {};
52
+ const tables = {};
53
+ for (const source of sources){
54
+ const sourceEnums = source.schema.enums ?? {};
55
+ for (const [enumKey, enumDef] of Object.entries(sourceEnums)){
56
+ if (enums[enumKey]) {
57
+ throw new Error(`Duplicate enum "${enumKey}" declared by "${source.name}".`);
58
+ }
59
+ const resolved = cloneEnum(enumDef);
60
+ resolved.key = enumKey;
61
+ resolved.dbName = enumDef.enumName ?? toSnakeCase(enumKey);
62
+ enums[enumKey] = resolved;
63
+ }
64
+ const sourceTables = source.schema.tables ?? {};
65
+ for (const [tableKey, tableDef] of Object.entries(sourceTables)){
66
+ if (tables[tableKey]) {
67
+ throw new Error(`Duplicate table "${tableKey}" declared by "${source.name}".`);
68
+ }
69
+ const resolved = {
70
+ key: tableKey,
71
+ dbName: tableDef.tableName ?? toSnakeCase(tableKey),
72
+ indexPrefix: tableDef.indexPrefix,
73
+ columns: cloneColumns(tableDef.columns),
74
+ indexes: cloneIndexes(Object.fromEntries(Object.entries(tableDef.indexes ?? {}).map(([indexKey, indexDef])=>[
75
+ indexKey,
76
+ {
77
+ ...indexDef,
78
+ columns: [
79
+ ...indexDef.columns
80
+ ]
81
+ }
82
+ ]))),
83
+ compositePrimaryKey: tableDef.compositePrimaryKey ? {
84
+ columns: [
85
+ ...tableDef.compositePrimaryKey.columns
86
+ ]
87
+ } : undefined,
88
+ foreignKeys: tableDef.foreignKeys ? tableDef.foreignKeys.map((fk)=>({
89
+ ...fk,
90
+ columns: [
91
+ ...fk.columns
92
+ ],
93
+ foreignColumns: [
94
+ ...fk.foreignColumns
95
+ ]
96
+ })) : undefined
97
+ };
98
+ tables[tableKey] = resolved;
99
+ }
100
+ }
101
+ // Phase 2: Apply extensions
102
+ for (const source of sources){
103
+ const sourceExtensions = source.schema.extend ?? {};
104
+ for (const [targetTableKey, extension] of Object.entries(sourceExtensions)){
105
+ const targetTable = tables[targetTableKey];
106
+ if (!targetTable) {
107
+ throw new Error(`Schema source "${source.name}" extends unknown table "${targetTableKey}".`);
108
+ }
109
+ for (const [columnKey, columnDef] of Object.entries(extension.columns)){
110
+ if (targetTable.columns[columnKey]) {
111
+ throw new Error(`Schema source "${source.name}" tried to add duplicate column "${columnKey}" to "${targetTableKey}".`);
112
+ }
113
+ targetTable.columns[columnKey] = {
114
+ ...columnDef
115
+ };
116
+ }
117
+ for (const [indexKey, indexDef] of Object.entries(extension.indexes ?? {})){
118
+ if (targetTable.indexes[indexKey]) {
119
+ throw new Error(`Schema source "${source.name}" tried to add duplicate index "${indexKey}" to "${targetTableKey}".`);
120
+ }
121
+ targetTable.indexes[indexKey] = {
122
+ ...indexDef,
123
+ columns: [
124
+ ...indexDef.columns
125
+ ]
126
+ };
127
+ }
128
+ }
129
+ }
130
+ // Phase 3: Validation
131
+ const enumDbNames = new Set();
132
+ for (const enumDef of Object.values(enums)){
133
+ if (enumDbNames.has(enumDef.dbName)) {
134
+ throw new Error(`Duplicate enum database name "${enumDef.dbName}".`);
135
+ }
136
+ enumDbNames.add(enumDef.dbName);
137
+ }
138
+ const tableDbNames = new Set();
139
+ for (const table of Object.values(tables)){
140
+ if (tableDbNames.has(table.dbName)) {
141
+ throw new Error(`Duplicate table database name "${table.dbName}".`);
142
+ }
143
+ tableDbNames.add(table.dbName);
144
+ for (const [columnKey, columnDef] of Object.entries(table.columns)){
145
+ if (typeof columnDef.type === 'object') {
146
+ const enumName = columnDef.type.enum;
147
+ if (!enums[enumName]) {
148
+ throw new Error(`Column "${table.key}.${columnKey}" references unknown enum "${enumName}".`);
149
+ }
150
+ }
151
+ if (columnDef.references) {
152
+ const referencedTable = tables[columnDef.references.table];
153
+ if (!referencedTable) {
154
+ throw new Error(`Column "${table.key}.${columnKey}" references unknown table "${columnDef.references.table}".`);
155
+ }
156
+ if (!referencedTable.columns[columnDef.references.column]) {
157
+ throw new Error(`Column "${table.key}.${columnKey}" references unknown column "${columnDef.references.table}.${columnDef.references.column}".`);
158
+ }
159
+ }
160
+ }
161
+ for (const [indexKey, indexDef] of Object.entries(table.indexes)){
162
+ for (const columnName of indexDef.columns){
163
+ if (!table.columns[columnName]) {
164
+ throw new Error(`Index "${table.key}.${indexKey}" references unknown column "${columnName}".`);
165
+ }
166
+ }
167
+ }
168
+ if (table.foreignKeys) {
169
+ for (const fk of table.foreignKeys){
170
+ for (const col of fk.columns){
171
+ if (!table.columns[col]) {
172
+ throw new Error(`Foreign key in "${table.key}" references unknown local column "${col}".`);
173
+ }
174
+ }
175
+ const refTable = tables[fk.foreignTable];
176
+ if (!refTable) {
177
+ throw new Error(`Foreign key in "${table.key}" references unknown table "${fk.foreignTable}".`);
178
+ }
179
+ for (const col of fk.foreignColumns){
180
+ if (!refTable.columns[col]) {
181
+ throw new Error(`Foreign key in "${table.key}" references unknown column "${fk.foreignTable}.${col}".`);
182
+ }
183
+ }
184
+ }
185
+ }
186
+ }
187
+ return {
188
+ enums,
189
+ tables
190
+ };
191
+ }
192
+
193
+ function quote(value) {
194
+ return JSON.stringify(value);
195
+ }
196
+ function toPascalCase(value) {
197
+ return value.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_\-\s]+/g, ' ').split(' ').filter(Boolean).map((part)=>part.charAt(0).toUpperCase() + part.slice(1)).join('');
198
+ }
199
+ function singularize(value) {
200
+ if (value.endsWith('ies')) {
201
+ return `${value.slice(0, -3)}y`;
202
+ }
203
+ if (value.endsWith('ches') || value.endsWith('shes') || value.endsWith('xes') || value.endsWith('zes')) {
204
+ return value.slice(0, -2);
205
+ }
206
+ if (value.endsWith('s') && !value.endsWith('ss')) {
207
+ return value.slice(0, -1);
208
+ }
209
+ return value;
210
+ }
211
+ function emitLiteral(value) {
212
+ return JSON.stringify(value.value);
213
+ }
214
+ function emitDefault(defaultValue) {
215
+ switch(defaultValue.kind){
216
+ case 'literal':
217
+ return {
218
+ code: `.default(${emitLiteral(defaultValue)})`,
219
+ needsSql: false
220
+ };
221
+ case 'sql':
222
+ return {
223
+ code: `.default(sql.raw(${quote(defaultValue.value)}))`,
224
+ needsSql: true
225
+ };
226
+ }
227
+ }
228
+ function emitEnum(enumDef) {
229
+ const values = `[${enumDef.values.map(quote).join(', ')}]`;
230
+ return `export const ${enumDef.key}Enum = cms.enum(${quote(enumDef.dbName)}, ${values});`;
231
+ }
232
+ function emitColumn(table, columnKey, columnDef) {
233
+ const columnName = columnDef.columnName ?? toSnakeCase(columnKey);
234
+ let builder = '';
235
+ let needsTsvector = false;
236
+ if (typeof columnDef.type === 'string') {
237
+ if (columnDef.type === 'tsvector') {
238
+ builder = `tsvectorColumn(${quote(columnName)})`;
239
+ needsTsvector = true;
240
+ } else {
241
+ builder = `${columnDef.type}(${quote(columnName)})`;
242
+ }
243
+ } else {
244
+ builder = `${columnDef.type.enum}Enum(${quote(columnName)})`;
245
+ }
246
+ let needsSql = false;
247
+ let needsAnyPgColumn = false;
248
+ if (columnDef.jsonType && typeof columnDef.type === 'string' && columnDef.type === 'jsonb') {
249
+ builder += `.$type<${columnDef.jsonType}>()`;
250
+ }
251
+ if (columnDef.primaryKey) {
252
+ builder += '.primaryKey()';
253
+ }
254
+ if (columnDef.notNull) {
255
+ builder += '.notNull()';
256
+ }
257
+ if (columnDef.unique) {
258
+ builder += '.unique()';
259
+ }
260
+ if (columnDef.defaultNow) {
261
+ builder += '.defaultNow()';
262
+ }
263
+ if (columnDef.defaultId) {
264
+ if (!columnDef.defaultIdPrefix) {
265
+ throw new Error(`Column "${columnKey}" has defaultId but no defaultIdPrefix`);
266
+ }
267
+ builder += `.$defaultFn(() => newId(${quote(columnDef.defaultIdPrefix)}))`;
268
+ }
269
+ if (columnDef.default) {
270
+ const emitted = emitDefault(columnDef.default);
271
+ builder += emitted.code;
272
+ needsSql ||= emitted.needsSql;
273
+ }
274
+ if (columnDef.references) {
275
+ const options = [];
276
+ if (columnDef.references.onDelete) {
277
+ options.push(`onDelete: ${quote(columnDef.references.onDelete)}`);
278
+ }
279
+ if (columnDef.references.onUpdate) {
280
+ options.push(`onUpdate: ${quote(columnDef.references.onUpdate)}`);
281
+ }
282
+ const suffix = options.length > 0 ? `, { ${options.join(', ')} }` : '';
283
+ const isSelfReference = columnDef.references.table === table.key;
284
+ const refCallback = isSelfReference ? `(): AnyPgColumn => ${columnDef.references.table}.${columnDef.references.column}` : `() => ${columnDef.references.table}.${columnDef.references.column}`;
285
+ needsAnyPgColumn ||= isSelfReference;
286
+ builder += `.references(${refCallback}${suffix})`;
287
+ }
288
+ return {
289
+ code: ` ${columnKey}: ${builder},`,
290
+ needsSql,
291
+ needsAnyPgColumn,
292
+ needsTsvector
293
+ };
294
+ }
295
+ function emitIndexes(table) {
296
+ const entries = Object.entries(table.indexes);
297
+ if (entries.length === 0) {
298
+ return [];
299
+ }
300
+ const prefix = table.indexPrefix ?? table.dbName;
301
+ return entries.map(([indexKey, indexDef])=>{
302
+ const factory = indexDef.unique ? 'uniqueIndex' : 'index';
303
+ const columns = indexDef.columns.map((column)=>`table.${column}`).join(', ');
304
+ let line;
305
+ if (indexDef.using && indexDef.using !== 'btree') {
306
+ line = ` ${factory}(${quote(`${prefix}_${toSnakeCase(indexKey)}`)}).using(${quote(indexDef.using)}, ${columns})`;
307
+ } else {
308
+ line = ` ${factory}(${quote(`${prefix}_${toSnakeCase(indexKey)}`)}).on(${columns})`;
309
+ }
310
+ if (indexDef.where) {
311
+ line += `.where(sql\`${indexDef.where}\`)`;
312
+ }
313
+ return `${line},`;
314
+ });
315
+ }
316
+ function emitCompositePrimaryKey(table) {
317
+ if (!table.compositePrimaryKey) return null;
318
+ const columns = table.compositePrimaryKey.columns.map((col)=>`table.${col}`).join(', ');
319
+ return ` primaryKey({ columns: [${columns}] }),`;
320
+ }
321
+ function emitTableLevelForeignKeys(table) {
322
+ if (!table.foreignKeys || table.foreignKeys.length === 0) {
323
+ return {
324
+ lines: [],
325
+ needsForeignKeyImport: false
326
+ };
327
+ }
328
+ const lines = table.foreignKeys.map((fk)=>{
329
+ const localCols = fk.columns.map((c)=>`table.${c}`).join(', ');
330
+ const isSelfReference = fk.foreignTable === table.key;
331
+ const foreignCols = fk.foreignColumns.map((c)=>`${isSelfReference ? 'table' : fk.foreignTable}.${c}`).join(', ');
332
+ const parts = [
333
+ ` columns: [${localCols}],`,
334
+ ` foreignColumns: [${foreignCols}],`
335
+ ];
336
+ if (fk.name) {
337
+ parts.push(` name: ${quote(fk.name)},`);
338
+ }
339
+ let chain = '';
340
+ if (fk.onDelete) {
341
+ chain += `.onDelete(${quote(fk.onDelete)})`;
342
+ }
343
+ if (fk.onUpdate) {
344
+ chain += `.onUpdate(${quote(fk.onUpdate)})`;
345
+ }
346
+ return ` foreignKey({\n${parts.join('\n')}\n })${chain},`;
347
+ });
348
+ return {
349
+ lines,
350
+ needsForeignKeyImport: true
351
+ };
352
+ }
353
+ function emitTableTypeAliases(table) {
354
+ const baseName = toPascalCase(singularize(table.key));
355
+ return `export type ${baseName} = typeof ${table.key}.$inferSelect;
356
+ export type New${baseName} = typeof ${table.key}.$inferInsert;`;
357
+ }
358
+ function emitTable(table) {
359
+ let needsSql = false;
360
+ let needsAnyPgColumn = false;
361
+ let needsForeignKeyImport = false;
362
+ let needsPrimaryKeyImport = false;
363
+ let needsTsvector = false;
364
+ const emittedColumns = Object.entries(table.columns).map(([columnKey, columnDef])=>{
365
+ const emitted = emitColumn(table, columnKey, columnDef);
366
+ needsSql ||= emitted.needsSql;
367
+ needsAnyPgColumn ||= emitted.needsAnyPgColumn;
368
+ needsTsvector ||= emitted.needsTsvector;
369
+ return emitted.code;
370
+ });
371
+ const indexes = emitIndexes(table);
372
+ for (const idx of Object.values(table.indexes)){
373
+ if (idx.where) needsSql = true;
374
+ }
375
+ const compositePK = emitCompositePrimaryKey(table);
376
+ if (compositePK) needsPrimaryKeyImport = true;
377
+ const { lines: fkLines, needsForeignKeyImport: needsFK } = emitTableLevelForeignKeys(table);
378
+ needsForeignKeyImport = needsFK;
379
+ const tableFactory = 'cms.table';
380
+ const callbackLines = [
381
+ ...compositePK ? [
382
+ compositePK
383
+ ] : [],
384
+ ...fkLines,
385
+ ...indexes
386
+ ];
387
+ const callback = callbackLines.length > 0 ? `,
388
+ (table) => [
389
+ ${callbackLines.join('\n')}
390
+ ]` : '';
391
+ return {
392
+ code: `export const ${table.key} = ${tableFactory}(
393
+ ${quote(table.dbName)},
394
+ {
395
+ ${emittedColumns.join('\n')}
396
+ }${callback},
397
+ );`,
398
+ needsSql,
399
+ needsAnyPgColumn,
400
+ needsForeignKeyImport,
401
+ needsPrimaryKeyImport,
402
+ needsTsvector
403
+ };
404
+ }
405
+ function emitDrizzleSchema(schema, options) {
406
+ const pgCoreImports = new Set([
407
+ 'pgSchema'
408
+ ]);
409
+ let needsSql = false;
410
+ let needsAnyPgColumn = false;
411
+ let needsForeignKeyImport = false;
412
+ let needsPrimaryKeyImport = false;
413
+ let needsTsvector = false;
414
+ const enums = Object.values(schema.enums).sort((a, b)=>a.key.localeCompare(b.key));
415
+ const tables = Object.values(schema.tables).sort((a, b)=>a.key.localeCompare(b.key));
416
+ for (const table of tables){
417
+ for (const column of Object.values(table.columns)){
418
+ if (typeof column.type === 'string') {
419
+ if (column.type !== 'tsvector') {
420
+ pgCoreImports.add(column.type);
421
+ }
422
+ }
423
+ if (column.default?.kind === 'sql') {
424
+ needsSql = true;
425
+ }
426
+ }
427
+ if (Object.keys(table.indexes).length > 0) {
428
+ pgCoreImports.add('index');
429
+ }
430
+ if (Object.values(table.indexes).some((indexDef)=>indexDef.unique)) {
431
+ pgCoreImports.add('uniqueIndex');
432
+ }
433
+ if (Object.values(table.indexes).some((indexDef)=>indexDef.where)) {
434
+ needsSql = true;
435
+ }
436
+ }
437
+ const enumBlocks = enums.map(emitEnum);
438
+ const tableBlocks = tables.map((table)=>{
439
+ const emitted = emitTable(table);
440
+ needsSql ||= emitted.needsSql;
441
+ needsAnyPgColumn ||= emitted.needsAnyPgColumn;
442
+ needsForeignKeyImport ||= emitted.needsForeignKeyImport;
443
+ needsPrimaryKeyImport ||= emitted.needsPrimaryKeyImport;
444
+ needsTsvector ||= emitted.needsTsvector;
445
+ return emitted.code;
446
+ });
447
+ const typeBlocks = tables.map(emitTableTypeAliases);
448
+ if (needsForeignKeyImport) pgCoreImports.add('foreignKey');
449
+ if (needsPrimaryKeyImport) pgCoreImports.add('primaryKey');
450
+ if (needsTsvector) pgCoreImports.add('customType');
451
+ const imports = [];
452
+ if (needsSql) {
453
+ imports.push(`import { sql } from 'drizzle-orm';`);
454
+ }
455
+ imports.push(`import { ${Array.from(pgCoreImports).sort().join(', ')} } from 'drizzle-orm/pg-core';`);
456
+ if (needsAnyPgColumn) {
457
+ imports.push(`import type { AnyPgColumn } from 'drizzle-orm/pg-core';`);
458
+ }
459
+ const needsNewId = tables.some((table)=>Object.values(table.columns).some((col)=>col.defaultId));
460
+ if (needsNewId) {
461
+ imports.push(options?.nanoidImport ?? `import { newId } from '@createcms/core/nanoid';`);
462
+ }
463
+ const tsvectorDef = needsTsvector ? `\nconst tsvectorColumn = customType<{ data: string }>({
464
+ dataType() { return 'tsvector'; },
465
+ });\n` : '';
466
+ const schemaExport = `export const schema = {
467
+ ${tables.map((table)=>` ${table.key},`).join('\n')}
468
+ ${enums.map((enumDef)=>` ${enumDef.key}Enum,`).join('\n')}
469
+ };`;
470
+ return `/* eslint-disable */
471
+ /**
472
+ * This file is generated by createcms.
473
+ * Do not edit manually.
474
+ */
475
+
476
+ ${imports.join('\n')}
477
+
478
+ export const cms = pgSchema('cms');
479
+ ${tsvectorDef}${enumBlocks.join('\n\n')}
480
+ ${enumBlocks.length > 0 && tableBlocks.length > 0 ? '\n' : ''}${tableBlocks.join('\n\n')}
481
+
482
+ ${schemaExport}
483
+
484
+ ${typeBlocks.join('\n\n')}
485
+ `;
486
+ }
487
+
488
+ export { defineColumns, defineCoreSchema, definePluginSchema, defineTable, emitDrizzleSchema, mergeSchemaSources, toSnakeCase };