@gravito/scaffold 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1119 -187
- package/dist/index.d.cts +32 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js +1119 -187
- package/package.json +1 -1
- package/templates/skills/SKILLS_USAGE.md +54 -0
- package/templates/skills/adr-scaffold/SKILL.md +67 -0
- package/templates/skills/adr-scaffold/assets/.keep +0 -0
- package/templates/skills/adr-scaffold/references/.keep +0 -0
- package/templates/skills/adr-scaffold/references/adr-rules.md +29 -0
- package/templates/skills/adr-scaffold/scripts/.keep +0 -0
- package/templates/skills/architecture-refiner/SKILL.md +28 -0
- package/templates/skills/architecture-refiner/assets/.keep +0 -0
- package/templates/skills/architecture-refiner/references/.keep +0 -0
- package/templates/skills/architecture-refiner/scripts/.keep +0 -0
- package/templates/skills/atlas-expert/SKILL.md +34 -0
- package/templates/skills/atlas-expert/assets/.keep +0 -0
- package/templates/skills/atlas-expert/references/.keep +0 -0
- package/templates/skills/atlas-expert/references/decorators.md +24 -0
- package/templates/skills/atlas-expert/scripts/.keep +0 -0
- package/templates/skills/clean-architect/SKILL.md +63 -0
- package/templates/skills/clean-architect/assets/.keep +0 -0
- package/templates/skills/clean-architect/references/.keep +0 -0
- package/templates/skills/clean-architect/scripts/.keep +0 -0
- package/templates/skills/cms-engine/SKILL.md +54 -0
- package/templates/skills/cms-engine/assets/.keep +0 -0
- package/templates/skills/cms-engine/references/.keep +0 -0
- package/templates/skills/cms-engine/scripts/.keep +0 -0
- package/templates/skills/commerce-blueprint/SKILL.md +53 -0
- package/templates/skills/commerce-blueprint/assets/.keep +0 -0
- package/templates/skills/commerce-blueprint/references/.keep +0 -0
- package/templates/skills/commerce-blueprint/scripts/.keep +0 -0
- package/templates/skills/ddd-domain-expert/SKILL.md +71 -0
- package/templates/skills/ddd-domain-expert/assets/.keep +0 -0
- package/templates/skills/ddd-domain-expert/references/.keep +0 -0
- package/templates/skills/ddd-domain-expert/scripts/.keep +0 -0
- package/templates/skills/fortify-security/SKILL.md +28 -0
- package/templates/skills/fortify-security/assets/.keep +0 -0
- package/templates/skills/fortify-security/references/.keep +0 -0
- package/templates/skills/fortify-security/scripts/.keep +0 -0
- package/templates/skills/freeze-static/SKILL.md +55 -0
- package/templates/skills/freeze-static/assets/.keep +0 -0
- package/templates/skills/freeze-static/references/.keep +0 -0
- package/templates/skills/freeze-static/scripts/.keep +0 -0
- package/templates/skills/identity-hub/SKILL.md +51 -0
- package/templates/skills/identity-hub/assets/.keep +0 -0
- package/templates/skills/identity-hub/references/.keep +0 -0
- package/templates/skills/identity-hub/scripts/.keep +0 -0
- package/templates/skills/localization-linguist/SKILL.md +28 -0
- package/templates/skills/localization-linguist/assets/.keep +0 -0
- package/templates/skills/localization-linguist/references/.keep +0 -0
- package/templates/skills/localization-linguist/scripts/.keep +0 -0
- package/templates/skills/migration-master/SKILL.md +28 -0
- package/templates/skills/migration-master/assets/.keep +0 -0
- package/templates/skills/migration-master/references/.keep +0 -0
- package/templates/skills/migration-master/scripts/.keep +0 -0
- package/templates/skills/mvc-master/SKILL.md +88 -0
- package/templates/skills/mvc-master/assets/.keep +0 -0
- package/templates/skills/mvc-master/references/.keep +0 -0
- package/templates/skills/mvc-master/scripts/.keep +0 -0
- package/templates/skills/ops-commander/SKILL.md +28 -0
- package/templates/skills/ops-commander/assets/.keep +0 -0
- package/templates/skills/ops-commander/references/.keep +0 -0
- package/templates/skills/ops-commander/scripts/.keep +0 -0
- package/templates/skills/performance-tuner/SKILL.md +28 -0
- package/templates/skills/performance-tuner/assets/.keep +0 -0
- package/templates/skills/performance-tuner/references/.keep +0 -0
- package/templates/skills/performance-tuner/scripts/.keep +0 -0
- package/templates/skills/quasar-queue/SKILL.md +28 -0
- package/templates/skills/quasar-queue/assets/.keep +0 -0
- package/templates/skills/quasar-queue/references/.keep +0 -0
- package/templates/skills/quasar-queue/scripts/.keep +0 -0
- package/templates/skills/satellites-pilot/SKILL.md +27 -0
- package/templates/skills/satellites-pilot/assets/.keep +0 -0
- package/templates/skills/satellites-pilot/references/.keep +0 -0
- package/templates/skills/satellites-pilot/scripts/.keep +0 -0
- package/templates/skills/test-guardian/SKILL.md +28 -0
- package/templates/skills/test-guardian/assets/.keep +0 -0
- package/templates/skills/test-guardian/references/.keep +0 -0
- package/templates/skills/test-guardian/scripts/.keep +0 -0
- package/templates/skills/zenith-ui/SKILL.md +29 -0
- package/templates/skills/zenith-ui/assets/.keep +0 -0
- package/templates/skills/zenith-ui/references/.keep +0 -0
- package/templates/skills/zenith-ui/scripts/.keep +0 -0
package/dist/index.cjs
CHANGED
|
@@ -392,6 +392,31 @@ var BaseGenerator = class {
|
|
|
392
392
|
"ARCHITECTURE.md",
|
|
393
393
|
this.generateArchitectureDoc(context)
|
|
394
394
|
);
|
|
395
|
+
await this.generateCheckScripts(context);
|
|
396
|
+
await this.generateSkills(context);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Copy AI Skills to the project
|
|
400
|
+
*/
|
|
401
|
+
async generateSkills(context) {
|
|
402
|
+
const skillsDir = import_node_path2.default.resolve(this.config.templatesDir, "skills");
|
|
403
|
+
const targetSkillsDir = import_node_path2.default.join(".skills");
|
|
404
|
+
try {
|
|
405
|
+
await import_promises2.default.access(skillsDir);
|
|
406
|
+
} catch {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
const files = await walk(skillsDir);
|
|
410
|
+
for (const filePath of files) {
|
|
411
|
+
const relativePath = import_node_path2.default.relative(skillsDir, filePath);
|
|
412
|
+
const targetPath = import_node_path2.default.join(targetSkillsDir, relativePath);
|
|
413
|
+
let content = await import_promises2.default.readFile(filePath, "utf-8");
|
|
414
|
+
try {
|
|
415
|
+
content = this.stubGenerator.render(content, context);
|
|
416
|
+
} catch {
|
|
417
|
+
}
|
|
418
|
+
await this.writeFile(context.targetDir, targetPath, content);
|
|
419
|
+
}
|
|
395
420
|
}
|
|
396
421
|
/**
|
|
397
422
|
* Apply profile-specific overlays
|
|
@@ -479,6 +504,10 @@ var BaseGenerator = class {
|
|
|
479
504
|
start: "bun run dist/bootstrap.js",
|
|
480
505
|
test: "bun test",
|
|
481
506
|
typecheck: "tsc --noEmit",
|
|
507
|
+
check: "bun run typecheck && bun run test",
|
|
508
|
+
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
509
|
+
validate: "bun run check && bun run check:deps",
|
|
510
|
+
precommit: "bun run validate",
|
|
482
511
|
"docker:build": `docker build -t ${context.nameKebabCase} .`,
|
|
483
512
|
"docker:run": `docker run -it -p 3000:3000 ${context.nameKebabCase}`
|
|
484
513
|
},
|
|
@@ -731,6 +760,430 @@ coverage/
|
|
|
731
760
|
};
|
|
732
761
|
return JSON.stringify(config, null, 2);
|
|
733
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* Generate check scripts for project validation.
|
|
765
|
+
*/
|
|
766
|
+
async generateCheckScripts(context) {
|
|
767
|
+
const scriptsDir = import_node_path2.default.resolve(context.targetDir, "scripts");
|
|
768
|
+
await import_promises2.default.mkdir(scriptsDir, { recursive: true });
|
|
769
|
+
await this.writeFile(
|
|
770
|
+
scriptsDir,
|
|
771
|
+
"check-dependencies.ts",
|
|
772
|
+
this.generateCheckDependenciesScript()
|
|
773
|
+
);
|
|
774
|
+
await this.writeFile(scriptsDir, "check.sh", this.generateCheckShellScript());
|
|
775
|
+
await this.writeFile(scriptsDir, "pre-commit.sh", this.generatePreCommitScript());
|
|
776
|
+
await this.writeFile(context.targetDir, "CHECK_SYSTEM.md", this.generateCheckSystemDoc(context));
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Generate check-dependencies.ts script content.
|
|
780
|
+
*/
|
|
781
|
+
generateCheckDependenciesScript() {
|
|
782
|
+
return `/**
|
|
783
|
+
* \u76F8\u4F9D\u5957\u4EF6\u7248\u672C\u6AA2\u67E5\u8173\u672C
|
|
784
|
+
*
|
|
785
|
+
* \u6AA2\u67E5 package.json \u4E2D\u7684\u5957\u4EF6\u662F\u5426\u70BA\u6700\u65B0\u7A69\u5B9A\u7248\u672C
|
|
786
|
+
* \u4E26\u63D0\u4F9B\u66F4\u65B0\u5EFA\u8B70
|
|
787
|
+
*/
|
|
788
|
+
|
|
789
|
+
import { readFileSync } from 'fs'
|
|
790
|
+
import { join } from 'path'
|
|
791
|
+
|
|
792
|
+
interface PackageJson {
|
|
793
|
+
dependencies?: Record<string, string>
|
|
794
|
+
devDependencies?: Record<string, string>
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
interface PackageInfo {
|
|
798
|
+
name: string
|
|
799
|
+
current: string
|
|
800
|
+
latest: string
|
|
801
|
+
outdated: boolean
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const colors = {
|
|
805
|
+
reset: '\\x1b[0m',
|
|
806
|
+
green: '\\x1b[32m',
|
|
807
|
+
yellow: '\\x1b[33m',
|
|
808
|
+
red: '\\x1b[31m',
|
|
809
|
+
blue: '\\x1b[36m',
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
function log(message: string, color: keyof typeof colors = 'reset') {
|
|
813
|
+
console.log(\`\${colors[color]}\${message}\${colors.reset}\`)
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
async function getLatestVersion(packageName: string): Promise<string | null> {
|
|
817
|
+
try {
|
|
818
|
+
const response = await fetch(\`https://registry.npmjs.org/\${packageName}/latest\`)
|
|
819
|
+
if (!response.ok) return null
|
|
820
|
+
const data = await response.json()
|
|
821
|
+
return data.version
|
|
822
|
+
} catch {
|
|
823
|
+
return null
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
function parseVersion(version: string): string {
|
|
828
|
+
// \u79FB\u9664 ^, ~, >= \u7B49\u524D\u7DB4
|
|
829
|
+
return version.replace(/^[\\^~>=<]/, '')
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
async function checkPackage(
|
|
833
|
+
name: string,
|
|
834
|
+
currentVersion: string
|
|
835
|
+
): Promise<PackageInfo | null> {
|
|
836
|
+
// \u8DF3\u904E\u672C\u5730\u9023\u7D50\u7684\u5957\u4EF6
|
|
837
|
+
if (currentVersion.startsWith('link:') || currentVersion.startsWith('workspace:')) {
|
|
838
|
+
return null
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
const current = parseVersion(currentVersion)
|
|
842
|
+
const latest = await getLatestVersion(name)
|
|
843
|
+
|
|
844
|
+
if (!latest) {
|
|
845
|
+
return null
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
return {
|
|
849
|
+
name,
|
|
850
|
+
current,
|
|
851
|
+
latest,
|
|
852
|
+
outdated: current !== latest,
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
async function main() {
|
|
857
|
+
log('\\n=== \u76F8\u4F9D\u5957\u4EF6\u7248\u672C\u6AA2\u67E5 ===\\n', 'blue')
|
|
858
|
+
|
|
859
|
+
const packageJsonPath = join(process.cwd(), 'package.json')
|
|
860
|
+
const packageJson: PackageJson = JSON.parse(
|
|
861
|
+
readFileSync(packageJsonPath, 'utf-8')
|
|
862
|
+
)
|
|
863
|
+
|
|
864
|
+
const allDependencies = {
|
|
865
|
+
...packageJson.dependencies,
|
|
866
|
+
...packageJson.devDependencies,
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
log(\`\u6AA2\u67E5 \${Object.keys(allDependencies).length} \u500B\u5957\u4EF6...\\n\`, 'yellow')
|
|
870
|
+
|
|
871
|
+
const results: PackageInfo[] = []
|
|
872
|
+
const outdated: PackageInfo[] = []
|
|
873
|
+
const upToDate: PackageInfo[] = []
|
|
874
|
+
|
|
875
|
+
// \u6AA2\u67E5\u6240\u6709\u5957\u4EF6
|
|
876
|
+
for (const [name, version] of Object.entries(allDependencies)) {
|
|
877
|
+
const info = await checkPackage(name, version)
|
|
878
|
+
if (info) {
|
|
879
|
+
results.push(info)
|
|
880
|
+
if (info.outdated) {
|
|
881
|
+
outdated.push(info)
|
|
882
|
+
} else {
|
|
883
|
+
upToDate.push(info)
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// \u986F\u793A\u7D50\u679C
|
|
889
|
+
if (upToDate.length > 0) {
|
|
890
|
+
log(\`\\n\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C (\${upToDate.length}):\`, 'green')
|
|
891
|
+
upToDate.forEach((pkg) => {
|
|
892
|
+
log(\` \${pkg.name}: \${pkg.current}\`, 'green')
|
|
893
|
+
})
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
if (outdated.length > 0) {
|
|
897
|
+
log(\`\\n\u26A0 \u9700\u8981\u66F4\u65B0 (\${outdated.length}):\`, 'yellow')
|
|
898
|
+
outdated.forEach((pkg) => {
|
|
899
|
+
log(\` \${pkg.name}: \${pkg.current} \u2192 \${pkg.latest}\`, 'yellow')
|
|
900
|
+
})
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// \u7E3D\u7D50
|
|
904
|
+
log('\\n=== \u6AA2\u67E5\u7D50\u679C ===', 'blue')
|
|
905
|
+
log(\`\u7E3D\u8A08: \${results.length} \u500B\u5957\u4EF6\`, 'blue')
|
|
906
|
+
log(\`\u6700\u65B0: \${upToDate.length} \u500B\`, 'green')
|
|
907
|
+
log(\`\u9700\u66F4\u65B0: \${outdated.length} \u500B\`, outdated.length > 0 ? 'yellow' : 'green')
|
|
908
|
+
|
|
909
|
+
// \u5982\u679C\u6709\u9700\u8981\u66F4\u65B0\u7684\u5957\u4EF6\uFF0C\u8FD4\u56DE\u975E\u96F6\u9000\u51FA\u78BC
|
|
910
|
+
if (outdated.length > 0) {
|
|
911
|
+
log('\\n\u5EFA\u8B70\u57F7\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0\u5957\u4EF6\uFF1A', 'yellow')
|
|
912
|
+
log(' bun update', 'yellow')
|
|
913
|
+
process.exit(1)
|
|
914
|
+
} else {
|
|
915
|
+
log('\\n\u2713 \u6240\u6709\u5957\u4EF6\u90FD\u662F\u6700\u65B0\u7248\u672C\uFF01', 'green')
|
|
916
|
+
process.exit(0)
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
main().catch((error) => {
|
|
921
|
+
log(\`\\n\u932F\u8AA4: \${error.message}\`, 'red')
|
|
922
|
+
process.exit(1)
|
|
923
|
+
})
|
|
924
|
+
`;
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Generate check.sh script content.
|
|
928
|
+
*/
|
|
929
|
+
generateCheckShellScript() {
|
|
930
|
+
return `#!/bin/bash
|
|
931
|
+
|
|
932
|
+
# \u5C08\u6848\u6AA2\u67E5\u8173\u672C
|
|
933
|
+
# \u57F7\u884C\u6240\u6709\u5FC5\u8981\u7684\u6AA2\u67E5\uFF1A\u985E\u578B\u6AA2\u67E5\u3001\u6E2C\u8A66\u3001\u4F9D\u8CF4\u6AA2\u67E5\u7B49
|
|
934
|
+
|
|
935
|
+
set -e
|
|
936
|
+
|
|
937
|
+
# \u984F\u8272\u5B9A\u7FA9
|
|
938
|
+
GREEN='\\033[0;32m'
|
|
939
|
+
YELLOW='\\033[1;33m'
|
|
940
|
+
RED='\\033[0;31m'
|
|
941
|
+
BLUE='\\033[0;34m'
|
|
942
|
+
NC='\\033[0m' # No Color
|
|
943
|
+
|
|
944
|
+
echo -e "\${BLUE}=== \u5C08\u6848\u6AA2\u67E5 ===\${NC}\\n"
|
|
945
|
+
|
|
946
|
+
# \u6AA2\u67E5\u662F\u5426\u5728\u6B63\u78BA\u7684\u76EE\u9304
|
|
947
|
+
if [ ! -f "package.json" ]; then
|
|
948
|
+
echo -e "\${RED}\u932F\u8AA4: \u8ACB\u5728\u5C08\u6848\u6839\u76EE\u9304\u57F7\u884C\u6B64\u8173\u672C\${NC}"
|
|
949
|
+
exit 1
|
|
950
|
+
fi
|
|
951
|
+
|
|
952
|
+
# \u6AA2\u67E5 Bun \u662F\u5426\u5B89\u88DD
|
|
953
|
+
if ! command -v bun &> /dev/null; then
|
|
954
|
+
echo -e "\${RED}\u932F\u8AA4: \u672A\u627E\u5230 bun\uFF0C\u8ACB\u5148\u5B89\u88DD Bun\${NC}"
|
|
955
|
+
exit 1
|
|
956
|
+
fi
|
|
957
|
+
|
|
958
|
+
# 1. \u985E\u578B\u6AA2\u67E5
|
|
959
|
+
echo -e "\${YELLOW}[1/3] \u57F7\u884C\u985E\u578B\u6AA2\u67E5...\${NC}"
|
|
960
|
+
if bun run typecheck; then
|
|
961
|
+
echo -e "\${GREEN}\u2713 \u985E\u578B\u6AA2\u67E5\u901A\u904E\${NC}\\n"
|
|
962
|
+
else
|
|
963
|
+
echo -e "\${RED}\u2717 \u985E\u578B\u6AA2\u67E5\u5931\u6557\${NC}"
|
|
964
|
+
exit 1
|
|
965
|
+
fi
|
|
966
|
+
|
|
967
|
+
# 2. \u57F7\u884C\u6E2C\u8A66
|
|
968
|
+
echo -e "\${YELLOW}[2/3] \u57F7\u884C\u6E2C\u8A66...\${NC}"
|
|
969
|
+
if bun test; then
|
|
970
|
+
echo -e "\${GREEN}\u2713 \u6E2C\u8A66\u901A\u904E\${NC}\\n"
|
|
971
|
+
else
|
|
972
|
+
echo -e "\${RED}\u2717 \u6E2C\u8A66\u5931\u6557\${NC}"
|
|
973
|
+
exit 1
|
|
974
|
+
fi
|
|
975
|
+
|
|
976
|
+
# 3. \u6AA2\u67E5\u4F9D\u8CF4\u7248\u672C\uFF08\u53EF\u9078\uFF0C\u56E0\u70BA\u9700\u8981\u7DB2\u8DEF\u9023\u7DDA\uFF09
|
|
977
|
+
echo -e "\${YELLOW}[3/3] \u6AA2\u67E5\u4F9D\u8CF4\u7248\u672C...\${NC}"
|
|
978
|
+
if bun run check:deps; then
|
|
979
|
+
echo -e "\${GREEN}\u2713 \u4F9D\u8CF4\u6AA2\u67E5\u5B8C\u6210\${NC}\\n"
|
|
980
|
+
else
|
|
981
|
+
echo -e "\${YELLOW}\u26A0 \u4F9D\u8CF4\u6AA2\u67E5\u6709\u8B66\u544A\uFF08\u67D0\u4E9B\u5957\u4EF6\u53EF\u80FD\u9700\u8981\u66F4\u65B0\uFF09\${NC}\\n"
|
|
982
|
+
fi
|
|
983
|
+
|
|
984
|
+
echo -e "\${GREEN}=== \u6240\u6709\u6AA2\u67E5\u5B8C\u6210 ===\${NC}"
|
|
985
|
+
`;
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Generate pre-commit.sh script content.
|
|
989
|
+
*/
|
|
990
|
+
generatePreCommitScript() {
|
|
991
|
+
return `#!/bin/bash
|
|
992
|
+
|
|
993
|
+
# Pre-commit Hook
|
|
994
|
+
# \u5728 git commit \u524D\u81EA\u52D5\u57F7\u884C\u6AA2\u67E5
|
|
995
|
+
#
|
|
996
|
+
# \u5B89\u88DD\u65B9\u5F0F\uFF1A
|
|
997
|
+
# ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit
|
|
998
|
+
# \u6216
|
|
999
|
+
# cp scripts/pre-commit.sh .git/hooks/pre-commit
|
|
1000
|
+
# chmod +x .git/hooks/pre-commit
|
|
1001
|
+
|
|
1002
|
+
set -e
|
|
1003
|
+
|
|
1004
|
+
# \u984F\u8272\u5B9A\u7FA9
|
|
1005
|
+
GREEN='\\033[0;32m'
|
|
1006
|
+
YELLOW='\\033[1;33m'
|
|
1007
|
+
RED='\\033[0;31m'
|
|
1008
|
+
BLUE='\\033[0;34m'
|
|
1009
|
+
NC='\\033[0m' # No Color
|
|
1010
|
+
|
|
1011
|
+
echo -e "\${BLUE}=== Pre-commit \u6AA2\u67E5 ===\${NC}\\n"
|
|
1012
|
+
|
|
1013
|
+
# \u5207\u63DB\u5230\u5C08\u6848\u6839\u76EE\u9304
|
|
1014
|
+
cd "$(git rev-parse --show-toplevel)"
|
|
1015
|
+
|
|
1016
|
+
# \u6AA2\u67E5\u662F\u5426\u5728\u6B63\u78BA\u7684\u76EE\u9304
|
|
1017
|
+
if [ ! -f "package.json" ]; then
|
|
1018
|
+
echo -e "\${RED}\u932F\u8AA4: \u627E\u4E0D\u5230 package.json\${NC}"
|
|
1019
|
+
exit 1
|
|
1020
|
+
fi
|
|
1021
|
+
|
|
1022
|
+
# \u6AA2\u67E5 Bun \u662F\u5426\u5B89\u88DD
|
|
1023
|
+
if ! command -v bun &> /dev/null; then
|
|
1024
|
+
echo -e "\${RED}\u932F\u8AA4: \u672A\u627E\u5230 bun\uFF0C\u8ACB\u5148\u5B89\u88DD Bun\${NC}"
|
|
1025
|
+
exit 1
|
|
1026
|
+
fi
|
|
1027
|
+
|
|
1028
|
+
# 1. \u985E\u578B\u6AA2\u67E5\uFF08\u5FEB\u901F\u6AA2\u67E5\uFF09
|
|
1029
|
+
echo -e "\${YELLOW}[1/2] \u57F7\u884C\u985E\u578B\u6AA2\u67E5...\${NC}"
|
|
1030
|
+
if bun run typecheck; then
|
|
1031
|
+
echo -e "\${GREEN}\u2713 \u985E\u578B\u6AA2\u67E5\u901A\u904E\${NC}\\n"
|
|
1032
|
+
else
|
|
1033
|
+
echo -e "\${RED}\u2717 \u985E\u578B\u6AA2\u67E5\u5931\u6557\${NC}"
|
|
1034
|
+
echo -e "\${YELLOW}\u63D0\u793A: \u8ACB\u4FEE\u6B63\u985E\u578B\u932F\u8AA4\u5F8C\u518D\u63D0\u4EA4\${NC}"
|
|
1035
|
+
exit 1
|
|
1036
|
+
fi
|
|
1037
|
+
|
|
1038
|
+
# 2. \u57F7\u884C\u6E2C\u8A66\uFF08\u53EF\u9078\uFF0C\u5982\u679C\u6E2C\u8A66\u6642\u9593\u8F03\u9577\u53EF\u4EE5\u8A3B\u89E3\u6389\uFF09
|
|
1039
|
+
echo -e "\${YELLOW}[2/2] \u57F7\u884C\u6E2C\u8A66...\${NC}"
|
|
1040
|
+
if bun test; then
|
|
1041
|
+
echo -e "\${GREEN}\u2713 \u6E2C\u8A66\u901A\u904E\${NC}\\n"
|
|
1042
|
+
else
|
|
1043
|
+
echo -e "\${RED}\u2717 \u6E2C\u8A66\u5931\u6557\${NC}"
|
|
1044
|
+
echo -e "\${YELLOW}\u63D0\u793A: \u8ACB\u4FEE\u6B63\u6E2C\u8A66\u932F\u8AA4\u5F8C\u518D\u63D0\u4EA4\${NC}"
|
|
1045
|
+
exit 1
|
|
1046
|
+
fi
|
|
1047
|
+
|
|
1048
|
+
echo -e "\${GREEN}=== Pre-commit \u6AA2\u67E5\u901A\u904E ===\${NC}\\n"
|
|
1049
|
+
`;
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Generate CHECK_SYSTEM.md documentation.
|
|
1053
|
+
*/
|
|
1054
|
+
generateCheckSystemDoc(context) {
|
|
1055
|
+
return `# \u5C08\u6848\u6AA2\u67E5\u7CFB\u7D71
|
|
1056
|
+
|
|
1057
|
+
\u672C\u5C08\u6848\u5DF2\u5EFA\u7ACB\u5B8C\u6574\u7684\u672C\u5730\u6AA2\u67E5\u6A5F\u5236\uFF0C\u7121\u9700\u4F9D\u8CF4 GitHub CI\u3002
|
|
1058
|
+
|
|
1059
|
+
## \u5FEB\u901F\u958B\u59CB
|
|
1060
|
+
|
|
1061
|
+
### \u57F7\u884C\u5B8C\u6574\u6AA2\u67E5
|
|
1062
|
+
\`\`\`bash
|
|
1063
|
+
bun run validate
|
|
1064
|
+
\`\`\`
|
|
1065
|
+
|
|
1066
|
+
### \u57F7\u884C\u55AE\u9805\u6AA2\u67E5
|
|
1067
|
+
\`\`\`bash
|
|
1068
|
+
# \u985E\u578B\u6AA2\u67E5
|
|
1069
|
+
bun run typecheck
|
|
1070
|
+
|
|
1071
|
+
# \u6E2C\u8A66
|
|
1072
|
+
bun run test
|
|
1073
|
+
|
|
1074
|
+
# \u4F9D\u8CF4\u7248\u672C\u6AA2\u67E5
|
|
1075
|
+
bun run check:deps
|
|
1076
|
+
\`\`\`
|
|
1077
|
+
|
|
1078
|
+
## \u53EF\u7528\u547D\u4EE4
|
|
1079
|
+
|
|
1080
|
+
### Package.json \u8173\u672C
|
|
1081
|
+
|
|
1082
|
+
| \u547D\u4EE4 | \u8AAA\u660E |
|
|
1083
|
+
|------|------|
|
|
1084
|
+
| \`bun run typecheck\` | TypeScript \u985E\u578B\u6AA2\u67E5 |
|
|
1085
|
+
| \`bun run test\` | \u57F7\u884C\u6240\u6709\u6E2C\u8A66 |
|
|
1086
|
+
| \`bun run check\` | \u985E\u578B\u6AA2\u67E5 + \u6E2C\u8A66 |
|
|
1087
|
+
| \`bun run check:deps\` | \u6AA2\u67E5\u4F9D\u8CF4\u7248\u672C |
|
|
1088
|
+
| \`bun run validate\` | \u5B8C\u6574\u9A57\u8B49\uFF08\u985E\u578B + \u6E2C\u8A66 + \u4F9D\u8CF4\uFF09 |
|
|
1089
|
+
| \`bun run precommit\` | \u7B49\u540C\u65BC \`validate\` |
|
|
1090
|
+
|
|
1091
|
+
### Shell \u8173\u672C
|
|
1092
|
+
|
|
1093
|
+
| \u8173\u672C | \u8AAA\u660E |
|
|
1094
|
+
|------|------|
|
|
1095
|
+
| \`./scripts/check.sh\` | \u5B8C\u6574\u5C08\u6848\u6AA2\u67E5\uFF08Shell \u7248\u672C\uFF09 |
|
|
1096
|
+
| \`./scripts/pre-commit.sh\` | Pre-commit hook \u8173\u672C |
|
|
1097
|
+
|
|
1098
|
+
## Pre-commit Hook\uFF08\u63A8\u85A6\uFF09
|
|
1099
|
+
|
|
1100
|
+
\u5B89\u88DD pre-commit hook \u5F8C\uFF0C\u6BCF\u6B21 \`git commit\` \u524D\u6703\u81EA\u52D5\u57F7\u884C\u6AA2\u67E5\uFF1A
|
|
1101
|
+
|
|
1102
|
+
\`\`\`bash
|
|
1103
|
+
# \u5B89\u88DD pre-commit hook
|
|
1104
|
+
ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit
|
|
1105
|
+
|
|
1106
|
+
# \u6216\u4F7F\u7528\u8907\u88FD\u65B9\u5F0F
|
|
1107
|
+
cp scripts/pre-commit.sh .git/hooks/pre-commit
|
|
1108
|
+
chmod +x .git/hooks/pre-commit
|
|
1109
|
+
\`\`\`
|
|
1110
|
+
|
|
1111
|
+
**\u529F\u80FD\uFF1A**
|
|
1112
|
+
- \u2705 \u81EA\u52D5\u57F7\u884C\u985E\u578B\u6AA2\u67E5
|
|
1113
|
+
- \u2705 \u81EA\u52D5\u57F7\u884C\u6E2C\u8A66
|
|
1114
|
+
- \u274C \u6AA2\u67E5\u5931\u6557\u6642\u963B\u6B62\u63D0\u4EA4
|
|
1115
|
+
|
|
1116
|
+
**\u8DF3\u904E\u6AA2\u67E5\uFF08\u4E0D\u63A8\u85A6\uFF09\uFF1A**
|
|
1117
|
+
\`\`\`bash
|
|
1118
|
+
git commit --no-verify -m "\u7DCA\u6025\u4FEE\u5FA9"
|
|
1119
|
+
\`\`\`
|
|
1120
|
+
|
|
1121
|
+
## \u6AA2\u67E5\u9805\u76EE
|
|
1122
|
+
|
|
1123
|
+
### 1. \u985E\u578B\u6AA2\u67E5
|
|
1124
|
+
- \u4F7F\u7528 \`tsc --noEmit\` \u6AA2\u67E5 TypeScript \u985E\u578B
|
|
1125
|
+
- \u78BA\u4FDD\u6C92\u6709\u985E\u578B\u932F\u8AA4
|
|
1126
|
+
|
|
1127
|
+
### 2. \u6E2C\u8A66
|
|
1128
|
+
- \u57F7\u884C\u6240\u6709\u55AE\u5143\u6E2C\u8A66\u548C\u6574\u5408\u6E2C\u8A66
|
|
1129
|
+
- \u78BA\u4FDD\u6E2C\u8A66\u901A\u904E
|
|
1130
|
+
|
|
1131
|
+
### 3. \u4F9D\u8CF4\u6AA2\u67E5\uFF08\u53EF\u9078\uFF09
|
|
1132
|
+
- \u6AA2\u67E5\u5957\u4EF6\u7248\u672C\u662F\u5426\u70BA\u6700\u65B0
|
|
1133
|
+
- \u63D0\u4F9B\u66F4\u65B0\u5EFA\u8B70
|
|
1134
|
+
- \u9700\u8981\u7DB2\u8DEF\u9023\u7DDA
|
|
1135
|
+
|
|
1136
|
+
## \u5DE5\u4F5C\u6D41\u7A0B\u5EFA\u8B70
|
|
1137
|
+
|
|
1138
|
+
### \u958B\u767C\u6642
|
|
1139
|
+
1. \u958B\u767C\u529F\u80FD
|
|
1140
|
+
2. \u63D0\u4EA4\u524D\u57F7\u884C \`bun run validate\`
|
|
1141
|
+
3. \u4FEE\u6B63\u554F\u984C
|
|
1142
|
+
4. \u63D0\u4EA4\u7A0B\u5F0F\u78BC
|
|
1143
|
+
|
|
1144
|
+
### \u4F7F\u7528 Pre-commit Hook\uFF08\u63A8\u85A6\uFF09
|
|
1145
|
+
1. \u5B89\u88DD pre-commit hook\uFF08\u53EA\u9700\u4E00\u6B21\uFF09
|
|
1146
|
+
2. \u6B63\u5E38\u958B\u767C\u548C\u63D0\u4EA4
|
|
1147
|
+
3. \u6AA2\u67E5\u6703\u81EA\u52D5\u57F7\u884C
|
|
1148
|
+
4. \u5982\u6709\u554F\u984C\uFF0C\u4FEE\u6B63\u5F8C\u91CD\u65B0\u63D0\u4EA4
|
|
1149
|
+
|
|
1150
|
+
## \u6A94\u6848\u7D50\u69CB
|
|
1151
|
+
|
|
1152
|
+
\`\`\`
|
|
1153
|
+
${context.nameKebabCase}/
|
|
1154
|
+
\u251C\u2500\u2500 package.json # \u6AA2\u67E5\u8173\u672C\u5B9A\u7FA9
|
|
1155
|
+
\u251C\u2500\u2500 scripts/
|
|
1156
|
+
\u2502 \u251C\u2500\u2500 check.sh # \u5B8C\u6574\u6AA2\u67E5\u8173\u672C\uFF08Shell\uFF09
|
|
1157
|
+
\u2502 \u251C\u2500\u2500 check-dependencies.ts # \u4F9D\u8CF4\u7248\u672C\u6AA2\u67E5
|
|
1158
|
+
\u2502 \u2514\u2500\u2500 pre-commit.sh # Pre-commit hook
|
|
1159
|
+
\u2514\u2500\u2500 CHECK_SYSTEM.md # \u672C\u6587\u4EF6
|
|
1160
|
+
\`\`\`
|
|
1161
|
+
|
|
1162
|
+
## \u6CE8\u610F\u4E8B\u9805
|
|
1163
|
+
|
|
1164
|
+
1. **\u4F9D\u8CF4\u6AA2\u67E5\u9700\u8981\u7DB2\u8DEF\u9023\u7DDA**\uFF1A\`check:deps\` \u9700\u8981\u9023\u63A5\u5230 npm registry
|
|
1165
|
+
2. **\u6E2C\u8A66\u6642\u9593**\uFF1A\u5982\u679C\u6E2C\u8A66\u6642\u9593\u8F03\u9577\uFF0C\u53EF\u4EE5\u7DE8\u8F2F \`pre-commit.sh\` \u8A3B\u89E3\u6389\u6E2C\u8A66\u90E8\u5206
|
|
1166
|
+
3. **\u985E\u578B\u932F\u8AA4**\uFF1A\u5C08\u6848\u4E2D\u53EF\u80FD\u9084\u6709\u4E00\u4E9B\u65E2\u6709\u7684\u985E\u578B\u932F\u8AA4\uFF0C\u5EFA\u8B70\u9010\u6B65\u4FEE\u6B63
|
|
1167
|
+
|
|
1168
|
+
## \u6545\u969C\u6392\u9664
|
|
1169
|
+
|
|
1170
|
+
### \u6AA2\u67E5\u5931\u6557
|
|
1171
|
+
1. \u67E5\u770B\u932F\u8AA4\u8A0A\u606F
|
|
1172
|
+
2. \u4FEE\u6B63\u554F\u984C
|
|
1173
|
+
3. \u91CD\u65B0\u57F7\u884C\u6AA2\u67E5
|
|
1174
|
+
|
|
1175
|
+
### \u8DF3\u904E\u6AA2\u67E5
|
|
1176
|
+
\u53EA\u6709\u5728\u7DCA\u6025\u60C5\u6CC1\u4E0B\u624D\u4F7F\u7528\uFF1A
|
|
1177
|
+
\`\`\`bash
|
|
1178
|
+
git commit --no-verify
|
|
1179
|
+
\`\`\`
|
|
1180
|
+
|
|
1181
|
+
### \u79FB\u9664 Pre-commit Hook
|
|
1182
|
+
\`\`\`bash
|
|
1183
|
+
rm .git/hooks/pre-commit
|
|
1184
|
+
\`\`\`
|
|
1185
|
+
`;
|
|
1186
|
+
}
|
|
734
1187
|
/**
|
|
735
1188
|
* Log a message if verbose mode is enabled.
|
|
736
1189
|
*/
|
|
@@ -911,6 +1364,11 @@ var CleanArchitectureGenerator = class extends BaseGenerator {
|
|
|
911
1364
|
type: "directory",
|
|
912
1365
|
name: "Providers",
|
|
913
1366
|
children: [
|
|
1367
|
+
{
|
|
1368
|
+
type: "file",
|
|
1369
|
+
name: "index.ts",
|
|
1370
|
+
content: this.generateProvidersIndex()
|
|
1371
|
+
},
|
|
914
1372
|
{
|
|
915
1373
|
type: "file",
|
|
916
1374
|
name: "AppServiceProvider.ts",
|
|
@@ -920,6 +1378,16 @@ var CleanArchitectureGenerator = class extends BaseGenerator {
|
|
|
920
1378
|
type: "file",
|
|
921
1379
|
name: "RepositoryServiceProvider.ts",
|
|
922
1380
|
content: this.generateRepositoryServiceProvider()
|
|
1381
|
+
},
|
|
1382
|
+
{
|
|
1383
|
+
type: "file",
|
|
1384
|
+
name: "MiddlewareProvider.ts",
|
|
1385
|
+
content: this.generateMiddlewareProvider()
|
|
1386
|
+
},
|
|
1387
|
+
{
|
|
1388
|
+
type: "file",
|
|
1389
|
+
name: "RouteProvider.ts",
|
|
1390
|
+
content: this.generateRouteProvider()
|
|
923
1391
|
}
|
|
924
1392
|
]
|
|
925
1393
|
}
|
|
@@ -1413,6 +1881,65 @@ export class RepositoryServiceProvider extends ServiceProvider {
|
|
|
1413
1881
|
container.singleton('mailService', () => new MailService())
|
|
1414
1882
|
}
|
|
1415
1883
|
}
|
|
1884
|
+
`;
|
|
1885
|
+
}
|
|
1886
|
+
generateProvidersIndex() {
|
|
1887
|
+
return `/**
|
|
1888
|
+
* Application Service Providers
|
|
1889
|
+
*/
|
|
1890
|
+
|
|
1891
|
+
export { AppServiceProvider } from './AppServiceProvider'
|
|
1892
|
+
export { RepositoryServiceProvider } from './RepositoryServiceProvider'
|
|
1893
|
+
export { MiddlewareProvider } from './MiddlewareProvider'
|
|
1894
|
+
export { RouteProvider } from './RouteProvider'
|
|
1895
|
+
`;
|
|
1896
|
+
}
|
|
1897
|
+
generateMiddlewareProvider() {
|
|
1898
|
+
return `/**
|
|
1899
|
+
* Middleware Service Provider
|
|
1900
|
+
*/
|
|
1901
|
+
|
|
1902
|
+
import {
|
|
1903
|
+
ServiceProvider,
|
|
1904
|
+
type Container,
|
|
1905
|
+
type PlanetCore,
|
|
1906
|
+
bodySizeLimit,
|
|
1907
|
+
securityHeaders,
|
|
1908
|
+
} from '@gravito/core'
|
|
1909
|
+
|
|
1910
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
1911
|
+
register(_container: Container): void {}
|
|
1912
|
+
|
|
1913
|
+
boot(core: PlanetCore): void {
|
|
1914
|
+
const isDev = process.env.NODE_ENV !== 'production'
|
|
1915
|
+
|
|
1916
|
+
core.adapter.use('*', securityHeaders({
|
|
1917
|
+
contentSecurityPolicy: isDev ? false : undefined,
|
|
1918
|
+
}))
|
|
1919
|
+
|
|
1920
|
+
core.adapter.use('*', bodySizeLimit(10 * 1024 * 1024))
|
|
1921
|
+
|
|
1922
|
+
core.logger.info('\u{1F6E1}\uFE0F Middleware registered')
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
`;
|
|
1926
|
+
}
|
|
1927
|
+
generateRouteProvider() {
|
|
1928
|
+
return `/**
|
|
1929
|
+
* Route Service Provider
|
|
1930
|
+
*/
|
|
1931
|
+
|
|
1932
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
1933
|
+
import { registerApiRoutes } from '../../Interface/Http/Routes/api'
|
|
1934
|
+
|
|
1935
|
+
export class RouteProvider extends ServiceProvider {
|
|
1936
|
+
register(_container: Container): void {}
|
|
1937
|
+
|
|
1938
|
+
boot(core: PlanetCore): void {
|
|
1939
|
+
registerApiRoutes(core.router)
|
|
1940
|
+
core.logger.info('\u{1F6E4}\uFE0F Routes registered')
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1416
1943
|
`;
|
|
1417
1944
|
}
|
|
1418
1945
|
// ─────────────────────────────────────────────────────────────
|
|
@@ -1497,64 +2024,55 @@ export class UserPresenter {
|
|
|
1497
2024
|
}
|
|
1498
2025
|
`;
|
|
1499
2026
|
}
|
|
1500
|
-
generateBootstrap(
|
|
2027
|
+
generateBootstrap(_context) {
|
|
1501
2028
|
return `/**
|
|
1502
2029
|
* Application Bootstrap
|
|
2030
|
+
*
|
|
2031
|
+
* The entry point for your Clean Architecture application.
|
|
2032
|
+
* Uses the ServiceProvider pattern for modular initialization.
|
|
2033
|
+
*
|
|
2034
|
+
* Lifecycle:
|
|
2035
|
+
* 1. Configure: Load app config and orbits
|
|
2036
|
+
* 2. Boot: Initialize PlanetCore
|
|
2037
|
+
* 3. Register Providers: Bind services to container
|
|
2038
|
+
* 4. Bootstrap: Boot all providers
|
|
1503
2039
|
*/
|
|
1504
2040
|
|
|
1505
|
-
import {
|
|
2041
|
+
import { defineConfig, PlanetCore } from '@gravito/core'
|
|
1506
2042
|
import { OrbitAtlas } from '@gravito/atlas'
|
|
1507
|
-
import
|
|
1508
|
-
import {
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
"default-src 'self'",
|
|
1521
|
-
"script-src 'self' 'unsafe-inline'",
|
|
1522
|
-
"style-src 'self' 'unsafe-inline'",
|
|
1523
|
-
"img-src 'self' data:",
|
|
1524
|
-
"object-src 'none'",
|
|
1525
|
-
"base-uri 'self'",
|
|
1526
|
-
"frame-ancestors 'none'",
|
|
1527
|
-
].join('; ')
|
|
1528
|
-
const cspValue = process.env.APP_CSP
|
|
1529
|
-
const csp = cspValue === 'false' ? false : (cspValue ?? defaultCsp)
|
|
1530
|
-
const hstsMaxAge = Number.parseInt(process.env.APP_HSTS_MAX_AGE ?? '15552000', 10)
|
|
1531
|
-
const bodyLimit = Number.parseInt(process.env.APP_BODY_LIMIT ?? '1048576', 10)
|
|
1532
|
-
const requireLength = process.env.APP_BODY_REQUIRE_LENGTH === 'true'
|
|
1533
|
-
|
|
1534
|
-
core.adapter.use(
|
|
1535
|
-
'*',
|
|
1536
|
-
securityHeaders({
|
|
1537
|
-
contentSecurityPolicy: csp,
|
|
1538
|
-
hsts:
|
|
1539
|
-
process.env.NODE_ENV === 'production'
|
|
1540
|
-
? { maxAge: Number.isNaN(hstsMaxAge) ? 15552000 : hstsMaxAge, includeSubDomains: true }
|
|
1541
|
-
: false,
|
|
2043
|
+
import appConfig from '../config/app'
|
|
2044
|
+
import {
|
|
2045
|
+
AppServiceProvider,
|
|
2046
|
+
RepositoryServiceProvider,
|
|
2047
|
+
MiddlewareProvider,
|
|
2048
|
+
RouteProvider,
|
|
2049
|
+
} from './Infrastructure/Providers'
|
|
2050
|
+
|
|
2051
|
+
export async function bootstrap() {
|
|
2052
|
+
// 1. Configure
|
|
2053
|
+
const config = defineConfig({
|
|
2054
|
+
config: appConfig,
|
|
2055
|
+
orbits: [new OrbitAtlas()],
|
|
1542
2056
|
})
|
|
1543
|
-
)
|
|
1544
|
-
if (!Number.isNaN(bodyLimit) && bodyLimit > 0) {
|
|
1545
|
-
core.adapter.use('*', bodySizeLimit(bodyLimit, { requireContentLength: requireLength }))
|
|
1546
|
-
}
|
|
1547
2057
|
|
|
1548
|
-
|
|
2058
|
+
// 2. Boot Core
|
|
2059
|
+
const core = await PlanetCore.boot(config)
|
|
2060
|
+
core.registerGlobalErrorHandlers()
|
|
1549
2061
|
|
|
1550
|
-
|
|
1551
|
-
core.register(new
|
|
2062
|
+
// 3. Register Providers
|
|
2063
|
+
core.register(new RepositoryServiceProvider())
|
|
2064
|
+
core.register(new AppServiceProvider())
|
|
2065
|
+
core.register(new MiddlewareProvider())
|
|
2066
|
+
core.register(new RouteProvider())
|
|
1552
2067
|
|
|
1553
|
-
|
|
2068
|
+
// 4. Bootstrap All Providers
|
|
2069
|
+
await core.bootstrap()
|
|
1554
2070
|
|
|
1555
|
-
|
|
1556
|
-
|
|
2071
|
+
return core
|
|
2072
|
+
}
|
|
1557
2073
|
|
|
2074
|
+
// Application Entry Point
|
|
2075
|
+
const core = await bootstrap()
|
|
1558
2076
|
export default core.liftoff()
|
|
1559
2077
|
`;
|
|
1560
2078
|
}
|
|
@@ -1566,6 +2084,15 @@ export default core.liftoff()
|
|
|
1566
2084
|
This project follows **Clean Architecture** (by Robert C. Martin).
|
|
1567
2085
|
The key principle is the **Dependency Rule**: dependencies point inward.
|
|
1568
2086
|
|
|
2087
|
+
## Service Providers
|
|
2088
|
+
|
|
2089
|
+
Service providers are the central place to configure your application. They follow the ServiceProvider pattern with \`register()\` and \`boot()\` lifecycle methods.
|
|
2090
|
+
|
|
2091
|
+
### Provider Lifecycle
|
|
2092
|
+
|
|
2093
|
+
1. **register()**: Bind services to the container (sync or async).
|
|
2094
|
+
2. **boot()**: Called after ALL providers have registered. Safe to use other services.
|
|
2095
|
+
|
|
1569
2096
|
## Layer Structure
|
|
1570
2097
|
|
|
1571
2098
|
\`\`\`
|
|
@@ -1637,6 +2164,10 @@ Created with \u2764\uFE0F using Gravito Framework
|
|
|
1637
2164
|
start: "bun run dist/bootstrap.js",
|
|
1638
2165
|
test: "bun test",
|
|
1639
2166
|
typecheck: "tsc --noEmit",
|
|
2167
|
+
check: "bun run typecheck && bun run test",
|
|
2168
|
+
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
2169
|
+
validate: "bun run check && bun run check:deps",
|
|
2170
|
+
precommit: "bun run validate",
|
|
1640
2171
|
"docker:build": `docker build -t ${context.nameKebabCase} .`,
|
|
1641
2172
|
"docker:run": `docker run -it -p 3000:3000 ${context.nameKebabCase}`
|
|
1642
2173
|
},
|
|
@@ -1960,63 +2491,46 @@ var DddGenerator = class extends BaseGenerator {
|
|
|
1960
2491
|
// ─────────────────────────────────────────────────────────────
|
|
1961
2492
|
// Bootstrap File Generators
|
|
1962
2493
|
// ─────────────────────────────────────────────────────────────
|
|
1963
|
-
generateBootstrapApp(
|
|
2494
|
+
generateBootstrapApp(_context) {
|
|
1964
2495
|
return `/**
|
|
1965
2496
|
* Application Bootstrap
|
|
1966
2497
|
*
|
|
1967
|
-
* Central configuration and initialization
|
|
2498
|
+
* Central configuration and initialization using the ServiceProvider pattern.
|
|
2499
|
+
*
|
|
2500
|
+
* Lifecycle:
|
|
2501
|
+
* 1. Configure: Load app config and orbits
|
|
2502
|
+
* 2. Boot: Initialize PlanetCore
|
|
2503
|
+
* 3. Register Providers: Bind services to container
|
|
2504
|
+
* 4. Bootstrap: Boot all providers
|
|
1968
2505
|
*/
|
|
1969
2506
|
|
|
1970
|
-
import {
|
|
2507
|
+
import { defineConfig, PlanetCore } from '@gravito/core'
|
|
2508
|
+
import { OrbitAtlas } from '@gravito/atlas'
|
|
2509
|
+
import appConfig from '../../config/app'
|
|
1971
2510
|
import { registerProviders } from './providers'
|
|
1972
2511
|
import { registerRoutes } from './routes'
|
|
1973
2512
|
|
|
1974
2513
|
export async function createApp(): Promise<PlanetCore> {
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2514
|
+
// 1. Configure
|
|
2515
|
+
const config = defineConfig({
|
|
2516
|
+
config: appConfig,
|
|
2517
|
+
orbits: [new OrbitAtlas()],
|
|
2518
|
+
})
|
|
1980
2519
|
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
"style-src 'self' 'unsafe-inline'",
|
|
1985
|
-
"img-src 'self' data:",
|
|
1986
|
-
"object-src 'none'",
|
|
1987
|
-
"base-uri 'self'",
|
|
1988
|
-
"frame-ancestors 'none'",
|
|
1989
|
-
].join('; ')
|
|
1990
|
-
const cspValue = process.env.APP_CSP
|
|
1991
|
-
const csp = cspValue === 'false' ? false : (cspValue ?? defaultCsp)
|
|
1992
|
-
const hstsMaxAge = Number.parseInt(process.env.APP_HSTS_MAX_AGE ?? '15552000', 10)
|
|
1993
|
-
const bodyLimit = Number.parseInt(process.env.APP_BODY_LIMIT ?? '1048576', 10)
|
|
1994
|
-
const requireLength = process.env.APP_BODY_REQUIRE_LENGTH === 'true'
|
|
1995
|
-
|
|
1996
|
-
core.adapter.use(
|
|
1997
|
-
'*',
|
|
1998
|
-
securityHeaders({
|
|
1999
|
-
contentSecurityPolicy: csp,
|
|
2000
|
-
hsts:
|
|
2001
|
-
process.env.NODE_ENV === 'production'
|
|
2002
|
-
? { maxAge: Number.isNaN(hstsMaxAge) ? 15552000 : hstsMaxAge, includeSubDomains: true }
|
|
2003
|
-
: false,
|
|
2004
|
-
})
|
|
2005
|
-
)
|
|
2006
|
-
if (!Number.isNaN(bodyLimit) && bodyLimit > 0) {
|
|
2007
|
-
core.adapter.use('*', bodySizeLimit(bodyLimit, { requireContentLength: requireLength }))
|
|
2008
|
-
}
|
|
2520
|
+
// 2. Boot Core
|
|
2521
|
+
const core = await PlanetCore.boot(config)
|
|
2522
|
+
core.registerGlobalErrorHandlers()
|
|
2009
2523
|
|
|
2010
|
-
|
|
2011
|
-
|
|
2524
|
+
// 3. Register Providers
|
|
2525
|
+
await registerProviders(core)
|
|
2012
2526
|
|
|
2013
|
-
|
|
2014
|
-
|
|
2527
|
+
// 4. Bootstrap All Providers
|
|
2528
|
+
await core.bootstrap()
|
|
2015
2529
|
|
|
2016
|
-
|
|
2017
|
-
|
|
2530
|
+
// Register routes after bootstrap
|
|
2531
|
+
registerRoutes(core.router)
|
|
2018
2532
|
|
|
2019
|
-
|
|
2533
|
+
return core
|
|
2020
2534
|
}
|
|
2021
2535
|
`;
|
|
2022
2536
|
}
|
|
@@ -2024,19 +2538,48 @@ export async function createApp(): Promise<PlanetCore> {
|
|
|
2024
2538
|
return `/**
|
|
2025
2539
|
* Service Providers Registry
|
|
2026
2540
|
*
|
|
2027
|
-
* Register all
|
|
2541
|
+
* Register all service providers here.
|
|
2542
|
+
* Include both global and module-specific providers.
|
|
2028
2543
|
*/
|
|
2029
2544
|
|
|
2030
|
-
import
|
|
2545
|
+
import {
|
|
2546
|
+
ServiceProvider,
|
|
2547
|
+
type Container,
|
|
2548
|
+
type PlanetCore,
|
|
2549
|
+
bodySizeLimit,
|
|
2550
|
+
securityHeaders,
|
|
2551
|
+
} from '@gravito/core'
|
|
2031
2552
|
import { OrderingServiceProvider } from '../Modules/Ordering/Infrastructure/Providers/OrderingServiceProvider'
|
|
2032
2553
|
import { CatalogServiceProvider } from '../Modules/Catalog/Infrastructure/Providers/CatalogServiceProvider'
|
|
2033
2554
|
|
|
2555
|
+
/**
|
|
2556
|
+
* Middleware Provider - Global middleware registration
|
|
2557
|
+
*/
|
|
2558
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
2559
|
+
register(_container: Container): void {}
|
|
2560
|
+
|
|
2561
|
+
boot(core: PlanetCore): void {
|
|
2562
|
+
const isDev = process.env.NODE_ENV !== 'production'
|
|
2563
|
+
|
|
2564
|
+
core.adapter.use('*', securityHeaders({
|
|
2565
|
+
contentSecurityPolicy: isDev ? false : undefined,
|
|
2566
|
+
}))
|
|
2567
|
+
|
|
2568
|
+
core.adapter.use('*', bodySizeLimit(10 * 1024 * 1024))
|
|
2569
|
+
|
|
2570
|
+
core.logger.info('\u{1F6E1}\uFE0F Global middleware registered')
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2034
2574
|
export async function registerProviders(core: PlanetCore): Promise<void> {
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
core.register(new CatalogServiceProvider())
|
|
2575
|
+
// Global Providers
|
|
2576
|
+
core.register(new MiddlewareProvider())
|
|
2038
2577
|
|
|
2039
|
-
|
|
2578
|
+
// Module Providers
|
|
2579
|
+
core.register(new OrderingServiceProvider())
|
|
2580
|
+
core.register(new CatalogServiceProvider())
|
|
2581
|
+
|
|
2582
|
+
// Add more providers as needed
|
|
2040
2583
|
}
|
|
2041
2584
|
`;
|
|
2042
2585
|
}
|
|
@@ -2150,6 +2693,10 @@ export class ${name}ServiceProvider extends ServiceProvider {
|
|
|
2150
2693
|
start: "bun run dist/main.js",
|
|
2151
2694
|
test: "bun test",
|
|
2152
2695
|
typecheck: "tsc --noEmit",
|
|
2696
|
+
check: "bun run typecheck && bun run test",
|
|
2697
|
+
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
2698
|
+
validate: "bun run check && bun run check:deps",
|
|
2699
|
+
precommit: "bun run validate",
|
|
2153
2700
|
"docker:build": `docker build -t ${context.nameKebabCase} .`,
|
|
2154
2701
|
"docker:run": `docker run -it -p 3000:3000 ${context.nameKebabCase}`
|
|
2155
2702
|
},
|
|
@@ -2590,6 +3137,16 @@ export function report(error: unknown): void {
|
|
|
2590
3137
|
|
|
2591
3138
|
This project follows **Domain-Driven Design (DDD)** with strategic and tactical patterns.
|
|
2592
3139
|
|
|
3140
|
+
## Service Providers
|
|
3141
|
+
|
|
3142
|
+
Service providers are the central place to configure your application and modules. They follow the ServiceProvider pattern with \`register()\` and \`boot()\` lifecycle methods.
|
|
3143
|
+
|
|
3144
|
+
### Internal Bootstrapping
|
|
3145
|
+
|
|
3146
|
+
1. **Bootstrap/app.ts**: Orchestrates the 4-step lifecycle (Configure, Boot, Register, Bootstrap).
|
|
3147
|
+
2. **Bootstrap/providers.ts**: Central registry for all global and module-specific providers.
|
|
3148
|
+
3. **Infrastructure/Providers/[Module]ServiceProvider.ts**: Module-specific service registration.
|
|
3149
|
+
|
|
2593
3150
|
## Bounded Contexts
|
|
2594
3151
|
|
|
2595
3152
|
\`\`\`
|
|
@@ -2727,6 +3284,11 @@ var EnterpriseMvcGenerator = class extends BaseGenerator {
|
|
|
2727
3284
|
type: "directory",
|
|
2728
3285
|
name: "Providers",
|
|
2729
3286
|
children: [
|
|
3287
|
+
{
|
|
3288
|
+
type: "file",
|
|
3289
|
+
name: "index.ts",
|
|
3290
|
+
content: this.generateProvidersIndex()
|
|
3291
|
+
},
|
|
2730
3292
|
{
|
|
2731
3293
|
type: "file",
|
|
2732
3294
|
name: "AppServiceProvider.ts",
|
|
@@ -2734,8 +3296,18 @@ var EnterpriseMvcGenerator = class extends BaseGenerator {
|
|
|
2734
3296
|
},
|
|
2735
3297
|
{
|
|
2736
3298
|
type: "file",
|
|
2737
|
-
name: "
|
|
2738
|
-
content: this.
|
|
3299
|
+
name: "DatabaseProvider.ts",
|
|
3300
|
+
content: this.generateDatabaseProvider()
|
|
3301
|
+
},
|
|
3302
|
+
{
|
|
3303
|
+
type: "file",
|
|
3304
|
+
name: "MiddlewareProvider.ts",
|
|
3305
|
+
content: this.generateMiddlewareProvider()
|
|
3306
|
+
},
|
|
3307
|
+
{
|
|
3308
|
+
type: "file",
|
|
3309
|
+
name: "RouteProvider.ts",
|
|
3310
|
+
content: this.generateRouteProvider()
|
|
2739
3311
|
}
|
|
2740
3312
|
]
|
|
2741
3313
|
},
|
|
@@ -3202,6 +3774,135 @@ export class RouteServiceProvider extends ServiceProvider {
|
|
|
3202
3774
|
registerRoutes(core.router)
|
|
3203
3775
|
}
|
|
3204
3776
|
}
|
|
3777
|
+
`;
|
|
3778
|
+
}
|
|
3779
|
+
// ─────────────────────────────────────────────────────────────
|
|
3780
|
+
// Modern Provider Generators (ServiceProvider Pattern)
|
|
3781
|
+
// ─────────────────────────────────────────────────────────────
|
|
3782
|
+
generateProvidersIndex() {
|
|
3783
|
+
return `/**
|
|
3784
|
+
* Application Service Providers
|
|
3785
|
+
*
|
|
3786
|
+
* Export all providers for easy importing in bootstrap.
|
|
3787
|
+
* Providers are registered in the order they are listed.
|
|
3788
|
+
*/
|
|
3789
|
+
|
|
3790
|
+
export { AppServiceProvider } from './AppServiceProvider'
|
|
3791
|
+
export { DatabaseProvider } from './DatabaseProvider'
|
|
3792
|
+
export { MiddlewareProvider } from './MiddlewareProvider'
|
|
3793
|
+
export { RouteProvider } from './RouteProvider'
|
|
3794
|
+
`;
|
|
3795
|
+
}
|
|
3796
|
+
generateDatabaseProvider() {
|
|
3797
|
+
return `/**
|
|
3798
|
+
* Database Service Provider
|
|
3799
|
+
*
|
|
3800
|
+
* Handles database initialization and migrations.
|
|
3801
|
+
*
|
|
3802
|
+
* Lifecycle:
|
|
3803
|
+
* - register(): Bind database config to container
|
|
3804
|
+
* - boot(): Run migrations and seeders
|
|
3805
|
+
*/
|
|
3806
|
+
|
|
3807
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
3808
|
+
import databaseConfig from '../../config/database'
|
|
3809
|
+
|
|
3810
|
+
export class DatabaseProvider extends ServiceProvider {
|
|
3811
|
+
/**
|
|
3812
|
+
* Register database configuration.
|
|
3813
|
+
*/
|
|
3814
|
+
register(_container: Container): void {
|
|
3815
|
+
this.mergeConfig(this.core!.config, 'database', databaseConfig)
|
|
3816
|
+
}
|
|
3817
|
+
|
|
3818
|
+
/**
|
|
3819
|
+
* Initialize database connections.
|
|
3820
|
+
*/
|
|
3821
|
+
async boot(core: PlanetCore): Promise<void> {
|
|
3822
|
+
// Database initialization will be handled by Atlas orbit
|
|
3823
|
+
core.logger.info('\u{1F4E6} Database provider booted')
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
`;
|
|
3827
|
+
}
|
|
3828
|
+
generateMiddlewareProvider() {
|
|
3829
|
+
return `/**
|
|
3830
|
+
* Middleware Service Provider
|
|
3831
|
+
*
|
|
3832
|
+
* Registers global middleware stack.
|
|
3833
|
+
* Provides a centralized location for middleware configuration.
|
|
3834
|
+
*
|
|
3835
|
+
* Lifecycle:
|
|
3836
|
+
* - register(): N/A (no container bindings)
|
|
3837
|
+
* - boot(): Register global middleware
|
|
3838
|
+
*/
|
|
3839
|
+
|
|
3840
|
+
import {
|
|
3841
|
+
ServiceProvider,
|
|
3842
|
+
type Container,
|
|
3843
|
+
type PlanetCore,
|
|
3844
|
+
bodySizeLimit,
|
|
3845
|
+
securityHeaders,
|
|
3846
|
+
} from '@gravito/core'
|
|
3847
|
+
|
|
3848
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
3849
|
+
/**
|
|
3850
|
+
* No container bindings needed.
|
|
3851
|
+
*/
|
|
3852
|
+
register(_container: Container): void {
|
|
3853
|
+
// Middleware doesn't require container bindings
|
|
3854
|
+
}
|
|
3855
|
+
|
|
3856
|
+
/**
|
|
3857
|
+
* Register global middleware stack.
|
|
3858
|
+
*/
|
|
3859
|
+
boot(core: PlanetCore): void {
|
|
3860
|
+
const isDev = process.env.NODE_ENV !== 'production'
|
|
3861
|
+
|
|
3862
|
+
// Security Headers
|
|
3863
|
+
core.adapter.use('*', securityHeaders({
|
|
3864
|
+
contentSecurityPolicy: isDev ? false : undefined,
|
|
3865
|
+
}))
|
|
3866
|
+
|
|
3867
|
+
// Body Parser Limits
|
|
3868
|
+
core.adapter.use('*', bodySizeLimit(10 * 1024 * 1024)) // 10MB limit
|
|
3869
|
+
|
|
3870
|
+
core.logger.info('\u{1F6E1}\uFE0F Middleware registered')
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
`;
|
|
3874
|
+
}
|
|
3875
|
+
generateRouteProvider() {
|
|
3876
|
+
return `/**
|
|
3877
|
+
* Route Service Provider
|
|
3878
|
+
*
|
|
3879
|
+
* Registers application routes.
|
|
3880
|
+
* Routes are registered in the boot phase after all services are available.
|
|
3881
|
+
*
|
|
3882
|
+
* Lifecycle:
|
|
3883
|
+
* - register(): N/A
|
|
3884
|
+
* - boot(): Register routes
|
|
3885
|
+
*/
|
|
3886
|
+
|
|
3887
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
3888
|
+
import { registerRoutes } from '../routes'
|
|
3889
|
+
|
|
3890
|
+
export class RouteProvider extends ServiceProvider {
|
|
3891
|
+
/**
|
|
3892
|
+
* No container bindings needed.
|
|
3893
|
+
*/
|
|
3894
|
+
register(_container: Container): void {
|
|
3895
|
+
// Routes don't require container bindings
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3898
|
+
/**
|
|
3899
|
+
* Register application routes.
|
|
3900
|
+
*/
|
|
3901
|
+
boot(core: PlanetCore): void {
|
|
3902
|
+
registerRoutes(core.router)
|
|
3903
|
+
core.logger.info('\u{1F6E4}\uFE0F Routes registered')
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3205
3906
|
`;
|
|
3206
3907
|
}
|
|
3207
3908
|
generateExceptionHandler() {
|
|
@@ -3250,74 +3951,75 @@ export const dontReport: string[] = [
|
|
|
3250
3951
|
}
|
|
3251
3952
|
generateBootstrap(context) {
|
|
3252
3953
|
const spectrumImport = context.withSpectrum ? "import { SpectrumOrbit } from '@gravito/spectrum'\n" : "";
|
|
3253
|
-
const spectrumOrbit = context.withSpectrum ?
|
|
3254
|
-
// Enable Debug Dashboard
|
|
3255
|
-
if (process.env.APP_DEBUG === 'true') {
|
|
3256
|
-
await core.orbit(new SpectrumOrbit())
|
|
3257
|
-
}
|
|
3258
|
-
` : "";
|
|
3954
|
+
const spectrumOrbit = context.withSpectrum ? " new SpectrumOrbit()," : "";
|
|
3259
3955
|
return `/**
|
|
3260
3956
|
* Application Bootstrap
|
|
3261
3957
|
*
|
|
3262
|
-
*
|
|
3263
|
-
*
|
|
3958
|
+
* The entry point for your Gravito application.
|
|
3959
|
+
* Uses the ServiceProvider pattern for modular, maintainable initialization.
|
|
3960
|
+
*
|
|
3961
|
+
* Lifecycle:
|
|
3962
|
+
* 1. Configure: Load app config and orbits
|
|
3963
|
+
* 2. Boot: Initialize PlanetCore
|
|
3964
|
+
* 3. Register Providers: Bind services to container
|
|
3965
|
+
* 4. Bootstrap: Boot all providers
|
|
3966
|
+
*
|
|
3967
|
+
* @module bootstrap
|
|
3264
3968
|
*/
|
|
3265
3969
|
|
|
3266
|
-
import {
|
|
3970
|
+
import { defineConfig, PlanetCore } from '@gravito/core'
|
|
3267
3971
|
import { OrbitAtlas } from '@gravito/atlas'
|
|
3268
|
-
import
|
|
3269
|
-
${spectrumImport}import {
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
// Create application core
|
|
3276
|
-
const core = new PlanetCore({
|
|
3277
|
-
config: {
|
|
3278
|
-
APP_NAME: process.env.APP_NAME ?? '${context.name}',
|
|
3279
|
-
database: databaseConfig,
|
|
3280
|
-
},
|
|
3281
|
-
})
|
|
3282
|
-
const defaultCsp = [
|
|
3283
|
-
"default-src 'self'",
|
|
3284
|
-
"script-src 'self' 'unsafe-inline'",
|
|
3285
|
-
"style-src 'self' 'unsafe-inline'",
|
|
3286
|
-
"img-src 'self' data:",
|
|
3287
|
-
"object-src 'none'",
|
|
3288
|
-
"base-uri 'self'",
|
|
3289
|
-
"frame-ancestors 'none'",
|
|
3290
|
-
].join('; ')
|
|
3291
|
-
const cspValue = process.env.APP_CSP
|
|
3292
|
-
const csp = cspValue === 'false' ? false : (cspValue ?? defaultCsp)
|
|
3293
|
-
const hstsMaxAge = Number.parseInt(process.env.APP_HSTS_MAX_AGE ?? '15552000', 10)
|
|
3294
|
-
const bodyLimit = Number.parseInt(process.env.APP_BODY_LIMIT ?? '1048576', 10)
|
|
3295
|
-
const requireLength = process.env.APP_BODY_REQUIRE_LENGTH === 'true'
|
|
3296
|
-
|
|
3297
|
-
core.adapter.use(
|
|
3298
|
-
'*',
|
|
3299
|
-
securityHeaders({
|
|
3300
|
-
contentSecurityPolicy: csp,
|
|
3301
|
-
hsts:
|
|
3302
|
-
process.env.NODE_ENV === 'production'
|
|
3303
|
-
? { maxAge: Number.isNaN(hstsMaxAge) ? 15552000 : hstsMaxAge, includeSubDomains: true }
|
|
3304
|
-
: false,
|
|
3305
|
-
})
|
|
3306
|
-
)
|
|
3307
|
-
if (!Number.isNaN(bodyLimit) && bodyLimit > 0) {
|
|
3308
|
-
core.adapter.use('*', bodySizeLimit(bodyLimit, { requireContentLength: requireLength }))
|
|
3309
|
-
}
|
|
3972
|
+
import appConfig from '../config/app'
|
|
3973
|
+
${spectrumImport}import {
|
|
3974
|
+
AppServiceProvider,
|
|
3975
|
+
DatabaseProvider,
|
|
3976
|
+
MiddlewareProvider,
|
|
3977
|
+
RouteProvider,
|
|
3978
|
+
} from './Providers'
|
|
3310
3979
|
|
|
3311
|
-
|
|
3980
|
+
/**
|
|
3981
|
+
* Bootstrap the application with service providers.
|
|
3982
|
+
*
|
|
3983
|
+
* @returns The booted PlanetCore instance
|
|
3984
|
+
*/
|
|
3985
|
+
export async function bootstrap() {
|
|
3986
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3987
|
+
// 1. Configure
|
|
3988
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3989
|
+
const config = defineConfig({
|
|
3990
|
+
config: appConfig,
|
|
3991
|
+
orbits: [
|
|
3992
|
+
new OrbitAtlas(),
|
|
3312
3993
|
${spectrumOrbit}
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
core.register(new RouteServiceProvider())
|
|
3994
|
+
],
|
|
3995
|
+
})
|
|
3316
3996
|
|
|
3317
|
-
//
|
|
3318
|
-
|
|
3997
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3998
|
+
// 2. Boot Core
|
|
3999
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4000
|
+
const core = await PlanetCore.boot(config)
|
|
4001
|
+
core.registerGlobalErrorHandlers()
|
|
4002
|
+
|
|
4003
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4004
|
+
// 3. Register Providers
|
|
4005
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4006
|
+
core.register(new AppServiceProvider())
|
|
4007
|
+
core.register(new DatabaseProvider())
|
|
4008
|
+
core.register(new MiddlewareProvider())
|
|
4009
|
+
core.register(new RouteProvider())
|
|
4010
|
+
|
|
4011
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4012
|
+
// 4. Bootstrap All Providers
|
|
4013
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4014
|
+
await core.bootstrap()
|
|
4015
|
+
|
|
4016
|
+
return core
|
|
4017
|
+
}
|
|
3319
4018
|
|
|
3320
|
-
//
|
|
4019
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4020
|
+
// Application Entry Point
|
|
4021
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4022
|
+
const core = await bootstrap()
|
|
3321
4023
|
export default core.liftoff()
|
|
3322
4024
|
`;
|
|
3323
4025
|
}
|
|
@@ -3744,7 +4446,9 @@ export class ${name}ServiceProvider extends ServiceProvider {
|
|
|
3744
4446
|
scripts: {
|
|
3745
4447
|
build: "tsup src/index.ts --format cjs,esm --dts",
|
|
3746
4448
|
test: "bun test",
|
|
3747
|
-
typecheck: "tsc --noEmit"
|
|
4449
|
+
typecheck: "tsc --noEmit",
|
|
4450
|
+
check: "bun run typecheck && bun run test",
|
|
4451
|
+
validate: "bun run check"
|
|
3748
4452
|
},
|
|
3749
4453
|
dependencies: {
|
|
3750
4454
|
"@gravito/core": depVersion,
|
|
@@ -4042,10 +4746,25 @@ var ActionDomainGenerator = class extends BaseGenerator {
|
|
|
4042
4746
|
type: "directory",
|
|
4043
4747
|
name: "providers",
|
|
4044
4748
|
children: [
|
|
4749
|
+
{
|
|
4750
|
+
type: "file",
|
|
4751
|
+
name: "index.ts",
|
|
4752
|
+
content: this.generateProvidersIndex()
|
|
4753
|
+
},
|
|
4045
4754
|
{
|
|
4046
4755
|
type: "file",
|
|
4047
4756
|
name: "AppServiceProvider.ts",
|
|
4048
4757
|
content: this.generateAppServiceProvider(context)
|
|
4758
|
+
},
|
|
4759
|
+
{
|
|
4760
|
+
type: "file",
|
|
4761
|
+
name: "MiddlewareProvider.ts",
|
|
4762
|
+
content: this.generateMiddlewareProvider()
|
|
4763
|
+
},
|
|
4764
|
+
{
|
|
4765
|
+
type: "file",
|
|
4766
|
+
name: "RouteProvider.ts",
|
|
4767
|
+
content: this.generateRouteProvider()
|
|
4049
4768
|
}
|
|
4050
4769
|
]
|
|
4051
4770
|
},
|
|
@@ -4223,7 +4942,7 @@ export function registerApiRoutes(router: Router) {
|
|
|
4223
4942
|
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
4224
4943
|
|
|
4225
4944
|
export class AppServiceProvider extends ServiceProvider {
|
|
4226
|
-
register(
|
|
4945
|
+
register(_container: Container): void {
|
|
4227
4946
|
// Register global services here
|
|
4228
4947
|
}
|
|
4229
4948
|
|
|
@@ -4233,47 +4952,140 @@ export class AppServiceProvider extends ServiceProvider {
|
|
|
4233
4952
|
}
|
|
4234
4953
|
`;
|
|
4235
4954
|
}
|
|
4236
|
-
|
|
4955
|
+
generateProvidersIndex() {
|
|
4237
4956
|
return `/**
|
|
4238
|
-
* Application
|
|
4957
|
+
* Application Service Providers
|
|
4239
4958
|
*/
|
|
4240
4959
|
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
APP_NAME: '${context.name}',
|
|
4251
|
-
database: databaseConfig
|
|
4252
|
-
},
|
|
4253
|
-
})
|
|
4960
|
+
export { AppServiceProvider } from './AppServiceProvider'
|
|
4961
|
+
export { MiddlewareProvider } from './MiddlewareProvider'
|
|
4962
|
+
export { RouteProvider } from './RouteProvider'
|
|
4963
|
+
`;
|
|
4964
|
+
}
|
|
4965
|
+
generateMiddlewareProvider() {
|
|
4966
|
+
return `/**
|
|
4967
|
+
* Middleware Service Provider
|
|
4968
|
+
*/
|
|
4254
4969
|
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4970
|
+
import {
|
|
4971
|
+
ServiceProvider,
|
|
4972
|
+
type Container,
|
|
4973
|
+
type PlanetCore,
|
|
4974
|
+
bodySizeLimit,
|
|
4975
|
+
securityHeaders,
|
|
4976
|
+
} from '@gravito/core'
|
|
4258
4977
|
|
|
4259
|
-
|
|
4260
|
-
|
|
4978
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
4979
|
+
register(_container: Container): void {}
|
|
4261
4980
|
|
|
4262
|
-
|
|
4263
|
-
core.
|
|
4981
|
+
boot(core: PlanetCore): void {
|
|
4982
|
+
core.adapter.use('*', securityHeaders())
|
|
4983
|
+
core.adapter.use('*', bodySizeLimit(1024 * 1024))
|
|
4984
|
+
core.logger.info('\u{1F6E1}\uFE0F Middleware registered')
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
`;
|
|
4988
|
+
}
|
|
4989
|
+
generateRouteProvider() {
|
|
4990
|
+
return `/**
|
|
4991
|
+
* Route Service Provider
|
|
4992
|
+
*/
|
|
4264
4993
|
|
|
4265
|
-
|
|
4266
|
-
|
|
4994
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
4995
|
+
import { registerApiRoutes } from '../routes/api'
|
|
4267
4996
|
|
|
4268
|
-
|
|
4269
|
-
|
|
4997
|
+
export class RouteProvider extends ServiceProvider {
|
|
4998
|
+
register(_container: Container): void {}
|
|
4270
4999
|
|
|
4271
|
-
|
|
5000
|
+
boot(core: PlanetCore): void {
|
|
5001
|
+
registerApiRoutes(core.router)
|
|
5002
|
+
core.logger.info('\u{1F6E4}\uFE0F Routes registered')
|
|
5003
|
+
}
|
|
5004
|
+
}
|
|
5005
|
+
`;
|
|
5006
|
+
}
|
|
5007
|
+
generateBootstrap(_context) {
|
|
5008
|
+
return `/**
|
|
5009
|
+
* Application Bootstrap
|
|
5010
|
+
*
|
|
5011
|
+
* Uses the ServiceProvider pattern for modular initialization.
|
|
5012
|
+
*/
|
|
5013
|
+
|
|
5014
|
+
import { defineConfig, PlanetCore } from '@gravito/core'
|
|
5015
|
+
import { OrbitAtlas } from '@gravito/atlas'
|
|
5016
|
+
import appConfig from '../config/app'
|
|
5017
|
+
import {
|
|
5018
|
+
AppServiceProvider,
|
|
5019
|
+
MiddlewareProvider,
|
|
5020
|
+
RouteProvider,
|
|
5021
|
+
} from './providers'
|
|
5022
|
+
|
|
5023
|
+
export async function bootstrap() {
|
|
5024
|
+
const config = defineConfig({
|
|
5025
|
+
config: appConfig,
|
|
5026
|
+
orbits: [new OrbitAtlas()],
|
|
5027
|
+
})
|
|
5028
|
+
|
|
5029
|
+
const core = await PlanetCore.boot(config)
|
|
5030
|
+
core.registerGlobalErrorHandlers()
|
|
5031
|
+
|
|
5032
|
+
core.register(new AppServiceProvider())
|
|
5033
|
+
core.register(new MiddlewareProvider())
|
|
5034
|
+
core.register(new RouteProvider())
|
|
5035
|
+
|
|
5036
|
+
await core.bootstrap()
|
|
5037
|
+
|
|
5038
|
+
return core
|
|
5039
|
+
}
|
|
5040
|
+
|
|
5041
|
+
const core = await bootstrap()
|
|
4272
5042
|
export default core.liftoff()
|
|
4273
5043
|
`;
|
|
4274
5044
|
}
|
|
4275
5045
|
generateArchitectureDoc(context) {
|
|
4276
|
-
return
|
|
5046
|
+
return `# ${context.name} - Action Domain Architecture
|
|
5047
|
+
|
|
5048
|
+
## Overview
|
|
5049
|
+
|
|
5050
|
+
This project uses the **Action Domain** pattern, designed for high-clarity API implementations.
|
|
5051
|
+
|
|
5052
|
+
## Service Providers
|
|
5053
|
+
|
|
5054
|
+
Service providers are the central place to configure your application. They follow the ServiceProvider pattern with \`register()\` and \`boot()\` lifecycle methods.
|
|
5055
|
+
|
|
5056
|
+
## Directory Structure
|
|
5057
|
+
|
|
5058
|
+
\`\`\`
|
|
5059
|
+
src/
|
|
5060
|
+
\u251C\u2500\u2500 actions/ # Single Responsibility Business Logic
|
|
5061
|
+
\u2502 \u251C\u2500\u2500 Action.ts # Base Action class
|
|
5062
|
+
\u2502 \u2514\u2500\u2500 [Domain]/ # Domain-specific actions
|
|
5063
|
+
\u251C\u2500\u2500 controllers/ # HTTP Request Handlers
|
|
5064
|
+
\u2502 \u2514\u2500\u2500 api/v1/ # API Controllers
|
|
5065
|
+
\u251C\u2500\u2500 types/ # TypeScript Definitions
|
|
5066
|
+
\u251C\u2500\u2500 repositories/ # Data Access Layer
|
|
5067
|
+
\u251C\u2500\u2500 routes/ # Route Definitions
|
|
5068
|
+
\u251C\u2500\u2500 providers/ # Service Providers
|
|
5069
|
+
\u2514\u2500\u2500 config/ # Configuration
|
|
5070
|
+
\`\`\`
|
|
5071
|
+
|
|
5072
|
+
## Core Concepts
|
|
5073
|
+
|
|
5074
|
+
### Actions
|
|
5075
|
+
Every business operation is an "Action". An action:
|
|
5076
|
+
- Does ONE thing.
|
|
5077
|
+
- Takes specific input.
|
|
5078
|
+
- Returns specific output.
|
|
5079
|
+
- Is framework-agnostic (ideally).
|
|
5080
|
+
|
|
5081
|
+
### Controllers
|
|
5082
|
+
Controllers are thin. They:
|
|
5083
|
+
1. Parse the request.
|
|
5084
|
+
2. Instantiate/Call the Action.
|
|
5085
|
+
3. Return the response.
|
|
5086
|
+
|
|
5087
|
+
Created with \u2764\uFE0F using Gravito Framework
|
|
5088
|
+
`;
|
|
4277
5089
|
}
|
|
4278
5090
|
generatePackageJson(context) {
|
|
4279
5091
|
const pkg = {
|
|
@@ -4285,7 +5097,11 @@ export default core.liftoff()
|
|
|
4285
5097
|
build: "bun build ./src/bootstrap.ts --outdir ./dist --target bun",
|
|
4286
5098
|
start: "bun run dist/bootstrap.js",
|
|
4287
5099
|
test: "bun test",
|
|
4288
|
-
typecheck: "tsc --noEmit"
|
|
5100
|
+
typecheck: "tsc --noEmit",
|
|
5101
|
+
check: "bun run typecheck && bun run test",
|
|
5102
|
+
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
5103
|
+
validate: "bun run check && bun run check:deps",
|
|
5104
|
+
precommit: "bun run validate"
|
|
4289
5105
|
},
|
|
4290
5106
|
dependencies: {
|
|
4291
5107
|
"@gravito/core": "workspace:*",
|
|
@@ -4302,6 +5118,115 @@ export default core.liftoff()
|
|
|
4302
5118
|
}
|
|
4303
5119
|
};
|
|
4304
5120
|
|
|
5121
|
+
// src/generators/StandaloneEngineGenerator.ts
|
|
5122
|
+
var StandaloneEngineGenerator = class extends BaseGenerator {
|
|
5123
|
+
get architectureType() {
|
|
5124
|
+
return "standalone-engine";
|
|
5125
|
+
}
|
|
5126
|
+
get displayName() {
|
|
5127
|
+
return "Standalone Engine";
|
|
5128
|
+
}
|
|
5129
|
+
get description() {
|
|
5130
|
+
return "High-performance pure Gravito Engine (minimal)";
|
|
5131
|
+
}
|
|
5132
|
+
getDirectoryStructure(context) {
|
|
5133
|
+
return [
|
|
5134
|
+
{
|
|
5135
|
+
type: "directory",
|
|
5136
|
+
name: "src",
|
|
5137
|
+
children: [
|
|
5138
|
+
{
|
|
5139
|
+
type: "file",
|
|
5140
|
+
name: "index.ts",
|
|
5141
|
+
content: this.getIndexContent()
|
|
5142
|
+
}
|
|
5143
|
+
]
|
|
5144
|
+
},
|
|
5145
|
+
{
|
|
5146
|
+
type: "file",
|
|
5147
|
+
name: "README.md",
|
|
5148
|
+
content: this.getReadmeContent(context)
|
|
5149
|
+
}
|
|
5150
|
+
];
|
|
5151
|
+
}
|
|
5152
|
+
async generateCommonFiles(context) {
|
|
5153
|
+
await this.writeFile(context.targetDir, "package.json", this.generatePackageJson(context));
|
|
5154
|
+
await this.writeFile(context.targetDir, "tsconfig.json", this.generateTsConfig());
|
|
5155
|
+
await this.writeFile(context.targetDir, ".gitignore", this.generateGitignore());
|
|
5156
|
+
}
|
|
5157
|
+
generatePackageJson(context) {
|
|
5158
|
+
const pkg = {
|
|
5159
|
+
name: context.nameKebabCase,
|
|
5160
|
+
version: "0.1.0",
|
|
5161
|
+
type: "module",
|
|
5162
|
+
scripts: {
|
|
5163
|
+
dev: "bun run --watch src/index.ts",
|
|
5164
|
+
build: "bun build ./src/index.ts --outdir ./dist --target bun",
|
|
5165
|
+
start: "bun run dist/index.js",
|
|
5166
|
+
test: "bun test"
|
|
5167
|
+
},
|
|
5168
|
+
dependencies: {
|
|
5169
|
+
"@gravito/core": "^1.1.0"
|
|
5170
|
+
},
|
|
5171
|
+
devDependencies: {
|
|
5172
|
+
"bun-types": "latest",
|
|
5173
|
+
typescript: "^5.0.0"
|
|
5174
|
+
}
|
|
5175
|
+
};
|
|
5176
|
+
return JSON.stringify(pkg, null, 2);
|
|
5177
|
+
}
|
|
5178
|
+
generateArchitectureDoc(_context) {
|
|
5179
|
+
return "";
|
|
5180
|
+
}
|
|
5181
|
+
getIndexContent() {
|
|
5182
|
+
return `import { Gravito } from '@gravito/core/engine'
|
|
5183
|
+
|
|
5184
|
+
const app = new Gravito()
|
|
5185
|
+
|
|
5186
|
+
// Basic Route
|
|
5187
|
+
app.get('/', (c) => c.text('Hello Gravito Engine!'))
|
|
5188
|
+
|
|
5189
|
+
// JSON Response
|
|
5190
|
+
app.get('/json', (c) => c.json({ message: 'High Performance' }))
|
|
5191
|
+
|
|
5192
|
+
// Path Parameters
|
|
5193
|
+
app.get('/user/:name', (c) => {
|
|
5194
|
+
const name = c.req.param('name')
|
|
5195
|
+
return c.text(\`Hello \${name}\`)
|
|
5196
|
+
})
|
|
5197
|
+
|
|
5198
|
+
export default app
|
|
5199
|
+
`;
|
|
5200
|
+
}
|
|
5201
|
+
getReadmeContent(context) {
|
|
5202
|
+
return `# ${context.name}
|
|
5203
|
+
|
|
5204
|
+
A high-performance web application powered by Gravito Engine.
|
|
5205
|
+
|
|
5206
|
+
## Getting Started
|
|
5207
|
+
|
|
5208
|
+
### Install Dependencies
|
|
5209
|
+
|
|
5210
|
+
\`\`\`bash
|
|
5211
|
+
bun install
|
|
5212
|
+
\`\`\`
|
|
5213
|
+
|
|
5214
|
+
### Run Development Server
|
|
5215
|
+
|
|
5216
|
+
\`\`\`bash
|
|
5217
|
+
bun run dev
|
|
5218
|
+
\`\`\`
|
|
5219
|
+
|
|
5220
|
+
### Production Build
|
|
5221
|
+
|
|
5222
|
+
\`\`\`bash
|
|
5223
|
+
bun run build
|
|
5224
|
+
bun start
|
|
5225
|
+
\`\`\`
|
|
5226
|
+
`;
|
|
5227
|
+
}
|
|
5228
|
+
};
|
|
5229
|
+
|
|
4305
5230
|
// src/Scaffold.ts
|
|
4306
5231
|
var Scaffold = class {
|
|
4307
5232
|
templatesDir;
|
|
@@ -4335,6 +5260,11 @@ var Scaffold = class {
|
|
|
4335
5260
|
name: "Action Domain",
|
|
4336
5261
|
description: "Single Action Controllers pattern for high-clarity APIs"
|
|
4337
5262
|
},
|
|
5263
|
+
{
|
|
5264
|
+
type: "standalone-engine",
|
|
5265
|
+
name: "Standalone Engine",
|
|
5266
|
+
description: "High-performance pure Gravito Engine (minimal)"
|
|
5267
|
+
},
|
|
4338
5268
|
{
|
|
4339
5269
|
type: "satellite",
|
|
4340
5270
|
name: "Gravito Satellite",
|
|
@@ -4410,6 +5340,8 @@ var Scaffold = class {
|
|
|
4410
5340
|
return new ActionDomainGenerator(config);
|
|
4411
5341
|
case "satellite":
|
|
4412
5342
|
return new SatelliteGenerator(config);
|
|
5343
|
+
case "standalone-engine":
|
|
5344
|
+
return new StandaloneEngineGenerator(config);
|
|
4413
5345
|
default:
|
|
4414
5346
|
throw new Error(`Unknown architecture type: ${type}`);
|
|
4415
5347
|
}
|