create-objectstack 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,653 @@
1
+ // src/index.ts
2
+ import { Command } from "commander";
3
+ import chalk from "chalk";
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import { execSync } from "child_process";
7
+ var TEMPLATES = {
8
+ "minimal-api": {
9
+ description: "Server + memory driver + 1 object + REST API",
10
+ files: {
11
+ "objectstack.config.ts": (name) => `import { defineStack } from '@objectstack/spec';
12
+ import * as objects from './src/objects';
13
+
14
+ export default defineStack({
15
+ manifest: {
16
+ id: 'com.example.${name}',
17
+ namespace: '${name}',
18
+ version: '0.1.0',
19
+ type: 'app',
20
+ name: '${toTitleCase(name)}',
21
+ description: '${toTitleCase(name)} \u2014 built with ObjectStack',
22
+ },
23
+
24
+ objects: Object.values(objects),
25
+
26
+ api: {
27
+ rest: { enabled: true, basePath: '/api' },
28
+ },
29
+ });
30
+ `,
31
+ "package.json": (name) => JSON.stringify({
32
+ name,
33
+ version: "0.1.0",
34
+ private: true,
35
+ type: "module",
36
+ scripts: {
37
+ dev: "objectstack dev",
38
+ start: "objectstack serve",
39
+ build: "objectstack compile",
40
+ validate: "objectstack validate",
41
+ typecheck: "tsc --noEmit"
42
+ },
43
+ dependencies: {
44
+ "@objectstack/spec": "^3.0.0",
45
+ "@objectstack/runtime": "^3.0.0",
46
+ "@objectstack/driver-memory": "^3.0.0",
47
+ "@objectstack/plugin-hono-server": "^3.0.0"
48
+ },
49
+ devDependencies: {
50
+ "@objectstack/cli": "^3.0.0",
51
+ "typescript": "^5.3.0"
52
+ }
53
+ }, null, 2) + "\n",
54
+ "tsconfig.json": () => JSON.stringify({
55
+ compilerOptions: {
56
+ target: "ES2022",
57
+ module: "ESNext",
58
+ moduleResolution: "bundler",
59
+ strict: true,
60
+ esModuleInterop: true,
61
+ skipLibCheck: true,
62
+ outDir: "dist",
63
+ rootDir: ".",
64
+ declaration: true
65
+ },
66
+ include: ["*.ts", "src/**/*"],
67
+ exclude: ["dist", "node_modules"]
68
+ }, null, 2) + "\n",
69
+ "src/objects/task.ts": () => `import { Data } from '@objectstack/spec';
70
+
71
+ const task: Data.Object = {
72
+ name: 'task',
73
+ label: 'Task',
74
+ ownership: 'own',
75
+ fields: {
76
+ title: {
77
+ type: 'text',
78
+ label: 'Title',
79
+ required: true,
80
+ },
81
+ description: {
82
+ type: 'textarea',
83
+ label: 'Description',
84
+ },
85
+ status: {
86
+ type: 'select',
87
+ label: 'Status',
88
+ options: [
89
+ { label: 'Open', value: 'open' },
90
+ { label: 'In Progress', value: 'in_progress' },
91
+ { label: 'Done', value: 'done' },
92
+ ],
93
+ defaultValue: 'open',
94
+ },
95
+ due_date: {
96
+ type: 'date',
97
+ label: 'Due Date',
98
+ },
99
+ },
100
+ };
101
+
102
+ export default task;
103
+ `,
104
+ "src/objects/index.ts": () => `export { default as task } from './task';
105
+ `,
106
+ ".gitignore": () => `node_modules/
107
+ dist/
108
+ *.tsbuildinfo
109
+ `,
110
+ "README.md": (name) => `# ${toTitleCase(name)}
111
+
112
+ Built with [ObjectStack](https://objectstack.com).
113
+
114
+ ## Quick Start
115
+
116
+ \`\`\`bash
117
+ # Install dependencies
118
+ npm install
119
+
120
+ # Start development server
121
+ npm run dev
122
+
123
+ # Validate configuration
124
+ npm run validate
125
+ \`\`\`
126
+
127
+ ## Project Structure
128
+
129
+ - \`objectstack.config.ts\` \u2014 Stack definition (objects, API, settings)
130
+ - \`src/objects/\` \u2014 Object definitions
131
+ - \`dist/\` \u2014 Compiled output
132
+
133
+ ## Learn More
134
+
135
+ - [ObjectStack Documentation](https://objectstack.com/docs)
136
+ `
137
+ }
138
+ },
139
+ "full-stack": {
140
+ description: "Server + UI + auth + 3 CRM objects",
141
+ files: {
142
+ "objectstack.config.ts": (name) => `import { defineStack } from '@objectstack/spec';
143
+ import * as objects from './src/objects';
144
+ import * as apps from './src/apps';
145
+
146
+ export default defineStack({
147
+ manifest: {
148
+ id: 'com.example.${name}',
149
+ namespace: '${name}',
150
+ version: '0.1.0',
151
+ type: 'app',
152
+ name: '${toTitleCase(name)}',
153
+ description: '${toTitleCase(name)} CRM \u2014 built with ObjectStack',
154
+ },
155
+
156
+ objects: Object.values(objects),
157
+ apps: Object.values(apps),
158
+
159
+ api: {
160
+ rest: { enabled: true, basePath: '/api' },
161
+ },
162
+ });
163
+ `,
164
+ "package.json": (name) => JSON.stringify({
165
+ name,
166
+ version: "0.1.0",
167
+ private: true,
168
+ type: "module",
169
+ scripts: {
170
+ dev: "objectstack dev",
171
+ start: "objectstack serve",
172
+ build: "objectstack compile",
173
+ validate: "objectstack validate",
174
+ typecheck: "tsc --noEmit"
175
+ },
176
+ dependencies: {
177
+ "@objectstack/spec": "^3.0.0",
178
+ "@objectstack/runtime": "^3.0.0",
179
+ "@objectstack/driver-memory": "^3.0.0",
180
+ "@objectstack/plugin-hono-server": "^3.0.0",
181
+ "@objectstack/plugin-auth": "^3.0.0"
182
+ },
183
+ devDependencies: {
184
+ "@objectstack/cli": "^3.0.0",
185
+ "typescript": "^5.3.0"
186
+ }
187
+ }, null, 2) + "\n",
188
+ "tsconfig.json": () => JSON.stringify({
189
+ compilerOptions: {
190
+ target: "ES2022",
191
+ module: "ESNext",
192
+ moduleResolution: "bundler",
193
+ strict: true,
194
+ esModuleInterop: true,
195
+ skipLibCheck: true,
196
+ outDir: "dist",
197
+ rootDir: ".",
198
+ declaration: true
199
+ },
200
+ include: ["*.ts", "src/**/*"],
201
+ exclude: ["dist", "node_modules"]
202
+ }, null, 2) + "\n",
203
+ "src/objects/contact.ts": () => `import { Data } from '@objectstack/spec';
204
+
205
+ const contact: Data.Object = {
206
+ name: 'contact',
207
+ label: 'Contact',
208
+ ownership: 'own',
209
+ fields: {
210
+ first_name: {
211
+ type: 'text',
212
+ label: 'First Name',
213
+ required: true,
214
+ },
215
+ last_name: {
216
+ type: 'text',
217
+ label: 'Last Name',
218
+ required: true,
219
+ },
220
+ email: {
221
+ type: 'text',
222
+ label: 'Email',
223
+ },
224
+ phone: {
225
+ type: 'text',
226
+ label: 'Phone',
227
+ },
228
+ company: {
229
+ type: 'lookup',
230
+ label: 'Company',
231
+ reference: 'company',
232
+ },
233
+ },
234
+ };
235
+
236
+ export default contact;
237
+ `,
238
+ "src/objects/company.ts": () => `import { Data } from '@objectstack/spec';
239
+
240
+ const company: Data.Object = {
241
+ name: 'company',
242
+ label: 'Company',
243
+ ownership: 'own',
244
+ fields: {
245
+ name: {
246
+ type: 'text',
247
+ label: 'Company Name',
248
+ required: true,
249
+ },
250
+ website: {
251
+ type: 'text',
252
+ label: 'Website',
253
+ },
254
+ industry: {
255
+ type: 'select',
256
+ label: 'Industry',
257
+ options: [
258
+ { label: 'Technology', value: 'technology' },
259
+ { label: 'Finance', value: 'finance' },
260
+ { label: 'Healthcare', value: 'healthcare' },
261
+ { label: 'Other', value: 'other' },
262
+ ],
263
+ },
264
+ },
265
+ };
266
+
267
+ export default company;
268
+ `,
269
+ "src/objects/deal.ts": () => `import { Data } from '@objectstack/spec';
270
+
271
+ const deal: Data.Object = {
272
+ name: 'deal',
273
+ label: 'Deal',
274
+ ownership: 'own',
275
+ fields: {
276
+ name: {
277
+ type: 'text',
278
+ label: 'Deal Name',
279
+ required: true,
280
+ },
281
+ amount: {
282
+ type: 'number',
283
+ label: 'Amount',
284
+ },
285
+ stage: {
286
+ type: 'select',
287
+ label: 'Stage',
288
+ options: [
289
+ { label: 'Prospecting', value: 'prospecting' },
290
+ { label: 'Qualification', value: 'qualification' },
291
+ { label: 'Proposal', value: 'proposal' },
292
+ { label: 'Closed Won', value: 'closed_won' },
293
+ { label: 'Closed Lost', value: 'closed_lost' },
294
+ ],
295
+ defaultValue: 'prospecting',
296
+ },
297
+ contact: {
298
+ type: 'lookup',
299
+ label: 'Contact',
300
+ reference: 'contact',
301
+ },
302
+ company: {
303
+ type: 'lookup',
304
+ label: 'Company',
305
+ reference: 'company',
306
+ },
307
+ close_date: {
308
+ type: 'date',
309
+ label: 'Close Date',
310
+ },
311
+ },
312
+ };
313
+
314
+ export default deal;
315
+ `,
316
+ "src/objects/index.ts": () => `export { default as contact } from './contact';
317
+ export { default as company } from './company';
318
+ export { default as deal } from './deal';
319
+ `,
320
+ "src/views/contact_list.ts": () => `import { UI } from '@objectstack/spec';
321
+
322
+ const contactList: UI.View = {
323
+ name: 'contact_list',
324
+ label: 'All Contacts',
325
+ object: 'contact',
326
+ type: 'list',
327
+ columns: ['first_name', 'last_name', 'email', 'phone', 'company'],
328
+ };
329
+
330
+ export default contactList;
331
+ `,
332
+ "src/views/company_list.ts": () => `import { UI } from '@objectstack/spec';
333
+
334
+ const companyList: UI.View = {
335
+ name: 'company_list',
336
+ label: 'All Companies',
337
+ object: 'company',
338
+ type: 'list',
339
+ columns: ['name', 'website', 'industry'],
340
+ };
341
+
342
+ export default companyList;
343
+ `,
344
+ "src/views/deal_list.ts": () => `import { UI } from '@objectstack/spec';
345
+
346
+ const dealList: UI.View = {
347
+ name: 'deal_list',
348
+ label: 'All Deals',
349
+ object: 'deal',
350
+ type: 'list',
351
+ columns: ['name', 'amount', 'stage', 'contact', 'close_date'],
352
+ };
353
+
354
+ export default dealList;
355
+ `,
356
+ "src/apps/crm.ts": () => `import { UI } from '@objectstack/spec';
357
+
358
+ const crm: UI.App = {
359
+ name: 'crm',
360
+ label: 'CRM',
361
+ description: 'Customer Relationship Management',
362
+ navigation: [
363
+ { type: 'object', object: 'contact', label: 'Contacts' },
364
+ { type: 'object', object: 'company', label: 'Companies' },
365
+ { type: 'object', object: 'deal', label: 'Deals' },
366
+ ],
367
+ };
368
+
369
+ export default crm;
370
+ `,
371
+ "src/apps/index.ts": () => `export { default as crm } from './crm';
372
+ `,
373
+ ".gitignore": () => `node_modules/
374
+ dist/
375
+ *.tsbuildinfo
376
+ `,
377
+ "README.md": (name) => `# ${toTitleCase(name)}
378
+
379
+ A full-stack CRM application built with [ObjectStack](https://objectstack.com).
380
+
381
+ ## Quick Start
382
+
383
+ \`\`\`bash
384
+ npm install
385
+ npm run dev
386
+ \`\`\`
387
+
388
+ ## Project Structure
389
+
390
+ - \`objectstack.config.ts\` \u2014 Stack definition
391
+ - \`src/objects/\` \u2014 Data objects (Contact, Company, Deal)
392
+ - \`src/views/\` \u2014 List views
393
+ - \`src/apps/crm.ts\` \u2014 CRM app with navigation
394
+
395
+ ## Learn More
396
+
397
+ - [ObjectStack Documentation](https://objectstack.com/docs)
398
+ `
399
+ }
400
+ },
401
+ plugin: {
402
+ description: "Plugin skeleton with test setup",
403
+ files: {
404
+ "objectstack.config.ts": (name) => `import { defineStack } from '@objectstack/spec';
405
+ import * as objects from './src/objects';
406
+
407
+ export default defineStack({
408
+ manifest: {
409
+ id: 'com.objectstack.plugin-${name}',
410
+ namespace: 'plugin_${name}',
411
+ version: '0.1.0',
412
+ type: 'plugin',
413
+ name: '${toTitleCase(name)} Plugin',
414
+ description: 'ObjectStack Plugin: ${toTitleCase(name)}',
415
+ },
416
+
417
+ objects: Object.values(objects),
418
+ });
419
+ `,
420
+ "package.json": (name) => JSON.stringify({
421
+ name: `@objectstack/plugin-${name}`,
422
+ version: "0.1.0",
423
+ description: `ObjectStack Plugin: ${toTitleCase(name)}`,
424
+ main: "dist/index.js",
425
+ types: "dist/index.d.ts",
426
+ type: "module",
427
+ scripts: {
428
+ build: "tsc",
429
+ dev: "tsc --watch",
430
+ test: "vitest run",
431
+ validate: "objectstack validate",
432
+ typecheck: "tsc --noEmit"
433
+ },
434
+ keywords: ["objectstack", "plugin", name],
435
+ author: "",
436
+ license: "MIT",
437
+ dependencies: {
438
+ "@objectstack/spec": "^3.0.0"
439
+ },
440
+ devDependencies: {
441
+ "@types/node": "^22.0.0",
442
+ "typescript": "^5.3.0",
443
+ "vitest": "^4.0.0"
444
+ }
445
+ }, null, 2) + "\n",
446
+ "tsconfig.json": () => JSON.stringify({
447
+ compilerOptions: {
448
+ target: "ES2022",
449
+ module: "ESNext",
450
+ moduleResolution: "bundler",
451
+ strict: true,
452
+ esModuleInterop: true,
453
+ skipLibCheck: true,
454
+ outDir: "dist",
455
+ rootDir: ".",
456
+ declaration: true
457
+ },
458
+ include: ["*.ts", "src/**/*"],
459
+ exclude: ["dist", "node_modules"]
460
+ }, null, 2) + "\n",
461
+ "src/index.ts": (name) => `/**
462
+ * ${toTitleCase(name)} Plugin for ObjectStack
463
+ *
464
+ * Entry point \u2014 re-exports all plugin metadata.
465
+ */
466
+ export * as objects from './objects';
467
+ `,
468
+ "src/objects/sample.ts": (name) => `import { Data } from '@objectstack/spec';
469
+
470
+ const sample: Data.Object = {
471
+ name: '${name}_sample',
472
+ label: '${toTitleCase(name)} Sample',
473
+ ownership: 'own',
474
+ fields: {
475
+ name: {
476
+ type: 'text',
477
+ label: 'Name',
478
+ required: true,
479
+ },
480
+ },
481
+ };
482
+
483
+ export default sample;
484
+ `,
485
+ "src/objects/index.ts": () => `export { default as sample } from './sample';
486
+ `,
487
+ "test/sample.test.ts": (name) => `import { describe, it, expect } from 'vitest';
488
+ import sample from '../src/objects/sample';
489
+
490
+ describe('${name} plugin', () => {
491
+ it('should export a valid sample object', () => {
492
+ expect(sample).toBeDefined();
493
+ expect(sample.name).toBe('${name}_sample');
494
+ expect(sample.fields).toHaveProperty('name');
495
+ });
496
+ });
497
+ `,
498
+ ".gitignore": () => `node_modules/
499
+ dist/
500
+ *.tsbuildinfo
501
+ `,
502
+ "README.md": (name) => `# @objectstack/plugin-${name}
503
+
504
+ ObjectStack Plugin: ${toTitleCase(name)}
505
+
506
+ ## Installation
507
+
508
+ \`\`\`bash
509
+ npm install @objectstack/plugin-${name}
510
+ \`\`\`
511
+
512
+ ## Usage
513
+
514
+ \`\`\`typescript
515
+ import { defineStack } from '@objectstack/spec';
516
+
517
+ export default defineStack({
518
+ plugins: [
519
+ '@objectstack/plugin-${name}',
520
+ ],
521
+ });
522
+ \`\`\`
523
+
524
+ ## Development
525
+
526
+ \`\`\`bash
527
+ # Run tests
528
+ npm test
529
+
530
+ # Build
531
+ npm run build
532
+
533
+ # Validate metadata
534
+ npm run validate
535
+ \`\`\`
536
+
537
+ ## License
538
+
539
+ MIT
540
+ `
541
+ }
542
+ }
543
+ };
544
+ function toTitleCase(str) {
545
+ return str.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
546
+ }
547
+ function printHeader(title) {
548
+ console.log(chalk.bold(`
549
+ \u25C6 ${title}`));
550
+ console.log(chalk.dim("\u2500".repeat(40)));
551
+ }
552
+ function printKV(key, value) {
553
+ console.log(` ${chalk.dim(key + ":")} ${chalk.white(value)}`);
554
+ }
555
+ function printSuccess(msg) {
556
+ console.log(chalk.green(` \u2713 ${msg}`));
557
+ }
558
+ function printError(msg) {
559
+ console.log(chalk.red(` \u2717 ${msg}`));
560
+ }
561
+ function printStep(msg) {
562
+ console.log(chalk.yellow(` \u2192 ${msg}`));
563
+ }
564
+ function printWarning(msg) {
565
+ console.log(chalk.yellow(` \u26A0 ${msg}`));
566
+ }
567
+ var program = new Command().name("create-objectstack").description("Create a new ObjectStack project").version("3.0.0").argument("[name]", "Project name (defaults to current directory name)").option(
568
+ "-t, --template <template>",
569
+ "Project template: minimal-api, full-stack, plugin",
570
+ "minimal-api"
571
+ ).option("--skip-install", "Skip dependency installation").action(async (name, options) => {
572
+ console.log("");
573
+ console.log(chalk.bold.cyan(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
574
+ console.log(chalk.bold.cyan(" \u2551") + chalk.bold(" \u25C6 Create ObjectStack ") + chalk.dim("v3.0") + chalk.bold.cyan(" \u2551"));
575
+ console.log(chalk.bold.cyan(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
576
+ printHeader("New Project");
577
+ const template = TEMPLATES[options.template];
578
+ if (!template) {
579
+ printError(`Unknown template: ${options.template}`);
580
+ console.log(chalk.dim(` Available: ${Object.keys(TEMPLATES).join(", ")}`));
581
+ process.exit(1);
582
+ }
583
+ const cwd = process.cwd();
584
+ const projectName = name || path.basename(cwd);
585
+ const targetDir = name ? path.resolve(cwd, name) : cwd;
586
+ const isCurrentDir = targetDir === cwd;
587
+ printKV("Project", projectName);
588
+ printKV("Template", `${options.template} \u2014 ${template.description}`);
589
+ printKV("Directory", targetDir);
590
+ console.log("");
591
+ if (!isCurrentDir && fs.existsSync(targetDir)) {
592
+ const existing = fs.readdirSync(targetDir);
593
+ if (existing.length > 0) {
594
+ printError(`Directory already exists and is not empty: ${targetDir}`);
595
+ process.exit(1);
596
+ }
597
+ }
598
+ const createdFiles = [];
599
+ try {
600
+ if (!fs.existsSync(targetDir)) {
601
+ fs.mkdirSync(targetDir, { recursive: true });
602
+ }
603
+ for (const [filePath, contentFn] of Object.entries(template.files)) {
604
+ const fullPath = path.join(targetDir, filePath);
605
+ const dir = path.dirname(fullPath);
606
+ if (!fs.existsSync(dir)) {
607
+ fs.mkdirSync(dir, { recursive: true });
608
+ }
609
+ fs.writeFileSync(fullPath, contentFn(projectName));
610
+ createdFiles.push(filePath);
611
+ }
612
+ console.log(chalk.bold(" Created files:"));
613
+ for (const f of createdFiles) {
614
+ console.log(chalk.green(` + ${f}`));
615
+ }
616
+ console.log("");
617
+ if (!options.skipInstall) {
618
+ printStep("Installing dependencies...");
619
+ try {
620
+ const pm = detectPackageManager();
621
+ execSync(`${pm} install`, { stdio: "inherit", cwd: targetDir });
622
+ console.log("");
623
+ } catch {
624
+ printWarning("Dependency installation failed. Run `npm install` manually.");
625
+ console.log("");
626
+ }
627
+ }
628
+ printSuccess("Project created!");
629
+ console.log("");
630
+ console.log(chalk.bold(" Next steps:"));
631
+ if (!isCurrentDir) {
632
+ console.log(chalk.dim(` cd ${name}`));
633
+ }
634
+ if (options.skipInstall) {
635
+ console.log(chalk.dim(" npm install"));
636
+ }
637
+ console.log(chalk.dim(" npm run dev # Start development server"));
638
+ console.log(chalk.dim(" npm run validate # Check configuration"));
639
+ console.log("");
640
+ } catch (error) {
641
+ printError(error.message || String(error));
642
+ process.exit(1);
643
+ }
644
+ });
645
+ function detectPackageManager() {
646
+ try {
647
+ execSync("pnpm --version", { stdio: "ignore" });
648
+ return "pnpm";
649
+ } catch {
650
+ return "npm";
651
+ }
652
+ }
653
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "create-objectstack",
3
+ "version": "3.0.0",
4
+ "description": "Create a new ObjectStack project — npx create-objectstack",
5
+ "bin": {
6
+ "create-objectstack": "./bin/create-objectstack.js"
7
+ },
8
+ "keywords": [
9
+ "objectstack",
10
+ "create",
11
+ "scaffold",
12
+ "cli"
13
+ ],
14
+ "type": "module",
15
+ "author": "Steedos",
16
+ "license": "Apache-2.0",
17
+ "dependencies": {
18
+ "chalk": "^5.3.0",
19
+ "commander": "^14.0.3"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^25.2.2",
23
+ "tsup": "^8.0.2",
24
+ "typescript": "^5.3.3"
25
+ },
26
+ "scripts": {
27
+ "build": "tsup",
28
+ "dev": "tsup --watch"
29
+ }
30
+ }