nextjs-cms-kit 0.5.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 (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -0
  3. package/dist/commands/db-config.d.ts +3 -0
  4. package/dist/commands/db-config.d.ts.map +1 -0
  5. package/dist/commands/db-config.js +20 -0
  6. package/dist/commands/fix-master-admin.d.ts +3 -0
  7. package/dist/commands/fix-master-admin.d.ts.map +1 -0
  8. package/dist/commands/fix-master-admin.js +19 -0
  9. package/dist/commands/set-master-admin.d.ts +3 -0
  10. package/dist/commands/set-master-admin.d.ts.map +1 -0
  11. package/dist/commands/set-master-admin.js +29 -0
  12. package/dist/commands/setup.d.ts +3 -0
  13. package/dist/commands/setup.d.ts.map +1 -0
  14. package/dist/commands/setup.js +61 -0
  15. package/dist/commands/update-sections.d.ts +3 -0
  16. package/dist/commands/update-sections.d.ts.map +1 -0
  17. package/dist/commands/update-sections.js +33 -0
  18. package/dist/index.d.ts +5 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +38 -0
  21. package/dist/lib/actions.d.ts +7 -0
  22. package/dist/lib/actions.d.ts.map +1 -0
  23. package/dist/lib/actions.js +62 -0
  24. package/dist/lib/add-table-keys.d.ts +32 -0
  25. package/dist/lib/add-table-keys.d.ts.map +1 -0
  26. package/dist/lib/add-table-keys.js +168 -0
  27. package/dist/lib/db-config-setup.d.ts +4 -0
  28. package/dist/lib/db-config-setup.d.ts.map +1 -0
  29. package/dist/lib/db-config-setup.js +216 -0
  30. package/dist/lib/fix-master-admin.d.ts +2 -0
  31. package/dist/lib/fix-master-admin.d.ts.map +1 -0
  32. package/dist/lib/fix-master-admin.js +7 -0
  33. package/dist/lib/reload-env.d.ts +16 -0
  34. package/dist/lib/reload-env.d.ts.map +1 -0
  35. package/dist/lib/reload-env.js +42 -0
  36. package/dist/lib/schema-generator.d.ts +10 -0
  37. package/dist/lib/schema-generator.d.ts.map +1 -0
  38. package/dist/lib/schema-generator.js +168 -0
  39. package/dist/lib/set-master-admin.d.ts +2 -0
  40. package/dist/lib/set-master-admin.d.ts.map +1 -0
  41. package/dist/lib/set-master-admin.js +53 -0
  42. package/dist/lib/update-sections.d.ts +2 -0
  43. package/dist/lib/update-sections.d.ts.map +1 -0
  44. package/dist/lib/update-sections.js +898 -0
  45. package/package.json +55 -0
@@ -0,0 +1,168 @@
1
+ import chalk from 'chalk';
2
+ import { db } from 'nextjs-cms/db/client';
3
+ export async function addTableKeys(table, existingKeys) {
4
+ // console.log(chalk.gray(` - Checking table keys`))
5
+ /**
6
+ * Number of SQL errors
7
+ */
8
+ let sqlErrors = 0;
9
+ /**
10
+ * Add the primary key, but first, check if the primary key exists or has changed
11
+ */
12
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
13
+ if (table.primaryKey) {
14
+ if (existingKeys) {
15
+ const { primaryKeys } = existingKeys;
16
+ /**
17
+ * Check if the existing primary key matches the new primary key
18
+ */
19
+ const primaryKeyChanged = primaryKeys.length !== table.primaryKey.length ||
20
+ !table.primaryKey.every((key) => primaryKeys.includes(key.name));
21
+ /**
22
+ * If primary key doesn't exist or has changed, update it
23
+ */
24
+ if (primaryKeys.length === 0 || primaryKeyChanged) {
25
+ /**
26
+ * Drop existing primary key if it exists
27
+ */
28
+ if (primaryKeys.length > 0) {
29
+ console.log(chalk.gray(` - Dropping existing primary key from '${table.name}: [${primaryKeys.join(', ')}]`));
30
+ try {
31
+ await db.execute(`ALTER TABLE \`${table.name}\` DROP PRIMARY KEY`);
32
+ }
33
+ catch (error) {
34
+ sqlErrors++;
35
+ console.error(chalk.red(` - Error dropping primary key for table '${table.name}':`, error));
36
+ }
37
+ }
38
+ /**
39
+ * Add the new primary key
40
+ */
41
+ console.log(chalk.gray(` - Adding primary key to '${table.name}': [${table.primaryKey.map((key) => key.name).join(', ')}]`));
42
+ try {
43
+ const primaryKeyColumns = table.primaryKey.map((column) => `\`${column.name}\``).join(', ');
44
+ await db.execute(`ALTER TABLE \`${table.name}\` ADD PRIMARY KEY (${primaryKeyColumns})`);
45
+ }
46
+ catch (error) {
47
+ sqlErrors++;
48
+ console.error(chalk.red(` - Error updating primary key for table '${table.name}':`, error));
49
+ /**
50
+ * Reverting to the old primary key
51
+ */
52
+ console.log(chalk.gray(` - Re-adding old primary key to '${table.name}': [${primaryKeys.map((key) => key).join(', ')}]`));
53
+ try {
54
+ const primaryKeyColumns = primaryKeys.map((column) => `\`${column}\``).join(', ');
55
+ await db.execute(`ALTER TABLE \`${table.name}\` ADD PRIMARY KEY (${primaryKeyColumns})`);
56
+ }
57
+ catch (error) {
58
+ sqlErrors++;
59
+ console.error(chalk.red(` - Error re-adding primary key for table '${table.name}':`, error));
60
+ }
61
+ }
62
+ }
63
+ }
64
+ else {
65
+ // TODO: What is this?
66
+ sqlErrors++;
67
+ }
68
+ }
69
+ /**
70
+ * Modify unique keys
71
+ */
72
+ if (table.unique) {
73
+ const existingUniqueKeys = existingKeys?.uniqueKeys ?? [];
74
+ for (const requestedUnique of table.unique) {
75
+ /**
76
+ * Check if the unique key already exists
77
+ */
78
+ const matchingUnique = existingUniqueKeys.find((u) => {
79
+ return (requestedUnique.columns.length === u.columns.length &&
80
+ requestedUnique.columns.every((col) => u.columns.includes(col.name)));
81
+ });
82
+ const uniqueColumns = requestedUnique.columns.map((col) => `\`${col.name}\``).join(', ');
83
+ /**
84
+ * If key doesn't exist, add it
85
+ */
86
+ if (!matchingUnique) {
87
+ console.log(chalk.gray(` - Adding unique key with columns [${requestedUnique.columns.map((col) => col.name).join(', ')}] to '${table.name}'`));
88
+ await db.execute(`ALTER TABLE \`${table.name}\` ADD UNIQUE ${requestedUnique.name ?? ''}(${uniqueColumns})`);
89
+ }
90
+ }
91
+ /**
92
+ * Drop any existing unique keys that are not in the new set (based on columns)
93
+ */
94
+ for (const existingUnique of existingUniqueKeys) {
95
+ if (!table.unique.find((unique) => {
96
+ return (unique.columns.length === existingUnique.columns.length &&
97
+ unique.columns.every((col) => existingUnique.columns.includes(col.name)));
98
+ })) {
99
+ console.log(chalk.gray(` - Dropping unique key with columns [${existingUnique.columns.join(', ')}] from '${table.name}'`));
100
+ await db.execute(`ALTER TABLE \`${table.name}\` DROP INDEX \`${existingUnique.name}\``);
101
+ }
102
+ }
103
+ }
104
+ /**
105
+ * Modify indexes
106
+ */
107
+ if (table.index) {
108
+ const existingIndexes = existingKeys?.indexKeys ?? [];
109
+ for (const index of table.index) {
110
+ const matchingIndex = existingIndexes.find((i) => {
111
+ return (index.columns.length === i.columns.length &&
112
+ index.columns.every((col) => i.columns.includes(col.name)));
113
+ });
114
+ const indexColumns = index.columns.map((col) => `\`${col.name}\``).join(', ');
115
+ if (!matchingIndex) {
116
+ // Add index
117
+ console.log(chalk.gray(` - Adding index with columns [${index.columns.map((col) => col.name).join(', ')}] to '${table.name}'`));
118
+ await db.execute(`ALTER TABLE \`${table.name}\` ADD INDEX ${index.name ?? ''}(${indexColumns})`);
119
+ }
120
+ }
121
+ /**
122
+ * Drop any existing indexes that are not in the new set (based on columns)
123
+ */
124
+ for (const existingIndex of existingIndexes) {
125
+ if (!table.index.find((index) => {
126
+ return (index.columns.length === existingIndex.columns.length &&
127
+ index.columns.every((col) => existingIndex.columns.includes(col.name)));
128
+ })) {
129
+ console.log(chalk.gray(` - Dropping index with columns [${existingIndex.columns.join(', ')}] from '${table.name}'`));
130
+ await db.execute(`ALTER TABLE \`${table.name}\` DROP INDEX \`${existingIndex.name}\``);
131
+ }
132
+ }
133
+ }
134
+ /**
135
+ * Modify fulltext indexes
136
+ */
137
+ if (table.fulltext) {
138
+ const existingIndexes = existingKeys?.fullTextKeys ?? [];
139
+ for (const requestedFullTextIndex of table.fulltext) {
140
+ const matchingFulltext = existingIndexes.find((i) => {
141
+ return (requestedFullTextIndex.columns.length === i.columns.length &&
142
+ requestedFullTextIndex.columns.every((col) => i.columns.includes(col.name)));
143
+ });
144
+ const fulltextColumns = requestedFullTextIndex.columns.map((col) => `\`${col.name}\``).join(', ');
145
+ /**
146
+ * If fulltext index doesn't exist, add it
147
+ */
148
+ if (!matchingFulltext) {
149
+ // Add fulltext index
150
+ console.log(chalk.gray(` - Adding fulltext index with columns [${requestedFullTextIndex.columns.map((col) => col.name).join(', ')}] to '${table.name}'`));
151
+ await db.execute(`ALTER TABLE \`${table.name}\` ADD FULLTEXT ${requestedFullTextIndex.name ?? ''}(${fulltextColumns})`);
152
+ }
153
+ }
154
+ /**
155
+ * Drop any existing fulltext indexes that are not in the new set (based on columns)
156
+ */
157
+ for (const existingFulltext of existingIndexes) {
158
+ if (!table.fulltext.find((fulltext) => {
159
+ return (fulltext.columns.length === existingFulltext.columns.length &&
160
+ fulltext.columns.every((col) => existingFulltext.columns.includes(col.name)));
161
+ })) {
162
+ console.log(chalk.gray(` - Dropping fulltext index with columns [${existingFulltext.columns.join(', ')}] from '${table.name}'`));
163
+ await db.execute(`ALTER TABLE \`${table.name}\` DROP INDEX \`${existingFulltext.name}\``);
164
+ }
165
+ }
166
+ }
167
+ return sqlErrors;
168
+ }
@@ -0,0 +1,4 @@
1
+ export declare function dbConfigSetup(options: {
2
+ dev: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=db-config-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-config-setup.d.ts","sourceRoot":"","sources":["../../src/lib/db-config-setup.ts"],"names":[],"mappings":"AAkCA,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,iBAqN5D"}
@@ -0,0 +1,216 @@
1
+ import { createConnection } from 'mysql2/promise';
2
+ import { intro, isCancel, outro, text, spinner, note } from '@clack/prompts';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { cwd } from 'process';
6
+ import { reloadAndUpdateEnvironmentVariables } from './reload-env';
7
+ /**
8
+ * Removes specific environment variables from the .env file content
9
+ * Removes both the generated comment block and the individual variable lines
10
+ */
11
+ function removeEnvVariables(content, variables) {
12
+ let result = content;
13
+ // Remove the generated block comment if it exists (including the markers)
14
+ const blockRegex = /\n*####\s*\n#\s*generated by the init script\s*\n####\s*\n?/g;
15
+ result = result.replace(blockRegex, '\n');
16
+ // Remove individual variable lines (entire lines including newline)
17
+ variables.forEach((variable) => {
18
+ result = result.replace(new RegExp(`^${variable}=.*$\\n?`, 'gm'), '');
19
+ });
20
+ return result;
21
+ }
22
+ /**
23
+ * Validates if a string is a valid port number
24
+ */
25
+ function isValidPort(value) {
26
+ const port = parseInt(value, 10);
27
+ return !isNaN(port) && port > 0 && port <= 65535;
28
+ }
29
+ export async function dbConfigSetup(options) {
30
+ const { dev = false } = options;
31
+ intro(`Welcome to LZCMS! Let's set up the database...`);
32
+ /**
33
+ * Step 1: Ask for connection credentials
34
+ */
35
+ note('Please provide your MySQL/MariaDB server credentials', 'Database Connection');
36
+ const dbHost = await text({
37
+ message: 'Database host:',
38
+ placeholder: 'localhost',
39
+ defaultValue: 'localhost',
40
+ validate(value) {
41
+ if (value && value.length < 2)
42
+ return `Database host must be at least 2 characters`;
43
+ },
44
+ });
45
+ if (isCancel(dbHost)) {
46
+ outro(`LZCMS init cancelled by user.`);
47
+ return;
48
+ }
49
+ const dbPort = await text({
50
+ message: 'Database port:',
51
+ placeholder: '3306',
52
+ defaultValue: '3306',
53
+ validate(value) {
54
+ if (value && !isValidPort(value)) {
55
+ return `Database port must be a valid number between 1 and 65535`;
56
+ }
57
+ },
58
+ });
59
+ if (isCancel(dbPort)) {
60
+ outro(`LZCMS init cancelled by user.`);
61
+ return;
62
+ }
63
+ const dbUser = await text({
64
+ message: 'Database username:',
65
+ validate(value) {
66
+ if (value.length < 1)
67
+ return `Database username is required`;
68
+ },
69
+ });
70
+ if (isCancel(dbUser)) {
71
+ outro(`LZCMS init cancelled by user.`);
72
+ return;
73
+ }
74
+ const dbPassword = await text({
75
+ message: 'Database password:',
76
+ validate(value) {
77
+ if (value.length < 1)
78
+ return `Database password is required`;
79
+ },
80
+ });
81
+ if (isCancel(dbPassword)) {
82
+ outro(`LZCMS init cancelled by user.`);
83
+ return;
84
+ }
85
+ /**
86
+ * Step 2: Test the database connection
87
+ */
88
+ const s = spinner();
89
+ let migrationClient;
90
+ try {
91
+ s.start('Testing database connection...');
92
+ /**
93
+ * It's recommended to not use a pool connection for migrations, that's why we're creating a new connection here.
94
+ */
95
+ migrationClient = await createConnection({
96
+ host: String(dbHost),
97
+ user: String(dbUser),
98
+ password: String(dbPassword),
99
+ database: '',
100
+ port: parseInt(String(dbPort), 10),
101
+ });
102
+ s.stop('✓ Connected successfully!');
103
+ /**
104
+ * Step 3: Now that connection is successful, ask for database name
105
+ */
106
+ note('If the database does not exist, it will be created', 'Database Name');
107
+ const dbName = await text({
108
+ message: 'Database name:',
109
+ validate(value) {
110
+ if (value.length < 2)
111
+ return `Database name must be at least 2 characters`;
112
+ // Validate database name format (alphanumeric, underscore, hyphen)
113
+ if (!/^[a-zA-Z0-9_-]+$/.test(value)) {
114
+ return `Database name can only contain letters, numbers, underscores, and hyphens`;
115
+ }
116
+ },
117
+ });
118
+ if (isCancel(dbName)) {
119
+ outro(`LZCMS init cancelled by user.`);
120
+ return;
121
+ }
122
+ /**
123
+ * Step 4: Create the database
124
+ */
125
+ s.start('Creating database...');
126
+ /**
127
+ * Let's create the database using parameterized query to prevent SQL injection
128
+ */
129
+ await migrationClient.query('CREATE DATABASE IF NOT EXISTS ??', [dbName]);
130
+ s.stop('✓ Database created successfully!');
131
+ /**
132
+ * Let's save the database credentials in the .env file
133
+ */
134
+ const envPath = path.resolve(cwd(), dev ? '.env.development' : '.env.production');
135
+ /**
136
+ * If the .env file does not exist, we'll create it
137
+ */
138
+ if (!fs.existsSync(envPath)) {
139
+ fs.writeFileSync(envPath, '');
140
+ }
141
+ /**
142
+ * Read current .env content and remove existing database credentials
143
+ */
144
+ let currentEnv = fs.readFileSync(envPath, 'utf8');
145
+ currentEnv = removeEnvVariables(currentEnv, ['DB_HOST', 'DB_PORT', 'DB_NAME', 'DB_USER', 'DB_PASSWORD']);
146
+ /**
147
+ * Prepare new environment variables block
148
+ */
149
+ const newEnvBlock = `
150
+
151
+ ####
152
+ # generated by the init script
153
+ ####
154
+ DB_HOST=${dbHost}
155
+ DB_PORT=${dbPort}
156
+ DB_NAME=${dbName}
157
+ DB_USER=${dbUser}
158
+ DB_PASSWORD='${dbPassword}'
159
+ `;
160
+ /**
161
+ * Append the new credentials to the .env file
162
+ */
163
+ let finalEnv = currentEnv + newEnvBlock;
164
+ // Trim multiple consecutive empty lines to a maximum of two empty lines
165
+ finalEnv = finalEnv.replace(/(\n\s*\n){3,}/g, '\n\n');
166
+ // Trim leading whitespace
167
+ finalEnv = finalEnv.trim() + '\n';
168
+ fs.writeFileSync(envPath, finalEnv);
169
+ // Reload environment variables after writing to .env file
170
+ const dbVariables = {
171
+ DB_HOST: String(dbHost),
172
+ DB_PORT: String(dbPort),
173
+ DB_NAME: String(dbName),
174
+ DB_USER: String(dbUser),
175
+ DB_PASSWORD: String(dbPassword),
176
+ };
177
+ const reloadSuccess = reloadAndUpdateEnvironmentVariables(dbVariables, dev ? '.env.development' : '.env.production');
178
+ if (reloadSuccess) {
179
+ console.log('✓ Environment variables reloaded successfully!');
180
+ }
181
+ else {
182
+ console.warn('⚠️ Environment variables written to file but could not be reloaded in current process');
183
+ }
184
+ outro(`✓ Database setup completed successfully! Please run 'npm run lz:setup' to finish the setup.`);
185
+ }
186
+ catch (error) {
187
+ s.stop('✗ Database setup failed!');
188
+ const errorMessage = error instanceof Error ? error.message : String(error);
189
+ const errorCode = error && typeof error === 'object' && 'code' in error ? error.code : null;
190
+ // Provide specific error messages based on error type
191
+ if (errorCode === 'ER_ACCESS_DENIED_ERROR' || errorCode === 'ECONNREFUSED') {
192
+ console.error('\n❌ Connection Error:', errorMessage);
193
+ console.error('\nPlease verify:');
194
+ console.error(' • Database host and port are correct');
195
+ console.error(' • Username and password are correct');
196
+ console.error(' • Database server is running');
197
+ console.error(' • User has sufficient privileges');
198
+ }
199
+ else if (errorCode === 'ER_BAD_DB_ERROR') {
200
+ console.error('\n❌ Database Error:', errorMessage);
201
+ }
202
+ else {
203
+ console.error('\n❌ Error:', errorMessage);
204
+ }
205
+ outro(`\nSetup failed. Please check the errors above and try again.`);
206
+ process.exit(1);
207
+ }
208
+ finally {
209
+ /**
210
+ * Always close the connection, even if an error occurred
211
+ */
212
+ if (migrationClient) {
213
+ await migrationClient.end();
214
+ }
215
+ }
216
+ }
@@ -0,0 +1,2 @@
1
+ export declare function fixMasterAdmin(): Promise<void>;
2
+ //# sourceMappingURL=fix-master-admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-master-admin.d.ts","sourceRoot":"","sources":["../../src/lib/fix-master-admin.ts"],"names":[],"mappings":"AAGA,wBAAsB,cAAc,kBAInC"}
@@ -0,0 +1,7 @@
1
+ import { intro, outro } from '@clack/prompts';
2
+ import { fixMasterAdminPrivileges } from './actions';
3
+ export async function fixMasterAdmin() {
4
+ intro(`Looking up sections...`);
5
+ await fixMasterAdminPrivileges();
6
+ outro(`Master admin privileges fixed`);
7
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Reloads environment variables from .env files
3
+ * This is useful after programmatically writing to .env files
4
+ */
5
+ export declare function reloadEnvironmentVariables(envFile?: string): boolean;
6
+ /**
7
+ * Updates specific environment variables in process.env
8
+ * This provides immediate availability without requiring a full reload
9
+ */
10
+ export declare function updateEnvironmentVariables(variables: Record<string, string>): void;
11
+ /**
12
+ * Reloads environment variables and updates specific ones in process.env
13
+ * This combines both approaches for maximum compatibility
14
+ */
15
+ export declare function reloadAndUpdateEnvironmentVariables(variables?: Record<string, string>, envFile?: string): boolean;
16
+ //# sourceMappingURL=reload-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reload-env.d.ts","sourceRoot":"","sources":["../../src/lib/reload-env.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAepE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAIlF;AAED;;;GAGG;AACH,wBAAgB,mCAAmC,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAQjH"}
@@ -0,0 +1,42 @@
1
+ import { config } from 'dotenv';
2
+ import { cwd } from 'process';
3
+ import path from 'path';
4
+ /**
5
+ * Reloads environment variables from .env files
6
+ * This is useful after programmatically writing to .env files
7
+ */
8
+ export function reloadEnvironmentVariables(envFile) {
9
+ try {
10
+ const envPath = envFile ? path.resolve(cwd(), envFile) : undefined;
11
+ const result = config({ path: envPath });
12
+ if (result.error) {
13
+ console.warn('⚠️ Error loading .env file:', result.error);
14
+ return false;
15
+ }
16
+ return true;
17
+ }
18
+ catch (error) {
19
+ console.warn('⚠️ Could not reload environment variables:', error);
20
+ return false;
21
+ }
22
+ }
23
+ /**
24
+ * Updates specific environment variables in process.env
25
+ * This provides immediate availability without requiring a full reload
26
+ */
27
+ export function updateEnvironmentVariables(variables) {
28
+ Object.entries(variables).forEach(([key, value]) => {
29
+ process.env[key] = value;
30
+ });
31
+ }
32
+ /**
33
+ * Reloads environment variables and updates specific ones in process.env
34
+ * This combines both approaches for maximum compatibility
35
+ */
36
+ export function reloadAndUpdateEnvironmentVariables(variables, envFile) {
37
+ const reloadSuccess = reloadEnvironmentVariables(envFile);
38
+ if (variables) {
39
+ updateEnvironmentVariables(variables);
40
+ }
41
+ return reloadSuccess;
42
+ }
@@ -0,0 +1,10 @@
1
+ import type { FieldConfig } from 'nextjs-cms/core/fields';
2
+ export declare function generateDrizzleSchema(table: {
3
+ name: string;
4
+ fields: FieldConfig[];
5
+ identifier: FieldConfig;
6
+ }): {
7
+ schema: string;
8
+ columnTypes: string[];
9
+ };
10
+ //# sourceMappingURL=schema-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-generator.d.ts","sourceRoot":"","sources":["../../src/lib/schema-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAqBzD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,EAAE,CAAC;IAAC,UAAU,EAAE,WAAW,CAAA;CAAE,GAAG;IAC5G,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,EAAE,CAAA;CACxB,CAiKA"}
@@ -0,0 +1,168 @@
1
+ import { getCMSConfig } from 'nextjs-cms/core/config';
2
+ // Converts snake_case to camelCase
3
+ function toCamelCase(snake) {
4
+ return snake.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
5
+ }
6
+ // Converts snake_case to PascalCase
7
+ function toPascalCase(snake) {
8
+ return snake.toLowerCase().replace(/(^|_)([a-z])/g, (_, __, letter) => letter.toUpperCase());
9
+ }
10
+ // Converts any case (camelCase, PascalCase, etc.) to snake_case
11
+ function toSnakeCase(str) {
12
+ return str
13
+ .replace(/([A-Z])/g, '_$1') // Add underscore before capital letters
14
+ .replace(/^_/, '') // Remove leading underscore if any
15
+ .toLowerCase();
16
+ }
17
+ export function generateDrizzleSchema(table) {
18
+ let tableCaseStyleFn;
19
+ let columnCaseStyleFn;
20
+ const lzConfig = getCMSConfig();
21
+ switch (lzConfig.db.schemaNamingConvention.tableCaseStyle) {
22
+ case 'snakeCase':
23
+ tableCaseStyleFn = toSnakeCase;
24
+ break;
25
+ case 'camelCase':
26
+ tableCaseStyleFn = toCamelCase;
27
+ break;
28
+ case 'pascalCase':
29
+ default:
30
+ tableCaseStyleFn = toPascalCase;
31
+ break;
32
+ }
33
+ switch (lzConfig.db.schemaNamingConvention.columnCaseStyle) {
34
+ case 'snakeCase':
35
+ columnCaseStyleFn = toSnakeCase;
36
+ break;
37
+ case 'pascalCase':
38
+ columnCaseStyleFn = toPascalCase;
39
+ break;
40
+ case 'camelCase':
41
+ default:
42
+ columnCaseStyleFn = toCamelCase;
43
+ break;
44
+ }
45
+ /**
46
+ * This function generates a Drizzle schema for a given table.
47
+ * It takes a table object with a name, inputs (fields), and an identifier field.
48
+ * It returns an object containing the generated schema as a string and an array of column types.
49
+ */
50
+ const drizzleColumnTypes = [];
51
+ let schema = '';
52
+ const schemaName = tableCaseStyleFn(`${table.name}_table`);
53
+ schema += `export const ${schemaName} = mysqlTable('${table.name}', {\n`;
54
+ for (const input of table.fields) {
55
+ let columnType;
56
+ let drizzleColumnType;
57
+ // let columnOptions = ''
58
+ switch (input.type) {
59
+ case 'text':
60
+ columnType = `varchar('${input.name}', { length: ${input.maxLength ?? 255} })`;
61
+ drizzleColumnType = 'varchar';
62
+ break;
63
+ case 'textarea':
64
+ case 'rich_text':
65
+ columnType = `longtext('${input.name}')`;
66
+ drizzleColumnType = 'longtext';
67
+ break;
68
+ case 'select_multiple':
69
+ case 'password':
70
+ columnType = `varchar('${input.name}', { length: 255 })`;
71
+ drizzleColumnType = 'varchar';
72
+ break;
73
+ case 'select':
74
+ if (input.optionsType === 'static' && input.options) {
75
+ columnType = `mysqlEnum('${input.name}', [${input.options.map((option) => `'${option.value}'`).join(', ')}])`;
76
+ drizzleColumnType = 'mysqlEnum';
77
+ }
78
+ else {
79
+ columnType = `varchar('${input.name}', { length: 255 })`;
80
+ drizzleColumnType = 'varchar';
81
+ }
82
+ break;
83
+ case 'checkbox':
84
+ columnType = `boolean('${input.name}')`;
85
+ drizzleColumnType = 'boolean';
86
+ break;
87
+ case 'color':
88
+ columnType = `varchar('${input.name}', { length: 7 })`; // #RRGGBB
89
+ drizzleColumnType = 'varchar';
90
+ break;
91
+ case 'date':
92
+ switch (input.format) {
93
+ case 'timestamp':
94
+ columnType = `timestamp('${input.name}')`;
95
+ drizzleColumnType = 'timestamp';
96
+ break;
97
+ case 'date':
98
+ columnType = `date('${input.name}')`;
99
+ drizzleColumnType = 'date';
100
+ break;
101
+ case 'datetime':
102
+ columnType = `datetime('${input.name}')`;
103
+ drizzleColumnType = 'datetime';
104
+ break;
105
+ }
106
+ break;
107
+ case 'number':
108
+ switch (input.format) {
109
+ case 'double':
110
+ columnType = `double('${input.name}')`;
111
+ drizzleColumnType = 'double';
112
+ break;
113
+ case 'float':
114
+ columnType = `float('${input.name}')`;
115
+ drizzleColumnType = 'float';
116
+ break;
117
+ case 'int':
118
+ default:
119
+ columnType = `int('${input.name}')`;
120
+ drizzleColumnType = 'int';
121
+ if (input.hasAutoIncrement) {
122
+ columnType += `.autoincrement()`;
123
+ }
124
+ break;
125
+ }
126
+ break;
127
+ case 'map':
128
+ case 'tags':
129
+ case 'photo':
130
+ case 'video':
131
+ case 'document':
132
+ columnType = `varchar('${input.name}', { length: 255 })`; // TEXT type
133
+ drizzleColumnType = 'varchar';
134
+ break;
135
+ default:
136
+ // @ts-expect-error name will be any at this point
137
+ // TODO: Should I throw an error instead?
138
+ columnType = `varchar('${input.name}', { length: 255 })`;
139
+ drizzleColumnType = 'varchar';
140
+ break;
141
+ }
142
+ if (input.required) {
143
+ columnType += `.notNull()`;
144
+ }
145
+ if (input === table.identifier) {
146
+ columnType += `.primaryKey()`;
147
+ }
148
+ /*if (input.type === 'date') {
149
+ columnType += `.defaultNow()`
150
+ }*/
151
+ schema += ` ${columnCaseStyleFn(input.name)}: ${columnType},\n`;
152
+ /**
153
+ * First, let's check if the column type is already in the drizzleColumnTypes array
154
+ */
155
+ if (drizzleColumnType && !drizzleColumnTypes.includes(drizzleColumnType)) {
156
+ /**
157
+ * If it's not, add it to the array
158
+ */
159
+ drizzleColumnTypes.push(drizzleColumnType);
160
+ }
161
+ }
162
+ schema = schema.slice(0, -2); // Remove the last comma and newline
163
+ schema += `\n});\n\n`;
164
+ return {
165
+ schema: schema,
166
+ columnTypes: drizzleColumnTypes,
167
+ };
168
+ }
@@ -0,0 +1,2 @@
1
+ export declare function setMasterAdmin(): Promise<void>;
2
+ //# sourceMappingURL=set-master-admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set-master-admin.d.ts","sourceRoot":"","sources":["../../src/lib/set-master-admin.ts"],"names":[],"mappings":"AAGA,wBAAsB,cAAc,kBA2DnC"}