@objectql/cli 1.8.4 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +2 -2
  2. package/dist/commands/database-push.d.ts +5 -0
  3. package/dist/commands/database-push.js +15 -0
  4. package/dist/commands/database-push.js.map +1 -0
  5. package/dist/commands/dev.d.ts +2 -0
  6. package/dist/commands/dev.js +94 -6
  7. package/dist/commands/dev.js.map +1 -1
  8. package/dist/commands/doctor.d.ts +4 -0
  9. package/dist/commands/doctor.js +37 -0
  10. package/dist/commands/doctor.js.map +1 -0
  11. package/dist/commands/init.js +31 -30
  12. package/dist/commands/init.js.map +1 -1
  13. package/dist/commands/serve.d.ts +2 -0
  14. package/dist/commands/serve.js +122 -46
  15. package/dist/commands/serve.js.map +1 -1
  16. package/dist/commands/start.d.ts +1 -0
  17. package/dist/commands/start.js +15 -0
  18. package/dist/commands/start.js.map +1 -1
  19. package/dist/index.js +173 -210
  20. package/dist/index.js.map +1 -1
  21. package/package.json +13 -7
  22. package/templates/hello-world/.vscode/extensions.json +7 -0
  23. package/templates/hello-world/CHANGELOG.md +41 -0
  24. package/templates/hello-world/README.md +29 -0
  25. package/templates/hello-world/package.json +24 -0
  26. package/templates/hello-world/src/index.ts +58 -0
  27. package/templates/hello-world/tsconfig.json +10 -0
  28. package/templates/starter/.vscode/extensions.json +7 -0
  29. package/{CHANGELOG.md → templates/starter/CHANGELOG.md} +36 -42
  30. package/templates/starter/README.md +17 -0
  31. package/templates/starter/__tests__/projects-hooks-actions.test.ts +490 -0
  32. package/templates/starter/jest.config.js +16 -0
  33. package/templates/starter/package.json +52 -0
  34. package/templates/starter/src/README.pages.md +110 -0
  35. package/templates/starter/src/demo.app.yml +4 -0
  36. package/templates/starter/src/i18n/zh-CN/projects.json +22 -0
  37. package/templates/starter/src/modules/kitchen-sink/kitchen_sink.data.yml +18 -0
  38. package/templates/starter/src/modules/kitchen-sink/kitchen_sink.object.yml +156 -0
  39. package/templates/starter/src/modules/projects/project_approval.workflow.yml +51 -0
  40. package/templates/starter/src/modules/projects/projects.action.ts +472 -0
  41. package/templates/starter/src/modules/projects/projects.data.yml +13 -0
  42. package/templates/starter/src/modules/projects/projects.hook.ts +339 -0
  43. package/templates/starter/src/modules/projects/projects.object.yml +148 -0
  44. package/templates/starter/src/modules/projects/projects.permission.yml +141 -0
  45. package/templates/starter/src/modules/projects/projects.validation.yml +37 -0
  46. package/templates/starter/src/modules/tasks/tasks.data.yml +23 -0
  47. package/templates/starter/src/modules/tasks/tasks.object.yml +34 -0
  48. package/templates/starter/src/modules/tasks/tasks.permission.yml +167 -0
  49. package/templates/starter/src/seed.ts +55 -0
  50. package/templates/starter/src/types/index.ts +3 -0
  51. package/templates/starter/src/types/kitchen_sink.ts +101 -0
  52. package/templates/starter/src/types/projects.ts +49 -0
  53. package/templates/starter/src/types/tasks.ts +33 -0
  54. package/templates/starter/tsconfig.json +11 -0
  55. package/templates/starter/tsconfig.tsbuildinfo +1 -0
  56. package/AI_EXAMPLES.md +0 -154
  57. package/AI_IMPLEMENTATION_SUMMARY.md +0 -509
  58. package/AI_TUTORIAL.md +0 -144
  59. package/IMPLEMENTATION_SUMMARY.md +0 -437
  60. package/USAGE_EXAMPLES.md +0 -951
  61. package/__tests__/commands.test.ts +0 -426
  62. package/jest.config.js +0 -19
  63. package/src/commands/ai.ts +0 -509
  64. package/src/commands/build.ts +0 -98
  65. package/src/commands/dev.ts +0 -23
  66. package/src/commands/format.ts +0 -110
  67. package/src/commands/generate.ts +0 -135
  68. package/src/commands/i18n.ts +0 -303
  69. package/src/commands/init.ts +0 -191
  70. package/src/commands/lint.ts +0 -98
  71. package/src/commands/migrate.ts +0 -314
  72. package/src/commands/new.ts +0 -221
  73. package/src/commands/repl.ts +0 -120
  74. package/src/commands/serve.ts +0 -96
  75. package/src/commands/start.ts +0 -100
  76. package/src/commands/sync.ts +0 -328
  77. package/src/commands/test.ts +0 -98
  78. package/src/index.ts +0 -356
  79. package/tsconfig.json +0 -15
  80. package/tsconfig.tsbuildinfo +0 -1
@@ -1,191 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import { exec } from 'child_process';
4
- import { promisify } from 'util';
5
- import chalk from 'chalk';
6
-
7
- const execAsync = promisify(exec);
8
-
9
- interface InitOptions {
10
- template?: string;
11
- name?: string;
12
- dir?: string;
13
- skipInstall?: boolean;
14
- skipGit?: boolean;
15
- }
16
-
17
- const TEMPLATES = {
18
- basic: '@objectql/starter-basic',
19
- 'express-api': '@objectql/starter-express-api',
20
- enterprise: '@objectql/starter-enterprise'
21
- };
22
-
23
- export async function initProject(options: InitOptions) {
24
- const projectName = options.name || 'my-objectql-project';
25
- const targetDir = options.dir || path.join(process.cwd(), projectName);
26
- const template = (options.template || 'basic') as keyof typeof TEMPLATES;
27
-
28
- if (!TEMPLATES[template]) {
29
- console.error(chalk.red(`❌ Unknown template: ${template}`));
30
- console.log(chalk.gray(`Available templates: ${Object.keys(TEMPLATES).join(', ')}`));
31
- process.exit(1);
32
- }
33
-
34
- console.log(chalk.blue(`\n🚀 Initializing ObjectQL project: ${chalk.bold(projectName)}`));
35
- console.log(chalk.gray(`Template: ${template}`));
36
- console.log(chalk.gray(`Directory: ${targetDir}\n`));
37
-
38
- // Check if directory exists
39
- if (fs.existsSync(targetDir)) {
40
- console.error(chalk.red(`❌ Directory already exists: ${targetDir}`));
41
- process.exit(1);
42
- }
43
-
44
- // Create project directory
45
- fs.mkdirSync(targetDir, { recursive: true });
46
-
47
- try {
48
- // Copy template files from starters
49
- const templatePath = path.join(__dirname, '../../../../starters', template);
50
-
51
- // Check if we're in the monorepo (for development)
52
- if (fs.existsSync(templatePath)) {
53
- console.log(chalk.gray('Copying template files...'));
54
- await copyDirectory(templatePath, targetDir, ['node_modules', 'dist', '.git']);
55
- } else {
56
- // Try to use the published package
57
- console.log(chalk.gray(`Installing template from npm: ${TEMPLATES[template]}...`));
58
- await execAsync(`npm create ${TEMPLATES[template]} ${targetDir}`, {
59
- cwd: process.cwd()
60
- });
61
- }
62
-
63
- // Update package.json with project name
64
- const pkgPath = path.join(targetDir, 'package.json');
65
- if (fs.existsSync(pkgPath)) {
66
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
67
- pkg.name = projectName;
68
- pkg.version = '0.1.0';
69
- // Convert workspace dependencies to actual versions for standalone project
70
- if (pkg.dependencies) {
71
- for (const dep of Object.keys(pkg.dependencies)) {
72
- if (pkg.dependencies[dep] === 'workspace:*') {
73
- pkg.dependencies[dep] = '^1.0.0'; // Use latest published version
74
- }
75
- }
76
- }
77
- if (pkg.devDependencies) {
78
- for (const dep of Object.keys(pkg.devDependencies)) {
79
- if (pkg.devDependencies[dep] === 'workspace:*') {
80
- pkg.devDependencies[dep] = '^1.0.0';
81
- }
82
- }
83
- }
84
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
85
- }
86
-
87
- // Initialize git repository
88
- if (!options.skipGit) {
89
- try {
90
- console.log(chalk.gray('\nInitializing git repository...'));
91
- await execAsync('git init', { cwd: targetDir });
92
-
93
- // Create .gitignore if it doesn't exist
94
- const gitignorePath = path.join(targetDir, '.gitignore');
95
- if (!fs.existsSync(gitignorePath)) {
96
- const gitignore = `node_modules/
97
- dist/
98
- *.log
99
- .DS_Store
100
- *.sqlite3
101
- .env
102
- .env.local
103
- `;
104
- fs.writeFileSync(gitignorePath, gitignore);
105
- }
106
-
107
- console.log(chalk.green('✓ Git repository initialized'));
108
- } catch (err) {
109
- console.log(chalk.yellow('⚠ Git initialization skipped (git not available)'));
110
- }
111
- }
112
-
113
- // Install dependencies
114
- if (!options.skipInstall) {
115
- console.log(chalk.gray('\nInstalling dependencies...'));
116
- console.log(chalk.gray('This might take a few minutes...\n'));
117
-
118
- try {
119
- // Try pnpm first, fall back to npm
120
- const hasNpm = await checkCommand('pnpm');
121
- const packageManager = hasNpm ? 'pnpm' : 'npm';
122
-
123
- await execAsync(`${packageManager} install`, {
124
- cwd: targetDir,
125
- // Show output in real-time would be better, but this is simpler
126
- });
127
- console.log(chalk.green(`✓ Dependencies installed with ${packageManager}`));
128
- } catch (err: any) {
129
- console.log(chalk.yellow(`⚠ Failed to install dependencies: ${err.message}`));
130
- console.log(chalk.gray(`You can install them manually by running:`));
131
- console.log(chalk.gray(` cd ${projectName} && npm install`));
132
- }
133
- }
134
-
135
- // Success message
136
- console.log(chalk.green('\n✅ Project created successfully!\n'));
137
- console.log(chalk.bold('Next steps:'));
138
- console.log(chalk.gray(` cd ${projectName}`));
139
-
140
- if (options.skipInstall) {
141
- console.log(chalk.gray(' pnpm install # or npm install'));
142
- }
143
-
144
- console.log(chalk.gray(' pnpm run build'));
145
- console.log(chalk.gray(' pnpm run repl\n'));
146
-
147
- console.log(chalk.blue('📚 Documentation: https://github.com/objectql/objectql'));
148
-
149
- } catch (error: any) {
150
- console.error(chalk.red(`\n❌ Failed to create project: ${error.message}`));
151
- // Clean up
152
- if (fs.existsSync(targetDir)) {
153
- fs.rmSync(targetDir, { recursive: true, force: true });
154
- }
155
- process.exit(1);
156
- }
157
- }
158
-
159
- async function copyDirectory(src: string, dest: string, ignore: string[] = []) {
160
- // Create destination directory
161
- if (!fs.existsSync(dest)) {
162
- fs.mkdirSync(dest, { recursive: true });
163
- }
164
-
165
- const entries = fs.readdirSync(src, { withFileTypes: true });
166
-
167
- for (const entry of entries) {
168
- const srcPath = path.join(src, entry.name);
169
- const destPath = path.join(dest, entry.name);
170
-
171
- // Skip ignored directories
172
- if (ignore.includes(entry.name)) {
173
- continue;
174
- }
175
-
176
- if (entry.isDirectory()) {
177
- await copyDirectory(srcPath, destPath, ignore);
178
- } else {
179
- fs.copyFileSync(srcPath, destPath);
180
- }
181
- }
182
- }
183
-
184
- async function checkCommand(cmd: string): Promise<boolean> {
185
- try {
186
- await execAsync(`${cmd} --version`);
187
- return true;
188
- } catch {
189
- return false;
190
- }
191
- }
@@ -1,98 +0,0 @@
1
- import { ObjectQL } from '@objectql/core';
2
- import { ObjectLoader } from '@objectql/platform-node';
3
- import { ObjectConfig, FieldConfig } from '@objectql/types';
4
- import * as path from 'path';
5
- import chalk from 'chalk';
6
-
7
- // Naming convention regex
8
- const VALID_NAME_REGEX = /^[a-z][a-z0-9_]*$/;
9
-
10
- interface LintOptions {
11
- dir?: string;
12
- fix?: boolean;
13
- }
14
-
15
- /**
16
- * Lint command - validates metadata files for correctness and best practices
17
- */
18
- export async function lint(options: LintOptions) {
19
- console.log(chalk.blue('🔍 Linting ObjectQL metadata files...\n'));
20
-
21
- const rootDir = path.resolve(process.cwd(), options.dir || '.');
22
- let hasErrors = false;
23
- let hasWarnings = false;
24
-
25
- try {
26
- const app = new ObjectQL({ datasources: {} });
27
- const loader = new ObjectLoader(app.metadata);
28
-
29
- console.log(chalk.cyan('Loading metadata files...'));
30
- loader.load(rootDir);
31
-
32
- const objects = app.metadata.list('object');
33
-
34
- console.log(chalk.green(`✅ Found ${objects.length} object(s)\n`));
35
-
36
- // Validate each object
37
- for (const obj of objects) {
38
- const objectConfig = obj as ObjectConfig;
39
- const name = objectConfig.name;
40
- console.log(chalk.cyan(`Checking object: ${name}`));
41
-
42
- // Check naming convention (lowercase with underscores)
43
- if (!VALID_NAME_REGEX.test(name)) {
44
- console.log(chalk.red(` ❌ Invalid name format: "${name}" should be lowercase with underscores`));
45
- hasErrors = true;
46
- }
47
-
48
- // Check if label exists
49
- if (!objectConfig.label) {
50
- console.log(chalk.yellow(` ⚠️ Missing label for object "${name}"`));
51
- hasWarnings = true;
52
- }
53
-
54
- // Check fields
55
- const fieldCount = Object.keys(objectConfig.fields || {}).length;
56
- if (fieldCount === 0) {
57
- console.log(chalk.yellow(` ⚠️ Object "${name}" has no fields defined`));
58
- hasWarnings = true;
59
- } else {
60
- console.log(chalk.gray(` ℹ️ ${fieldCount} field(s) defined`));
61
- }
62
-
63
- // Validate field names
64
- for (const [fieldName, field] of Object.entries(objectConfig.fields || {})) {
65
- if (!VALID_NAME_REGEX.test(fieldName)) {
66
- console.log(chalk.red(` ❌ Invalid field name: "${fieldName}" should be lowercase with underscores`));
67
- hasErrors = true;
68
- }
69
-
70
- const fieldConfig = field as FieldConfig;
71
- // Check for required label on fields
72
- if (!fieldConfig.label) {
73
- console.log(chalk.yellow(` ⚠️ Field "${fieldName}" missing label`));
74
- hasWarnings = true;
75
- }
76
- }
77
-
78
- console.log('');
79
- }
80
-
81
- // Summary
82
- if (hasErrors) {
83
- console.log(chalk.red.bold('❌ Linting failed with errors\n'));
84
- process.exit(1);
85
- } else if (hasWarnings) {
86
- console.log(chalk.yellow.bold('⚠️ Linting completed with warnings\n'));
87
- } else {
88
- console.log(chalk.green.bold('✅ Linting passed - no issues found!\n'));
89
- }
90
-
91
- } catch (e: any) {
92
- console.error(chalk.red('❌ Linting failed:'), e.message);
93
- if (e.stack) {
94
- console.error(chalk.gray(e.stack));
95
- }
96
- process.exit(1);
97
- }
98
- }
@@ -1,314 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import chalk from 'chalk';
4
-
5
- interface MigrateOptions {
6
- config?: string;
7
- dir?: string;
8
- }
9
-
10
- interface MigrateCreateOptions {
11
- name: string;
12
- dir?: string;
13
- }
14
-
15
- interface MigrateStatusOptions {
16
- config?: string;
17
- dir?: string;
18
- }
19
-
20
- const MIGRATION_TEMPLATE = `import { ObjectQL } from '@objectql/core';
21
-
22
- /**
23
- * Migration: {{name}}
24
- * Created: {{timestamp}}
25
- */
26
- export async function up(app: ObjectQL) {
27
- // TODO: Implement migration logic
28
- console.log('Running migration: {{name}}');
29
-
30
- // Example: Add a new field to an object
31
- // const tasks = app.getObject('tasks');
32
- // await tasks.updateSchema({
33
- // fields: {
34
- // new_field: { type: 'text', label: 'New Field' }
35
- // }
36
- // });
37
- }
38
-
39
- export async function down(app: ObjectQL) {
40
- // TODO: Implement rollback logic
41
- console.log('Rolling back migration: {{name}}');
42
-
43
- // Example: Remove the field
44
- // const tasks = app.getObject('tasks');
45
- // await tasks.updateSchema({
46
- // fields: {
47
- // new_field: undefined
48
- // }
49
- // });
50
- }
51
- `;
52
-
53
- /**
54
- * Run pending migrations
55
- */
56
- export async function migrate(options: MigrateOptions) {
57
- const migrationsDir = path.resolve(process.cwd(), options.dir || './migrations');
58
-
59
- console.log(chalk.blue('🔄 Running migrations...'));
60
- console.log(chalk.gray(`Migrations directory: ${migrationsDir}\n`));
61
-
62
- if (!fs.existsSync(migrationsDir)) {
63
- console.log(chalk.yellow('⚠ No migrations directory found'));
64
- console.log(chalk.gray('Create one with: objectql migrate:create --name init'));
65
- return;
66
- }
67
-
68
- try {
69
- // Load ObjectQL instance from config
70
- const app = await loadObjectQLInstance(options.config);
71
-
72
- // Get list of migration files
73
- const files = fs.readdirSync(migrationsDir)
74
- .filter(f => f.endsWith('.ts') || f.endsWith('.js'))
75
- .sort();
76
-
77
- if (files.length === 0) {
78
- console.log(chalk.yellow('⚠ No migration files found'));
79
- return;
80
- }
81
-
82
- // Get already run migrations
83
- const migrations = app.getObject('_migrations');
84
- let runMigrations: string[] = [];
85
-
86
- try {
87
- const result = await migrations.find({
88
- fields: ['name'],
89
- sort: [['created_at', 'asc']]
90
- });
91
- runMigrations = result.records.map((r: any) => r.name);
92
- } catch (err) {
93
- // Migrations table doesn't exist yet, create it
94
- console.log(chalk.gray('Creating migrations tracking table...'));
95
- await createMigrationsTable(app);
96
- }
97
-
98
- // Run pending migrations
99
- let ranCount = 0;
100
- for (const file of files) {
101
- const migrationName = file.replace(/\.(ts|js)$/, '');
102
-
103
- if (runMigrations.includes(migrationName)) {
104
- console.log(chalk.gray(`⊘ ${migrationName} (already run)`));
105
- continue;
106
- }
107
-
108
- console.log(chalk.blue(`▶ ${migrationName}`));
109
-
110
- const migrationPath = path.join(migrationsDir, file);
111
- const migration = require(migrationPath);
112
-
113
- if (!migration.up) {
114
- console.log(chalk.red(` ✗ No 'up' function found`));
115
- continue;
116
- }
117
-
118
- try {
119
- await migration.up(app);
120
-
121
- // Record migration
122
- await migrations.insert({
123
- name: migrationName,
124
- run_at: new Date()
125
- });
126
-
127
- console.log(chalk.green(` ✓ Complete`));
128
- ranCount++;
129
- } catch (error: any) {
130
- console.log(chalk.red(` ✗ Failed: ${error.message}`));
131
- throw error;
132
- }
133
- }
134
-
135
- console.log(chalk.green(`\n✅ Ran ${ranCount} migration(s)`));
136
-
137
- } catch (error: any) {
138
- console.error(chalk.red(`❌ Migration failed: ${error.message}`));
139
- process.exit(1);
140
- }
141
- }
142
-
143
- /**
144
- * Create a new migration file with boilerplate code
145
- */
146
- export async function migrateCreate(options: MigrateCreateOptions) {
147
- const { name } = options;
148
- const migrationsDir = path.resolve(process.cwd(), options.dir || './migrations');
149
-
150
- // Validate name
151
- if (!name || !/^[a-z][a-z0-9_]*$/.test(name)) {
152
- console.error(chalk.red('❌ Invalid migration name. Use lowercase with underscores (e.g., add_status_field)'));
153
- process.exit(1);
154
- }
155
-
156
- // Create migrations directory if it doesn't exist
157
- if (!fs.existsSync(migrationsDir)) {
158
- fs.mkdirSync(migrationsDir, { recursive: true });
159
- console.log(chalk.gray(`Created directory: ${migrationsDir}`));
160
- }
161
-
162
- // Generate filename with timestamp
163
- const timestamp = new Date().toISOString().replace(/[:\-T.]/g, '').slice(0, 14);
164
- const filename = `${timestamp}_${name}.ts`;
165
- const filePath = path.join(migrationsDir, filename);
166
-
167
- // Create migration file from template
168
- const content = MIGRATION_TEMPLATE
169
- .replace(/\{\{name\}\}/g, name)
170
- .replace(/\{\{timestamp\}\}/g, new Date().toISOString());
171
-
172
- fs.writeFileSync(filePath, content, 'utf-8');
173
-
174
- console.log(chalk.green(`✅ Created migration: ${filename}`));
175
- console.log(chalk.gray(`Path: ${filePath}`));
176
- console.log(chalk.gray(`\nNext steps:`));
177
- console.log(chalk.gray(` 1. Edit the migration file to add your changes`));
178
- console.log(chalk.gray(` 2. Run: objectql migrate`));
179
- }
180
-
181
- /**
182
- * Show migration status - displays pending and completed migrations
183
- * @param options - Configuration options including config path and migrations directory
184
- */
185
- export async function migrateStatus(options: MigrateStatusOptions) {
186
- const migrationsDir = path.resolve(process.cwd(), options.dir || './migrations');
187
-
188
- console.log(chalk.blue('📊 Migration Status\n'));
189
-
190
- if (!fs.existsSync(migrationsDir)) {
191
- console.log(chalk.yellow('⚠ No migrations directory found'));
192
- return;
193
- }
194
-
195
- try {
196
- // Load ObjectQL instance
197
- const app = await loadObjectQLInstance(options.config);
198
-
199
- // Get list of migration files
200
- const files = fs.readdirSync(migrationsDir)
201
- .filter(f => f.endsWith('.ts') || f.endsWith('.js'))
202
- .sort();
203
-
204
- if (files.length === 0) {
205
- console.log(chalk.gray('No migration files found'));
206
- return;
207
- }
208
-
209
- // Get run migrations
210
- const migrations = app.getObject('_migrations');
211
- let runMigrations: string[] = [];
212
-
213
- try {
214
- const result = await migrations.find({
215
- fields: ['name', 'run_at'],
216
- sort: [['run_at', 'asc']]
217
- });
218
- runMigrations = result.records.map((r: any) => r.name);
219
- } catch (err) {
220
- // Migrations table doesn't exist
221
- runMigrations = [];
222
- }
223
-
224
- // Display status
225
- let pendingCount = 0;
226
- for (const file of files) {
227
- const migrationName = file.replace(/\.(ts|js)$/, '');
228
- const isRun = runMigrations.includes(migrationName);
229
-
230
- if (isRun) {
231
- console.log(chalk.green(`✓ ${migrationName}`));
232
- } else {
233
- console.log(chalk.yellow(`○ ${migrationName} (pending)`));
234
- pendingCount++;
235
- }
236
- }
237
-
238
- console.log(chalk.blue(`\n📊 Summary:`));
239
- console.log(chalk.gray(`Total migrations: ${files.length}`));
240
- console.log(chalk.gray(`Run: ${files.length - pendingCount}`));
241
- console.log(chalk.gray(`Pending: ${pendingCount}`));
242
-
243
- } catch (error: any) {
244
- console.error(chalk.red(`❌ Failed to get status: ${error.message}`));
245
- process.exit(1);
246
- }
247
- }
248
-
249
- async function loadObjectQLInstance(configPath?: string): Promise<any> {
250
- const cwd = process.cwd();
251
-
252
- // Try to load from config file
253
- let configFile = configPath;
254
- if (!configFile) {
255
- const potentialFiles = ['objectql.config.ts', 'objectql.config.js'];
256
- for (const file of potentialFiles) {
257
- if (fs.existsSync(path.join(cwd, file))) {
258
- configFile = file;
259
- break;
260
- }
261
- }
262
- }
263
-
264
- if (!configFile) {
265
- throw new Error('No configuration file found (objectql.config.ts/js)');
266
- }
267
-
268
- // Register ts-node for TypeScript support
269
- try {
270
- require('ts-node').register({
271
- transpileOnly: true,
272
- compilerOptions: {
273
- module: 'commonjs'
274
- }
275
- });
276
- } catch (err) {
277
- // ts-node not available, try to load JS directly
278
- }
279
-
280
- const configModule = require(path.join(cwd, configFile));
281
- const app = configModule.default || configModule.app || configModule.objectql || configModule.db;
282
-
283
- if (!app) {
284
- throw new Error('Config file must export an ObjectQL instance');
285
- }
286
-
287
- await app.init();
288
- return app;
289
- }
290
-
291
- async function createMigrationsTable(app: any) {
292
- // Create a system object to track migrations
293
- app.metadata.register('object', {
294
- name: '_migrations',
295
- label: 'Migrations',
296
- system: true,
297
- fields: {
298
- name: {
299
- type: 'text',
300
- label: 'Migration Name',
301
- required: true,
302
- unique: true
303
- },
304
- run_at: {
305
- type: 'datetime',
306
- label: 'Run At',
307
- required: true
308
- }
309
- }
310
- });
311
-
312
- // Sync to database
313
- await app.getObject('_migrations').sync();
314
- }