@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/README.md +30 -6
- package/dist/index.cjs +491 -87
- package/dist/index.d.ts +240 -3
- package/dist/index.js +491 -87
- package/package.json +5 -2
- package/dist/index.d.cts +0 -686
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
|
-
|
|
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
|
-
|
|
2158
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
2754
|
-
|
|
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
|
-
|
|
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: "
|
|
4120
|
+
name: "Aggregates",
|
|
3867
4121
|
children: [
|
|
3868
|
-
{ type: "file", name: `${name}.ts`, content: this.
|
|
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
|
-
{
|
|
3883
|
-
|
|
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:
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
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
|
-
|
|
3957
|
-
return `import {
|
|
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
|
|
3965
|
-
constructor(id:
|
|
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:
|
|
3970
|
-
|
|
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 '../
|
|
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},
|
|
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/
|
|
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 =
|
|
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/
|
|
4023
|
-
import {
|
|
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
|
-
//
|
|
4028
|
-
console.log('[Atlas] Saving
|
|
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:
|
|
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:
|
|
4375
|
+
async delete(id: ${name}Id): Promise<void> {}
|
|
4041
4376
|
|
|
4042
|
-
async exists(id:
|
|
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
|
|
4063
|
-
|
|
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: "
|
|
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
|
-
|
|
4470
|
-
|
|
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
|