@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.js CHANGED
@@ -4,6 +4,11 @@ var DependencyValidator = class _DependencyValidator {
4
4
  * Driver 到 Package 的映射規則
5
5
  */
6
6
  static DRIVER_DEPENDENCIES = [
7
+ {
8
+ driver: "none",
9
+ requiredPackages: [],
10
+ description: "No database driver - developer to choose and install"
11
+ },
7
12
  {
8
13
  driver: "redis",
9
14
  requiredPackages: ["@gravito/ion"],
@@ -480,12 +485,14 @@ var BaseGenerator = class {
480
485
  templateManager;
481
486
  fileMerger;
482
487
  filesCreated = [];
488
+ context = null;
483
489
  constructor(config) {
484
490
  this.config = config;
485
491
  this.templateManager = new TemplateManager(config.templatesDir);
486
492
  this.fileMerger = new FileMerger();
487
493
  }
488
494
  async generate(context) {
495
+ this.context = context;
489
496
  this.filesCreated = [];
490
497
  const structure = this.getDirectoryStructure(context);
491
498
  await this.createStructure(context.targetDir, structure, context);
@@ -721,6 +728,22 @@ describe('Example Test', () => {
721
728
 
722
729
  // src/utils/ConfigGenerator.ts
723
730
  var ConfigGenerator = class {
731
+ /**
732
+ * Generate database configuration based on driver type
733
+ */
734
+ static generateDatabaseConfig(driver) {
735
+ switch (driver) {
736
+ case "none":
737
+ return this.generateNoDatabaseConfig();
738
+ case "sqlite":
739
+ return this.generateSimpleDatabaseConfig();
740
+ case "postgresql":
741
+ case "mysql":
742
+ return this.generateDetailedDatabaseConfig();
743
+ default:
744
+ return this.generateNoDatabaseConfig();
745
+ }
746
+ }
724
747
  /**
725
748
  * Generate app configuration (simple version for Clean Architecture)
726
749
  */
@@ -803,6 +826,58 @@ export default {
803
826
  // 'AppServiceProvider',
804
827
  ],
805
828
  }
829
+ `;
830
+ }
831
+ /**
832
+ * Generate database configuration (no default driver - developer to choose)
833
+ */
834
+ static generateNoDatabaseConfig() {
835
+ return `/**
836
+ * Database Configuration
837
+ *
838
+ * Configure your database connection below.
839
+ * Choose one of the following drivers by installing the required package:
840
+ *
841
+ * SQLite: bun add better-sqlite3
842
+ * PostgreSQL: bun add pg
843
+ * MySQL: bun add mysql2
844
+ */
845
+ export default {
846
+ default: process.env.DB_CONNECTION ?? 'sqlite',
847
+
848
+ connections: {
849
+ sqlite: {
850
+ driver: 'sqlite',
851
+ database: process.env.DB_DATABASE ?? 'database/database.sqlite',
852
+ },
853
+
854
+ postgresql: {
855
+ driver: 'postgresql',
856
+ host: process.env.DB_HOST ?? 'localhost',
857
+ port: Number(process.env.DB_PORT ?? 5432),
858
+ database: process.env.DB_DATABASE ?? 'forge',
859
+ username: process.env.DB_USERNAME ?? 'forge',
860
+ password: process.env.DB_PASSWORD ?? '',
861
+ },
862
+
863
+ mysql: {
864
+ driver: 'mysql',
865
+ host: process.env.DB_HOST ?? 'localhost',
866
+ port: Number(process.env.DB_PORT ?? 3306),
867
+ database: process.env.DB_DATABASE ?? 'forge',
868
+ username: process.env.DB_USERNAME ?? 'forge',
869
+ password: process.env.DB_PASSWORD ?? '',
870
+ },
871
+ },
872
+
873
+ /**
874
+ * Migration settings
875
+ */
876
+ migrations: {
877
+ table: 'migrations',
878
+ path: 'database/migrations',
879
+ },
880
+ }
806
881
  `;
807
882
  }
808
883
  /**
@@ -933,6 +1008,118 @@ export default {
933
1008
  }
934
1009
  `;
935
1010
  }
1011
+ /**
1012
+ * Generate workers configuration for job queue system
1013
+ */
1014
+ static generateWorkersConfig(level = "basic") {
1015
+ switch (level) {
1016
+ case "advanced":
1017
+ return this.generateAdvancedWorkersConfig();
1018
+ case "production":
1019
+ return this.generateProductionWorkersConfig();
1020
+ default:
1021
+ return this.generateBasicWorkersConfig();
1022
+ }
1023
+ }
1024
+ /**
1025
+ * Generate basic workers configuration
1026
+ */
1027
+ static generateBasicWorkersConfig() {
1028
+ return ` /**
1029
+ * Workers Configuration
1030
+ *
1031
+ * Manages job execution in isolated worker threads.
1032
+ * Automatically selects best available runtime (Bun or Node.js).
1033
+ */
1034
+ workers: {
1035
+ // Runtime environment: 'auto' | 'bun' | 'node'
1036
+ runtime: process.env.WORKERS_RUNTIME as 'auto' | 'bun' | 'node' ?? 'auto',
1037
+
1038
+ pool: {
1039
+ poolSize: Number.parseInt(process.env.WORKERS_POOL_SIZE ?? '4', 10),
1040
+ minWorkers: Number.parseInt(process.env.WORKERS_MIN_WORKERS ?? '0', 10),
1041
+ healthCheckInterval: 30000,
1042
+ },
1043
+
1044
+ execution: {
1045
+ maxExecutionTime: Number.parseInt(process.env.WORKERS_MAX_EXECUTION_TIME ?? '30000', 10),
1046
+ maxMemory: Number.parseInt(process.env.WORKERS_MAX_MEMORY ?? '0', 10),
1047
+ idleTimeout: Number.parseInt(process.env.WORKERS_IDLE_TIMEOUT ?? '60000', 10),
1048
+ isolateContexts: process.env.WORKERS_ISOLATE_CONTEXTS === 'true',
1049
+ },
1050
+ },`;
1051
+ }
1052
+ /**
1053
+ * Generate advanced workers configuration with Bun optimizations
1054
+ */
1055
+ static generateAdvancedWorkersConfig() {
1056
+ return ` /**
1057
+ * Workers Configuration (Advanced)
1058
+ *
1059
+ * Manages job execution in isolated worker threads.
1060
+ * Includes Bun-specific optimizations for enhanced performance.
1061
+ *
1062
+ * Performance characteristics:
1063
+ * - Bun: 2-241x faster message passing, 20-30% less memory (smol mode)
1064
+ * - Node.js: Stable, widely tested, compatible
1065
+ */
1066
+ workers: {
1067
+ runtime: process.env.WORKERS_RUNTIME as 'auto' | 'bun' | 'node' ?? 'auto',
1068
+
1069
+ pool: {
1070
+ poolSize: Number.parseInt(process.env.WORKERS_POOL_SIZE ?? '4', 10),
1071
+ minWorkers: Number.parseInt(process.env.WORKERS_MIN_WORKERS ?? '1', 10),
1072
+ healthCheckInterval: 30000,
1073
+ },
1074
+
1075
+ execution: {
1076
+ maxExecutionTime: Number.parseInt(process.env.WORKERS_MAX_EXECUTION_TIME ?? '30000', 10),
1077
+ maxMemory: Number.parseInt(process.env.WORKERS_MAX_MEMORY ?? '0', 10),
1078
+ idleTimeout: Number.parseInt(process.env.WORKERS_IDLE_TIMEOUT ?? '60000', 10),
1079
+ isolateContexts: process.env.WORKERS_ISOLATE_CONTEXTS === 'true',
1080
+ },
1081
+
1082
+ // Bun-specific optimizations
1083
+ bun: {
1084
+ smol: process.env.WORKERS_BUN_SMOL === 'true',
1085
+ preload: process.env.WORKERS_BUN_PRELOAD
1086
+ ? process.env.WORKERS_BUN_PRELOAD.split(',').map((p) => p.trim())
1087
+ : undefined,
1088
+ inspectPort: process.env.WORKERS_BUN_INSPECT_PORT
1089
+ ? Number.parseInt(process.env.WORKERS_BUN_INSPECT_PORT, 10)
1090
+ : undefined,
1091
+ },
1092
+ },`;
1093
+ }
1094
+ /**
1095
+ * Generate production-optimized workers configuration
1096
+ */
1097
+ static generateProductionWorkersConfig() {
1098
+ return ` /**
1099
+ * Workers Configuration (Production Optimized)
1100
+ */
1101
+ workers: {
1102
+ runtime: 'auto' as const,
1103
+
1104
+ pool: {
1105
+ poolSize: Number.parseInt(process.env.WORKERS_POOL_SIZE ?? '8', 10),
1106
+ minWorkers: 2,
1107
+ healthCheckInterval: 30000,
1108
+ },
1109
+
1110
+ execution: {
1111
+ maxExecutionTime: 30000,
1112
+ maxMemory: Number.parseInt(process.env.WORKERS_MAX_MEMORY ?? '512', 10),
1113
+ idleTimeout: 60000,
1114
+ isolateContexts: false,
1115
+ },
1116
+
1117
+ bun: {
1118
+ smol: true,
1119
+ preload: process.env.WORKERS_BUN_PRELOAD?.split(',').map((p) => p.trim()),
1120
+ },
1121
+ },`;
1122
+ }
936
1123
  };
937
1124
 
938
1125
  // src/utils/ServiceProviderGenerator.ts
@@ -1338,7 +1525,8 @@ var CleanArchitectureGenerator = class extends BaseGenerator {
1338
1525
  return ConfigGenerator.generateSimpleAppConfig(context);
1339
1526
  }
1340
1527
  generateDatabaseConfig() {
1341
- return ConfigGenerator.generateSimpleDatabaseConfig();
1528
+ const driver = this.context?.profileConfig?.drivers?.database ?? "none";
1529
+ return ConfigGenerator.generateDatabaseConfig(driver);
1342
1530
  }
1343
1531
  generateAuthConfig() {
1344
1532
  return ConfigGenerator.generateAuthConfig();
@@ -1946,7 +2134,9 @@ Created with \u2764\uFE0F using Gravito Framework
1946
2134
 
1947
2135
  // src/generators/ddd/BootstrapGenerator.ts
1948
2136
  var BootstrapGenerator = class {
2137
+ context = null;
1949
2138
  generate(context) {
2139
+ this.context = context;
1950
2140
  return {
1951
2141
  type: "directory",
1952
2142
  name: "Bootstrap",
@@ -1959,6 +2149,7 @@ var BootstrapGenerator = class {
1959
2149
  };
1960
2150
  }
1961
2151
  generateConfigDirectory(context) {
2152
+ this.context = context;
1962
2153
  return {
1963
2154
  type: "directory",
1964
2155
  name: "config",
@@ -2154,13 +2345,8 @@ export default {
2154
2345
  `;
2155
2346
  }
2156
2347
  generateDatabaseConfig() {
2157
- return `export default {
2158
- default: process.env.DB_CONNECTION ?? 'sqlite',
2159
- connections: {
2160
- sqlite: { driver: 'sqlite', database: 'database/database.sqlite' },
2161
- },
2162
- }
2163
- `;
2348
+ const driver = this.context?.profileConfig?.drivers?.database ?? "none";
2349
+ return ConfigGenerator.generateDatabaseConfig(driver);
2164
2350
  }
2165
2351
  generateCacheConfig() {
2166
2352
  return `export default {
@@ -2321,6 +2507,30 @@ var ModuleGenerator = class {
2321
2507
  ]
2322
2508
  }
2323
2509
  ]
2510
+ },
2511
+ // UserInterface Layer
2512
+ {
2513
+ type: "directory",
2514
+ name: "UserInterface",
2515
+ children: [
2516
+ {
2517
+ type: "directory",
2518
+ name: "Http",
2519
+ children: [
2520
+ {
2521
+ type: "directory",
2522
+ name: "Controllers",
2523
+ children: [
2524
+ {
2525
+ type: "file",
2526
+ name: `${name}Controller.ts`,
2527
+ content: this.generateController(name)
2528
+ }
2529
+ ]
2530
+ }
2531
+ ]
2532
+ }
2533
+ ]
2324
2534
  }
2325
2535
  ]
2326
2536
  };
@@ -2336,17 +2546,13 @@ import { ${name}Created } from '../../Events/${name}Created'
2336
2546
  import { ${name}Status } from './${name}Status'
2337
2547
 
2338
2548
  export interface ${name}Props {
2339
- // Add properties here
2340
2549
  status: ${name}Status
2341
2550
  createdAt: Date
2342
2551
  }
2343
2552
 
2344
2553
  export class ${name} extends AggregateRoot<Id> {
2345
- private props: ${name}Props
2346
-
2347
- private constructor(id: Id, props: ${name}Props) {
2554
+ private constructor(id: Id, private props: ${name}Props) {
2348
2555
  super(id)
2349
- this.props = props
2350
2556
  }
2351
2557
 
2352
2558
  static create(id: Id): ${name} {
@@ -2364,7 +2570,12 @@ export class ${name} extends AggregateRoot<Id> {
2364
2570
  return this.props.status
2365
2571
  }
2366
2572
 
2367
- // Add domain methods here
2573
+ /**
2574
+ * Complete the ${name} process
2575
+ */
2576
+ complete(): void {
2577
+ this.props.status = ${name}Status.COMPLETED
2578
+ }
2368
2579
  }
2369
2580
  `;
2370
2581
  }
@@ -2389,17 +2600,13 @@ export enum ${name}Status {
2389
2600
  import { DomainEvent } from '@gravito/enterprise'
2390
2601
 
2391
2602
  export class ${name}Created extends DomainEvent {
2392
- constructor(public readonly ${name.toLowerCase()}Id: string) {
2603
+ constructor(public readonly aggregateId: string) {
2393
2604
  super()
2394
2605
  }
2395
2606
 
2396
2607
  override get eventName(): string {
2397
2608
  return '${name.toLowerCase()}.created'
2398
2609
  }
2399
-
2400
- get aggregateId(): string {
2401
- return this.${name.toLowerCase()}Id
2402
- }
2403
2610
  }
2404
2611
  `;
2405
2612
  }
@@ -2426,7 +2633,6 @@ import { Command } from '@gravito/enterprise'
2426
2633
 
2427
2634
  export class Create${name}Command extends Command {
2428
2635
  constructor(
2429
- // Add command properties
2430
2636
  public readonly id?: string
2431
2637
  ) {
2432
2638
  super()
@@ -2481,13 +2687,15 @@ export class Get${name}ByIdQuery extends Query {
2481
2687
  import { QueryHandler } from '@gravito/enterprise'
2482
2688
  import type { I${name}Repository } from '../../../Domain/Repositories/I${name}Repository'
2483
2689
  import type { ${name}DTO } from '../../DTOs/${name}DTO'
2690
+ import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
2484
2691
  import type { Get${name}ByIdQuery } from './Get${name}ByIdQuery'
2485
2692
 
2486
2693
  export class Get${name}ByIdHandler implements QueryHandler<Get${name}ByIdQuery, ${name}DTO | null> {
2487
2694
  constructor(private repository: I${name}Repository) {}
2488
2695
 
2489
2696
  async handle(query: Get${name}ByIdQuery): Promise<${name}DTO | null> {
2490
- const aggregate = await this.repository.findById(query.id as any) // Simplified for demo
2697
+ const id = Id.from(query.id)
2698
+ const aggregate = await this.repository.findById(id)
2491
2699
  if (!aggregate) return null
2492
2700
 
2493
2701
  return {
@@ -2508,7 +2716,6 @@ import type { ${name}Status } from '../../Domain/Aggregates/${name}/${name}Statu
2508
2716
  export interface ${name}DTO {
2509
2717
  id: string
2510
2718
  status: ${name}Status
2511
- // Add more fields
2512
2719
  }
2513
2720
  `;
2514
2721
  }
@@ -2519,29 +2726,29 @@ export interface ${name}DTO {
2519
2726
 
2520
2727
  import type { ${name} } from '../../Domain/Aggregates/${name}/${name}'
2521
2728
  import type { I${name}Repository } from '../../Domain/Repositories/I${name}Repository'
2522
- import type { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
2523
-
2524
- const store = new Map<string, ${name}>()
2729
+ import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
2525
2730
 
2526
2731
  export class ${name}Repository implements I${name}Repository {
2732
+ private store = new Map<string, ${name}>()
2733
+
2527
2734
  async findById(id: Id): Promise<${name} | null> {
2528
- return store.get(id.value) ?? null
2735
+ return this.store.get(id.value) ?? null
2529
2736
  }
2530
2737
 
2531
2738
  async save(aggregate: ${name}): Promise<void> {
2532
- store.set(aggregate.id.value, aggregate)
2739
+ this.store.set(aggregate.id.value, aggregate)
2533
2740
  }
2534
2741
 
2535
2742
  async delete(id: Id): Promise<void> {
2536
- store.delete(id.value)
2743
+ this.store.delete(id.value)
2537
2744
  }
2538
2745
 
2539
2746
  async findAll(): Promise<${name}[]> {
2540
- return Array.from(store.values())
2747
+ return Array.from(this.store.values())
2541
2748
  }
2542
2749
 
2543
2750
  async exists(id: Id): Promise<boolean> {
2544
- return store.has(id.value)
2751
+ return this.store.has(id.value)
2545
2752
  }
2546
2753
  }
2547
2754
  `;
@@ -2563,6 +2770,37 @@ export class ${name}ServiceProvider extends ServiceProvider {
2563
2770
  console.log('[${name}] Module loaded')
2564
2771
  }
2565
2772
  }
2773
+ `;
2774
+ }
2775
+ generateController(name) {
2776
+ return `/**
2777
+ * ${name} Controller
2778
+ */
2779
+
2780
+ import type { GravitoContext } from '@gravito/core'
2781
+
2782
+ export class ${name}Controller {
2783
+ /**
2784
+ * GET /${name.toLowerCase()}
2785
+ */
2786
+ async index(ctx: GravitoContext) {
2787
+ return ctx.json({
2788
+ success: true,
2789
+ data: []
2790
+ })
2791
+ }
2792
+
2793
+ /**
2794
+ * GET /${name.toLowerCase()}/:id
2795
+ */
2796
+ async show(ctx: GravitoContext) {
2797
+ const id = ctx.req.param('id')
2798
+ return ctx.json({
2799
+ success: true,
2800
+ data: { id }
2801
+ })
2802
+ }
2803
+ }
2566
2804
  `;
2567
2805
  }
2568
2806
  };
@@ -2737,24 +2975,39 @@ export class Email extends ValueObject<EmailProps> {
2737
2975
 
2738
2976
  import type { DomainEvent } from '@gravito/enterprise'
2739
2977
 
2740
- type EventHandler = (event: DomainEvent) => void | Promise<void>
2978
+ type EventHandler<T extends DomainEvent = any> = (event: T) => void | Promise<void>
2741
2979
 
2742
2980
  export class EventDispatcher {
2743
2981
  private handlers: Map<string, EventHandler[]> = new Map()
2744
2982
 
2745
- subscribe(eventName: string, handler: EventHandler): void {
2983
+ /**
2984
+ * Subscribe to an event
2985
+ */
2986
+ subscribe<T extends DomainEvent>(eventName: string, handler: EventHandler<T>): void {
2746
2987
  const handlers = this.handlers.get(eventName) ?? []
2747
2988
  handlers.push(handler)
2748
2989
  this.handlers.set(eventName, handlers)
2749
2990
  }
2750
2991
 
2992
+ /**
2993
+ * Dispatch a single event
2994
+ */
2751
2995
  async dispatch(event: DomainEvent): Promise<void> {
2752
2996
  const handlers = this.handlers.get(event.eventName) ?? []
2753
- for (const handler of handlers) {
2754
- await handler(event)
2755
- }
2997
+ const promises = handlers.map(handler => {
2998
+ try {
2999
+ return handler(event)
3000
+ } catch (error) {
3001
+ console.error(\`[EventDispatcher] Error in handler for \${event.eventName}:\`, error)
3002
+ }
3003
+ })
3004
+
3005
+ await Promise.all(promises)
2756
3006
  }
2757
3007
 
3008
+ /**
3009
+ * Dispatch multiple events sequentially
3010
+ */
2758
3011
  async dispatchAll(events: DomainEvent[]): Promise<void> {
2759
3012
  for (const event of events) {
2760
3013
  await this.dispatch(event)
@@ -3147,7 +3400,8 @@ describe('Example Test', () => {
3147
3400
  return ConfigGenerator.generateDetailedAppConfig(context);
3148
3401
  }
3149
3402
  generateDatabaseConfig() {
3150
- return ConfigGenerator.generateDetailedDatabaseConfig();
3403
+ const driver = this.context?.profileConfig?.drivers?.database ?? "none";
3404
+ return ConfigGenerator.generateDatabaseConfig(driver);
3151
3405
  }
3152
3406
  generateAuthConfig() {
3153
3407
  return `/**
@@ -3863,9 +4117,9 @@ var SatelliteGenerator = class extends BaseGenerator {
3863
4117
  children: [
3864
4118
  {
3865
4119
  type: "directory",
3866
- name: "Entities",
4120
+ name: "Aggregates",
3867
4121
  children: [
3868
- { type: "file", name: `${name}.ts`, content: this.generateEntity(name) }
4122
+ { type: "file", name: `${name}.ts`, content: this.generateAggregate(name) }
3869
4123
  ]
3870
4124
  },
3871
4125
  {
@@ -3879,8 +4133,24 @@ var SatelliteGenerator = class extends BaseGenerator {
3879
4133
  }
3880
4134
  ]
3881
4135
  },
3882
- { type: "directory", name: "ValueObjects", children: [] },
3883
- { type: "directory", name: "Events", children: [] }
4136
+ {
4137
+ type: "directory",
4138
+ name: "ValueObjects",
4139
+ children: [
4140
+ { type: "file", name: `${name}Id.ts`, content: this.generateIdValueObject(name) }
4141
+ ]
4142
+ },
4143
+ {
4144
+ type: "directory",
4145
+ name: "Events",
4146
+ children: [
4147
+ {
4148
+ type: "file",
4149
+ name: `${name}Created.ts`,
4150
+ content: this.generateCreatedEvent(name)
4151
+ }
4152
+ ]
4153
+ }
3884
4154
  ]
3885
4155
  },
3886
4156
  // Application Layer
@@ -3921,6 +4191,31 @@ var SatelliteGenerator = class extends BaseGenerator {
3921
4191
  }
3922
4192
  ]
3923
4193
  },
4194
+ // Interface Layer (HTTP/API)
4195
+ {
4196
+ type: "directory",
4197
+ name: "Interface",
4198
+ children: [
4199
+ {
4200
+ type: "directory",
4201
+ name: "Http",
4202
+ children: [
4203
+ {
4204
+ type: "directory",
4205
+ name: "Controllers",
4206
+ children: [
4207
+ {
4208
+ type: "file",
4209
+ name: `${name}Controller.ts`,
4210
+ content: this.generateController(name)
4211
+ }
4212
+ ]
4213
+ },
4214
+ { type: "directory", name: "Middleware", children: [] }
4215
+ ]
4216
+ }
4217
+ ]
4218
+ },
3924
4219
  // Entry Point
3925
4220
  { type: "file", name: "index.ts", content: this.generateEntryPoint(name) },
3926
4221
  {
@@ -3938,13 +4233,12 @@ var SatelliteGenerator = class extends BaseGenerator {
3938
4233
  {
3939
4234
  type: "file",
3940
4235
  name: "unit.test.ts",
3941
- content: `import { describe, it, expect } from "bun:test";
3942
-
3943
- describe("${name}", () => {
3944
- it("should work", () => {
3945
- expect(true).toBe(true);
3946
- });
3947
- });`
4236
+ content: this.generateUnitTest(name)
4237
+ },
4238
+ {
4239
+ type: "file",
4240
+ name: "integration.test.ts",
4241
+ content: this.generateIntegrationTest(name)
3948
4242
  }
3949
4243
  ]
3950
4244
  }
@@ -3953,35 +4247,76 @@ describe("${name}", () => {
3953
4247
  // ─────────────────────────────────────────────────────────────
3954
4248
  // Domain Templates
3955
4249
  // ─────────────────────────────────────────────────────────────
3956
- generateEntity(name) {
3957
- return `import { Entity } from '@gravito/enterprise'
4250
+ generateIdValueObject(name) {
4251
+ return `import { ValueObject } from '@gravito/enterprise'
4252
+
4253
+ interface IdProps {
4254
+ value: string
4255
+ }
4256
+
4257
+ export class ${name}Id extends ValueObject<IdProps> {
4258
+ constructor(value: string) {
4259
+ super({ value })
4260
+ }
4261
+
4262
+ static create(): ${name}Id {
4263
+ return new ${name}Id(crypto.randomUUID())
4264
+ }
4265
+
4266
+ get value(): string { return this.props.value }
4267
+ }
4268
+ `;
4269
+ }
4270
+ generateAggregate(name) {
4271
+ return `import { AggregateRoot } from '@gravito/enterprise'
4272
+ import { ${name}Id } from '../ValueObjects/${name}Id'
4273
+ import { ${name}Created } from '../Events/${name}Created'
3958
4274
 
3959
4275
  export interface ${name}Props {
3960
4276
  name: string
3961
4277
  createdAt: Date
3962
4278
  }
3963
4279
 
3964
- export class ${name} extends Entity<string> {
3965
- constructor(id: string, private props: ${name}Props) {
4280
+ export class ${name} extends AggregateRoot<${name}Id> {
4281
+ constructor(id: ${name}Id, private props: ${name}Props) {
3966
4282
  super(id)
3967
4283
  }
3968
4284
 
3969
- static create(id: string, name: string): ${name} {
3970
- return new ${name}(id, {
4285
+ static create(id: ${name}Id, name: string): ${name} {
4286
+ const aggregate = new ${name}(id, {
3971
4287
  name,
3972
4288
  createdAt: new Date()
3973
4289
  })
4290
+
4291
+ aggregate.addDomainEvent(new ${name}Created(id.value))
4292
+
4293
+ return aggregate
3974
4294
  }
3975
4295
 
3976
4296
  get name() { return this.props.name }
3977
4297
  }
4298
+ `;
4299
+ }
4300
+ generateCreatedEvent(name) {
4301
+ return `import { DomainEvent } from '@gravito/enterprise'
4302
+
4303
+ export class ${name}Created extends DomainEvent {
4304
+ constructor(public readonly aggregateId: string) {
4305
+ super()
4306
+ }
4307
+
4308
+ get eventName(): string {
4309
+ return '${this.context?.nameKebabCase}.created'
4310
+ }
4311
+ }
3978
4312
  `;
3979
4313
  }
3980
4314
  generateRepositoryInterface(name) {
3981
4315
  return `import { Repository } from '@gravito/enterprise'
3982
- import { ${name} } from '../Entities/${name}'
4316
+ import { ${name} } from '../Aggregates/${name}'
4317
+ import { ${name}Id } from '../ValueObjects/${name}Id'
3983
4318
 
3984
- export interface I${name}Repository extends Repository<${name}, string> {
4319
+ export interface I${name}Repository extends Repository<${name}, ${name}Id> {
3985
4320
  // Add custom methods here
3986
4321
  }
3987
4322
  `;
@@ -3992,7 +4327,8 @@ export interface I${name}Repository extends Repository<${name}, string> {
3992
4327
  generateUseCase(name) {
3993
4328
  return `import { UseCase } from '@gravito/enterprise'
3994
4329
  import { I${name}Repository } from '../../Domain/Contracts/I${name}Repository'
3995
- import { ${name} } from '../../Domain/Entities/${name}'
4330
+ import { ${name} } from '../../Domain/Aggregates/${name}'
4331
+ import { ${name}Id } from '../../Domain/ValueObjects/${name}Id'
3996
4332
 
3997
4333
  export interface Create${name}Input {
3998
4334
  name: string
@@ -4004,12 +4340,12 @@ export class Create${name} extends UseCase<Create${name}Input, string> {
4004
4340
  }
4005
4341
 
4006
4342
  async execute(input: Create${name}Input): Promise<string> {
4007
- const id = crypto.randomUUID()
4343
+ const id = ${name}Id.create()
4008
4344
  const entity = ${name}.create(id, input.name)
4009
4345
 
4010
4346
  await this.repository.save(entity)
4011
4347
 
4012
- return id
4348
+ return id.value
4013
4349
  }
4014
4350
  }
4015
4351
  `;
@@ -4019,17 +4355,16 @@ export class Create${name} extends UseCase<Create${name}Input, string> {
4019
4355
  // ─────────────────────────────────────────────────────────────
4020
4356
  generateAtlasRepository(name) {
4021
4357
  return `import { I${name}Repository } from '../../Domain/Contracts/I${name}Repository'
4022
- import { ${name} } from '../../Domain/Entities/${name}'
4023
- import { DB } from '@gravito/atlas'
4358
+ import { ${name} } from '../../Domain/Aggregates/${name}'
4359
+ import { ${name}Id } from '../../Domain/ValueObjects/${name}Id'
4024
4360
 
4025
4361
  export class Atlas${name}Repository implements I${name}Repository {
4026
4362
  async save(entity: ${name}): Promise<void> {
4027
- // Dogfooding: Use @gravito/atlas for persistence
4028
- console.log('[Atlas] Saving entity:', entity.id)
4029
- // await DB.table('${name.toLowerCase()}s').insert({ ... })
4363
+ // Implementation using @gravito/atlas
4364
+ console.log('[Atlas] Saving aggregate:', entity.id.value)
4030
4365
  }
4031
4366
 
4032
- async findById(id: string): Promise<${name} | null> {
4367
+ async findById(id: ${name}Id): Promise<${name} | null> {
4033
4368
  return null
4034
4369
  }
4035
4370
 
@@ -4037,12 +4372,77 @@ export class Atlas${name}Repository implements I${name}Repository {
4037
4372
  return []
4038
4373
  }
4039
4374
 
4040
- async delete(id: string): Promise<void> {}
4375
+ async delete(id: ${name}Id): Promise<void> {}
4041
4376
 
4042
- async exists(id: string): Promise<boolean> {
4377
+ async exists(id: ${name}Id): Promise<boolean> {
4043
4378
  return false
4044
4379
  }
4045
4380
  }
4381
+ `;
4382
+ }
4383
+ // ─────────────────────────────────────────────────────────────
4384
+ // Test Templates
4385
+ // ─────────────────────────────────────────────────────────────
4386
+ generateUnitTest(name) {
4387
+ return `import { describe, it, expect } from "bun:test";
4388
+ import { ${name} } from "../src/Domain/Aggregates/${name}";
4389
+ import { ${name}Id } from "../src/Domain/ValueObjects/${name}Id";
4390
+
4391
+ describe("${name} Aggregate", () => {
4392
+ it("should create a new aggregate with a domain event", () => {
4393
+ const id = ${name}Id.create();
4394
+ const aggregate = ${name}.create(id, "Test Name");
4395
+
4396
+ expect(aggregate.id).toBe(id);
4397
+ expect(aggregate.name).toBe("Test Name");
4398
+ expect(aggregate.pullDomainEvents()).toHaveLength(1);
4399
+ });
4400
+ });`;
4401
+ }
4402
+ generateIntegrationTest(name) {
4403
+ return `import { describe, it, expect, beforeAll } from "bun:test";
4404
+ import { PlanetCore } from "@gravito/core";
4405
+
4406
+ describe("${name} Integration", () => {
4407
+ let core: PlanetCore;
4408
+
4409
+ beforeAll(async () => {
4410
+ core = new PlanetCore();
4411
+ // Setup dependencies here
4412
+ });
4413
+
4414
+ it("should handle the creation flow", async () => {
4415
+ expect(true).toBe(true); // Placeholder for actual integration logic
4416
+ });
4417
+ });`;
4418
+ }
4419
+ // ─────────────────────────────────────────────────────────────
4420
+ // Interface Templates
4421
+ // ─────────────────────────────────────────────────────────────
4422
+ generateController(name) {
4423
+ return `import type { GravitoContext } from '@gravito/core'
4424
+ import { Create${name} } from '../../../Application/UseCases/Create${name}'
4425
+
4426
+ export class ${name}Controller {
4427
+ constructor(private createUseCase: Create${name}) {}
4428
+
4429
+ async store(ctx: GravitoContext) {
4430
+ const body = await ctx.req.json()
4431
+ const id = await this.createUseCase.execute({ name: body.name })
4432
+
4433
+ return ctx.json({
4434
+ success: true,
4435
+ data: { id }
4436
+ }, 201)
4437
+ }
4438
+
4439
+ async index(ctx: GravitoContext) {
4440
+ return ctx.json({
4441
+ success: true,
4442
+ data: []
4443
+ })
4444
+ }
4445
+ }
4046
4446
  `;
4047
4447
  }
4048
4448
  // ─────────────────────────────────────────────────────────────
@@ -4051,17 +4451,22 @@ export class Atlas${name}Repository implements I${name}Repository {
4051
4451
  generateEntryPoint(name) {
4052
4452
  return `import { ServiceProvider, type Container } from '@gravito/core'
4053
4453
  import { Atlas${name}Repository } from './Infrastructure/Persistence/Atlas${name}Repository'
4454
+ import { Create${name} } from './Application/UseCases/Create${name}'
4455
+ import { ${name}Controller } from './Interface/Http/Controllers/${name}Controller'
4054
4456
 
4055
4457
  export class ${name}ServiceProvider extends ServiceProvider {
4056
4458
  register(container: Container): void {
4057
- // Bind Repository
4459
+ // 1. Bind Repository (Infrastructure)
4058
4460
  container.singleton('${name.toLowerCase()}.repo', () => new Atlas${name}Repository())
4059
4461
 
4060
- // Bind UseCases
4061
- container.singleton('${name.toLowerCase()}.create', () => {
4062
- return new (require('./Application/UseCases/Create${name}').Create${name})(
4063
- container.make('${name.toLowerCase()}.repo')
4064
- )
4462
+ // 2. Bind UseCases (Application)
4463
+ container.singleton('${name.toLowerCase()}.usecase.create', (c) => {
4464
+ return new Create${name}(c.make('${name.toLowerCase()}.repo'))
4465
+ })
4466
+
4467
+ // 3. Bind Controllers (Interface)
4468
+ container.singleton('${name.toLowerCase()}.controller', (c) => {
4469
+ return new ${name}Controller(c.make('${name.toLowerCase()}.usecase.create'))
4065
4470
  })
4066
4471
  }
4067
4472
 
@@ -4166,13 +4571,15 @@ var ProfileResolver = class _ProfileResolver {
4166
4571
  static DEFAULTS = {
4167
4572
  core: {
4168
4573
  drivers: {
4169
- database: "sqlite",
4574
+ database: "none",
4170
4575
  cache: "memory",
4171
4576
  queue: "sync",
4172
4577
  storage: "local",
4173
4578
  session: "file"
4174
4579
  },
4175
- features: []
4580
+ features: [],
4581
+ workers: "basic"
4582
+ // Basic workers configuration for core profile
4176
4583
  },
4177
4584
  scale: {
4178
4585
  drivers: {
@@ -4182,7 +4589,9 @@ var ProfileResolver = class _ProfileResolver {
4182
4589
  storage: "s3",
4183
4590
  session: "redis"
4184
4591
  },
4185
- features: ["stream", "nebula"]
4592
+ features: ["stream", "nebula"],
4593
+ workers: "advanced"
4594
+ // Advanced workers with Bun optimizations
4186
4595
  },
4187
4596
  enterprise: {
4188
4597
  drivers: {
@@ -4192,14 +4601,17 @@ var ProfileResolver = class _ProfileResolver {
4192
4601
  storage: "s3",
4193
4602
  session: "redis"
4194
4603
  },
4195
- features: ["stream", "nebula", "monitor", "sentinel", "fortify"]
4604
+ features: ["stream", "nebula", "monitor", "sentinel", "fortify"],
4605
+ workers: "production"
4606
+ // Production-optimized workers
4196
4607
  }
4197
4608
  };
4198
4609
  resolve(profile = "core", withFeatures = []) {
4199
4610
  const base = _ProfileResolver.DEFAULTS[profile] || _ProfileResolver.DEFAULTS.core;
4200
4611
  const config = {
4201
4612
  drivers: { ...base.drivers },
4202
- features: [...base.features]
4613
+ features: [...base.features],
4614
+ workers: base.workers
4203
4615
  };
4204
4616
  for (const feature of withFeatures) {
4205
4617
  this.applyFeature(config, feature);
@@ -4466,16 +4878,8 @@ describe('Example Test', () => {
4466
4878
  `;
4467
4879
  }
4468
4880
  generateDatabaseConfig() {
4469
- return `export default {
4470
- default: process.env.DB_CONNECTION ?? 'sqlite',
4471
- connections: {
4472
- sqlite: {
4473
- driver: 'sqlite',
4474
- database: process.env.DB_DATABASE ?? 'database/database.sqlite',
4475
- },
4476
- },
4477
- }
4478
- `;
4881
+ const driver = this.context?.profileConfig?.drivers?.database ?? "none";
4882
+ return ConfigGenerator.generateDatabaseConfig(driver);
4479
4883
  }
4480
4884
  // ─────────────────────────────────────────────────────────────
4481
4885
  // Model Generators