@h-ai/cli 1.0.0-beta.2 → 1.0.0-beta.21
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 +11 -6
- 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 +58 -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
|
@@ -6,7 +6,9 @@ import { ai } from '@h-ai/ai'
|
|
|
6
6
|
import { kit } from '@h-ai/kit'
|
|
7
7
|
import { z } from 'zod'
|
|
8
8
|
|
|
9
|
-
const ChatInputSchema = z.object({
|
|
9
|
+
const ChatInputSchema = z.object({
|
|
10
|
+
message: z.string().trim().min(1).max(4000),
|
|
11
|
+
}).strict()
|
|
10
12
|
|
|
11
13
|
export const POST: RequestHandler = kit.handler(async ({ request, locals }) => {
|
|
12
14
|
const { message } = await kit.validate.body(request, ChatInputSchema)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
|
-
import {
|
|
2
|
+
import { resolve } from '$app/paths'
|
|
3
3
|
import { page } from '$app/state'
|
|
4
4
|
import { kit } from '@h-ai/kit'
|
|
5
5
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
6
6
|
|
|
7
|
-
const actions = kit.client.createAuthActions({ basePath: `${
|
|
7
|
+
const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
|
-
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('
|
|
10
|
+
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
2
|
import { goto } from '$app/navigation'
|
|
3
|
-
import {
|
|
3
|
+
import { resolve } from '$app/paths'
|
|
4
4
|
import { page } from '$app/state'
|
|
5
5
|
import { kit } from '@h-ai/kit'
|
|
6
6
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
7
7
|
|
|
8
|
-
const actions = kit.client.createAuthActions({ basePath: `${
|
|
8
|
+
const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
|
-
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='login' loginUrl={resolve('
|
|
11
|
+
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='login' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('admin'))} />
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
2
|
import { goto } from '$app/navigation'
|
|
3
|
-
import {
|
|
3
|
+
import { resolve } from '$app/paths'
|
|
4
4
|
import { page } from '$app/state'
|
|
5
5
|
import { kit } from '@h-ai/kit'
|
|
6
6
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
7
7
|
|
|
8
|
-
const actions = kit.client.createAuthActions({ basePath: `${
|
|
8
|
+
const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
|
-
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='register' loginUrl={resolve('
|
|
11
|
+
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='register' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('admin'))} />
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
|
-
import {
|
|
2
|
+
import { resolve } from '$app/paths'
|
|
3
3
|
import { page } from '$app/state'
|
|
4
4
|
import { kit } from '@h-ai/kit'
|
|
5
5
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
6
6
|
|
|
7
|
-
const actions = kit.client.createAuthActions({ basePath: `${
|
|
7
|
+
const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
|
-
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('
|
|
10
|
+
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
|
-
import {
|
|
2
|
+
import { resolve } from '$app/paths'
|
|
3
3
|
import { page } from '$app/state'
|
|
4
4
|
import { kit } from '@h-ai/kit'
|
|
5
5
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
6
6
|
|
|
7
|
-
const actions = kit.client.createAuthActions({ basePath: `${
|
|
7
|
+
const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
|
-
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('
|
|
10
|
+
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
2
|
import { goto } from '$app/navigation'
|
|
3
|
-
import {
|
|
3
|
+
import { resolve } from '$app/paths'
|
|
4
4
|
import { page } from '$app/state'
|
|
5
5
|
import { kit } from '@h-ai/kit'
|
|
6
6
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
7
7
|
|
|
8
|
-
const authActions = kit.client.createAuthActions({ basePath: `${
|
|
8
|
+
const authActions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
|
-
<AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='login' loginUrl={resolve('
|
|
11
|
+
<AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='login' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('/'))} />
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
2
|
import { goto } from '$app/navigation'
|
|
3
|
-
import {
|
|
3
|
+
import { resolve } from '$app/paths'
|
|
4
4
|
import { page } from '$app/state'
|
|
5
5
|
import { kit } from '@h-ai/kit'
|
|
6
6
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
7
7
|
|
|
8
|
-
const authActions = kit.client.createAuthActions({ basePath: `${
|
|
8
|
+
const authActions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
|
-
<AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='register' loginUrl={resolve('
|
|
11
|
+
<AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='register' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('/'))} />
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
|
-
import {
|
|
2
|
+
import { resolve } from '$app/paths'
|
|
3
3
|
import { page } from '$app/state'
|
|
4
4
|
import { kit } from '@h-ai/kit'
|
|
5
5
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
6
6
|
|
|
7
|
-
const actions = kit.client.createAuthActions({ basePath: `${
|
|
7
|
+
const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
|
-
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('
|
|
10
|
+
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
|
-
import {
|
|
2
|
+
import { resolve } from '$app/paths'
|
|
3
3
|
import { page } from '$app/state'
|
|
4
4
|
import { kit } from '@h-ai/kit'
|
|
5
5
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
6
6
|
|
|
7
|
-
const actions = kit.client.createAuthActions({ basePath: `${
|
|
7
|
+
const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
|
-
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('
|
|
10
|
+
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
2
|
import { goto } from '$app/navigation'
|
|
3
|
-
import {
|
|
3
|
+
import { resolve } from '$app/paths'
|
|
4
4
|
import { page } from '$app/state'
|
|
5
5
|
import { kit } from '@h-ai/kit'
|
|
6
6
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
7
7
|
|
|
8
|
-
const authActions = kit.client.createAuthActions({ basePath: `${
|
|
8
|
+
const authActions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
|
-
<AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='login' loginUrl={resolve('
|
|
11
|
+
<AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='login' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('/'))} />
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
2
|
import { goto } from '$app/navigation'
|
|
3
|
-
import {
|
|
3
|
+
import { resolve } from '$app/paths'
|
|
4
4
|
import { page } from '$app/state'
|
|
5
5
|
import { kit } from '@h-ai/kit'
|
|
6
6
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
7
7
|
|
|
8
|
-
const authActions = kit.client.createAuthActions({ basePath: `${
|
|
8
|
+
const authActions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
|
-
<AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='register' loginUrl={resolve('
|
|
11
|
+
<AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='register' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('/'))} />
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang='ts'>
|
|
2
|
-
import {
|
|
2
|
+
import { resolve } from '$app/paths'
|
|
3
3
|
import { page } from '$app/state'
|
|
4
4
|
import { kit } from '@h-ai/kit'
|
|
5
5
|
import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
|
|
6
6
|
|
|
7
|
-
const actions = kit.client.createAuthActions({ basePath: `${
|
|
7
|
+
const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
|
-
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('
|
|
10
|
+
<AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/** 创建支付参数 API;渠道、场景与 openid 必须通过显式校验,禁止回落到其它支付模式。 */
|
|
2
2
|
import type { RequestHandler } from './$types'
|
|
3
|
-
import {
|
|
3
|
+
import { resolve } from '$app/paths'
|
|
4
4
|
import { kit } from '@h-ai/kit'
|
|
5
5
|
import { payment } from '@h-ai/payment'
|
|
6
6
|
import { z } from 'zod'
|
|
7
7
|
|
|
8
|
+
// Vite 配置固定 paths.relative=false,HTTP 前缀不会随 SSR 页面深度改变。
|
|
9
|
+
const base = resolve('/').replace(/\/$/, '')
|
|
10
|
+
|
|
8
11
|
/** 本模板的业务字段;服务端仍需从可信订单重新核对金额、描述、订单号和所属用户。 */
|
|
9
12
|
const CreatePaymentSchema = z.object({
|
|
10
13
|
provider: z.enum(['wechat', 'alipay', 'stripe']),
|
|
@@ -15,7 +18,13 @@ const CreatePaymentSchema = z.object({
|
|
|
15
18
|
userId: z.string().trim().min(1).max(128).optional(),
|
|
16
19
|
metadata: z.record(z.string(), z.string()).optional(),
|
|
17
20
|
notifyUrl: z.url({ protocol: /^https?$/ }).optional(),
|
|
18
|
-
}).strict().refine(input => input.tradeType === (input.provider === 'wechat'
|
|
21
|
+
}).strict().refine(input => input.tradeType === (input.provider === 'wechat'
|
|
22
|
+
? 'jsapi'
|
|
23
|
+
: 'h5'), {
|
|
24
|
+
path: ['tradeType'],
|
|
25
|
+
}).refine(input => input.provider !== 'wechat' || input.userId !== undefined, {
|
|
26
|
+
path: ['userId'],
|
|
27
|
+
})
|
|
19
28
|
|
|
20
29
|
export const POST: RequestHandler = async ({ request, locals }) => {
|
|
21
30
|
const { provider, tradeType, outTradeNo, totalAmount, subject, notifyUrl, userId, metadata } = await kit.validate.body(request, CreatePaymentSchema)
|
|
@@ -28,5 +37,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|
|
28
37
|
metadata,
|
|
29
38
|
notifyUrl: notifyUrl ?? `${new URL(request.url).origin}${base}/api/v1/payment/notify/${provider}`,
|
|
30
39
|
})
|
|
31
|
-
|
|
40
|
+
if (!result.success)
|
|
41
|
+
return kit.response.fromError(result.error, locals.requestId)
|
|
42
|
+
return kit.response.ok(result.data, locals.requestId)
|
|
32
43
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* eslint-disable no-var, object-shorthand, prefer-template, prefer-arrow-callback -- 此脚本须在低版本浏览器中直接执行,使用 ES5 语法。 */
|
|
2
|
+
;(function () {
|
|
3
|
+
var agent = navigator.userAgent
|
|
4
|
+
var root = document.documentElement
|
|
5
|
+
var location = window.location
|
|
6
|
+
var edgeHelp = 'https://support.microsoft.com/edge/microsoft-edge-update-settings'
|
|
7
|
+
var chromeHelp = 'https://support.google.com/chrome/answer/95414'
|
|
8
|
+
var firefoxHelp = 'https://support.mozilla.org/kb/update-firefox-latest-release'
|
|
9
|
+
var safariHelp = 'https://support.apple.com/102665'
|
|
10
|
+
var iosHelp = 'https://support.apple.com/118575'
|
|
11
|
+
var browser = getOutdatedBrowser()
|
|
12
|
+
|
|
13
|
+
// 匹配 Vite 8 的默认构建基线。Edge 的 UA 同时包含 Chrome,iOS 先按系统版本判断。
|
|
14
|
+
function getOutdatedBrowser() {
|
|
15
|
+
var version = /\b(?:CPU (?:iPhone )?OS|iPhone OS) (\d+_\d+(?:_\d+)?)/.exec(agent)
|
|
16
|
+
if (version && /\b(?:iPhone|iPad|iPod)\b/.test(agent)) {
|
|
17
|
+
return outdated('iOS / iPadOS', version, 16, 4, iosHelp)
|
|
18
|
+
}
|
|
19
|
+
version = /\b(?:EdgA?|Edge)\/(\d+(?:\.\d+)*)/.exec(agent)
|
|
20
|
+
if (version) {
|
|
21
|
+
return outdated('Microsoft Edge', version, 111, 0, edgeHelp)
|
|
22
|
+
}
|
|
23
|
+
version = /\bFirefox\/(\d+(?:\.\d+)*)/.exec(agent)
|
|
24
|
+
if (version) {
|
|
25
|
+
return outdated('Firefox', version, 114, 0, firefoxHelp)
|
|
26
|
+
}
|
|
27
|
+
version = /\bChrome\/(\d+(?:\.\d+)*)/.exec(agent)
|
|
28
|
+
if (version) {
|
|
29
|
+
if (/\b(?:wv|OPR\/|SamsungBrowser\/|Vivaldi\/|YaBrowser\/|HeadlessChrome\/)/.test(agent))
|
|
30
|
+
return null
|
|
31
|
+
return outdated('Google Chrome', version, 111, 0, chromeHelp)
|
|
32
|
+
}
|
|
33
|
+
version = /\bVersion\/(\d+(?:\.\d+)*)/.exec(agent)
|
|
34
|
+
if (version && /\bSafari\//.test(agent)) {
|
|
35
|
+
return outdated('Safari', version, 16, 4, safariHelp)
|
|
36
|
+
}
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function outdated(name, match, major, minor, help) {
|
|
41
|
+
var version = match[1].replace(/_/g, '.')
|
|
42
|
+
var parts = version.split('.')
|
|
43
|
+
var currentMajor = Number(parts[0])
|
|
44
|
+
var currentMinor = Number(parts[1] || 0)
|
|
45
|
+
if (currentMajor > major || (currentMajor === major && currentMinor >= minor))
|
|
46
|
+
return null
|
|
47
|
+
return {
|
|
48
|
+
name: name,
|
|
49
|
+
version: version,
|
|
50
|
+
minimum: minor
|
|
51
|
+
? major + '.' + minor
|
|
52
|
+
: String(major),
|
|
53
|
+
help: help,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getLanguage(value) {
|
|
58
|
+
var language = (value || '').toLowerCase().split(/[-_]/)[0]
|
|
59
|
+
return language === 'zh' || language === 'ja' || language === 'en'
|
|
60
|
+
? language
|
|
61
|
+
: ''
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function openUpdatePage() {
|
|
65
|
+
// 以静态脚本地址为基准,保留发布目录。仅传语言,不把原页面地址写到升级页。
|
|
66
|
+
var script = document.getElementById('hai-browser-startup')
|
|
67
|
+
var language = getLanguage(root.lang) || getLanguage(navigator.language) || 'en'
|
|
68
|
+
location.replace(script.src.replace(/\/startup\.js$/, '/update.html') + '#' + language)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function showUpdateInstructions() {
|
|
72
|
+
var locale = getLanguage(location.hash.slice(1)) || getLanguage(navigator.language) || 'en'
|
|
73
|
+
var messages = {
|
|
74
|
+
zh: [
|
|
75
|
+
'浏览器版本过低',
|
|
76
|
+
'当前使用 {name} {version}。此站点至少需要 {name} {minimum}。',
|
|
77
|
+
'请更新到最新版本,然后重新打开此站点。',
|
|
78
|
+
'查看官方更新说明',
|
|
79
|
+
],
|
|
80
|
+
en: [
|
|
81
|
+
'Update your browser',
|
|
82
|
+
'You are using {name} {version}. This site requires {name} {minimum} or later.',
|
|
83
|
+
'Install the latest update, then reopen this site.',
|
|
84
|
+
'Official update instructions',
|
|
85
|
+
],
|
|
86
|
+
ja: [
|
|
87
|
+
'ブラウザーを更新してください',
|
|
88
|
+
'現在のバージョンは {name} {version} です。このサイトには {name} {minimum} 以降が必要です。',
|
|
89
|
+
'最新版に更新してから、このサイトを開き直してください。',
|
|
90
|
+
'公式の更新手順を見る',
|
|
91
|
+
],
|
|
92
|
+
}
|
|
93
|
+
var message = messages[locale]
|
|
94
|
+
var help = document.getElementById('browser-update-help')
|
|
95
|
+
root.lang = locale === 'zh'
|
|
96
|
+
? 'zh-CN'
|
|
97
|
+
: locale
|
|
98
|
+
document.title = message[0]
|
|
99
|
+
document.getElementById('browser-update-title').textContent = message[0]
|
|
100
|
+
document.getElementById('browser-update-version').textContent = message[1].replace(/\{(name|version|minimum)\}/g, function (_match, key) {
|
|
101
|
+
return browser[key]
|
|
102
|
+
})
|
|
103
|
+
document.getElementById('browser-update-instruction').textContent = message[2]
|
|
104
|
+
help.textContent = message[3]
|
|
105
|
+
help.href = browser.help
|
|
106
|
+
help.hidden = false
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!browser)
|
|
110
|
+
return
|
|
111
|
+
if (root.hasAttribute('data-hai-browser-update'))
|
|
112
|
+
showUpdateInstructions()
|
|
113
|
+
else
|
|
114
|
+
openUpdatePage()
|
|
115
|
+
})()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 12vh 20px 32px;
|
|
4
|
+
background: #f4f6fa;
|
|
5
|
+
color: #1b263b;
|
|
6
|
+
font-family: system-ui, sans-serif;
|
|
7
|
+
font-size: 1rem;
|
|
8
|
+
line-height: 1.6;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
main {
|
|
12
|
+
max-width: 33rem;
|
|
13
|
+
margin: 0 auto;
|
|
14
|
+
padding: 1.5rem;
|
|
15
|
+
border: 1px solid #dce2ec;
|
|
16
|
+
border-radius: 0.75rem;
|
|
17
|
+
background: #fff;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
h1 {
|
|
21
|
+
margin: 0 0 1rem;
|
|
22
|
+
font-size: 1.5rem;
|
|
23
|
+
line-height: 1.25;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
p {
|
|
27
|
+
margin: 0 0 0.75rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
a {
|
|
31
|
+
color: #1642a3;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
a:focus {
|
|
35
|
+
outline: 2px solid currentColor;
|
|
36
|
+
outline-offset: 4px;
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-hai-browser-update>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta name="robots" content="noindex" />
|
|
7
|
+
<title>Browser requirements</title>
|
|
8
|
+
<link rel="stylesheet" href="./update.css" />
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<main>
|
|
12
|
+
<h1 id="browser-update-title">Browser requirements</h1>
|
|
13
|
+
<p id="browser-update-version">This site requires a current browser.</p>
|
|
14
|
+
<p id="browser-update-instruction">Install the latest update, then reopen this site.</p>
|
|
15
|
+
<a id="browser-update-help" rel="noreferrer" hidden></a>
|
|
16
|
+
</main>
|
|
17
|
+
<script src="./startup.js"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test('old browser sees upgrade instructions without the application bundles', async ({ page }) => {
|
|
4
|
+
// 只改变浏览器脚本看到的版本,确保检测在客户端执行。
|
|
5
|
+
await page.addInitScript(() => {
|
|
6
|
+
Object.defineProperty(navigator, 'userAgent', {
|
|
7
|
+
get: () => 'Mozilla/5.0 Gecko/20100101 Firefox/113.0',
|
|
8
|
+
})
|
|
9
|
+
})
|
|
10
|
+
await page.route('**/*', async (route) => {
|
|
11
|
+
const { pathname } = new URL(route.request().url())
|
|
12
|
+
if (/\.(?:js|css)$/.test(pathname) && !pathname.includes('/_hai/browser-check/'))
|
|
13
|
+
await route.abort()
|
|
14
|
+
else
|
|
15
|
+
await route.continue()
|
|
16
|
+
})
|
|
17
|
+
await page.goto('./', { waitUntil: 'commit' })
|
|
18
|
+
await expect(page).toHaveURL(/\/_hai\/browser-check\/update\.html#(?:zh|en|ja)$/)
|
|
19
|
+
await expect(page.getByRole('heading', { level: 1 })).toBeVisible()
|
|
20
|
+
await expect(page.getByRole('main')).toContainText('Firefox 113.0')
|
|
21
|
+
await expect(page.getByRole('main')).toContainText('Firefox 114')
|
|
22
|
+
await expect(page.getByRole('link')).toHaveAttribute('href', 'https://support.mozilla.org/kb/update-firefox-latest-release')
|
|
23
|
+
})
|
|
@@ -7,7 +7,9 @@ import process from 'node:process'
|
|
|
7
7
|
/** 当前编译目标的私有产物身份;同一 SSR 构建重入复用身份,各端版本来自自己的 manifest。 */
|
|
8
8
|
export function resolveBuildMetadata(directory: string): { appVersion: string, buildId: string, commit: string } {
|
|
9
9
|
const manifest: { version?: unknown } = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8'))
|
|
10
|
-
const appVersion = typeof manifest.version === 'string' && manifest.version.trim()
|
|
10
|
+
const appVersion = typeof manifest.version === 'string' && manifest.version.trim()
|
|
11
|
+
? manifest.version.trim()
|
|
12
|
+
: 'unknown'
|
|
11
13
|
if (appVersion.length > 128)
|
|
12
14
|
throw new Error('Invalid package.json version: maximum length is 128')
|
|
13
15
|
const suppliedId = process.env.HAI_BUILD_ID?.trim()
|
|
@@ -27,14 +29,26 @@ export function resolveBuildMetadata(directory: string): { appVersion: string, b
|
|
|
27
29
|
/** 未跟踪的生成工程不能把临时目录的父框架提交冒充自身源码。 */
|
|
28
30
|
function sourceCommit(directory: string): string {
|
|
29
31
|
try {
|
|
30
|
-
const options = {
|
|
32
|
+
const options = {
|
|
33
|
+
cwd: directory,
|
|
34
|
+
encoding: 'utf8' as const,
|
|
35
|
+
stdio: 'pipe' as const,
|
|
36
|
+
windowsHide: true,
|
|
37
|
+
}
|
|
31
38
|
const root = execFileSync('git', ['rev-parse', '--show-toplevel'], options).trim()
|
|
32
39
|
const manifest = relative(root, join(directory, 'package.json')).replaceAll('\\', '/')
|
|
33
40
|
if (manifest.startsWith('../'))
|
|
34
41
|
return 'unknown'
|
|
35
|
-
execFileSync('git', [
|
|
42
|
+
execFileSync('git', [
|
|
43
|
+
'ls-files',
|
|
44
|
+
'--error-unmatch',
|
|
45
|
+
'--',
|
|
46
|
+
manifest,
|
|
47
|
+
], { ...options, cwd: root })
|
|
36
48
|
const commit = execFileSync('git', ['rev-parse', 'HEAD'], options).trim()
|
|
37
|
-
return /^(?:[a-f\d]{40}|[a-f\d]{64})$/i.test(commit)
|
|
49
|
+
return /^(?:[a-f\d]{40}|[a-f\d]{64})$/i.test(commit)
|
|
50
|
+
? commit
|
|
51
|
+
: 'unknown'
|
|
38
52
|
}
|
|
39
53
|
catch {
|
|
40
54
|
return 'unknown'
|
|
@@ -29,7 +29,12 @@ export function createE2eServerEnv(profile: Record<string, string>): Record<stri
|
|
|
29
29
|
const environment: Record<string, string | undefined> = Object.fromEntries(
|
|
30
30
|
Object.keys(process.env).filter(key => /^(?:HAI_|PUBLIC_|VITE_)/i.test(key)).map(key => [key, undefined]),
|
|
31
31
|
)
|
|
32
|
-
for (const name of [
|
|
32
|
+
for (const name of [
|
|
33
|
+
'HAI_E2E_DATA_ROOT',
|
|
34
|
+
'HAI_AUTH_EVIDENCE_DIR',
|
|
35
|
+
'HAI_CORE_NAME',
|
|
36
|
+
'HAI_CORE_VERSION',
|
|
37
|
+
]) {
|
|
33
38
|
if (process.env[name] !== undefined)
|
|
34
39
|
environment[name] = process.env[name]
|
|
35
40
|
}
|
|
@@ -56,10 +61,15 @@ export function createE2eServerEnv(profile: Record<string, string>): Record<stri
|
|
|
56
61
|
export function createE2eTransportRing(): string {
|
|
57
62
|
const key = createECDH('SM2')
|
|
58
63
|
key.generateKeys()
|
|
59
|
-
return JSON.stringify({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
return JSON.stringify({
|
|
65
|
+
activeKeyId: 'e2e-v1',
|
|
66
|
+
keys: {
|
|
67
|
+
'e2e-v1': {
|
|
68
|
+
publicKey: key.getPublicKey('hex'),
|
|
69
|
+
privateKey: key.getPrivateKey('hex').padStart(64, '0'),
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
})
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
/**
|
|
@@ -93,6 +103,12 @@ export function createE2eNotificationEnv(): Record<string, string> {
|
|
|
93
103
|
{ name: 'password_reset', provider: 'email', body: 'Reset: {token}' },
|
|
94
104
|
{ name: 'password_reset_sms', provider: 'sms', body: 'Reset: {token}' },
|
|
95
105
|
]),
|
|
96
|
-
HAI_IAM_AGREEMENTS: JSON.stringify({
|
|
106
|
+
HAI_IAM_AGREEMENTS: JSON.stringify({
|
|
107
|
+
showOnRegister: true,
|
|
108
|
+
showOnLogin: true,
|
|
109
|
+
userAgreementMarkdown: '# Configured registration agreement\n\n**Registration terms**\n\n- Keep your account credentials secure.',
|
|
110
|
+
userAgreementUrl: new URL('/terms', url).href,
|
|
111
|
+
privacyPolicyUrl: new URL('/privacy', url).href,
|
|
112
|
+
}),
|
|
97
113
|
}
|
|
98
114
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/** 原生工具在 Node 边界解析 Core 名称,不初始化服务或导出完整配置。 */
|
|
2
|
+
import process from 'node:process'
|
|
3
|
+
import { core, CoreConfigSchema } from '@h-ai/core'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 读取原生构建所需的 Core 环境覆盖,父级必须是对象。
|
|
7
|
+
* @param {NodeJS.ProcessEnv} [environment] 原生构建的已合并环境。
|
|
8
|
+
* @returns {Record<string, unknown>} Core 环境覆盖值。
|
|
9
|
+
*/
|
|
10
|
+
function resolveCoreInputs(environment) {
|
|
11
|
+
const resolved = core.config.resolve({
|
|
12
|
+
name: 'core',
|
|
13
|
+
value: {},
|
|
14
|
+
schema: CoreConfigSchema,
|
|
15
|
+
environment,
|
|
16
|
+
})
|
|
17
|
+
if (!resolved.success)
|
|
18
|
+
throw new Error(resolved.error.message)
|
|
19
|
+
const { data } = resolved
|
|
20
|
+
if (data === null || typeof data !== 'object' || Array.isArray(data))
|
|
21
|
+
throw new Error('Invalid HAI_CORE: expected a JSON object')
|
|
22
|
+
return /** @type {Record<string, unknown>} */ (data)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 只将显式名称和环境模式传给原生构建子进程,父 JSON 中的其他字段不透传。
|
|
27
|
+
* @param {string} [envDir] 指定时先读取该目录的环境文件,供隔离容器的名称输入使用。
|
|
28
|
+
* @returns {Record<string, string>} 原生名称的公开构建输入。
|
|
29
|
+
*/
|
|
30
|
+
export function nativeNameEnvironment(envDir) {
|
|
31
|
+
let inputs = process.env
|
|
32
|
+
/** @type {string | undefined} */
|
|
33
|
+
let selectedMode
|
|
34
|
+
if (envDir) {
|
|
35
|
+
selectedMode = /** @type {string | undefined} */ (resolveCoreInputs().env) ?? 'production'
|
|
36
|
+
const loaded = core.config.loadEnvFiles({ envDir, mode: selectedMode })
|
|
37
|
+
if (!loaded.success)
|
|
38
|
+
throw new Error(loaded.error.message)
|
|
39
|
+
inputs = loaded.data
|
|
40
|
+
}
|
|
41
|
+
const value = resolveCoreInputs(inputs)
|
|
42
|
+
// 父 JSON 替换 YAML。只转发细项时也要保留 name 缺省后的 Schema 默认值。
|
|
43
|
+
if (inputs.HAI_CORE !== undefined && value.name === undefined)
|
|
44
|
+
value.name = CoreConfigSchema.shape.name.parse(undefined)
|
|
45
|
+
/** @type {Record<string, string>} */
|
|
46
|
+
const environment = {}
|
|
47
|
+
for (const key of ['name', 'env']) {
|
|
48
|
+
if (value[key] === undefined)
|
|
49
|
+
continue
|
|
50
|
+
const schema = key === 'name'
|
|
51
|
+
? CoreConfigSchema.shape.name
|
|
52
|
+
: CoreConfigSchema.shape.env
|
|
53
|
+
const parsed = schema.safeParse(value[key])
|
|
54
|
+
if (!parsed.success)
|
|
55
|
+
throw new Error(`Invalid HAI_CORE_${key.toUpperCase()}`)
|
|
56
|
+
environment[`HAI_CORE_${key.toUpperCase()}`] = parsed.data
|
|
57
|
+
}
|
|
58
|
+
// 保留本次入口选择的模式,避免 dotenv 的运行环境字段改变子进程二次加载的文件集合。
|
|
59
|
+
if (selectedMode)
|
|
60
|
+
environment.HAI_CORE_ENV = selectedMode
|
|
61
|
+
return environment
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 按 Core 统一的 dotenv 优先级加载名称;环境只在同步解析期间注入并在结束后还原。
|
|
66
|
+
* @param {string} envDir 环境文件目录。
|
|
67
|
+
* @param {string} configFile Core YAML 的绝对路径。
|
|
68
|
+
* @param {string} [mode] 未指定时使用显式 Core 模式、NODE_ENV,最后默认为 prod。
|
|
69
|
+
* @returns {string} 应用显示名称。
|
|
70
|
+
*/
|
|
71
|
+
export function resolveNativeName(envDir, configFile, mode) {
|
|
72
|
+
const overrides = nativeNameEnvironment()
|
|
73
|
+
const loaded = core.config.loadEnvFiles({ mode: overrides.HAI_CORE_ENV ?? mode ?? process.env.NODE_ENV ?? 'prod', envDir })
|
|
74
|
+
if (!loaded.success)
|
|
75
|
+
throw new Error(loaded.error.message)
|
|
76
|
+
const previous = new Map(Object.keys(loaded.data).map(key => [key, process.env[key]]))
|
|
77
|
+
try {
|
|
78
|
+
Object.assign(process.env, loaded.data)
|
|
79
|
+
const result = core.config.load('core', configFile, CoreConfigSchema)
|
|
80
|
+
if (!result.success)
|
|
81
|
+
throw new Error(result.error.message)
|
|
82
|
+
if (!result.data.name.trim())
|
|
83
|
+
throw new Error('Invalid HAI_CORE_NAME: expected a nonempty application name')
|
|
84
|
+
return result.data.name
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
for (const [key, value] of previous) {
|
|
88
|
+
if (value === undefined)
|
|
89
|
+
delete process.env[key]
|
|
90
|
+
else
|
|
91
|
+
process.env[key] = value
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|