@h-ai/cli 1.0.0-beta.18 → 1.0.0-beta.19
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 +4 -0
- package/README.ja.md +4 -0
- package/README.md +4 -0
- package/dist/{chunk-6YZBC5MO.js → chunk-2ZL5ORQ2.js} +85 -25
- package/dist/chunk-2ZL5ORQ2.js.map +1 -0
- package/dist/{chunk-7NVRYYHN.js → chunk-L53P43B2.js} +129 -31
- package/dist/chunk-L53P43B2.js.map +1 -0
- package/dist/cli-config-templates-LWMD2I6V.js +5 -0
- package/dist/{cli-config-templates-QG5HOYR5.js.map → cli-config-templates-LWMD2I6V.js.map} +1 -1
- package/dist/{cli-skill-templates-W4I6ZKYW.js → cli-skill-templates-D6S2OQ6X.js} +3 -3
- package/dist/{cli-skill-templates-W4I6ZKYW.js.map → cli-skill-templates-D6S2OQ6X.js.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2747 -671
- package/dist/index.js.map +1 -1
- package/dist/metafile-esm.json +1 -1
- package/package.json +22 -22
- 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/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/src/app.ts.hbs +71 -32
- 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 +131 -54
- 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 +78 -31
- 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 +3 -4
- package/templates/apps/api/playwright.config.ts.hbs +23 -19
- package/templates/apps/api/pnpm-workspace.yaml.hbs +27 -16
- package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +1 -3
- package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +10 -2
- 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/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/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}}-web/eslint.config.js.hbs +10 -2
- 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/e2e/fullstack.spec.ts.hbs +111 -26
- 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 +3 -4
- package/templates/apps/fullstack/images/web.Dockerfile.hbs +0 -2
- 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/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/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 +139 -49
- 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 +139 -28
- 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 +141 -25
- 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/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 +9 -3
- package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +30 -15
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +57 -21
- 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/src/App.svelte.hbs +17 -5
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +14 -3
- 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/tasks.svelte.hbs +5 -1
- package/templates/apps/website/scripts/static-website.mjs.hbs +16 -3
- package/templates/apps/website/src/routes/+layout.svelte.hbs +44 -23
- 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/e2e/app.spec.ts.hbs +49 -16
- package/templates/base/eslint-rules.js +44 -25
- package/templates/base/eslint.config.js.hbs +3 -1
- package/templates/base/images/web.Dockerfile.hbs +3 -4
- package/templates/base/package.json.hbs +5 -4
- 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/hooks.server.ts.hbs +36 -27
- package/templates/base/src/lib/build-metadata.ts.hbs +0 -1
- package/templates/base/src/lib/server/init.ts.hbs +124 -51
- 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 +11 -2
- package/templates/shared/browser-check/startup.js +32 -6
- package/templates/shared/browser-startup.spec.ts +3 -1
- package/templates/shared/build-metadata.ts +18 -4
- package/templates/shared/e2e-env.ts +22 -6
- package/templates/shared/native-name.mjs +9 -2
- package/templates/shared/public-base-path.mjs +17 -4
- package/templates/shared/run-e2e.mjs +40 -9
- package/templates/shared/run-node.mjs +15 -4
- package/templates/shared/run-tauri.mjs +37 -8
- 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/acp.md +2 -0
- package/templates/skills/hai-ai/guide.md +17 -6
- package/templates/skills/hai-ai/reference.md +21 -12
- package/templates/skills/hai-api-client/reference.md +1 -1
- package/templates/skills/hai-app-create/development.md +3 -1
- package/templates/skills/hai-app-create/project.md +33 -0
- package/templates/skills/hai-app-create/reference.md +8 -8
- package/templates/skills/hai-app-tests/reference.md +1 -1
- package/templates/skills/hai-build/SKILL.md +2 -2
- package/templates/skills/hai-build/paths.md +1 -1
- package/templates/skills/hai-build/reference.md +11 -7
- package/templates/skills/hai-capacitor/reference.md +2 -0
- package/templates/skills/hai-ci/SKILL.md +1 -0
- package/templates/skills/hai-core/reference.md +3 -0
- package/templates/skills/hai-crypto/reference.md +2 -0
- package/templates/skills/hai-deploy/SKILL.md +7 -1
- package/templates/skills/hai-deploy/middleware.md +3 -1
- package/templates/skills/hai-framework-sync/sync.md +2 -0
- package/templates/skills/hai-kit/reference.md +16 -4
- package/templates/skills/hai-payment/reference.md +2 -0
- package/templates/skills/hai-reach/SKILL.md +2 -1
- package/templates/skills/hai-reach/reference.md +1 -1
- package/templates/skills/hai-reldb/SKILL.md +1 -1
- package/templates/skills/hai-reldb/reference.md +4 -0
- package/templates/skills/hai-serv/reference.md +12 -2
- package/templates/skills/hai-storage/reference.md +12 -3
- package/templates/skills/hai-ui/SKILL.md +3 -2
- package/templates/skills/hai-ui/guide.md +1 -1
- package/templates/skills/hai-ui/reference.md +23 -35
- package/templates/skills/hai-vecdb/reference.md +1 -1
- package/dist/chunk-6YZBC5MO.js.map +0 -1
- package/dist/chunk-7NVRYYHN.js.map +0 -1
- package/dist/cli-config-templates-QG5HOYR5.js +0 -5
|
@@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'
|
|
|
12
12
|
{{#if_eq appType 'h5'}}
|
|
13
13
|
/** 延迟客户端脚本,覆盖 SSR 已显示而事件尚未绑定的阶段。 */
|
|
14
14
|
async function whileClientBootPaused(page: Page, inspect: () => Promise<void>) {
|
|
15
|
-
let resumeClient = () => {}
|
|
15
|
+
let resumeClient = () => { }
|
|
16
16
|
const clientBoot = new Promise<void>((resolve) => {
|
|
17
17
|
resumeClient = resolve
|
|
18
18
|
})
|
|
@@ -29,7 +29,6 @@ async function whileClientBootPaused(page: Page, inspect: () => Promise<void>) {
|
|
|
29
29
|
await page.unrouteAll({ behavior: 'wait' })
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
|
|
33
32
|
{{/if_eq}}
|
|
34
33
|
{{#if_eq appType 'admin'}}
|
|
35
34
|
test('high contrast appearance is selectable and survives reload', async ({ page }) => {
|
|
@@ -51,7 +50,6 @@ test('high contrast appearance is selectable and survives reload', async ({ page
|
|
|
51
50
|
expect(await header.locator('button').first().evaluate(element => getComputedStyle(element).borderTopLeftRadius)).toBe('0px')
|
|
52
51
|
})
|
|
53
52
|
{{/if_eq}}
|
|
54
|
-
|
|
55
53
|
{{#if hasUi}}
|
|
56
54
|
{{#unless isCapacitorApp}}
|
|
57
55
|
test('eye care appearance is selectable and survives reload', async ({ page }, testInfo) => {
|
|
@@ -73,19 +71,28 @@ test('eye care appearance is selectable and survives reload', async ({ page }, t
|
|
|
73
71
|
await expect(page.locator('html')).toHaveAttribute('data-theme', 'eye-care')
|
|
74
72
|
await expect.poll(() => page.evaluate(() => getComputedStyle(document.documentElement).colorScheme)).toBe('light')
|
|
75
73
|
await expect.poll(() => page.evaluate(() => getComputedStyle(document.documentElement).getPropertyValue('--color-base-100').trim())).toBe('#e8f0df')
|
|
76
|
-
await page.screenshot({
|
|
74
|
+
await page.screenshot({
|
|
75
|
+
path: testInfo.outputPath('eye-care-desktop.png'),
|
|
76
|
+
animations: 'disabled',
|
|
77
|
+
})
|
|
77
78
|
await page.setViewportSize({ width: 390, height: 844 })
|
|
78
79
|
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
|
|
79
|
-
await page.screenshot({
|
|
80
|
+
await page.screenshot({
|
|
81
|
+
path: testInfo.outputPath('eye-care-mobile.png'),
|
|
82
|
+
animations: 'disabled',
|
|
83
|
+
})
|
|
80
84
|
})
|
|
81
85
|
{{/unless}}
|
|
82
86
|
{{/if}}
|
|
83
|
-
|
|
84
87
|
{{#if_eq appType 'h5'}}
|
|
85
|
-
test.use({
|
|
88
|
+
test.use({
|
|
89
|
+
viewport: { width: 390, height: 844 },
|
|
90
|
+
})
|
|
86
91
|
{{/if_eq}}
|
|
87
92
|
{{#if isCapacitorApp}}
|
|
88
|
-
test.use({
|
|
93
|
+
test.use({
|
|
94
|
+
viewport: { width: 390, height: 844 },
|
|
95
|
+
})
|
|
89
96
|
{{/if}}
|
|
90
97
|
|
|
91
98
|
/** 首页从真实浏览器页面发起,覆盖基础渲染链路。 */
|
|
@@ -137,7 +144,11 @@ test('home page renders from browser', async ({ page }) => {
|
|
|
137
144
|
const evidence = process.env.HAI_AUTH_EVIDENCE_DIR || path.resolve('test-results/auth-screenshots')
|
|
138
145
|
await mkdir(evidence, { recursive: true })
|
|
139
146
|
await page.evaluate(() => document.fonts.ready)
|
|
140
|
-
await page.screenshot({
|
|
147
|
+
await page.screenshot({
|
|
148
|
+
path: path.join(evidence, '{{projectName}}-home.png'),
|
|
149
|
+
fullPage: true,
|
|
150
|
+
animations: 'disabled',
|
|
151
|
+
})
|
|
141
152
|
})
|
|
142
153
|
{{#if features.iam}}
|
|
143
154
|
|
|
@@ -156,21 +167,30 @@ test('configured IAM registration and password login', async ({ page, context })
|
|
|
156
167
|
await expect(page.locator('#login-username')).toBeVisible()
|
|
157
168
|
await expect(page.locator('header').first()).toBeVisible()
|
|
158
169
|
await expect(page.locator('footer')).toBeVisible()
|
|
159
|
-
await page.screenshot({
|
|
170
|
+
await page.screenshot({
|
|
171
|
+
path: path.join(evidence, '{{projectName}}-login.png'),
|
|
172
|
+
fullPage: true,
|
|
173
|
+
})
|
|
160
174
|
await page.getByRole('{{#if isCapacitorApp}}button{{else}}link{{/if}}', { name: /立即注册|Register now/i }).click()
|
|
161
175
|
{{#unless isCapacitorApp}}
|
|
162
176
|
await expect(page).toHaveURL(/\/auth\/register(?:\?|$)/)
|
|
163
177
|
{{/unless}}
|
|
164
178
|
const registerForm = page.locator('.register-form')
|
|
165
179
|
await expect(registerForm.locator('#register-username')).toBeVisible()
|
|
166
|
-
await page.screenshot({
|
|
180
|
+
await page.screenshot({
|
|
181
|
+
path: path.join(evidence, '{{projectName}}-register.png'),
|
|
182
|
+
fullPage: true,
|
|
183
|
+
})
|
|
167
184
|
if (process.env.IAM_NOTIFICATION_URL) {
|
|
168
185
|
// 协议弹窗留在认证页,关闭后继续填写注册表单。
|
|
169
186
|
await registerForm.getByRole('button', { name: /用户协议|Terms of Service/i, exact: true }).click()
|
|
170
187
|
await expect(page.getByRole('dialog')).toBeVisible()
|
|
171
188
|
await expect(page.getByRole('dialog').getByRole('heading', { name: 'Configured registration agreement' })).toBeVisible()
|
|
172
189
|
await expect(page.locator('iframe')).toHaveCount(0)
|
|
173
|
-
await page.screenshot({
|
|
190
|
+
await page.screenshot({
|
|
191
|
+
path: path.join(evidence, '{{projectName}}-agreement.png'),
|
|
192
|
+
fullPage: true,
|
|
193
|
+
})
|
|
174
194
|
await page.keyboard.press('Escape')
|
|
175
195
|
await expect(page.getByRole('dialog')).not.toBeVisible()
|
|
176
196
|
}
|
|
@@ -193,7 +213,11 @@ test('configured IAM registration and password login', async ({ page, context })
|
|
|
193
213
|
await expect(page.getByTestId('profile-theme')).toBeVisible()
|
|
194
214
|
await expect(page.locator('html')).toHaveAttribute('data-theme', 'eye-care')
|
|
195
215
|
await expect.poll(() => page.evaluate(() => getComputedStyle(document.documentElement).getPropertyValue('--color-base-100').trim())).toBe('#e8f0df')
|
|
196
|
-
await page.screenshot({
|
|
216
|
+
await page.screenshot({
|
|
217
|
+
path: path.join(evidence, '{{projectName}}-eye-care.png'),
|
|
218
|
+
fullPage: true,
|
|
219
|
+
animations: 'disabled',
|
|
220
|
+
})
|
|
197
221
|
{{else}}
|
|
198
222
|
// 通过页面 fetch 复用 Cookie 与已安装的传输加密,避免 HTTP 辅助客户端绕过浏览器协议。
|
|
199
223
|
const me = await page.evaluate(async url => (await fetch(url)).status, new URL('./api/auth/me', test.info().project.use.baseURL).href)
|
|
@@ -215,7 +239,10 @@ test('configured IAM registration and password login', async ({ page, context })
|
|
|
215
239
|
await page.reload()
|
|
216
240
|
await page.goto(authUrl)
|
|
217
241
|
await page.getByRole('button', { name: /邮件验证码|Email code/i, exact: true }).click()
|
|
218
|
-
await page.screenshot({
|
|
242
|
+
await page.screenshot({
|
|
243
|
+
path: path.join(evidence, '{{projectName}}-email.png'),
|
|
244
|
+
fullPage: true,
|
|
245
|
+
})
|
|
219
246
|
const email = `${username}@example.com`
|
|
220
247
|
await page.locator('#login-username').fill(email)
|
|
221
248
|
await page.getByRole('button', { name: /发送验证码|Send code/i, exact: true }).click()
|
|
@@ -234,14 +261,20 @@ test('configured IAM registration and password login', async ({ page, context })
|
|
|
234
261
|
await page.reload()
|
|
235
262
|
await page.goto(authUrl)
|
|
236
263
|
await page.getByRole('button', { name: /忘记密码|Forgot password/i }).click()
|
|
237
|
-
await page.screenshot({
|
|
264
|
+
await page.screenshot({
|
|
265
|
+
path: path.join(evidence, '{{projectName}}-forgot.png'),
|
|
266
|
+
fullPage: true,
|
|
267
|
+
})
|
|
238
268
|
await page.locator('input[type="email"]').fill(email)
|
|
239
269
|
await page.locator('button[type="submit"]').click()
|
|
240
270
|
await expect(page.locator('.hai-toast-item[data-variant="success"]')).toBeVisible()
|
|
241
271
|
const reset = await received('password_reset')
|
|
242
272
|
expect(Boolean(reset?.token)).toBe(true)
|
|
243
273
|
await page.getByRole('button', { name: /已有重置令牌|I have a reset token/i }).click()
|
|
244
|
-
await page.screenshot({
|
|
274
|
+
await page.screenshot({
|
|
275
|
+
path: path.join(evidence, '{{projectName}}-reset.png'),
|
|
276
|
+
fullPage: true,
|
|
277
|
+
})
|
|
245
278
|
const resetUrl = `{{#if isCapacitorApp}}/{{else}}/auth/reset-password{{/if}}?token=${encodeURIComponent(reset?.token ?? '')}`
|
|
246
279
|
{{#if_eq appType 'h5'}}
|
|
247
280
|
await whileClientBootPaused(page, async () => {
|
|
@@ -11,35 +11,54 @@ export const haiQualityConfig = {
|
|
|
11
11
|
rules: {
|
|
12
12
|
'no-console': ['error', {}],
|
|
13
13
|
'ts/no-explicit-any': 'error',
|
|
14
|
-
'ts/ban-ts-comment': [
|
|
15
|
-
'
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
'ts/ban-ts-comment': [
|
|
15
|
+
'error',
|
|
16
|
+
{
|
|
17
|
+
'ts-ignore': true,
|
|
18
|
+
'ts-nocheck': true,
|
|
19
|
+
'ts-check': false,
|
|
20
|
+
'ts-expect-error': 'allow-with-description',
|
|
21
|
+
'minimumDescriptionLength': 10,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
21
24
|
'eslint-comments/no-unlimited-disable': 'error',
|
|
22
25
|
'eslint-comments/require-description': 'error',
|
|
23
26
|
// 只禁内部源码/构建目录,公开的 /client、/adapter 等 exports 子路径可用。
|
|
24
|
-
'no-restricted-imports': [
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
'no-restricted-imports': [
|
|
28
|
+
'error',
|
|
29
|
+
{
|
|
30
|
+
patterns: [
|
|
31
|
+
{
|
|
32
|
+
group: [
|
|
33
|
+
'@h-ai/*/src',
|
|
34
|
+
'@h-ai/*/src/**',
|
|
35
|
+
'@h-ai/*/dist',
|
|
36
|
+
'@h-ai/*/dist/**',
|
|
37
|
+
],
|
|
38
|
+
message: 'Use the public exports of hai packages instead of their src/dist internals.',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
'no-restricted-syntax': [
|
|
44
|
+
'error',
|
|
45
|
+
{
|
|
46
|
+
selector: ':matches(TSAsExpression, TSTypeAssertion)[expression.typeAnnotation.type="TSUnknownKeyword"]',
|
|
47
|
+
message: 'Use the real upstream type or narrow unknown. Explain necessary third-party workarounds with a scoped lint exception.',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
selector: 'ImportExpression[source.value=/^@h-ai\\/[^/]+\\/(src|dist)(\\/|$)/]',
|
|
27
51
|
message: 'Use the public exports of hai packages instead of their src/dist internals.',
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
'no-restricted-syntax': ['error', {
|
|
31
|
-
selector: ':matches(TSAsExpression, TSTypeAssertion)[expression.typeAnnotation.type="TSUnknownKeyword"]',
|
|
32
|
-
message: 'Use the real upstream type or narrow unknown. Explain necessary third-party workarounds with a scoped lint exception.',
|
|
33
|
-
}, {
|
|
34
|
-
selector: 'ImportExpression[source.value=/^@h-ai\\/[^/]+\\/(src|dist)(\\/|$)/]',
|
|
35
|
-
message: 'Use the public exports of hai packages instead of their src/dist internals.',
|
|
36
|
-
}, {
|
|
52
|
+
},
|
|
53
|
+
{
|
|
37
54
|
// 仅识别明确的静态敏感键;变量键、别名及业务敏感程度仍需审查。
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
55
|
+
selector: 'CallExpression[callee.property.name="setItem"][callee.object.name="localStorage"][arguments.0.value=/^(token|password|secret|api[_-]?key|(access|refresh|auth|session)[_-]?token)$/i]',
|
|
56
|
+
message: 'Keep sensitive tokens in memory, httpOnly cookies or a secure native TokenStore instead of localStorage.',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
selector: 'CallExpression[callee.property.name="setItem"][callee.object.property.name="localStorage"][arguments.0.value=/^(token|password|secret|api[_-]?key|(access|refresh|auth|session)[_-]?token)$/i]',
|
|
60
|
+
message: 'Keep sensitive tokens in memory, httpOnly cookies or a secure native TokenStore instead of localStorage.',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
44
63
|
},
|
|
45
64
|
}
|
|
@@ -9,7 +9,9 @@ import { haiQualityConfig } from './eslint-rules.js'
|
|
|
9
9
|
|
|
10
10
|
export default antfu({
|
|
11
11
|
// unused-imports 使用 TS 规则,JS 同样使用 TS parser 以保持 scope 契约一致。
|
|
12
|
-
typescript: {
|
|
12
|
+
typescript: {
|
|
13
|
+
files: [GLOB_SRC],
|
|
14
|
+
},
|
|
13
15
|
formatters: true,
|
|
14
16
|
ignores: [
|
|
15
17
|
{{#unless isSvelteOnlyApp}}
|
|
@@ -36,8 +36,6 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
|
36
36
|
CMD wget -q -O /dev/null http://127.0.0.1:8080/health || exit 1
|
|
37
37
|
{{else}}
|
|
38
38
|
FROM ${HAI_NODE_IMAGE} AS build
|
|
39
|
-
ARG SQLITE_PREBUILD_MIRROR=
|
|
40
|
-
ENV npm_config_better_sqlite3_binary_host_mirror=$SQLITE_PREBUILD_MIRROR
|
|
41
39
|
|
|
42
40
|
ENV PNPM_HOME=/pnpm
|
|
43
41
|
ENV PATH=$PNPM_HOME:$PATH
|
|
@@ -59,8 +57,9 @@ ARG HAI_BUILD_ID=
|
|
|
59
57
|
ARG HAI_BUILD_COMMIT=unknown
|
|
60
58
|
ARG PUBLIC_BASE_PATH=
|
|
61
59
|
RUN HAI_BUILD_ID="$HAI_BUILD_ID" HAI_BUILD_COMMIT="$HAI_BUILD_COMMIT" PUBLIC_BASE_PATH="$PUBLIC_BASE_PATH" pnpm compile
|
|
62
|
-
|
|
63
|
-
RUN
|
|
60
|
+
# SQLite 13 的原生二进制随 npm 包交付,在构建时验证实际加载。
|
|
61
|
+
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
|
|
62
|
+
RUN --mount=type=cache,id={{projectName}}-pnpm,target=/pnpm/store pnpm pm deploy --filter {{projectName}} --prod /prod/app
|
|
64
63
|
RUN rm -f /prod/app/README* && find /prod/app/build -type f \( -name '*.map' -o -name '*.d.ts' -o -name '*.d.mts' -o -name '*.d.cts' \) -delete
|
|
65
64
|
|
|
66
65
|
FROM ${HAI_NODE_IMAGE} AS runtime-base
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"engines": { "node": "^22.23.4 || ^24.22.1 || ^26.12.1" },
|
|
3
3
|
"name": "{{projectName}}",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.19",
|
|
5
5
|
"private": true,
|
|
6
6
|
"packageManager": "pnpm@12.11.2",
|
|
7
7
|
"description": "{{#if_eq appType 'admin'}}Enterprise management system built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'website'}}Enterprise website built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'h5'}}Mobile H5 app built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'api'}}REST API service built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'mobile-app'}}Mobile app built with hai Agent Framework{{/if_eq}}",
|
|
8
8
|
"keywords": ["hai", {{#unless isSvelteOnlyApp}}"sveltekit", {{/unless}}"svelte5", "{{appType}}"],
|
|
9
9
|
"license": "Apache-2.0",
|
|
10
10
|
"type": "module",
|
|
11
|
+
"imports": { "#lib/*": "./src/lib/*" },
|
|
11
12
|
{{#unless isSvelteOnlyApp}}
|
|
12
13
|
"files": [
|
|
13
14
|
"build",
|
|
@@ -38,8 +39,8 @@
|
|
|
38
39
|
"typecheck": "{{#if hasI18n}}pnpm paraglide:compile && {{/if}}{{#if isSvelteOnlyApp}}svelte-check --tsconfig ./tsconfig.json{{else}}svelte-kit sync && svelte-check --tsconfig ./tsconfig.json{{/if}}",
|
|
39
40
|
"lint": "eslint .",
|
|
40
41
|
"lint:fix": "eslint . --fix",
|
|
41
|
-
"test": "{{#if hasI18n}}pnpm paraglide:compile && {{/if}}vitest run",
|
|
42
|
-
"test:watch": "vitest",
|
|
42
|
+
"test": "{{#if hasI18n}}pnpm paraglide:compile && {{/if}}{{#unless isSvelteOnlyApp}}svelte-kit sync && {{/unless}}vitest run",
|
|
43
|
+
"test:watch": "{{#if hasI18n}}pnpm paraglide:compile && {{/if}}{{#unless isSvelteOnlyApp}}svelte-kit sync && {{/unless}}vitest",
|
|
43
44
|
"test:e2e": "node scripts/run-e2e.mjs",
|
|
44
45
|
"clean": "{{#if isSvelteOnlyApp}}rimraf dist build .turbo src/lib/paraglide{{else}}rimraf .svelte-kit build .turbo{{/if}}"{{#if isCapacitorApp}},
|
|
45
46
|
"cap:add:android": "cap add android",
|
|
@@ -87,7 +88,7 @@
|
|
|
87
88
|
"@h-ai/capacitor": "{{haiPackageSpecifier}}"{{/if}}{{#if isCapacitorApp}}{{#unless features.api-client}},
|
|
88
89
|
"@h-ai/api-client": "{{haiPackageSpecifier}}"{{/unless}}{{#unless features.capacitor}},
|
|
89
90
|
"@h-ai/capacitor": "{{haiPackageSpecifier}}"{{/unless}}{{/if}},
|
|
90
|
-
"sm-crypto": "0.5.
|
|
91
|
+
"sm-crypto": "0.5.8",
|
|
91
92
|
"zod": "{{versions.zod}}"
|
|
92
93
|
{{/if}}
|
|
93
94
|
},
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
diff --git a/utilities/join/object.js b/utilities/join/object.js
|
|
2
|
+
--- a/utilities/join/object.js
|
|
3
|
+
+++ b/utilities/join/object.js
|
|
4
|
+
@@ -1 +1 @@
|
|
5
|
+
-export default {".join":{"display":"inline-flex","align-items":"stretch","--join-ss":"0","--join-se":"0","--join-es":"0","--join-ee":"0","--join-ml":"0","--join-mt":"0","--join-v":"0","--join-h":"1","@scope (&)":{"> :where(:focus, :has(:focus))":{"z-index":2},"@media (hover: hover)":{"> :where(.btn:hover, :has(.btn:hover))":{"z-index":1}},":where(:scope > :first-child)":{"--join-ss":"var(--radius-field)","--join-se":"calc(var(--radius-field) * var(--join-v))","--join-es":"calc(var(--radius-field) * var(--join-h))","--join-ee":"0"},":where(:scope > :last-child)":{"--join-ss":"0","--join-se":"calc(var(--radius-field) * var(--join-h))","--join-es":"calc(var(--radius-field) * var(--join-v))","--join-ee":"var(--radius-field)"},":where(:scope > :only-child)":{"--join-ss":"var(--radius-field)","--join-se":"var(--radius-field)","--join-es":"var(--radius-field)","--join-ee":"var(--radius-field)"},":where(:scope > :not(:first-child))":{"--join-ml":"calc(var(--border, 1px) * -1 * var(--join-h))","--join-mt":"calc(var(--border, 1px) * -1 * var(--join-v))"}}},".join-item":{"@layer daisyui.l1.l2.l3.l4":{"> *":{"--join-ss":"initial","--join-se":"initial","--join-es":"initial","--join-ee":"initial"}},"border-style":"solid","border-width":"var(--border, 1px)","border-start-start-radius":"var(--join-ss)","border-start-end-radius":"var(--join-se)","border-end-start-radius":"var(--join-es)","border-end-end-radius":"var(--join-ee)","&:not(:disabled, [disabled], .btn-disabled)":{"margin-inline-start":"var(--join-ml, 0)","margin-block-start":"var(--join-mt, 0)"},"&:is(:disabled, [disabled], .btn-disabled)":{"border-width":"var(--border, 1px)","border-inline-end-width":"calc(var(--border, 1px) * var(--join-v))","border-block-end-width":"calc(var(--border, 1px) * var(--join-h))"}},".join-vertical":{"flex-direction":"column","--join-v":"1","--join-h":"0"},".join-horizontal":{"flex-direction":"row","--join-v":"0","--join-h":"1"}};
|
|
6
|
+
|
|
7
|
+
+export default {".join":{"display":"inline-flex","align-items":"stretch","--join-ss":"0","--join-se":"0","--join-es":"0","--join-ee":"0","--join-ml":"0","--join-mt":"0","--join-v":"0","--join-h":"1","@scope (&)":{":where(:scope) > :where(:focus, :has(:focus))":{"z-index":2},"@media (hover: hover)":{":where(:scope) > :where(.btn:hover, :has(.btn:hover))":{"z-index":1}},":where(:scope > :first-child)":{"--join-ss":"var(--radius-field)","--join-se":"calc(var(--radius-field) * var(--join-v))","--join-es":"calc(var(--radius-field) * var(--join-h))","--join-ee":"0"},":where(:scope > :last-child)":{"--join-ss":"0","--join-se":"calc(var(--radius-field) * var(--join-h))","--join-es":"calc(var(--radius-field) * var(--join-v))","--join-ee":"var(--radius-field)"},":where(:scope > :only-child)":{"--join-ss":"var(--radius-field)","--join-se":"var(--radius-field)","--join-es":"var(--radius-field)","--join-ee":"var(--radius-field)"},":where(:scope > :not(:first-child))":{"--join-ml":"calc(var(--border, 1px) * -1 * var(--join-h))","--join-mt":"calc(var(--border, 1px) * -1 * var(--join-v))"}}},".join-item":{"@layer daisyui.l1.l2.l3.l4":{"> *":{"--join-ss":"initial","--join-se":"initial","--join-es":"initial","--join-ee":"initial"}},"border-style":"solid","border-width":"var(--border, 1px)","border-start-start-radius":"var(--join-ss)","border-start-end-radius":"var(--join-se)","border-end-start-radius":"var(--join-es)","border-end-end-radius":"var(--join-ee)","&:not(:disabled, [disabled], .btn-disabled)":{"margin-inline-start":"var(--join-ml, 0)","margin-block-start":"var(--join-mt, 0)"},"&:is(:disabled, [disabled], .btn-disabled)":{"border-width":"var(--border, 1px)","border-inline-end-width":"calc(var(--border, 1px) * var(--join-v))","border-block-end-width":"calc(var(--border, 1px) * var(--join-h))"}},".join-vertical":{"flex-direction":"column","--join-v":"1","--join-h":"0"},".join-horizontal":{"flex-direction":"row","--join-v":"0","--join-h":"1"}};
|
|
8
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
diff --git a/index.js b/index.js
|
|
2
|
+
--- a/index.js
|
|
3
|
+
+++ b/index.js
|
|
4
|
+
@@ -55,11 +55,12 @@
|
|
5
|
+
var destination = {}
|
|
6
|
+
if (options.isMergeableObject(target)) {
|
|
7
|
+
getKeys(target).forEach(function(key) {
|
|
8
|
+
+ if (key === '__proto__') return
|
|
9
|
+
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options)
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
getKeys(source).forEach(function(key) {
|
|
13
|
+
- if (propertyIsUnsafe(target, key)) {
|
|
14
|
+
+ if (key === '__proto__' || propertyIsUnsafe(target, key)) {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
diff --git a/dist/cjs.js b/dist/cjs.js
|
|
19
|
+
--- a/dist/cjs.js
|
|
20
|
+
+++ b/dist/cjs.js
|
|
21
|
+
@@ -80,11 +80,12 @@
|
|
22
|
+
var destination = {};
|
|
23
|
+
if (options.isMergeableObject(target)) {
|
|
24
|
+
getKeys(target).forEach(function(key) {
|
|
25
|
+
+ if (key === '__proto__') return
|
|
26
|
+
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
getKeys(source).forEach(function(key) {
|
|
30
|
+
- if (propertyIsUnsafe(target, key)) {
|
|
31
|
+
+ if (key === '__proto__' || propertyIsUnsafe(target, key)) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
diff --git a/dist/umd.js b/dist/umd.js
|
|
36
|
+
--- a/dist/umd.js
|
|
37
|
+
+++ b/dist/umd.js
|
|
38
|
+
@@ -84,11 +84,12 @@
|
|
39
|
+
var destination = {};
|
|
40
|
+
if (options.isMergeableObject(target)) {
|
|
41
|
+
getKeys(target).forEach(function(key) {
|
|
42
|
+
+ if (key === '__proto__') return
|
|
43
|
+
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
getKeys(source).forEach(function(key) {
|
|
47
|
+
- if (propertyIsUnsafe(target, key)) {
|
|
48
|
+
+ if (key === '__proto__' || propertyIsUnsafe(target, key)) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{{! @skipIfEmpty }}
|
|
2
2
|
{{#if useCatalogProtocol}}
|
|
3
|
-
|
|
3
|
+
minimumReleaseAgeExcludePrune: true
|
|
4
4
|
|
|
5
5
|
trustPolicy: no-downgrade
|
|
6
6
|
# 上游构建工具仍要求 4.x;4.0.3 tarball 已核对原 lockfile 的 SHA-512。
|
|
@@ -9,32 +9,49 @@ trustPolicyExclude:
|
|
|
9
9
|
|
|
10
10
|
# pnpm 12 配置;原生依赖仅运行明确列出的安装脚本。
|
|
11
11
|
nodeLinker: hoisted
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
ssh2: true
|
|
17
|
-
vue-demi: true
|
|
18
|
-
better-sqlite3: true
|
|
19
|
-
esbuild: true
|
|
20
|
-
core-js: false
|
|
12
|
+
shellEmulator: true
|
|
13
|
+
|
|
14
|
+
packages:
|
|
15
|
+
- .
|
|
21
16
|
|
|
17
|
+
# 构建与浏览器依赖的安全修复;版本与框架工作区同步维护。
|
|
22
18
|
overrides:
|
|
23
|
-
|
|
19
|
+
'@ai-sdk/provider-utils@>=4.0.0 <4.0.33': 4.0.57
|
|
20
|
+
'@types/node': {{versions.nodeTypes}}
|
|
21
|
+
body-parser@>=2 <2.4.0: 2.4.0
|
|
24
22
|
cookie@<0.7.0: 0.7.2
|
|
23
|
+
dompurify@>=3 <3.4.17: 3.4.17
|
|
25
24
|
esbuild@<0.28.1: 0.28.2
|
|
25
|
+
fast-uri@>=3 <3.1.9: 3.1.9
|
|
26
|
+
follow-redirects@>=1.16.0 <1.16.2: 1.16.2
|
|
27
|
+
glob@>=9 <=14.0.1: 14.0.4
|
|
28
|
+
ip-address@<=10.7.3: 10.7.6
|
|
26
29
|
katex@<0.18.2: 0.18.10
|
|
30
|
+
minimatch@>=7 <11.0.1: 11.0.5
|
|
31
|
+
parse5@>=8 <8.1.0: 8.1.0
|
|
32
|
+
qs@>=6.7 <6.16.1: 6.17.1
|
|
33
|
+
runed@<0.38.0: 0.38.0
|
|
27
34
|
sharp@<0.35.5: 0.35.5
|
|
28
35
|
tinypool@<2.1.2: 2.2.0
|
|
29
|
-
'@qdrant/js-client-rest>undici': 7.30.0
|
|
30
36
|
xcode>uuid: 11.1.1
|
|
31
|
-
"@types/node": "{{versions.nodeTypes}}"
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
{{#if hasUi}}
|
|
39
|
+
patchedDependencies:
|
|
40
|
+
daisyui@5.7.50: patches/daisyui-5.7.50.patch
|
|
41
|
+
deepmerge@4.3.1: patches/deepmerge-4.3.1.patch
|
|
42
|
+
{{/if}}
|
|
43
|
+
|
|
44
|
+
allowBuilds:
|
|
45
|
+
core-js: false
|
|
46
|
+
cpu-features: true
|
|
47
|
+
esbuild: true
|
|
48
|
+
onnxruntime-node: true
|
|
49
|
+
protobufjs: true
|
|
50
|
+
ssh2: true
|
|
51
|
+
vue-demi: true
|
|
35
52
|
|
|
36
53
|
catalog:
|
|
37
54
|
{{#each haiCatalogPackages}}
|
|
38
|
-
|
|
55
|
+
{{{yaml @key this}}}
|
|
39
56
|
{{/each}}
|
|
40
57
|
{{/if}}
|
|
@@ -3,28 +3,22 @@
|
|
|
3
3
|
* {{projectName}} - Server Hooks
|
|
4
4
|
* =============================================================================
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
6
|
{{#if features.crypto}}
|
|
8
7
|
import type { TransportEncryptionOptions } from '@h-ai/kit'
|
|
9
8
|
{{/if}}
|
|
10
|
-
import type { Handle } from '@sveltejs/kit'
|
|
9
|
+
import type { Handle } from '@sveltejs/kit/hooks'
|
|
11
10
|
import process from 'node:process'
|
|
12
11
|
{{#if hasI18n}}
|
|
13
|
-
import {
|
|
12
|
+
import { resolve as resolvePath } from '$app/paths'
|
|
14
13
|
{{else}}
|
|
15
14
|
{{#if features.iam}}
|
|
16
|
-
import {
|
|
15
|
+
import { resolve as resolvePath } from '$app/paths'
|
|
17
16
|
{{else}}
|
|
18
17
|
{{#if features.crypto}}
|
|
19
|
-
import {
|
|
20
|
-
{{/if}}
|
|
18
|
+
import { resolve as resolvePath } from '$app/paths'
|
|
21
19
|
{{/if}}
|
|
22
20
|
{{/if}}
|
|
23
|
-
{{#if hasI18n}}
|
|
24
|
-
import { paraglideMiddleware } from '$lib/paraglide/server.js'
|
|
25
21
|
{{/if}}
|
|
26
|
-
import { closeApp, initApp } from '$lib/server/init.js'
|
|
27
|
-
import { getKitConfig } from '$lib/server/kit-config.js'
|
|
28
22
|
{{#if features.cache}}
|
|
29
23
|
import { cache } from '@h-ai/cache'
|
|
30
24
|
{{/if}}
|
|
@@ -41,6 +35,11 @@ import { kit } from '@h-ai/kit'
|
|
|
41
35
|
import { reldb } from '@h-ai/reldb'
|
|
42
36
|
{{/if}}
|
|
43
37
|
{{/if}}
|
|
38
|
+
{{#if hasI18n}}
|
|
39
|
+
import { paraglideMiddleware } from '#lib/paraglide/server.js'
|
|
40
|
+
{{/if}}
|
|
41
|
+
import { closeApp, initApp } from '#lib/server/init.js'
|
|
42
|
+
import { getKitConfig } from '#lib/server/kit-config.js'
|
|
44
43
|
|
|
45
44
|
// =============================================================================
|
|
46
45
|
// 应用初始化
|
|
@@ -74,7 +73,6 @@ const initHandle: Handle = async ({ event, resolve }) => {
|
|
|
74
73
|
await ensureAppInitialized()
|
|
75
74
|
return resolve(event)
|
|
76
75
|
}
|
|
77
|
-
|
|
78
76
|
{{#if hasI18n}}
|
|
79
77
|
// =============================================================================
|
|
80
78
|
// Paraglide i18n Middleware
|
|
@@ -86,7 +84,7 @@ const initHandle: Handle = async ({ event, resolve }) => {
|
|
|
86
84
|
* API 请求跳过 paraglideMiddleware(不需要页面级 locale + 避免消耗 body)
|
|
87
85
|
*/
|
|
88
86
|
const i18nHandle: Handle = async ({ event, resolve }) => {
|
|
89
|
-
if (event.url.pathname.startsWith(`${
|
|
87
|
+
if (event.url.pathname.startsWith(`${resolvePath('/').replace(/\/$/, '')}/api/`)) {
|
|
90
88
|
const locale = event.cookies.get('PARAGLIDE_LOCALE') ?? '{{defaultLocale}}'
|
|
91
89
|
event.locals.locale = locale
|
|
92
90
|
return kit.i18n.runWithLocale(locale, () => resolve(event))
|
|
@@ -99,7 +97,6 @@ const i18nHandle: Handle = async ({ event, resolve }) => {
|
|
|
99
97
|
}))
|
|
100
98
|
})
|
|
101
99
|
}
|
|
102
|
-
|
|
103
100
|
{{/if}}
|
|
104
101
|
// =============================================================================
|
|
105
102
|
// hai Handle(会话验证 + 限流 + 日志)
|
|
@@ -113,20 +110,20 @@ const haiHandle: Handle = async (input) => {
|
|
|
113
110
|
let transport: TransportEncryptionOptions | undefined
|
|
114
111
|
if (settings.transport !== false) {
|
|
115
112
|
{{#unless features.db}}
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
if (core.module.requiresSharedState(process.env))
|
|
114
|
+
throw new Error('Production transport requires the db feature and a shared database registry')
|
|
118
115
|
{{/unless}}
|
|
119
116
|
const ring = parseTransportServerKeyRing(process.env.HAI_CRYPTO_TRANSPORT_SERVERKEYRING)
|
|
120
117
|
if (!ring.success)
|
|
121
118
|
throw new Error(`HAI_CRYPTO_TRANSPORT_SERVERKEYRING: ${ring.error.message} (${ring.error.code})`)
|
|
122
119
|
transport = {
|
|
123
120
|
...settings.transport,
|
|
124
|
-
basePath:
|
|
121
|
+
basePath: resolvePath('/').replace(/\/$/, ''),
|
|
125
122
|
serverKeyRing: ring.data,
|
|
126
123
|
{{#if features.db}}
|
|
127
124
|
keyStore: createReldbTransportKeyStore({ reldb, ttlSeconds: 3600 }),
|
|
128
125
|
{{else}}
|
|
129
|
-
|
|
126
|
+
keyStore: createInMemoryKeyStore(),
|
|
130
127
|
{{/if}}
|
|
131
128
|
}
|
|
132
129
|
}
|
|
@@ -140,7 +137,7 @@ const haiHandle: Handle = async (input) => {
|
|
|
140
137
|
{{#if features.crypto}}
|
|
141
138
|
crypto: { crypto, transport },
|
|
142
139
|
{{/if}}
|
|
143
|
-
|
|
140
|
+
{{#if features.iam}}
|
|
144
141
|
auth: {
|
|
145
142
|
verifyToken: async (token) => {
|
|
146
143
|
const result = await iam.auth.verifyToken(token)
|
|
@@ -156,18 +153,27 @@ const haiHandle: Handle = async (input) => {
|
|
|
156
153
|
data: session.data,
|
|
157
154
|
}
|
|
158
155
|
},
|
|
159
|
-
loginUrl: `${
|
|
160
|
-
protectedPaths: ['/admin/*', '/api/*'].map(path => `${
|
|
161
|
-
publicPaths: [
|
|
156
|
+
loginUrl: `${resolvePath('/').replace(/\/$/, '')}/auth/login`,
|
|
157
|
+
protectedPaths: ['/admin/*', '/api/*'].map(path => `${resolvePath('/').replace(/\/$/, '')}${path}`),
|
|
158
|
+
publicPaths: [
|
|
159
|
+
...kit.auth.publicPaths,
|
|
160
|
+
'/api/auth/logout',
|
|
161
|
+
'/api/public/*',
|
|
162
|
+
'/api/health',
|
|
163
|
+
].map(path => `${resolvePath('/').replace(/\/$/, '')}${path}`),
|
|
162
164
|
operations: () => iam.auth,
|
|
163
165
|
},
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
rateLimit: {
|
|
167
|
-
|
|
166
|
+
{{/if}}
|
|
167
|
+
{{#if features.cache}}
|
|
168
|
+
rateLimit: {
|
|
169
|
+
windowMs: 60000,
|
|
170
|
+
maxRequests: 200,
|
|
171
|
+
store: kit.middleware.createCacheRateLimitStore(cache, { namespace: '{{projectName}}', allowMemory: process.env.NODE_ENV !== 'production' || process.env.HAI_E2E === '1' }),
|
|
172
|
+
},
|
|
173
|
+
{{else}}
|
|
168
174
|
// 未选择cache能力时不启用限流;启用前须接入共享原子store。
|
|
169
175
|
rateLimit: false,
|
|
170
|
-
|
|
176
|
+
{{/if}}
|
|
171
177
|
logging: { logBody: false },
|
|
172
178
|
onError: (error: unknown, _event) => {
|
|
173
179
|
core.logger.error('Request error:', { error })
|
|
@@ -176,7 +182,10 @@ const haiHandle: Handle = async (input) => {
|
|
|
176
182
|
success: false,
|
|
177
183
|
error: core.error.toPublic({ code: 'INTERNAL_ERROR', message: '', httpStatus: 500 }),
|
|
178
184
|
}),
|
|
179
|
-
{
|
|
185
|
+
{
|
|
186
|
+
status: 500,
|
|
187
|
+
headers: { 'Content-Type': 'application/json' },
|
|
188
|
+
},
|
|
180
189
|
)
|
|
181
190
|
},
|
|
182
191
|
})
|