@h-ai/cli 1.0.0-beta.2 → 1.0.0-beta.20
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 +74 -154
- package/README.ja.md +74 -154
- package/README.md +74 -154
- package/dist/{chunk-AKV2CQZV.js → chunk-2ZL5ORQ2.js} +316 -97
- package/dist/chunk-2ZL5ORQ2.js.map +1 -0
- package/dist/{chunk-EF7WOFWZ.js → chunk-L53P43B2.js} +1312 -163
- package/dist/chunk-L53P43B2.js.map +1 -0
- package/dist/cli-config-templates-LWMD2I6V.js +5 -0
- package/dist/{cli-config-templates-HHFHNXBN.js.map → cli-config-templates-LWMD2I6V.js.map} +1 -1
- package/dist/{cli-skill-templates-PN4FLGBC.js → cli-skill-templates-D6S2OQ6X.js} +3 -3
- package/dist/{cli-skill-templates-PN4FLGBC.js.map → cli-skill-templates-D6S2OQ6X.js.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +30118 -3253
- package/dist/index.js.map +1 -1
- package/dist/metafile-esm.json +1 -1
- package/package.json +22 -18
- package/templates/README.md +45 -30
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +16 -10
- package/templates/apps/admin/src/routes/+page.svelte.hbs +4 -4
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +17 -7
- package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +26 -6
- package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +2 -2
- package/templates/apps/api/.dockerignore.hbs +10 -0
- package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +8 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +6 -1
- package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +13 -5
- package/templates/apps/api/apps/{{projectName}}-contract/tests/contract.test.ts.hbs +13 -5
- package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +3 -1
- package/templates/apps/api/apps/{{projectName}}-serv/README.md.hbs +6 -2
- package/templates/apps/api/apps/{{projectName}}-serv/config/_serv.yml.hbs +24 -2
- package/templates/apps/api/apps/{{projectName}}-serv/package.json.hbs +4 -4
- package/templates/apps/api/apps/{{projectName}}-serv/src/app.ts.hbs +74 -24
- package/templates/apps/api/apps/{{projectName}}-serv/src/build-metadata.ts.hbs +0 -1
- package/templates/apps/api/apps/{{projectName}}-serv/src/lib/server/init.ts.hbs +153 -37
- package/templates/apps/api/apps/{{projectName}}-serv/src/server/procedures/index.ts.hbs +39 -13
- package/templates/apps/api/apps/{{projectName}}-serv/tests/service.test.ts.hbs +106 -33
- package/templates/apps/api/apps/{{projectName}}-serv/tsup.config.ts.hbs +3 -1
- package/templates/apps/api/apps/{{projectName}}-serv/vitest.config.ts.hbs +3 -1
- package/templates/apps/api/e2e/api-serv.spec.ts.hbs +20 -3
- package/templates/apps/api/e2e/capture-evidence.ts.hbs +4 -1
- package/templates/apps/api/eslint.config.js.hbs +3 -1
- package/templates/apps/api/images/serv.Dockerfile.hbs +15 -10
- package/templates/apps/api/playwright.config.ts.hbs +23 -19
- package/templates/apps/api/pnpm-workspace.yaml.hbs +27 -16
- package/templates/apps/fullstack/.dockerignore.hbs +10 -0
- package/templates/apps/fullstack/.gitignore.hbs +7 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +14 -12
- package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +5 -3
- package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +10 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +10 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/build-metadata.ts.hbs +0 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +0 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +4 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +16 -4
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +10 -8
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +3 -3
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +8 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/build-metadata.ts.hbs +0 -1
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +0 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +4 -1
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +16 -4
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +2 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +9 -9
- package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +10 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/build-metadata.ts.hbs +0 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +0 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +4 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +19 -5
- package/templates/apps/fullstack/docs/security-configuration.md.hbs +4 -1
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +140 -28
- package/templates/apps/fullstack/e2e/session-close.spec.ts.hbs +19 -5
- package/templates/apps/fullstack/eslint.config.js.hbs +3 -1
- package/templates/apps/fullstack/images/serv.Dockerfile.hbs +19 -11
- package/templates/apps/fullstack/images/web.Dockerfile.hbs +17 -8
- package/templates/apps/fullstack/package.json.hbs +2 -1
- package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +7 -5
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +114 -23
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +57 -11
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +3 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +17 -7
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_reach.yml.hbs +13 -7
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +17 -7
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +10 -4
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +65 -30
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/build-metadata.ts.hbs +0 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +1 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +69 -21
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/business-settings.ts.hbs +21 -5
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +63 -11
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +6 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +3 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +147 -33
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/security-roles.ts.hbs +43 -12
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +146 -30
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/runtime.test.ts.hbs +33 -10
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/security.test.ts.hbs +142 -26
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +6 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/vitest.config.ts.hbs +3 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +48 -66
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/ja-JP.json.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +9 -2
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/feedback-client.ts.hbs +0 -3
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/sensitive-actions.svelte.ts.hbs +15 -3
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +33 -7
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/FeedbackEntry.svelte.hbs +16 -2
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/audit.svelte.hbs +104 -13
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/feedback.svelte.hbs +37 -7
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/roles.svelte.hbs +9 -3
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +25 -3
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/users.svelte.hbs +133 -19
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/security/role-label.ts.hbs +14 -2
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/guide-store.ts.hbs +66 -34
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +132 -30
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme-store.svelte.ts.hbs +8 -2
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +23 -5
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +143 -21
- package/templates/apps/fullstack/packages/{{projectName}}-shared/vitest.config.ts.hbs +7 -2
- package/templates/apps/fullstack/playwright.config.ts.hbs +25 -3
- package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +30 -14
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +74 -30
- package/templates/apps/h5/src/routes/+page.svelte.hbs +2 -2
- package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +2 -2
- package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +2 -2
- package/templates/apps/mobile-app/capacitor.config.ts.hbs +5 -2
- package/templates/apps/mobile-app/messages/en-US.json +2 -2
- package/templates/apps/mobile-app/messages/ja-JP.json +2 -2
- package/templates/apps/mobile-app/messages/zh-CN.json +2 -2
- package/templates/apps/mobile-app/src/App.svelte.hbs +17 -5
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +20 -6
- package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +8 -1
- package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +6 -2
- package/templates/apps/mobile-app/src/lib/pages/profile.svelte.hbs +13 -1
- package/templates/apps/mobile-app/src/lib/pages/tasks.svelte.hbs +5 -1
- package/templates/apps/website/scripts/static-website.mjs.hbs +19 -6
- package/templates/apps/website/src/routes/+layout.svelte.hbs +56 -29
- package/templates/apps/website/src/routes/+page.svelte.hbs +4 -4
- package/templates/apps/website/src/routes/about/+page.svelte.hbs +2 -2
- package/templates/apps/website/src/routes/contact/+page.svelte.hbs +2 -2
- package/templates/apps/website/src/routes/services/+page.svelte.hbs +20 -5
- package/templates/base/.dockerignore.hbs +10 -0
- package/templates/base/.gitignore.hbs +7 -2
- package/templates/base/e2e/app.spec.ts.hbs +130 -36
- package/templates/base/eslint-rules.js +44 -25
- package/templates/base/eslint.config.js.hbs +3 -1
- package/templates/base/images/web.Dockerfile.hbs +25 -14
- package/templates/base/package.json.hbs +13 -7
- package/templates/base/patches/daisyui-5.7.50.patch +8 -0
- package/templates/base/patches/deepmerge-4.3.1.patch +51 -0
- package/templates/base/playwright.config.ts +3 -1
- package/templates/base/pnpm-workspace.yaml.hbs +33 -16
- package/templates/base/src/app.d.ts.hbs +1 -1
- package/templates/base/src/app.html.hbs +1 -0
- package/templates/base/src/hooks.server.ts.hbs +44 -33
- package/templates/base/src/lib/build-metadata.ts.hbs +0 -1
- package/templates/base/src/lib/server/init.ts.hbs +146 -35
- package/templates/base/src/lib/server/kit-config.ts.hbs +7 -4
- package/templates/base/src/routes/+layout.server.ts.hbs +2 -2
- package/templates/base/svelte.config.js.hbs +10 -100
- package/templates/base/tests/scaffold.test.ts.hbs +12 -3
- package/templates/base/tsconfig.json.hbs +7 -4
- package/templates/base/vite.config.ts.hbs +108 -14
- package/templates/base/vitest.config.ts.hbs +6 -2
- package/templates/features/ai/routes/api/chat/+server.ts +3 -1
- package/templates/features/iam/routes-admin/(auth)/auth/forgot-password/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-admin/(auth)/auth/reset-password/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-h5/auth/forgot-password/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-h5/auth/reset-password/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-website/auth/forgot-password/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-website/auth/login/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-website/auth/register/+page.svelte.hbs +3 -3
- package/templates/features/iam/routes-website/auth/reset-password/+page.svelte.hbs +3 -3
- package/templates/features/payment/routes/api/v1/payment/create/+server.ts +14 -3
- package/templates/shared/browser-check/startup.js +115 -0
- package/templates/shared/browser-check/update.css +37 -0
- package/templates/shared/browser-check/update.html +19 -0
- package/templates/shared/browser-startup.spec.ts +23 -0
- package/templates/shared/build-metadata.ts +18 -4
- package/templates/shared/e2e-env.ts +22 -6
- package/templates/shared/native-name.d.mts +5 -0
- package/templates/shared/native-name.mjs +94 -0
- package/templates/shared/public-base-path.mjs +17 -4
- package/templates/shared/run-e2e.mjs +46 -12
- package/templates/shared/run-node.mjs +56 -0
- package/templates/shared/run-tauri.mjs +74 -0
- package/templates/shared/vite-runtime-config.ts +9 -3
- package/templates/skills/AGENTS.md +10 -73
- package/templates/skills/bridges/admin/AGENTS.md +9 -65
- package/templates/skills/bridges/api/AGENTS.md +8 -59
- package/templates/skills/bridges/fullstack/AGENTS.md.hbs +9 -54
- package/templates/skills/bridges/h5/AGENTS.md +8 -63
- package/templates/skills/bridges/mobile-app/AGENTS.md +8 -62
- package/templates/skills/bridges/website/AGENTS.md +8 -63
- package/templates/skills/hai-ai/SKILL.md +6 -2
- package/templates/skills/hai-ai/acp.md +153 -0
- package/templates/skills/hai-ai/guide.md +27 -12
- package/templates/skills/hai-ai/reference.md +24 -15
- package/templates/skills/hai-ai/resources.md +69 -0
- package/templates/skills/hai-api-client/SKILL.md +1 -1
- package/templates/skills/hai-api-client/reference.md +3 -1
- package/templates/skills/hai-app-create/collaboration.md +7 -0
- package/templates/skills/hai-app-create/development.md +19 -10
- package/templates/skills/hai-app-create/project.md +33 -0
- package/templates/skills/hai-app-create/reference.md +10 -10
- package/templates/skills/hai-app-tests/reference.md +1 -1
- package/templates/skills/hai-app-tests/validation.md +1 -0
- package/templates/skills/hai-build/SKILL.md +19 -9
- package/templates/skills/hai-build/paths.md +4 -2
- package/templates/skills/hai-build/reference.md +26 -8
- package/templates/skills/hai-cache/reference.md +6 -2
- package/templates/skills/hai-capacitor/SKILL.md +1 -0
- package/templates/skills/hai-capacitor/reference.md +24 -0
- package/templates/skills/hai-ci/SKILL.md +3 -0
- package/templates/skills/hai-core/SKILL.md +9 -4
- package/templates/skills/hai-core/reference.md +40 -10
- package/templates/skills/hai-core/request-access.md +2 -2
- package/templates/skills/hai-crypto/SKILL.md +2 -2
- package/templates/skills/hai-crypto/reference.md +7 -3
- package/templates/skills/hai-deploy/SKILL.md +41 -5
- package/templates/skills/hai-deploy/middleware.md +26 -14
- package/templates/skills/hai-framework-sync/SKILL.md +13 -9
- package/templates/skills/hai-framework-sync/sync.md +2 -0
- package/templates/skills/hai-iam/reference.md +2 -2
- package/templates/skills/hai-kit/SKILL.md +1 -1
- package/templates/skills/hai-kit/reference.md +19 -5
- package/templates/skills/hai-payment/reference.md +41 -17
- package/templates/skills/hai-reach/SKILL.md +3 -1
- package/templates/skills/hai-reach/reference.md +29 -9
- package/templates/skills/hai-reldb/SKILL.md +1 -1
- package/templates/skills/hai-reldb/reference.md +9 -2
- package/templates/skills/hai-scheduler/reference.md +1 -1
- package/templates/skills/hai-serv/SKILL.md +2 -1
- package/templates/skills/hai-serv/reference.md +26 -15
- package/templates/skills/hai-storage/reference.md +23 -6
- package/templates/skills/hai-ui/SKILL.md +8 -5
- package/templates/skills/hai-ui/charts.md +51 -0
- package/templates/skills/hai-ui/guide.md +1 -1
- package/templates/skills/hai-ui/reference.md +29 -38
- package/templates/skills/hai-vecdb/reference.md +8 -3
- package/dist/chunk-AKV2CQZV.js.map +0 -1
- package/dist/chunk-EF7WOFWZ.js.map +0 -1
- package/dist/chunk-MUHRBJSW.js +0 -29272
- package/dist/chunk-MUHRBJSW.js.map +0 -1
- package/dist/cli-config-templates-HHFHNXBN.js +0 -5
- package/dist/src-TEBHR5I5.js +0 -5
- package/dist/src-TEBHR5I5.js.map +0 -1
- package/templates/apps/fullstack/playwright.session-close.config.ts.hbs +0 -18
|
@@ -4,17 +4,29 @@ import type { AddressInfo } from 'node:net'
|
|
|
4
4
|
import { mkdtempSync, rmSync } from 'node:fs'
|
|
5
5
|
import { tmpdir } from 'node:os'
|
|
6
6
|
import { join } from 'node:path'
|
|
7
|
-
{{#if features.ai}}
|
|
8
|
-
|
|
9
|
-
{{
|
|
10
|
-
|
|
11
|
-
{{#if features.
|
|
12
|
-
|
|
13
|
-
{{/if}}
|
|
14
|
-
|
|
15
|
-
{{
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
{{#if features.ai}}
|
|
8
|
+
import { ai } from '@h-ai/ai'
|
|
9
|
+
{{/if}}
|
|
10
|
+
import { apiClient } from '@h-ai/api-client'
|
|
11
|
+
{{#if features.cache}}
|
|
12
|
+
import { cache } from '@h-ai/cache'
|
|
13
|
+
{{/if}}
|
|
14
|
+
import { core } from '@h-ai/core'
|
|
15
|
+
{{#if features.iam}}
|
|
16
|
+
import { iam } from '@h-ai/iam'
|
|
17
|
+
{{/if}}
|
|
18
|
+
{{#if features.db}}
|
|
19
|
+
import { reldb } from '@h-ai/reldb'
|
|
20
|
+
{{/if}}
|
|
21
|
+
import { serv } from '@h-ai/serv'
|
|
22
|
+
{{#if features.storage}}
|
|
23
|
+
import { storage } from '@h-ai/storage'
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{#if features.vecdb}}
|
|
26
|
+
import { vecdb } from '@h-ai/vecdb'
|
|
27
|
+
{{/if}}
|
|
28
|
+
import { {{api.contractExportName}} } from '{{api.contractPackageName}}'
|
|
29
|
+
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
|
|
18
30
|
|
|
19
31
|
import { {{api.serviceAppFactoryName}} } from '../src/app.js'
|
|
20
32
|
|
|
@@ -23,10 +35,12 @@ let baseUrl = ''
|
|
|
23
35
|
let client: ReturnType<typeof apiClient.create<typeof {{api.contractExportName}}>>
|
|
24
36
|
let server: ReturnType<typeof serv.listen>
|
|
25
37
|
let servConfig: ServConfig
|
|
26
|
-
{{#if features.storage}}
|
|
27
|
-
|
|
38
|
+
{{#if features.storage}}
|
|
39
|
+
let storageRoot = ''
|
|
40
|
+
{{/if}}
|
|
41
|
+
{{#if features.vecdb}}
|
|
42
|
+
let vecdbRoot = ''
|
|
28
43
|
{{/if}}
|
|
29
|
-
|
|
30
44
|
{{#if features.iam}}
|
|
31
45
|
function uniqueUser(prefix = 'api') {
|
|
32
46
|
const suffix = `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`.slice(-8)
|
|
@@ -40,10 +54,14 @@ function uniqueUser(prefix = 'api') {
|
|
|
40
54
|
|
|
41
55
|
beforeAll(async () => {
|
|
42
56
|
tempRoot = mkdtempSync(join(tmpdir(), '{{projectName}}-service-test-'))
|
|
43
|
-
{{#if features.storage}}
|
|
44
|
-
|
|
57
|
+
{{#if features.storage}}
|
|
58
|
+
storageRoot = join(tempRoot, 'storage')
|
|
59
|
+
{{/if}}
|
|
60
|
+
{{#if features.vecdb}}
|
|
61
|
+
vecdbRoot = join(tempRoot, 'vecdb')
|
|
45
62
|
{{/if}}
|
|
46
63
|
|
|
64
|
+
vi.stubEnv('HAI_SERV_CORS_NATIVEORIGINS', undefined)
|
|
47
65
|
core.init({
|
|
48
66
|
configDir: './config',
|
|
49
67
|
logging: { level: 'warn' },
|
|
@@ -54,27 +72,32 @@ beforeAll(async () => {
|
|
|
54
72
|
const dbResult = await reldb.init({ type: 'sqlite', database: ':memory:' })
|
|
55
73
|
if (!dbResult.success)
|
|
56
74
|
throw new Error(`reldb: ${dbResult.error.message}`)
|
|
57
|
-
{{/if}}
|
|
75
|
+
{{/if}}
|
|
76
|
+
{{#if features.cache}}
|
|
58
77
|
|
|
59
78
|
const cacheResult = await cache.init({ type: 'memory' })
|
|
60
79
|
if (!cacheResult.success)
|
|
61
80
|
throw new Error(`cache: ${cacheResult.error.message}`)
|
|
62
|
-
{{/if}}
|
|
81
|
+
{{/if}}
|
|
82
|
+
{{#if features.vecdb}}
|
|
63
83
|
|
|
64
84
|
const vecdbResult = await vecdb.init({ type: 'lancedb', path: vecdbRoot })
|
|
65
85
|
if (!vecdbResult.success)
|
|
66
86
|
throw new Error(`vecdb: ${vecdbResult.error.message}`)
|
|
67
|
-
{{/if}}
|
|
87
|
+
{{/if}}
|
|
88
|
+
{{#if features.iam}}
|
|
68
89
|
|
|
69
90
|
const iamResult = await iam.init({})
|
|
70
91
|
if (!iamResult.success)
|
|
71
92
|
throw new Error(`iam: ${iamResult.error.message}`)
|
|
72
|
-
{{/if}}
|
|
93
|
+
{{/if}}
|
|
94
|
+
{{#if features.storage}}
|
|
73
95
|
|
|
74
96
|
const storageResult = await storage.init({ type: 'local', root: storageRoot })
|
|
75
97
|
if (!storageResult.success)
|
|
76
98
|
throw new Error(`storage: ${storageResult.error.message}`)
|
|
77
|
-
{{/if}}
|
|
99
|
+
{{/if}}
|
|
100
|
+
{{#if features.ai}}
|
|
78
101
|
|
|
79
102
|
const aiResult = await ai.init({})
|
|
80
103
|
if (!aiResult.success)
|
|
@@ -82,8 +105,7 @@ beforeAll(async () => {
|
|
|
82
105
|
{{/if}}
|
|
83
106
|
|
|
84
107
|
const app = {{api.serviceAppFactoryName}}({
|
|
85
|
-
transport: 'disabled',
|
|
86
|
-
refreshCookie: 'disabled',{{/if}}
|
|
108
|
+
transport: 'disabled',
|
|
87
109
|
})
|
|
88
110
|
const listening = new Promise<AddressInfo>((resolve) => {
|
|
89
111
|
server = serv.listen(app, {
|
|
@@ -98,7 +120,11 @@ beforeAll(async () => {
|
|
|
98
120
|
client = apiClient.create({{api.contractExportName}})
|
|
99
121
|
const initResult = await client.init({
|
|
100
122
|
baseUrl: `${baseUrl}${servConfig.http.apiPrefix}`,
|
|
101
|
-
|
|
123
|
+
clientName: 'hai-mobile-app',
|
|
124
|
+
headers: { 'origin': 'capacitor://localhost', 'x-hai-token-transport': 'body' },
|
|
125
|
+
auth: {
|
|
126
|
+
storage: apiClient.tokenStorage.memory(),
|
|
127
|
+
},
|
|
102
128
|
})
|
|
103
129
|
if (!initResult.success)
|
|
104
130
|
throw new Error(`client.init: ${initResult.error.message}`)
|
|
@@ -107,13 +133,26 @@ beforeAll(async () => {
|
|
|
107
133
|
afterAll(async () => {
|
|
108
134
|
await client?.close()
|
|
109
135
|
await server?.close()
|
|
110
|
-
{{#if features.ai}}
|
|
111
|
-
|
|
112
|
-
{{/if}}
|
|
113
|
-
{{
|
|
114
|
-
|
|
115
|
-
{{/if}}
|
|
116
|
-
{{
|
|
136
|
+
{{#if features.ai}}
|
|
137
|
+
await ai.close()
|
|
138
|
+
{{/if}}
|
|
139
|
+
{{#if features.storage}}
|
|
140
|
+
await storage.close()
|
|
141
|
+
{{/if}}
|
|
142
|
+
{{#if features.iam}}
|
|
143
|
+
await iam.close()
|
|
144
|
+
{{/if}}
|
|
145
|
+
{{#if features.vecdb}}
|
|
146
|
+
await vecdb.close()
|
|
147
|
+
{{/if}}
|
|
148
|
+
{{#if features.cache}}
|
|
149
|
+
await cache.close()
|
|
150
|
+
{{/if}}
|
|
151
|
+
{{#if features.db}}
|
|
152
|
+
await reldb.close()
|
|
153
|
+
{{/if}}
|
|
154
|
+
rmSync(tempRoot, { recursive: true, force: true })
|
|
155
|
+
vi.unstubAllEnvs()
|
|
117
156
|
})
|
|
118
157
|
|
|
119
158
|
describe('{{api.servPackageName}}', () => {
|
|
@@ -132,7 +171,12 @@ describe('{{api.servPackageName}}', () => {
|
|
|
132
171
|
expect(result.success).toBe(true)
|
|
133
172
|
if (result.success) {
|
|
134
173
|
const config = core.config.getOrThrow<CoreConfig>('core')
|
|
135
|
-
expect(result.data).toMatchObject({
|
|
174
|
+
expect(result.data).toMatchObject({
|
|
175
|
+
name: config.name,
|
|
176
|
+
version: config.version,
|
|
177
|
+
env: config.env,
|
|
178
|
+
defaultLocale: config.defaultLocale,
|
|
179
|
+
})
|
|
136
180
|
expect(typeof result.data.transportEnabled).toBe('boolean')
|
|
137
181
|
}
|
|
138
182
|
})
|
|
@@ -142,8 +186,37 @@ describe('{{api.servPackageName}}', () => {
|
|
|
142
186
|
|
|
143
187
|
expect(result.success).toBe(false)
|
|
144
188
|
})
|
|
145
|
-
|
|
146
189
|
{{#if features.iam}}
|
|
190
|
+
it.each([
|
|
191
|
+
['capacitor://localhost', 'hai-mobile-app'],
|
|
192
|
+
['https://localhost', 'hai-mobile-app'],
|
|
193
|
+
['http://tauri.localhost', 'hai-desktop-app'],
|
|
194
|
+
['https://tauri.localhost', 'hai-desktop-app'],
|
|
195
|
+
['tauri://localhost', 'hai-desktop-app'],
|
|
196
|
+
])('refreshes an expired access token at the default native Origin %s', async (origin, clientName) => {
|
|
197
|
+
const native = apiClient.create({{api.contractExportName}})
|
|
198
|
+
try {
|
|
199
|
+
expect((await native.init({
|
|
200
|
+
baseUrl: `${baseUrl}${servConfig.http.apiPrefix}`,
|
|
201
|
+
clientName,
|
|
202
|
+
headers: { 'origin': origin, 'x-hai-token-transport': 'body' },
|
|
203
|
+
auth: {
|
|
204
|
+
storage: apiClient.tokenStorage.memory(),
|
|
205
|
+
},
|
|
206
|
+
})).success).toBe(true)
|
|
207
|
+
const registration = await apiClient.createAuthActions(native).register(uniqueUser('refresh'))
|
|
208
|
+
expect(registration.success).toBe(true)
|
|
209
|
+
if (!registration.success)
|
|
210
|
+
return
|
|
211
|
+
expect(registration.data.tokens.refreshToken).toBeTruthy()
|
|
212
|
+
await native.auth.setTokens({ ...registration.data.tokens, accessToken: 'expired-access-for-test' })
|
|
213
|
+
expect((await native.iam.auth.currentUser()).success).toBe(true)
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
await native.close()
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
|
|
147
220
|
it('registers a user and returns authenticated echo context', async () => {
|
|
148
221
|
const user = uniqueUser('svc')
|
|
149
222
|
const authActions = apiClient.createAuthActions(client)
|
|
@@ -6,7 +6,9 @@ import { resolveBuildMetadata } from '../../scripts/build-metadata.js'
|
|
|
6
6
|
const buildMetadata = resolveBuildMetadata(fileURLToPath(new URL('.', import.meta.url)))
|
|
7
7
|
|
|
8
8
|
export default defineConfig({
|
|
9
|
-
define: {
|
|
9
|
+
define: {
|
|
10
|
+
__HAI_BUILD_METADATA__: JSON.stringify(buildMetadata),
|
|
11
|
+
},
|
|
10
12
|
async onSuccess() {
|
|
11
13
|
await writeFile(new URL('./dist/build-metadata.json', import.meta.url), JSON.stringify(buildMetadata))
|
|
12
14
|
},
|
|
@@ -3,7 +3,9 @@ import { defineConfig } from 'vitest/config'
|
|
|
3
3
|
import { resolveBuildMetadata } from '../../scripts/build-metadata.js'
|
|
4
4
|
|
|
5
5
|
export default defineConfig({
|
|
6
|
-
define: {
|
|
6
|
+
define: {
|
|
7
|
+
__HAI_BUILD_METADATA__: JSON.stringify(resolveBuildMetadata(fileURLToPath(new URL('.', import.meta.url)))),
|
|
8
|
+
},
|
|
7
9
|
test: {
|
|
8
10
|
globals: true,
|
|
9
11
|
environment: 'node',
|
|
@@ -16,7 +16,9 @@ test.beforeAll(async () => {
|
|
|
16
16
|
const result = await client.init({
|
|
17
17
|
baseUrl: `${process.env.BASE_URL || 'http://127.0.0.1:3000'}${API_PREFIX}`,
|
|
18
18
|
{{#if features.iam}}
|
|
19
|
-
auth: {
|
|
19
|
+
auth: {
|
|
20
|
+
storage: apiClient.tokenStorage.memory(),
|
|
21
|
+
},
|
|
20
22
|
{{/if}}
|
|
21
23
|
{{#if features.crypto}}
|
|
22
24
|
transport: { crypto },
|
|
@@ -105,9 +107,24 @@ test('feedback intake is idempotent and creator can append evidence without admi
|
|
|
105
107
|
expect(duplicate.success).toBe(true)
|
|
106
108
|
if (duplicate.success)
|
|
107
109
|
expect(duplicate.data.id).toBe(created.data.id)
|
|
108
|
-
const evidence = await client.feedback.reports.appendEvidence({
|
|
110
|
+
const evidence = await client.feedback.reports.appendEvidence({
|
|
111
|
+
id: created.data.id,
|
|
112
|
+
evidence: [
|
|
113
|
+
{
|
|
114
|
+
id: 'event-1',
|
|
115
|
+
source: 'api-test',
|
|
116
|
+
sequence: 1,
|
|
117
|
+
kind: 'business',
|
|
118
|
+
timestamp: Date.now(),
|
|
119
|
+
data: { action: 'api-feedback' },
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
})
|
|
109
123
|
expect(evidence.success).toBe(true)
|
|
110
|
-
expect((await client.feedback.reports.completeCollection({
|
|
124
|
+
expect((await client.feedback.reports.completeCollection({
|
|
125
|
+
id: created.data.id,
|
|
126
|
+
missing: ['browser-not-applicable'],
|
|
127
|
+
})).success).toBe(true)
|
|
111
128
|
expect((await client.feedback.reports.list({})).success).toBe(false)
|
|
112
129
|
})
|
|
113
130
|
{{/if}}
|
|
@@ -15,7 +15,10 @@ export default async function captureEvidence() {
|
|
|
15
15
|
expect(response?.status()).toBe(200)
|
|
16
16
|
await expect(page.locator('body')).toContainText('ok')
|
|
17
17
|
await mkdir(evidence, { recursive: true })
|
|
18
|
-
await page.screenshot({
|
|
18
|
+
await page.screenshot({
|
|
19
|
+
path: path.join(evidence, '{{projectName}}-health.png'),
|
|
20
|
+
fullPage: true,
|
|
21
|
+
})
|
|
19
22
|
}
|
|
20
23
|
finally {
|
|
21
24
|
await browser.close()
|
|
@@ -3,7 +3,9 @@ import { haiQualityConfig } from './eslint-rules.js'
|
|
|
3
3
|
|
|
4
4
|
export default antfu({
|
|
5
5
|
// unused-imports 使用 TS 规则,JS 同样使用 TS parser 以保持 scope 契约一致。
|
|
6
|
-
typescript: {
|
|
6
|
+
typescript: {
|
|
7
|
+
files: [GLOB_SRC],
|
|
8
|
+
},
|
|
7
9
|
formatters: true,
|
|
8
10
|
ignores: [
|
|
9
11
|
'**/dist/**',
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
ENV npm_config_better_sqlite3_binary_host_mirror=$SQLITE_PREBUILD_MIRROR
|
|
1
|
+
ARG HAI_NODE_IMAGE=node:24.22.1-bookworm-slim
|
|
2
|
+
FROM ${HAI_NODE_IMAGE} AS build
|
|
4
3
|
|
|
5
4
|
ENV PNPM_HOME=/pnpm
|
|
6
5
|
ENV PATH=$PNPM_HOME:$PATH
|
|
@@ -8,19 +7,25 @@ ENV CI=true
|
|
|
8
7
|
ENV ONNXRUNTIME_NODE_INSTALL_CUDA=skip
|
|
9
8
|
WORKDIR /workspace
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
ARG HAI_NPM_REGISTRY=https://registry.npmjs.org
|
|
11
|
+
ARG COREPACK_NPM_REGISTRY=$HAI_NPM_REGISTRY
|
|
12
|
+
ARG npm_config_registry=$HAI_NPM_REGISTRY
|
|
13
|
+
ARG pnpm_config_registry=$HAI_NPM_REGISTRY
|
|
14
|
+
RUN node -e "const p=process.env.HTTPS_PROXY||process.env.HTTP_PROXY;if(p){const u=new URL(p);const s=require('node:net').connect({host:u.hostname,port:Number(u.port||(u.protocol==='https:'?443:80))});s.setTimeout(3000);s.on('connect',()=>s.end());const fail=()=>{process.stderr.write('Build proxy is unreachable from the container. Check the host address and proxy listener.\\n');process.exit(1)};s.on('error',fail);s.on('timeout',fail)}" && corepack enable && corepack prepare pnpm@12.11.2 --activate && pnpm config set store-dir /pnpm/store
|
|
12
15
|
COPY pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
13
16
|
COPY images/dependencies/ ./
|
|
14
|
-
RUN --mount=type=cache,id={{projectName}}-pnpm,target=/pnpm/store pnpm fetch --ignore-scripts
|
|
17
|
+
RUN --mount=type=cache,id={{projectName}}-pnpm,target=/pnpm/store pnpm fetch --reporter=append-only --ignore-scripts
|
|
18
|
+
RUN --mount=type=cache,id={{projectName}}-pnpm,target=/pnpm/store pnpm install --reporter=append-only --offline --frozen-lockfile --ignore-scripts
|
|
15
19
|
COPY . .
|
|
16
|
-
RUN --mount=type=cache,id={{projectName}}-pnpm,target=/pnpm/store pnpm install --offline --frozen-lockfile --ignore-scripts
|
|
17
20
|
ARG HAI_BUILD_ID=
|
|
18
21
|
ARG HAI_BUILD_COMMIT=unknown
|
|
19
22
|
RUN HAI_BUILD_ID="$HAI_BUILD_ID" HAI_BUILD_COMMIT="$HAI_BUILD_COMMIT" pnpm compile
|
|
20
|
-
|
|
21
|
-
RUN
|
|
23
|
+
# SQLite 13 的原生二进制随 npm 包交付,在构建时验证实际加载。
|
|
24
|
+
RUN if [ -d node_modules/better-sqlite3 ]; then node -e "const Database=require('better-sqlite3');const db=new Database(':memory:');db.prepare('SELECT 1').get();db.close()"; fi
|
|
25
|
+
RUN --mount=type=cache,id={{projectName}}-pnpm,target=/pnpm/store pnpm pm deploy --filter {{api.servPackageName}} --prod /prod/app
|
|
26
|
+
RUN rm -f /prod/app/README* && find /prod/app/dist -type f \( -name '*.map' -o -name '*.d.ts' -o -name '*.d.mts' -o -name '*.d.cts' \) -delete
|
|
22
27
|
|
|
23
|
-
FROM
|
|
28
|
+
FROM ${HAI_NODE_IMAGE} AS runtime-base
|
|
24
29
|
|
|
25
30
|
ENV NODE_ENV=production
|
|
26
31
|
ENV HOST=0.0.0.0
|
|
@@ -33,5 +38,5 @@ RUN mkdir -p /app/data && chown node:node /app/data
|
|
|
33
38
|
USER node
|
|
34
39
|
EXPOSE 3000
|
|
35
40
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
|
36
|
-
CMD node -e "fetch('http://127.0.0.1:'+
|
|
41
|
+
CMD node -e "(async () => { try { const { core } = await import('@h-ai/core'); const { ServConfigSchema } = await import('@h-ai/serv'); core.init({ configDir: './config', configSchemas: { serv: ServConfigSchema } }); const { server, http } = ServConfigSchema.parse(core.config.getOrThrow('serv')); if (http.health === false) process.exit(0); const response = await fetch('http://127.0.0.1:' + server.port + http.health.path, { signal: AbortSignal.timeout(4000) }); process.exit(response.ok ? 0 : 1); } catch { process.exit(1); } })()"
|
|
37
42
|
CMD ["node", "dist/index.js"]
|
|
@@ -24,7 +24,9 @@ function resolvePortFromBaseUrl(urlString: string, fallbackPort: string): string
|
|
|
24
24
|
return url.port
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
return url.protocol === 'https:'
|
|
27
|
+
return url.protocol === 'https:'
|
|
28
|
+
? '443'
|
|
29
|
+
: '80'
|
|
28
30
|
}
|
|
29
31
|
catch {
|
|
30
32
|
return fallbackPort
|
|
@@ -46,22 +48,24 @@ export default defineConfig({
|
|
|
46
48
|
trace: 'retain-on-failure',
|
|
47
49
|
screenshot: 'only-on-failure',
|
|
48
50
|
},
|
|
49
|
-
webServer: [
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
webServer: [
|
|
52
|
+
{
|
|
53
|
+
name: '{{api.servPackageName}}',
|
|
54
|
+
command: 'pnpm --filter {{api.servPackageName}} exec node dist/index.js',
|
|
55
|
+
env: createE2eServerEnv({
|
|
56
|
+
...createE2eNotificationEnv(),
|
|
57
|
+
HAI_CORE_ENV: 'test',
|
|
58
|
+
HAI_DB: JSON.stringify({ type: 'sqlite', database: `${process.env.HAI_E2E_DATA_ROOT}/api.db` }),
|
|
59
|
+
HAI_CACHE: JSON.stringify({ type: 'memory' }),
|
|
60
|
+
HAI_STORAGE: JSON.stringify({ type: 'local', root: `${process.env.HAI_E2E_DATA_ROOT}/uploads` }),
|
|
61
|
+
HAI_VECDB: JSON.stringify({ type: 'lancedb', path: `${process.env.HAI_E2E_DATA_ROOT}/vecdb` }),
|
|
62
|
+
HAI_CRYPTO_TRANSPORT_SERVERKEYRING: createE2eTransportRing(),
|
|
63
|
+
HOST: serviceHost,
|
|
64
|
+
PORT: servicePort,
|
|
65
|
+
}),
|
|
66
|
+
url: `${baseURL}/health`,
|
|
67
|
+
reuseExistingServer: false,
|
|
68
|
+
timeout: 120_000,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
67
71
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{{! @skipIfEmpty }}
|
|
2
|
-
|
|
2
|
+
minimumReleaseAgeExcludePrune: true
|
|
3
3
|
|
|
4
4
|
trustPolicy: no-downgrade
|
|
5
5
|
# 上游构建工具仍要求 4.x;4.0.3 tarball 已核对原 lockfile 的 SHA-512。
|
|
@@ -8,33 +8,44 @@ trustPolicyExclude:
|
|
|
8
8
|
|
|
9
9
|
# pnpm 12 配置;原生依赖仅运行明确列出的安装脚本。
|
|
10
10
|
nodeLinker: hoisted
|
|
11
|
-
|
|
12
|
-
cpu-features: true
|
|
13
|
-
onnxruntime-node: true
|
|
14
|
-
protobufjs: true
|
|
15
|
-
ssh2: true
|
|
16
|
-
vue-demi: true
|
|
17
|
-
better-sqlite3: true
|
|
18
|
-
esbuild: true
|
|
19
|
-
core-js: false
|
|
11
|
+
shellEmulator: true
|
|
20
12
|
|
|
13
|
+
packages:
|
|
14
|
+
- apps/*
|
|
15
|
+
|
|
16
|
+
# 构建与浏览器依赖的安全修复;版本与框架工作区同步维护。
|
|
21
17
|
overrides:
|
|
22
|
-
|
|
18
|
+
'@ai-sdk/provider-utils@>=4.0.0 <4.0.33': 4.0.57
|
|
19
|
+
'@types/node': {{versions.nodeTypes}}
|
|
20
|
+
body-parser@>=2 <2.4.0: 2.4.0
|
|
23
21
|
cookie@<0.7.0: 0.7.2
|
|
22
|
+
dompurify@>=3 <3.4.17: 3.4.17
|
|
24
23
|
esbuild@<0.28.1: 0.28.2
|
|
24
|
+
fast-uri@>=3 <3.1.9: 3.1.9
|
|
25
|
+
follow-redirects@>=1.16.0 <1.16.2: 1.16.2
|
|
26
|
+
glob@>=9 <=14.0.1: 14.0.4
|
|
27
|
+
ip-address@<=10.7.3: 10.7.6
|
|
25
28
|
katex@<0.18.2: 0.18.10
|
|
29
|
+
minimatch@>=7 <11.0.1: 11.0.5
|
|
30
|
+
parse5@>=8 <8.1.0: 8.1.0
|
|
31
|
+
qs@>=6.7 <6.16.1: 6.17.1
|
|
32
|
+
runed@<0.38.0: 0.38.0
|
|
26
33
|
sharp@<0.35.5: 0.35.5
|
|
27
34
|
tinypool@<2.1.2: 2.2.0
|
|
28
|
-
'@qdrant/js-client-rest>undici': 7.30.0
|
|
29
35
|
xcode>uuid: 11.1.1
|
|
30
|
-
"@types/node": "{{versions.nodeTypes}}"
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
-
|
|
37
|
+
allowBuilds:
|
|
38
|
+
core-js: false
|
|
39
|
+
cpu-features: true
|
|
40
|
+
esbuild: true
|
|
41
|
+
onnxruntime-node: true
|
|
42
|
+
protobufjs: true
|
|
43
|
+
ssh2: true
|
|
44
|
+
vue-demi: true
|
|
34
45
|
|
|
35
46
|
{{#if useCatalogProtocol}}
|
|
36
47
|
catalog:
|
|
37
48
|
{{#each haiCatalogPackages}}
|
|
38
|
-
|
|
49
|
+
{{{yaml @key this}}}
|
|
39
50
|
{{/each}}
|
|
40
51
|
{{/if}}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
## 简介
|
|
6
6
|
|
|
7
|
+
`android` / `ios` 是需要维护的原生工程,应提交 Git;签名秘密单独忽略。普通 `clean` 保留这些目录,只清除构建产物。
|
|
8
|
+
|
|
7
9
|
App/H5 前端工程,复用 shared 的响应式 mini 后台,使用 Svelte 5 + Vite + Capacitor,可输出 Web 预览并同步 Android / iOS 原生工程。
|
|
8
10
|
|
|
9
11
|
## 核心功能清单
|
|
@@ -14,8 +16,12 @@ App/H5 前端工程,复用 shared 的响应式 mini 后台,使用 Svelte 5 +
|
|
|
14
16
|
|
|
15
17
|
## 使用入门
|
|
16
18
|
|
|
19
|
+
`capacitor.config.ts` 的 `appName` 动态读取 `packages/{{fullstack.servPackageName}}/config/_core.yml` 的 `name`,环境文件从工程根加载,支持 `HAI_CORE_NAME` 及 Core 的统一优先级。正式打包默认 `prod`,进程 `HAI_CORE_ENV` 可选择模式。名称在原生构建时固定;已有 Android/iOS 工程还需同步平台显示名(Android `strings.xml` 的 `app_name` / `title_activity_main`,iOS `CFBundleDisplayName`),再重新打包。
|
|
20
|
+
|
|
17
21
|
### i18n 与 shared 协同
|
|
18
22
|
|
|
23
|
+
先从工程根安装依赖并启动Serv。浏览器预览输入有效账号应进入共享界面,原生包还要配置设备真实可达API。上传头像的输入为允许类型且不超过512KiB的图片,输出为服务端生成资源标识和展示结果;不把本机任意路径当上传key。主题/语言改变后应在重新登录时恢复。
|
|
24
|
+
|
|
19
25
|
- 本端页面文案:`messages/{locale}.json` + `project.inlang/settings.json`
|
|
20
26
|
- 共享 Shell/主题/语言/API:`packages/{{fullstack.sharedPackageName}}`
|
|
21
27
|
- 语言切换通过 shared runtime 与本端 `src/lib/paraglide/runtime.js` 同步。
|
|
@@ -35,25 +41,21 @@ pnpm --filter {{projectName}}-app build
|
|
|
35
41
|
# 同步原生工程;首次使用前按需执行 cap:add:android / cap:add:ios
|
|
36
42
|
pnpm --filter {{projectName}}-app cap:sync
|
|
37
43
|
|
|
38
|
-
#
|
|
39
|
-
pnpm --
|
|
40
|
-
pnpm --
|
|
41
|
-
pnpm --
|
|
44
|
+
# 工程根的原生打包入口
|
|
45
|
+
pnpm build --target app --platform android --runtime auto --debug
|
|
46
|
+
pnpm build --target app --platform android --runtime auto
|
|
47
|
+
pnpm build --target app --platform ios
|
|
42
48
|
```
|
|
43
49
|
|
|
44
50
|
本地开发通过根 `.env` 的 `PUBLIC_API_BASE` 配置代理。原生打包前,在本端 `public/runtime-config.js` 中设置 `globalThis.__HAI_PUBLIC_CONFIG__ = { apiBase: 'https://api.example.com/api/v1' }`,再编译并同步原生工程;这里只能放公开地址,不能放密钥。Android 模拟器访问宿主机通常使用 `http://10.0.2.2:3000/api/v1`。
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### IAM 认证配置
|
|
49
|
-
|
|
50
|
-
服务端 `config/_iam.yml` 统一控制登录、注册、重置、协议与 `ui` 品牌。邮件/短信可用 `_reach.yml` 中的 Provider/标准模板或自定义发送回调。`AuthPanel` 使用安全公开配置及框架认证动作;无需在页面适配 Token、验证码倒计时和错误提示。Memory 仅用于本地开发和显式测试;生产环境即使只有一个实例,也须使用框架支持的共享数据库与 Redis,并按工程根 README 配置写入路由和传输会话。
|
|
52
|
+
Android 容器会安装依赖、编译 workspace 并打包。调试时可临时生成缺失的 Android 工程。发布时使用已有 Android 工程和私有签名配置,见 [Android 容器打包](../../.agents/skills/hai-capacitor/reference.md#android-容器打包)。iOS 使用 macOS/Xcode 和相应签名。`CAPACITOR_SERVER_URL` 仅供开发热更新。成功后 CLI 打印 `.hai/build/app/<平台>/<构建类型>/build-{{projectName}}-app-<平台>-<类型>-YYYYMMDD-HHmmss-<随机串>-<版本>/` 中的安装包路径;APK 如 `{{projectName}}-android-debug-<版本>.apk`,使用工程标识,显示名仍取 Core。
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
### 认证与模块导航
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
认证方式、注册、密码策略、协议与品牌由Serv的 `_iam.yml` 控制。前端只接收安全公开配置,使用共享AuthPanel和加密typed client;服务端再次核验权限。LDAP、通知回调、用途证明和会话限制在服务端接入,不把私密配置复制到客户端。
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
所有前端共用的偏好、认证存储、表单、审计与帮助行为见[共享工作区](../../packages/{{fullstack.sharedPackageName}}/README.md),详细配置见[生成应用IAM技能](../../.agents/skills/hai-iam/reference.md)。
|
|
57
59
|
|
|
58
60
|
启用反馈时,shared SDK 负责图片预览/比例标注/导出轮询;原生保存使用 Filesystem 缓存与 Share,完成/取消清理临时文件。首次添加 iOS 平台后按 Filesystem 插件要求配置 PrivacyInfo.xcprivacy。
|
|
59
61
|
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{{! @skipIfEmpty }}
|
|
2
2
|
{{#if fullstack.frontends.app}}
|
|
3
3
|
import type { CapacitorConfig } from '@capacitor/cli'
|
|
4
|
+
import { resolve } from 'node:path'
|
|
4
5
|
import process from 'node:process'
|
|
6
|
+
import { resolveNativeName } from '../../scripts/native-name.mjs'
|
|
5
7
|
|
|
8
|
+
const envDir = resolve(process.cwd(), '../..')
|
|
6
9
|
const config: CapacitorConfig = {
|
|
7
10
|
appId: 'com.hai.{{fullstack.nativeAppIdSegment}}.app',
|
|
8
|
-
appName: {{
|
|
11
|
+
appName: resolveNativeName(envDir, resolve(envDir, 'packages/{{fullstack.servPackageName}}/config/_core.yml')),
|
|
9
12
|
webDir: 'dist',
|
|
10
13
|
server: process.env.NODE_ENV === 'production'
|
|
11
14
|
? undefined
|
|
12
15
|
: {
|
|
13
|
-
|
|
16
|
+
// 仅用于 Capacitor live reload 前端页面;API 地址由前端配置或 shared client 参数控制。
|
|
14
17
|
url: process.env.CAPACITOR_SERVER_URL,
|
|
15
18
|
cleartext: process.env.CAPACITOR_SERVER_URL?.startsWith('http://') ?? false,
|
|
16
19
|
},
|
|
17
20
|
}
|
|
18
|
-
|
|
19
21
|
export default config
|
|
20
22
|
{{/if}}
|
|
@@ -5,9 +5,17 @@ import { haiQualityConfig } from '../../eslint-rules.js'
|
|
|
5
5
|
|
|
6
6
|
export default antfu({
|
|
7
7
|
// unused-imports 使用 TS 规则,JS 同样使用 TS parser 以保持 scope 契约一致。
|
|
8
|
-
typescript: {
|
|
8
|
+
typescript: {
|
|
9
|
+
files: [GLOB_SRC],
|
|
10
|
+
},
|
|
9
11
|
formatters: true,
|
|
10
|
-
ignores: [
|
|
12
|
+
ignores: [
|
|
13
|
+
'**/build/**',
|
|
14
|
+
'**/dist/**',
|
|
15
|
+
'**/*.d.ts',
|
|
16
|
+
'**/project.inlang/**',
|
|
17
|
+
'**/src/lib/paraglide/**',
|
|
18
|
+
],
|
|
11
19
|
svelte: true,
|
|
12
20
|
}, haiQualityConfig, {
|
|
13
21
|
files: ['**/*.svelte'],
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"lint:fix": "eslint . --fix",
|
|
24
24
|
"test": "pnpm paraglide:compile && vitest run --passWithNoTests",
|
|
25
25
|
"test:watch": "pnpm paraglide:compile && vitest",
|
|
26
|
-
"clean": "rimraf dist build
|
|
26
|
+
"clean": "rimraf dist build .turbo src/lib/paraglide",
|
|
27
27
|
"cap:add:android": "cap add android",
|
|
28
28
|
"cap:add:ios": "cap add ios",
|
|
29
29
|
"cap:sync": "pnpm build && cap sync",
|
|
@@ -30,7 +30,13 @@
|
|
|
30
30
|
apiOptions = {
|
|
31
31
|
clientName: '{{projectName}}-app',
|
|
32
32
|
terminalType: 'app',
|
|
33
|
-
...(capacitor.isNative()
|
|
33
|
+
...(capacitor.isNative()
|
|
34
|
+
? {
|
|
35
|
+
requireApiBase: true,
|
|
36
|
+
tokenStorage: createCapacitorTokenStorage(),
|
|
37
|
+
headers: { 'X-HAI-Token-Transport': 'body' },
|
|
38
|
+
}
|
|
39
|
+
: {}),
|
|
34
40
|
}
|
|
35
41
|
}
|
|
36
42
|
onMount(() => {
|
|
@@ -42,7 +48,9 @@
|
|
|
42
48
|
})
|
|
43
49
|
}
|
|
44
50
|
})
|
|
45
|
-
useToastFeedback(() => startupFailed
|
|
51
|
+
useToastFeedback(() => startupFailed
|
|
52
|
+
? messages.operation_failed()
|
|
53
|
+
: '')
|
|
46
54
|
</script>
|
|
47
55
|
|
|
48
56
|
{#if startupFailed}
|