@h-ai/cli 0.1.0-alpha9 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +229 -0
- package/README.ja.md +229 -0
- package/README.md +175 -113
- package/dist/chunk-AKV2CQZV.js +1497 -0
- package/dist/chunk-AKV2CQZV.js.map +1 -0
- package/dist/chunk-EF7WOFWZ.js +7557 -0
- package/dist/chunk-EF7WOFWZ.js.map +1 -0
- package/dist/chunk-MUHRBJSW.js +29272 -0
- package/dist/chunk-MUHRBJSW.js.map +1 -0
- package/dist/chunk-ZSDEVXZ7.js +38 -0
- package/dist/{chunk-2H7UOFLK.js.map → chunk-ZSDEVXZ7.js.map} +1 -1
- package/dist/cli-config-templates-HHFHNXBN.js +5 -0
- package/dist/cli-config-templates-HHFHNXBN.js.map +1 -0
- package/dist/cli-skill-templates-PN4FLGBC.js +5 -0
- package/dist/cli-skill-templates-PN4FLGBC.js.map +1 -0
- package/dist/index.js +4444 -554
- package/dist/index.js.map +1 -1
- package/dist/metafile-esm.json +1 -0
- package/dist/src-TEBHR5I5.js +5 -0
- package/dist/src-TEBHR5I5.js.map +1 -0
- package/package.json +35 -15
- package/templates/README.md +56 -114
- package/templates/apps/admin/messages/en-US.json +7 -0
- package/templates/apps/admin/messages/ja-JP.json +40 -0
- package/templates/apps/admin/messages/zh-CN.json +7 -0
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +65 -8
- package/templates/apps/admin/src/routes/+page.svelte.hbs +35 -14
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +54 -22
- package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +33 -24
- package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +16 -13
- package/templates/apps/api/.dockerignore.hbs +25 -0
- package/templates/apps/api/.gitignore.hbs +22 -0
- package/templates/apps/api/.npmrc.hbs +1 -0
- package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +39 -0
- package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +41 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/app-contract.ts.hbs +27 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +28 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/index.ts.hbs +5 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +16 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tests/contract.test.ts.hbs +18 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tsconfig.json.hbs +12 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +11 -0
- package/templates/apps/api/apps/{{projectName}}-contract/vitest.config.ts.hbs +9 -0
- package/templates/apps/api/apps/{{projectName}}-serv/README.md.hbs +60 -0
- package/templates/apps/api/apps/{{projectName}}-serv/config/_core.yml.hbs +17 -0
- package/templates/apps/api/apps/{{projectName}}-serv/config/_serv.yml.hbs +54 -0
- package/templates/apps/api/apps/{{projectName}}-serv/data/.gitkeep.hbs +1 -0
- package/templates/apps/api/apps/{{projectName}}-serv/package.json.hbs +66 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/app.ts.hbs +119 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/build-metadata.ts.hbs +7 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/index.ts.hbs +41 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/lib/server/init.ts.hbs +165 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +57 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/server/procedures/index.ts.hbs +41 -0
- package/templates/apps/api/apps/{{projectName}}-serv/tests/service.test.ts.hbs +176 -0
- package/templates/apps/api/apps/{{projectName}}-serv/tsconfig.json.hbs +16 -0
- package/templates/apps/api/apps/{{projectName}}-serv/tsup.config.ts.hbs +20 -0
- package/templates/apps/api/apps/{{projectName}}-serv/vitest.config.ts.hbs +12 -0
- package/templates/apps/api/e2e/api-serv.spec.ts.hbs +113 -0
- package/templates/apps/api/e2e/capture-evidence.ts.hbs +23 -0
- package/templates/apps/api/eslint.config.js.hbs +30 -0
- package/templates/apps/api/hai.json.hbs +4 -0
- package/templates/apps/api/images/serv.Dockerfile.hbs +37 -0
- package/templates/apps/api/package.json.hbs +53 -0
- package/templates/apps/api/playwright.config.ts.hbs +67 -0
- package/templates/apps/api/pnpm-workspace.yaml.hbs +40 -0
- package/templates/apps/api/tsconfig.base.json +14 -0
- package/templates/apps/fullstack/.dockerignore.hbs +25 -0
- package/templates/apps/fullstack/.gitignore.hbs +38 -0
- package/templates/apps/fullstack/.npmrc.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/.env.example.hbs +10 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +67 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +22 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/ja-JP.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +86 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/public/runtime-config.js.hbs +4 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +59 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.css.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +8 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/build-metadata.ts.hbs +9 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +19 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/main.ts.hbs +21 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +16 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/tsconfig.json.hbs +23 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +74 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/.env.example.hbs +6 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +64 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/index.html.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/en-US.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/ja-JP.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/zh-CN.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +66 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +25 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.css.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.d.ts.hbs +8 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/build-metadata.ts.hbs +9 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/main.ts.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +33 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/build.rs.hbs +6 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/capabilities/default.json.hbs +16 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128.png +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128@2x.png +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/32x32.png +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.icns +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.ico +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +91 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/main.rs.hbs +8 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +46 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +14 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/tsconfig.json.hbs +22 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +89 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +25 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/en-US.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/ja-JP.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/zh-CN.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +54 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +21 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/en-US.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/ja-JP.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/zh-CN.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +53 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/public/runtime-config.js.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/App.svelte.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.css.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +8 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/build-metadata.ts.hbs +9 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +14 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +16 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/tsconfig.json.hbs +23 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +76 -0
- package/templates/apps/fullstack/docs/security-configuration.md.hbs +349 -0
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +988 -0
- package/templates/apps/fullstack/e2e/session-close.spec.ts.hbs +119 -0
- package/templates/apps/fullstack/eslint.config.js.hbs +41 -0
- package/templates/apps/fullstack/hai.json.hbs +11 -0
- package/templates/apps/fullstack/images/serv.Dockerfile.hbs +38 -0
- package/templates/apps/fullstack/images/web/19-runtime-config.envsh.hbs +5 -0
- package/templates/apps/fullstack/images/web/nginx.conf.hbs +24 -0
- package/templates/apps/fullstack/images/web/runtime-config.js.template.hbs +3 -0
- package/templates/apps/fullstack/images/web.Dockerfile.hbs +37 -0
- package/templates/apps/fullstack/package.json.hbs +61 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +40 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +30 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +78 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +134 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-contract.ts.hbs +20 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-schemas.ts.hbs +35 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +7 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +23 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tests/contract.test.ts.hbs +31 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tsconfig.json.hbs +9 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +9 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +84 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_ai.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_audit.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_cache.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +22 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_db.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_feedback.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_iam.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_payment.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_reach.yml.hbs +60 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_scheduler.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +64 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_storage.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_vecdb.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/data/.gitkeep.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +62 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +115 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/build-metadata.ts.hbs +7 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +40 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +294 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/audit-jobs.ts.hbs +28 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/business-settings.ts.hbs +50 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/messages.ts.hbs +50 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +106 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +49 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +34 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +159 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/security-roles.ts.hbs +73 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +505 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/runtime.test.ts.hbs +72 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/security.test.ts.hbs +183 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tsconfig.json.hbs +10 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +18 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/vitest.config.ts.hbs +12 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/.gitignore.hbs +10 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +97 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +164 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/ja-JP.json.hbs +164 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +164 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +55 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/project.inlang/settings.json.hbs +11 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +7 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +94 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/feedback-client.ts.hbs +36 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/sensitive-actions.svelte.ts.hbs +16 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/session-recovery.svelte.ts.hbs +4 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +122 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +90 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/FeedbackEntry.svelte.hbs +86 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/audit.svelte.hbs +94 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/configuration.svelte.hbs +25 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/feedback.svelte.hbs +157 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/roles.svelte.hbs +77 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +44 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/users.svelte.hbs +216 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/security/role-label.ts.hbs +12 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/guide-store.ts.hbs +55 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +614 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme-store.svelte.ts.hbs +23 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/svelte.config.js.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +150 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +253 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tsconfig.json.hbs +17 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/vitest.config.ts.hbs +7 -0
- package/templates/apps/fullstack/playwright.config.ts.hbs +114 -0
- package/templates/apps/fullstack/playwright.session-close.config.ts.hbs +18 -0
- package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +38 -0
- package/templates/apps/fullstack/tsconfig.base.json +14 -0
- package/templates/apps/h5/messages/en-US.json +3 -0
- package/templates/apps/h5/messages/ja-JP.json +40 -0
- package/templates/apps/h5/messages/zh-CN.json +3 -0
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +85 -30
- package/templates/apps/h5/src/routes/+page.svelte.hbs +20 -8
- package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +17 -6
- package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +17 -6
- package/templates/apps/mobile-app/.env.hbs +3 -0
- package/templates/apps/{android-app → mobile-app}/capacitor.config.ts.hbs +2 -2
- package/templates/apps/mobile-app/index.html.hbs +14 -0
- package/templates/apps/mobile-app/messages/en-US.json +36 -0
- package/templates/apps/mobile-app/messages/ja-JP.json +36 -0
- package/templates/apps/mobile-app/messages/zh-CN.json +36 -0
- package/templates/apps/mobile-app/public/runtime-config.js +1 -0
- package/templates/apps/mobile-app/src/App.svelte.hbs +153 -0
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +213 -0
- package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +14 -0
- package/templates/apps/{android-app → mobile-app}/src/lib/capacitor.ts +6 -7
- package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +58 -0
- package/templates/apps/mobile-app/src/lib/pages/profile.svelte.hbs +13 -0
- package/templates/apps/mobile-app/src/lib/pages/tasks.svelte.hbs +16 -0
- package/templates/apps/mobile-app/src/main.ts.hbs +11 -0
- package/templates/apps/website/messages/en-US.json +4 -2
- package/templates/apps/website/messages/ja-JP.json +34 -0
- package/templates/apps/website/messages/zh-CN.json +4 -2
- package/templates/apps/website/scripts/static-website.mjs.hbs +67 -0
- package/templates/apps/website/src/routes/+layout.svelte.hbs +77 -26
- package/templates/apps/website/src/routes/+layout.ts +3 -0
- package/templates/apps/website/src/routes/+page.svelte.hbs +31 -12
- package/templates/apps/website/src/routes/about/+page.svelte.hbs +11 -6
- package/templates/apps/website/src/routes/api/health/+server.ts +3 -0
- package/templates/apps/website/src/routes/contact/+page.svelte.hbs +44 -34
- package/templates/apps/website/src/routes/services/+page.svelte.hbs +27 -40
- package/templates/base/.dockerignore.hbs +27 -0
- package/templates/base/.gitignore.hbs +41 -0
- package/templates/base/.npmrc.hbs +1 -0
- package/templates/base/e2e/app.spec.ts.hbs +213 -0
- package/templates/base/e2e/helpers.ts +1 -1
- package/templates/base/eslint-rules.js +45 -0
- package/templates/base/eslint.config.js.hbs +34 -0
- package/templates/base/hai.json.hbs +4 -0
- package/templates/base/images/web/nginx.conf.hbs +24 -0
- package/templates/base/images/web.Dockerfile.hbs +72 -0
- package/templates/base/package.json.hbs +125 -49
- package/templates/base/playwright.config.ts +44 -6
- package/templates/base/pnpm-workspace.yaml.hbs +40 -0
- package/templates/base/src/app.css.hbs +40 -0
- package/templates/base/src/app.d.ts.hbs +14 -1
- package/templates/base/src/app.html.hbs +13 -0
- package/templates/base/src/hooks.server.ts.hbs +115 -43
- package/templates/base/src/lib/build-metadata.ts.hbs +7 -0
- package/templates/base/src/lib/server/init.ts.hbs +125 -152
- package/templates/base/src/lib/server/kit-config.ts.hbs +40 -0
- package/templates/base/src/routes/+layout.server.ts.hbs +35 -0
- package/templates/base/static/favicon.png +0 -0
- package/templates/base/svelte.config.js.hbs +84 -5
- package/templates/base/tests/scaffold.test.ts.hbs +102 -0
- package/templates/base/tsconfig.json.hbs +50 -0
- package/templates/base/vite.config.ts.hbs +117 -12
- package/templates/base/vitest.config.ts.hbs +19 -0
- package/templates/features/ai/routes/api/chat/+server.ts +6 -7
- package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +3 -17
- package/templates/features/iam/routes-admin/(auth)/auth/forgot-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +9 -96
- package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +9 -122
- package/templates/features/iam/routes-admin/(auth)/auth/reset-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-h5/auth/forgot-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +9 -96
- package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +9 -112
- package/templates/features/iam/routes-h5/auth/reset-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-shared/api/auth/captcha/+server.ts.hbs +4 -0
- package/templates/features/iam/routes-shared/api/auth/config/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/login/+server.ts +1 -29
- package/templates/features/iam/routes-shared/api/auth/login/ldap/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/login/otp/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +13 -6
- package/templates/features/iam/routes-shared/api/auth/otp/send/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/password/renew/+server.ts +5 -0
- package/templates/features/iam/routes-shared/api/auth/password-reset/confirm/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/password-reset/request/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/reauthenticate/+server.ts +5 -0
- package/templates/features/iam/routes-shared/api/auth/register/+server.ts +1 -23
- package/templates/features/iam/routes-shared/api/auth/session/close/+server.ts.hbs +4 -0
- package/templates/features/iam/routes-website/auth/forgot-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-website/auth/login/+page.svelte.hbs +11 -0
- package/templates/features/iam/routes-website/auth/register/+page.svelte.hbs +11 -0
- package/templates/features/iam/routes-website/auth/reset-password/+page.svelte.hbs +10 -0
- package/templates/features/payment/routes/api/v1/payment/create/+server.ts +25 -23
- package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +5 -2
- package/templates/features/storage/routes/api/upload/+server.ts +10 -8
- package/templates/i18n/project.inlang/settings.json +2 -2
- package/templates/shared/.gitattributes +11 -0
- package/templates/shared/build-metadata.ts +42 -0
- package/templates/shared/container-runtime-config.sh +30 -0
- package/templates/shared/e2e-env.ts +98 -0
- package/templates/shared/hash-router.svelte.ts +83 -0
- package/templates/shared/public-base-path.mjs +19 -0
- package/templates/shared/run-e2e.mjs +104 -0
- package/templates/shared/vite-runtime-config.ts +56 -0
- package/templates/skills/AGENTS.md +75 -16
- package/templates/skills/CLAUDE.md +0 -11
- package/templates/skills/bridges/admin/AGENTS.md +89 -0
- package/templates/skills/bridges/api/AGENTS.md +83 -0
- package/templates/skills/bridges/fullstack/AGENTS.md.hbs +102 -0
- package/templates/skills/bridges/h5/AGENTS.md +88 -0
- package/templates/skills/bridges/mobile-app/AGENTS.md +100 -0
- package/templates/skills/bridges/website/AGENTS.md +88 -0
- package/templates/skills/copilot-instructions.md +3 -59
- package/templates/skills/hai-ai/SKILL.md +44 -715
- package/templates/skills/hai-ai/guide.md +457 -0
- package/templates/skills/hai-ai/reference.md +292 -0
- package/templates/skills/hai-api-client/SKILL.md +26 -339
- package/templates/skills/hai-api-client/reference.md +180 -0
- package/templates/skills/hai-api-contract/SKILL.md +36 -0
- package/templates/skills/hai-api-contract/reference.md +280 -0
- package/templates/skills/hai-app-create/SKILL.md +38 -351
- package/templates/skills/hai-app-create/collaboration.md +52 -0
- package/templates/skills/hai-app-create/development.md +243 -0
- package/templates/skills/hai-app-create/reference.md +376 -0
- package/templates/skills/hai-app-review/SKILL.md +57 -126
- package/templates/skills/hai-app-review/differential.md +34 -0
- package/templates/skills/hai-app-tests/SKILL.md +34 -454
- package/templates/skills/hai-app-tests/reference.md +462 -0
- package/templates/skills/hai-app-tests/validation.md +42 -0
- package/templates/skills/hai-audit/SKILL.md +37 -122
- package/templates/skills/hai-audit/reference.md +184 -0
- package/templates/skills/hai-build/SKILL.md +62 -315
- package/templates/skills/hai-build/paths.md +30 -0
- package/templates/skills/hai-build/reference.md +353 -0
- package/templates/skills/hai-cache/SKILL.md +26 -175
- package/templates/skills/hai-cache/reference.md +229 -0
- package/templates/skills/hai-capacitor/SKILL.md +24 -364
- package/templates/skills/hai-capacitor/reference.md +358 -0
- package/templates/skills/hai-change-plan/SKILL.md +46 -0
- package/templates/skills/hai-ci/SKILL.md +114 -0
- package/templates/skills/hai-core/SKILL.md +31 -469
- package/templates/skills/hai-core/reference.md +557 -0
- package/templates/skills/hai-core/request-access.md +65 -0
- package/templates/skills/hai-crypto/SKILL.md +29 -180
- package/templates/skills/hai-crypto/reference.md +317 -0
- package/templates/skills/hai-datapipe/SKILL.md +24 -207
- package/templates/skills/hai-datapipe/reference.md +204 -0
- package/templates/skills/hai-deploy/SKILL.md +53 -178
- package/templates/skills/hai-deploy/credentials.md +19 -0
- package/templates/skills/hai-deploy/middleware.md +129 -0
- package/templates/skills/hai-feedback/SKILL.md +85 -0
- package/templates/skills/hai-framework-sync/SKILL.md +105 -0
- package/templates/skills/hai-framework-sync/sync.md +49 -0
- package/templates/skills/hai-iam/SKILL.md +53 -325
- package/templates/skills/hai-iam/reference.md +535 -0
- package/templates/skills/hai-kit/SKILL.md +33 -329
- package/templates/skills/hai-kit/reference.md +202 -0
- package/templates/skills/hai-payment/SKILL.md +28 -262
- package/templates/skills/hai-payment/reference.md +295 -0
- package/templates/skills/hai-pr-review/SKILL.md +41 -0
- package/templates/skills/hai-reach/SKILL.md +28 -300
- package/templates/skills/hai-reach/reference.md +363 -0
- package/templates/skills/hai-reldb/SKILL.md +28 -449
- package/templates/skills/hai-reldb/reference.md +500 -0
- package/templates/skills/hai-scheduler/SKILL.md +26 -174
- package/templates/skills/hai-scheduler/reference.md +216 -0
- package/templates/skills/hai-serv/SKILL.md +60 -0
- package/templates/skills/hai-serv/reference.md +792 -0
- package/templates/skills/hai-spec-implement/SKILL.md +50 -0
- package/templates/skills/hai-spec-implement/changes.md +67 -0
- package/templates/skills/hai-spec-implement/evaluation.md +18 -0
- package/templates/skills/hai-spec-implement/handoff.md +47 -0
- package/templates/skills/hai-spec-implement/templates.md +117 -0
- package/templates/skills/hai-spec-implement/workflow.md +56 -0
- package/templates/skills/hai-spec-review/SKILL.md +57 -0
- package/templates/skills/hai-spec-review/checklist.md +71 -0
- package/templates/skills/hai-storage/SKILL.md +31 -262
- package/templates/skills/hai-storage/reference.md +284 -0
- package/templates/skills/hai-ui/SKILL.md +62 -238
- package/templates/skills/hai-ui/guide.md +81 -0
- package/templates/skills/hai-ui/reference.md +705 -0
- package/templates/skills/hai-ui-design/SKILL.md +31 -0
- package/templates/skills/hai-ui-design/patterns.md +31 -0
- package/templates/skills/hai-ui-review/SKILL.md +32 -0
- package/templates/skills/hai-ui-review/checklist.md +29 -0
- package/templates/skills/hai-vecdb/SKILL.md +25 -267
- package/templates/skills/hai-vecdb/reference.md +325 -0
- package/templates/skills/opencode.json +0 -5
- package/dist/chunk-2H7UOFLK.js +0 -10
- package/dist/chunk-LANIDJC7.js +0 -659
- package/dist/chunk-LANIDJC7.js.map +0 -1
- package/dist/chunk-YV7WPUI6.js +0 -206
- package/dist/chunk-YV7WPUI6.js.map +0 -1
- package/dist/config-templates-S5RI2MC6.js +0 -5
- package/dist/config-templates-S5RI2MC6.js.map +0 -1
- package/dist/skill-templates-N5DU5FNX.js +0 -5
- package/dist/skill-templates-N5DU5FNX.js.map +0 -1
- package/dist/src-XJ6YXNAF.js +0 -15030
- package/dist/src-XJ6YXNAF.js.map +0 -1
- package/templates/apps/android-app/.env.hbs +0 -3
- package/templates/apps/android-app/messages/en-US.json +0 -24
- package/templates/apps/android-app/messages/zh-CN.json +0 -24
- package/templates/apps/android-app/src/lib/api.ts.hbs +0 -30
- package/templates/apps/android-app/src/routes/+layout.svelte.hbs +0 -42
- package/templates/apps/android-app/src/routes/+layout.ts +0 -7
- package/templates/apps/android-app/src/routes/+page.svelte.hbs +0 -27
- package/templates/apps/api/src/routes/+layout.svelte +0 -14
- package/templates/apps/api/src/routes/+page.svelte +0 -11
- package/templates/apps/api/src/routes/api/v1/health/+server.ts +0 -14
- package/templates/apps/api/src/routes/api/v1/items/+server.ts +0 -37
- package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +0 -30
- package/templates/base/src/app.css +0 -2
- package/templates/base/tsconfig.json +0 -8
|
@@ -1,354 +1,58 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hai-kit
|
|
3
|
-
description:
|
|
3
|
+
description: "在 SvelteKit 中接入 hooks、认证守卫、输入校验、响应和同源加密客户端;不用于独立 serv 服务。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# hai-kit
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
限流采用首次成功提交为起点的固定窗口,后续请求不延长 TTL。必须显式传 store;应用先检查共享 Redis 初始化结果,所有节点使用相同 namespace/windowMs/maxRequests。缓存读取/条件提交失败或冲突耗尽返回503,超限429;不会回退 get+set 或本地计数。createMemoryRateLimitStore 仅开发或显式 HAI_E2E/HAI_E2E_MOCK 测试使用,无常驻定时器,丢弃引用即可回收;每次请求最多惰性扫描 64 项,最多保存 10000 个窗口,容量满时对新 key 返回503且不驱逐有效计数,外部 store 生命周期由创建者管理;生产不得设置测试开关。响应重置时间为节点时钟估算,实际窗口由 Redis TTL 决定,须同步时钟。默认键只读取可信 adapter 的 getClientAddress、规范化等价IPv6和IPv4映射地址,不采信原始转发头;代理信任通过部署adapter配置。
|
|
9
9
|
|
|
10
|
-
-
|
|
11
|
-
- 安全边界:`guard` / `middleware`
|
|
12
|
-
- API 工具:`handler` / `response` / `validate`
|
|
13
|
-
- Bearer Token 认证:从 `Authorization` header 解析,SSR 端通过 `hai_token` Cookie 透传
|
|
14
|
-
- 契约处理:`fromContract(endpoint, fn)` — 基于 EndpointDef 的类型安全 handler
|
|
15
|
-
- 双构建模式:`createAdapter()` 根据环境变量选择 adapter-node 或 adapter-static
|
|
10
|
+
transport 仅支持 v2:SM2 发送方签名、独立密钥的 Encrypt-then-HMAC、HTTP 上下文/响应状态绑定及共享原子防重放。GET/HEAD、空 POST 与空响应也认证;无降级开关。TLS 信任边界、5 分钟窗口、nonce 持久化与实现示例见 [参考](reference.md)。
|
|
16
11
|
|
|
17
|
-
##
|
|
12
|
+
## 能力契约
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
| 项目 | 契约 |
|
|
15
|
+
| -------- | ------------------------------------------------------------------------------------------------------- |
|
|
16
|
+
| 能力 | 使用 @h-ai/kit 集成 SvelteKit hooks、守卫、校验、响应及同源客户端传输 |
|
|
17
|
+
| 适用场景 | SvelteKit hooks、load 和同源端点集成 |
|
|
18
|
+
| 输入 | SvelteKit handle/RequestEvent、schema、guard、transport |
|
|
19
|
+
| 输出 | handle、Response、校验值和客户端请求结果 |
|
|
20
|
+
| 限制 | 无 init/close;保留 SvelteKit 控制流异常。跨端共享 HTTP contract 用 api-contract + serv,勿复制到 kit。 |
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
- `kit.createHandle` / `kit.sequence`
|
|
23
|
-
- `kit.guard.*`(`require` / `check`)
|
|
24
|
-
- `kit.handler` / `kit.response` / `kit.validate`
|
|
25
|
-
- `kit.fromContract(endpoint, fn)` — 契约到 SvelteKit handler
|
|
26
|
-
- `kit.client.create()` — 浏览器端统一 API 客户端(`apiFetch`)
|
|
27
|
-
- `kit.auth.createTokenStore()` — 浏览器端 Token 存储
|
|
28
|
-
- `kit.auth.createHandleFetch()` — `hooks.client.ts` 自动附加 Token
|
|
29
|
-
- Bearer Token / `Authorization` header
|
|
30
|
-
- CORS 配置(含 Capacitor Origin 预设)
|
|
31
|
-
- 传输加密(key exchange / `X-Client-Id`)
|
|
22
|
+
容量通过 resolveTransportBodyLimits(explicitLimit, { requiredPlaintextBytes }) 合并:省略/auto 才按模块需求推导,显式整数不足时报错,不得静默取大或覆盖。Serv/Kit auto 解析为 undefined;部署代理和 BODY_SIZE_LIMIT 与运行时复用同一结果,反馈业务预算独立。
|
|
32
23
|
|
|
33
|
-
|
|
24
|
+
## 使用路径
|
|
34
25
|
|
|
35
|
-
|
|
26
|
+
1. 仅在 SvelteKit 集成;先查现有 hooks、配置、守卫与路由,不将其套用于独立 serv 应用。
|
|
27
|
+
2. 用 createHandle 编排已初始化模块;认证 API 与公开路径复用 kit.auth,客户端复用框架动作。
|
|
28
|
+
3. 区分返回 HaiResult 的业务操作与抛 Response/redirect/error 的框架控制流,不吞掉控制流。
|
|
29
|
+
4. 对齐 Cookie/CSRF/transport 与服务端配置,验证匿名、登录、权限拒绝和表单失败。
|
|
36
30
|
|
|
37
|
-
|
|
38
|
-
| --- | --- | --- | --- |
|
|
39
|
-
| `@h-ai/iam` | 身份认证与授权(A2A 认证) | 可选 | 使用 A2A 功能时需在 kit 使用前初始化 |
|
|
40
|
-
| `@h-ai/crypto` | 加密(传输加密 / Cookie 加密) | 可选 | 启用加密时需在 kit 使用前初始化 |
|
|
31
|
+
默认请求日志支持 prerender:查询应从独立 `new URL(event.request.url)` 读取,路径保留 `event.url.pathname`,不为观测读取跟踪 URL 的 search/searchParams 而建立页面依赖或触发静态构建错误。保持默认日志开启、JSON 正文日志默认关闭;查询/可选正文先脱敏再写 trace,正文读取副本,不能消耗业务请求。页面业务确实依赖查询时仍按 SvelteKit 的动态路由条件处理,不用日志绕过来声明业务可静态生成。
|
|
41
32
|
|
|
42
|
-
|
|
33
|
+
Kit 自动请求审计与 Serv 一样,仅在请求时发现 audit.isInitialized 才写入;未选 Audit 的站点不因默认 handle 产生未初始化错误。选择 Audit 时检查 init 结果并失败停止启动;显式业务审计仍遵守初始化和事务合同,已就绪模块写入失败必须保留诊断,不能当作可选模块静默跳过。handle 创建早于模块初始化时不能在装配阶段把审计永久禁用。
|
|
43
34
|
|
|
44
|
-
|
|
35
|
+
服务端 transport 使用含受管 serverKeyRing、共享 keyStore 的对象,不再接受单独 true。公开 _kit.yml 只保留路径/开关,不放私钥;浏览器无 ring。请求携带协商 serverKeyId,各节点同 ring + registry,不依赖粘性路由;轮换见 hai-crypto。
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
import { kit } from '@h-ai/kit'
|
|
37
|
+
传输加密按实际请求/响应 body 判断空正文,不信任 Content-Type/Length;非空明文不能借缺头、chunked 或伪造零长度旁路,实际空流保留无 input POST 行为。
|
|
48
38
|
|
|
49
|
-
|
|
50
|
-
auth: {
|
|
51
|
-
verifyToken: async token => token
|
|
52
|
-
? { userId: 'u_1', roles: ['admin'], permissions: ['user:read'] }
|
|
53
|
-
: null,
|
|
54
|
-
loginUrl: '/auth/login',
|
|
55
|
-
protectedPaths: ['/admin/*', '/api/*'],
|
|
56
|
-
publicPaths: ['/api/auth/*', '/api/public/*'],
|
|
57
|
-
},
|
|
58
|
-
rateLimit: { windowMs: 60_000, maxRequests: 100 },
|
|
59
|
-
logging: true,
|
|
60
|
-
cors: {
|
|
61
|
-
origins: ['https://example.com'],
|
|
62
|
-
capacitor: true, // 自动添加 capacitor://localhost 等原生 App Origin
|
|
63
|
-
},
|
|
64
|
-
})
|
|
65
|
-
```
|
|
39
|
+
业务容量统一配置 transport.maxPlaintextBytes:UTF-8 JSON 明文字节,默认 1 MiB,有效整数范围 1 KiB~64 MiB,请求和响应共用。客户端从握手获取服务端预算,可选本地上限取较小值;resolveTransportBodyLimits 自动推导密文预算为两倍明文加 32 KiB。握手 JSON 16 KiB、公钥 4 KiB、认证头 16 KiB、路径 8 KiB、认证及防重放保持独立。原流超限/取消立即停止、取消并释放 reader;请求 413、响应返回加密的 500 容量错误,客户端识别 TransportBodyTooLargeError / hai:crypto:070。 通过 _kit.yml 的 transport.maxPlaintextBytes 或对应 HAI_*_TRANSPORT_MAXPLAINTEXTBYTES 配置并转发到服务端 transport;重建正文保留 signal 并删除旧长度/编码头。
|
|
66
40
|
|
|
67
|
-
|
|
41
|
+
错误提示与诊断分离:HTTP/UI 边界用 core.error.toPublic,仅公开 i18n 安全消息及 error.traceId;重新翻译后用 core.error.formatMessage 保留关联。ToastContainer 默认只显示可读说明,自动将编号移入排查信息图标,展开后可查看、复制并提供给客户支持或开发人员。前后端日志传完整 Error 和操作上下文,使用同一 requestId/traceId 并脱敏;禁止只写通用错误标题,也不能把 cause/ext/SQL/绑定值直接返回用户。数据库日志保留安全的驱动错误码、消息和堆栈。
|
|
68
42
|
|
|
69
|
-
|
|
70
|
-
import { kit } from '@h-ai/kit'
|
|
71
|
-
import { z } from 'zod'
|
|
43
|
+
## 按需参考
|
|
72
44
|
|
|
73
|
-
|
|
45
|
+
按路径/IP/时间检查每次请求、真实 IP 与独立文件见[请求访问控制](../hai-core/request-access.md)。完整 Kit 配置只在服务端读取,浏览器接收 transport 等公开投影。
|
|
74
46
|
|
|
75
|
-
|
|
76
|
-
kit.guard.require(locals.session, 'user:create')
|
|
77
|
-
const data = await kit.validate.body(request, CreateSchema)
|
|
78
|
-
return kit.response.created(data)
|
|
79
|
-
})
|
|
80
|
-
```
|
|
47
|
+
按本次操作读取对应小节;以已安装版本的公开类型核验签名,示例中的业务变量由应用提供。
|
|
81
48
|
|
|
82
|
-
|
|
49
|
+
- [使用步骤](reference.md#使用步骤)
|
|
50
|
+
- [核心 API](reference.md#核心-api)
|
|
51
|
+
- [常见模式](reference.md#常见模式)
|
|
52
|
+
- [声明式 CRUD 表单字段](reference.md#声明式-crud-表单字段)
|
|
83
53
|
|
|
84
|
-
|
|
85
|
-
import { iam } from '@h-ai/iam'
|
|
86
|
-
import { iamEndpoints } from '@h-ai/iam/api'
|
|
87
|
-
import { kit } from '@h-ai/kit'
|
|
54
|
+
Node 请求/SSR 必须用 `core.i18n.runWithLocale(locale, callback)`(kit 同名方法)包裹实际异步 resolve;serv 自动建立请求语言上下文。浏览器 setGlobalLocale/createLocaleStore 继续管理应用语言,SSR 的 UI setter/store 不写全局值。显式 MessageOptions.locale 优先;进程默认语言仅在启动时设置。
|
|
88
55
|
|
|
89
|
-
|
|
90
|
-
export const POST = kit.fromContract(iamEndpoints.login, async (input, event) => {
|
|
91
|
-
const result = await iam.auth.login(input)
|
|
92
|
-
if (!result.success) {
|
|
93
|
-
return kit.response.unauthorized(result.error.message)
|
|
94
|
-
}
|
|
95
|
-
return kit.response.ok(result.data)
|
|
96
|
-
})
|
|
97
|
-
```
|
|
56
|
+
认证 Cookie 在 NODE_ENV 或 HAI_CORE_ENV 为 production 时默认启用 Secure,HAI_E2E/HAI_E2E_MOCK 不降低 Cookie 安全;限流生产判断也识别这两个环境标志,测试开关仅放宽共享状态要求。
|
|
98
57
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
```typescript
|
|
102
|
-
export const handle = kit.createHandle({
|
|
103
|
-
cors: {
|
|
104
|
-
origins: ['https://example.com', 'https://*.example.com'], // 支持通配符
|
|
105
|
-
capacitor: true, // 自动添加 capacitor://localhost, ionic://localhost 等
|
|
106
|
-
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
107
|
-
credentials: true,
|
|
108
|
-
},
|
|
109
|
-
})
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### 5) 需要传输加密时启用 `crypto` 配置
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
import { crypto } from '@h-ai/crypto'
|
|
116
|
-
import { kit } from '@h-ai/kit'
|
|
117
|
-
|
|
118
|
-
export const handle = kit.createHandle({
|
|
119
|
-
crypto: {
|
|
120
|
-
crypto,
|
|
121
|
-
transport: true,
|
|
122
|
-
cookieEncryptionKey: process.env.HAI_KIT_COOKIE_KEY,
|
|
123
|
-
},
|
|
124
|
-
})
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## 核心 API
|
|
128
|
-
|
|
129
|
-
| API | 用途 | 关键点 |
|
|
130
|
-
| --------------------------- | ---------------------- | --------------------------------------------- |
|
|
131
|
-
| `kit.createHandle(config?)` | 创建 SvelteKit Handle | Bearer Token 解析、守卫、中间件、CORS |
|
|
132
|
-
| `kit.sequence(...handles)` | 组合多个 Handle | 洋葱模型顺序执行 |
|
|
133
|
-
| `kit.handler(fn)` | 包装 API 处理函数 | 非控制流异常统一转 500 |
|
|
134
|
-
| `kit.fromContract(ep, fn)` | 契约到 handler | 自动 Zod 入参校验,类型安全 |
|
|
135
|
-
| `kit.guard.*` | 权限守卫 | `require`(throw 式) / `check`(布尔) |
|
|
136
|
-
| `kit.response.*` | 标准化响应 | 统一 `{ success, data?, error?, requestId? }` |
|
|
137
|
-
| `kit.validate.*` | 请求体/查询/参数校验 | 失败 throw Response(SvelteKit 控制流) |
|
|
138
|
-
| `defineEndpoint(def)` | 定义 EndpointDef 契约 | 与 api-client 配合使用 |
|
|
139
|
-
|
|
140
|
-
### EndpointDef 契约
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
import { defineEndpoint } from '@h-ai/kit'
|
|
144
|
-
import { z } from 'zod'
|
|
145
|
-
|
|
146
|
-
const myEndpoint = defineEndpoint({
|
|
147
|
-
method: 'POST',
|
|
148
|
-
path: '/api/v1/items',
|
|
149
|
-
input: z.object({ name: z.string() }),
|
|
150
|
-
output: z.object({ id: z.string(), name: z.string() }),
|
|
151
|
-
requireAuth: true,
|
|
152
|
-
})
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## 错误码(常见)
|
|
156
|
-
|
|
157
|
-
### API 响应错误码(`kit.response`)
|
|
158
|
-
|
|
159
|
-
| code | status | 场景 |
|
|
160
|
-
| ------------------ | ------ | ------------------ |
|
|
161
|
-
| `BAD_REQUEST` | 400 | 参数或请求格式错误 |
|
|
162
|
-
| `UNAUTHORIZED` | 401 | 未认证 |
|
|
163
|
-
| `FORBIDDEN` | 403 | 无权限 |
|
|
164
|
-
| `NOT_FOUND` | 404 | 资源不存在 |
|
|
165
|
-
| `CONFLICT` | 409 | 资源冲突 |
|
|
166
|
-
| `VALIDATION_ERROR` | 422 | 数据校验失败 |
|
|
167
|
-
| `INTERNAL_ERROR` | 500 | 未处理异常 |
|
|
168
|
-
|
|
169
|
-
## API 契约范式(端到端类型安全)
|
|
170
|
-
|
|
171
|
-
> `kit.fromContract` 和 `api.call` 共同消费模块 `api/` 下的 `EndpointDef`,实现服务端↔客户端的全链路类型安全 + 运行时 Zod 校验。
|
|
172
|
-
|
|
173
|
-
### 服务端流程(本模块责任)
|
|
174
|
-
|
|
175
|
-
1. 从 `@h-ai/xx/api` 导入 `xxEndpoints`
|
|
176
|
-
2. `kit.fromContract(xxEndpoints.xxx, handler)` → 自动 Zod 校验入参 → handler 获得类型安全的 `input`
|
|
177
|
-
3. 需权限时在 handler 内调用 `kit.guard.require`
|
|
178
|
-
|
|
179
|
-
### 多模块契约示例
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
// ─── 存储:预签名上传 ───
|
|
183
|
-
import { storageEndpoints } from '@h-ai/storage/api'
|
|
184
|
-
import { storage } from '$lib/server/init'
|
|
185
|
-
|
|
186
|
-
export const POST = kit.fromContract(storageEndpoints.presignUpload, async (input, event) => {
|
|
187
|
-
kit.guard.require(event.locals.session, 'storage:write')
|
|
188
|
-
const result = await storage.presign.putUrl(input.key, input)
|
|
189
|
-
if (!result.success) {
|
|
190
|
-
return kit.response.internalError(result.error.message)
|
|
191
|
-
}
|
|
192
|
-
return kit.response.ok({ url: result.data, key: input.key })
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
// ─── IAM:登录 ───
|
|
196
|
-
import { iamEndpoints } from '@h-ai/iam/api'
|
|
197
|
-
import { iam } from '$lib/server/init'
|
|
198
|
-
|
|
199
|
-
export const POST = kit.fromContract(iamEndpoints.login, async (input) => {
|
|
200
|
-
const result = await iam.auth.login(input)
|
|
201
|
-
if (!result.success) {
|
|
202
|
-
return kit.response.unauthorized(result.error.message)
|
|
203
|
-
}
|
|
204
|
-
return kit.response.ok(result.data)
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
// ─── 支付:创建订单 ───
|
|
208
|
-
import { paymentEndpoints } from '@h-ai/payment/api'
|
|
209
|
-
import { payment } from '$lib/server/init'
|
|
210
|
-
|
|
211
|
-
export const POST = kit.fromContract(paymentEndpoints.createOrder, async (input, event) => {
|
|
212
|
-
kit.guard.require(event.locals.session, 'payment:create')
|
|
213
|
-
const result = await payment.order.create(input)
|
|
214
|
-
if (!result.success) {
|
|
215
|
-
return kit.response.internalError(result.error.message)
|
|
216
|
-
}
|
|
217
|
-
return kit.response.created(result.data)
|
|
218
|
-
})
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
## 常见模式
|
|
222
|
-
|
|
223
|
-
### 契约模式(推荐新项目使用)
|
|
224
|
-
|
|
225
|
-
1. 在模块的 `api/` 目录定义 `EndpointDef`(Zod schema)
|
|
226
|
-
2. 服务端用 `kit.fromContract(endpoint, handler)` 处理
|
|
227
|
-
3. 客户端用 `api.call(endpoint, input)` 调用
|
|
228
|
-
4. 入参/出参全链路类型安全 + 运行时校验
|
|
229
|
-
|
|
230
|
-
### CORS + Capacitor 配置
|
|
231
|
-
|
|
232
|
-
Capacitor 原生 App 的 WebView 发送的请求并非 CORS 同源,需要配置:
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
cors: {
|
|
236
|
-
origins: ['https://your-api.com'],
|
|
237
|
-
capacitor: true, // 自动添加 capacitor://* 和 ionic://* 等预设
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### 双构建模式
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
// svelte.config.js
|
|
245
|
-
import { createAdapter } from '@h-ai/kit/adapter'
|
|
246
|
-
|
|
247
|
-
const config = {
|
|
248
|
-
kit: {
|
|
249
|
-
adapter: createAdapter(),
|
|
250
|
-
// VITE_ADAPTER=static → adapter-static (SPA)
|
|
251
|
-
// VITE_ADAPTER=node → adapter-node (SSR)
|
|
252
|
-
// 默认 → adapter-node
|
|
253
|
-
},
|
|
254
|
-
}
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
## 相关 Skills
|
|
258
|
-
|
|
259
|
-
- `hai-core`:全局配置、日志、HaiResult 基础能力
|
|
260
|
-
- `hai-iam`:Token 认证、角色权限模型
|
|
261
|
-
- `hai-api-client`:客户端契约调用(SPA / 原生 App 场景)
|
|
262
|
-
- `hai-crypto`:传输加密与密钥管理能力
|
|
263
|
-
- `hai-capacitor`:原生 App CORS 场景
|
|
264
|
-
|
|
265
|
-
---
|
|
266
|
-
|
|
267
|
-
## 浏览器侧使用
|
|
268
|
-
|
|
269
|
-
### 创建统一 API 客户端 — `kit.client`
|
|
270
|
-
|
|
271
|
-
> **所有浏览器端 API 请求必须通过 `apiFetch`,禁止直接 `fetch()`。**
|
|
272
|
-
|
|
273
|
-
在 `src/lib/utils/api.ts` 中一次性创建,全应用共享:
|
|
274
|
-
|
|
275
|
-
```typescript
|
|
276
|
-
// src/lib/utils/api.ts
|
|
277
|
-
import { kit } from '@h-ai/kit'
|
|
278
|
-
|
|
279
|
-
const client = kit.client.create({
|
|
280
|
-
auth: true, // 自动从 localStorage 注入 Bearer Token
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
export const { apiFetch } = client
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
如需传输加密,传入 crypto:
|
|
287
|
-
|
|
288
|
-
```typescript
|
|
289
|
-
import { crypto } from '@h-ai/crypto'
|
|
290
|
-
import { kit } from '@h-ai/kit'
|
|
291
|
-
|
|
292
|
-
if (typeof window !== 'undefined') {
|
|
293
|
-
crypto.init() // 浏览器端初始化加密模块
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const client = kit.client.create({
|
|
297
|
-
transport: { crypto }, // 透明完成密钥交换 + 请求/响应体加解密
|
|
298
|
-
auth: true,
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
export const { apiFetch } = client
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
`apiFetch` 自动处理:
|
|
305
|
-
- **CSRF**:写方法(POST/PUT/DELETE)自动读取 `hai_csrf` Cookie 并设置 `X-CSRF-Token`
|
|
306
|
-
- **Bearer Token**:自动从 localStorage 读取并注入 `Authorization` header
|
|
307
|
-
- **传输加密**:可选,首次写请求时自动密钥交换
|
|
308
|
-
|
|
309
|
-
使用示例:
|
|
310
|
-
|
|
311
|
-
```typescript
|
|
312
|
-
// ✅ 正确方式
|
|
313
|
-
import { apiFetch } from '$lib/utils/api'
|
|
314
|
-
|
|
315
|
-
const res = await apiFetch('/api/users', {
|
|
316
|
-
method: 'POST',
|
|
317
|
-
headers: { 'Content-Type': 'application/json' },
|
|
318
|
-
body: JSON.stringify(data),
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
// ❌ 禁止在组件中直接 fetch
|
|
322
|
-
// const res = await fetch('/api/users', { ... })
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### Token 存储 — `kit.auth.createTokenStore`
|
|
326
|
-
|
|
327
|
-
```typescript
|
|
328
|
-
import { kit } from '@h-ai/kit'
|
|
329
|
-
|
|
330
|
-
// 创建 localStorage 存储(Web 端默认)
|
|
331
|
-
const tokenStore = kit.auth.createTokenStore('hai_access_token')
|
|
332
|
-
tokenStore.set(tokens.accessToken) // 登录后保存
|
|
333
|
-
tokenStore.get() // string | null
|
|
334
|
-
tokenStore.clear() // 登出时清除
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### hooks.client.ts 标准配置 — `kit.auth.createHandleFetch`
|
|
338
|
-
|
|
339
|
-
```typescript
|
|
340
|
-
// src/hooks.client.ts
|
|
341
|
-
import { kit } from '@h-ai/kit'
|
|
342
|
-
|
|
343
|
-
// 自动为同源请求附加 Authorization: Bearer <token>
|
|
344
|
-
export const handleFetch = kit.auth.createHandleFetch()
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
### 选择指南:kit.client vs api-client
|
|
348
|
-
|
|
349
|
-
| 场景 | 推荐 | 原因 |
|
|
350
|
-
|------|------|------|
|
|
351
|
-
| SSR SvelteKit 应用(同源请求) | `kit.client.create().apiFetch` | 自动 CSRF、同源 Cookie 透传、传输加密 |
|
|
352
|
-
| SPA / 原生 App(跨域请求) | `api.init()` + `api.call()` | 完整 Token 管理、401 自动刷新 |
|
|
353
|
-
| 服务端 `+page.server.ts` | 直接调用模块 API | 无需 HTTP 自环 |
|
|
354
|
-
| 契约调用(类型安全) | `api.call(endpoint, input)` | EndpointDef 双向 Zod 校验 |
|
|
58
|
+
`kit.auth.logout(cookies, accessToken)` 返回 `Promise<HaiResult<void>>`。无令牌时仅清除 Cookie 并成功;有令牌但未配置认证操作时返回失败。无论服务端结果如何都清除本地 Cookie,调用方仍必须把失败转换为错误响应或提示;仅成功结果代表服务端撤销已经确认。底层控制流异常继续传播。
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# hai-kit 参考
|
|
2
|
+
|
|
3
|
+
> `@h-ai/kit` 只负责 SvelteKit 集成:`handle` hook、guard、response、validate、client、auth、crud、A2A。公共跨端 HTTP API 契约统一使用 `@h-ai/api-contract` + `@h-ai/serv`,不要在 kit 中定义业务 API contract。
|
|
4
|
+
|
|
5
|
+
认证协议仅支持 v2:独立随机 SM4-CBC 密钥和 HMAC-SM3 密钥由 SM2 封装,先验签、再验证 MAC,最后解密 CBC。请求由客户端私钥签名,响应由所选服务端版本签名。认证字段包括 version、direction、serverKeyId、clientId、128 位随机 requestId(兼 nonce)、issuedAt、HTTP method、pathname + 原始 search 的 SM3 pathHash,以及响应 status。请求有效期 5 分钟,未来时钟偏差最多 30 秒;共享 registry 原子消费 (clientId, requestId),nonce 至少保留到 issuedAt + 6 分钟以覆盖节点偏差,存储故障拒绝请求。Redis 必须保留有效 nonce,使用 noeviction/可靠持久化策略;各节点时钟须同步。此能力防止同一传输消息重放,业务重试仍需自己的幂等键。
|
|
6
|
+
|
|
7
|
+
空 POST 也发送空明文的认证封装;GET/HEAD 将封装放在 X-Hai-Transport 头,204/304/HEAD 等无正文响应也使用同名头承载认证封装。其它请求/响应在 JSON 正文承载封装并带 X-Encrypted: true。客户端必须关联原请求上下文和 HTTP status,缺标记、旧格式或认证失败一律 reject;明文接口由 Serv/Kit 路径规则 `encryption: disabled` 或宿主 `excludePaths` 显式允许;调用方同步选择普通请求,API Client/Kit 包装器使用自己的 `excludePaths`。CORS 须允许并暴露 X-Hai-Transport。握手公钥的真实性依赖 TLS,不替代 IAM 业务授权。
|
|
8
|
+
|
|
9
|
+
## 使用步骤
|
|
10
|
+
|
|
11
|
+
### 1. 请求管道
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { Handle } from '@sveltejs/kit'
|
|
15
|
+
import { cache } from '@h-ai/cache'
|
|
16
|
+
import { kit } from '@h-ai/kit'
|
|
17
|
+
|
|
18
|
+
const haiHandle = kit.createHandle({
|
|
19
|
+
auth: {
|
|
20
|
+
verifyToken: async token => token ? { userId: 'u_1', roles: ['admin'], permissions: ['user:read'] } : null,
|
|
21
|
+
loginUrl: '/auth/login',
|
|
22
|
+
protectedPaths: ['/admin/*'],
|
|
23
|
+
},
|
|
24
|
+
rateLimit: { windowMs: 60_000, maxRequests: 100, store: kit.middleware.createCacheRateLimitStore(cache, { namespace: 'app' }) },
|
|
25
|
+
logging: true,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
export const handle: Handle = haiHandle
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
限流采用首次成功提交为起点的固定窗口,后续请求不延长 TTL。必须显式传 store;应用先检查共享 Redis 初始化结果,所有节点使用相同 namespace/windowMs/maxRequests。缓存读取/条件提交失败或冲突耗尽返回503,超限429;不会回退 get+set 或本地计数。createMemoryRateLimitStore 仅开发或显式 HAI_E2E/HAI_E2E_MOCK 测试使用,无常驻定时器,丢弃引用即可回收;每次请求最多惰性扫描 64 项,最多保存 10000 个窗口,容量满时对新 key 返回503且不驱逐有效计数,外部 store 生命周期由创建者管理;生产不得设置测试开关。响应重置时间为节点时钟估算,实际窗口由 Redis TTL 决定,须同步时钟。默认键只读取可信 adapter 的 getClientAddress、规范化等价IPv6和IPv4映射地址,不采信原始转发头;代理信任通过部署adapter配置。
|
|
32
|
+
|
|
33
|
+
### 2. SvelteKit API endpoint
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { kit } from '@h-ai/kit'
|
|
37
|
+
import { z } from 'zod'
|
|
38
|
+
|
|
39
|
+
const CreateUserSchema = z.object({ name: z.string().min(1) })
|
|
40
|
+
|
|
41
|
+
export const POST = kit.handler(async ({ request, locals }) => {
|
|
42
|
+
kit.guard.require(locals.session, 'user:create')
|
|
43
|
+
const payload = await kit.validate.body(request, CreateUserSchema)
|
|
44
|
+
return kit.response.created(payload)
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. 浏览器同源请求
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { kit } from '@h-ai/kit'
|
|
52
|
+
|
|
53
|
+
const client = kit.client.create()
|
|
54
|
+
export const { apiFetch } = client
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> 同源 endpoint 使用 httpOnly Cookie;`auth: true` 只读取 `kit.auth.setBrowserToken()` 写入的页面内存 Token。自定义 `BrowserTokenStore` 也须使用内存或平台安全存储,禁止把敏感凭据持久化到 Web Storage。
|
|
58
|
+
|
|
59
|
+
### 4. 同源传输加密
|
|
60
|
+
|
|
61
|
+
kit 不再维护本地传输加密实现;服务端和客户端都统一委托 `@h-ai/crypto` 的 `crypto.transport`。
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// hooks.server.ts
|
|
65
|
+
import { cache } from '@h-ai/cache'
|
|
66
|
+
import { createRedisTransportKeyStore, crypto, parseTransportServerKeyRing } from '@h-ai/crypto'
|
|
67
|
+
import { kit } from '@h-ai/kit'
|
|
68
|
+
|
|
69
|
+
await crypto.init()
|
|
70
|
+
const ring = parseTransportServerKeyRing(process.env.HAI_CRYPTO_TRANSPORT_SERVERKEYRING)
|
|
71
|
+
if (!ring.success)
|
|
72
|
+
throw new Error(ring.error.message)
|
|
73
|
+
const serverKeyRing = ring.data
|
|
74
|
+
await cache.init({ type: 'redis', host: '127.0.0.1', port: 6379 })
|
|
75
|
+
|
|
76
|
+
export const handle = kit.createHandle({
|
|
77
|
+
auth: {
|
|
78
|
+
verifyToken,
|
|
79
|
+
protectedPaths: ['/api/*'],
|
|
80
|
+
publicPaths: ['/api/_hai/*'],
|
|
81
|
+
},
|
|
82
|
+
crypto: {
|
|
83
|
+
crypto,
|
|
84
|
+
transport: {
|
|
85
|
+
serverKeyRing,
|
|
86
|
+
keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
需要保护会话 Cookie 时配置 `crypto.encryptedCookies`,并通过 `crypto.cookieEncryptionKey` 或 `HAI_KIT_COOKIE_KEY` 提供密钥。缺少密钥会在 `createHandle()` 时失败;加解密错误不会回退到明文 Cookie。
|
|
93
|
+
|
|
94
|
+
```svelte
|
|
95
|
+
<!-- src/routes/+layout.svelte -->
|
|
96
|
+
<script lang='ts'>
|
|
97
|
+
import { browser } from '$app/environment'
|
|
98
|
+
import type { LayoutData } from './$types'
|
|
99
|
+
import { crypto } from '@h-ai/crypto'
|
|
100
|
+
import { kit } from '@h-ai/kit'
|
|
101
|
+
import { untrack } from 'svelte'
|
|
102
|
+
|
|
103
|
+
const { data }: { data: LayoutData } = $props()
|
|
104
|
+
|
|
105
|
+
// 服务端 layout 只返回 kit 公共投影;初次加载安装,不下发完整策略。
|
|
106
|
+
if (browser) {
|
|
107
|
+
kit.client.installBrowserTransport(untrack(() => data.kit), { crypto })
|
|
108
|
+
}
|
|
109
|
+
</script>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
// lib/utils/api.ts —— 业务层只看到 apiFetch
|
|
114
|
+
import { kit } from '@h-ai/kit'
|
|
115
|
+
|
|
116
|
+
export const { apiFetch } = kit.client.create()
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
默认协商端点:`/api/_hai/key-exchange`。如 `keyExchangePath` 自定义,浏览器端同步设置 `keyExchangeUrl`。
|
|
120
|
+
|
|
121
|
+
启用 transport 使用 `{ serverKeyRing, keyStore, ...公开路径配置 }`,两项必填,不再接受单独的 true。serverKeyRing 通过服务端 Secret/私有 `HAI_CRYPTO_TRANSPORT_SERVERKEYRING` 安全解析,不放 `_kit.yml`、PUBLIC_/VITE_ 或日志;浏览器仅需公开 transport 配置和 crypto。各节点使用同一版本化 ring 与共享 Redis/数据库 registry;仅共享客户端公钥不够。请求带协商 serverKeyId,无需 sticky session;轮换先分发新旧 ring,再切 activeKeyId 重建 manager,删除旧 ID 后客户端 destroy 并重协商。开发/测试须显式选择内存 registry;原公开 maxClients 已删除。完整轮换步骤见 hai-crypto。
|
|
122
|
+
|
|
123
|
+
transport 默认保护同源 `/api/*` endpoint 与 SvelteKit `__data.json` 页面数据请求;页面文档、静态资源与 `multipart/form-data` 上传请求保持明文透传。
|
|
124
|
+
|
|
125
|
+
受保护路径不允许协议降级;缺少认证、管理器不可用、响应加密失败均拒绝。明文接口通过请求规则 encryption:disabled 或宿主 excludePaths 显式配置,调用方同步选择协议;IP、时间和认证继续检查。规则 required 优先于宿主排除表,冲突或缺少加密装配会拒绝创建 Handle。
|
|
126
|
+
|
|
127
|
+
空 POST 也发送空明文的认证封装;GET/HEAD 将封装放在 X-Hai-Transport 头,204/304/HEAD 等无正文响应也使用同名头承载认证封装。其它请求/响应在 JSON 正文承载封装并带 X-Encrypted: true。客户端必须关联原请求上下文和 HTTP status,缺标记、旧格式或认证失败一律 reject;明文接口由 Serv/Kit 路径规则 `encryption: disabled` 或宿主 `excludePaths` 显式允许;调用方同步选择普通请求,API Client/Kit 包装器使用自己的 `excludePaths`。CORS 须允许并暴露 X-Hai-Transport。握手公钥的真实性依赖 TLS,不替代 IAM 业务授权。
|
|
128
|
+
|
|
129
|
+
业务容量统一配置 transport.maxPlaintextBytes:UTF-8 JSON 明文字节,默认 1 MiB,有效整数范围 1 KiB~64 MiB,请求和响应共用。客户端从握手获取服务端预算,可选本地上限取较小值;resolveTransportBodyLimits(limit, { requiredPlaintextBytes }) 合并模块需求:保留显式上限,不足时报配置冲突;省略时按需要推导,无模块需要仍为 1 MiB。Serv/Kit 的 auto 规范化为 undefined。密文预算为两倍明文加 32 KiB。握手 JSON 16 KiB、公钥 4 KiB、认证头 16 KiB、路径 8 KiB、认证及防重放保持独立。原流超限/取消立即停止、取消并释放 reader;请求 413、响应返回加密的 500 容量错误,客户端识别 TransportBodyTooLargeError / hai:crypto:070。 通过 _kit.yml 的 transport.maxPlaintextBytes 或对应 HAI_*_TRANSPORT_MAXPLAINTEXTBYTES 配置并转发到服务端 transport;重建正文保留 signal 并删除旧长度/编码头。
|
|
130
|
+
|
|
131
|
+
### 5. 使用 `_kit.yml` 统一 transport 配置
|
|
132
|
+
|
|
133
|
+
`@h-ai/kit` 现在提供 `KitConfigSchema` / `resolveKitConfig()`,适合同一份 `_kit.yml`
|
|
134
|
+
同时驱动 `hooks.server.ts` 与浏览器端 `kit.client.installBrowserTransport()`:
|
|
135
|
+
|
|
136
|
+
```yml
|
|
137
|
+
server:
|
|
138
|
+
host: 127.0.0.1
|
|
139
|
+
port: 3000
|
|
140
|
+
|
|
141
|
+
transport:
|
|
142
|
+
keyExchangePath: /api/_hai/key-exchange
|
|
143
|
+
excludePaths:
|
|
144
|
+
- /api/storage
|
|
145
|
+
- /api/public
|
|
146
|
+
- /api/auth/profile/avatar
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { core } from '@h-ai/core'
|
|
151
|
+
import { KitConfigSchema } from '@h-ai/kit'
|
|
152
|
+
|
|
153
|
+
// src/routes/+layout.server.ts;服务端已先完成应用配置初始化。
|
|
154
|
+
export function load() {
|
|
155
|
+
const loaded = core.config.load('kit', './config/_kit.yml', KitConfigSchema)
|
|
156
|
+
if (!loaded.success)
|
|
157
|
+
throw new Error(loaded.error.message)
|
|
158
|
+
return { kit: { transport: loaded.data.transport } }
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`resolveKitConfig()` 同时解析 `server`(host/port)与 `transport`;host/port 优先级为 `HOST` / `PORT` 环境变量 > `_kit.yml` 的 `server` > 默认 `127.0.0.1:3000`(与 `@h-ai/serv` 同构)。
|
|
163
|
+
`_kit.yml` 在服务端读取,可包含 access 和 trustedProxies;layout data 只投影公开 transport,不通过 ?raw 导入完整文件到浏览器,也不放密钥。如自定义 `keyExchangePath`,浏览器端必须同步映射为 `keyExchangeUrl`。请求策略按[共享约定](../hai-core/request-access.md)装配与验证。
|
|
164
|
+
|
|
165
|
+
子目录部署从 `$app/paths` 取 `base`,服务端 `crypto.transport.basePath` 与客户端 `installBrowserTransport(config, { crypto, basePath: base })` 同步;独立 client 的 `transport.basePath` 也用该值。默认空字符串为根目录,不能仅调整资源地址后把登录成功当作加密验证。交换/排除/容量路径保持完整请求路径,验证原始请求带加密标记、缺协议被拒绝、排除接口正常且不影响相邻目录。
|
|
166
|
+
|
|
167
|
+
## 核心 API
|
|
168
|
+
|
|
169
|
+
| API | 用途 |
|
|
170
|
+
| -------------------------------------------------------- | -------------------------------------------------------- |
|
|
171
|
+
| `kit.createHandle()` | 创建 SvelteKit Handle |
|
|
172
|
+
| `kit.sequence()` | 组合多个 Handle |
|
|
173
|
+
| `kit.handler()` | API endpoint 错误边界 |
|
|
174
|
+
| `kit.guard.require()` | 权限守卫 |
|
|
175
|
+
| `kit.response.*` | 统一响应工厂 |
|
|
176
|
+
| `kit.validate.*` | Zod 请求校验 |
|
|
177
|
+
| `kit.auth.*` | Cookie / Token 辅助 |
|
|
178
|
+
| `kit.client.create()` | 浏览器端同源 apiFetch |
|
|
179
|
+
| `kit.client.installBrowserTransport(config, { crypto })` | 接收 KitPublicConfig,只含 transport;不要求浏览器接收代理或访问策略 |
|
|
180
|
+
| `kit.client.installBrowserTransportFetch()` | 底层入口:直接传 transport 配置安装浏览器全局 fetch 包装 |
|
|
181
|
+
| `kit.crud.define()` | 声明式 CRUD 资源 |
|
|
182
|
+
|
|
183
|
+
`guard.require` 和 `validate` 的 OrFail Response 仅由 `kit.handler` 处理 API 控制流。页面 load 用 guard.check 加 SvelteKit error,查询参数先 safeParse;不能把 API Response 直接抛给页面运行时。
|
|
184
|
+
|
|
185
|
+
## 常见模式
|
|
186
|
+
|
|
187
|
+
- SvelteKit 应用内同源请求用 `kit.client.create().apiFetch`。
|
|
188
|
+
- SvelteKit 应用启用 transport 时,服务端 layout 只投影 transport 为公共 data;`+layout.svelte` 的 `if (browser)` 分支调用一次安装器,无需复制 `keyExchangeUrl` / `excludePaths`,不下发完整配置。
|
|
189
|
+
- Web/App/小程序跨域访问公共 API 用 `@h-ai/api-client` typed client。
|
|
190
|
+
- 传输加密只通过 `crypto.transport` 间接装配,不在 kit 中新增本地加密工厂或鸭子类型。
|
|
191
|
+
- 服务端业务模块直接调用模块 API,不通过 HTTP 自环。
|
|
192
|
+
- API endpoint 必须用 Zod 校验用户输入,并设置认证/权限边界。
|
|
193
|
+
|
|
194
|
+
## 声明式 CRUD 表单字段
|
|
195
|
+
|
|
196
|
+
`kit.crud.define` 的字段支持 `colSpan: 'auto' | 1 | 2`,以及 `validation.message: string | (() => string)`。布局通过 UI 的 `CrudPage.form` 配置;客户端校验用于交互提示,服务端仍使用 Zod 验证和现有权限守卫。UI 公共契约见相邻 [hai-ui skill](../hai-ui/SKILL.md)。
|
|
197
|
+
|
|
198
|
+
Node 请求/SSR 必须用 `core.i18n.runWithLocale(locale, callback)`(kit 同名方法)包裹实际异步 resolve;serv 自动建立请求语言上下文。浏览器 setGlobalLocale/createLocaleStore 继续管理应用语言,SSR 的 UI setter/store 不写全局值。显式 MessageOptions.locale 优先;进程默认语言仅在启动时设置。
|
|
199
|
+
|
|
200
|
+
认证 Cookie 在 NODE_ENV 或 HAI_CORE_ENV 为 production 时默认启用 Secure,HAI_E2E/HAI_E2E_MOCK 不降低 Cookie 安全;限流生产判断也识别这两个环境标志,测试开关仅放宽共享状态要求。
|
|
201
|
+
|
|
202
|
+
`kit.auth.logout(cookies, accessToken)` 返回 `Promise<HaiResult<void>>`。无令牌时仅清除 Cookie 并成功;有令牌但未配置认证操作时返回失败。无论服务端结果如何都清除本地 Cookie,调用方仍必须把失败转换为错误响应或提示;仅成功结果代表服务端撤销已经确认。底层控制流异常继续传播。
|