@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
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {{projectName}} — API 客户端初始化。
|
|
3
|
+
* Web 预览仅使用内存 TokenStore;原生端使用 Capacitor 安全存储。
|
|
4
|
+
* 原生存储失败会拒绝 Promise;登录/退出调用方须处理 auth.setTokens/clear 失败并释放界面 loading。
|
|
5
|
+
*/
|
|
6
|
+
import { apiClient } from '@h-ai/api-client'
|
|
7
|
+
import { createCapacitorTokenStorage } from '@h-ai/capacitor'
|
|
8
|
+
{{#if features.crypto}}
|
|
9
|
+
import { crypto } from '@h-ai/crypto'
|
|
10
|
+
{{/if}}
|
|
11
|
+
|
|
12
|
+
const DEFAULT_API_BASE = 'http://localhost:3000/api/v1'
|
|
13
|
+
|
|
14
|
+
let initialized = false
|
|
15
|
+
let initializing: Promise<void> | undefined
|
|
16
|
+
let closing: Promise<void> | undefined
|
|
17
|
+
{{#if features.crypto}}
|
|
18
|
+
// 只关闭本客户端实际初始化的 crypto,保留外部调用方已有实例。
|
|
19
|
+
let ownsCrypto = false
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 解析客户端传输选项;仅显式 off 连接匹配的明文 API,握手失败不降级。
|
|
23
|
+
* @returns 绑定实际 crypto 与公开协商子路径的选项,或显式明文模式的 undefined。
|
|
24
|
+
* @example 模块内部上下文
|
|
25
|
+
* ```ts
|
|
26
|
+
* const transport = resolveTransport()
|
|
27
|
+
* if (transport) {
|
|
28
|
+
* await initApi()
|
|
29
|
+
* try {
|
|
30
|
+
* if (!apiClient.config?.transport) throw new Error('Transport configuration missing')
|
|
31
|
+
* }
|
|
32
|
+
* finally { await closeApi() }
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
function resolveTransport() {
|
|
37
|
+
const runtime = (globalThis as typeof globalThis & { __HAI_PUBLIC_CONFIG__?: { apiTransport?: string, apiKeyExchangePath?: string } }).__HAI_PUBLIC_CONFIG__
|
|
38
|
+
if ((runtime?.apiTransport || import.meta.env.PUBLIC_API_TRANSPORT) === 'off')
|
|
39
|
+
return undefined
|
|
40
|
+
return { crypto, keyExchangePath: runtime?.apiKeyExchangePath || import.meta.env.PUBLIC_API_KEY_EXCHANGE_PATH || '/_hai/key-exchange' }
|
|
41
|
+
}
|
|
42
|
+
{{/if}}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 按公开运行配置、构建配置、本地示例地址的顺序解析含 API 前缀的 baseUrl。
|
|
46
|
+
* @returns API baseUrl;服务端私钥和连接配置不属于该公开地址。
|
|
47
|
+
* @example 模块内部上下文
|
|
48
|
+
* ```ts
|
|
49
|
+
* const base = new URL(resolveApiBase())
|
|
50
|
+
* const apiOrigin = base.origin
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function resolveApiBase(): string {
|
|
54
|
+
const runtime = (globalThis as typeof globalThis & { __HAI_PUBLIC_CONFIG__?: { apiBase?: string } }).__HAI_PUBLIC_CONFIG__
|
|
55
|
+
return runtime?.apiBase || import.meta.env.PUBLIC_API_BASE || DEFAULT_API_BASE
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 查询实际 Capacitor 平台,决定安全原生存储或 Web 内存存储。
|
|
60
|
+
* @returns 是否处于 Capacitor 原生平台;浏览器预览返回 false。
|
|
61
|
+
* @throws Error - 平台模块加载或检测失败时拒绝 Promise,不伪装为 Web 模式。
|
|
62
|
+
* @example 模块内部上下文
|
|
63
|
+
* ```ts
|
|
64
|
+
* if (await usesNativeTokenStorage()) {
|
|
65
|
+
* const storage = createCapacitorTokenStorage()
|
|
66
|
+
* const accessToken = await storage.getAccessToken() // 只用于认证,不输出令牌。
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export async function usesNativeTokenStorage(): Promise<boolean> {
|
|
71
|
+
const { Capacitor } = await import('@capacitor/core')
|
|
72
|
+
return Capacitor.isNativePlatform()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 按真实平台创建 TokenStorage;绑定 client 后通过 client.auth 变更身份。
|
|
77
|
+
* @returns 原生安全存储或 Web 内存存储;其方法的读写故障继续拒绝 Promise。
|
|
78
|
+
* @throws Error - 平台检测或存储工厂失败时拒绝,不改用较弱的持久化方式。
|
|
79
|
+
* @example 模块内部上下文
|
|
80
|
+
* ```ts
|
|
81
|
+
* const storage = await createTokenStorage()
|
|
82
|
+
* const accessToken = await storage.getAccessToken() // null 表示未认证,不记录令牌。
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
async function createTokenStorage() {
|
|
86
|
+
if (await usesNativeTokenStorage())
|
|
87
|
+
return createCapacitorTokenStorage()
|
|
88
|
+
|
|
89
|
+
return apiClient.tokenStorage.memory()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 合并在途初始化并等待关闭;安全存储、所选 crypto 与 typed client 依次就绪。
|
|
94
|
+
* @returns 客户端已准备;重复调用复用同一客户端。
|
|
95
|
+
* @throws Error - 安全存储、crypto 或 client 初始化失败,业务 HaiResult 在此边界明确转成拒绝。
|
|
96
|
+
* @throws AggregateError - 初始化和本次 crypto 清理同时失败,后续 closeApi 可重试。
|
|
97
|
+
* @example 模块内部上下文;目标 API 已提供标准 IAM 端点。
|
|
98
|
+
* ```ts
|
|
99
|
+
* await initApi()
|
|
100
|
+
* try {
|
|
101
|
+
* const current = await apiClient.iam.auth.currentUser()
|
|
102
|
+
* if (!current.success) throw new Error(current.error.message)
|
|
103
|
+
* }
|
|
104
|
+
* finally { await closeApi() }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export async function initApi(): Promise<void> {
|
|
108
|
+
if (closing)
|
|
109
|
+
await closing
|
|
110
|
+
if (initialized)
|
|
111
|
+
return
|
|
112
|
+
if (initializing)
|
|
113
|
+
return initializing
|
|
114
|
+
{{#if features.crypto}}
|
|
115
|
+
if (ownsCrypto)
|
|
116
|
+
await closeApi()
|
|
117
|
+
{{/if}}
|
|
118
|
+
initializing = initialize().finally(() => {
|
|
119
|
+
initializing = undefined
|
|
120
|
+
})
|
|
121
|
+
return initializing
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 在初始化屏障内装配客户端;安全存储先就绪,失败不退回明文并释放本次资源。
|
|
126
|
+
* @returns 当前客户端已初始化;由 initApi 管理并发屏障。
|
|
127
|
+
* @throws Error - 平台、所选 crypto 或 client 拒绝初始化。
|
|
128
|
+
* @throws AggregateError - 初始化失败且本次 crypto 未确认清理,保留关闭重试义务。
|
|
129
|
+
* @example 模块内部上下文;仅在初始化屏障内调用。
|
|
130
|
+
* ```ts
|
|
131
|
+
* await initialize()
|
|
132
|
+
* try {
|
|
133
|
+
* const current = await apiClient.iam.auth.currentUser()
|
|
134
|
+
* if (!current.success) throw new Error(current.error.message)
|
|
135
|
+
* }
|
|
136
|
+
* finally { await closeApi() }
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
async function initialize(): Promise<void> {
|
|
140
|
+
const storage = await createTokenStorage()
|
|
141
|
+
{{#if features.crypto}}
|
|
142
|
+
const transport = resolveTransport()
|
|
143
|
+
try {
|
|
144
|
+
if (transport && !crypto.isInitialized) {
|
|
145
|
+
const result = await crypto.init()
|
|
146
|
+
if (!result.success)
|
|
147
|
+
throw new Error(result.error.message)
|
|
148
|
+
ownsCrypto = true
|
|
149
|
+
}
|
|
150
|
+
const result = await apiClient.init({
|
|
151
|
+
baseUrl: resolveApiBase(),
|
|
152
|
+
auth: { storage },
|
|
153
|
+
...(transport ? { transport } : {}),
|
|
154
|
+
})
|
|
155
|
+
if (!result.success)
|
|
156
|
+
throw new Error(result.error.message)
|
|
157
|
+
initialized = true
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
if (ownsCrypto) {
|
|
161
|
+
try {
|
|
162
|
+
await crypto.close()
|
|
163
|
+
ownsCrypto = false
|
|
164
|
+
}
|
|
165
|
+
catch (cleanupError) {
|
|
166
|
+
throw new AggregateError([error, cleanupError], 'Mobile API initialization and crypto cleanup failed')
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
throw error
|
|
170
|
+
}
|
|
171
|
+
{{else}}
|
|
172
|
+
const result = await apiClient.init({ baseUrl: resolveApiBase(), auth: { storage } })
|
|
173
|
+
if (!result.success)
|
|
174
|
+
throw new Error(result.error.message)
|
|
175
|
+
initialized = true
|
|
176
|
+
{{/if}}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 等待在途初始化,先销毁客户端 transport,再释放自身初始化的 crypto。
|
|
181
|
+
* @returns 所有本次资源确认关闭;无资源或并发关闭时安全复用。
|
|
182
|
+
* @throws Error - client 或 crypto 未确认关闭;保留状态供下一次 closeApi 重试。
|
|
183
|
+
* @example 模块内部上下文;目标 API 已提供标准 IAM 端点。
|
|
184
|
+
* ```ts
|
|
185
|
+
* await initApi()
|
|
186
|
+
* try {
|
|
187
|
+
* const current = await apiClient.iam.auth.currentUser()
|
|
188
|
+
* if (!current.success) throw new Error(current.error.message)
|
|
189
|
+
* }
|
|
190
|
+
* finally { await closeApi() } // 先 client,再本客户端初始化的 crypto。
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export async function closeApi(): Promise<void> {
|
|
194
|
+
closing ??= (async () => {
|
|
195
|
+
if (initializing)
|
|
196
|
+
await initializing.catch(() => undefined)
|
|
197
|
+
if (initialized) {
|
|
198
|
+
await apiClient.close()
|
|
199
|
+
initialized = false
|
|
200
|
+
}
|
|
201
|
+
{{#if features.crypto}}
|
|
202
|
+
if (ownsCrypto) {
|
|
203
|
+
await crypto.close()
|
|
204
|
+
ownsCrypto = false
|
|
205
|
+
}
|
|
206
|
+
{{/if}}
|
|
207
|
+
})().finally(() => {
|
|
208
|
+
closing = undefined
|
|
209
|
+
})
|
|
210
|
+
return closing
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export { apiClient }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CoreConfig } from '@h-ai/core'
|
|
2
|
+
import { core } from '@h-ai/core'
|
|
3
|
+
|
|
4
|
+
declare const __APP_CORE_CONFIG__: Pick<CoreConfig, 'name' | 'version' | 'env' | 'defaultLocale'> & {
|
|
5
|
+
logging?: Pick<NonNullable<CoreConfig['logging']>, 'level' | 'format'>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** 构建包含公开默认值;预览或容器启动时的公开配置覆盖默认值,不重建静态资源。 */
|
|
9
|
+
const runtime = (globalThis as typeof globalThis & { __HAI_PUBLIC_CONFIG__?: { core?: Partial<typeof __APP_CORE_CONFIG__> } }).__HAI_PUBLIC_CONFIG__?.core
|
|
10
|
+
export const appConfig = { ...__APP_CORE_CONFIG__, ...runtime, logging: { ...__APP_CORE_CONFIG__.logging, ...runtime?.logging } }
|
|
11
|
+
|
|
12
|
+
export function initClientCore(): void {
|
|
13
|
+
core.init({ logging: appConfig.logging })
|
|
14
|
+
}
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Capacitor
|
|
3
|
-
*
|
|
4
|
-
* 在应用启动时调用,配置状态栏等原生能力。
|
|
2
|
+
* Capacitor 初始化。
|
|
5
3
|
*/
|
|
6
4
|
import { capacitor } from '@h-ai/capacitor'
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
export async function isNativeApp(): Promise<boolean> {
|
|
7
|
+
return capacitor.isNative()
|
|
8
|
+
}
|
|
9
|
+
|
|
11
10
|
export async function initCapacitor(): Promise<void> {
|
|
12
11
|
await capacitor.init()
|
|
13
12
|
|
|
14
13
|
if (capacitor.isNative()) {
|
|
15
14
|
await capacitor.statusBar.configure({
|
|
16
15
|
backgroundColor: '#ffffff',
|
|
17
|
-
style: '
|
|
16
|
+
style: 'light',
|
|
18
17
|
overlay: false,
|
|
19
18
|
})
|
|
20
19
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script lang='ts'>
|
|
2
|
+
import { resolveApiBase } from '../api.js'
|
|
3
|
+
import { appConfig } from '../app-config.js'
|
|
4
|
+
import * as m from '../paraglide/messages.js'
|
|
5
|
+
/** 首页展示的平台运行状态;例如 { nativeRuntime: true, nativeTokenStorage: true }。 */
|
|
6
|
+
interface Props {
|
|
7
|
+
/** 是否运行于原生壳。 */
|
|
8
|
+
nativeRuntime: boolean
|
|
9
|
+
/** 是否使用原生安全凭据存储。 */
|
|
10
|
+
nativeTokenStorage: boolean
|
|
11
|
+
}
|
|
12
|
+
const { nativeRuntime, nativeTokenStorage }: Props = $props()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<section class='grid gap-4 p-4 pb-6 lg:grid-cols-2'>
|
|
16
|
+
<div class='lg:col-span-2 bg-primary text-primary-content rounded-2xl p-5 shadow-sm'>
|
|
17
|
+
<p class='text-sm opacity-75'>{m.hero_eyebrow()}</p>
|
|
18
|
+
<h1 class='mt-1 text-2xl font-bold'>{m.hero_title()}</h1>
|
|
19
|
+
<p class='mt-2 text-sm opacity-80'>{m.hero_subtitle()}</p>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class='grid grid-cols-2 gap-3'>
|
|
23
|
+
<Card padding='sm' shadow='sm'>
|
|
24
|
+
<div class='flex flex-col gap-2'>
|
|
25
|
+
<span class='icon-[tabler--device-mobile-code] text-primary text-2xl'></span>
|
|
26
|
+
<span class='text-sm font-medium'>{m.feature_native_title()}</span>
|
|
27
|
+
<span class='text-base-content/60 text-xs'>{m.feature_native_desc()}</span>
|
|
28
|
+
</div>
|
|
29
|
+
</Card>
|
|
30
|
+
<Card padding='sm' shadow='sm'>
|
|
31
|
+
<div class='flex flex-col gap-2'>
|
|
32
|
+
<span class='icon-[tabler--api-app] text-primary text-2xl'></span>
|
|
33
|
+
<span class='text-sm font-medium'>{m.feature_api_title()}</span>
|
|
34
|
+
<span class='text-base-content/60 text-xs'>{m.feature_api_desc()}</span>
|
|
35
|
+
</div>
|
|
36
|
+
</Card>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<Card title={m.status_title()} shadow='sm'>
|
|
40
|
+
<p class='mb-3 text-xs text-base-content/50'>{appConfig.name} · {appConfig.version} · {appConfig.env}</p>
|
|
41
|
+
<div class='grid grid-cols-2 gap-3 text-sm'>
|
|
42
|
+
<div>
|
|
43
|
+
<p class='text-base-content/50'>{m.status_api_label()}</p>
|
|
44
|
+
<p class='font-medium break-all'>{resolveApiBase()}</p>
|
|
45
|
+
</div>
|
|
46
|
+
<div>
|
|
47
|
+
<p class='text-base-content/50'>{m.status_runtime_label()}</p>
|
|
48
|
+
<Badge variant={nativeRuntime ? 'success' : 'warning'} size='sm'>
|
|
49
|
+
{nativeRuntime ? m.status_runtime_native() : m.status_runtime_web()}
|
|
50
|
+
</Badge>
|
|
51
|
+
</div>
|
|
52
|
+
<div class='col-span-2'>
|
|
53
|
+
<p class='text-base-content/50'>{m.status_token_label()}</p>
|
|
54
|
+
<p class='font-medium'>{nativeTokenStorage ? m.status_token_native() : m.status_token_memory()}</p>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</Card>
|
|
58
|
+
</section>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script lang='ts'>
|
|
2
|
+
import * as m from '../paraglide/messages.js'
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<section class='space-y-4 p-4 pb-6'>
|
|
6
|
+
<Card title={m.profile_title()} shadow='sm'>
|
|
7
|
+
<div class='space-y-3 text-sm'>
|
|
8
|
+
<div class='bg-base-200 rounded-xl p-3'>{m.profile_language()}</div>
|
|
9
|
+
<div class='bg-base-200 rounded-xl p-3'>{m.profile_theme()}</div>
|
|
10
|
+
<div class='bg-base-200 rounded-xl p-3'>{m.profile_secure()}</div>
|
|
11
|
+
</div>
|
|
12
|
+
</Card>
|
|
13
|
+
</section>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang='ts'>
|
|
2
|
+
import * as m from '../paraglide/messages.js'
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<section class='space-y-4 p-4 pb-6'>
|
|
6
|
+
<Card title={m.tasks_title()} shadow='sm'>
|
|
7
|
+
<div class='space-y-3'>
|
|
8
|
+
{#each [m.tasks_sync(), m.tasks_polish(), m.tasks_release()] as task (task)}
|
|
9
|
+
<div class='bg-base-200 rounded-xl flex items-center gap-3 p-3'>
|
|
10
|
+
<span class='icon-[tabler--circle-check] text-success text-xl'></span>
|
|
11
|
+
<span class='text-sm font-medium'>{task}</span>
|
|
12
|
+
</div>
|
|
13
|
+
{/each}
|
|
14
|
+
</div>
|
|
15
|
+
</Card>
|
|
16
|
+
</section>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { mount } from 'svelte'
|
|
2
|
+
import App from './App.svelte'
|
|
3
|
+
import './app.css'
|
|
4
|
+
|
|
5
|
+
const target = document.getElementById('app')
|
|
6
|
+
if (!target)
|
|
7
|
+
throw new Error('Root element #app not found')
|
|
8
|
+
|
|
9
|
+
const app = mount(App, { target })
|
|
10
|
+
|
|
11
|
+
export default app
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
"page_about_title": "About Us",
|
|
20
20
|
"page_about_desc": "Company information and development history.",
|
|
21
21
|
"page_services_title": "Our Services",
|
|
22
|
-
"page_services_item1": "
|
|
23
|
-
"page_services_item2": "
|
|
22
|
+
"page_services_item1": "Technical Consulting",
|
|
23
|
+
"page_services_item2": "Custom Development",
|
|
24
|
+
"page_services_item3": "Operations Support",
|
|
24
25
|
"page_services_desc": "Service description content.",
|
|
25
26
|
"page_contact_title": "Contact Us",
|
|
26
27
|
"page_contact_desc": "Have any questions? Feel free to contact us.",
|
|
@@ -28,5 +29,6 @@
|
|
|
28
29
|
"page_contact_email": "Email",
|
|
29
30
|
"page_contact_message": "Message",
|
|
30
31
|
"page_contact_submit": "Send",
|
|
32
|
+
"page_contact_unavailable": "Online messages are not available yet. Please use another contact method. Your input has been kept.",
|
|
31
33
|
"footer_copyright": "Copyright © {year}. All rights reserved."
|
|
32
34
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app_title": "企業サイト",
|
|
3
|
+
"app_description": "企業の公式サイト",
|
|
4
|
+
"meta_description": "企業の公式サイト",
|
|
5
|
+
"nav_home": "ホーム",
|
|
6
|
+
"nav_about": "会社概要",
|
|
7
|
+
"nav_services": "サービス",
|
|
8
|
+
"nav_contact": "担当者",
|
|
9
|
+
"page_home_title": "ようこそ",
|
|
10
|
+
"page_home_subtitle": "専門的で信頼できる企業向けサービス",
|
|
11
|
+
"page_home_cta": "お問い合わせ",
|
|
12
|
+
"page_home_advantages": "私たちの強み",
|
|
13
|
+
"page_home_team": "専門チーム",
|
|
14
|
+
"page_home_team_desc": "長年の業界経験を持つチームです。",
|
|
15
|
+
"page_home_service": "高品質なサービス",
|
|
16
|
+
"page_home_service_desc": "総合的で質の高いサポートを提供します。",
|
|
17
|
+
"page_home_tech": "革新的な技術",
|
|
18
|
+
"page_home_tech_desc": "業界をリードする革新的な技術ソリューション。",
|
|
19
|
+
"page_about_title": "会社概要",
|
|
20
|
+
"page_about_desc": "企業情報とこれまでの歩み。",
|
|
21
|
+
"page_services_title": "サービス",
|
|
22
|
+
"page_services_item1": "技術コンサルティング",
|
|
23
|
+
"page_services_item2": "カスタム開発",
|
|
24
|
+
"page_services_item3": "運用サポート",
|
|
25
|
+
"page_services_desc": "サービスの説明。",
|
|
26
|
+
"page_contact_title": "お問い合わせ",
|
|
27
|
+
"page_contact_desc": "ご質問はお気軽にお問い合わせください。",
|
|
28
|
+
"page_contact_name": "お名前",
|
|
29
|
+
"page_contact_email": "メールアドレス",
|
|
30
|
+
"page_contact_message": "メッセージ",
|
|
31
|
+
"page_contact_submit": "送信",
|
|
32
|
+
"page_contact_unavailable": "オンラインメッセージは未対応です。別の連絡方法をご利用ください。入力内容は保持されています。",
|
|
33
|
+
"footer_copyright": "Copyright © {year}. All rights reserved."
|
|
34
|
+
}
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
"page_about_title": "关于我们",
|
|
20
20
|
"page_about_desc": "在此介绍公司信息和发展历程。",
|
|
21
21
|
"page_services_title": "我们的服务",
|
|
22
|
-
"page_services_item1": "
|
|
23
|
-
"page_services_item2": "
|
|
22
|
+
"page_services_item1": "咨询服务",
|
|
23
|
+
"page_services_item2": "定制开发",
|
|
24
|
+
"page_services_item3": "运维支持",
|
|
24
25
|
"page_services_desc": "服务描述内容。",
|
|
25
26
|
"page_contact_title": "联系我们",
|
|
26
27
|
"page_contact_desc": "有任何疑问?欢迎联系我们。",
|
|
@@ -28,5 +29,6 @@
|
|
|
28
29
|
"page_contact_email": "邮箱",
|
|
29
30
|
"page_contact_message": "留言",
|
|
30
31
|
"page_contact_submit": "发送",
|
|
32
|
+
"page_contact_unavailable": "在线留言尚未开通,请使用其他联系方式。您的输入已保留。",
|
|
31
33
|
"footer_copyright": "Copyright © {year}. All rights reserved."
|
|
32
34
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** website静态构建的显式开关、公开子路径和路由边界;普通SSR保持默认。 */
|
|
2
|
+
import { existsSync, lstatSync, readdirSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import process from 'node:process'
|
|
5
|
+
import { core } from '@h-ai/core'
|
|
6
|
+
import { resolvePublicBasePath } from './public-base-path.mjs'
|
|
7
|
+
|
|
8
|
+
const message = core.i18n.createMessageGetter({
|
|
9
|
+
'zh-CN': {
|
|
10
|
+
flag: 'HAI_BUILD_STATIC仅支持0或1;省略或0保持SSR,1启用website静态构建。',
|
|
11
|
+
base: 'PUBLIC_BASE_PATH须为空或以/开头的站内目录;不允许外部地址、末尾/、查询、片段或路径逃逸。',
|
|
12
|
+
modules: '静态website不能启用服务端业务模块。请使用--features none创建纯展示站点,或继续使用默认SSR。',
|
|
13
|
+
routes: '静态website不能包含自定义API、表单actions或未预渲染页面;请移除动态入口或使用SSR。',
|
|
14
|
+
assets: 'static是公开资产目录,不能放入.env私有环境文件或符号链接;请移动私有内容后重新构建。',
|
|
15
|
+
},
|
|
16
|
+
'en-US': {
|
|
17
|
+
flag: 'HAI_BUILD_STATIC accepts only 0 or 1: omitted/0 keeps SSR, and 1 enables a static website build.',
|
|
18
|
+
base: 'PUBLIC_BASE_PATH must be empty or a site-local directory beginning with /. External URLs, trailing /, queries, fragments and path traversal are not allowed.',
|
|
19
|
+
modules: 'A static website cannot enable server-side business modules. Create a presentation site with --features none, or keep the default SSR mode.',
|
|
20
|
+
routes: 'A static website cannot contain custom APIs, form actions or pages that were not prerendered. Remove dynamic routes or use SSR.',
|
|
21
|
+
assets: 'static is a public asset directory and cannot contain private .env files or symbolic links. Move private content before building.',
|
|
22
|
+
},
|
|
23
|
+
'ja-JP': {
|
|
24
|
+
flag: 'HAI_BUILD_STATICは0または1です。省略/0はSSR、1はwebsiteの静的構築を有効にします。',
|
|
25
|
+
base: 'PUBLIC_BASE_PATHは空、または/で始まるサイト内ディレクトリーです。外部URL、末尾の/、クエリー、フラグメント、パス逸脱は使えません。',
|
|
26
|
+
modules: '静的websiteではサーバー業務モジュールを有効にできません。--features noneで表示専用サイトを作成するか、既定のSSRを使用してください。',
|
|
27
|
+
routes: '静的websiteに独自API、form actions、事前描画されないページを含められません。動的ルートを削除するかSSRを使用してください。',
|
|
28
|
+
assets: 'staticは公開資産ディレクトリーです。非公開.envファイルやシンボリックリンクを置かず、非公開内容を移動してから構築してください。',
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
const serverFeatures = [{{#each websiteServerFeatures}}'{{this}}'{{#unless @last}}, {{/unless}}{{/each}}]
|
|
32
|
+
const requestedLocale = [process.env.HAI_CORE_DEFAULTLOCALE, process.env.LC_ALL, process.env.LC_MESSAGES, process.env.LANG].find(value => value?.trim())?.split(/[_.-]/)[0]?.toLowerCase()
|
|
33
|
+
const locale = requestedLocale === 'en' || requestedLocale === 'c' || requestedLocale === 'posix' ? 'en-US' : requestedLocale === 'ja' ? 'ja-JP' : 'zh-CN'
|
|
34
|
+
|
|
35
|
+
/** 只读取显式构建值,不加载dotenv和服务端秘密。 */
|
|
36
|
+
export function resolveStaticWebsite() {
|
|
37
|
+
const flag = process.env.HAI_BUILD_STATIC
|
|
38
|
+
if (flag !== undefined && flag !== '' && flag !== '0' && flag !== '1')
|
|
39
|
+
throw new Error(message('flag', { locale }))
|
|
40
|
+
const enabled = flag === '1'
|
|
41
|
+
const base = resolvePublicBasePath()
|
|
42
|
+
if (enabled && serverFeatures.length)
|
|
43
|
+
throw new Error(`${message('modules', { locale })} (${serverFeatures.join(', ')})`)
|
|
44
|
+
if (enabled) {
|
|
45
|
+
const assets = path.resolve(process.cwd(), 'static')
|
|
46
|
+
if (existsSync(assets)) {
|
|
47
|
+
if (lstatSync(assets).isSymbolicLink())
|
|
48
|
+
throw new Error(message('assets', { locale }))
|
|
49
|
+
for (const entry of readdirSync(assets, { recursive: true, withFileTypes: true })) {
|
|
50
|
+
if (entry.isSymbolicLink() || entry.name === '.env' || entry.name.startsWith('.env.'))
|
|
51
|
+
throw new Error(message('assets', { locale }))
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { enabled, base }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** @param {import('@sveltejs/kit').Builder['routes']} routes - SvelteKit实际解析的路由。 */
|
|
59
|
+
export function validateStaticRoutes(routes) {
|
|
60
|
+
const invalid = routes.filter((route) => {
|
|
61
|
+
// Builder始终提供api/page对象;只按实际方法判断,模板健康端点也不能豁免新增写入方法。
|
|
62
|
+
const templateHealth = route.id === '/api/health' && route.page.methods.length === 0 && route.api.methods.length > 0 && route.api.methods.every(method => method === 'GET' || method === 'HEAD')
|
|
63
|
+
return !templateHealth && (route.api.methods.length > 0 || route.prerender !== true || route.page.methods.includes('POST'))
|
|
64
|
+
})
|
|
65
|
+
if (invalid.length)
|
|
66
|
+
throw new Error(`${message('routes', { locale })} (${invalid.map(route => route.id).join(', ')})`)
|
|
67
|
+
}
|
|
@@ -1,23 +1,73 @@
|
|
|
1
1
|
{{!-- 官网根布局 --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* 官网根布局
|
|
5
5
|
*/
|
|
6
6
|
import type { Snippet } from 'svelte'
|
|
7
|
-
import '../app.css'
|
|
8
7
|
{{#if hasI18n}}
|
|
9
8
|
import { browser } from '$app/environment'
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
{{else}}
|
|
10
|
+
{{#if features.crypto}}
|
|
11
|
+
import { browser } from '$app/environment'
|
|
12
|
+
{{/if}}
|
|
13
|
+
{{/if}}
|
|
14
|
+
import { {{#if features.iam}}base, {{else}}{{#if features.crypto}}base, {{/if}}{{/if}}resolve } from '$app/paths'
|
|
15
|
+
import { page } from '$app/state'
|
|
16
|
+
{{#if hasI18n}}
|
|
12
17
|
import * as m from '$lib/paraglide/messages'
|
|
18
|
+
import { getLocale, setLocale } from '$lib/paraglide/runtime.js'
|
|
19
|
+
{{/if}}
|
|
20
|
+
{{#if features.crypto}}
|
|
21
|
+
import { crypto } from '@h-ai/crypto'
|
|
22
|
+
import { kit } from '@h-ai/kit'
|
|
23
|
+
{{else}}
|
|
24
|
+
{{#if features.iam}}
|
|
25
|
+
import { kit } from '@h-ai/kit'
|
|
26
|
+
{{/if}}
|
|
13
27
|
{{/if}}
|
|
28
|
+
{{#if hasI18n}}
|
|
29
|
+
import { LanguageSwitch, setGlobalLocale, ToastContainer } from '@h-ai/ui'
|
|
30
|
+
{{else}}
|
|
31
|
+
import { ToastContainer } from '@h-ai/ui'
|
|
32
|
+
{{/if}}
|
|
33
|
+
{{#if features.crypto}}
|
|
34
|
+
import { untrack } from 'svelte'
|
|
35
|
+
{{/if}}
|
|
36
|
+
import '../app.css'
|
|
14
37
|
|
|
15
38
|
interface Props {
|
|
16
39
|
children: Snippet
|
|
17
40
|
}
|
|
18
41
|
|
|
19
|
-
|
|
42
|
+
const { children }: Props = $props()
|
|
43
|
+
{{#if features.crypto}}
|
|
44
|
+
if (browser)
|
|
45
|
+
kit.client.installBrowserTransport(untrack(() => page.data.kitConfig), { crypto, basePath: base })
|
|
46
|
+
{{/if}}
|
|
47
|
+
{{#if features.iam}}
|
|
48
|
+
const authActions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
|
|
49
|
+
$effect(() => authActions.bindPageExit({ enabled: page.data.iamPublicConfig?.session.endOnPageHide }))
|
|
50
|
+
{{/if}}
|
|
51
|
+
|
|
52
|
+
const navItems = [
|
|
20
53
|
{{#if hasI18n}}
|
|
54
|
+
{ path: '/', label: m.nav_home() },
|
|
55
|
+
{ path: '/about', label: m.nav_about() },
|
|
56
|
+
{ path: '/services', label: m.nav_services() },
|
|
57
|
+
{ path: '/contact', label: m.nav_contact() },
|
|
58
|
+
{{else}}
|
|
59
|
+
{ path: '/', label: '首页' },
|
|
60
|
+
{ path: '/about', label: '关于' },
|
|
61
|
+
{ path: '/services', label: '服务' },
|
|
62
|
+
{ path: '/contact', label: '联系我们' },
|
|
63
|
+
{{/if}}
|
|
64
|
+
] as const
|
|
65
|
+
{{#if hasI18n}}
|
|
66
|
+
|
|
67
|
+
function handleLanguageChange(language: string) {
|
|
68
|
+
setGlobalLocale(language)
|
|
69
|
+
setLocale(language as Parameters<typeof setLocale>[0])
|
|
70
|
+
}
|
|
21
71
|
|
|
22
72
|
if (browser) {
|
|
23
73
|
const paraglideLocale = getLocale()
|
|
@@ -26,41 +76,42 @@
|
|
|
26
76
|
{{/if}}
|
|
27
77
|
</script>
|
|
28
78
|
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
|
|
79
|
+
<svelte:head>
|
|
80
|
+
<title>{page.data.appConfig.name}</title>
|
|
81
|
+
</svelte:head>
|
|
82
|
+
|
|
83
|
+
<div class='min-h-screen flex flex-col'>
|
|
84
|
+
<header class='navbar flex-wrap bg-base-100 shadow-sm'>
|
|
85
|
+
<div class='flex-1'>
|
|
32
86
|
{{#if hasI18n}}
|
|
33
|
-
<a href=
|
|
87
|
+
<a href={resolve('/', {})} class='btn btn-ghost text-xl font-black tracking-tight'>{page.data.appConfig.name}</a>
|
|
34
88
|
{{else}}
|
|
35
|
-
<a href=
|
|
89
|
+
<a href={resolve('/', {})} class='btn btn-ghost text-xl font-black tracking-tight'>{page.data.appConfig.name}</a>
|
|
36
90
|
{{/if}}
|
|
37
91
|
</div>
|
|
38
|
-
<nav class=
|
|
39
|
-
<ul class=
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<li><a href="/services">{m.nav_services()}</a></li>
|
|
44
|
-
<li><a href="/contact">{m.nav_contact()}</a></li>
|
|
45
|
-
{{else}}
|
|
46
|
-
<li><a href="/">首页</a></li>
|
|
47
|
-
<li><a href="/about">关于</a></li>
|
|
48
|
-
<li><a href="/services">服务</a></li>
|
|
49
|
-
<li><a href="/contact">联系我们</a></li>
|
|
50
|
-
{{/if}}
|
|
92
|
+
<nav class='w-full flex-none sm:w-auto'>
|
|
93
|
+
<ul class='menu menu-horizontal flex-wrap px-1'>
|
|
94
|
+
{#each navItems as item (item.path)}
|
|
95
|
+
<li><a href={resolve(item.path, {})}>{item.label}</a></li>
|
|
96
|
+
{/each}
|
|
51
97
|
</ul>
|
|
52
98
|
</nav>
|
|
99
|
+
{{#if hasI18n}}
|
|
100
|
+
<LanguageSwitch currentLanguage={getLocale()} onchange={handleLanguageChange} />
|
|
101
|
+
{{/if}}
|
|
53
102
|
</header>
|
|
54
103
|
|
|
55
|
-
<main class=
|
|
104
|
+
<main class='flex-1'>
|
|
56
105
|
{@render children()}
|
|
57
106
|
</main>
|
|
58
107
|
|
|
59
|
-
<footer class=
|
|
108
|
+
<footer class='footer footer-center p-4 bg-base-300 text-base-content'>
|
|
109
|
+
<span>{page.data.appConfig.name} · {page.data.appConfig.version} · {page.data.appConfig.env}</span>
|
|
60
110
|
{{#if hasI18n}}
|
|
61
|
-
<p>{m.footer_copyright()}</p>
|
|
111
|
+
<p>{m.footer_copyright({ year: new Date().getFullYear() })}</p>
|
|
62
112
|
{{else}}
|
|
63
113
|
<p>Copyright © 2025 - All rights reserved</p>
|
|
64
114
|
{{/if}}
|
|
65
115
|
</footer>
|
|
66
116
|
</div>
|
|
117
|
+
<ToastContainer />
|