@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.js
CHANGED
|
@@ -346,6 +346,31 @@ var BaseGenerator = class {
|
|
|
346
346
|
"ARCHITECTURE.md",
|
|
347
347
|
this.generateArchitectureDoc(context)
|
|
348
348
|
);
|
|
349
|
+
await this.generateCheckScripts(context);
|
|
350
|
+
await this.generateSkills(context);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Copy AI Skills to the project
|
|
354
|
+
*/
|
|
355
|
+
async generateSkills(context) {
|
|
356
|
+
const skillsDir = path2.resolve(this.config.templatesDir, "skills");
|
|
357
|
+
const targetSkillsDir = path2.join(".skills");
|
|
358
|
+
try {
|
|
359
|
+
await fs2.access(skillsDir);
|
|
360
|
+
} catch {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const files = await walk(skillsDir);
|
|
364
|
+
for (const filePath of files) {
|
|
365
|
+
const relativePath = path2.relative(skillsDir, filePath);
|
|
366
|
+
const targetPath = path2.join(targetSkillsDir, relativePath);
|
|
367
|
+
let content = await fs2.readFile(filePath, "utf-8");
|
|
368
|
+
try {
|
|
369
|
+
content = this.stubGenerator.render(content, context);
|
|
370
|
+
} catch {
|
|
371
|
+
}
|
|
372
|
+
await this.writeFile(context.targetDir, targetPath, content);
|
|
373
|
+
}
|
|
349
374
|
}
|
|
350
375
|
/**
|
|
351
376
|
* Apply profile-specific overlays
|
|
@@ -433,6 +458,10 @@ var BaseGenerator = class {
|
|
|
433
458
|
start: "bun run dist/bootstrap.js",
|
|
434
459
|
test: "bun test",
|
|
435
460
|
typecheck: "tsc --noEmit",
|
|
461
|
+
check: "bun run typecheck && bun run test",
|
|
462
|
+
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
463
|
+
validate: "bun run check && bun run check:deps",
|
|
464
|
+
precommit: "bun run validate",
|
|
436
465
|
"docker:build": `docker build -t ${context.nameKebabCase} .`,
|
|
437
466
|
"docker:run": `docker run -it -p 3000:3000 ${context.nameKebabCase}`
|
|
438
467
|
},
|
|
@@ -685,6 +714,430 @@ coverage/
|
|
|
685
714
|
};
|
|
686
715
|
return JSON.stringify(config, null, 2);
|
|
687
716
|
}
|
|
717
|
+
/**
|
|
718
|
+
* Generate check scripts for project validation.
|
|
719
|
+
*/
|
|
720
|
+
async generateCheckScripts(context) {
|
|
721
|
+
const scriptsDir = path2.resolve(context.targetDir, "scripts");
|
|
722
|
+
await fs2.mkdir(scriptsDir, { recursive: true });
|
|
723
|
+
await this.writeFile(
|
|
724
|
+
scriptsDir,
|
|
725
|
+
"check-dependencies.ts",
|
|
726
|
+
this.generateCheckDependenciesScript()
|
|
727
|
+
);
|
|
728
|
+
await this.writeFile(scriptsDir, "check.sh", this.generateCheckShellScript());
|
|
729
|
+
await this.writeFile(scriptsDir, "pre-commit.sh", this.generatePreCommitScript());
|
|
730
|
+
await this.writeFile(context.targetDir, "CHECK_SYSTEM.md", this.generateCheckSystemDoc(context));
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Generate check-dependencies.ts script content.
|
|
734
|
+
*/
|
|
735
|
+
generateCheckDependenciesScript() {
|
|
736
|
+
return `/**
|
|
737
|
+
* \u76F8\u4F9D\u5957\u4EF6\u7248\u672C\u6AA2\u67E5\u8173\u672C
|
|
738
|
+
*
|
|
739
|
+
* \u6AA2\u67E5 package.json \u4E2D\u7684\u5957\u4EF6\u662F\u5426\u70BA\u6700\u65B0\u7A69\u5B9A\u7248\u672C
|
|
740
|
+
* \u4E26\u63D0\u4F9B\u66F4\u65B0\u5EFA\u8B70
|
|
741
|
+
*/
|
|
742
|
+
|
|
743
|
+
import { readFileSync } from 'fs'
|
|
744
|
+
import { join } from 'path'
|
|
745
|
+
|
|
746
|
+
interface PackageJson {
|
|
747
|
+
dependencies?: Record<string, string>
|
|
748
|
+
devDependencies?: Record<string, string>
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
interface PackageInfo {
|
|
752
|
+
name: string
|
|
753
|
+
current: string
|
|
754
|
+
latest: string
|
|
755
|
+
outdated: boolean
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const colors = {
|
|
759
|
+
reset: '\\x1b[0m',
|
|
760
|
+
green: '\\x1b[32m',
|
|
761
|
+
yellow: '\\x1b[33m',
|
|
762
|
+
red: '\\x1b[31m',
|
|
763
|
+
blue: '\\x1b[36m',
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
function log(message: string, color: keyof typeof colors = 'reset') {
|
|
767
|
+
console.log(\`\${colors[color]}\${message}\${colors.reset}\`)
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
async function getLatestVersion(packageName: string): Promise<string | null> {
|
|
771
|
+
try {
|
|
772
|
+
const response = await fetch(\`https://registry.npmjs.org/\${packageName}/latest\`)
|
|
773
|
+
if (!response.ok) return null
|
|
774
|
+
const data = await response.json()
|
|
775
|
+
return data.version
|
|
776
|
+
} catch {
|
|
777
|
+
return null
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function parseVersion(version: string): string {
|
|
782
|
+
// \u79FB\u9664 ^, ~, >= \u7B49\u524D\u7DB4
|
|
783
|
+
return version.replace(/^[\\^~>=<]/, '')
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
async function checkPackage(
|
|
787
|
+
name: string,
|
|
788
|
+
currentVersion: string
|
|
789
|
+
): Promise<PackageInfo | null> {
|
|
790
|
+
// \u8DF3\u904E\u672C\u5730\u9023\u7D50\u7684\u5957\u4EF6
|
|
791
|
+
if (currentVersion.startsWith('link:') || currentVersion.startsWith('workspace:')) {
|
|
792
|
+
return null
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const current = parseVersion(currentVersion)
|
|
796
|
+
const latest = await getLatestVersion(name)
|
|
797
|
+
|
|
798
|
+
if (!latest) {
|
|
799
|
+
return null
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
return {
|
|
803
|
+
name,
|
|
804
|
+
current,
|
|
805
|
+
latest,
|
|
806
|
+
outdated: current !== latest,
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
async function main() {
|
|
811
|
+
log('\\n=== \u76F8\u4F9D\u5957\u4EF6\u7248\u672C\u6AA2\u67E5 ===\\n', 'blue')
|
|
812
|
+
|
|
813
|
+
const packageJsonPath = join(process.cwd(), 'package.json')
|
|
814
|
+
const packageJson: PackageJson = JSON.parse(
|
|
815
|
+
readFileSync(packageJsonPath, 'utf-8')
|
|
816
|
+
)
|
|
817
|
+
|
|
818
|
+
const allDependencies = {
|
|
819
|
+
...packageJson.dependencies,
|
|
820
|
+
...packageJson.devDependencies,
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
log(\`\u6AA2\u67E5 \${Object.keys(allDependencies).length} \u500B\u5957\u4EF6...\\n\`, 'yellow')
|
|
824
|
+
|
|
825
|
+
const results: PackageInfo[] = []
|
|
826
|
+
const outdated: PackageInfo[] = []
|
|
827
|
+
const upToDate: PackageInfo[] = []
|
|
828
|
+
|
|
829
|
+
// \u6AA2\u67E5\u6240\u6709\u5957\u4EF6
|
|
830
|
+
for (const [name, version] of Object.entries(allDependencies)) {
|
|
831
|
+
const info = await checkPackage(name, version)
|
|
832
|
+
if (info) {
|
|
833
|
+
results.push(info)
|
|
834
|
+
if (info.outdated) {
|
|
835
|
+
outdated.push(info)
|
|
836
|
+
} else {
|
|
837
|
+
upToDate.push(info)
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// \u986F\u793A\u7D50\u679C
|
|
843
|
+
if (upToDate.length > 0) {
|
|
844
|
+
log(\`\\n\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C (\${upToDate.length}):\`, 'green')
|
|
845
|
+
upToDate.forEach((pkg) => {
|
|
846
|
+
log(\` \${pkg.name}: \${pkg.current}\`, 'green')
|
|
847
|
+
})
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (outdated.length > 0) {
|
|
851
|
+
log(\`\\n\u26A0 \u9700\u8981\u66F4\u65B0 (\${outdated.length}):\`, 'yellow')
|
|
852
|
+
outdated.forEach((pkg) => {
|
|
853
|
+
log(\` \${pkg.name}: \${pkg.current} \u2192 \${pkg.latest}\`, 'yellow')
|
|
854
|
+
})
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// \u7E3D\u7D50
|
|
858
|
+
log('\\n=== \u6AA2\u67E5\u7D50\u679C ===', 'blue')
|
|
859
|
+
log(\`\u7E3D\u8A08: \${results.length} \u500B\u5957\u4EF6\`, 'blue')
|
|
860
|
+
log(\`\u6700\u65B0: \${upToDate.length} \u500B\`, 'green')
|
|
861
|
+
log(\`\u9700\u66F4\u65B0: \${outdated.length} \u500B\`, outdated.length > 0 ? 'yellow' : 'green')
|
|
862
|
+
|
|
863
|
+
// \u5982\u679C\u6709\u9700\u8981\u66F4\u65B0\u7684\u5957\u4EF6\uFF0C\u8FD4\u56DE\u975E\u96F6\u9000\u51FA\u78BC
|
|
864
|
+
if (outdated.length > 0) {
|
|
865
|
+
log('\\n\u5EFA\u8B70\u57F7\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0\u5957\u4EF6\uFF1A', 'yellow')
|
|
866
|
+
log(' bun update', 'yellow')
|
|
867
|
+
process.exit(1)
|
|
868
|
+
} else {
|
|
869
|
+
log('\\n\u2713 \u6240\u6709\u5957\u4EF6\u90FD\u662F\u6700\u65B0\u7248\u672C\uFF01', 'green')
|
|
870
|
+
process.exit(0)
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
main().catch((error) => {
|
|
875
|
+
log(\`\\n\u932F\u8AA4: \${error.message}\`, 'red')
|
|
876
|
+
process.exit(1)
|
|
877
|
+
})
|
|
878
|
+
`;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Generate check.sh script content.
|
|
882
|
+
*/
|
|
883
|
+
generateCheckShellScript() {
|
|
884
|
+
return `#!/bin/bash
|
|
885
|
+
|
|
886
|
+
# \u5C08\u6848\u6AA2\u67E5\u8173\u672C
|
|
887
|
+
# \u57F7\u884C\u6240\u6709\u5FC5\u8981\u7684\u6AA2\u67E5\uFF1A\u985E\u578B\u6AA2\u67E5\u3001\u6E2C\u8A66\u3001\u4F9D\u8CF4\u6AA2\u67E5\u7B49
|
|
888
|
+
|
|
889
|
+
set -e
|
|
890
|
+
|
|
891
|
+
# \u984F\u8272\u5B9A\u7FA9
|
|
892
|
+
GREEN='\\033[0;32m'
|
|
893
|
+
YELLOW='\\033[1;33m'
|
|
894
|
+
RED='\\033[0;31m'
|
|
895
|
+
BLUE='\\033[0;34m'
|
|
896
|
+
NC='\\033[0m' # No Color
|
|
897
|
+
|
|
898
|
+
echo -e "\${BLUE}=== \u5C08\u6848\u6AA2\u67E5 ===\${NC}\\n"
|
|
899
|
+
|
|
900
|
+
# \u6AA2\u67E5\u662F\u5426\u5728\u6B63\u78BA\u7684\u76EE\u9304
|
|
901
|
+
if [ ! -f "package.json" ]; then
|
|
902
|
+
echo -e "\${RED}\u932F\u8AA4: \u8ACB\u5728\u5C08\u6848\u6839\u76EE\u9304\u57F7\u884C\u6B64\u8173\u672C\${NC}"
|
|
903
|
+
exit 1
|
|
904
|
+
fi
|
|
905
|
+
|
|
906
|
+
# \u6AA2\u67E5 Bun \u662F\u5426\u5B89\u88DD
|
|
907
|
+
if ! command -v bun &> /dev/null; then
|
|
908
|
+
echo -e "\${RED}\u932F\u8AA4: \u672A\u627E\u5230 bun\uFF0C\u8ACB\u5148\u5B89\u88DD Bun\${NC}"
|
|
909
|
+
exit 1
|
|
910
|
+
fi
|
|
911
|
+
|
|
912
|
+
# 1. \u985E\u578B\u6AA2\u67E5
|
|
913
|
+
echo -e "\${YELLOW}[1/3] \u57F7\u884C\u985E\u578B\u6AA2\u67E5...\${NC}"
|
|
914
|
+
if bun run typecheck; then
|
|
915
|
+
echo -e "\${GREEN}\u2713 \u985E\u578B\u6AA2\u67E5\u901A\u904E\${NC}\\n"
|
|
916
|
+
else
|
|
917
|
+
echo -e "\${RED}\u2717 \u985E\u578B\u6AA2\u67E5\u5931\u6557\${NC}"
|
|
918
|
+
exit 1
|
|
919
|
+
fi
|
|
920
|
+
|
|
921
|
+
# 2. \u57F7\u884C\u6E2C\u8A66
|
|
922
|
+
echo -e "\${YELLOW}[2/3] \u57F7\u884C\u6E2C\u8A66...\${NC}"
|
|
923
|
+
if bun test; then
|
|
924
|
+
echo -e "\${GREEN}\u2713 \u6E2C\u8A66\u901A\u904E\${NC}\\n"
|
|
925
|
+
else
|
|
926
|
+
echo -e "\${RED}\u2717 \u6E2C\u8A66\u5931\u6557\${NC}"
|
|
927
|
+
exit 1
|
|
928
|
+
fi
|
|
929
|
+
|
|
930
|
+
# 3. \u6AA2\u67E5\u4F9D\u8CF4\u7248\u672C\uFF08\u53EF\u9078\uFF0C\u56E0\u70BA\u9700\u8981\u7DB2\u8DEF\u9023\u7DDA\uFF09
|
|
931
|
+
echo -e "\${YELLOW}[3/3] \u6AA2\u67E5\u4F9D\u8CF4\u7248\u672C...\${NC}"
|
|
932
|
+
if bun run check:deps; then
|
|
933
|
+
echo -e "\${GREEN}\u2713 \u4F9D\u8CF4\u6AA2\u67E5\u5B8C\u6210\${NC}\\n"
|
|
934
|
+
else
|
|
935
|
+
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"
|
|
936
|
+
fi
|
|
937
|
+
|
|
938
|
+
echo -e "\${GREEN}=== \u6240\u6709\u6AA2\u67E5\u5B8C\u6210 ===\${NC}"
|
|
939
|
+
`;
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* Generate pre-commit.sh script content.
|
|
943
|
+
*/
|
|
944
|
+
generatePreCommitScript() {
|
|
945
|
+
return `#!/bin/bash
|
|
946
|
+
|
|
947
|
+
# Pre-commit Hook
|
|
948
|
+
# \u5728 git commit \u524D\u81EA\u52D5\u57F7\u884C\u6AA2\u67E5
|
|
949
|
+
#
|
|
950
|
+
# \u5B89\u88DD\u65B9\u5F0F\uFF1A
|
|
951
|
+
# ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit
|
|
952
|
+
# \u6216
|
|
953
|
+
# cp scripts/pre-commit.sh .git/hooks/pre-commit
|
|
954
|
+
# chmod +x .git/hooks/pre-commit
|
|
955
|
+
|
|
956
|
+
set -e
|
|
957
|
+
|
|
958
|
+
# \u984F\u8272\u5B9A\u7FA9
|
|
959
|
+
GREEN='\\033[0;32m'
|
|
960
|
+
YELLOW='\\033[1;33m'
|
|
961
|
+
RED='\\033[0;31m'
|
|
962
|
+
BLUE='\\033[0;34m'
|
|
963
|
+
NC='\\033[0m' # No Color
|
|
964
|
+
|
|
965
|
+
echo -e "\${BLUE}=== Pre-commit \u6AA2\u67E5 ===\${NC}\\n"
|
|
966
|
+
|
|
967
|
+
# \u5207\u63DB\u5230\u5C08\u6848\u6839\u76EE\u9304
|
|
968
|
+
cd "$(git rev-parse --show-toplevel)"
|
|
969
|
+
|
|
970
|
+
# \u6AA2\u67E5\u662F\u5426\u5728\u6B63\u78BA\u7684\u76EE\u9304
|
|
971
|
+
if [ ! -f "package.json" ]; then
|
|
972
|
+
echo -e "\${RED}\u932F\u8AA4: \u627E\u4E0D\u5230 package.json\${NC}"
|
|
973
|
+
exit 1
|
|
974
|
+
fi
|
|
975
|
+
|
|
976
|
+
# \u6AA2\u67E5 Bun \u662F\u5426\u5B89\u88DD
|
|
977
|
+
if ! command -v bun &> /dev/null; then
|
|
978
|
+
echo -e "\${RED}\u932F\u8AA4: \u672A\u627E\u5230 bun\uFF0C\u8ACB\u5148\u5B89\u88DD Bun\${NC}"
|
|
979
|
+
exit 1
|
|
980
|
+
fi
|
|
981
|
+
|
|
982
|
+
# 1. \u985E\u578B\u6AA2\u67E5\uFF08\u5FEB\u901F\u6AA2\u67E5\uFF09
|
|
983
|
+
echo -e "\${YELLOW}[1/2] \u57F7\u884C\u985E\u578B\u6AA2\u67E5...\${NC}"
|
|
984
|
+
if bun run typecheck; then
|
|
985
|
+
echo -e "\${GREEN}\u2713 \u985E\u578B\u6AA2\u67E5\u901A\u904E\${NC}\\n"
|
|
986
|
+
else
|
|
987
|
+
echo -e "\${RED}\u2717 \u985E\u578B\u6AA2\u67E5\u5931\u6557\${NC}"
|
|
988
|
+
echo -e "\${YELLOW}\u63D0\u793A: \u8ACB\u4FEE\u6B63\u985E\u578B\u932F\u8AA4\u5F8C\u518D\u63D0\u4EA4\${NC}"
|
|
989
|
+
exit 1
|
|
990
|
+
fi
|
|
991
|
+
|
|
992
|
+
# 2. \u57F7\u884C\u6E2C\u8A66\uFF08\u53EF\u9078\uFF0C\u5982\u679C\u6E2C\u8A66\u6642\u9593\u8F03\u9577\u53EF\u4EE5\u8A3B\u89E3\u6389\uFF09
|
|
993
|
+
echo -e "\${YELLOW}[2/2] \u57F7\u884C\u6E2C\u8A66...\${NC}"
|
|
994
|
+
if bun test; then
|
|
995
|
+
echo -e "\${GREEN}\u2713 \u6E2C\u8A66\u901A\u904E\${NC}\\n"
|
|
996
|
+
else
|
|
997
|
+
echo -e "\${RED}\u2717 \u6E2C\u8A66\u5931\u6557\${NC}"
|
|
998
|
+
echo -e "\${YELLOW}\u63D0\u793A: \u8ACB\u4FEE\u6B63\u6E2C\u8A66\u932F\u8AA4\u5F8C\u518D\u63D0\u4EA4\${NC}"
|
|
999
|
+
exit 1
|
|
1000
|
+
fi
|
|
1001
|
+
|
|
1002
|
+
echo -e "\${GREEN}=== Pre-commit \u6AA2\u67E5\u901A\u904E ===\${NC}\\n"
|
|
1003
|
+
`;
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Generate CHECK_SYSTEM.md documentation.
|
|
1007
|
+
*/
|
|
1008
|
+
generateCheckSystemDoc(context) {
|
|
1009
|
+
return `# \u5C08\u6848\u6AA2\u67E5\u7CFB\u7D71
|
|
1010
|
+
|
|
1011
|
+
\u672C\u5C08\u6848\u5DF2\u5EFA\u7ACB\u5B8C\u6574\u7684\u672C\u5730\u6AA2\u67E5\u6A5F\u5236\uFF0C\u7121\u9700\u4F9D\u8CF4 GitHub CI\u3002
|
|
1012
|
+
|
|
1013
|
+
## \u5FEB\u901F\u958B\u59CB
|
|
1014
|
+
|
|
1015
|
+
### \u57F7\u884C\u5B8C\u6574\u6AA2\u67E5
|
|
1016
|
+
\`\`\`bash
|
|
1017
|
+
bun run validate
|
|
1018
|
+
\`\`\`
|
|
1019
|
+
|
|
1020
|
+
### \u57F7\u884C\u55AE\u9805\u6AA2\u67E5
|
|
1021
|
+
\`\`\`bash
|
|
1022
|
+
# \u985E\u578B\u6AA2\u67E5
|
|
1023
|
+
bun run typecheck
|
|
1024
|
+
|
|
1025
|
+
# \u6E2C\u8A66
|
|
1026
|
+
bun run test
|
|
1027
|
+
|
|
1028
|
+
# \u4F9D\u8CF4\u7248\u672C\u6AA2\u67E5
|
|
1029
|
+
bun run check:deps
|
|
1030
|
+
\`\`\`
|
|
1031
|
+
|
|
1032
|
+
## \u53EF\u7528\u547D\u4EE4
|
|
1033
|
+
|
|
1034
|
+
### Package.json \u8173\u672C
|
|
1035
|
+
|
|
1036
|
+
| \u547D\u4EE4 | \u8AAA\u660E |
|
|
1037
|
+
|------|------|
|
|
1038
|
+
| \`bun run typecheck\` | TypeScript \u985E\u578B\u6AA2\u67E5 |
|
|
1039
|
+
| \`bun run test\` | \u57F7\u884C\u6240\u6709\u6E2C\u8A66 |
|
|
1040
|
+
| \`bun run check\` | \u985E\u578B\u6AA2\u67E5 + \u6E2C\u8A66 |
|
|
1041
|
+
| \`bun run check:deps\` | \u6AA2\u67E5\u4F9D\u8CF4\u7248\u672C |
|
|
1042
|
+
| \`bun run validate\` | \u5B8C\u6574\u9A57\u8B49\uFF08\u985E\u578B + \u6E2C\u8A66 + \u4F9D\u8CF4\uFF09 |
|
|
1043
|
+
| \`bun run precommit\` | \u7B49\u540C\u65BC \`validate\` |
|
|
1044
|
+
|
|
1045
|
+
### Shell \u8173\u672C
|
|
1046
|
+
|
|
1047
|
+
| \u8173\u672C | \u8AAA\u660E |
|
|
1048
|
+
|------|------|
|
|
1049
|
+
| \`./scripts/check.sh\` | \u5B8C\u6574\u5C08\u6848\u6AA2\u67E5\uFF08Shell \u7248\u672C\uFF09 |
|
|
1050
|
+
| \`./scripts/pre-commit.sh\` | Pre-commit hook \u8173\u672C |
|
|
1051
|
+
|
|
1052
|
+
## Pre-commit Hook\uFF08\u63A8\u85A6\uFF09
|
|
1053
|
+
|
|
1054
|
+
\u5B89\u88DD pre-commit hook \u5F8C\uFF0C\u6BCF\u6B21 \`git commit\` \u524D\u6703\u81EA\u52D5\u57F7\u884C\u6AA2\u67E5\uFF1A
|
|
1055
|
+
|
|
1056
|
+
\`\`\`bash
|
|
1057
|
+
# \u5B89\u88DD pre-commit hook
|
|
1058
|
+
ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit
|
|
1059
|
+
|
|
1060
|
+
# \u6216\u4F7F\u7528\u8907\u88FD\u65B9\u5F0F
|
|
1061
|
+
cp scripts/pre-commit.sh .git/hooks/pre-commit
|
|
1062
|
+
chmod +x .git/hooks/pre-commit
|
|
1063
|
+
\`\`\`
|
|
1064
|
+
|
|
1065
|
+
**\u529F\u80FD\uFF1A**
|
|
1066
|
+
- \u2705 \u81EA\u52D5\u57F7\u884C\u985E\u578B\u6AA2\u67E5
|
|
1067
|
+
- \u2705 \u81EA\u52D5\u57F7\u884C\u6E2C\u8A66
|
|
1068
|
+
- \u274C \u6AA2\u67E5\u5931\u6557\u6642\u963B\u6B62\u63D0\u4EA4
|
|
1069
|
+
|
|
1070
|
+
**\u8DF3\u904E\u6AA2\u67E5\uFF08\u4E0D\u63A8\u85A6\uFF09\uFF1A**
|
|
1071
|
+
\`\`\`bash
|
|
1072
|
+
git commit --no-verify -m "\u7DCA\u6025\u4FEE\u5FA9"
|
|
1073
|
+
\`\`\`
|
|
1074
|
+
|
|
1075
|
+
## \u6AA2\u67E5\u9805\u76EE
|
|
1076
|
+
|
|
1077
|
+
### 1. \u985E\u578B\u6AA2\u67E5
|
|
1078
|
+
- \u4F7F\u7528 \`tsc --noEmit\` \u6AA2\u67E5 TypeScript \u985E\u578B
|
|
1079
|
+
- \u78BA\u4FDD\u6C92\u6709\u985E\u578B\u932F\u8AA4
|
|
1080
|
+
|
|
1081
|
+
### 2. \u6E2C\u8A66
|
|
1082
|
+
- \u57F7\u884C\u6240\u6709\u55AE\u5143\u6E2C\u8A66\u548C\u6574\u5408\u6E2C\u8A66
|
|
1083
|
+
- \u78BA\u4FDD\u6E2C\u8A66\u901A\u904E
|
|
1084
|
+
|
|
1085
|
+
### 3. \u4F9D\u8CF4\u6AA2\u67E5\uFF08\u53EF\u9078\uFF09
|
|
1086
|
+
- \u6AA2\u67E5\u5957\u4EF6\u7248\u672C\u662F\u5426\u70BA\u6700\u65B0
|
|
1087
|
+
- \u63D0\u4F9B\u66F4\u65B0\u5EFA\u8B70
|
|
1088
|
+
- \u9700\u8981\u7DB2\u8DEF\u9023\u7DDA
|
|
1089
|
+
|
|
1090
|
+
## \u5DE5\u4F5C\u6D41\u7A0B\u5EFA\u8B70
|
|
1091
|
+
|
|
1092
|
+
### \u958B\u767C\u6642
|
|
1093
|
+
1. \u958B\u767C\u529F\u80FD
|
|
1094
|
+
2. \u63D0\u4EA4\u524D\u57F7\u884C \`bun run validate\`
|
|
1095
|
+
3. \u4FEE\u6B63\u554F\u984C
|
|
1096
|
+
4. \u63D0\u4EA4\u7A0B\u5F0F\u78BC
|
|
1097
|
+
|
|
1098
|
+
### \u4F7F\u7528 Pre-commit Hook\uFF08\u63A8\u85A6\uFF09
|
|
1099
|
+
1. \u5B89\u88DD pre-commit hook\uFF08\u53EA\u9700\u4E00\u6B21\uFF09
|
|
1100
|
+
2. \u6B63\u5E38\u958B\u767C\u548C\u63D0\u4EA4
|
|
1101
|
+
3. \u6AA2\u67E5\u6703\u81EA\u52D5\u57F7\u884C
|
|
1102
|
+
4. \u5982\u6709\u554F\u984C\uFF0C\u4FEE\u6B63\u5F8C\u91CD\u65B0\u63D0\u4EA4
|
|
1103
|
+
|
|
1104
|
+
## \u6A94\u6848\u7D50\u69CB
|
|
1105
|
+
|
|
1106
|
+
\`\`\`
|
|
1107
|
+
${context.nameKebabCase}/
|
|
1108
|
+
\u251C\u2500\u2500 package.json # \u6AA2\u67E5\u8173\u672C\u5B9A\u7FA9
|
|
1109
|
+
\u251C\u2500\u2500 scripts/
|
|
1110
|
+
\u2502 \u251C\u2500\u2500 check.sh # \u5B8C\u6574\u6AA2\u67E5\u8173\u672C\uFF08Shell\uFF09
|
|
1111
|
+
\u2502 \u251C\u2500\u2500 check-dependencies.ts # \u4F9D\u8CF4\u7248\u672C\u6AA2\u67E5
|
|
1112
|
+
\u2502 \u2514\u2500\u2500 pre-commit.sh # Pre-commit hook
|
|
1113
|
+
\u2514\u2500\u2500 CHECK_SYSTEM.md # \u672C\u6587\u4EF6
|
|
1114
|
+
\`\`\`
|
|
1115
|
+
|
|
1116
|
+
## \u6CE8\u610F\u4E8B\u9805
|
|
1117
|
+
|
|
1118
|
+
1. **\u4F9D\u8CF4\u6AA2\u67E5\u9700\u8981\u7DB2\u8DEF\u9023\u7DDA**\uFF1A\`check:deps\` \u9700\u8981\u9023\u63A5\u5230 npm registry
|
|
1119
|
+
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
|
|
1120
|
+
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
|
|
1121
|
+
|
|
1122
|
+
## \u6545\u969C\u6392\u9664
|
|
1123
|
+
|
|
1124
|
+
### \u6AA2\u67E5\u5931\u6557
|
|
1125
|
+
1. \u67E5\u770B\u932F\u8AA4\u8A0A\u606F
|
|
1126
|
+
2. \u4FEE\u6B63\u554F\u984C
|
|
1127
|
+
3. \u91CD\u65B0\u57F7\u884C\u6AA2\u67E5
|
|
1128
|
+
|
|
1129
|
+
### \u8DF3\u904E\u6AA2\u67E5
|
|
1130
|
+
\u53EA\u6709\u5728\u7DCA\u6025\u60C5\u6CC1\u4E0B\u624D\u4F7F\u7528\uFF1A
|
|
1131
|
+
\`\`\`bash
|
|
1132
|
+
git commit --no-verify
|
|
1133
|
+
\`\`\`
|
|
1134
|
+
|
|
1135
|
+
### \u79FB\u9664 Pre-commit Hook
|
|
1136
|
+
\`\`\`bash
|
|
1137
|
+
rm .git/hooks/pre-commit
|
|
1138
|
+
\`\`\`
|
|
1139
|
+
`;
|
|
1140
|
+
}
|
|
688
1141
|
/**
|
|
689
1142
|
* Log a message if verbose mode is enabled.
|
|
690
1143
|
*/
|
|
@@ -865,6 +1318,11 @@ var CleanArchitectureGenerator = class extends BaseGenerator {
|
|
|
865
1318
|
type: "directory",
|
|
866
1319
|
name: "Providers",
|
|
867
1320
|
children: [
|
|
1321
|
+
{
|
|
1322
|
+
type: "file",
|
|
1323
|
+
name: "index.ts",
|
|
1324
|
+
content: this.generateProvidersIndex()
|
|
1325
|
+
},
|
|
868
1326
|
{
|
|
869
1327
|
type: "file",
|
|
870
1328
|
name: "AppServiceProvider.ts",
|
|
@@ -874,6 +1332,16 @@ var CleanArchitectureGenerator = class extends BaseGenerator {
|
|
|
874
1332
|
type: "file",
|
|
875
1333
|
name: "RepositoryServiceProvider.ts",
|
|
876
1334
|
content: this.generateRepositoryServiceProvider()
|
|
1335
|
+
},
|
|
1336
|
+
{
|
|
1337
|
+
type: "file",
|
|
1338
|
+
name: "MiddlewareProvider.ts",
|
|
1339
|
+
content: this.generateMiddlewareProvider()
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
type: "file",
|
|
1343
|
+
name: "RouteProvider.ts",
|
|
1344
|
+
content: this.generateRouteProvider()
|
|
877
1345
|
}
|
|
878
1346
|
]
|
|
879
1347
|
}
|
|
@@ -1367,6 +1835,65 @@ export class RepositoryServiceProvider extends ServiceProvider {
|
|
|
1367
1835
|
container.singleton('mailService', () => new MailService())
|
|
1368
1836
|
}
|
|
1369
1837
|
}
|
|
1838
|
+
`;
|
|
1839
|
+
}
|
|
1840
|
+
generateProvidersIndex() {
|
|
1841
|
+
return `/**
|
|
1842
|
+
* Application Service Providers
|
|
1843
|
+
*/
|
|
1844
|
+
|
|
1845
|
+
export { AppServiceProvider } from './AppServiceProvider'
|
|
1846
|
+
export { RepositoryServiceProvider } from './RepositoryServiceProvider'
|
|
1847
|
+
export { MiddlewareProvider } from './MiddlewareProvider'
|
|
1848
|
+
export { RouteProvider } from './RouteProvider'
|
|
1849
|
+
`;
|
|
1850
|
+
}
|
|
1851
|
+
generateMiddlewareProvider() {
|
|
1852
|
+
return `/**
|
|
1853
|
+
* Middleware Service Provider
|
|
1854
|
+
*/
|
|
1855
|
+
|
|
1856
|
+
import {
|
|
1857
|
+
ServiceProvider,
|
|
1858
|
+
type Container,
|
|
1859
|
+
type PlanetCore,
|
|
1860
|
+
bodySizeLimit,
|
|
1861
|
+
securityHeaders,
|
|
1862
|
+
} from '@gravito/core'
|
|
1863
|
+
|
|
1864
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
1865
|
+
register(_container: Container): void {}
|
|
1866
|
+
|
|
1867
|
+
boot(core: PlanetCore): void {
|
|
1868
|
+
const isDev = process.env.NODE_ENV !== 'production'
|
|
1869
|
+
|
|
1870
|
+
core.adapter.use('*', securityHeaders({
|
|
1871
|
+
contentSecurityPolicy: isDev ? false : undefined,
|
|
1872
|
+
}))
|
|
1873
|
+
|
|
1874
|
+
core.adapter.use('*', bodySizeLimit(10 * 1024 * 1024))
|
|
1875
|
+
|
|
1876
|
+
core.logger.info('\u{1F6E1}\uFE0F Middleware registered')
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
`;
|
|
1880
|
+
}
|
|
1881
|
+
generateRouteProvider() {
|
|
1882
|
+
return `/**
|
|
1883
|
+
* Route Service Provider
|
|
1884
|
+
*/
|
|
1885
|
+
|
|
1886
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
1887
|
+
import { registerApiRoutes } from '../../Interface/Http/Routes/api'
|
|
1888
|
+
|
|
1889
|
+
export class RouteProvider extends ServiceProvider {
|
|
1890
|
+
register(_container: Container): void {}
|
|
1891
|
+
|
|
1892
|
+
boot(core: PlanetCore): void {
|
|
1893
|
+
registerApiRoutes(core.router)
|
|
1894
|
+
core.logger.info('\u{1F6E4}\uFE0F Routes registered')
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1370
1897
|
`;
|
|
1371
1898
|
}
|
|
1372
1899
|
// ─────────────────────────────────────────────────────────────
|
|
@@ -1451,64 +1978,55 @@ export class UserPresenter {
|
|
|
1451
1978
|
}
|
|
1452
1979
|
`;
|
|
1453
1980
|
}
|
|
1454
|
-
generateBootstrap(
|
|
1981
|
+
generateBootstrap(_context) {
|
|
1455
1982
|
return `/**
|
|
1456
1983
|
* Application Bootstrap
|
|
1984
|
+
*
|
|
1985
|
+
* The entry point for your Clean Architecture application.
|
|
1986
|
+
* Uses the ServiceProvider pattern for modular initialization.
|
|
1987
|
+
*
|
|
1988
|
+
* Lifecycle:
|
|
1989
|
+
* 1. Configure: Load app config and orbits
|
|
1990
|
+
* 2. Boot: Initialize PlanetCore
|
|
1991
|
+
* 3. Register Providers: Bind services to container
|
|
1992
|
+
* 4. Bootstrap: Boot all providers
|
|
1457
1993
|
*/
|
|
1458
1994
|
|
|
1459
|
-
import {
|
|
1995
|
+
import { defineConfig, PlanetCore } from '@gravito/core'
|
|
1460
1996
|
import { OrbitAtlas } from '@gravito/atlas'
|
|
1461
|
-
import
|
|
1462
|
-
import {
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
"default-src 'self'",
|
|
1475
|
-
"script-src 'self' 'unsafe-inline'",
|
|
1476
|
-
"style-src 'self' 'unsafe-inline'",
|
|
1477
|
-
"img-src 'self' data:",
|
|
1478
|
-
"object-src 'none'",
|
|
1479
|
-
"base-uri 'self'",
|
|
1480
|
-
"frame-ancestors 'none'",
|
|
1481
|
-
].join('; ')
|
|
1482
|
-
const cspValue = process.env.APP_CSP
|
|
1483
|
-
const csp = cspValue === 'false' ? false : (cspValue ?? defaultCsp)
|
|
1484
|
-
const hstsMaxAge = Number.parseInt(process.env.APP_HSTS_MAX_AGE ?? '15552000', 10)
|
|
1485
|
-
const bodyLimit = Number.parseInt(process.env.APP_BODY_LIMIT ?? '1048576', 10)
|
|
1486
|
-
const requireLength = process.env.APP_BODY_REQUIRE_LENGTH === 'true'
|
|
1487
|
-
|
|
1488
|
-
core.adapter.use(
|
|
1489
|
-
'*',
|
|
1490
|
-
securityHeaders({
|
|
1491
|
-
contentSecurityPolicy: csp,
|
|
1492
|
-
hsts:
|
|
1493
|
-
process.env.NODE_ENV === 'production'
|
|
1494
|
-
? { maxAge: Number.isNaN(hstsMaxAge) ? 15552000 : hstsMaxAge, includeSubDomains: true }
|
|
1495
|
-
: false,
|
|
1997
|
+
import appConfig from '../config/app'
|
|
1998
|
+
import {
|
|
1999
|
+
AppServiceProvider,
|
|
2000
|
+
RepositoryServiceProvider,
|
|
2001
|
+
MiddlewareProvider,
|
|
2002
|
+
RouteProvider,
|
|
2003
|
+
} from './Infrastructure/Providers'
|
|
2004
|
+
|
|
2005
|
+
export async function bootstrap() {
|
|
2006
|
+
// 1. Configure
|
|
2007
|
+
const config = defineConfig({
|
|
2008
|
+
config: appConfig,
|
|
2009
|
+
orbits: [new OrbitAtlas()],
|
|
1496
2010
|
})
|
|
1497
|
-
)
|
|
1498
|
-
if (!Number.isNaN(bodyLimit) && bodyLimit > 0) {
|
|
1499
|
-
core.adapter.use('*', bodySizeLimit(bodyLimit, { requireContentLength: requireLength }))
|
|
1500
|
-
}
|
|
1501
2011
|
|
|
1502
|
-
|
|
2012
|
+
// 2. Boot Core
|
|
2013
|
+
const core = await PlanetCore.boot(config)
|
|
2014
|
+
core.registerGlobalErrorHandlers()
|
|
1503
2015
|
|
|
1504
|
-
|
|
1505
|
-
core.register(new
|
|
2016
|
+
// 3. Register Providers
|
|
2017
|
+
core.register(new RepositoryServiceProvider())
|
|
2018
|
+
core.register(new AppServiceProvider())
|
|
2019
|
+
core.register(new MiddlewareProvider())
|
|
2020
|
+
core.register(new RouteProvider())
|
|
1506
2021
|
|
|
1507
|
-
|
|
2022
|
+
// 4. Bootstrap All Providers
|
|
2023
|
+
await core.bootstrap()
|
|
1508
2024
|
|
|
1509
|
-
|
|
1510
|
-
|
|
2025
|
+
return core
|
|
2026
|
+
}
|
|
1511
2027
|
|
|
2028
|
+
// Application Entry Point
|
|
2029
|
+
const core = await bootstrap()
|
|
1512
2030
|
export default core.liftoff()
|
|
1513
2031
|
`;
|
|
1514
2032
|
}
|
|
@@ -1520,6 +2038,15 @@ export default core.liftoff()
|
|
|
1520
2038
|
This project follows **Clean Architecture** (by Robert C. Martin).
|
|
1521
2039
|
The key principle is the **Dependency Rule**: dependencies point inward.
|
|
1522
2040
|
|
|
2041
|
+
## Service Providers
|
|
2042
|
+
|
|
2043
|
+
Service providers are the central place to configure your application. They follow the ServiceProvider pattern with \`register()\` and \`boot()\` lifecycle methods.
|
|
2044
|
+
|
|
2045
|
+
### Provider Lifecycle
|
|
2046
|
+
|
|
2047
|
+
1. **register()**: Bind services to the container (sync or async).
|
|
2048
|
+
2. **boot()**: Called after ALL providers have registered. Safe to use other services.
|
|
2049
|
+
|
|
1523
2050
|
## Layer Structure
|
|
1524
2051
|
|
|
1525
2052
|
\`\`\`
|
|
@@ -1591,6 +2118,10 @@ Created with \u2764\uFE0F using Gravito Framework
|
|
|
1591
2118
|
start: "bun run dist/bootstrap.js",
|
|
1592
2119
|
test: "bun test",
|
|
1593
2120
|
typecheck: "tsc --noEmit",
|
|
2121
|
+
check: "bun run typecheck && bun run test",
|
|
2122
|
+
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
2123
|
+
validate: "bun run check && bun run check:deps",
|
|
2124
|
+
precommit: "bun run validate",
|
|
1594
2125
|
"docker:build": `docker build -t ${context.nameKebabCase} .`,
|
|
1595
2126
|
"docker:run": `docker run -it -p 3000:3000 ${context.nameKebabCase}`
|
|
1596
2127
|
},
|
|
@@ -1914,63 +2445,46 @@ var DddGenerator = class extends BaseGenerator {
|
|
|
1914
2445
|
// ─────────────────────────────────────────────────────────────
|
|
1915
2446
|
// Bootstrap File Generators
|
|
1916
2447
|
// ─────────────────────────────────────────────────────────────
|
|
1917
|
-
generateBootstrapApp(
|
|
2448
|
+
generateBootstrapApp(_context) {
|
|
1918
2449
|
return `/**
|
|
1919
2450
|
* Application Bootstrap
|
|
1920
2451
|
*
|
|
1921
|
-
* Central configuration and initialization
|
|
2452
|
+
* Central configuration and initialization using the ServiceProvider pattern.
|
|
2453
|
+
*
|
|
2454
|
+
* Lifecycle:
|
|
2455
|
+
* 1. Configure: Load app config and orbits
|
|
2456
|
+
* 2. Boot: Initialize PlanetCore
|
|
2457
|
+
* 3. Register Providers: Bind services to container
|
|
2458
|
+
* 4. Bootstrap: Boot all providers
|
|
1922
2459
|
*/
|
|
1923
2460
|
|
|
1924
|
-
import {
|
|
2461
|
+
import { defineConfig, PlanetCore } from '@gravito/core'
|
|
2462
|
+
import { OrbitAtlas } from '@gravito/atlas'
|
|
2463
|
+
import appConfig from '../../config/app'
|
|
1925
2464
|
import { registerProviders } from './providers'
|
|
1926
2465
|
import { registerRoutes } from './routes'
|
|
1927
2466
|
|
|
1928
2467
|
export async function createApp(): Promise<PlanetCore> {
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
2468
|
+
// 1. Configure
|
|
2469
|
+
const config = defineConfig({
|
|
2470
|
+
config: appConfig,
|
|
2471
|
+
orbits: [new OrbitAtlas()],
|
|
2472
|
+
})
|
|
1934
2473
|
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
"style-src 'self' 'unsafe-inline'",
|
|
1939
|
-
"img-src 'self' data:",
|
|
1940
|
-
"object-src 'none'",
|
|
1941
|
-
"base-uri 'self'",
|
|
1942
|
-
"frame-ancestors 'none'",
|
|
1943
|
-
].join('; ')
|
|
1944
|
-
const cspValue = process.env.APP_CSP
|
|
1945
|
-
const csp = cspValue === 'false' ? false : (cspValue ?? defaultCsp)
|
|
1946
|
-
const hstsMaxAge = Number.parseInt(process.env.APP_HSTS_MAX_AGE ?? '15552000', 10)
|
|
1947
|
-
const bodyLimit = Number.parseInt(process.env.APP_BODY_LIMIT ?? '1048576', 10)
|
|
1948
|
-
const requireLength = process.env.APP_BODY_REQUIRE_LENGTH === 'true'
|
|
1949
|
-
|
|
1950
|
-
core.adapter.use(
|
|
1951
|
-
'*',
|
|
1952
|
-
securityHeaders({
|
|
1953
|
-
contentSecurityPolicy: csp,
|
|
1954
|
-
hsts:
|
|
1955
|
-
process.env.NODE_ENV === 'production'
|
|
1956
|
-
? { maxAge: Number.isNaN(hstsMaxAge) ? 15552000 : hstsMaxAge, includeSubDomains: true }
|
|
1957
|
-
: false,
|
|
1958
|
-
})
|
|
1959
|
-
)
|
|
1960
|
-
if (!Number.isNaN(bodyLimit) && bodyLimit > 0) {
|
|
1961
|
-
core.adapter.use('*', bodySizeLimit(bodyLimit, { requireContentLength: requireLength }))
|
|
1962
|
-
}
|
|
2474
|
+
// 2. Boot Core
|
|
2475
|
+
const core = await PlanetCore.boot(config)
|
|
2476
|
+
core.registerGlobalErrorHandlers()
|
|
1963
2477
|
|
|
1964
|
-
|
|
1965
|
-
|
|
2478
|
+
// 3. Register Providers
|
|
2479
|
+
await registerProviders(core)
|
|
1966
2480
|
|
|
1967
|
-
|
|
1968
|
-
|
|
2481
|
+
// 4. Bootstrap All Providers
|
|
2482
|
+
await core.bootstrap()
|
|
1969
2483
|
|
|
1970
|
-
|
|
1971
|
-
|
|
2484
|
+
// Register routes after bootstrap
|
|
2485
|
+
registerRoutes(core.router)
|
|
1972
2486
|
|
|
1973
|
-
|
|
2487
|
+
return core
|
|
1974
2488
|
}
|
|
1975
2489
|
`;
|
|
1976
2490
|
}
|
|
@@ -1978,19 +2492,48 @@ export async function createApp(): Promise<PlanetCore> {
|
|
|
1978
2492
|
return `/**
|
|
1979
2493
|
* Service Providers Registry
|
|
1980
2494
|
*
|
|
1981
|
-
* Register all
|
|
2495
|
+
* Register all service providers here.
|
|
2496
|
+
* Include both global and module-specific providers.
|
|
1982
2497
|
*/
|
|
1983
2498
|
|
|
1984
|
-
import
|
|
2499
|
+
import {
|
|
2500
|
+
ServiceProvider,
|
|
2501
|
+
type Container,
|
|
2502
|
+
type PlanetCore,
|
|
2503
|
+
bodySizeLimit,
|
|
2504
|
+
securityHeaders,
|
|
2505
|
+
} from '@gravito/core'
|
|
1985
2506
|
import { OrderingServiceProvider } from '../Modules/Ordering/Infrastructure/Providers/OrderingServiceProvider'
|
|
1986
2507
|
import { CatalogServiceProvider } from '../Modules/Catalog/Infrastructure/Providers/CatalogServiceProvider'
|
|
1987
2508
|
|
|
2509
|
+
/**
|
|
2510
|
+
* Middleware Provider - Global middleware registration
|
|
2511
|
+
*/
|
|
2512
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
2513
|
+
register(_container: Container): void {}
|
|
2514
|
+
|
|
2515
|
+
boot(core: PlanetCore): void {
|
|
2516
|
+
const isDev = process.env.NODE_ENV !== 'production'
|
|
2517
|
+
|
|
2518
|
+
core.adapter.use('*', securityHeaders({
|
|
2519
|
+
contentSecurityPolicy: isDev ? false : undefined,
|
|
2520
|
+
}))
|
|
2521
|
+
|
|
2522
|
+
core.adapter.use('*', bodySizeLimit(10 * 1024 * 1024))
|
|
2523
|
+
|
|
2524
|
+
core.logger.info('\u{1F6E1}\uFE0F Global middleware registered')
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
|
|
1988
2528
|
export async function registerProviders(core: PlanetCore): Promise<void> {
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
core.register(new CatalogServiceProvider())
|
|
2529
|
+
// Global Providers
|
|
2530
|
+
core.register(new MiddlewareProvider())
|
|
1992
2531
|
|
|
1993
|
-
|
|
2532
|
+
// Module Providers
|
|
2533
|
+
core.register(new OrderingServiceProvider())
|
|
2534
|
+
core.register(new CatalogServiceProvider())
|
|
2535
|
+
|
|
2536
|
+
// Add more providers as needed
|
|
1994
2537
|
}
|
|
1995
2538
|
`;
|
|
1996
2539
|
}
|
|
@@ -2104,6 +2647,10 @@ export class ${name}ServiceProvider extends ServiceProvider {
|
|
|
2104
2647
|
start: "bun run dist/main.js",
|
|
2105
2648
|
test: "bun test",
|
|
2106
2649
|
typecheck: "tsc --noEmit",
|
|
2650
|
+
check: "bun run typecheck && bun run test",
|
|
2651
|
+
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
2652
|
+
validate: "bun run check && bun run check:deps",
|
|
2653
|
+
precommit: "bun run validate",
|
|
2107
2654
|
"docker:build": `docker build -t ${context.nameKebabCase} .`,
|
|
2108
2655
|
"docker:run": `docker run -it -p 3000:3000 ${context.nameKebabCase}`
|
|
2109
2656
|
},
|
|
@@ -2544,6 +3091,16 @@ export function report(error: unknown): void {
|
|
|
2544
3091
|
|
|
2545
3092
|
This project follows **Domain-Driven Design (DDD)** with strategic and tactical patterns.
|
|
2546
3093
|
|
|
3094
|
+
## Service Providers
|
|
3095
|
+
|
|
3096
|
+
Service providers are the central place to configure your application and modules. They follow the ServiceProvider pattern with \`register()\` and \`boot()\` lifecycle methods.
|
|
3097
|
+
|
|
3098
|
+
### Internal Bootstrapping
|
|
3099
|
+
|
|
3100
|
+
1. **Bootstrap/app.ts**: Orchestrates the 4-step lifecycle (Configure, Boot, Register, Bootstrap).
|
|
3101
|
+
2. **Bootstrap/providers.ts**: Central registry for all global and module-specific providers.
|
|
3102
|
+
3. **Infrastructure/Providers/[Module]ServiceProvider.ts**: Module-specific service registration.
|
|
3103
|
+
|
|
2547
3104
|
## Bounded Contexts
|
|
2548
3105
|
|
|
2549
3106
|
\`\`\`
|
|
@@ -2681,6 +3238,11 @@ var EnterpriseMvcGenerator = class extends BaseGenerator {
|
|
|
2681
3238
|
type: "directory",
|
|
2682
3239
|
name: "Providers",
|
|
2683
3240
|
children: [
|
|
3241
|
+
{
|
|
3242
|
+
type: "file",
|
|
3243
|
+
name: "index.ts",
|
|
3244
|
+
content: this.generateProvidersIndex()
|
|
3245
|
+
},
|
|
2684
3246
|
{
|
|
2685
3247
|
type: "file",
|
|
2686
3248
|
name: "AppServiceProvider.ts",
|
|
@@ -2688,8 +3250,18 @@ var EnterpriseMvcGenerator = class extends BaseGenerator {
|
|
|
2688
3250
|
},
|
|
2689
3251
|
{
|
|
2690
3252
|
type: "file",
|
|
2691
|
-
name: "
|
|
2692
|
-
content: this.
|
|
3253
|
+
name: "DatabaseProvider.ts",
|
|
3254
|
+
content: this.generateDatabaseProvider()
|
|
3255
|
+
},
|
|
3256
|
+
{
|
|
3257
|
+
type: "file",
|
|
3258
|
+
name: "MiddlewareProvider.ts",
|
|
3259
|
+
content: this.generateMiddlewareProvider()
|
|
3260
|
+
},
|
|
3261
|
+
{
|
|
3262
|
+
type: "file",
|
|
3263
|
+
name: "RouteProvider.ts",
|
|
3264
|
+
content: this.generateRouteProvider()
|
|
2693
3265
|
}
|
|
2694
3266
|
]
|
|
2695
3267
|
},
|
|
@@ -3156,6 +3728,135 @@ export class RouteServiceProvider extends ServiceProvider {
|
|
|
3156
3728
|
registerRoutes(core.router)
|
|
3157
3729
|
}
|
|
3158
3730
|
}
|
|
3731
|
+
`;
|
|
3732
|
+
}
|
|
3733
|
+
// ─────────────────────────────────────────────────────────────
|
|
3734
|
+
// Modern Provider Generators (ServiceProvider Pattern)
|
|
3735
|
+
// ─────────────────────────────────────────────────────────────
|
|
3736
|
+
generateProvidersIndex() {
|
|
3737
|
+
return `/**
|
|
3738
|
+
* Application Service Providers
|
|
3739
|
+
*
|
|
3740
|
+
* Export all providers for easy importing in bootstrap.
|
|
3741
|
+
* Providers are registered in the order they are listed.
|
|
3742
|
+
*/
|
|
3743
|
+
|
|
3744
|
+
export { AppServiceProvider } from './AppServiceProvider'
|
|
3745
|
+
export { DatabaseProvider } from './DatabaseProvider'
|
|
3746
|
+
export { MiddlewareProvider } from './MiddlewareProvider'
|
|
3747
|
+
export { RouteProvider } from './RouteProvider'
|
|
3748
|
+
`;
|
|
3749
|
+
}
|
|
3750
|
+
generateDatabaseProvider() {
|
|
3751
|
+
return `/**
|
|
3752
|
+
* Database Service Provider
|
|
3753
|
+
*
|
|
3754
|
+
* Handles database initialization and migrations.
|
|
3755
|
+
*
|
|
3756
|
+
* Lifecycle:
|
|
3757
|
+
* - register(): Bind database config to container
|
|
3758
|
+
* - boot(): Run migrations and seeders
|
|
3759
|
+
*/
|
|
3760
|
+
|
|
3761
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
3762
|
+
import databaseConfig from '../../config/database'
|
|
3763
|
+
|
|
3764
|
+
export class DatabaseProvider extends ServiceProvider {
|
|
3765
|
+
/**
|
|
3766
|
+
* Register database configuration.
|
|
3767
|
+
*/
|
|
3768
|
+
register(_container: Container): void {
|
|
3769
|
+
this.mergeConfig(this.core!.config, 'database', databaseConfig)
|
|
3770
|
+
}
|
|
3771
|
+
|
|
3772
|
+
/**
|
|
3773
|
+
* Initialize database connections.
|
|
3774
|
+
*/
|
|
3775
|
+
async boot(core: PlanetCore): Promise<void> {
|
|
3776
|
+
// Database initialization will be handled by Atlas orbit
|
|
3777
|
+
core.logger.info('\u{1F4E6} Database provider booted')
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
`;
|
|
3781
|
+
}
|
|
3782
|
+
generateMiddlewareProvider() {
|
|
3783
|
+
return `/**
|
|
3784
|
+
* Middleware Service Provider
|
|
3785
|
+
*
|
|
3786
|
+
* Registers global middleware stack.
|
|
3787
|
+
* Provides a centralized location for middleware configuration.
|
|
3788
|
+
*
|
|
3789
|
+
* Lifecycle:
|
|
3790
|
+
* - register(): N/A (no container bindings)
|
|
3791
|
+
* - boot(): Register global middleware
|
|
3792
|
+
*/
|
|
3793
|
+
|
|
3794
|
+
import {
|
|
3795
|
+
ServiceProvider,
|
|
3796
|
+
type Container,
|
|
3797
|
+
type PlanetCore,
|
|
3798
|
+
bodySizeLimit,
|
|
3799
|
+
securityHeaders,
|
|
3800
|
+
} from '@gravito/core'
|
|
3801
|
+
|
|
3802
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
3803
|
+
/**
|
|
3804
|
+
* No container bindings needed.
|
|
3805
|
+
*/
|
|
3806
|
+
register(_container: Container): void {
|
|
3807
|
+
// Middleware doesn't require container bindings
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
/**
|
|
3811
|
+
* Register global middleware stack.
|
|
3812
|
+
*/
|
|
3813
|
+
boot(core: PlanetCore): void {
|
|
3814
|
+
const isDev = process.env.NODE_ENV !== 'production'
|
|
3815
|
+
|
|
3816
|
+
// Security Headers
|
|
3817
|
+
core.adapter.use('*', securityHeaders({
|
|
3818
|
+
contentSecurityPolicy: isDev ? false : undefined,
|
|
3819
|
+
}))
|
|
3820
|
+
|
|
3821
|
+
// Body Parser Limits
|
|
3822
|
+
core.adapter.use('*', bodySizeLimit(10 * 1024 * 1024)) // 10MB limit
|
|
3823
|
+
|
|
3824
|
+
core.logger.info('\u{1F6E1}\uFE0F Middleware registered')
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
`;
|
|
3828
|
+
}
|
|
3829
|
+
generateRouteProvider() {
|
|
3830
|
+
return `/**
|
|
3831
|
+
* Route Service Provider
|
|
3832
|
+
*
|
|
3833
|
+
* Registers application routes.
|
|
3834
|
+
* Routes are registered in the boot phase after all services are available.
|
|
3835
|
+
*
|
|
3836
|
+
* Lifecycle:
|
|
3837
|
+
* - register(): N/A
|
|
3838
|
+
* - boot(): Register routes
|
|
3839
|
+
*/
|
|
3840
|
+
|
|
3841
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
3842
|
+
import { registerRoutes } from '../routes'
|
|
3843
|
+
|
|
3844
|
+
export class RouteProvider extends ServiceProvider {
|
|
3845
|
+
/**
|
|
3846
|
+
* No container bindings needed.
|
|
3847
|
+
*/
|
|
3848
|
+
register(_container: Container): void {
|
|
3849
|
+
// Routes don't require container bindings
|
|
3850
|
+
}
|
|
3851
|
+
|
|
3852
|
+
/**
|
|
3853
|
+
* Register application routes.
|
|
3854
|
+
*/
|
|
3855
|
+
boot(core: PlanetCore): void {
|
|
3856
|
+
registerRoutes(core.router)
|
|
3857
|
+
core.logger.info('\u{1F6E4}\uFE0F Routes registered')
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3159
3860
|
`;
|
|
3160
3861
|
}
|
|
3161
3862
|
generateExceptionHandler() {
|
|
@@ -3204,74 +3905,75 @@ export const dontReport: string[] = [
|
|
|
3204
3905
|
}
|
|
3205
3906
|
generateBootstrap(context) {
|
|
3206
3907
|
const spectrumImport = context.withSpectrum ? "import { SpectrumOrbit } from '@gravito/spectrum'\n" : "";
|
|
3207
|
-
const spectrumOrbit = context.withSpectrum ?
|
|
3208
|
-
// Enable Debug Dashboard
|
|
3209
|
-
if (process.env.APP_DEBUG === 'true') {
|
|
3210
|
-
await core.orbit(new SpectrumOrbit())
|
|
3211
|
-
}
|
|
3212
|
-
` : "";
|
|
3908
|
+
const spectrumOrbit = context.withSpectrum ? " new SpectrumOrbit()," : "";
|
|
3213
3909
|
return `/**
|
|
3214
3910
|
* Application Bootstrap
|
|
3215
3911
|
*
|
|
3216
|
-
*
|
|
3217
|
-
*
|
|
3912
|
+
* The entry point for your Gravito application.
|
|
3913
|
+
* Uses the ServiceProvider pattern for modular, maintainable initialization.
|
|
3914
|
+
*
|
|
3915
|
+
* Lifecycle:
|
|
3916
|
+
* 1. Configure: Load app config and orbits
|
|
3917
|
+
* 2. Boot: Initialize PlanetCore
|
|
3918
|
+
* 3. Register Providers: Bind services to container
|
|
3919
|
+
* 4. Bootstrap: Boot all providers
|
|
3920
|
+
*
|
|
3921
|
+
* @module bootstrap
|
|
3218
3922
|
*/
|
|
3219
3923
|
|
|
3220
|
-
import {
|
|
3924
|
+
import { defineConfig, PlanetCore } from '@gravito/core'
|
|
3221
3925
|
import { OrbitAtlas } from '@gravito/atlas'
|
|
3222
|
-
import
|
|
3223
|
-
${spectrumImport}import {
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
// Create application core
|
|
3230
|
-
const core = new PlanetCore({
|
|
3231
|
-
config: {
|
|
3232
|
-
APP_NAME: process.env.APP_NAME ?? '${context.name}',
|
|
3233
|
-
database: databaseConfig,
|
|
3234
|
-
},
|
|
3235
|
-
})
|
|
3236
|
-
const defaultCsp = [
|
|
3237
|
-
"default-src 'self'",
|
|
3238
|
-
"script-src 'self' 'unsafe-inline'",
|
|
3239
|
-
"style-src 'self' 'unsafe-inline'",
|
|
3240
|
-
"img-src 'self' data:",
|
|
3241
|
-
"object-src 'none'",
|
|
3242
|
-
"base-uri 'self'",
|
|
3243
|
-
"frame-ancestors 'none'",
|
|
3244
|
-
].join('; ')
|
|
3245
|
-
const cspValue = process.env.APP_CSP
|
|
3246
|
-
const csp = cspValue === 'false' ? false : (cspValue ?? defaultCsp)
|
|
3247
|
-
const hstsMaxAge = Number.parseInt(process.env.APP_HSTS_MAX_AGE ?? '15552000', 10)
|
|
3248
|
-
const bodyLimit = Number.parseInt(process.env.APP_BODY_LIMIT ?? '1048576', 10)
|
|
3249
|
-
const requireLength = process.env.APP_BODY_REQUIRE_LENGTH === 'true'
|
|
3250
|
-
|
|
3251
|
-
core.adapter.use(
|
|
3252
|
-
'*',
|
|
3253
|
-
securityHeaders({
|
|
3254
|
-
contentSecurityPolicy: csp,
|
|
3255
|
-
hsts:
|
|
3256
|
-
process.env.NODE_ENV === 'production'
|
|
3257
|
-
? { maxAge: Number.isNaN(hstsMaxAge) ? 15552000 : hstsMaxAge, includeSubDomains: true }
|
|
3258
|
-
: false,
|
|
3259
|
-
})
|
|
3260
|
-
)
|
|
3261
|
-
if (!Number.isNaN(bodyLimit) && bodyLimit > 0) {
|
|
3262
|
-
core.adapter.use('*', bodySizeLimit(bodyLimit, { requireContentLength: requireLength }))
|
|
3263
|
-
}
|
|
3926
|
+
import appConfig from '../config/app'
|
|
3927
|
+
${spectrumImport}import {
|
|
3928
|
+
AppServiceProvider,
|
|
3929
|
+
DatabaseProvider,
|
|
3930
|
+
MiddlewareProvider,
|
|
3931
|
+
RouteProvider,
|
|
3932
|
+
} from './Providers'
|
|
3264
3933
|
|
|
3265
|
-
|
|
3934
|
+
/**
|
|
3935
|
+
* Bootstrap the application with service providers.
|
|
3936
|
+
*
|
|
3937
|
+
* @returns The booted PlanetCore instance
|
|
3938
|
+
*/
|
|
3939
|
+
export async function bootstrap() {
|
|
3940
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3941
|
+
// 1. Configure
|
|
3942
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3943
|
+
const config = defineConfig({
|
|
3944
|
+
config: appConfig,
|
|
3945
|
+
orbits: [
|
|
3946
|
+
new OrbitAtlas(),
|
|
3266
3947
|
${spectrumOrbit}
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
core.register(new RouteServiceProvider())
|
|
3948
|
+
],
|
|
3949
|
+
})
|
|
3270
3950
|
|
|
3271
|
-
//
|
|
3272
|
-
|
|
3951
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3952
|
+
// 2. Boot Core
|
|
3953
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3954
|
+
const core = await PlanetCore.boot(config)
|
|
3955
|
+
core.registerGlobalErrorHandlers()
|
|
3956
|
+
|
|
3957
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3958
|
+
// 3. Register Providers
|
|
3959
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3960
|
+
core.register(new AppServiceProvider())
|
|
3961
|
+
core.register(new DatabaseProvider())
|
|
3962
|
+
core.register(new MiddlewareProvider())
|
|
3963
|
+
core.register(new RouteProvider())
|
|
3964
|
+
|
|
3965
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3966
|
+
// 4. Bootstrap All Providers
|
|
3967
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3968
|
+
await core.bootstrap()
|
|
3969
|
+
|
|
3970
|
+
return core
|
|
3971
|
+
}
|
|
3273
3972
|
|
|
3274
|
-
//
|
|
3973
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3974
|
+
// Application Entry Point
|
|
3975
|
+
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3976
|
+
const core = await bootstrap()
|
|
3275
3977
|
export default core.liftoff()
|
|
3276
3978
|
`;
|
|
3277
3979
|
}
|
|
@@ -3698,7 +4400,9 @@ export class ${name}ServiceProvider extends ServiceProvider {
|
|
|
3698
4400
|
scripts: {
|
|
3699
4401
|
build: "tsup src/index.ts --format cjs,esm --dts",
|
|
3700
4402
|
test: "bun test",
|
|
3701
|
-
typecheck: "tsc --noEmit"
|
|
4403
|
+
typecheck: "tsc --noEmit",
|
|
4404
|
+
check: "bun run typecheck && bun run test",
|
|
4405
|
+
validate: "bun run check"
|
|
3702
4406
|
},
|
|
3703
4407
|
dependencies: {
|
|
3704
4408
|
"@gravito/core": depVersion,
|
|
@@ -3996,10 +4700,25 @@ var ActionDomainGenerator = class extends BaseGenerator {
|
|
|
3996
4700
|
type: "directory",
|
|
3997
4701
|
name: "providers",
|
|
3998
4702
|
children: [
|
|
4703
|
+
{
|
|
4704
|
+
type: "file",
|
|
4705
|
+
name: "index.ts",
|
|
4706
|
+
content: this.generateProvidersIndex()
|
|
4707
|
+
},
|
|
3999
4708
|
{
|
|
4000
4709
|
type: "file",
|
|
4001
4710
|
name: "AppServiceProvider.ts",
|
|
4002
4711
|
content: this.generateAppServiceProvider(context)
|
|
4712
|
+
},
|
|
4713
|
+
{
|
|
4714
|
+
type: "file",
|
|
4715
|
+
name: "MiddlewareProvider.ts",
|
|
4716
|
+
content: this.generateMiddlewareProvider()
|
|
4717
|
+
},
|
|
4718
|
+
{
|
|
4719
|
+
type: "file",
|
|
4720
|
+
name: "RouteProvider.ts",
|
|
4721
|
+
content: this.generateRouteProvider()
|
|
4003
4722
|
}
|
|
4004
4723
|
]
|
|
4005
4724
|
},
|
|
@@ -4177,7 +4896,7 @@ export function registerApiRoutes(router: Router) {
|
|
|
4177
4896
|
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
4178
4897
|
|
|
4179
4898
|
export class AppServiceProvider extends ServiceProvider {
|
|
4180
|
-
register(
|
|
4899
|
+
register(_container: Container): void {
|
|
4181
4900
|
// Register global services here
|
|
4182
4901
|
}
|
|
4183
4902
|
|
|
@@ -4187,47 +4906,140 @@ export class AppServiceProvider extends ServiceProvider {
|
|
|
4187
4906
|
}
|
|
4188
4907
|
`;
|
|
4189
4908
|
}
|
|
4190
|
-
|
|
4909
|
+
generateProvidersIndex() {
|
|
4191
4910
|
return `/**
|
|
4192
|
-
* Application
|
|
4911
|
+
* Application Service Providers
|
|
4193
4912
|
*/
|
|
4194
4913
|
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
APP_NAME: '${context.name}',
|
|
4205
|
-
database: databaseConfig
|
|
4206
|
-
},
|
|
4207
|
-
})
|
|
4914
|
+
export { AppServiceProvider } from './AppServiceProvider'
|
|
4915
|
+
export { MiddlewareProvider } from './MiddlewareProvider'
|
|
4916
|
+
export { RouteProvider } from './RouteProvider'
|
|
4917
|
+
`;
|
|
4918
|
+
}
|
|
4919
|
+
generateMiddlewareProvider() {
|
|
4920
|
+
return `/**
|
|
4921
|
+
* Middleware Service Provider
|
|
4922
|
+
*/
|
|
4208
4923
|
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4924
|
+
import {
|
|
4925
|
+
ServiceProvider,
|
|
4926
|
+
type Container,
|
|
4927
|
+
type PlanetCore,
|
|
4928
|
+
bodySizeLimit,
|
|
4929
|
+
securityHeaders,
|
|
4930
|
+
} from '@gravito/core'
|
|
4212
4931
|
|
|
4213
|
-
|
|
4214
|
-
|
|
4932
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
4933
|
+
register(_container: Container): void {}
|
|
4215
4934
|
|
|
4216
|
-
|
|
4217
|
-
core.
|
|
4935
|
+
boot(core: PlanetCore): void {
|
|
4936
|
+
core.adapter.use('*', securityHeaders())
|
|
4937
|
+
core.adapter.use('*', bodySizeLimit(1024 * 1024))
|
|
4938
|
+
core.logger.info('\u{1F6E1}\uFE0F Middleware registered')
|
|
4939
|
+
}
|
|
4940
|
+
}
|
|
4941
|
+
`;
|
|
4942
|
+
}
|
|
4943
|
+
generateRouteProvider() {
|
|
4944
|
+
return `/**
|
|
4945
|
+
* Route Service Provider
|
|
4946
|
+
*/
|
|
4218
4947
|
|
|
4219
|
-
|
|
4220
|
-
|
|
4948
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
4949
|
+
import { registerApiRoutes } from '../routes/api'
|
|
4221
4950
|
|
|
4222
|
-
|
|
4223
|
-
|
|
4951
|
+
export class RouteProvider extends ServiceProvider {
|
|
4952
|
+
register(_container: Container): void {}
|
|
4224
4953
|
|
|
4225
|
-
|
|
4954
|
+
boot(core: PlanetCore): void {
|
|
4955
|
+
registerApiRoutes(core.router)
|
|
4956
|
+
core.logger.info('\u{1F6E4}\uFE0F Routes registered')
|
|
4957
|
+
}
|
|
4958
|
+
}
|
|
4959
|
+
`;
|
|
4960
|
+
}
|
|
4961
|
+
generateBootstrap(_context) {
|
|
4962
|
+
return `/**
|
|
4963
|
+
* Application Bootstrap
|
|
4964
|
+
*
|
|
4965
|
+
* Uses the ServiceProvider pattern for modular initialization.
|
|
4966
|
+
*/
|
|
4967
|
+
|
|
4968
|
+
import { defineConfig, PlanetCore } from '@gravito/core'
|
|
4969
|
+
import { OrbitAtlas } from '@gravito/atlas'
|
|
4970
|
+
import appConfig from '../config/app'
|
|
4971
|
+
import {
|
|
4972
|
+
AppServiceProvider,
|
|
4973
|
+
MiddlewareProvider,
|
|
4974
|
+
RouteProvider,
|
|
4975
|
+
} from './providers'
|
|
4976
|
+
|
|
4977
|
+
export async function bootstrap() {
|
|
4978
|
+
const config = defineConfig({
|
|
4979
|
+
config: appConfig,
|
|
4980
|
+
orbits: [new OrbitAtlas()],
|
|
4981
|
+
})
|
|
4982
|
+
|
|
4983
|
+
const core = await PlanetCore.boot(config)
|
|
4984
|
+
core.registerGlobalErrorHandlers()
|
|
4985
|
+
|
|
4986
|
+
core.register(new AppServiceProvider())
|
|
4987
|
+
core.register(new MiddlewareProvider())
|
|
4988
|
+
core.register(new RouteProvider())
|
|
4989
|
+
|
|
4990
|
+
await core.bootstrap()
|
|
4991
|
+
|
|
4992
|
+
return core
|
|
4993
|
+
}
|
|
4994
|
+
|
|
4995
|
+
const core = await bootstrap()
|
|
4226
4996
|
export default core.liftoff()
|
|
4227
4997
|
`;
|
|
4228
4998
|
}
|
|
4229
4999
|
generateArchitectureDoc(context) {
|
|
4230
|
-
return
|
|
5000
|
+
return `# ${context.name} - Action Domain Architecture
|
|
5001
|
+
|
|
5002
|
+
## Overview
|
|
5003
|
+
|
|
5004
|
+
This project uses the **Action Domain** pattern, designed for high-clarity API implementations.
|
|
5005
|
+
|
|
5006
|
+
## Service Providers
|
|
5007
|
+
|
|
5008
|
+
Service providers are the central place to configure your application. They follow the ServiceProvider pattern with \`register()\` and \`boot()\` lifecycle methods.
|
|
5009
|
+
|
|
5010
|
+
## Directory Structure
|
|
5011
|
+
|
|
5012
|
+
\`\`\`
|
|
5013
|
+
src/
|
|
5014
|
+
\u251C\u2500\u2500 actions/ # Single Responsibility Business Logic
|
|
5015
|
+
\u2502 \u251C\u2500\u2500 Action.ts # Base Action class
|
|
5016
|
+
\u2502 \u2514\u2500\u2500 [Domain]/ # Domain-specific actions
|
|
5017
|
+
\u251C\u2500\u2500 controllers/ # HTTP Request Handlers
|
|
5018
|
+
\u2502 \u2514\u2500\u2500 api/v1/ # API Controllers
|
|
5019
|
+
\u251C\u2500\u2500 types/ # TypeScript Definitions
|
|
5020
|
+
\u251C\u2500\u2500 repositories/ # Data Access Layer
|
|
5021
|
+
\u251C\u2500\u2500 routes/ # Route Definitions
|
|
5022
|
+
\u251C\u2500\u2500 providers/ # Service Providers
|
|
5023
|
+
\u2514\u2500\u2500 config/ # Configuration
|
|
5024
|
+
\`\`\`
|
|
5025
|
+
|
|
5026
|
+
## Core Concepts
|
|
5027
|
+
|
|
5028
|
+
### Actions
|
|
5029
|
+
Every business operation is an "Action". An action:
|
|
5030
|
+
- Does ONE thing.
|
|
5031
|
+
- Takes specific input.
|
|
5032
|
+
- Returns specific output.
|
|
5033
|
+
- Is framework-agnostic (ideally).
|
|
5034
|
+
|
|
5035
|
+
### Controllers
|
|
5036
|
+
Controllers are thin. They:
|
|
5037
|
+
1. Parse the request.
|
|
5038
|
+
2. Instantiate/Call the Action.
|
|
5039
|
+
3. Return the response.
|
|
5040
|
+
|
|
5041
|
+
Created with \u2764\uFE0F using Gravito Framework
|
|
5042
|
+
`;
|
|
4231
5043
|
}
|
|
4232
5044
|
generatePackageJson(context) {
|
|
4233
5045
|
const pkg = {
|
|
@@ -4239,7 +5051,11 @@ export default core.liftoff()
|
|
|
4239
5051
|
build: "bun build ./src/bootstrap.ts --outdir ./dist --target bun",
|
|
4240
5052
|
start: "bun run dist/bootstrap.js",
|
|
4241
5053
|
test: "bun test",
|
|
4242
|
-
typecheck: "tsc --noEmit"
|
|
5054
|
+
typecheck: "tsc --noEmit",
|
|
5055
|
+
check: "bun run typecheck && bun run test",
|
|
5056
|
+
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
5057
|
+
validate: "bun run check && bun run check:deps",
|
|
5058
|
+
precommit: "bun run validate"
|
|
4243
5059
|
},
|
|
4244
5060
|
dependencies: {
|
|
4245
5061
|
"@gravito/core": "workspace:*",
|
|
@@ -4256,6 +5072,115 @@ export default core.liftoff()
|
|
|
4256
5072
|
}
|
|
4257
5073
|
};
|
|
4258
5074
|
|
|
5075
|
+
// src/generators/StandaloneEngineGenerator.ts
|
|
5076
|
+
var StandaloneEngineGenerator = class extends BaseGenerator {
|
|
5077
|
+
get architectureType() {
|
|
5078
|
+
return "standalone-engine";
|
|
5079
|
+
}
|
|
5080
|
+
get displayName() {
|
|
5081
|
+
return "Standalone Engine";
|
|
5082
|
+
}
|
|
5083
|
+
get description() {
|
|
5084
|
+
return "High-performance pure Gravito Engine (minimal)";
|
|
5085
|
+
}
|
|
5086
|
+
getDirectoryStructure(context) {
|
|
5087
|
+
return [
|
|
5088
|
+
{
|
|
5089
|
+
type: "directory",
|
|
5090
|
+
name: "src",
|
|
5091
|
+
children: [
|
|
5092
|
+
{
|
|
5093
|
+
type: "file",
|
|
5094
|
+
name: "index.ts",
|
|
5095
|
+
content: this.getIndexContent()
|
|
5096
|
+
}
|
|
5097
|
+
]
|
|
5098
|
+
},
|
|
5099
|
+
{
|
|
5100
|
+
type: "file",
|
|
5101
|
+
name: "README.md",
|
|
5102
|
+
content: this.getReadmeContent(context)
|
|
5103
|
+
}
|
|
5104
|
+
];
|
|
5105
|
+
}
|
|
5106
|
+
async generateCommonFiles(context) {
|
|
5107
|
+
await this.writeFile(context.targetDir, "package.json", this.generatePackageJson(context));
|
|
5108
|
+
await this.writeFile(context.targetDir, "tsconfig.json", this.generateTsConfig());
|
|
5109
|
+
await this.writeFile(context.targetDir, ".gitignore", this.generateGitignore());
|
|
5110
|
+
}
|
|
5111
|
+
generatePackageJson(context) {
|
|
5112
|
+
const pkg = {
|
|
5113
|
+
name: context.nameKebabCase,
|
|
5114
|
+
version: "0.1.0",
|
|
5115
|
+
type: "module",
|
|
5116
|
+
scripts: {
|
|
5117
|
+
dev: "bun run --watch src/index.ts",
|
|
5118
|
+
build: "bun build ./src/index.ts --outdir ./dist --target bun",
|
|
5119
|
+
start: "bun run dist/index.js",
|
|
5120
|
+
test: "bun test"
|
|
5121
|
+
},
|
|
5122
|
+
dependencies: {
|
|
5123
|
+
"@gravito/core": "^1.1.0"
|
|
5124
|
+
},
|
|
5125
|
+
devDependencies: {
|
|
5126
|
+
"bun-types": "latest",
|
|
5127
|
+
typescript: "^5.0.0"
|
|
5128
|
+
}
|
|
5129
|
+
};
|
|
5130
|
+
return JSON.stringify(pkg, null, 2);
|
|
5131
|
+
}
|
|
5132
|
+
generateArchitectureDoc(_context) {
|
|
5133
|
+
return "";
|
|
5134
|
+
}
|
|
5135
|
+
getIndexContent() {
|
|
5136
|
+
return `import { Gravito } from '@gravito/core/engine'
|
|
5137
|
+
|
|
5138
|
+
const app = new Gravito()
|
|
5139
|
+
|
|
5140
|
+
// Basic Route
|
|
5141
|
+
app.get('/', (c) => c.text('Hello Gravito Engine!'))
|
|
5142
|
+
|
|
5143
|
+
// JSON Response
|
|
5144
|
+
app.get('/json', (c) => c.json({ message: 'High Performance' }))
|
|
5145
|
+
|
|
5146
|
+
// Path Parameters
|
|
5147
|
+
app.get('/user/:name', (c) => {
|
|
5148
|
+
const name = c.req.param('name')
|
|
5149
|
+
return c.text(\`Hello \${name}\`)
|
|
5150
|
+
})
|
|
5151
|
+
|
|
5152
|
+
export default app
|
|
5153
|
+
`;
|
|
5154
|
+
}
|
|
5155
|
+
getReadmeContent(context) {
|
|
5156
|
+
return `# ${context.name}
|
|
5157
|
+
|
|
5158
|
+
A high-performance web application powered by Gravito Engine.
|
|
5159
|
+
|
|
5160
|
+
## Getting Started
|
|
5161
|
+
|
|
5162
|
+
### Install Dependencies
|
|
5163
|
+
|
|
5164
|
+
\`\`\`bash
|
|
5165
|
+
bun install
|
|
5166
|
+
\`\`\`
|
|
5167
|
+
|
|
5168
|
+
### Run Development Server
|
|
5169
|
+
|
|
5170
|
+
\`\`\`bash
|
|
5171
|
+
bun run dev
|
|
5172
|
+
\`\`\`
|
|
5173
|
+
|
|
5174
|
+
### Production Build
|
|
5175
|
+
|
|
5176
|
+
\`\`\`bash
|
|
5177
|
+
bun run build
|
|
5178
|
+
bun start
|
|
5179
|
+
\`\`\`
|
|
5180
|
+
`;
|
|
5181
|
+
}
|
|
5182
|
+
};
|
|
5183
|
+
|
|
4259
5184
|
// src/Scaffold.ts
|
|
4260
5185
|
var Scaffold = class {
|
|
4261
5186
|
templatesDir;
|
|
@@ -4289,6 +5214,11 @@ var Scaffold = class {
|
|
|
4289
5214
|
name: "Action Domain",
|
|
4290
5215
|
description: "Single Action Controllers pattern for high-clarity APIs"
|
|
4291
5216
|
},
|
|
5217
|
+
{
|
|
5218
|
+
type: "standalone-engine",
|
|
5219
|
+
name: "Standalone Engine",
|
|
5220
|
+
description: "High-performance pure Gravito Engine (minimal)"
|
|
5221
|
+
},
|
|
4292
5222
|
{
|
|
4293
5223
|
type: "satellite",
|
|
4294
5224
|
name: "Gravito Satellite",
|
|
@@ -4364,6 +5294,8 @@ var Scaffold = class {
|
|
|
4364
5294
|
return new ActionDomainGenerator(config);
|
|
4365
5295
|
case "satellite":
|
|
4366
5296
|
return new SatelliteGenerator(config);
|
|
5297
|
+
case "standalone-engine":
|
|
5298
|
+
return new StandaloneEngineGenerator(config);
|
|
4367
5299
|
default:
|
|
4368
5300
|
throw new Error(`Unknown architecture type: ${type}`);
|
|
4369
5301
|
}
|