@gravito/scaffold 3.2.0 → 4.1.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.cjs CHANGED
@@ -51,6 +51,11 @@ var DependencyValidator = class _DependencyValidator {
51
51
  * Driver 到 Package 的映射規則
52
52
  */
53
53
  static DRIVER_DEPENDENCIES = [
54
+ {
55
+ driver: "none",
56
+ requiredPackages: [],
57
+ description: "No database driver - developer to choose and install"
58
+ },
54
59
  {
55
60
  driver: "redis",
56
61
  requiredPackages: ["@gravito/ion"],
@@ -527,12 +532,14 @@ var BaseGenerator = class {
527
532
  templateManager;
528
533
  fileMerger;
529
534
  filesCreated = [];
535
+ context = null;
530
536
  constructor(config) {
531
537
  this.config = config;
532
538
  this.templateManager = new TemplateManager(config.templatesDir);
533
539
  this.fileMerger = new FileMerger();
534
540
  }
535
541
  async generate(context) {
542
+ this.context = context;
536
543
  this.filesCreated = [];
537
544
  const structure = this.getDirectoryStructure(context);
538
545
  await this.createStructure(context.targetDir, structure, context);
@@ -768,6 +775,22 @@ describe('Example Test', () => {
768
775
 
769
776
  // src/utils/ConfigGenerator.ts
770
777
  var ConfigGenerator = class {
778
+ /**
779
+ * Generate database configuration based on driver type
780
+ */
781
+ static generateDatabaseConfig(driver) {
782
+ switch (driver) {
783
+ case "none":
784
+ return this.generateNoDatabaseConfig();
785
+ case "sqlite":
786
+ return this.generateSimpleDatabaseConfig();
787
+ case "postgresql":
788
+ case "mysql":
789
+ return this.generateDetailedDatabaseConfig();
790
+ default:
791
+ return this.generateNoDatabaseConfig();
792
+ }
793
+ }
771
794
  /**
772
795
  * Generate app configuration (simple version for Clean Architecture)
773
796
  */
@@ -850,6 +873,58 @@ export default {
850
873
  // 'AppServiceProvider',
851
874
  ],
852
875
  }
876
+ `;
877
+ }
878
+ /**
879
+ * Generate database configuration (no default driver - developer to choose)
880
+ */
881
+ static generateNoDatabaseConfig() {
882
+ return `/**
883
+ * Database Configuration
884
+ *
885
+ * Configure your database connection below.
886
+ * Choose one of the following drivers by installing the required package:
887
+ *
888
+ * SQLite: bun add better-sqlite3
889
+ * PostgreSQL: bun add pg
890
+ * MySQL: bun add mysql2
891
+ */
892
+ export default {
893
+ default: process.env.DB_CONNECTION ?? 'sqlite',
894
+
895
+ connections: {
896
+ sqlite: {
897
+ driver: 'sqlite',
898
+ database: process.env.DB_DATABASE ?? 'database/database.sqlite',
899
+ },
900
+
901
+ postgresql: {
902
+ driver: 'postgresql',
903
+ host: process.env.DB_HOST ?? 'localhost',
904
+ port: Number(process.env.DB_PORT ?? 5432),
905
+ database: process.env.DB_DATABASE ?? 'forge',
906
+ username: process.env.DB_USERNAME ?? 'forge',
907
+ password: process.env.DB_PASSWORD ?? '',
908
+ },
909
+
910
+ mysql: {
911
+ driver: 'mysql',
912
+ host: process.env.DB_HOST ?? 'localhost',
913
+ port: Number(process.env.DB_PORT ?? 3306),
914
+ database: process.env.DB_DATABASE ?? 'forge',
915
+ username: process.env.DB_USERNAME ?? 'forge',
916
+ password: process.env.DB_PASSWORD ?? '',
917
+ },
918
+ },
919
+
920
+ /**
921
+ * Migration settings
922
+ */
923
+ migrations: {
924
+ table: 'migrations',
925
+ path: 'database/migrations',
926
+ },
927
+ }
853
928
  `;
854
929
  }
855
930
  /**
@@ -980,6 +1055,118 @@ export default {
980
1055
  }
981
1056
  `;
982
1057
  }
1058
+ /**
1059
+ * Generate workers configuration for job queue system
1060
+ */
1061
+ static generateWorkersConfig(level = "basic") {
1062
+ switch (level) {
1063
+ case "advanced":
1064
+ return this.generateAdvancedWorkersConfig();
1065
+ case "production":
1066
+ return this.generateProductionWorkersConfig();
1067
+ default:
1068
+ return this.generateBasicWorkersConfig();
1069
+ }
1070
+ }
1071
+ /**
1072
+ * Generate basic workers configuration
1073
+ */
1074
+ static generateBasicWorkersConfig() {
1075
+ return ` /**
1076
+ * Workers Configuration
1077
+ *
1078
+ * Manages job execution in isolated worker threads.
1079
+ * Automatically selects best available runtime (Bun or Node.js).
1080
+ */
1081
+ workers: {
1082
+ // Runtime environment: 'auto' | 'bun' | 'node'
1083
+ runtime: process.env.WORKERS_RUNTIME as 'auto' | 'bun' | 'node' ?? 'auto',
1084
+
1085
+ pool: {
1086
+ poolSize: Number.parseInt(process.env.WORKERS_POOL_SIZE ?? '4', 10),
1087
+ minWorkers: Number.parseInt(process.env.WORKERS_MIN_WORKERS ?? '0', 10),
1088
+ healthCheckInterval: 30000,
1089
+ },
1090
+
1091
+ execution: {
1092
+ maxExecutionTime: Number.parseInt(process.env.WORKERS_MAX_EXECUTION_TIME ?? '30000', 10),
1093
+ maxMemory: Number.parseInt(process.env.WORKERS_MAX_MEMORY ?? '0', 10),
1094
+ idleTimeout: Number.parseInt(process.env.WORKERS_IDLE_TIMEOUT ?? '60000', 10),
1095
+ isolateContexts: process.env.WORKERS_ISOLATE_CONTEXTS === 'true',
1096
+ },
1097
+ },`;
1098
+ }
1099
+ /**
1100
+ * Generate advanced workers configuration with Bun optimizations
1101
+ */
1102
+ static generateAdvancedWorkersConfig() {
1103
+ return ` /**
1104
+ * Workers Configuration (Advanced)
1105
+ *
1106
+ * Manages job execution in isolated worker threads.
1107
+ * Includes Bun-specific optimizations for enhanced performance.
1108
+ *
1109
+ * Performance characteristics:
1110
+ * - Bun: 2-241x faster message passing, 20-30% less memory (smol mode)
1111
+ * - Node.js: Stable, widely tested, compatible
1112
+ */
1113
+ workers: {
1114
+ runtime: process.env.WORKERS_RUNTIME as 'auto' | 'bun' | 'node' ?? 'auto',
1115
+
1116
+ pool: {
1117
+ poolSize: Number.parseInt(process.env.WORKERS_POOL_SIZE ?? '4', 10),
1118
+ minWorkers: Number.parseInt(process.env.WORKERS_MIN_WORKERS ?? '1', 10),
1119
+ healthCheckInterval: 30000,
1120
+ },
1121
+
1122
+ execution: {
1123
+ maxExecutionTime: Number.parseInt(process.env.WORKERS_MAX_EXECUTION_TIME ?? '30000', 10),
1124
+ maxMemory: Number.parseInt(process.env.WORKERS_MAX_MEMORY ?? '0', 10),
1125
+ idleTimeout: Number.parseInt(process.env.WORKERS_IDLE_TIMEOUT ?? '60000', 10),
1126
+ isolateContexts: process.env.WORKERS_ISOLATE_CONTEXTS === 'true',
1127
+ },
1128
+
1129
+ // Bun-specific optimizations
1130
+ bun: {
1131
+ smol: process.env.WORKERS_BUN_SMOL === 'true',
1132
+ preload: process.env.WORKERS_BUN_PRELOAD
1133
+ ? process.env.WORKERS_BUN_PRELOAD.split(',').map((p) => p.trim())
1134
+ : undefined,
1135
+ inspectPort: process.env.WORKERS_BUN_INSPECT_PORT
1136
+ ? Number.parseInt(process.env.WORKERS_BUN_INSPECT_PORT, 10)
1137
+ : undefined,
1138
+ },
1139
+ },`;
1140
+ }
1141
+ /**
1142
+ * Generate production-optimized workers configuration
1143
+ */
1144
+ static generateProductionWorkersConfig() {
1145
+ return ` /**
1146
+ * Workers Configuration (Production Optimized)
1147
+ */
1148
+ workers: {
1149
+ runtime: 'auto' as const,
1150
+
1151
+ pool: {
1152
+ poolSize: Number.parseInt(process.env.WORKERS_POOL_SIZE ?? '8', 10),
1153
+ minWorkers: 2,
1154
+ healthCheckInterval: 30000,
1155
+ },
1156
+
1157
+ execution: {
1158
+ maxExecutionTime: 30000,
1159
+ maxMemory: Number.parseInt(process.env.WORKERS_MAX_MEMORY ?? '512', 10),
1160
+ idleTimeout: 60000,
1161
+ isolateContexts: false,
1162
+ },
1163
+
1164
+ bun: {
1165
+ smol: true,
1166
+ preload: process.env.WORKERS_BUN_PRELOAD?.split(',').map((p) => p.trim()),
1167
+ },
1168
+ },`;
1169
+ }
983
1170
  };
984
1171
 
985
1172
  // src/utils/ServiceProviderGenerator.ts
@@ -1385,7 +1572,8 @@ var CleanArchitectureGenerator = class extends BaseGenerator {
1385
1572
  return ConfigGenerator.generateSimpleAppConfig(context);
1386
1573
  }
1387
1574
  generateDatabaseConfig() {
1388
- return ConfigGenerator.generateSimpleDatabaseConfig();
1575
+ const driver = this.context?.profileConfig?.drivers?.database ?? "none";
1576
+ return ConfigGenerator.generateDatabaseConfig(driver);
1389
1577
  }
1390
1578
  generateAuthConfig() {
1391
1579
  return ConfigGenerator.generateAuthConfig();
@@ -1993,7 +2181,9 @@ Created with \u2764\uFE0F using Gravito Framework
1993
2181
 
1994
2182
  // src/generators/ddd/BootstrapGenerator.ts
1995
2183
  var BootstrapGenerator = class {
2184
+ context = null;
1996
2185
  generate(context) {
2186
+ this.context = context;
1997
2187
  return {
1998
2188
  type: "directory",
1999
2189
  name: "Bootstrap",
@@ -2006,6 +2196,7 @@ var BootstrapGenerator = class {
2006
2196
  };
2007
2197
  }
2008
2198
  generateConfigDirectory(context) {
2199
+ this.context = context;
2009
2200
  return {
2010
2201
  type: "directory",
2011
2202
  name: "config",
@@ -2201,13 +2392,8 @@ export default {
2201
2392
  `;
2202
2393
  }
2203
2394
  generateDatabaseConfig() {
2204
- return `export default {
2205
- default: process.env.DB_CONNECTION ?? 'sqlite',
2206
- connections: {
2207
- sqlite: { driver: 'sqlite', database: 'database/database.sqlite' },
2208
- },
2209
- }
2210
- `;
2395
+ const driver = this.context?.profileConfig?.drivers?.database ?? "none";
2396
+ return ConfigGenerator.generateDatabaseConfig(driver);
2211
2397
  }
2212
2398
  generateCacheConfig() {
2213
2399
  return `export default {
@@ -2368,6 +2554,30 @@ var ModuleGenerator = class {
2368
2554
  ]
2369
2555
  }
2370
2556
  ]
2557
+ },
2558
+ // UserInterface Layer
2559
+ {
2560
+ type: "directory",
2561
+ name: "UserInterface",
2562
+ children: [
2563
+ {
2564
+ type: "directory",
2565
+ name: "Http",
2566
+ children: [
2567
+ {
2568
+ type: "directory",
2569
+ name: "Controllers",
2570
+ children: [
2571
+ {
2572
+ type: "file",
2573
+ name: `${name}Controller.ts`,
2574
+ content: this.generateController(name)
2575
+ }
2576
+ ]
2577
+ }
2578
+ ]
2579
+ }
2580
+ ]
2371
2581
  }
2372
2582
  ]
2373
2583
  };
@@ -2383,17 +2593,13 @@ import { ${name}Created } from '../../Events/${name}Created'
2383
2593
  import { ${name}Status } from './${name}Status'
2384
2594
 
2385
2595
  export interface ${name}Props {
2386
- // Add properties here
2387
2596
  status: ${name}Status
2388
2597
  createdAt: Date
2389
2598
  }
2390
2599
 
2391
2600
  export class ${name} extends AggregateRoot<Id> {
2392
- private props: ${name}Props
2393
-
2394
- private constructor(id: Id, props: ${name}Props) {
2601
+ private constructor(id: Id, private props: ${name}Props) {
2395
2602
  super(id)
2396
- this.props = props
2397
2603
  }
2398
2604
 
2399
2605
  static create(id: Id): ${name} {
@@ -2411,7 +2617,12 @@ export class ${name} extends AggregateRoot<Id> {
2411
2617
  return this.props.status
2412
2618
  }
2413
2619
 
2414
- // Add domain methods here
2620
+ /**
2621
+ * Complete the ${name} process
2622
+ */
2623
+ complete(): void {
2624
+ this.props.status = ${name}Status.COMPLETED
2625
+ }
2415
2626
  }
2416
2627
  `;
2417
2628
  }
@@ -2436,17 +2647,13 @@ export enum ${name}Status {
2436
2647
  import { DomainEvent } from '@gravito/enterprise'
2437
2648
 
2438
2649
  export class ${name}Created extends DomainEvent {
2439
- constructor(public readonly ${name.toLowerCase()}Id: string) {
2650
+ constructor(public readonly aggregateId: string) {
2440
2651
  super()
2441
2652
  }
2442
2653
 
2443
2654
  override get eventName(): string {
2444
2655
  return '${name.toLowerCase()}.created'
2445
2656
  }
2446
-
2447
- get aggregateId(): string {
2448
- return this.${name.toLowerCase()}Id
2449
- }
2450
2657
  }
2451
2658
  `;
2452
2659
  }
@@ -2473,7 +2680,6 @@ import { Command } from '@gravito/enterprise'
2473
2680
 
2474
2681
  export class Create${name}Command extends Command {
2475
2682
  constructor(
2476
- // Add command properties
2477
2683
  public readonly id?: string
2478
2684
  ) {
2479
2685
  super()
@@ -2528,13 +2734,15 @@ export class Get${name}ByIdQuery extends Query {
2528
2734
  import { QueryHandler } from '@gravito/enterprise'
2529
2735
  import type { I${name}Repository } from '../../../Domain/Repositories/I${name}Repository'
2530
2736
  import type { ${name}DTO } from '../../DTOs/${name}DTO'
2737
+ import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
2531
2738
  import type { Get${name}ByIdQuery } from './Get${name}ByIdQuery'
2532
2739
 
2533
2740
  export class Get${name}ByIdHandler implements QueryHandler<Get${name}ByIdQuery, ${name}DTO | null> {
2534
2741
  constructor(private repository: I${name}Repository) {}
2535
2742
 
2536
2743
  async handle(query: Get${name}ByIdQuery): Promise<${name}DTO | null> {
2537
- const aggregate = await this.repository.findById(query.id as any) // Simplified for demo
2744
+ const id = Id.from(query.id)
2745
+ const aggregate = await this.repository.findById(id)
2538
2746
  if (!aggregate) return null
2539
2747
 
2540
2748
  return {
@@ -2555,7 +2763,6 @@ import type { ${name}Status } from '../../Domain/Aggregates/${name}/${name}Statu
2555
2763
  export interface ${name}DTO {
2556
2764
  id: string
2557
2765
  status: ${name}Status
2558
- // Add more fields
2559
2766
  }
2560
2767
  `;
2561
2768
  }
@@ -2566,29 +2773,29 @@ export interface ${name}DTO {
2566
2773
 
2567
2774
  import type { ${name} } from '../../Domain/Aggregates/${name}/${name}'
2568
2775
  import type { I${name}Repository } from '../../Domain/Repositories/I${name}Repository'
2569
- import type { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
2570
-
2571
- const store = new Map<string, ${name}>()
2776
+ import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
2572
2777
 
2573
2778
  export class ${name}Repository implements I${name}Repository {
2779
+ private store = new Map<string, ${name}>()
2780
+
2574
2781
  async findById(id: Id): Promise<${name} | null> {
2575
- return store.get(id.value) ?? null
2782
+ return this.store.get(id.value) ?? null
2576
2783
  }
2577
2784
 
2578
2785
  async save(aggregate: ${name}): Promise<void> {
2579
- store.set(aggregate.id.value, aggregate)
2786
+ this.store.set(aggregate.id.value, aggregate)
2580
2787
  }
2581
2788
 
2582
2789
  async delete(id: Id): Promise<void> {
2583
- store.delete(id.value)
2790
+ this.store.delete(id.value)
2584
2791
  }
2585
2792
 
2586
2793
  async findAll(): Promise<${name}[]> {
2587
- return Array.from(store.values())
2794
+ return Array.from(this.store.values())
2588
2795
  }
2589
2796
 
2590
2797
  async exists(id: Id): Promise<boolean> {
2591
- return store.has(id.value)
2798
+ return this.store.has(id.value)
2592
2799
  }
2593
2800
  }
2594
2801
  `;
@@ -2610,6 +2817,37 @@ export class ${name}ServiceProvider extends ServiceProvider {
2610
2817
  console.log('[${name}] Module loaded')
2611
2818
  }
2612
2819
  }
2820
+ `;
2821
+ }
2822
+ generateController(name) {
2823
+ return `/**
2824
+ * ${name} Controller
2825
+ */
2826
+
2827
+ import type { GravitoContext } from '@gravito/core'
2828
+
2829
+ export class ${name}Controller {
2830
+ /**
2831
+ * GET /${name.toLowerCase()}
2832
+ */
2833
+ async index(ctx: GravitoContext) {
2834
+ return ctx.json({
2835
+ success: true,
2836
+ data: []
2837
+ })
2838
+ }
2839
+
2840
+ /**
2841
+ * GET /${name.toLowerCase()}/:id
2842
+ */
2843
+ async show(ctx: GravitoContext) {
2844
+ const id = ctx.req.param('id')
2845
+ return ctx.json({
2846
+ success: true,
2847
+ data: { id }
2848
+ })
2849
+ }
2850
+ }
2613
2851
  `;
2614
2852
  }
2615
2853
  };
@@ -2784,24 +3022,39 @@ export class Email extends ValueObject<EmailProps> {
2784
3022
 
2785
3023
  import type { DomainEvent } from '@gravito/enterprise'
2786
3024
 
2787
- type EventHandler = (event: DomainEvent) => void | Promise<void>
3025
+ type EventHandler<T extends DomainEvent = any> = (event: T) => void | Promise<void>
2788
3026
 
2789
3027
  export class EventDispatcher {
2790
3028
  private handlers: Map<string, EventHandler[]> = new Map()
2791
3029
 
2792
- subscribe(eventName: string, handler: EventHandler): void {
3030
+ /**
3031
+ * Subscribe to an event
3032
+ */
3033
+ subscribe<T extends DomainEvent>(eventName: string, handler: EventHandler<T>): void {
2793
3034
  const handlers = this.handlers.get(eventName) ?? []
2794
3035
  handlers.push(handler)
2795
3036
  this.handlers.set(eventName, handlers)
2796
3037
  }
2797
3038
 
3039
+ /**
3040
+ * Dispatch a single event
3041
+ */
2798
3042
  async dispatch(event: DomainEvent): Promise<void> {
2799
3043
  const handlers = this.handlers.get(event.eventName) ?? []
2800
- for (const handler of handlers) {
2801
- await handler(event)
2802
- }
3044
+ const promises = handlers.map(handler => {
3045
+ try {
3046
+ return handler(event)
3047
+ } catch (error) {
3048
+ console.error(\`[EventDispatcher] Error in handler for \${event.eventName}:\`, error)
3049
+ }
3050
+ })
3051
+
3052
+ await Promise.all(promises)
2803
3053
  }
2804
3054
 
3055
+ /**
3056
+ * Dispatch multiple events sequentially
3057
+ */
2805
3058
  async dispatchAll(events: DomainEvent[]): Promise<void> {
2806
3059
  for (const event of events) {
2807
3060
  await this.dispatch(event)
@@ -3194,7 +3447,8 @@ describe('Example Test', () => {
3194
3447
  return ConfigGenerator.generateDetailedAppConfig(context);
3195
3448
  }
3196
3449
  generateDatabaseConfig() {
3197
- return ConfigGenerator.generateDetailedDatabaseConfig();
3450
+ const driver = this.context?.profileConfig?.drivers?.database ?? "none";
3451
+ return ConfigGenerator.generateDatabaseConfig(driver);
3198
3452
  }
3199
3453
  generateAuthConfig() {
3200
3454
  return `/**
@@ -3910,9 +4164,9 @@ var SatelliteGenerator = class extends BaseGenerator {
3910
4164
  children: [
3911
4165
  {
3912
4166
  type: "directory",
3913
- name: "Entities",
4167
+ name: "Aggregates",
3914
4168
  children: [
3915
- { type: "file", name: `${name}.ts`, content: this.generateEntity(name) }
4169
+ { type: "file", name: `${name}.ts`, content: this.generateAggregate(name) }
3916
4170
  ]
3917
4171
  },
3918
4172
  {
@@ -3926,8 +4180,24 @@ var SatelliteGenerator = class extends BaseGenerator {
3926
4180
  }
3927
4181
  ]
3928
4182
  },
3929
- { type: "directory", name: "ValueObjects", children: [] },
3930
- { type: "directory", name: "Events", children: [] }
4183
+ {
4184
+ type: "directory",
4185
+ name: "ValueObjects",
4186
+ children: [
4187
+ { type: "file", name: `${name}Id.ts`, content: this.generateIdValueObject(name) }
4188
+ ]
4189
+ },
4190
+ {
4191
+ type: "directory",
4192
+ name: "Events",
4193
+ children: [
4194
+ {
4195
+ type: "file",
4196
+ name: `${name}Created.ts`,
4197
+ content: this.generateCreatedEvent(name)
4198
+ }
4199
+ ]
4200
+ }
3931
4201
  ]
3932
4202
  },
3933
4203
  // Application Layer
@@ -3968,6 +4238,31 @@ var SatelliteGenerator = class extends BaseGenerator {
3968
4238
  }
3969
4239
  ]
3970
4240
  },
4241
+ // Interface Layer (HTTP/API)
4242
+ {
4243
+ type: "directory",
4244
+ name: "Interface",
4245
+ children: [
4246
+ {
4247
+ type: "directory",
4248
+ name: "Http",
4249
+ children: [
4250
+ {
4251
+ type: "directory",
4252
+ name: "Controllers",
4253
+ children: [
4254
+ {
4255
+ type: "file",
4256
+ name: `${name}Controller.ts`,
4257
+ content: this.generateController(name)
4258
+ }
4259
+ ]
4260
+ },
4261
+ { type: "directory", name: "Middleware", children: [] }
4262
+ ]
4263
+ }
4264
+ ]
4265
+ },
3971
4266
  // Entry Point
3972
4267
  { type: "file", name: "index.ts", content: this.generateEntryPoint(name) },
3973
4268
  {
@@ -3985,13 +4280,12 @@ var SatelliteGenerator = class extends BaseGenerator {
3985
4280
  {
3986
4281
  type: "file",
3987
4282
  name: "unit.test.ts",
3988
- content: `import { describe, it, expect } from "bun:test";
3989
-
3990
- describe("${name}", () => {
3991
- it("should work", () => {
3992
- expect(true).toBe(true);
3993
- });
3994
- });`
4283
+ content: this.generateUnitTest(name)
4284
+ },
4285
+ {
4286
+ type: "file",
4287
+ name: "integration.test.ts",
4288
+ content: this.generateIntegrationTest(name)
3995
4289
  }
3996
4290
  ]
3997
4291
  }
@@ -4000,35 +4294,76 @@ describe("${name}", () => {
4000
4294
  // ─────────────────────────────────────────────────────────────
4001
4295
  // Domain Templates
4002
4296
  // ─────────────────────────────────────────────────────────────
4003
- generateEntity(name) {
4004
- return `import { Entity } from '@gravito/enterprise'
4297
+ generateIdValueObject(name) {
4298
+ return `import { ValueObject } from '@gravito/enterprise'
4299
+
4300
+ interface IdProps {
4301
+ value: string
4302
+ }
4303
+
4304
+ export class ${name}Id extends ValueObject<IdProps> {
4305
+ constructor(value: string) {
4306
+ super({ value })
4307
+ }
4308
+
4309
+ static create(): ${name}Id {
4310
+ return new ${name}Id(crypto.randomUUID())
4311
+ }
4312
+
4313
+ get value(): string { return this.props.value }
4314
+ }
4315
+ `;
4316
+ }
4317
+ generateAggregate(name) {
4318
+ return `import { AggregateRoot } from '@gravito/enterprise'
4319
+ import { ${name}Id } from '../ValueObjects/${name}Id'
4320
+ import { ${name}Created } from '../Events/${name}Created'
4005
4321
 
4006
4322
  export interface ${name}Props {
4007
4323
  name: string
4008
4324
  createdAt: Date
4009
4325
  }
4010
4326
 
4011
- export class ${name} extends Entity<string> {
4012
- constructor(id: string, private props: ${name}Props) {
4327
+ export class ${name} extends AggregateRoot<${name}Id> {
4328
+ constructor(id: ${name}Id, private props: ${name}Props) {
4013
4329
  super(id)
4014
4330
  }
4015
4331
 
4016
- static create(id: string, name: string): ${name} {
4017
- return new ${name}(id, {
4332
+ static create(id: ${name}Id, name: string): ${name} {
4333
+ const aggregate = new ${name}(id, {
4018
4334
  name,
4019
4335
  createdAt: new Date()
4020
4336
  })
4337
+
4338
+ aggregate.addDomainEvent(new ${name}Created(id.value))
4339
+
4340
+ return aggregate
4021
4341
  }
4022
4342
 
4023
4343
  get name() { return this.props.name }
4024
4344
  }
4345
+ `;
4346
+ }
4347
+ generateCreatedEvent(name) {
4348
+ return `import { DomainEvent } from '@gravito/enterprise'
4349
+
4350
+ export class ${name}Created extends DomainEvent {
4351
+ constructor(public readonly aggregateId: string) {
4352
+ super()
4353
+ }
4354
+
4355
+ get eventName(): string {
4356
+ return '${this.context?.nameKebabCase}.created'
4357
+ }
4358
+ }
4025
4359
  `;
4026
4360
  }
4027
4361
  generateRepositoryInterface(name) {
4028
4362
  return `import { Repository } from '@gravito/enterprise'
4029
- import { ${name} } from '../Entities/${name}'
4363
+ import { ${name} } from '../Aggregates/${name}'
4364
+ import { ${name}Id } from '../ValueObjects/${name}Id'
4030
4365
 
4031
- export interface I${name}Repository extends Repository<${name}, string> {
4366
+ export interface I${name}Repository extends Repository<${name}, ${name}Id> {
4032
4367
  // Add custom methods here
4033
4368
  }
4034
4369
  `;
@@ -4039,7 +4374,8 @@ export interface I${name}Repository extends Repository<${name}, string> {
4039
4374
  generateUseCase(name) {
4040
4375
  return `import { UseCase } from '@gravito/enterprise'
4041
4376
  import { I${name}Repository } from '../../Domain/Contracts/I${name}Repository'
4042
- import { ${name} } from '../../Domain/Entities/${name}'
4377
+ import { ${name} } from '../../Domain/Aggregates/${name}'
4378
+ import { ${name}Id } from '../../Domain/ValueObjects/${name}Id'
4043
4379
 
4044
4380
  export interface Create${name}Input {
4045
4381
  name: string
@@ -4051,12 +4387,12 @@ export class Create${name} extends UseCase<Create${name}Input, string> {
4051
4387
  }
4052
4388
 
4053
4389
  async execute(input: Create${name}Input): Promise<string> {
4054
- const id = crypto.randomUUID()
4390
+ const id = ${name}Id.create()
4055
4391
  const entity = ${name}.create(id, input.name)
4056
4392
 
4057
4393
  await this.repository.save(entity)
4058
4394
 
4059
- return id
4395
+ return id.value
4060
4396
  }
4061
4397
  }
4062
4398
  `;
@@ -4066,17 +4402,16 @@ export class Create${name} extends UseCase<Create${name}Input, string> {
4066
4402
  // ─────────────────────────────────────────────────────────────
4067
4403
  generateAtlasRepository(name) {
4068
4404
  return `import { I${name}Repository } from '../../Domain/Contracts/I${name}Repository'
4069
- import { ${name} } from '../../Domain/Entities/${name}'
4070
- import { DB } from '@gravito/atlas'
4405
+ import { ${name} } from '../../Domain/Aggregates/${name}'
4406
+ import { ${name}Id } from '../../Domain/ValueObjects/${name}Id'
4071
4407
 
4072
4408
  export class Atlas${name}Repository implements I${name}Repository {
4073
4409
  async save(entity: ${name}): Promise<void> {
4074
- // Dogfooding: Use @gravito/atlas for persistence
4075
- console.log('[Atlas] Saving entity:', entity.id)
4076
- // await DB.table('${name.toLowerCase()}s').insert({ ... })
4410
+ // Implementation using @gravito/atlas
4411
+ console.log('[Atlas] Saving aggregate:', entity.id.value)
4077
4412
  }
4078
4413
 
4079
- async findById(id: string): Promise<${name} | null> {
4414
+ async findById(id: ${name}Id): Promise<${name} | null> {
4080
4415
  return null
4081
4416
  }
4082
4417
 
@@ -4084,12 +4419,77 @@ export class Atlas${name}Repository implements I${name}Repository {
4084
4419
  return []
4085
4420
  }
4086
4421
 
4087
- async delete(id: string): Promise<void> {}
4422
+ async delete(id: ${name}Id): Promise<void> {}
4088
4423
 
4089
- async exists(id: string): Promise<boolean> {
4424
+ async exists(id: ${name}Id): Promise<boolean> {
4090
4425
  return false
4091
4426
  }
4092
4427
  }
4428
+ `;
4429
+ }
4430
+ // ─────────────────────────────────────────────────────────────
4431
+ // Test Templates
4432
+ // ─────────────────────────────────────────────────────────────
4433
+ generateUnitTest(name) {
4434
+ return `import { describe, it, expect } from "bun:test";
4435
+ import { ${name} } from "../src/Domain/Aggregates/${name}";
4436
+ import { ${name}Id } from "../src/Domain/ValueObjects/${name}Id";
4437
+
4438
+ describe("${name} Aggregate", () => {
4439
+ it("should create a new aggregate with a domain event", () => {
4440
+ const id = ${name}Id.create();
4441
+ const aggregate = ${name}.create(id, "Test Name");
4442
+
4443
+ expect(aggregate.id).toBe(id);
4444
+ expect(aggregate.name).toBe("Test Name");
4445
+ expect(aggregate.pullDomainEvents()).toHaveLength(1);
4446
+ });
4447
+ });`;
4448
+ }
4449
+ generateIntegrationTest(name) {
4450
+ return `import { describe, it, expect, beforeAll } from "bun:test";
4451
+ import { PlanetCore } from "@gravito/core";
4452
+
4453
+ describe("${name} Integration", () => {
4454
+ let core: PlanetCore;
4455
+
4456
+ beforeAll(async () => {
4457
+ core = new PlanetCore();
4458
+ // Setup dependencies here
4459
+ });
4460
+
4461
+ it("should handle the creation flow", async () => {
4462
+ expect(true).toBe(true); // Placeholder for actual integration logic
4463
+ });
4464
+ });`;
4465
+ }
4466
+ // ─────────────────────────────────────────────────────────────
4467
+ // Interface Templates
4468
+ // ─────────────────────────────────────────────────────────────
4469
+ generateController(name) {
4470
+ return `import type { GravitoContext } from '@gravito/core'
4471
+ import { Create${name} } from '../../../Application/UseCases/Create${name}'
4472
+
4473
+ export class ${name}Controller {
4474
+ constructor(private createUseCase: Create${name}) {}
4475
+
4476
+ async store(ctx: GravitoContext) {
4477
+ const body = await ctx.req.json()
4478
+ const id = await this.createUseCase.execute({ name: body.name })
4479
+
4480
+ return ctx.json({
4481
+ success: true,
4482
+ data: { id }
4483
+ }, 201)
4484
+ }
4485
+
4486
+ async index(ctx: GravitoContext) {
4487
+ return ctx.json({
4488
+ success: true,
4489
+ data: []
4490
+ })
4491
+ }
4492
+ }
4093
4493
  `;
4094
4494
  }
4095
4495
  // ─────────────────────────────────────────────────────────────
@@ -4098,17 +4498,22 @@ export class Atlas${name}Repository implements I${name}Repository {
4098
4498
  generateEntryPoint(name) {
4099
4499
  return `import { ServiceProvider, type Container } from '@gravito/core'
4100
4500
  import { Atlas${name}Repository } from './Infrastructure/Persistence/Atlas${name}Repository'
4501
+ import { Create${name} } from './Application/UseCases/Create${name}'
4502
+ import { ${name}Controller } from './Interface/Http/Controllers/${name}Controller'
4101
4503
 
4102
4504
  export class ${name}ServiceProvider extends ServiceProvider {
4103
4505
  register(container: Container): void {
4104
- // Bind Repository
4506
+ // 1. Bind Repository (Infrastructure)
4105
4507
  container.singleton('${name.toLowerCase()}.repo', () => new Atlas${name}Repository())
4106
4508
 
4107
- // Bind UseCases
4108
- container.singleton('${name.toLowerCase()}.create', () => {
4109
- return new (require('./Application/UseCases/Create${name}').Create${name})(
4110
- container.make('${name.toLowerCase()}.repo')
4111
- )
4509
+ // 2. Bind UseCases (Application)
4510
+ container.singleton('${name.toLowerCase()}.usecase.create', (c) => {
4511
+ return new Create${name}(c.make('${name.toLowerCase()}.repo'))
4512
+ })
4513
+
4514
+ // 3. Bind Controllers (Interface)
4515
+ container.singleton('${name.toLowerCase()}.controller', (c) => {
4516
+ return new ${name}Controller(c.make('${name.toLowerCase()}.usecase.create'))
4112
4517
  })
4113
4518
  }
4114
4519
 
@@ -4213,13 +4618,15 @@ var ProfileResolver = class _ProfileResolver {
4213
4618
  static DEFAULTS = {
4214
4619
  core: {
4215
4620
  drivers: {
4216
- database: "sqlite",
4621
+ database: "none",
4217
4622
  cache: "memory",
4218
4623
  queue: "sync",
4219
4624
  storage: "local",
4220
4625
  session: "file"
4221
4626
  },
4222
- features: []
4627
+ features: [],
4628
+ workers: "basic"
4629
+ // Basic workers configuration for core profile
4223
4630
  },
4224
4631
  scale: {
4225
4632
  drivers: {
@@ -4229,7 +4636,9 @@ var ProfileResolver = class _ProfileResolver {
4229
4636
  storage: "s3",
4230
4637
  session: "redis"
4231
4638
  },
4232
- features: ["stream", "nebula"]
4639
+ features: ["stream", "nebula"],
4640
+ workers: "advanced"
4641
+ // Advanced workers with Bun optimizations
4233
4642
  },
4234
4643
  enterprise: {
4235
4644
  drivers: {
@@ -4239,14 +4648,17 @@ var ProfileResolver = class _ProfileResolver {
4239
4648
  storage: "s3",
4240
4649
  session: "redis"
4241
4650
  },
4242
- features: ["stream", "nebula", "monitor", "sentinel", "fortify"]
4651
+ features: ["stream", "nebula", "monitor", "sentinel", "fortify"],
4652
+ workers: "production"
4653
+ // Production-optimized workers
4243
4654
  }
4244
4655
  };
4245
4656
  resolve(profile = "core", withFeatures = []) {
4246
4657
  const base = _ProfileResolver.DEFAULTS[profile] || _ProfileResolver.DEFAULTS.core;
4247
4658
  const config = {
4248
4659
  drivers: { ...base.drivers },
4249
- features: [...base.features]
4660
+ features: [...base.features],
4661
+ workers: base.workers
4250
4662
  };
4251
4663
  for (const feature of withFeatures) {
4252
4664
  this.applyFeature(config, feature);
@@ -4513,16 +4925,8 @@ describe('Example Test', () => {
4513
4925
  `;
4514
4926
  }
4515
4927
  generateDatabaseConfig() {
4516
- return `export default {
4517
- default: process.env.DB_CONNECTION ?? 'sqlite',
4518
- connections: {
4519
- sqlite: {
4520
- driver: 'sqlite',
4521
- database: process.env.DB_DATABASE ?? 'database/database.sqlite',
4522
- },
4523
- },
4524
- }
4525
- `;
4928
+ const driver = this.context?.profileConfig?.drivers?.database ?? "none";
4929
+ return ConfigGenerator.generateDatabaseConfig(driver);
4526
4930
  }
4527
4931
  // ─────────────────────────────────────────────────────────────
4528
4932
  // Model Generators