From f9e1286ab188d9351ab20258c31324e472768f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Thu, 9 Apr 2026 07:35:34 +0800 Subject: [PATCH] =?UTF-8?q?refactor(developer-config):=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E5=BC=80=E5=8F=91=E8=80=85=E9=85=8D=E7=BD=AE=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=E5=92=8C=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除应用配置页面及相关组件,重构路由为 /developer/config/[id].vue - 移除开发者文档页面及其导航与样式实现 - 清理开发者侧功能完善工作日志文件 - 删除全局.gitignore配置文件,清理无用忽略规则 - 优化应用配置页面的参数读取和路由结构,解决刷新404问题 - 解决数据库配置唯一键冲突,调整保存逻辑避免重复插入 - 移除对后端配置加密字段的 secret 标记,修正加密异常问题 --- .data/content/contents.sqlite | Bin 589824 -> 589824 bytes .gitignore | 26 - .nuxt/app.config.mjs | 21 + .nuxt/components.d.ts | 162 + .nuxt/content/components.ts | 58 + .nuxt/content/database.compressed.mjs | 1 + .nuxt/content/manifest.ts | 33 + .nuxt/content/sql_dump.txt | 18 + .nuxt/content/types.d.ts | 21 + .nuxt/dev/index.mjs | 4271 +++++++++++++++++ .nuxt/dev/index.mjs.map | 1 + .nuxt/i18n-route-resources.mjs | 3 + .nuxt/imports.d.ts | 49 + .nuxt/mdc-configs.mjs | 8 + .nuxt/mdc-highlighter.mjs | 217 + .nuxt/mdc-image-component.mjs | 1 + .nuxt/mdc-imports.mjs | 12 + .nuxt/nitro.json | 17 + .nuxt/nuxt.d.ts | 26 + .nuxt/nuxt.json | 9 + .nuxt/nuxt.node.d.ts | 16 + .nuxt/nuxt.shared.d.ts | 5 + .nuxt/schema/nuxt.schema.d.ts | 17 + .nuxt/schema/nuxt.schema.json | 3 + .nuxt/tailwind/postcss.mjs | 16 + .nuxt/tsconfig.app.json | 263 + .nuxt/tsconfig.json | 264 + .nuxt/tsconfig.node.json | 140 + .nuxt/tsconfig.server.json | 194 + .nuxt/tsconfig.shared.json | 188 + .nuxt/types/app.config.d.ts | 35 + .nuxt/types/build.d.ts | 26 + .nuxt/types/builder-env.d.ts | 1 + .nuxt/types/components.d.ts | 167 + .nuxt/types/i18n-plugin.d.ts | 115 + .nuxt/types/imports.d.ts | 485 ++ .nuxt/types/layouts.d.ts | 7 + .nuxt/types/middleware.d.ts | 7 + .nuxt/types/modules.d.ts | 139 + .nuxt/types/nitro-config.d.ts | 14 + .nuxt/types/nitro-imports.d.ts | 171 + .nuxt/types/nitro-middleware.d.ts | 11 + .nuxt/types/nitro-nuxt.d.ts | 61 + .nuxt/types/nitro-routes.d.ts | 50 + .nuxt/types/nitro.d.ts | 3 + .nuxt/types/plugins.d.ts | 45 + .nuxt/types/runtime-config.d.ts | 184 + .nuxt/types/vue-shim.d.ts | 0 .workbuddy/expert-history.json | 48 +- .workbuddy/memory/2026-04-09.md | 35 + app/config/admin-nav.ts | 160 +- app/config/oa-nav.ts | 10 +- app/layouts/developer.vue | 664 --- app/pages/admin/account.vue | 247 + app/pages/admin/developers.vue | 569 +-- app/pages/admin/developers/audit.vue | 119 + app/pages/admin/enterprises.vue | 301 ++ app/pages/admin/enterprises/detail.vue | 78 + app/pages/admin/finance.vue | 267 ++ app/pages/admin/finance/recharge.vue | 89 + app/pages/admin/index.vue | 578 ++- app/pages/admin/management/decision.vue | 144 + app/pages/admin/management/finance.vue | 383 ++ app/pages/admin/management/hr.vue | 453 ++ app/pages/admin/management/office.vue | 477 ++ app/pages/admin/members.vue | 328 ++ app/pages/admin/members/roles.vue | 96 + app/pages/admin/product/design.vue | 352 ++ app/pages/admin/product/marketing.vue | 169 + app/pages/admin/product/service.vue | 127 + app/pages/admin/production/control.vue | 113 + app/pages/admin/production/energy.vue | 111 + app/pages/admin/production/equipment.vue | 617 +++ app/pages/admin/production/quality.vue | 98 + app/pages/admin/production/safety.vue | 95 + app/pages/admin/production/schedule.vue | 155 + app/pages/admin/supply/purchase.vue | 465 ++ app/pages/admin/supply/warehouse.vue | 462 ++ app/pages/ai-agent.vue | 342 -- app/pages/apps.vue | 11 - app/pages/bind-phone.vue | 283 -- app/pages/create-app.vue | 595 --- app/pages/deploy.vue | 91 - app/pages/developer-center.vue | 364 -- .../developer/.workbuddy/memory/2026-03-30.md | 41 - .../developer/.workbuddy/memory/2026-03-31.md | 126 - .../developer/.workbuddy/memory/MEMORY.md | 102 - app/pages/developer/analytics.vue | 979 ---- app/pages/developer/apikeys.vue | 675 --- app/pages/developer/apps.vue | 235 - app/pages/developer/build.vue | 701 --- app/pages/developer/cloudCredentials.vue | 419 -- app/pages/developer/config/[id].vue | 693 --- app/pages/developer/docs/[...slug].vue | 567 --- app/pages/developer/docs/index.vue | 422 -- app/pages/developer/git.vue | 524 -- app/pages/developer/index.vue | 845 ---- app/pages/developer/pipeline.vue | 653 --- app/pages/developer/publish.vue | 699 --- app/pages/developer/requests.vue | 564 --- .../resources/README_RESOURCE_COLLAB.md | 142 - app/pages/developer/resources/SSL_TESTS.md | 98 - app/pages/developer/resources/databases.vue | 508 -- app/pages/developer/resources/domains.vue | 388 -- app/pages/developer/resources/git.vue | 682 --- app/pages/developer/resources/index.vue | 289 -- app/pages/developer/resources/servers.vue | 1039 ---- app/pages/developer/resources/ssl.vue | 1108 ----- app/pages/developer/resources/storage.vue | 568 --- app/pages/developer/source.vue | 368 -- app/pages/developer/support.vue | 405 -- app/pages/developer/tickets.vue | 865 ---- app/pages/developer/versions.vue | 673 --- app/pages/flow.vue | 71 - app/pages/login.vue | 2 +- app/pages/market.vue | 900 ---- app/pages/market/[id].vue | 547 --- app/pages/miniapp.vue | 297 -- app/pages/oa.vue | 955 ++-- app/pages/oa/projects.vue | 792 +++ app/pages/oa/tasks.vue | 1031 ++++ app/pages/openclaw.vue | 328 -- app/pages/platform.vue | 115 - app/pages/procurement.vue | 580 +++ app/pages/products.vue | 64 - app/pages/shop.vue | 281 -- app/pages/tiantian-system/index.vue | 496 -- app/pages/website.vue | 332 -- 人力资源管理.html | 805 ++++ 采购管理.html | 748 +++ 130 files changed, 18656 insertions(+), 22143 deletions(-) delete mode 100644 .gitignore create mode 100644 .nuxt/app.config.mjs create mode 100644 .nuxt/components.d.ts create mode 100644 .nuxt/content/components.ts create mode 100644 .nuxt/content/database.compressed.mjs create mode 100644 .nuxt/content/manifest.ts create mode 100644 .nuxt/content/sql_dump.txt create mode 100644 .nuxt/content/types.d.ts create mode 100644 .nuxt/dev/index.mjs create mode 100644 .nuxt/dev/index.mjs.map create mode 100644 .nuxt/i18n-route-resources.mjs create mode 100644 .nuxt/imports.d.ts create mode 100644 .nuxt/mdc-configs.mjs create mode 100644 .nuxt/mdc-highlighter.mjs create mode 100644 .nuxt/mdc-image-component.mjs create mode 100644 .nuxt/mdc-imports.mjs create mode 100644 .nuxt/nitro.json create mode 100644 .nuxt/nuxt.d.ts create mode 100644 .nuxt/nuxt.json create mode 100644 .nuxt/nuxt.node.d.ts create mode 100644 .nuxt/nuxt.shared.d.ts create mode 100644 .nuxt/schema/nuxt.schema.d.ts create mode 100644 .nuxt/schema/nuxt.schema.json create mode 100644 .nuxt/tailwind/postcss.mjs create mode 100644 .nuxt/tsconfig.app.json create mode 100644 .nuxt/tsconfig.json create mode 100644 .nuxt/tsconfig.node.json create mode 100644 .nuxt/tsconfig.server.json create mode 100644 .nuxt/tsconfig.shared.json create mode 100644 .nuxt/types/app.config.d.ts create mode 100644 .nuxt/types/build.d.ts create mode 100644 .nuxt/types/builder-env.d.ts create mode 100644 .nuxt/types/components.d.ts create mode 100644 .nuxt/types/i18n-plugin.d.ts create mode 100644 .nuxt/types/imports.d.ts create mode 100644 .nuxt/types/layouts.d.ts create mode 100644 .nuxt/types/middleware.d.ts create mode 100644 .nuxt/types/modules.d.ts create mode 100644 .nuxt/types/nitro-config.d.ts create mode 100644 .nuxt/types/nitro-imports.d.ts create mode 100644 .nuxt/types/nitro-middleware.d.ts create mode 100644 .nuxt/types/nitro-nuxt.d.ts create mode 100644 .nuxt/types/nitro-routes.d.ts create mode 100644 .nuxt/types/nitro.d.ts create mode 100644 .nuxt/types/plugins.d.ts create mode 100644 .nuxt/types/runtime-config.d.ts create mode 100644 .nuxt/types/vue-shim.d.ts create mode 100644 .workbuddy/memory/2026-04-09.md delete mode 100644 app/layouts/developer.vue create mode 100644 app/pages/admin/account.vue create mode 100644 app/pages/admin/developers/audit.vue create mode 100644 app/pages/admin/enterprises.vue create mode 100644 app/pages/admin/enterprises/detail.vue create mode 100644 app/pages/admin/finance.vue create mode 100644 app/pages/admin/finance/recharge.vue create mode 100644 app/pages/admin/management/decision.vue create mode 100644 app/pages/admin/management/finance.vue create mode 100644 app/pages/admin/management/hr.vue create mode 100644 app/pages/admin/management/office.vue create mode 100644 app/pages/admin/members.vue create mode 100644 app/pages/admin/members/roles.vue create mode 100644 app/pages/admin/product/design.vue create mode 100644 app/pages/admin/product/marketing.vue create mode 100644 app/pages/admin/product/service.vue create mode 100644 app/pages/admin/production/control.vue create mode 100644 app/pages/admin/production/energy.vue create mode 100644 app/pages/admin/production/equipment.vue create mode 100644 app/pages/admin/production/quality.vue create mode 100644 app/pages/admin/production/safety.vue create mode 100644 app/pages/admin/production/schedule.vue create mode 100644 app/pages/admin/supply/purchase.vue create mode 100644 app/pages/admin/supply/warehouse.vue delete mode 100644 app/pages/ai-agent.vue delete mode 100644 app/pages/apps.vue delete mode 100644 app/pages/bind-phone.vue delete mode 100644 app/pages/create-app.vue delete mode 100644 app/pages/deploy.vue delete mode 100644 app/pages/developer-center.vue delete mode 100644 app/pages/developer/.workbuddy/memory/2026-03-30.md delete mode 100644 app/pages/developer/.workbuddy/memory/2026-03-31.md delete mode 100644 app/pages/developer/.workbuddy/memory/MEMORY.md delete mode 100644 app/pages/developer/analytics.vue delete mode 100644 app/pages/developer/apikeys.vue delete mode 100644 app/pages/developer/apps.vue delete mode 100644 app/pages/developer/build.vue delete mode 100644 app/pages/developer/cloudCredentials.vue delete mode 100644 app/pages/developer/config/[id].vue delete mode 100644 app/pages/developer/docs/[...slug].vue delete mode 100644 app/pages/developer/docs/index.vue delete mode 100644 app/pages/developer/git.vue delete mode 100644 app/pages/developer/index.vue delete mode 100644 app/pages/developer/pipeline.vue delete mode 100644 app/pages/developer/publish.vue delete mode 100644 app/pages/developer/requests.vue delete mode 100644 app/pages/developer/resources/README_RESOURCE_COLLAB.md delete mode 100644 app/pages/developer/resources/SSL_TESTS.md delete mode 100644 app/pages/developer/resources/databases.vue delete mode 100644 app/pages/developer/resources/domains.vue delete mode 100644 app/pages/developer/resources/git.vue delete mode 100644 app/pages/developer/resources/index.vue delete mode 100644 app/pages/developer/resources/servers.vue delete mode 100644 app/pages/developer/resources/ssl.vue delete mode 100644 app/pages/developer/resources/storage.vue delete mode 100644 app/pages/developer/source.vue delete mode 100644 app/pages/developer/support.vue delete mode 100644 app/pages/developer/tickets.vue delete mode 100644 app/pages/developer/versions.vue delete mode 100644 app/pages/flow.vue delete mode 100644 app/pages/market.vue delete mode 100644 app/pages/market/[id].vue delete mode 100644 app/pages/miniapp.vue create mode 100644 app/pages/oa/projects.vue create mode 100644 app/pages/oa/tasks.vue delete mode 100644 app/pages/openclaw.vue delete mode 100644 app/pages/platform.vue create mode 100644 app/pages/procurement.vue delete mode 100644 app/pages/products.vue delete mode 100644 app/pages/shop.vue delete mode 100644 app/pages/tiantian-system/index.vue delete mode 100644 app/pages/website.vue create mode 100644 人力资源管理.html create mode 100644 采购管理.html diff --git a/.data/content/contents.sqlite b/.data/content/contents.sqlite index 613f3191f15613a059cafeaf5732c77629060539..50ff26a0ae39c883c05f81928616e18205a1c856 100644 GIT binary patch delta 1480 zcmXxkdu$X%7y$75c6VmCaJ^X`fkJ^h-ll2ksel0m4-oH&rh8o1NKw^Udte z>^RO8$C;8W9yZtG@g&L9-;1Y9pNF}f(NZ5&9BcO-Z}$Pwh%VcG#_mK%%CK7sDIC}s z5B;}OwUIo%CaCTZm2@YmC#OgQ*-M_r?V>@3@ zsc0q#i3-|B_7jy*C2k?>|5r)ZbwmxcjZ~41WD}_-TgYY-C0mJ#sUdBoov6vHz9+~@ za@6A~8Jw*{jWuK?Sw&Wp2suXHBNb#>XQEG+W6l~6hIkpZE%7szp4X%|ZS)HNb}uzf z4W*)W2o-UQiWZZK8Wnt0{&n48L8g*z!v*`aV(HJZdjcXjaVc9Ns~h2>z~B|#Yf!}M zuEKP`a8u0%sVk7=ol73E{t-|q?Fi%r#%Gv= zSyp0G6_jB*u8qRzETd3HqmUAAWSKXUj0wZl!DF)Np0X3u7@$@=9Aa5qM7X)5gtCwTwCM$Q-l?<=>%|*Ow zdQH3`hAZcpFU!Y{HbP*&P8*K(Ve=eR%ga$373~Ll4caG7j^RTv1bfTPnXnOIqOn14 z3Yr}PqWEbTrs4c<(<^89nBNQ7f=xxxfWHeEE?cu^i-4`t$e9Cvh+!hiiZI>JzLAfU zKm%TH18*j6rghjPJG;yh4x8oeZgVn+_DkH(4-(gftrY-vXLD@|K-Rs-(B^d1<~)oS{A>nBUeZ>{4+2`PICqg5m_N@(z!BL~qJbvIJf}SSo0h+B5kuy}tk(>V*T+Tgv)%*pUe` zdK+&`BSbym9k=t_HCX0li{-}=787tBpEO&I_|bA!C3~Z6rhs>8F;w!Cbvt7P9Wn1?BFsuKc$iH)lkmIw=ya^UqWQ4?zP3=( vqYM{jyhfd0ZPHA`pF*!|h;<}QJ7cSn)G2rjp+c8uRt>J!OevnV`h5Qay+)dU delta 1507 zcmXw&Yitx%6vy|>6TY1rDc(pwm{qEC67|N zON$6nS(w1l55j7sgapEthP_}ST|cOa33iQ%F#*X+5Nsm44SrA)g6FPuGQV@rYi|Dc z-nqeGelVCH&UvoD<#L6I(Z_SLcor1&`-`(+X?Jhdk=`sI6halfS=!D}S0=TBKG{XD zk6iijC^9}w^bp;|31Y=FU*=>@_H+=(p7}DCJu8VOVl%OY*h;hz&BSQFk^HU(GTVq6 zVzg1ltwbA9_lyvYhlqNjme@_KCuDszx0C!%;s7B|5UBnJzJF$nTa=D7q zYNhIRgj~f@;s_BY0>oNkDY2|SG@^>h=e37p`@)*#)+uN5pUAo@ggdGYagWbU!HNtr zE60*)Hp#RZWDdyYD)H~2rkBCmn2$Z>&=a#v8ji-2a_ESanHg?4CfxJP$0}@&*`{j2 zDxvvgb+yy~^(rixYAzOM{bnPFHTY+~9>9<5%vv!NFlTe97FtlYu0wC5mLoi2<35L4 zjGtC((fV7Ng2`8u4Dq2?Y366H8XBgq7~|n>5ie3e5tCn59%f>yiA~T*Xq~WpkmA_> zo$i)#J#Mds5{$Mh6VX3M%M^Y;M7ZNymacBV+!}Mas1LxW9Lp}N>7*YQ?NLZYN+T5; z5eiv0M)TNL;!zmJa~wPl?mnAYa`sIK*9|Ym4=|6Ywv~$H-{` zX_%rS%x-XKz-2*}CuRiM9S%(xUTDq{<$m@pheiy&so3~Mp7A2uJ!-qS9bg4KmXy1_ zEf!&#bxkwK-{Ne%J=gKyFvaqSdX+ojC27sA!V0P>ZWVWQ7Egb@@~uTnmd_`BTk)41 zWrE1|8o$w8M&%f&5x!yL3WN2rfKG?hE-pruYVKI~yqLMhT#L!;kb!qk=mikKp>xV~ zOgb=43`dkn9DP&uVl0a)`&615`%7uj--MNNjyG4UrD(V4rB1Y3$D3F5H(-~z=%`DbALWhDz+A1JShKjJWsv-SpgWiZ!(Y)mW$ zwPulyVrM zLKUZ0c=6mOb++Im=17*zcZ+FW*;kQIyO}CAt(Yy(@!f&U#AAMH1W$gZcn3=2 zKX8m}fOPJ?fz0S*?nHK_qxZ3MsWD091nIwk;~1K+o)>XjwK)!V8B?HF_W!%rYpxTB7VH{~POOVds|7~rxHHVh+)ObOtDfWc_ E2gb*vHvj+t diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ea1e3d0..0000000 --- a/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# Nuxt dev/build outputs -.output -.data -.nuxt -.nitro -.cache -dist - -# Node dependencies -node_modules - -# Logs -logs -*.log -.pm2 - -# Misc -.DS_Store -.fleet -.idea - -# Local env files -.env -.env.* -!.env.example -/.npm-cache/ diff --git a/.nuxt/app.config.mjs b/.nuxt/app.config.mjs new file mode 100644 index 0000000..0b712c1 --- /dev/null +++ b/.nuxt/app.config.mjs @@ -0,0 +1,21 @@ + +import { defuFn } from 'defu' + +const inlineConfig = { + "nuxt": {} +} + +/** client **/ +import { _replaceAppConfig } from '#app/config' + +// Vite - webpack is handled directly in #app/config +if (import.meta.dev && !import.meta.nitro && import.meta.hot) { + import.meta.hot.accept((newModule) => { + _replaceAppConfig(newModule.default) + }) +} +/** client-end **/ + + + +export default /*@__PURE__*/ defuFn(inlineConfig) diff --git a/.nuxt/components.d.ts b/.nuxt/components.d.ts new file mode 100644 index 0000000..434238f --- /dev/null +++ b/.nuxt/components.d.ts @@ -0,0 +1,162 @@ + +import type { DefineComponent, SlotsType } from 'vue' +type IslandComponent = DefineComponent<{}, {refresh: () => Promise}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, SlotsType<{ fallback: { error: unknown } }>> & T + +type HydrationStrategies = { + hydrateOnVisible?: IntersectionObserverInit | true + hydrateOnIdle?: number | true + hydrateOnInteraction?: keyof HTMLElementEventMap | Array | true + hydrateOnMediaQuery?: string + hydrateAfter?: number + hydrateWhen?: boolean + hydrateNever?: true +} +type LazyComponent = DefineComponent void }> & T + + +export const LangSwitch: typeof import("../app/components/LangSwitch.vue").default +export const NotificationBell: typeof import("../app/components/NotificationBell.vue").default +export const QrCodeModal: typeof import("../app/components/QrCodeModal.vue").default +export const QrLogin: typeof import("../app/components/QrLogin.vue").default +export const SiteFooter: typeof import("../app/components/SiteFooter.vue").default +export const SiteHeader: typeof import("../app/components/SiteHeader.vue").default +export const AdminMarkdownEditor: typeof import("../app/components/admin/MarkdownEditor.vue").default +export const AdminMarkdownRenderer: typeof import("../app/components/admin/MarkdownRenderer.vue").default +export const ConsoleAppsCenter: typeof import("../app/components/console/AppsCenter.vue").default +export const ConsoleHeader: typeof import("../app/components/console/ConsoleHeader.vue").default +export const DeveloperAppDetail: typeof import("../app/components/developer/AppDetail.vue").default +export const DeveloperAppsCenter: typeof import("../app/components/developer/AppsCenter.vue").default +export const DeveloperPermissionGuard: typeof import("../app/components/developer/PermissionGuard.vue").default +export const DeveloperRoleTag: typeof import("../app/components/developer/RoleTag.vue").default +export const InviteBell: typeof import("../app/components/invite/InviteBell.vue").default +export const InviteNotification: typeof import("../app/components/invite/InviteNotification.vue").default +export const PaymentModal: typeof import("../app/components/payment/PaymentModal.vue").default +export const ProseA: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseA.vue").default +export const ProseBlockquote: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseBlockquote.vue").default +export const ProseCode: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseCode.vue").default +export const ProseEm: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseEm.vue").default +export const ProseH1: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseH1.vue").default +export const ProseH2: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseH2.vue").default +export const ProseH3: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseH3.vue").default +export const ProseH4: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseH4.vue").default +export const ProseH5: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseH5.vue").default +export const ProseH6: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseH6.vue").default +export const ProseHr: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseHr.vue").default +export const ProseImg: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseImg.vue").default +export const ProseLi: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseLi.vue").default +export const ProseOl: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseOl.vue").default +export const ProseP: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseP.vue").default +export const ProsePre: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProsePre.vue").default +export const ProseScript: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseScript.vue").default +export const ProseStrong: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseStrong.vue").default +export const ProseTable: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseTable.vue").default +export const ProseTbody: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseTbody.vue").default +export const ProseTd: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseTd.vue").default +export const ProseTh: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseTh.vue").default +export const ProseThead: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseThead.vue").default +export const ProseTr: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseTr.vue").default +export const ProseUl: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/prose/ProseUl.vue").default +export const NuxtWelcome: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/welcome.vue").default +export const NuxtLayout: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-layout").default +export const NuxtErrorBoundary: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-error-boundary.vue").default +export const ClientOnly: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/client-only").default +export const DevOnly: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/dev-only").default +export const ServerPlaceholder: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/server-placeholder").default +export const NuxtLink: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-link").default +export const NuxtLoadingIndicator: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-loading-indicator").default +export const NuxtTime: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-time.vue").default +export const NuxtRouteAnnouncer: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-route-announcer").default +export const NuxtImg: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-stubs").NuxtImg +export const NuxtPicture: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-stubs").NuxtPicture +export const ContentRenderer: typeof import("../node_modules/.pnpm/@nuxt+content@3.12.0_better-sqlite3@12.8.0_magicast@0.5.1/node_modules/@nuxt/content/dist/runtime/components/ContentRenderer.vue").default +export const NuxtLinkLocale: typeof import("../node_modules/.pnpm/@nuxtjs+i18n@10.2.4_@emnapi+core@1.7.1_@emnapi+runtime@1.7.1_@vue+compiler-dom@3.5.26_d_a5323b549840adcc2cb57cfe4f807173/node_modules/@nuxtjs/i18n/dist/runtime/components/NuxtLinkLocale").default +export const SwitchLocalePathLink: typeof import("../node_modules/.pnpm/@nuxtjs+i18n@10.2.4_@emnapi+core@1.7.1_@emnapi+runtime@1.7.1_@vue+compiler-dom@3.5.26_d_a5323b549840adcc2cb57cfe4f807173/node_modules/@nuxtjs/i18n/dist/runtime/components/SwitchLocalePathLink").default +export const NuxtPage: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/pages/runtime/page").default +export const NoScript: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").NoScript +export const Link: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").Link +export const Base: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").Base +export const Title: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").Title +export const Meta: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").Meta +export const Style: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").Style +export const Head: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").Head +export const Html: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").Html +export const Body: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").Body +export const MDC: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDC.vue").default +export const MDCCached: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDCCached.vue").default +export const MDCRenderer: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDCRenderer.vue").default +export const MDCSlot: typeof import("../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDCSlot.vue").default +export const NuxtIsland: typeof import("../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-island").default +export const LazyLangSwitch: LazyComponent +export const LazyNotificationBell: LazyComponent +export const LazyQrCodeModal: LazyComponent +export const LazyQrLogin: LazyComponent +export const LazySiteFooter: LazyComponent +export const LazySiteHeader: LazyComponent +export const LazyAdminMarkdownEditor: LazyComponent +export const LazyAdminMarkdownRenderer: LazyComponent +export const LazyConsoleAppsCenter: LazyComponent +export const LazyConsoleHeader: LazyComponent +export const LazyDeveloperAppDetail: LazyComponent +export const LazyDeveloperAppsCenter: LazyComponent +export const LazyDeveloperPermissionGuard: LazyComponent +export const LazyDeveloperRoleTag: LazyComponent +export const LazyInviteBell: LazyComponent +export const LazyInviteNotification: LazyComponent +export const LazyPaymentModal: LazyComponent +export const LazyProseA: LazyComponent +export const LazyProseBlockquote: LazyComponent +export const LazyProseCode: LazyComponent +export const LazyProseEm: LazyComponent +export const LazyProseH1: LazyComponent +export const LazyProseH2: LazyComponent +export const LazyProseH3: LazyComponent +export const LazyProseH4: LazyComponent +export const LazyProseH5: LazyComponent +export const LazyProseH6: LazyComponent +export const LazyProseHr: LazyComponent +export const LazyProseImg: LazyComponent +export const LazyProseLi: LazyComponent +export const LazyProseOl: LazyComponent +export const LazyProseP: LazyComponent +export const LazyProsePre: LazyComponent +export const LazyProseScript: LazyComponent +export const LazyProseStrong: LazyComponent +export const LazyProseTable: LazyComponent +export const LazyProseTbody: LazyComponent +export const LazyProseTd: LazyComponent +export const LazyProseTh: LazyComponent +export const LazyProseThead: LazyComponent +export const LazyProseTr: LazyComponent +export const LazyProseUl: LazyComponent +export const LazyNuxtWelcome: LazyComponent +export const LazyNuxtLayout: LazyComponent +export const LazyNuxtErrorBoundary: LazyComponent +export const LazyClientOnly: LazyComponent +export const LazyDevOnly: LazyComponent +export const LazyServerPlaceholder: LazyComponent +export const LazyNuxtLink: LazyComponent +export const LazyNuxtLoadingIndicator: LazyComponent +export const LazyNuxtTime: LazyComponent +export const LazyNuxtRouteAnnouncer: LazyComponent +export const LazyNuxtImg: LazyComponent +export const LazyNuxtPicture: LazyComponent +export const LazyContentRenderer: LazyComponent +export const LazyNuxtLinkLocale: LazyComponent +export const LazySwitchLocalePathLink: LazyComponent +export const LazyNuxtPage: LazyComponent +export const LazyNoScript: LazyComponent +export const LazyLink: LazyComponent +export const LazyBase: LazyComponent +export const LazyTitle: LazyComponent +export const LazyMeta: LazyComponent +export const LazyStyle: LazyComponent +export const LazyHead: LazyComponent +export const LazyHtml: LazyComponent +export const LazyBody: LazyComponent +export const LazyMDC: LazyComponent +export const LazyMDCCached: LazyComponent +export const LazyMDCRenderer: LazyComponent +export const LazyMDCSlot: LazyComponent +export const LazyNuxtIsland: LazyComponent + +export const componentNames: string[] diff --git a/.nuxt/content/components.ts b/.nuxt/content/components.ts new file mode 100644 index 0000000..da66108 --- /dev/null +++ b/.nuxt/content/components.ts @@ -0,0 +1,58 @@ +const pickExport = (mod, exportName, componentName, path) => { + const resolved = exportName === 'default' ? mod?.default : mod?.[exportName] + if (!resolved) { + throw new Error(`[nuxt-content] Missing export "${exportName}" for component "${componentName}" in "${path}".`) + } + return resolved +} +export const localComponentLoaders = { + LangSwitch: () => import("./../../app/components/LangSwitch.vue").then(m => pickExport(m, "default", "LangSwitch", "./../../app/components/LangSwitch.vue")), + NotificationBell: () => import("./../../app/components/NotificationBell.vue").then(m => pickExport(m, "default", "NotificationBell", "./../../app/components/NotificationBell.vue")), + QrCodeModal: () => import("./../../app/components/QrCodeModal.vue").then(m => pickExport(m, "default", "QrCodeModal", "./../../app/components/QrCodeModal.vue")), + QrLogin: () => import("./../../app/components/QrLogin.vue").then(m => pickExport(m, "default", "QrLogin", "./../../app/components/QrLogin.vue")), + SiteFooter: () => import("./../../app/components/SiteFooter.vue").then(m => pickExport(m, "default", "SiteFooter", "./../../app/components/SiteFooter.vue")), + SiteHeader: () => import("./../../app/components/SiteHeader.vue").then(m => pickExport(m, "default", "SiteHeader", "./../../app/components/SiteHeader.vue")), + AdminMarkdownEditor: () => import("./../../app/components/admin/MarkdownEditor.vue").then(m => pickExport(m, "default", "AdminMarkdownEditor", "./../../app/components/admin/MarkdownEditor.vue")), + AdminMarkdownRenderer: () => import("./../../app/components/admin/MarkdownRenderer.vue").then(m => pickExport(m, "default", "AdminMarkdownRenderer", "./../../app/components/admin/MarkdownRenderer.vue")), + ConsoleAppsCenter: () => import("./../../app/components/console/AppsCenter.vue").then(m => pickExport(m, "default", "ConsoleAppsCenter", "./../../app/components/console/AppsCenter.vue")), + ConsoleHeader: () => import("./../../app/components/console/ConsoleHeader.vue").then(m => pickExport(m, "default", "ConsoleHeader", "./../../app/components/console/ConsoleHeader.vue")), + DeveloperAppDetail: () => import("./../../app/components/developer/AppDetail.vue").then(m => pickExport(m, "default", "DeveloperAppDetail", "./../../app/components/developer/AppDetail.vue")), + DeveloperAppsCenter: () => import("./../../app/components/developer/AppsCenter.vue").then(m => pickExport(m, "default", "DeveloperAppsCenter", "./../../app/components/developer/AppsCenter.vue")), + DeveloperPermissionGuard: () => import("./../../app/components/developer/PermissionGuard.vue").then(m => pickExport(m, "default", "DeveloperPermissionGuard", "./../../app/components/developer/PermissionGuard.vue")), + DeveloperRoleTag: () => import("./../../app/components/developer/RoleTag.vue").then(m => pickExport(m, "default", "DeveloperRoleTag", "./../../app/components/developer/RoleTag.vue")), + InviteBell: () => import("./../../app/components/invite/InviteBell.vue").then(m => pickExport(m, "default", "InviteBell", "./../../app/components/invite/InviteBell.vue")), + InviteNotification: () => import("./../../app/components/invite/InviteNotification.vue").then(m => pickExport(m, "default", "InviteNotification", "./../../app/components/invite/InviteNotification.vue")), + PaymentModal: () => import("./../../app/components/payment/PaymentModal.vue").then(m => pickExport(m, "default", "PaymentModal", "./../../app/components/payment/PaymentModal.vue")), + NuxtWelcome: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/welcome.vue").then(m => pickExport(m, "default", "NuxtWelcome", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/welcome.vue")), + NuxtLayout: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-layout").then(m => pickExport(m, "default", "NuxtLayout", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-layout")), + NuxtErrorBoundary: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-error-boundary.vue").then(m => pickExport(m, "default", "NuxtErrorBoundary", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-error-boundary.vue")), + ClientOnly: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/client-only").then(m => pickExport(m, "default", "ClientOnly", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/client-only")), + DevOnly: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/dev-only").then(m => pickExport(m, "default", "DevOnly", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/dev-only")), + ServerPlaceholder: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/server-placeholder").then(m => pickExport(m, "default", "ServerPlaceholder", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/server-placeholder")), + NuxtLink: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-link").then(m => pickExport(m, "default", "NuxtLink", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-link")), + NuxtLoadingIndicator: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-loading-indicator").then(m => pickExport(m, "default", "NuxtLoadingIndicator", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-loading-indicator")), + NuxtTime: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-time.vue").then(m => pickExport(m, "default", "NuxtTime", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-time.vue")), + NuxtRouteAnnouncer: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-route-announcer").then(m => pickExport(m, "default", "NuxtRouteAnnouncer", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-route-announcer")), + NuxtImg: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-stubs").then(m => pickExport(m, "NuxtImg", "NuxtImg", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-stubs")), + NuxtPicture: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-stubs").then(m => pickExport(m, "NuxtPicture", "NuxtPicture", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-stubs")), + ContentRenderer: () => import("./../../node_modules/.pnpm/@nuxt+content@3.12.0_better-sqlite3@12.8.0_magicast@0.5.1/node_modules/@nuxt/content/dist/runtime/components/ContentRenderer.vue").then(m => pickExport(m, "default", "ContentRenderer", "./../../node_modules/.pnpm/@nuxt+content@3.12.0_better-sqlite3@12.8.0_magicast@0.5.1/node_modules/@nuxt/content/dist/runtime/components/ContentRenderer.vue")), + NuxtLinkLocale: () => import("./../../node_modules/.pnpm/@nuxtjs+i18n@10.2.4_@emnapi+core@1.7.1_@emnapi+runtime@1.7.1_@vue+compiler-dom@3.5.26_d_a5323b549840adcc2cb57cfe4f807173/node_modules/@nuxtjs/i18n/dist/runtime/components/NuxtLinkLocale").then(m => pickExport(m, "default", "NuxtLinkLocale", "./../../node_modules/.pnpm/@nuxtjs+i18n@10.2.4_@emnapi+core@1.7.1_@emnapi+runtime@1.7.1_@vue+compiler-dom@3.5.26_d_a5323b549840adcc2cb57cfe4f807173/node_modules/@nuxtjs/i18n/dist/runtime/components/NuxtLinkLocale")), + SwitchLocalePathLink: () => import("./../../node_modules/.pnpm/@nuxtjs+i18n@10.2.4_@emnapi+core@1.7.1_@emnapi+runtime@1.7.1_@vue+compiler-dom@3.5.26_d_a5323b549840adcc2cb57cfe4f807173/node_modules/@nuxtjs/i18n/dist/runtime/components/SwitchLocalePathLink").then(m => pickExport(m, "default", "SwitchLocalePathLink", "./../../node_modules/.pnpm/@nuxtjs+i18n@10.2.4_@emnapi+core@1.7.1_@emnapi+runtime@1.7.1_@vue+compiler-dom@3.5.26_d_a5323b549840adcc2cb57cfe4f807173/node_modules/@nuxtjs/i18n/dist/runtime/components/SwitchLocalePathLink")), + NuxtPage: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/pages/runtime/page").then(m => pickExport(m, "default", "NuxtPage", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/pages/runtime/page")), + NoScript: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").then(m => pickExport(m, "NoScript", "NoScript", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components")), + Link: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").then(m => pickExport(m, "Link", "Link", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components")), + Base: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").then(m => pickExport(m, "Base", "Base", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components")), + Title: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").then(m => pickExport(m, "Title", "Title", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components")), + Meta: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").then(m => pickExport(m, "Meta", "Meta", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components")), + Style: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").then(m => pickExport(m, "Style", "Style", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components")), + Head: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").then(m => pickExport(m, "Head", "Head", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components")), + Html: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").then(m => pickExport(m, "Html", "Html", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components")), + Body: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components").then(m => pickExport(m, "Body", "Body", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/head/runtime/components")), + MDC: () => import("./../../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDC.vue").then(m => pickExport(m, "default", "MDC", "./../../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDC.vue")), + MDCCached: () => import("./../../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDCCached.vue").then(m => pickExport(m, "default", "MDCCached", "./../../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDCCached.vue")), + MDCRenderer: () => import("./../../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDCRenderer.vue").then(m => pickExport(m, "default", "MDCRenderer", "./../../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDCRenderer.vue")), + MDCSlot: () => import("./../../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDCSlot.vue").then(m => pickExport(m, "default", "MDCSlot", "./../../node_modules/.pnpm/@nuxtjs+mdc@0.20.2_magicast@0.5.1/node_modules/@nuxtjs/mdc/dist/runtime/components/MDCSlot.vue")), + NuxtIsland: () => import("./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-island").then(m => pickExport(m, "default", "NuxtIsland", "./../../node_modules/.pnpm/nuxt@4.2.2_@parcel+watcher@2.5.1_@types+node@25.0.3_@vue+compiler-sfc@3.5.26_better-sql_ac6a4d57fe59bc83c2ad1951937f70f6/node_modules/nuxt/dist/app/components/nuxt-island")), +} +export const globalComponents: string[] = ["ProseA","ProseBlockquote","ProseCode","ProseEm","ProseH1","ProseH2","ProseH3","ProseH4","ProseH5","ProseH6","ProseHr","ProseImg","ProseLi","ProseOl","ProseP","ProsePre","ProseScript","ProseStrong","ProseTable","ProseTbody","ProseTd","ProseTh","ProseThead","ProseTr","ProseUl"] +export const localComponents: string[] = ["LangSwitch","NotificationBell","QrCodeModal","QrLogin","SiteFooter","SiteHeader","AdminMarkdownEditor","AdminMarkdownRenderer","ConsoleAppsCenter","ConsoleHeader","DeveloperAppDetail","DeveloperAppsCenter","DeveloperPermissionGuard","DeveloperRoleTag","InviteBell","InviteNotification","PaymentModal","NuxtWelcome","NuxtLayout","NuxtErrorBoundary","ClientOnly","DevOnly","ServerPlaceholder","NuxtLink","NuxtLoadingIndicator","NuxtTime","NuxtRouteAnnouncer","NuxtImg","NuxtPicture","ContentRenderer","NuxtLinkLocale","SwitchLocalePathLink","NuxtPage","NoScript","Link","Base","Title","Meta","Style","Head","Html","Body","MDC","MDCCached","MDCRenderer","MDCSlot","NuxtIsland"] \ No newline at end of file diff --git a/.nuxt/content/database.compressed.mjs b/.nuxt/content/database.compressed.mjs new file mode 100644 index 0000000..a78fbdc --- /dev/null +++ b/.nuxt/content/database.compressed.mjs @@ -0,0 +1 @@ +export const docs = "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" \ No newline at end of file diff --git a/.nuxt/content/manifest.ts b/.nuxt/content/manifest.ts new file mode 100644 index 0000000..6a5ed22 --- /dev/null +++ b/.nuxt/content/manifest.ts @@ -0,0 +1,33 @@ +export const checksums = { + "docs": "v3.5.0--jyttfyMCdlkkD2Cy6uAigSOupLz7w9JK12BEQDx-Jb8" +} +export const checksumsStructure = { + "docs": "quFkNIUZZFAwcn0ok74-KsIERem9u0p5DW-cqEgxrPA" +} + +export const tables = { + "docs": "_content_docs", + "info": "_content_info" +} + +export default { + "docs": { + "type": "page", + "fields": { + "id": "string", + "title": "string", + "body": "json", + "description": "string", + "extension": "string", + "meta": "json", + "navigation": "json", + "path": "string", + "seo": "json", + "stem": "string" + } + }, + "info": { + "type": "data", + "fields": {} + } +} \ No newline at end of file diff --git a/.nuxt/content/sql_dump.txt b/.nuxt/content/sql_dump.txt new file mode 100644 index 0000000..ced1522 --- /dev/null +++ b/.nuxt/content/sql_dump.txt @@ -0,0 +1,18 @@ +CREATE TABLE IF NOT EXISTS _content_info (id TEXT PRIMARY KEY, "ready" BOOLEAN, "structureVersion" VARCHAR, "version" VARCHAR, "__hash__" TEXT UNIQUE); -- structure +INSERT INTO _content_info VALUES ('checksum_docs', false, 'quFkNIUZZFAwcn0ok74-KsIERem9u0p5DW-cqEgxrPA', 'v3.5.0--jyttfyMCdlkkD2Cy6uAigSOupLz7w9JK12BEQDx-Jb8', '0Z0mnYn3eH5Uu-q6HoFazESkAO3KD7UVALLwkXG_HCo'); -- meta +DROP TABLE IF EXISTS _content_docs; -- structure +CREATE TABLE IF NOT EXISTS _content_docs (id TEXT PRIMARY KEY, "title" VARCHAR, "body" TEXT, "description" VARCHAR, "extension" VARCHAR, "meta" TEXT, "navigation" TEXT DEFAULT true, "path" VARCHAR, "seo" TEXT DEFAULT '{}', "stem" VARCHAR, "__hash__" TEXT UNIQUE); -- structure +INSERT INTO _content_docs VALUES ('docs/docs/ai/agent.md', 'AI 智能体接入', '{"type":"minimark","value":[["h1",{"id":"ai-智能体接入"},"AI 智能体接入"],["blockquote",{},["p",{},"集成 AI Agent,实现知识库问答、工作流触发与多模型切换。"]],["h2",{"id":"什么是-ai-智能体"},"🧠 什么是 AI 智能体?"],["p",{},"AI 智能体(AI Agent)是 Websopy 平台的核心能力,它能:"],["ul",{},["li",{},"🤖 基于自然语言理解用户意图"],["li",{},"📚 连接你的知识库进行精准问答"],["li",{},"🔗 触发业务工作流执行自动化任务"],["li",{},"🔄 在多个 AI 模型间智能切换"]],["h2",{"id":"前提条件"},"📋 前提条件"],["ul",{},["li",{},"已完成 ",["a",{"href":"/developer/docs/getting-started/quickstart"},"快速上手"]],["li",{},"已开通 AI 功能(控制台 → 开发者中心 → AI 功能)"]],["h2",{"id":"接入步骤"},"🚀 接入步骤"],["h3",{"id":"第一步安装-ai-sdk"},"第一步:安装 AI SDK"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"npm install @websopy/ai-sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"npm"],["span",{"class":"sZZnC"}," install"],["span",{"class":"sZZnC"}," @websopy/ai-sdk\n"]]]],["h3",{"id":"第二步初始化-agent"},"第二步:初始化 Agent"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { AIAgent } from ''@websopy/ai-sdk''\n\nconst agent = new AIAgent({\n apiKey: process.env.WEBSOPY_API_KEY,\n defaultModel: ''gpt-4'',\n models: [''gpt-4'', ''claude-3'', ''gemini-pro'']\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { AIAgent } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/ai-sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," agent"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," AIAgent"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," defaultModel: "],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," models: ["],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''claude-3''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''gemini-pro''"],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"第三步创建会话"},"第三步:创建会话"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const session = await agent.createSession({\n userId: ''user-123'',\n knowledgeBaseId: ''kb-abc456'',\n metadata: {\n source: ''website'',\n language: ''zh-CN''\n }\n})\n\nconsole.log(''会话 ID:'', session.id)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," session"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"createSession"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," userId: "],["span",{"class":"sZZnC"},"''user-123''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," knowledgeBaseId: "],["span",{"class":"sZZnC"},"''kb-abc456''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," metadata: {\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," source: "],["span",{"class":"sZZnC"},"''website''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," language: "],["span",{"class":"sZZnC"},"''zh-CN''\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''会话 ID:''"],["span",{"class":"sVt8B"},", session.id)\n"]]]],["h3",{"id":"第四步发送消息"},"第四步:发送消息"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const response = await agent.sendMessage(session.id, {\n content: ''我想了解你们的产品价格'',\n context: {\n userPlan: ''free'',\n priority: ''normal''\n }\n})\n\nconsole.log(''AI 回复:'', response.content)\nconsole.log(''使用模型:'', response.model)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"sendMessage"],["span",{"class":"sVt8B"},"(session.id, {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," content: "],["span",{"class":"sZZnC"},"''我想了解你们的产品价格''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," context: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," userPlan: "],["span",{"class":"sZZnC"},"''free''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," priority: "],["span",{"class":"sZZnC"},"''normal''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":8},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''AI 回复:''"],["span",{"class":"sVt8B"},", response.content)\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''使用模型:''"],["span",{"class":"sVt8B"},", response.model)\n"]]]],["h3",{"id":"第五步流式响应sse"},"第五步:流式响应(SSE)"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const stream = await agent.sendMessageStream(session.id, {\n content: ''写一篇关于 AI 的博客文章''\n})\n\nfor await (const chunk of stream) {\n process.stdout.write(chunk.content)\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"sendMessageStream"],["span",{"class":"sVt8B"},"(session.id, {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," content: "],["span",{"class":"sZZnC"},"''写一篇关于 AI 的博客文章''\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"},"for"],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," chunk"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," stream) {\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," process.stdout."],["span",{"class":"sScJk"},"write"],["span",{"class":"sVt8B"},"(chunk.content)\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"知识库集成"},"📚 知识库集成"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const kb = await agent.createKnowledgeBase({\n name: ''产品文档'',\n description: ''公司产品相关文档'',\n embeddingModel: ''text-embedding-3-small''\n})\n\nawait agent.uploadDocument(kb.id, {\n file: ''./docs/product-guide.pdf'',\n metadata: {\n category: ''documentation'',\n version: ''2.0''\n }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," kb"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"createKnowledgeBase"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," name: "],["span",{"class":"sZZnC"},"''产品文档''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," description: "],["span",{"class":"sZZnC"},"''公司产品相关文档''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," embeddingModel: "],["span",{"class":"sZZnC"},"''text-embedding-3-small''\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"uploadDocument"],["span",{"class":"sVt8B"},"(kb.id, {\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," file: "],["span",{"class":"sZZnC"},"''./docs/product-guide.pdf''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," metadata: {\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," category: "],["span",{"class":"sZZnC"},"''documentation''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"}," version: "],["span",{"class":"sZZnC"},"''2.0''\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"多模型切换"},"🔄 多模型切换"],["h3",{"id":"自动路由"},"自动路由"],["p",{},"根据任务类型自动选择最优模型:"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const agent = new AIAgent({\n apiKey: process.env.WEBSOPY_API_KEY,\n autoRoute: {\n enabled: true,\n rules: [\n { task: ''coding'', models: [''gpt-4'', ''claude-3''] },\n { task: ''creative'', models: [''gpt-4'', ''gemini-pro''] },\n { task: ''analysis'', models: [''claude-3'', ''gpt-4''] }\n ]\n }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," agent"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," AIAgent"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," autoRoute: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," enabled: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," rules: [\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," { task: "],["span",{"class":"sZZnC"},"''coding''"],["span",{"class":"sVt8B"},", models: ["],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''claude-3''"],["span",{"class":"sVt8B"},"] },\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," { task: "],["span",{"class":"sZZnC"},"''creative''"],["span",{"class":"sVt8B"},", models: ["],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''gemini-pro''"],["span",{"class":"sVt8B"},"] },\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," { task: "],["span",{"class":"sZZnC"},"''analysis''"],["span",{"class":"sVt8B"},", models: ["],["span",{"class":"sZZnC"},"''claude-3''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''gpt-4''"],["span",{"class":"sVt8B"},"] }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," ]\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"完整示例"},"🧪 完整示例"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { AIAgent } from ''@websopy/ai-sdk''\n\nasync function main() {\n const agent = new AIAgent({\n apiKey: process.env.WEBSOPY_API_KEY,\n defaultModel: ''gpt-4''\n })\n\n const session = await agent.createSession({\n userId: ''user-123'',\n knowledgeBaseId: ''kb-product-docs''\n })\n\n const messages = [\n ''你好,我想了解一下企业版的功能'',\n ''支持私有化部署吗?'',\n ''好的,我想试用一下''\n ]\n\n for (const msg of messages) {\n const response = await agent.sendMessage(session.id, { content: msg })\n console.log(`\\n👤 用户: ${msg}`)\n console.log(`🤖 AI: ${response.content}`)\n }\n}\n\nmain()\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { AIAgent } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/ai-sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," main"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," agent"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," AIAgent"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," defaultModel: "],["span",{"class":"sZZnC"},"''gpt-4''\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":8},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":9},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," session"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"createSession"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," userId: "],["span",{"class":"sZZnC"},"''user-123''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"}," knowledgeBaseId: "],["span",{"class":"sZZnC"},"''kb-product-docs''\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," messages"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," [\n"]],["span",{"class":"line","line":15},["span",{"class":"sZZnC"}," ''你好,我想了解一下企业版的功能''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":16},["span",{"class":"sZZnC"}," ''支持私有化部署吗?''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":17},["span",{"class":"sZZnC"}," ''好的,我想试用一下''\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"}," ]\n"]],["span",{"class":"line","line":19},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":20},["span",{"class":"szBVR"}," for"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," msg"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," messages) {\n"]],["span",{"class":"line","line":21},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," agent."],["span",{"class":"sScJk"},"sendMessage"],["span",{"class":"sVt8B"},"(session.id, { content: msg })\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"`"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"👤 用户: ${"],["span",{"class":"sVt8B"},"msg"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":23},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"`🤖 AI: ${"],["span",{"class":"sVt8B"},"response"],["span",{"class":"sZZnC"},"."],["span",{"class":"sVt8B"},"content"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":24},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":25},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":26},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":27},["span",{"class":"sScJk"},"main"],["span",{"class":"sVt8B"},"()\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-支持哪些-embedding-模型"},"Q: 支持哪些 Embedding 模型?"],["p",{},"目前支持:"],["ul",{},["li",{},["code",{},"text-embedding-3-small"],"(推荐,速度快)"],["li",{},["code",{},"text-embedding-3-large"],"(高精度)"],["li",{},["code",{},"text-embedding-ada-002"],"(兼容性)"]],["h3",{"id":"q-知识库检索不到相关内容"},"Q: 知识库检索不到相关内容?"],["ol",{},["li",{},"检查文档是否已成功上传和向量化"],["li",{},"调整 ",["code",{},"scoreThreshold"]," 降低阈值"],["li",{},"尝试增加 ",["code",{},"topK"]," 获取更多候选"]],["style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-ai-智能体","depth":2,"text":"🧠 什么是 AI 智能体?"},{"id":"前提条件","depth":2,"text":"📋 前提条件"},{"id":"接入步骤","depth":2,"text":"🚀 接入步骤","children":[{"id":"第一步安装-ai-sdk","depth":3,"text":"第一步:安装 AI SDK"},{"id":"第二步初始化-agent","depth":3,"text":"第二步:初始化 Agent"},{"id":"第三步创建会话","depth":3,"text":"第三步:创建会话"},{"id":"第四步发送消息","depth":3,"text":"第四步:发送消息"},{"id":"第五步流式响应sse","depth":3,"text":"第五步:流式响应(SSE)"}]},{"id":"知识库集成","depth":2,"text":"📚 知识库集成"},{"id":"多模型切换","depth":2,"text":"🔄 多模型切换","children":[{"id":"自动路由","depth":3,"text":"自动路由"}]},{"id":"完整示例","depth":2,"text":"🧪 完整示例"},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-支持哪些-embedding-模型","depth":3,"text":"Q: 支持哪些 Embedding 模型?"},{"id":"q-知识库检索不到相关内容","depth":3,"text":"Q: 知识库检索不到相关内容?"}]}]}}', '集成 AI Agent,实现知识库问答、工作流触发与多模型切换。', 'md', '{"category":"ai","order":1}', 'true', '/docs/ai/agent', '{"title":"AI 智能体接入","description":"集成 AI Agent,实现知识库问答、工作流触发与多模型切换。"}', 'docs/ai/agent', 'aYeCTE7aiIr5B_LqjvVhtpMOyh9-xfwEvuxpdb32bRQ'); -- aYeCTE7aiIr5B_LqjvVhtpMOyh9-xfwEvuxpdb32bRQ +INSERT INTO _content_docs VALUES ('docs/docs/ai/rag.md', 'RAG 知识库搭建', '{"type":"minimark","value":[["h1",{"id":"rag-知识库搭建"},"RAG 知识库搭建"],["blockquote",{},["p",{},"上传文档、向量化存储,构建企业级知识库问答系统。"]],["h2",{"id":"什么是-rag"},"🧠 什么是 RAG?"],["p",{},"RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合「知识检索」和「AI 生成」的技术:"],["ol",{},["li",{},["strong",{},"检索"],":从知识库中找到相关内容"],["li",{},["strong",{},"增强"],":将检索结果作为上下文"],["li",{},["strong",{},"生成"],":让 AI 基于上下文生成答案"]],["pre",{"className":["language-text"],"code":"用户问题 → 检索相关文档 → 拼接到 Prompt → AI 生成回答\n","language":"text"},["code",{"__ignoreMap":""},"用户问题 → 检索相关文档 → 拼接到 Prompt → AI 生成回答\n"]],["h2",{"id":"适用场景"},"📋 适用场景"],["ul",{},["li",{},"📄 企业内部文档问答"],["li",{},"🎯 产品 FAQ 自动化"],["li",{},"📚 培训资料检索"],["li",{},"🔍 合同/政策查询"],["li",{},"🏥 专业知识库"]],["h2",{"id":"搭建步骤"},"🚀 搭建步骤"],["h3",{"id":"第一步创建知识库"},"第一步:创建知识库"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const knowledgeBase = await client.ai.createKnowledgeBase({\n name: ''产品使用手册'',\n description: ''公司产品相关文档'',\n embeddingModel: ''text-embedding-3-small'',\n chunking: {\n type: ''recursive'',\n chunkSize: 1000,\n chunkOverlap: 200\n }\n})\n\nconsole.log(''知识库 ID:'', knowledgeBase.id)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," knowledgeBase"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"createKnowledgeBase"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," name: "],["span",{"class":"sZZnC"},"''产品使用手册''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," description: "],["span",{"class":"sZZnC"},"''公司产品相关文档''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," embeddingModel: "],["span",{"class":"sZZnC"},"''text-embedding-3-small''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," chunking: {\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," type: "],["span",{"class":"sZZnC"},"''recursive''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," chunkSize: "],["span",{"class":"sj4cs"},"1000"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," chunkOverlap: "],["span",{"class":"sj4cs"},"200\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":11},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''知识库 ID:''"],["span",{"class":"sVt8B"},", knowledgeBase.id)\n"]]]],["h3",{"id":"第二步上传文档"},"第二步:上传文档"],["p",{},"支持格式:PDF、Word、TXT、Markdown、HTML"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 上传单个文件\nconst doc = await client.ai.uploadDocument(knowledgeBase.id, {\n file: ''./docs/user-guide.pdf'',\n metadata: {\n category: ''manual'',\n version: ''2.0'',\n language: ''zh-CN''\n }\n})\n\n// 批量上传\nconst docs = await client.ai.uploadDocuments(knowledgeBase.id, [\n { file: ''./docs/faq.md'', metadata: { category: ''faq'' } },\n { file: ''./docs/api.md'', metadata: { category: ''api'' } },\n])\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 上传单个文件\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," doc"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"uploadDocument"],["span",{"class":"sVt8B"},"(knowledgeBase.id, {\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," file: "],["span",{"class":"sZZnC"},"''./docs/user-guide.pdf''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," metadata: {\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," category: "],["span",{"class":"sZZnC"},"''manual''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," version: "],["span",{"class":"sZZnC"},"''2.0''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," language: "],["span",{"class":"sZZnC"},"''zh-CN''\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"},"// 批量上传\n"]],["span",{"class":"line","line":12},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," docs"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"uploadDocuments"],["span",{"class":"sVt8B"},"(knowledgeBase.id, [\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"}," { file: "],["span",{"class":"sZZnC"},"''./docs/faq.md''"],["span",{"class":"sVt8B"},", metadata: { category: "],["span",{"class":"sZZnC"},"''faq''"],["span",{"class":"sVt8B"}," } },\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"}," { file: "],["span",{"class":"sZZnC"},"''./docs/api.md''"],["span",{"class":"sVt8B"},", metadata: { category: "],["span",{"class":"sZZnC"},"''api''"],["span",{"class":"sVt8B"}," } },\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"])\n"]]]],["h3",{"id":"第三步配置检索"},"第三步:配置检索"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"await client.ai.configureRetrieval(knowledgeBase.id, {\n retrieval: {\n topK: 5,\n scoreThreshold: 0.7,\n hybridSearch: true\n },\n rerank: {\n enabled: true,\n model: ''bge-reranker''\n }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"configureRetrieval"],["span",{"class":"sVt8B"},"(knowledgeBase.id, {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," retrieval: {\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," topK: "],["span",{"class":"sj4cs"},"5"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," scoreThreshold: "],["span",{"class":"sj4cs"},"0.7"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," hybridSearch: "],["span",{"class":"sj4cs"},"true\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," },\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," rerank: {\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," enabled: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," model: "],["span",{"class":"sZZnC"},"''bge-reranker''\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"第四步问答"},"第四步:问答"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const response = await client.ai.ask({\n knowledgeBaseId: knowledgeBase.id,\n question: ''如何创建新项目?'',\n options: {\n maxTokens: 1000,\n temperature: 0.7,\n includeSources: true\n }\n})\n\nconsole.log(''回答:'', response.answer)\nconsole.log(''引用:'', response.citations)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"ask"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," knowledgeBaseId: knowledgeBase.id,\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," question: "],["span",{"class":"sZZnC"},"''如何创建新项目?''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," options: {\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," maxTokens: "],["span",{"class":"sj4cs"},"1000"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," temperature: "],["span",{"class":"sj4cs"},"0.7"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," includeSources: "],["span",{"class":"sj4cs"},"true\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''回答:''"],["span",{"class":"sVt8B"},", response.answer)\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''引用:''"],["span",{"class":"sVt8B"},", response.citations)\n"]]]],["h3",{"id":"响应示例"},"响应示例"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n \"answer\": \"创建新项目的步骤如下:\\n1. 点击「新建项目」按钮\\n2. 填写项目名称和描述\\n3. 选择项目模板\\n4. 点击「创建」完成\",\n \"citations\": [\n {\n \"document_id\": \"doc_abc123\",\n \"chunk_text\": \"点击「新建项目」按钮,进入项目创建页面...\",\n \"score\": 0.95\n }\n ],\n \"model\": \"gpt-4\",\n \"tokens_used\": 850\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"}," \"answer\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"创建新项目的步骤如下:"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"1. 点击「新建项目」按钮"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"2. 填写项目名称和描述"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"3. 选择项目模板"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"4. 点击「创建」完成\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"}," \"citations\""],["span",{"class":"sVt8B"},": [\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"}," \"document_id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"doc_abc123\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sj4cs"}," \"chunk_text\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"点击「新建项目」按钮,进入项目创建页面...\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sj4cs"}," \"score\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"0.95\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," ],\n"]],["span",{"class":"line","line":10},["span",{"class":"sj4cs"}," \"model\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"gpt-4\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sj4cs"}," \"tokens_used\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"850\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"最佳实践"},"🧪 最佳实践"],["h3",{"id":"文档准备"},"文档准备"],["ol",{},["li",{},"✅ 清理格式,移除无关内容"],["li",{},"✅ 添加目录和标题结构"],["li",{},"✅ QA 格式文档效果最好"],["li",{},"❌ 避免过长的无结构文本"],["li",{},"❌ 避免大量表格(难以正确分块)"]],["h3",{"id":"检索优化"},"检索优化"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const optimalConfig = {\n topK: 3, // 不要太多,可能引入噪音\n scoreThreshold: 0.75, // 设置合理阈值\n enableRerank: true // 启用重排序\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," optimalConfig"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," topK: "],["span",{"class":"sj4cs"},"3"],["span",{"class":"sVt8B"},", "],["span",{"class":"sJ8bj"},"// 不要太多,可能引入噪音\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," scoreThreshold: "],["span",{"class":"sj4cs"},"0.75"],["span",{"class":"sVt8B"},", "],["span",{"class":"sJ8bj"},"// 设置合理阈值\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," enableRerank: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sJ8bj"}," // 启用重排序\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"prompt-工程"},"Prompt 工程"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const response = await client.ai.ask({\n knowledgeBaseId: knowledgeBase.id,\n question: ''...'',\n systemPrompt: `你是一个专业客服,请基于给定的知识库内容回答用户问题。\n - 如果知识库中没有相关内容,请如实告知\n - 回答要简洁、专业、易懂\n - 适当引用原文帮助用户理解`\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"ask"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," knowledgeBaseId: knowledgeBase.id,\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," question: "],["span",{"class":"sZZnC"},"''...''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," systemPrompt: "],["span",{"class":"sZZnC"},"`你是一个专业客服,请基于给定的知识库内容回答用户问题。\n"]],["span",{"class":"line","line":5},["span",{"class":"sZZnC"}," - 如果知识库中没有相关内容,请如实告知\n"]],["span",{"class":"line","line":6},["span",{"class":"sZZnC"}," - 回答要简洁、专业、易懂\n"]],["span",{"class":"line","line":7},["span",{"class":"sZZnC"}," - 适当引用原文帮助用户理解`\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-检索不到相关内容"},"Q: 检索不到相关内容?"],["ol",{},["li",{},"检查文档是否处理完成(状态为 ",["code",{},"ready"],")"],["li",{},"降低 ",["code",{},"scoreThreshold"]," 阈值"],["li",{},"尝试 ",["code",{},"hybridSearch: true"]," 混合搜索"],["li",{},"增加 ",["code",{},"topK"]," 获取更多候选"]],["h3",{"id":"q-回答不准确"},"Q: 回答不准确?"],["ol",{},["li",{},"检查源文档质量"],["li",{},"调整 ",["code",{},"chunkSize"],",太小可能丢失上下文"],["li",{},"启用 ",["code",{},"rerank"]," 提高相关性"],["li",{},"优化 system prompt"]],["style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-rag","depth":2,"text":"🧠 什么是 RAG?"},{"id":"适用场景","depth":2,"text":"📋 适用场景"},{"id":"搭建步骤","depth":2,"text":"🚀 搭建步骤","children":[{"id":"第一步创建知识库","depth":3,"text":"第一步:创建知识库"},{"id":"第二步上传文档","depth":3,"text":"第二步:上传文档"},{"id":"第三步配置检索","depth":3,"text":"第三步:配置检索"},{"id":"第四步问答","depth":3,"text":"第四步:问答"},{"id":"响应示例","depth":3,"text":"响应示例"}]},{"id":"最佳实践","depth":2,"text":"🧪 最佳实践","children":[{"id":"文档准备","depth":3,"text":"文档准备"},{"id":"检索优化","depth":3,"text":"检索优化"},{"id":"prompt-工程","depth":3,"text":"Prompt 工程"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-检索不到相关内容","depth":3,"text":"Q: 检索不到相关内容?"},{"id":"q-回答不准确","depth":3,"text":"Q: 回答不准确?"}]}]}}', '上传文档、向量化存储,构建企业级知识库问答系统。', 'md', '{"category":"ai","order":2}', 'true', '/docs/ai/rag', '{"title":"RAG 知识库搭建","description":"上传文档、向量化存储,构建企业级知识库问答系统。"}', 'docs/ai/rag', 'DcpoLfXPgq7FWv-OLVP6_igv1nI_7FiOGJvjbOBeCDw'); -- DcpoLfXPgq7FWv-OLVP6_igv1nI_7FiOGJvjbOBeCDw +INSERT INTO _content_docs VALUES ('docs/docs/ai/workflow.md', 'AI 工作流配置', '{"type":"minimark","value":[["h1",{"id":"ai-工作流配置"},"AI 工作流配置"],["blockquote",{},["p",{},"使用工作流引擎,构建定时任务与自动化业务流。"]],["h2",{"id":"什么是工作流"},"🔄 什么是工作流?"],["p",{},"工作流(Workflow)是预定义的一系列自动化步骤,可以:"],["ul",{},["li",{},"⏰ ",["strong",{},"定时执行"],":每天早上发送报表"],["li",{},"🔗 ",["strong",{},"事件触发"],":用户注册后自动发送欢迎邮件"],["li",{},"🔁 ",["strong",{},"条件分支"],":根据条件执行不同操作"],["li",{},"📊 ",["strong",{},"数据处理"],":批量处理数据"]],["h2",{"id":"️-核心概念"},"🏗️ 核心概念"],["table",{},["thead",{},["tr",{},["th",{},"概念"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},["strong",{},"触发器 (Trigger)"]],["td",{},"工作流的启动条件"]],["tr",{},["td",{},["strong",{},"节点 (Node)"]],["td",{},"工作流中的单个步骤"]],["tr",{},["td",{},["strong",{},"连接 (Edge)"]],["td",{},"节点之间的数据流向"]],["tr",{},["td",{},["strong",{},"变量 (Variable)"]],["td",{},"存储和传递数据"]],["tr",{},["td",{},["strong",{},"执行日志"]],["td",{},"每次运行的记录"]]]],["h2",{"id":"创建第一个工作流"},"🚀 创建第一个工作流"],["h3",{"id":"代码定义"},"代码定义"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WorkflowBuilder } from ''@websopy/ai-sdk''\n\nconst workflow = new WorkflowBuilder({\n name: ''每日数据报告'',\n description: ''每天早上 9 点生成数据报告''\n})\n\n// 添加触发器:定时执行\nworkflow.addTrigger({\n type: ''schedule'',\n config: {\n cron: ''0 9 * * *'', // 每天 9:00\n timezone: ''Asia/Shanghai''\n }\n})\n\n// 添加节点:获取数据\nworkflow.addNode(''fetch-data'', {\n type: ''http-request'',\n config: {\n url: ''https://api.analytics.com/daily-stats'',\n method: ''GET''\n }\n})\n\n// 添加节点:生成报告\nworkflow.addNode(''generate-report'', {\n type: ''ai-agent'',\n config: {\n prompt: ''根据以下数据生成日报:{{fetch-data.output}}''\n }\n})\n\n// 添加节点:发送邮件\nworkflow.addNode(''send-email'', {\n type: ''email'',\n config: {\n to: [''team@company.com''],\n subject: ''📊 每日数据报告'',\n body: ''{{generate-report.output}}''\n }\n})\n\n// 节点连接\nworkflow.connect(''fetch-data'', ''generate-report'')\nworkflow.connect(''generate-report'', ''send-email'')\n\n// 保存\nconst created = await client.workflow.create(workflow.toJSON())\nconsole.log(''工作流 ID:'', created.id)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WorkflowBuilder } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/ai-sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," workflow"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WorkflowBuilder"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," name: "],["span",{"class":"sZZnC"},"''每日数据报告''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," description: "],["span",{"class":"sZZnC"},"''每天早上 9 点生成数据报告''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"// 添加触发器:定时执行\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addTrigger"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," type: "],["span",{"class":"sZZnC"},"''schedule''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"}," config: {\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"}," cron: "],["span",{"class":"sZZnC"},"''0 9 * * *''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sJ8bj"},"// 每天 9:00\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"}," timezone: "],["span",{"class":"sZZnC"},"''Asia/Shanghai''\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":16},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":17},["span",{"class":"sJ8bj"},"// 添加节点:获取数据\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addNode"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''fetch-data''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":19},["span",{"class":"sVt8B"}," type: "],["span",{"class":"sZZnC"},"''http-request''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"}," config: {\n"]],["span",{"class":"line","line":21},["span",{"class":"sVt8B"}," url: "],["span",{"class":"sZZnC"},"''https://api.analytics.com/daily-stats''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"}," method: "],["span",{"class":"sZZnC"},"''GET''\n"]],["span",{"class":"line","line":23},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":24},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":25},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":26},["span",{"class":"sJ8bj"},"// 添加节点:生成报告\n"]],["span",{"class":"line","line":27},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addNode"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''generate-report''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":28},["span",{"class":"sVt8B"}," type: "],["span",{"class":"sZZnC"},"''ai-agent''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":29},["span",{"class":"sVt8B"}," config: {\n"]],["span",{"class":"line","line":30},["span",{"class":"sVt8B"}," prompt: "],["span",{"class":"sZZnC"},"''根据以下数据生成日报:{{fetch-data.output}}''\n"]],["span",{"class":"line","line":31},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":32},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":33},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":34},["span",{"class":"sJ8bj"},"// 添加节点:发送邮件\n"]],["span",{"class":"line","line":35},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addNode"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''send-email''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":36},["span",{"class":"sVt8B"}," type: "],["span",{"class":"sZZnC"},"''email''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":37},["span",{"class":"sVt8B"}," config: {\n"]],["span",{"class":"line","line":38},["span",{"class":"sVt8B"}," to: ["],["span",{"class":"sZZnC"},"''team@company.com''"],["span",{"class":"sVt8B"},"],\n"]],["span",{"class":"line","line":39},["span",{"class":"sVt8B"}," subject: "],["span",{"class":"sZZnC"},"''📊 每日数据报告''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":40},["span",{"class":"sVt8B"}," body: "],["span",{"class":"sZZnC"},"''{{generate-report.output}}''\n"]],["span",{"class":"line","line":41},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":42},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":43},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":44},["span",{"class":"sJ8bj"},"// 节点连接\n"]],["span",{"class":"line","line":45},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"connect"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''fetch-data''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''generate-report''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":46},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"connect"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''generate-report''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''send-email''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":47},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":48},["span",{"class":"sJ8bj"},"// 保存\n"]],["span",{"class":"line","line":49},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," created"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.workflow."],["span",{"class":"sScJk"},"create"],["span",{"class":"sVt8B"},"(workflow."],["span",{"class":"sScJk"},"toJSON"],["span",{"class":"sVt8B"},"())\n"]],["span",{"class":"line","line":50},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''工作流 ID:''"],["span",{"class":"sVt8B"},", created.id)\n"]]]],["h3",{"id":"可视化编辑器"},"可视化编辑器"],["p",{},"在控制台 → AI 功能 → 工作流,点击「新建工作流」打开可视化编辑器。"],["h2",{"id":"节点类型"},"📦 节点类型"],["table",{},["thead",{},["tr",{},["th",{},"节点类型"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},["code",{},"http-request"]],["td",{},"HTTP 请求"]],["tr",{},["td",{},["code",{},"ai-agent"]],["td",{},"AI 智能体"]],["tr",{},["td",{},["code",{},"condition"]],["td",{},"条件分支"]],["tr",{},["td",{},["code",{},"loop"]],["td",{},"循环"]],["tr",{},["td",{},["code",{},"delay"]],["td",{},"等待/延迟"]],["tr",{},["td",{},["code",{},"webhook"]],["td",{},"Webhook 通知"]],["tr",{},["td",{},["code",{},"transform"]],["td",{},"数据转换"]],["tr",{},["td",{},["code",{},"email"]],["td",{},"发送邮件"]]]],["h2",{"id":"触发器类型"},"🔔 触发器类型"],["h3",{"id":"定时触发"},"定时触发"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"workflow.addTrigger({\n type: ''schedule'',\n config: {\n cron: ''0 */4 * * *'', // 每 4 小时\n interval: ''daily'', // daily, weekly, monthly\n time: ''09:00''\n }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addTrigger"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," type: "],["span",{"class":"sZZnC"},"''schedule''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," config: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," cron: "],["span",{"class":"sZZnC"},"''0 */4 * * *''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sJ8bj"},"// 每 4 小时\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," interval: "],["span",{"class":"sZZnC"},"''daily''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sJ8bj"},"// daily, weekly, monthly\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," time: "],["span",{"class":"sZZnC"},"''09:00''\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"webhook-触发"},"Webhook 触发"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"workflow.addTrigger({\n type: ''webhook'',\n config: {\n // 创建后获得 webhook URL\n }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addTrigger"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," type: "],["span",{"class":"sZZnC"},"''webhook''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," config: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"}," // 创建后获得 webhook URL\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"事件触发"},"事件触发"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"workflow.addTrigger({\n type: ''event'',\n config: {\n events: [\n ''user.created'',\n ''order.completed'',\n ''ai.task.failed''\n ]\n }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addTrigger"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," type: "],["span",{"class":"sZZnC"},"''event''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," config: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," events: [\n"]],["span",{"class":"line","line":5},["span",{"class":"sZZnC"}," ''user.created''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sZZnC"}," ''order.completed''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sZZnC"}," ''ai.task.failed''\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," ]\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"执行与监控"},"📊 执行与监控"],["h3",{"id":"手动执行"},"手动执行"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const run = await client.workflow.run(workflowId, {\n input: { date: ''2024-01-15'' }\n})\n\nconsole.log(''执行 ID:'', run.id)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," run"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.workflow."],["span",{"class":"sScJk"},"run"],["span",{"class":"sVt8B"},"(workflowId, {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," input: { date: "],["span",{"class":"sZZnC"},"''2024-01-15''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''执行 ID:''"],["span",{"class":"sVt8B"},", run.id)\n"]]]],["h3",{"id":"查看执行日志"},"查看执行日志"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const logs = await client.workflow.getRunLogs(run.id)\n\nfor (const log of logs) {\n console.log(`[${log.timestamp}] ${log.node}: ${log.status}`)\n if (log.error) {\n console.log('' 错误:'', log.error)\n }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," logs"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.workflow."],["span",{"class":"sScJk"},"getRunLogs"],["span",{"class":"sVt8B"},"(run.id)\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"for"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," log"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," logs) {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"`[${"],["span",{"class":"sVt8B"},"log"],["span",{"class":"sZZnC"},"."],["span",{"class":"sVt8B"},"timestamp"],["span",{"class":"sZZnC"},"}] ${"],["span",{"class":"sVt8B"},"log"],["span",{"class":"sZZnC"},"."],["span",{"class":"sVt8B"},"node"],["span",{"class":"sZZnC"},"}: ${"],["span",{"class":"sVt8B"},"log"],["span",{"class":"sZZnC"},"."],["span",{"class":"sVt8B"},"status"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"}," if"],["span",{"class":"sVt8B"}," (log.error) {\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"'' 错误:''"],["span",{"class":"sVt8B"},", log.error)\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-工作流执行失败怎么办"},"Q: 工作流执行失败怎么办?"],["ol",{},["li",{},"查看执行日志定位问题节点"],["li",{},"检查输入数据格式"],["li",{},"查看节点配置是否正确"],["li",{},"联系支持时提供执行 ID"]],["h3",{"id":"q-可以嵌套工作流吗"},"Q: 可以嵌套工作流吗?"],["p",{},"是的,可以在一个工作流中调用另一个工作流:"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"workflow.addNode(''sub-workflow'', {\n type: ''workflow'',\n config: {\n workflowId: ''wf-xxx'',\n input: ''{{current-data}}''\n }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"workflow."],["span",{"class":"sScJk"},"addNode"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''sub-workflow''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," type: "],["span",{"class":"sZZnC"},"''workflow''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," config: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," workflowId: "],["span",{"class":"sZZnC"},"''wf-xxx''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," input: "],["span",{"class":"sZZnC"},"''{{current-data}}''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是工作流","depth":2,"text":"🔄 什么是工作流?"},{"id":"️-核心概念","depth":2,"text":"🏗️ 核心概念"},{"id":"创建第一个工作流","depth":2,"text":"🚀 创建第一个工作流","children":[{"id":"代码定义","depth":3,"text":"代码定义"},{"id":"可视化编辑器","depth":3,"text":"可视化编辑器"}]},{"id":"节点类型","depth":2,"text":"📦 节点类型"},{"id":"触发器类型","depth":2,"text":"🔔 触发器类型","children":[{"id":"定时触发","depth":3,"text":"定时触发"},{"id":"webhook-触发","depth":3,"text":"Webhook 触发"},{"id":"事件触发","depth":3,"text":"事件触发"}]},{"id":"执行与监控","depth":2,"text":"📊 执行与监控","children":[{"id":"手动执行","depth":3,"text":"手动执行"},{"id":"查看执行日志","depth":3,"text":"查看执行日志"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-工作流执行失败怎么办","depth":3,"text":"Q: 工作流执行失败怎么办?"},{"id":"q-可以嵌套工作流吗","depth":3,"text":"Q: 可以嵌套工作流吗?"}]}]}}', '使用工作流引擎,构建定时任务与自动化业务流。', 'md', '{"category":"ai","order":3}', 'true', '/docs/ai/workflow', '{"title":"AI 工作流配置","description":"使用工作流引擎,构建定时任务与自动化业务流。"}', 'docs/ai/workflow', 'EZRBCN9XfN1yY6NZaqT1Tp1EWDfLjaTKQOmEJtLXuwg'); -- EZRBCN9XfN1yY6NZaqT1Tp1EWDfLjaTKQOmEJtLXuwg +INSERT INTO _content_docs VALUES ('docs/docs/api/rest-api.md', 'REST API 完整参考', '{"type":"minimark","value":[["h1",{"id":"rest-api-完整参考"},"REST API 完整参考"],["blockquote",{},["p",{},"200+ 标准接口文档,覆盖用户、内容、AI、支付等全部模块。"]],["h2",{"id":"api-概览"},"📚 API 概览"],["p",{},["strong",{},"基础 URL:"]," ",["code",{},"https://api.websopy.com/v1"]],["p",{},["strong",{},"认证方式:"]," Bearer Token"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"curl -H \"Authorization: Bearer YOUR_API_KEY\" \\\n https://api.websopy.com/v1/user/profile\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"curl"],["span",{"class":"sj4cs"}," -H"],["span",{"class":"sZZnC"}," \"Authorization: Bearer YOUR_API_KEY\""],["span",{"class":"sj4cs"}," \\\n"]],["span",{"class":"line","line":2},["span",{"class":"sZZnC"}," https://api.websopy.com/v1/user/profile\n"]]]],["h2",{"id":"端点列表"},"📋 端点列表"],["h3",{"id":"用户管理-user"},"用户管理 ",["code",{},"/user"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"GET"],["td",{},["code",{},"/user/profile"]],["td",{},"获取当前用户信息"]],["tr",{},["td",{},"PUT"],["td",{},["code",{},"/user/profile"]],["td",{},"更新用户信息"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/user/settings"]],["td",{},"获取用户设置"]],["tr",{},["td",{},"PUT"],["td",{},["code",{},"/user/settings"]],["td",{},"更新用户设置"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/user/avatar"]],["td",{},"上传头像"]]]],["h3",{"id":"项目管理-projects"},"项目管理 ",["code",{},"/projects"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"GET"],["td",{},["code",{},"/projects"]],["td",{},"列出项目"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/projects"]],["td",{},"创建项目"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/projects/:id"]],["td",{},"获取项目详情"]],["tr",{},["td",{},"PUT"],["td",{},["code",{},"/projects/:id"]],["td",{},"更新项目"]],["tr",{},["td",{},"DELETE"],["td",{},["code",{},"/projects/:id"]],["td",{},"删除项目"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/projects/:id/members"]],["td",{},"获取项目成员"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/projects/:id/members"]],["td",{},"添加成员"]]]],["h3",{"id":"文件存储-storage"},"文件存储 ",["code",{},"/storage"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"GET"],["td",{},["code",{},"/storage/files"]],["td",{},"列出文件"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/storage/upload"]],["td",{},"上传文件"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/storage/files/:id"]],["td",{},"获取文件信息"]],["tr",{},["td",{},"DELETE"],["td",{},["code",{},"/storage/files/:id"]],["td",{},"删除文件"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/storage/files/:id/download"]],["td",{},"下载文件"]]]],["h3",{"id":"ai-功能-ai"},"AI 功能 ",["code",{},"/ai"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/chat"]],["td",{},"发送对话请求"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/chat/stream"]],["td",{},"流式对话"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/ai/sessions"]],["td",{},"列出会话"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/sessions"]],["td",{},"创建会话"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/ai/sessions/:id"]],["td",{},"获取会话详情"]],["tr",{},["td",{},"DELETE"],["td",{},["code",{},"/ai/sessions/:id"]],["td",{},"删除会话"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/knowledge"]],["td",{},"创建知识库"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/ai/knowledge/:id/documents"]],["td",{},"添加文档"]]]],["h3",{"id":"支付-payments"},"支付 ",["code",{},"/payments"]],["table",{},["thead",{},["tr",{},["th",{},"方法"],["th",{},"端点"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"GET"],["td",{},["code",{},"/payments/orders"]],["td",{},"列出订单"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/payments/orders"]],["td",{},"创建订单"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/payments/orders/:id"]],["td",{},"订单详情"]],["tr",{},["td",{},"POST"],["td",{},["code",{},"/payments/checkout"]],["td",{},"创建结算会话"]],["tr",{},["td",{},"GET"],["td",{},["code",{},"/payments/subscriptions"]],["td",{},"订阅列表"]]]],["h2",{"id":"请求与响应"},"🔍 请求与响应"],["h3",{"id":"请求头"},"请求头"],["pre",{"className":"language-http shiki shiki-themes github-light github-dark","code":"Authorization: Bearer YOUR_API_KEY\nContent-Type: application/json\nAccept: application/json\nX-Request-ID: unique-request-id\n","language":"http","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"Authorization: Bearer YOUR_API_KEY\n"]],["span",{"class":"line","line":2},["span",{},"Content-Type: application/json\n"]],["span",{"class":"line","line":3},["span",{},"Accept: application/json\n"]],["span",{"class":"line","line":4},["span",{},"X-Request-ID: unique-request-id\n"]]]],["h3",{"id":"分页"},"分页"],["pre",{"className":"language-http shiki shiki-themes github-light github-dark","code":"GET /projects?page=2&limit=20\n","language":"http","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"GET /projects?page=2&limit=20\n"]]]],["p",{},"响应包含分页信息:"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n \"data\": [...],\n \"pagination\": {\n \"page\": 2,\n \"limit\": 20,\n \"total\": 100,\n \"total_pages\": 5\n }\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"}," \"data\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"s7hpK"},"..."],["span",{"class":"sVt8B"},"],\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"}," \"pagination\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":4},["span",{"class":"sj4cs"}," \"page\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"2"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"}," \"limit\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"20"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sj4cs"}," \"total\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"100"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sj4cs"}," \"total_pages\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"5\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"排序"},"排序"],["pre",{"className":"language-http shiki shiki-themes github-light github-dark","code":"GET /projects?sort=created_at&order=desc\n","language":"http","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"GET /projects?sort=created_at&order=desc\n"]]]],["h3",{"id":"过滤"},"过滤"],["pre",{"className":"language-http shiki shiki-themes github-light github-dark","code":"GET /projects?status=active&category=ai\n","language":"http","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"GET /projects?status=active&category=ai\n"]]]],["h2",{"id":"错误处理"},"📝 错误处理"],["h3",{"id":"错误码"},"错误码"],["table",{},["thead",{},["tr",{},["th",{},"状态码"],["th",{},"错误码"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"400"],["td",{},["code",{},"INVALID_REQUEST"]],["td",{},"请求参数错误"]],["tr",{},["td",{},"401"],["td",{},["code",{},"UNAUTHORIZED"]],["td",{},"未认证或 Token 无效"]],["tr",{},["td",{},"403"],["td",{},["code",{},"FORBIDDEN"]],["td",{},"无权限访问"]],["tr",{},["td",{},"404"],["td",{},["code",{},"NOT_FOUND"]],["td",{},"资源不存在"]],["tr",{},["td",{},"429"],["td",{},["code",{},"RATE_LIMITED"]],["td",{},"请求过于频繁"]],["tr",{},["td",{},"500"],["td",{},["code",{},"SERVER_ERROR"]],["td",{},"服务器内部错误"]]]],["h3",{"id":"错误响应格式"},"错误响应格式"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n \"error\": {\n \"code\": \"INVALID_REQUEST\",\n \"message\": \"参数 ''name'' 不能为空\",\n \"details\": {\n \"field\": \"name\",\n \"constraint\": \"required\"\n }\n }\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"}," \"error\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"}," \"code\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"INVALID_REQUEST\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sj4cs"}," \"message\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"参数 ''name'' 不能为空\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"}," \"details\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":6},["span",{"class":"sj4cs"}," \"field\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"name\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sj4cs"}," \"constraint\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"required\"\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"使用示例"},"🔧 使用示例"],["h3",{"id":"javascripttypescript"},"JavaScript/TypeScript"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const response = await fetch(''https://api.websopy.com/v1/projects'', {\n method: ''POST'',\n headers: {\n ''Authorization'': `Bearer ${apiKey}`,\n ''Content-Type'': ''application/json''\n },\n body: JSON.stringify({\n name: ''我的项目'',\n description: ''项目描述''\n })\n})\n\nconst data = await response.json()\nconsole.log(data)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sScJk"}," fetch"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''https://api.websopy.com/v1/projects''"],["span",{"class":"sVt8B"},", {\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," method: "],["span",{"class":"sZZnC"},"''POST''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," headers: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sZZnC"}," ''Authorization''"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"`Bearer ${"],["span",{"class":"sVt8B"},"apiKey"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sZZnC"}," ''Content-Type''"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''application/json''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," },\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," body: "],["span",{"class":"sj4cs"},"JSON"],["span",{"class":"sVt8B"},"."],["span",{"class":"sScJk"},"stringify"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," name: "],["span",{"class":"sZZnC"},"''我的项目''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," description: "],["span",{"class":"sZZnC"},"''项目描述''\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":12},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":13},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," data"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," response."],["span",{"class":"sScJk"},"json"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"(data)\n"]]]],["h3",{"id":"python"},"Python"],["pre",{"className":"language-python shiki shiki-themes github-light github-dark","code":"import requests\n\nresponse = requests.post(\n ''https://api.websopy.com/v1/projects'',\n headers={\n ''Authorization'': f''Bearer {api_key}'',\n ''Content-Type'': ''application/json''\n },\n json={\n ''name'': ''我的项目'',\n ''description'': ''项目描述''\n }\n)\n\ndata = response.json()\nprint(data)\n","language":"python","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"import requests\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{},"response = requests.post(\n"]],["span",{"class":"line","line":4},["span",{}," ''https://api.websopy.com/v1/projects'',\n"]],["span",{"class":"line","line":5},["span",{}," headers={\n"]],["span",{"class":"line","line":6},["span",{}," ''Authorization'': f''Bearer {api_key}'',\n"]],["span",{"class":"line","line":7},["span",{}," ''Content-Type'': ''application/json''\n"]],["span",{"class":"line","line":8},["span",{}," },\n"]],["span",{"class":"line","line":9},["span",{}," json={\n"]],["span",{"class":"line","line":10},["span",{}," ''name'': ''我的项目'',\n"]],["span",{"class":"line","line":11},["span",{}," ''description'': ''项目描述''\n"]],["span",{"class":"line","line":12},["span",{}," }\n"]],["span",{"class":"line","line":13},["span",{},")\n"]],["span",{"class":"line","line":14},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":15},["span",{},"data = response.json()\n"]],["span",{"class":"line","line":16},["span",{},"print(data)\n"]]]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s7hpK, html code.shiki .s7hpK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"api-概览","depth":2,"text":"📚 API 概览"},{"id":"端点列表","depth":2,"text":"📋 端点列表","children":[{"id":"用户管理-user","depth":3,"text":"用户管理 /user"},{"id":"项目管理-projects","depth":3,"text":"项目管理 /projects"},{"id":"文件存储-storage","depth":3,"text":"文件存储 /storage"},{"id":"ai-功能-ai","depth":3,"text":"AI 功能 /ai"},{"id":"支付-payments","depth":3,"text":"支付 /payments"}]},{"id":"请求与响应","depth":2,"text":"🔍 请求与响应","children":[{"id":"请求头","depth":3,"text":"请求头"},{"id":"分页","depth":3,"text":"分页"},{"id":"排序","depth":3,"text":"排序"},{"id":"过滤","depth":3,"text":"过滤"}]},{"id":"错误处理","depth":2,"text":"📝 错误处理","children":[{"id":"错误码","depth":3,"text":"错误码"},{"id":"错误响应格式","depth":3,"text":"错误响应格式"}]},{"id":"使用示例","depth":2,"text":"🔧 使用示例","children":[{"id":"javascripttypescript","depth":3,"text":"JavaScript/TypeScript"},{"id":"python","depth":3,"text":"Python"}]}]}}', '200+ 标准接口文档,覆盖用户、内容、AI、支付等全部模块。', 'md', '{"category":"api","order":1}', 'true', '/docs/api/rest-api', '{"title":"REST API 完整参考","description":"200+ 标准接口文档,覆盖用户、内容、AI、支付等全部模块。"}', 'docs/api/rest-api', 'UrSAbHsueij0gNTWlXd4iyiJTMb9Byd5YRQx6ZWNkQg'); -- UrSAbHsueij0gNTWlXd4iyiJTMb9Byd5YRQx6ZWNkQg +INSERT INTO _content_docs VALUES ('docs/docs/api/streaming.md', '流式输出(SSE)接入', '{"type":"minimark","value":[["h1",{"id":"流式输出sse接入"},"流式输出(SSE)接入"],["blockquote",{},["p",{},"使用 Server-Sent Events 实现 AI 流式响应,提升用户体验。"]],["h2",{"id":"什么是流式输出"},"🌊 什么是流式输出?"],["p",{},"流式输出(Streaming)是一种数据传输方式,服务器将数据「分块」发送给客户端,而不是等待全部完成后再返回。"],["h3",{"id":"对比"},"对比"],["table",{},["thead",{},["tr",{},["th",{},"方式"],["th",{},"等待时间"],["th",{},"体验"],["th",{},"适用场景"]]],["tbody",{},["tr",{},["td",{},"普通请求"],["td",{},"等待完整响应"],["td",{},"一般"],["td",{},"简单、快速的请求"]],["tr",{},["td",{},"流式输出"],["td",{},"实时看到生成过程"],["td",{},"⭐ 优秀"],["td",{},"AI 生成、长文本"]]]],["h2",{"id":"开始使用"},"🚀 开始使用"],["h3",{"id":"前端接收流式响应"},"前端:接收流式响应"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WebsopyClient } from ''@websopy/sdk''\n\nconst client = new WebsopyClient({\n apiKey: process.env.WEBSOPY_API_KEY\n})\n\nasync function streamChat() {\n const stream = await client.ai.chatStream({\n messages: [\n { role: ''user'', content: ''写一篇关于 AI 的文章'' }\n ]\n })\n\n // 方法 1:遍历数据块\n for await (const chunk of stream) {\n if (chunk.type === ''content'') {\n process.stdout.write(chunk.content)\n }\n }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," streamChat"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"chatStream"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," messages: [\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," { role: "],["span",{"class":"sZZnC"},"''user''"],["span",{"class":"sVt8B"},", content: "],["span",{"class":"sZZnC"},"''写一篇关于 AI 的文章''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"}," ]\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"sJ8bj"}," // 方法 1:遍历数据块\n"]],["span",{"class":"line","line":15},["span",{"class":"szBVR"}," for"],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," chunk"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," stream) {\n"]],["span",{"class":"line","line":16},["span",{"class":"szBVR"}," if"],["span",{"class":"sVt8B"}," (chunk.type "],["span",{"class":"szBVR"},"==="],["span",{"class":"sZZnC"}," ''content''"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"}," process.stdout."],["span",{"class":"sScJk"},"write"],["span",{"class":"sVt8B"},"(chunk.content)\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":19},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"响应数据结构"},"响应数据结构"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"interface StreamChunk {\n type: ''content'' | ''tool_call'' | ''done'' | ''error''\n content?: string\n tool?: {\n name: string\n arguments: string\n }\n usage?: {\n promptTokens: number\n completionTokens: number\n }\n}\n\n// 示例数据块\n{ type: ''content'', content: ''AI'' }\n{ type: ''content'', content: '' 正在'' }\n{ type: ''content'', content: ''改变'' }\n{ type: ''content'', content: ''世界...'' }\n{ type: ''done'', usage: { promptTokens: 20, completionTokens: 150 } }\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"interface"],["span",{"class":"sScJk"}," StreamChunk"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":2},["span",{"class":"s4XuR"}," type"],["span",{"class":"szBVR"},":"],["span",{"class":"sZZnC"}," ''content''"],["span",{"class":"szBVR"}," |"],["span",{"class":"sZZnC"}," ''tool_call''"],["span",{"class":"szBVR"}," |"],["span",{"class":"sZZnC"}," ''done''"],["span",{"class":"szBVR"}," |"],["span",{"class":"sZZnC"}," ''error''\n"]],["span",{"class":"line","line":3},["span",{"class":"s4XuR"}," content"],["span",{"class":"szBVR"},"?:"],["span",{"class":"sj4cs"}," string\n"]],["span",{"class":"line","line":4},["span",{"class":"s4XuR"}," tool"],["span",{"class":"szBVR"},"?:"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":5},["span",{"class":"s4XuR"}," name"],["span",{"class":"szBVR"},":"],["span",{"class":"sj4cs"}," string\n"]],["span",{"class":"line","line":6},["span",{"class":"s4XuR"}," arguments"],["span",{"class":"szBVR"},":"],["span",{"class":"sj4cs"}," string\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":8},["span",{"class":"s4XuR"}," usage"],["span",{"class":"szBVR"},"?:"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":9},["span",{"class":"s4XuR"}," promptTokens"],["span",{"class":"szBVR"},":"],["span",{"class":"sj4cs"}," number\n"]],["span",{"class":"line","line":10},["span",{"class":"s4XuR"}," completionTokens"],["span",{"class":"szBVR"},":"],["span",{"class":"sj4cs"}," number\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"sJ8bj"},"// 示例数据块\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''content''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"content"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''AI''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''content''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"content"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"'' 正在''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''content''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"content"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''改变''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''content''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"content"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''世界...''"],["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":19},["span",{"class":"sVt8B"},"{ "],["span",{"class":"sScJk"},"type"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''done''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"usage"],["span",{"class":"sVt8B"},": { "],["span",{"class":"sScJk"},"promptTokens"],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"20"],["span",{"class":"sVt8B"},", "],["span",{"class":"sScJk"},"completionTokens"],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"150"],["span",{"class":"sVt8B"}," } }\n"]]]],["h2",{"id":"原生-sse-实现"},"🌐 原生 SSE 实现"],["p",{},"如果不用 SDK,直接使用 Fetch API:"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"async function nativeStream() {\n const response = await fetch(\n ''https://api.websopy.com/v1/ai/chat?message=Hello'',\n {\n headers: {\n ''Authorization'': `Bearer ${apiKey}`,\n ''Accept'': ''text/event-stream''\n }\n }\n )\n\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n \n const chunk = decoder.decode(value)\n const lines = chunk.split(''\\n'')\n for (const line of lines) {\n if (line.startsWith(''data: '')) {\n const data = JSON.parse(line.slice(6))\n console.log(''收到:'', data)\n }\n }\n }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," nativeStream"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," response"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sScJk"}," fetch"],["span",{"class":"sVt8B"},"(\n"]],["span",{"class":"line","line":3},["span",{"class":"sZZnC"}," ''https://api.websopy.com/v1/ai/chat?message=Hello''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," headers: {\n"]],["span",{"class":"line","line":6},["span",{"class":"sZZnC"}," ''Authorization''"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"`Bearer ${"],["span",{"class":"sVt8B"},"apiKey"],["span",{"class":"sZZnC"},"}`"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sZZnC"}," ''Accept''"],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"''text/event-stream''\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," )\n"]],["span",{"class":"line","line":11},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":12},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," reader"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," response.body."],["span",{"class":"sScJk"},"getReader"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":13},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," decoder"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," TextDecoder"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":14},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":15},["span",{"class":"szBVR"}," while"],["span",{"class":"sVt8B"}," ("],["span",{"class":"sj4cs"},"true"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":16},["span",{"class":"szBVR"}," const"],["span",{"class":"sVt8B"}," { "],["span",{"class":"sj4cs"},"done"],["span",{"class":"sVt8B"},", "],["span",{"class":"sj4cs"},"value"],["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," reader."],["span",{"class":"sScJk"},"read"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":17},["span",{"class":"szBVR"}," if"],["span",{"class":"sVt8B"}," (done) "],["span",{"class":"szBVR"},"break\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":19},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," chunk"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," decoder."],["span",{"class":"sScJk"},"decode"],["span",{"class":"sVt8B"},"(value)\n"]],["span",{"class":"line","line":20},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," lines"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," chunk."],["span",{"class":"sScJk"},"split"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''"],["span",{"class":"sj4cs"},"\\n"],["span",{"class":"sZZnC"},"''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":21},["span",{"class":"szBVR"}," for"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," line"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," lines) {\n"]],["span",{"class":"line","line":22},["span",{"class":"szBVR"}," if"],["span",{"class":"sVt8B"}," (line."],["span",{"class":"sScJk"},"startsWith"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''data: ''"],["span",{"class":"sVt8B"},")) {\n"]],["span",{"class":"line","line":23},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," data"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," JSON"],["span",{"class":"sVt8B"},"."],["span",{"class":"sScJk"},"parse"],["span",{"class":"sVt8B"},"(line."],["span",{"class":"sScJk"},"slice"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"6"],["span",{"class":"sVt8B"},"))\n"]],["span",{"class":"line","line":24},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''收到:''"],["span",{"class":"sVt8B"},", data)\n"]],["span",{"class":"line","line":25},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":26},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":27},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":28},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"前端组件示例"},"🎨 前端组件示例"],["h3",{"id":"vue-composition-api"},"Vue Composition API"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { ref } from ''vue''\n\nexport function useStreamingChat() {\n const messages = ref([])\n const streaming = ref(false)\n const currentContent = ref('''')\n\n const sendMessage = async (content) => {\n streaming.value = true\n currentContent.value = ''''\n \n messages.value.push({ role: ''user'', content })\n \n const stream = await client.ai.chatStream({\n messages: messages.value\n })\n\n for await (const chunk of stream) {\n if (chunk.type === ''content'') {\n currentContent.value += chunk.content\n }\n }\n \n messages.value.push({ role: ''assistant'', content: currentContent.value })\n streaming.value = false\n }\n\n return { messages, streaming, currentContent, sendMessage }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { ref } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''vue''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"export"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," useStreamingChat"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," messages"],["span",{"class":"szBVR"}," ="],["span",{"class":"sScJk"}," ref"],["span",{"class":"sVt8B"},"([])\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," streaming"],["span",{"class":"szBVR"}," ="],["span",{"class":"sScJk"}," ref"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"false"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":6},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," currentContent"],["span",{"class":"szBVR"}," ="],["span",{"class":"sScJk"}," ref"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"}," const"],["span",{"class":"sScJk"}," sendMessage"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," async"],["span",{"class":"sVt8B"}," ("],["span",{"class":"s4XuR"},"content"],["span",{"class":"sVt8B"},") "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," streaming.value "],["span",{"class":"szBVR"},"="],["span",{"class":"sj4cs"}," true\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," currentContent.value "],["span",{"class":"szBVR"},"="],["span",{"class":"sZZnC"}," ''''\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"}," messages.value."],["span",{"class":"sScJk"},"push"],["span",{"class":"sVt8B"},"({ role: "],["span",{"class":"sZZnC"},"''user''"],["span",{"class":"sVt8B"},", content })\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":14},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"chatStream"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"}," messages: messages.value\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":17},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":18},["span",{"class":"szBVR"}," for"],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," chunk"],["span",{"class":"szBVR"}," of"],["span",{"class":"sVt8B"}," stream) {\n"]],["span",{"class":"line","line":19},["span",{"class":"szBVR"}," if"],["span",{"class":"sVt8B"}," (chunk.type "],["span",{"class":"szBVR"},"==="],["span",{"class":"sZZnC"}," ''content''"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"}," currentContent.value "],["span",{"class":"szBVR"},"+="],["span",{"class":"sVt8B"}," chunk.content\n"]],["span",{"class":"line","line":21},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":23},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":24},["span",{"class":"sVt8B"}," messages.value."],["span",{"class":"sScJk"},"push"],["span",{"class":"sVt8B"},"({ role: "],["span",{"class":"sZZnC"},"''assistant''"],["span",{"class":"sVt8B"},", content: currentContent.value })\n"]],["span",{"class":"line","line":25},["span",{"class":"sVt8B"}," streaming.value "],["span",{"class":"szBVR"},"="],["span",{"class":"sj4cs"}," false\n"]],["span",{"class":"line","line":26},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":27},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":28},["span",{"class":"szBVR"}," return"],["span",{"class":"sVt8B"}," { messages, streaming, currentContent, sendMessage }\n"]],["span",{"class":"line","line":29},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-流式中断怎么办"},"Q: 流式中断怎么办?"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"async function streamWithReconnect() {\n const maxRetries = 3\n let retries = 0\n \n while (retries < maxRetries) {\n try {\n const stream = await client.ai.chatStream({...})\n return stream\n } catch (error) {\n retries++\n await sleep(1000 * retries) // 指数退避\n }\n }\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," streamWithReconnect"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," maxRetries"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," 3\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"}," let"],["span",{"class":"sVt8B"}," retries "],["span",{"class":"szBVR"},"="],["span",{"class":"sj4cs"}," 0\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"}," while"],["span",{"class":"sVt8B"}," (retries "],["span",{"class":"szBVR"},"<"],["span",{"class":"sVt8B"}," maxRetries) {\n"]],["span",{"class":"line","line":6},["span",{"class":"szBVR"}," try"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"chatStream"],["span",{"class":"sVt8B"},"({"],["span",{"class":"szBVR"},"..."],["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"}," return"],["span",{"class":"sVt8B"}," stream\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"catch"],["span",{"class":"sVt8B"}," (error) {\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," retries"],["span",{"class":"szBVR"},"++\n"]],["span",{"class":"line","line":11},["span",{"class":"szBVR"}," await"],["span",{"class":"sScJk"}," sleep"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"1000"],["span",{"class":"szBVR"}," *"],["span",{"class":"sVt8B"}," retries) "],["span",{"class":"sJ8bj"},"// 指数退避\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"q-如何在流式过程中取消请求"},"Q: 如何在流式过程中取消请求?"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const controller = new AbortController()\n\n// 发送请求\nconst stream = await client.ai.chatStream({\n messages: [...],\n signal: controller.signal\n})\n\n// 取消请求\ncontroller.abort()\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," controller"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," AbortController"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"sJ8bj"},"// 发送请求\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," stream"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.ai."],["span",{"class":"sScJk"},"chatStream"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," messages: ["],["span",{"class":"szBVR"},"..."],["span",{"class":"sVt8B"},"],\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," signal: controller.signal\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":8},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":9},["span",{"class":"sJ8bj"},"// 取消请求\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"},"controller."],["span",{"class":"sScJk"},"abort"],["span",{"class":"sVt8B"},"()\n"]]]],["h3",{"id":"q-sse-和-websocket-区别"},"Q: SSE 和 WebSocket 区别?"],["table",{},["thead",{},["tr",{},["th",{},"特性"],["th",{},"SSE"],["th",{},"WebSocket"]]],["tbody",{},["tr",{},["td",{},"方向"],["td",{},"单向(服务端→客户端)"],["td",{},"双向"]],["tr",{},["td",{},"协议"],["td",{},"HTTP"],["td",{},"ws://"]],["tr",{},["td",{},"重连"],["td",{},"自动"],["td",{},"需手动处理"]],["tr",{},["td",{},"复杂度"],["td",{},"简单"],["td",{},"复杂"]],["tr",{},["td",{},"适用"],["td",{},"AI 流式输出"],["td",{},"实时聊天"]]]],["style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是流式输出","depth":2,"text":"🌊 什么是流式输出?","children":[{"id":"对比","depth":3,"text":"对比"}]},{"id":"开始使用","depth":2,"text":"🚀 开始使用","children":[{"id":"前端接收流式响应","depth":3,"text":"前端:接收流式响应"},{"id":"响应数据结构","depth":3,"text":"响应数据结构"}]},{"id":"原生-sse-实现","depth":2,"text":"🌐 原生 SSE 实现"},{"id":"前端组件示例","depth":2,"text":"🎨 前端组件示例","children":[{"id":"vue-composition-api","depth":3,"text":"Vue Composition API"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-流式中断怎么办","depth":3,"text":"Q: 流式中断怎么办?"},{"id":"q-如何在流式过程中取消请求","depth":3,"text":"Q: 如何在流式过程中取消请求?"},{"id":"q-sse-和-websocket-区别","depth":3,"text":"Q: SSE 和 WebSocket 区别?"}]}]}}', '使用 Server-Sent Events 实现 AI 流式响应,提升用户体验。', 'md', '{"category":"api","order":2}', 'true', '/docs/api/streaming', '{"title":"流式输出(SSE)接入","description":"使用 Server-Sent Events 实现 AI 流式响应,提升用户体验。"}', 'docs/api/streaming', '7KYLowobLFDLS7cOqbBp4iZ20Cc95cZzYg2PYk_PHsE'); -- 7KYLowobLFDLS7cOqbBp4iZ20Cc95cZzYg2PYk_PHsE +INSERT INTO _content_docs VALUES ('docs/docs/api/webhook.md', 'Webhook 事件接入', '{"type":"minimark","value":[["h1",{"id":"webhook-事件接入"},"Webhook 事件接入"],["blockquote",{},["p",{},"订阅业务事件,处理订单支付、AI 任务完成等异步通知。"]],["h2",{"id":"什么是-webhook"},"🔔 什么是 Webhook?"],["p",{},"Webhook 是一种「反向 API 调用」机制:"],["ul",{},["li",{},"传统 API:你 → 平台(主动拉取)"],["li",{},"Webhook:平台 → 你(被动接收)"]],["p",{},"当某个事件发生时(如支付成功),平台主动通知你的服务器。"],["h2",{"id":"可订阅的事件"},"📋 可订阅的事件"],["table",{},["thead",{},["tr",{},["th",{},"事件类型"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},["code",{},"payment.completed"]],["td",{},"支付完成"]],["tr",{},["td",{},["code",{},"payment.failed"]],["td",{},"支付失败"]],["tr",{},["td",{},["code",{},"subscription.created"]],["td",{},"订阅创建"]],["tr",{},["td",{},["code",{},"subscription.cancelled"]],["td",{},"订阅取消"]],["tr",{},["td",{},["code",{},"ai.task.completed"]],["td",{},"AI 任务完成"]],["tr",{},["td",{},["code",{},"ai.task.failed"]],["td",{},"AI 任务失败"]],["tr",{},["td",{},["code",{},"file.uploaded"]],["td",{},"文件上传完成"]],["tr",{},["td",{},["code",{},"project.created"]],["td",{},"项目创建"]],["tr",{},["td",{},["code",{},"user.invited"]],["td",{},"用户被邀请"]],["tr",{},["td",{},["code",{},"workflow.triggered"]],["td",{},"工作流触发"]]]],["h2",{"id":"配置-webhook"},"🚀 配置 Webhook"],["h3",{"id":"步骤-1创建-webhook-端点"},"步骤 1:创建 Webhook 端点"],["p",{},"在你的服务器创建一个 API 端点:"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// Node.js Express 示例\napp.post(''/webhook/websopy'', express.raw({ type: ''application/json'' }), (req, res) => {\n // 验证签名\n const signature = req.headers[''x-websopy-signature'']\n const timestamp = req.headers[''x-websopy-timestamp'']\n \n if (!verifySignature(req.body, signature, timestamp)) {\n return res.status(401).send(''Invalid signature'')\n }\n \n // 处理事件\n const event = JSON.parse(req.body)\n console.log(''收到事件:'', event.type)\n \n // 立即返回 200(重要!)\n res.status(200).send(''OK'')\n \n // 异步处理业务逻辑\n processEvent(event)\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// Node.js Express 示例\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"app."],["span",{"class":"sScJk"},"post"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''/webhook/websopy''"],["span",{"class":"sVt8B"},", express."],["span",{"class":"sScJk"},"raw"],["span",{"class":"sVt8B"},"({ type: "],["span",{"class":"sZZnC"},"''application/json''"],["span",{"class":"sVt8B"}," }), ("],["span",{"class":"s4XuR"},"req"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"res"],["span",{"class":"sVt8B"},") "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":3},["span",{"class":"sJ8bj"}," // 验证签名\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," signature"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," req.headers["],["span",{"class":"sZZnC"},"''x-websopy-signature''"],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," timestamp"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," req.headers["],["span",{"class":"sZZnC"},"''x-websopy-timestamp''"],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"}," if"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"!"],["span",{"class":"sScJk"},"verifySignature"],["span",{"class":"sVt8B"},"(req.body, signature, timestamp)) {\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"}," return"],["span",{"class":"sVt8B"}," res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"401"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''Invalid signature''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"}," // 处理事件\n"]],["span",{"class":"line","line":12},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," event"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," JSON"],["span",{"class":"sVt8B"},"."],["span",{"class":"sScJk"},"parse"],["span",{"class":"sVt8B"},"(req.body)\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''收到事件:''"],["span",{"class":"sVt8B"},", event.type)\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":15},["span",{"class":"sJ8bj"}," // 立即返回 200(重要!)\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"}," res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"200"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''OK''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":18},["span",{"class":"sJ8bj"}," // 异步处理业务逻辑\n"]],["span",{"class":"line","line":19},["span",{"class":"sScJk"}," processEvent"],["span",{"class":"sVt8B"},"(event)\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"步骤-2在控制台配置"},"步骤 2:在控制台配置"],["ol",{},["li",{},"进入 ",["strong",{},"开发者中心 → Webhook"]],["li",{},"点击 ",["strong",{},"添加端点"]],["li",{},"填写配置:"]],["table",{},["thead",{},["tr",{},["th",{},"配置项"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},"URL"],["td",{},"你的服务器地址,如 ",["code",{},"https://your-server.com/webhook/websopy"]]],["tr",{},["td",{},"事件类型"],["td",{},"选择要订阅的事件"]],["tr",{},["td",{},"密钥"],["td",{},"用于验证签名的密钥"]]]],["h3",{"id":"步骤-3验证签名"},"步骤 3:验证签名"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import crypto from ''crypto''\n\nfunction verifySignature(body, signature, timestamp) {\n const secret = process.env.WEBSOPY_WEBHOOK_SECRET\n \n // 检查时间戳(5分钟内有效)\n const ts = parseInt(timestamp)\n if (Date.now() - ts > 5 * 60 * 1000) {\n return false\n }\n \n // 计算签名\n const payload = `${timestamp}.${body}`\n const expectedSignature = crypto\n .createHmac(''sha256'', secret)\n .update(payload)\n .digest(''hex'')\n \n return crypto.timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature)\n )\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," crypto "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''crypto''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"function"],["span",{"class":"sScJk"}," verifySignature"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"body"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"signature"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"timestamp"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," secret"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," process.env."],["span",{"class":"sj4cs"},"WEBSOPY_WEBHOOK_SECRET\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"}," // 检查时间戳(5分钟内有效)\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," ts"],["span",{"class":"szBVR"}," ="],["span",{"class":"sScJk"}," parseInt"],["span",{"class":"sVt8B"},"(timestamp)\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"}," if"],["span",{"class":"sVt8B"}," (Date."],["span",{"class":"sScJk"},"now"],["span",{"class":"sVt8B"},"() "],["span",{"class":"szBVR"},"-"],["span",{"class":"sVt8B"}," ts "],["span",{"class":"szBVR"},">"],["span",{"class":"sj4cs"}," 5"],["span",{"class":"szBVR"}," *"],["span",{"class":"sj4cs"}," 60"],["span",{"class":"szBVR"}," *"],["span",{"class":"sj4cs"}," 1000"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":9},["span",{"class":"szBVR"}," return"],["span",{"class":"sj4cs"}," false\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":12},["span",{"class":"sJ8bj"}," // 计算签名\n"]],["span",{"class":"line","line":13},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," payload"],["span",{"class":"szBVR"}," ="],["span",{"class":"sZZnC"}," `${"],["span",{"class":"sVt8B"},"timestamp"],["span",{"class":"sZZnC"},"}.${"],["span",{"class":"sVt8B"},"body"],["span",{"class":"sZZnC"},"}`\n"]],["span",{"class":"line","line":14},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," expectedSignature"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," crypto\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"}," ."],["span",{"class":"sScJk"},"createHmac"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''sha256''"],["span",{"class":"sVt8B"},", secret)\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"}," ."],["span",{"class":"sScJk"},"update"],["span",{"class":"sVt8B"},"(payload)\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"}," ."],["span",{"class":"sScJk"},"digest"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''hex''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":19},["span",{"class":"szBVR"}," return"],["span",{"class":"sVt8B"}," crypto."],["span",{"class":"sScJk"},"timingSafeEqual"],["span",{"class":"sVt8B"},"(\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"}," Buffer."],["span",{"class":"sScJk"},"from"],["span",{"class":"sVt8B"},"(signature),\n"]],["span",{"class":"line","line":21},["span",{"class":"sVt8B"}," Buffer."],["span",{"class":"sScJk"},"from"],["span",{"class":"sVt8B"},"(expectedSignature)\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"}," )\n"]],["span",{"class":"line","line":23},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"事件数据格式"},"📨 事件数据格式"],["h3",{"id":"通用结构"},"通用结构"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n \"id\": \"evt_abc123xyz\",\n \"type\": \"payment.completed\",\n \"created_at\": \"2024-01-15T10:30:00Z\",\n \"data\": {\n // 事件相关数据\n }\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"}," \"id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"evt_abc123xyz\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"}," \"type\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"payment.completed\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sj4cs"}," \"created_at\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"2024-01-15T10:30:00Z\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"}," \"data\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"}," // 事件相关数据\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"}\n"]]]],["h3",{"id":"支付完成事件"},"支付完成事件"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n \"id\": \"evt_abc123xyz\",\n \"type\": \"payment.completed\",\n \"created_at\": \"2024-01-15T10:30:00Z\",\n \"data\": {\n \"order_id\": \"ord_xyz789\",\n \"amount\": 29900,\n \"currency\": \"CNY\",\n \"payment_method\": \"alipay\",\n \"status\": \"completed\",\n \"user_id\": \"user_123\"\n }\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"}," \"id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"evt_abc123xyz\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"}," \"type\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"payment.completed\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sj4cs"}," \"created_at\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"2024-01-15T10:30:00Z\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sj4cs"}," \"data\""],["span",{"class":"sVt8B"},": {\n"]],["span",{"class":"line","line":6},["span",{"class":"sj4cs"}," \"order_id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"ord_xyz789\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sj4cs"}," \"amount\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"29900"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":8},["span",{"class":"sj4cs"}," \"currency\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"CNY\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sj4cs"}," \"payment_method\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"alipay\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":10},["span",{"class":"sj4cs"}," \"status\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"completed\""],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":11},["span",{"class":"sj4cs"}," \"user_id\""],["span",{"class":"sVt8B"},": "],["span",{"class":"sZZnC"},"\"user_123\"\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"失败重试"},"⏰ 失败重试"],["p",{},"如果你的服务器返回非 200 状态码,Websopy 会自动重试:"],["table",{},["thead",{},["tr",{},["th",{},"重试次数"],["th",{},"延迟"]]],["tbody",{},["tr",{},["td",{},"第 1 次"],["td",{},"1 分钟"]],["tr",{},["td",{},"第 2 次"],["td",{},"5 分钟"]],["tr",{},["td",{},"第 3 次"],["td",{},"30 分钟"]],["tr",{},["td",{},"第 4 次"],["td",{},"2 小时"]],["tr",{},["td",{},"第 5 次"],["td",{},"12 小时"]]]],["p",{},"超过重试次数仍未成功,事件将被标记为失败,可在控制台手动重试。"],["h3",{"id":"幂等处理"},"幂等处理"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const processedEvents = new Set()\n\napp.post(''/webhook/websopy'', async (req, res) => {\n const event = JSON.parse(req.body)\n \n // 幂等检查\n if (processedEvents.has(event.id)) {\n return res.status(200).send(''Already processed'')\n }\n \n try {\n await processEvent(event)\n processedEvents.add(event.id)\n res.status(200).send(''OK'')\n } catch (error) {\n res.status(500).send(''Error'')\n }\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," processedEvents"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," Set"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"app."],["span",{"class":"sScJk"},"post"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''/webhook/websopy''"],["span",{"class":"sVt8B"},", "],["span",{"class":"szBVR"},"async"],["span",{"class":"sVt8B"}," ("],["span",{"class":"s4XuR"},"req"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"res"],["span",{"class":"sVt8B"},") "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," event"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," JSON"],["span",{"class":"sVt8B"},"."],["span",{"class":"sScJk"},"parse"],["span",{"class":"sVt8B"},"(req.body)\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"}," // 幂等检查\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"}," if"],["span",{"class":"sVt8B"}," (processedEvents."],["span",{"class":"sScJk"},"has"],["span",{"class":"sVt8B"},"(event.id)) {\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"}," return"],["span",{"class":"sVt8B"}," res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"200"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''Already processed''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":11},["span",{"class":"szBVR"}," try"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":12},["span",{"class":"szBVR"}," await"],["span",{"class":"sScJk"}," processEvent"],["span",{"class":"sVt8B"},"(event)\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"}," processedEvents."],["span",{"class":"sScJk"},"add"],["span",{"class":"sVt8B"},"(event.id)\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"}," res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"200"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''OK''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"catch"],["span",{"class":"sVt8B"}," (error) {\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"}," res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"500"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''Error''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"本地开发测试"},"🧪 本地开发测试"],["h3",{"id":"使用-ngrok"},"使用 ngrok"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 安装 ngrok\nnpm install -g ngrok\n\n# 启动本地服务\nngrok http 3000\n\n# 复制输出的 https URL 到 Webhook 配置\n# https://abc123.ngrok.io/webhook/websopy\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 安装 ngrok\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"npm"],["span",{"class":"sZZnC"}," install"],["span",{"class":"sj4cs"}," -g"],["span",{"class":"sZZnC"}," ngrok\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 启动本地服务\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"ngrok"],["span",{"class":"sZZnC"}," http"],["span",{"class":"sj4cs"}," 3000\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 复制输出的 https URL 到 Webhook 配置\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"# https://abc123.ngrok.io/webhook/websopy\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-收到重复事件怎么办"},"Q: 收到重复事件怎么办?"],["p",{},"使用事件 ID 做幂等检查,参考上文示例。"],["h3",{"id":"q-处理超时怎么办"},"Q: 处理超时怎么办?"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"app.post(''/webhook'', async (req, res) => {\n // 立即返回\n res.status(200).send(''OK'')\n \n // 异步处理\n setImmediate(() => processEvent(req.body))\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"app."],["span",{"class":"sScJk"},"post"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''/webhook''"],["span",{"class":"sVt8B"},", "],["span",{"class":"szBVR"},"async"],["span",{"class":"sVt8B"}," ("],["span",{"class":"s4XuR"},"req"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"res"],["span",{"class":"sVt8B"},") "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":2},["span",{"class":"sJ8bj"}," // 立即返回\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," res."],["span",{"class":"sScJk"},"status"],["span",{"class":"sVt8B"},"("],["span",{"class":"sj4cs"},"200"],["span",{"class":"sVt8B"},")."],["span",{"class":"sScJk"},"send"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''OK''"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"}," // 异步处理\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"}," setImmediate"],["span",{"class":"sVt8B"},"(() "],["span",{"class":"szBVR"},"=>"],["span",{"class":"sScJk"}," processEvent"],["span",{"class":"sVt8B"},"(req.body))\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-webhook","depth":2,"text":"🔔 什么是 Webhook?"},{"id":"可订阅的事件","depth":2,"text":"📋 可订阅的事件"},{"id":"配置-webhook","depth":2,"text":"🚀 配置 Webhook","children":[{"id":"步骤-1创建-webhook-端点","depth":3,"text":"步骤 1:创建 Webhook 端点"},{"id":"步骤-2在控制台配置","depth":3,"text":"步骤 2:在控制台配置"},{"id":"步骤-3验证签名","depth":3,"text":"步骤 3:验证签名"}]},{"id":"事件数据格式","depth":2,"text":"📨 事件数据格式","children":[{"id":"通用结构","depth":3,"text":"通用结构"},{"id":"支付完成事件","depth":3,"text":"支付完成事件"}]},{"id":"失败重试","depth":2,"text":"⏰ 失败重试","children":[{"id":"幂等处理","depth":3,"text":"幂等处理"}]},{"id":"本地开发测试","depth":2,"text":"🧪 本地开发测试","children":[{"id":"使用-ngrok","depth":3,"text":"使用 ngrok"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-收到重复事件怎么办","depth":3,"text":"Q: 收到重复事件怎么办?"},{"id":"q-处理超时怎么办","depth":3,"text":"Q: 处理超时怎么办?"}]}]}}', '订阅业务事件,处理订单支付、AI 任务完成等异步通知。', 'md', '{"category":"api","order":3}', 'true', '/docs/api/webhook', '{"title":"Webhook 事件接入","description":"订阅业务事件,处理订单支付、AI 任务完成等异步通知。"}', 'docs/api/webhook', 'JzUDaOPT8P4lqAf6z6op6nMpr0qauqZr8pTO6bB32u8'); -- JzUDaOPT8P4lqAf6z6op6nMpr0qauqZr8pTO6bB32u8 +INSERT INTO _content_docs VALUES ('docs/docs/deploy/docker.md', 'Docker Compose 部署', '{"type":"minimark","value":[["h1",{"id":"docker-compose-部署"},"Docker Compose 部署"],["blockquote",{},["p",{},"一键部署全套服务(前端+后端+数据库+AI),本地与云端通用。"]],["h2",{"id":"什么是-docker-compose"},"🐳 什么是 Docker Compose?"],["p",{},"Docker Compose 是一个工具,用于定义和运行多容器 Docker 应用。通过一个 ",["code",{},"docker-compose.yml"]," 文件,你可以一键启动所有相关服务。"],["h2",{"id":"前提条件"},"📋 前提条件"],["ul",{},["li",{},"Docker 20.10+"],["li",{},"Docker Compose 2.0+"],["li",{},"至少 4GB 内存"]],["h2",{"id":"快速开始"},"🚀 快速开始"],["h3",{"id":"第一步下载模板"},"第一步:下载模板"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 克隆模板仓库\ngit clone https://github.com/websopy/deploy-templates.git websopy-deploy\ncd websopy-deploy\n\n# 选择版本\ngit checkout v2.3.0\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 克隆模板仓库\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," clone"],["span",{"class":"sZZnC"}," https://github.com/websopy/deploy-templates.git"],["span",{"class":"sZZnC"}," websopy-deploy\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"cd"],["span",{"class":"sZZnC"}," websopy-deploy\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"},"# 选择版本\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," checkout"],["span",{"class":"sZZnC"}," v2.3.0\n"]]]],["h3",{"id":"第二步配置环境"},"第二步:配置环境"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 复制环境变量文件\ncp .env.example .env\n\n# 编辑配置\nnano .env\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 复制环境变量文件\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"cp"],["span",{"class":"sZZnC"}," .env.example"],["span",{"class":"sZZnC"}," .env\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 编辑配置\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"nano"],["span",{"class":"sZZnC"}," .env\n"]]]],["p",{},"关键配置:"],["pre",{"className":"language-env shiki shiki-themes github-light github-dark","code":"# 版本\nWEBSOPY_VERSION=2.3.0\n\n# 数据库\nPOSTGRES_DB=websopy\nPOSTGRES_USER=websopy\nPOSTGRES_PASSWORD=your-strong-password\n\n# Redis\nREDIS_PASSWORD=your-redis-password\n\n# JWT 密钥(生成随机字符串)\nJWT_SECRET=$(openssl rand -hex 32)\n\n# 域名(可选)\nDOMAIN=your-domain.com\n","language":"env","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"# 版本\n"]],["span",{"class":"line","line":2},["span",{},"WEBSOPY_VERSION=2.3.0\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{},"# 数据库\n"]],["span",{"class":"line","line":5},["span",{},"POSTGRES_DB=websopy\n"]],["span",{"class":"line","line":6},["span",{},"POSTGRES_USER=websopy\n"]],["span",{"class":"line","line":7},["span",{},"POSTGRES_PASSWORD=your-strong-password\n"]],["span",{"class":"line","line":8},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":9},["span",{},"# Redis\n"]],["span",{"class":"line","line":10},["span",{},"REDIS_PASSWORD=your-redis-password\n"]],["span",{"class":"line","line":11},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":12},["span",{},"# JWT 密钥(生成随机字符串)\n"]],["span",{"class":"line","line":13},["span",{},"JWT_SECRET=$(openssl rand -hex 32)\n"]],["span",{"class":"line","line":14},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":15},["span",{},"# 域名(可选)\n"]],["span",{"class":"line","line":16},["span",{},"DOMAIN=your-domain.com\n"]]]],["h3",{"id":"第三步启动服务"},"第三步:启动服务"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 一键启动所有服务\ndocker-compose up -d\n\n# 查看服务状态\ndocker-compose ps\n\n# 查看日志\ndocker-compose logs -f\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 一键启动所有服务\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 查看服务状态\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 查看日志\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f\n"]]]],["h3",{"id":"第四步验证部署"},"第四步:验证部署"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 检查服务健康状态\ncurl http://localhost:3000/api/health\n\n# 预期输出\n{\"status\":\"ok\",\"version\":\"2.3.0\",\"services\":{\"db\":\"up\",\"redis\":\"up\",\"ai\":\"up\"}}\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 检查服务健康状态\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"curl"],["span",{"class":"sZZnC"}," http://localhost:3000/api/health\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 预期输出\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"{"],["span",{"class":"sScJk"},"\"status\""],["span",{"class":"sj4cs"},":"],["span",{"class":"sScJk"},"\"ok\""],["span",{"class":"sScJk"},","],["span",{"class":"sScJk"},"\"version\""],["span",{"class":"sj4cs"},":"],["span",{"class":"sScJk"},"\"2.3.0\""],["span",{"class":"sScJk"},","],["span",{"class":"sScJk"},"\"services\""],["span",{"class":"sj4cs"},":"],["span",{"class":"sZZnC"},"{"],["span",{"class":"sVt8B"},"\""],["span",{"class":"sScJk"},"db"],["span",{"class":"sScJk"},"\":\""],["span",{"class":"sScJk"},"up"],["span",{"class":"sScJk"},"\",\""],["span",{"class":"sScJk"},"redis"],["span",{"class":"sScJk"},"\":\""],["span",{"class":"sScJk"},"up"],["span",{"class":"sScJk"},"\",\""],["span",{"class":"sScJk"},"ai"],["span",{"class":"sScJk"},"\":\""],["span",{"class":"sScJk"},"up"],["span",{"class":"sScJk"},"\"}}\n"]]]],["h2",{"id":"️-服务架构"},"🏗️ 服务架构"],["pre",{"className":["language-text"],"code":" ┌─────────────┐\n │ Nginx │\n │ (反向代理) │\n └──────┬──────┘\n │\n ┌───────────────┼───────────────┐\n │ │ │\n ┌────▼────┐ ┌─────▼────┐ ┌────▼────┐\n │ Web │ │ API │ │ Worker │\n │ (前端) │ │ (后端) │ │ (异步) │\n └─────────┘ └─────┬────┘ └─────────┘\n │\n ┌────────────┼────────────┐\n │ │ │\n ┌────▼───┐ ┌─────▼────┐ ┌───▼────┐\n │Postgres│ │ Redis │ │ AI │\n │(数据库) │ │ (缓存) │ │(AI服务) │\n └────────┘ └──────────┘ └────────┘\n","language":"text"},["code",{"__ignoreMap":""}," ┌─────────────┐\n │ Nginx │\n │ (反向代理) │\n └──────┬──────┘\n │\n ┌───────────────┼───────────────┐\n │ │ │\n ┌────▼────┐ ┌─────▼────┐ ┌────▼────┐\n │ Web │ │ API │ │ Worker │\n │ (前端) │ │ (后端) │ │ (异步) │\n └─────────┘ └─────┬────┘ └─────────┘\n │\n ┌────────────┼────────────┐\n │ │ │\n ┌────▼───┐ ┌─────▼────┐ ┌───▼────┐\n │Postgres│ │ Redis │ │ AI │\n │(数据库) │ │ (缓存) │ │(AI服务) │\n └────────┘ └──────────┘ └────────┘\n"]],["h2",{"id":"常用命令"},"🔧 常用命令"],["h3",{"id":"启动与停止"},"启动与停止"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 启动所有服务\ndocker-compose up -d\n\n# 停止所有服务\ndocker-compose down\n\n# 重启所有服务\ndocker-compose restart\n\n# 重启指定服务\ndocker-compose restart api\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 启动所有服务\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 停止所有服务\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," down\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 重启所有服务\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," restart\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"# 重启指定服务\n"]],["span",{"class":"line","line":11},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," restart"],["span",{"class":"sZZnC"}," api\n"]]]],["h3",{"id":"日志查看"},"日志查看"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看所有日志\ndocker-compose logs -f\n\n# 查看特定服务日志\ndocker-compose logs -f api\ndocker-compose logs -f web\n\n# 查看最近 100 行\ndocker-compose logs --tail=100\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看所有日志\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 查看特定服务日志\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f"],["span",{"class":"sZZnC"}," api\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f"],["span",{"class":"sZZnC"}," web\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"# 查看最近 100 行\n"]],["span",{"class":"line","line":9},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," --tail=100\n"]]]],["h3",{"id":"进入容器"},"进入容器"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 进入 API 容器\ndocker-compose exec api sh\n\n# 进入数据库\ndocker-compose exec postgres psql -U websopy\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 进入 API 容器\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," sh\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 进入数据库\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," psql"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy\n"]]]],["h2",{"id":"数据持久化"},"💾 数据持久化"],["p",{},"数据存储在 Docker volumes 中:"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看 volumes\ndocker volume ls | grep websopy\n\n# 备份数据\ndocker-compose exec postgres pg_dump -U websopy > backup.sql\n\n# 恢复数据\ndocker exec -i $(docker-compose ps -q postgres) psql -U websopy < backup.sql\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看 volumes\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," volume"],["span",{"class":"sZZnC"}," ls"],["span",{"class":"szBVR"}," |"],["span",{"class":"sScJk"}," grep"],["span",{"class":"sZZnC"}," websopy\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 备份数据\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," pg_dump"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," >"],["span",{"class":"sZZnC"}," backup.sql\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 恢复数据\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sj4cs"}," -i"],["span",{"class":"sVt8B"}," $("],["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps"],["span",{"class":"sj4cs"}," -q"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sVt8B"},") "],["span",{"class":"sZZnC"},"psql"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," <"],["span",{"class":"sZZnC"}," backup.sql\n"]]]],["h2",{"id":"故障排查"},"🐛 故障排查"],["h3",{"id":"服务无法启动"},"服务无法启动"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 1. 检查 Docker 是否运行\ndocker info\n\n# 2. 查看详细日志\ndocker-compose up\n\n# 3. 检查端口占用\nlsof -i :80\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 1. 检查 Docker 是否运行\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," info\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 2. 查看详细日志\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 3. 检查端口占用\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"lsof"],["span",{"class":"sj4cs"}," -i"],["span",{"class":"sZZnC"}," :80\n"]]]],["h3",{"id":"数据库连接失败"},"数据库连接失败"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 1. 检查 postgres 是否运行\ndocker-compose ps postgres\n\n# 2. 查看数据库日志\ndocker-compose logs postgres\n\n# 3. 测试连接\ndocker-compose exec postgres psql -U websopy -c \"SELECT 1\"\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 1. 检查 postgres 是否运行\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps"],["span",{"class":"sZZnC"}," postgres\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 2. 查看数据库日志\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sZZnC"}," postgres\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 3. 测试连接\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," psql"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sj4cs"}," -c"],["span",{"class":"sZZnC"}," \"SELECT 1\"\n"]]]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-docker-compose","depth":2,"text":"🐳 什么是 Docker Compose?"},{"id":"前提条件","depth":2,"text":"📋 前提条件"},{"id":"快速开始","depth":2,"text":"🚀 快速开始","children":[{"id":"第一步下载模板","depth":3,"text":"第一步:下载模板"},{"id":"第二步配置环境","depth":3,"text":"第二步:配置环境"},{"id":"第三步启动服务","depth":3,"text":"第三步:启动服务"},{"id":"第四步验证部署","depth":3,"text":"第四步:验证部署"}]},{"id":"️-服务架构","depth":2,"text":"🏗️ 服务架构"},{"id":"常用命令","depth":2,"text":"🔧 常用命令","children":[{"id":"启动与停止","depth":3,"text":"启动与停止"},{"id":"日志查看","depth":3,"text":"日志查看"},{"id":"进入容器","depth":3,"text":"进入容器"}]},{"id":"数据持久化","depth":2,"text":"💾 数据持久化"},{"id":"故障排查","depth":2,"text":"🐛 故障排查","children":[{"id":"服务无法启动","depth":3,"text":"服务无法启动"},{"id":"数据库连接失败","depth":3,"text":"数据库连接失败"}]}]}}', '一键部署全套服务(前端+后端+数据库+AI),本地与云端通用。', 'md', '{"category":"deploy","order":1}', 'true', '/docs/deploy/docker', '{"title":"Docker Compose 部署","description":"一键部署全套服务(前端+后端+数据库+AI),本地与云端通用。"}', 'docs/deploy/docker', 'JLPDy1ukkZcXDwJc1JrVAKX-blTkv_BsqqzsEhQ4L1A'); -- JLPDy1ukkZcXDwJc1JrVAKX-blTkv_BsqqzsEhQ4L1A +INSERT INTO _content_docs VALUES ('docs/docs/deploy/private-deploy.md', '私有化部署完全指南', '{"type":"minimark","value":[["h1",{"id":"私有化部署完全指南"},"私有化部署完全指南"],["blockquote",{},["p",{},"Docker Compose 一键部署,HTTPS 配置、备份策略与版本升级。"]],["h2",{"id":"什么是私有化部署"},"🏠 什么是私有化部署?"],["p",{},"私有化部署让你在自己的服务器上运行 Websopy 平台,享受:"],["ul",{},["li",{},"🔒 ",["strong",{},"数据完全自主"]," - 所有数据存储在你的服务器"],["li",{},"⚙️ ",["strong",{},"完全可控"]," - 自定义配置、插件、界面"],["li",{},"💰 ",["strong",{},"成本可控"]," - 无按调用量计费"],["li",{},"🏢 ",["strong",{},"合规无忧"]," - 满足数据不出网要求"]],["h2",{"id":"系统要求"},"📋 系统要求"],["h3",{"id":"最低配置"},"最低配置"],["table",{},["thead",{},["tr",{},["th",{},"资源"],["th",{},"最低要求"]]],["tbody",{},["tr",{},["td",{},"CPU"],["td",{},"4 核"]],["tr",{},["td",{},"内存"],["td",{},"8 GB"]],["tr",{},["td",{},"硬盘"],["td",{},"100 GB SSD"]],["tr",{},["td",{},"系统"],["td",{},"Ubuntu 20.04+ / CentOS 8+"]]]],["h3",{"id":"推荐配置"},"推荐配置"],["table",{},["thead",{},["tr",{},["th",{},"资源"],["th",{},"推荐配置"]]],["tbody",{},["tr",{},["td",{},"CPU"],["td",{},"8 核+"]],["tr",{},["td",{},"内存"],["td",{},"16 GB+"]],["tr",{},["td",{},"硬盘"],["td",{},"500 GB SSD+"]],["tr",{},["td",{},"系统"],["td",{},"Ubuntu 22.04 LTS"]]]],["h3",{"id":"软件依赖"},"软件依赖"],["ul",{},["li",{},"Docker 20.10+"],["li",{},"Docker Compose 2.0+"],["li",{},"Git"],["li",{},"域名(可选,用于 HTTPS)"]],["h2",{"id":"开始部署"},"🚀 开始部署"],["h3",{"id":"第一步准备服务器"},"第一步:准备服务器"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 更新系统\nsudo apt update && sudo apt upgrade -y\n\n# 安装 Docker(Ubuntu/Debian)\ncurl -fsSL https://get.docker.com | sh\nsudo usermod -aG docker $USER\n\n# 验证安装\ndocker --version\ndocker-compose --version\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 更新系统\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," apt"],["span",{"class":"sZZnC"}," update"],["span",{"class":"sVt8B"}," && "],["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," apt"],["span",{"class":"sZZnC"}," upgrade"],["span",{"class":"sj4cs"}," -y\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 安装 Docker(Ubuntu/Debian)\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"curl"],["span",{"class":"sj4cs"}," -fsSL"],["span",{"class":"sZZnC"}," https://get.docker.com"],["span",{"class":"szBVR"}," |"],["span",{"class":"sScJk"}," sh\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," usermod"],["span",{"class":"sj4cs"}," -aG"],["span",{"class":"sZZnC"}," docker"],["span",{"class":"sVt8B"}," $USER\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"# 验证安装\n"]],["span",{"class":"line","line":9},["span",{"class":"sScJk"},"docker"],["span",{"class":"sj4cs"}," --version\n"]],["span",{"class":"line","line":10},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sj4cs"}," --version\n"]]]],["h3",{"id":"第二步下载部署包"},"第二步:下载部署包"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 创建工作目录\nmkdir -p ~/websopy && cd ~/websopy\n\n# 下载最新版本\nwget https://releases.websopy.com/on-premise/latest.tar.gz\n\n# 解压\ntar -xzf latest.tar.gz\ncd websopy-deploy\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 创建工作目录\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"mkdir"],["span",{"class":"sj4cs"}," -p"],["span",{"class":"sZZnC"}," ~/websopy"],["span",{"class":"sVt8B"}," && "],["span",{"class":"sj4cs"},"cd"],["span",{"class":"sZZnC"}," ~/websopy\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 下载最新版本\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"wget"],["span",{"class":"sZZnC"}," https://releases.websopy.com/on-premise/latest.tar.gz\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 解压\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"tar"],["span",{"class":"sj4cs"}," -xzf"],["span",{"class":"sZZnC"}," latest.tar.gz\n"]],["span",{"class":"line","line":9},["span",{"class":"sj4cs"},"cd"],["span",{"class":"sZZnC"}," websopy-deploy\n"]]]],["h3",{"id":"第三步配置环境"},"第三步:配置环境"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 复制配置文件\ncp .env.example .env\n\n# 编辑配置文件\nnano .env\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 复制配置文件\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"cp"],["span",{"class":"sZZnC"}," .env.example"],["span",{"class":"sZZnC"}," .env\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 编辑配置文件\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"nano"],["span",{"class":"sZZnC"}," .env\n"]]]],["p",{},"关键配置项:"],["pre",{"className":"language-env shiki shiki-themes github-light github-dark","code":"# 版本配置\nWEBSOPY_VERSION=latest\n\n# 数据库配置\nDB_HOST=postgres\nDB_PORT=5432\nDB_NAME=websopy\nDB_USER=websopy\nDB_PASSWORD=your-secure-password\n\n# Redis 配置\nREDIS_HOST=redis\nREDIS_PORT=6379\nREDIS_PASSWORD=your-redis-password\n\n# 域名配置(可选)\nDOMAIN=your-domain.com\nHTTPS_ENABLED=true\n\n# 管理员账户\nADMIN_EMAIL=admin@yourcompany.com\nADMIN_PASSWORD=your-admin-password\n","language":"env","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"# 版本配置\n"]],["span",{"class":"line","line":2},["span",{},"WEBSOPY_VERSION=latest\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{},"# 数据库配置\n"]],["span",{"class":"line","line":5},["span",{},"DB_HOST=postgres\n"]],["span",{"class":"line","line":6},["span",{},"DB_PORT=5432\n"]],["span",{"class":"line","line":7},["span",{},"DB_NAME=websopy\n"]],["span",{"class":"line","line":8},["span",{},"DB_USER=websopy\n"]],["span",{"class":"line","line":9},["span",{},"DB_PASSWORD=your-secure-password\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{},"# Redis 配置\n"]],["span",{"class":"line","line":12},["span",{},"REDIS_HOST=redis\n"]],["span",{"class":"line","line":13},["span",{},"REDIS_PORT=6379\n"]],["span",{"class":"line","line":14},["span",{},"REDIS_PASSWORD=your-redis-password\n"]],["span",{"class":"line","line":15},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":16},["span",{},"# 域名配置(可选)\n"]],["span",{"class":"line","line":17},["span",{},"DOMAIN=your-domain.com\n"]],["span",{"class":"line","line":18},["span",{},"HTTPS_ENABLED=true\n"]],["span",{"class":"line","line":19},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":20},["span",{},"# 管理员账户\n"]],["span",{"class":"line","line":21},["span",{},"ADMIN_EMAIL=admin@yourcompany.com\n"]],["span",{"class":"line","line":22},["span",{},"ADMIN_PASSWORD=your-admin-password\n"]]]],["h3",{"id":"第四步启动服务"},"第四步:启动服务"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 拉取镜像\ndocker-compose pull\n\n# 启动所有服务\ndocker-compose up -d\n\n# 查看服务状态\ndocker-compose ps\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 拉取镜像\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," pull\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 启动所有服务\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 查看服务状态\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps\n"]]]],["h3",{"id":"第五步访问平台"},"第五步:访问平台"],["p",{},"服务启动后,通过浏览器访问:"],["ul",{},["li",{},"前端界面:",["code",{},"http://your-server-ip:80"]],["li",{},"管理后台:",["code",{},"http://your-server-ip:80/admin"]],["li",{},"API 端点:",["code",{},"http://your-server-ip:8080/api/v1"]]],["h2",{"id":"https-配置"},"🔒 HTTPS 配置"],["h3",{"id":"使用-lets-encrypt推荐"},"使用 Let''s Encrypt(推荐)"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 申请 SSL 证书\ncertbot --nginx -d your-domain.com\n\n# 重启 nginx\ndocker-compose restart nginx\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 申请 SSL 证书\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"certbot"],["span",{"class":"sj4cs"}," --nginx"],["span",{"class":"sj4cs"}," -d"],["span",{"class":"sZZnC"}," your-domain.com\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 重启 nginx\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," restart"],["span",{"class":"sZZnC"}," nginx\n"]]]],["h2",{"id":"备份策略"},"💾 备份策略"],["h3",{"id":"自动备份脚本"},"自动备份脚本"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"#!/bin/bash\nBACKUP_DIR=/data/backups/websopy\nDATE=$(date +%Y%m%d_%H%M%S)\n\nmkdir -p $BACKUP_DIR\n\n# 备份数据库\ndocker exec websopy-postgres pg_dump -U websopy > $BACKUP_DIR/db_$DATE.sql\n\n# 备份上传文件\ntar -czf $BACKUP_DIR/uploads_$DATE.tar.gz /data/websopy/uploads\n\n# 保留最近 30 天的备份\nfind $BACKUP_DIR -mtime +30 -delete\n\necho \"备份完成: $DATE\"\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"#!/bin/bash\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"BACKUP_DIR"],["span",{"class":"szBVR"},"="],["span",{"class":"sZZnC"},"/data/backups/websopy\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"DATE"],["span",{"class":"szBVR"},"="],["span",{"class":"sVt8B"},"$("],["span",{"class":"sScJk"},"date"],["span",{"class":"sZZnC"}," +%Y%m%d_%H%M%S"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"mkdir"],["span",{"class":"sj4cs"}," -p"],["span",{"class":"sVt8B"}," $BACKUP_DIR\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 备份数据库\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," websopy-postgres"],["span",{"class":"sZZnC"}," pg_dump"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," >"],["span",{"class":"sVt8B"}," $BACKUP_DIR"],["span",{"class":"sZZnC"},"/db_"],["span",{"class":"sVt8B"},"$DATE"],["span",{"class":"sZZnC"},".sql\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"# 备份上传文件\n"]],["span",{"class":"line","line":11},["span",{"class":"sScJk"},"tar"],["span",{"class":"sj4cs"}," -czf"],["span",{"class":"sVt8B"}," $BACKUP_DIR"],["span",{"class":"sZZnC"},"/uploads_"],["span",{"class":"sVt8B"},"$DATE"],["span",{"class":"sZZnC"},".tar.gz"],["span",{"class":"sZZnC"}," /data/websopy/uploads\n"]],["span",{"class":"line","line":12},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":13},["span",{"class":"sJ8bj"},"# 保留最近 30 天的备份\n"]],["span",{"class":"line","line":14},["span",{"class":"sScJk"},"find"],["span",{"class":"sVt8B"}," $BACKUP_DIR "],["span",{"class":"sj4cs"},"-mtime"],["span",{"class":"sZZnC"}," +30"],["span",{"class":"sj4cs"}," -delete\n"]],["span",{"class":"line","line":15},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":16},["span",{"class":"sj4cs"},"echo"],["span",{"class":"sZZnC"}," \"备份完成: "],["span",{"class":"sVt8B"},"$DATE"],["span",{"class":"sZZnC"},"\"\n"]]]],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 设置定时任务(每天凌晨 3 点执行)\ncrontab -e\n# 添加行: 0 3 * * * /data/websopy/backup.sh >> /var/log/backup.log 2>&1\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 设置定时任务(每天凌晨 3 点执行)\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"crontab"],["span",{"class":"sj4cs"}," -e\n"]],["span",{"class":"line","line":3},["span",{"class":"sJ8bj"},"# 添加行: 0 3 * * * /data/websopy/backup.sh >> /var/log/backup.log 2>&1\n"]]]],["h2",{"id":"常见问题"},"🐛 常见问题"],["h3",{"id":"q-服务启动失败"},"Q: 服务启动失败?"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看日志\ndocker-compose logs -f\n\n# 检查端口占用\nnetstat -tlnp | grep -E ''80|443|5432|6379''\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看日志\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sj4cs"}," -f\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 检查端口占用\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"netstat"],["span",{"class":"sj4cs"}," -tlnp"],["span",{"class":"szBVR"}," |"],["span",{"class":"sScJk"}," grep"],["span",{"class":"sj4cs"}," -E"],["span",{"class":"sZZnC"}," ''80|443|5432|6379''\n"]]]],["h3",{"id":"q-内存不足"},"Q: 内存不足?"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看内存使用\ndocker stats\n\n# 增加 swap\nsudo fallocate -l 4G /swapfile\nsudo chmod 600 /swapfile\nsudo mkswap /swapfile\nsudo swapon /swapfile\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看内存使用\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," stats\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 增加 swap\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," fallocate"],["span",{"class":"sj4cs"}," -l"],["span",{"class":"sZZnC"}," 4G"],["span",{"class":"sZZnC"}," /swapfile\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," chmod"],["span",{"class":"sj4cs"}," 600"],["span",{"class":"sZZnC"}," /swapfile\n"]],["span",{"class":"line","line":7},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," mkswap"],["span",{"class":"sZZnC"}," /swapfile\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," swapon"],["span",{"class":"sZZnC"}," /swapfile\n"]]]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是私有化部署","depth":2,"text":"🏠 什么是私有化部署?"},{"id":"系统要求","depth":2,"text":"📋 系统要求","children":[{"id":"最低配置","depth":3,"text":"最低配置"},{"id":"推荐配置","depth":3,"text":"推荐配置"},{"id":"软件依赖","depth":3,"text":"软件依赖"}]},{"id":"开始部署","depth":2,"text":"🚀 开始部署","children":[{"id":"第一步准备服务器","depth":3,"text":"第一步:准备服务器"},{"id":"第二步下载部署包","depth":3,"text":"第二步:下载部署包"},{"id":"第三步配置环境","depth":3,"text":"第三步:配置环境"},{"id":"第四步启动服务","depth":3,"text":"第四步:启动服务"},{"id":"第五步访问平台","depth":3,"text":"第五步:访问平台"}]},{"id":"https-配置","depth":2,"text":"🔒 HTTPS 配置","children":[{"id":"使用-lets-encrypt推荐","depth":3,"text":"使用 Let''s Encrypt(推荐)"}]},{"id":"备份策略","depth":2,"text":"💾 备份策略","children":[{"id":"自动备份脚本","depth":3,"text":"自动备份脚本"}]},{"id":"常见问题","depth":2,"text":"🐛 常见问题","children":[{"id":"q-服务启动失败","depth":3,"text":"Q: 服务启动失败?"},{"id":"q-内存不足","depth":3,"text":"Q: 内存不足?"}]}]}}', 'Docker Compose 一键部署,HTTPS 配置、备份策略与版本升级。', 'md', '{"category":"deploy","order":2}', 'true', '/docs/deploy/private-deploy', '{"title":"私有化部署完全指南","description":"Docker Compose 一键部署,HTTPS 配置、备份策略与版本升级。"}', 'docs/deploy/private-deploy', 'cEk_JZvZaEC-Q8JKLtEhR4k3b9LNnnRxxcs2pGB9R8w'); -- cEk_JZvZaEC-Q8JKLtEhR4k3b9LNnnRxxcs2pGB9R8w +INSERT INTO _content_docs VALUES ('docs/docs/deploy/upgrade.md', '版本升级与回滚', '{"type":"minimark","value":[["h1",{"id":"版本升级与回滚"},"版本升级与回滚"],["blockquote",{},["p",{},"平滑升级生产环境,数据库迁移方案,紧急回滚操作手册。"]],["h2",{"id":"️-升级前必读"},"⚠️ 升级前必读"],["h3",{"id":"重要检查清单"},"重要检查清单"],["ul",{"className":["contains-task-list"]},["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 备份数据库"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 查阅版本更新日志"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 在测试环境验证"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 确认回滚方案"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 通知相关人员"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 选择低峰期执行"]],["h3",{"id":"版本兼容性"},"版本兼容性"],["table",{},["thead",{},["tr",{},["th",{},"当前版本"],["th",{},"可直接升级到"]]],["tbody",{},["tr",{},["td",{},"2.0.x"],["td",{},"2.1.x"]],["tr",{},["td",{},"2.1.x"],["td",{},"2.2.x, 2.3.x"]],["tr",{},["td",{},"2.2.x"],["td",{},"2.3.x"]],["tr",{},["td",{},"1.x"],["td",{},"需要先升级到 2.0"]]]],["h2",{"id":"升级步骤"},"🚀 升级步骤"],["h3",{"id":"准备工作"},"准备工作"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 1. 进入部署目录\ncd ~/websopy-deploy\n\n# 2. 备份当前版本配置\ncp docker-compose.yml docker-compose.yml.bak\ncp .env .env.bak\n\n# 3. 备份数据库(必须!)\ndocker-compose exec postgres pg_dump -U websopy > backups/db_backup_$(date +%Y%m%d).sql\n\n# 4. 备份上传文件\ntar -czf backups/uploads_$(date +%Y%m%d).tar.gz -C /data/websopy uploads/\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 1. 进入部署目录\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"cd"],["span",{"class":"sZZnC"}," ~/websopy-deploy\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 2. 备份当前版本配置\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"cp"],["span",{"class":"sZZnC"}," docker-compose.yml"],["span",{"class":"sZZnC"}," docker-compose.yml.bak\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"cp"],["span",{"class":"sZZnC"}," .env"],["span",{"class":"sZZnC"}," .env.bak\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"},"# 3. 备份数据库(必须!)\n"]],["span",{"class":"line","line":9},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," pg_dump"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," >"],["span",{"class":"sZZnC"}," backups/db_backup_"],["span",{"class":"sVt8B"},"$("],["span",{"class":"sScJk"},"date"],["span",{"class":"sZZnC"}," +%Y%m%d"],["span",{"class":"sVt8B"},")"],["span",{"class":"sZZnC"},".sql\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"},"# 4. 备份上传文件\n"]],["span",{"class":"line","line":12},["span",{"class":"sScJk"},"tar"],["span",{"class":"sj4cs"}," -czf"],["span",{"class":"sZZnC"}," backups/uploads_"],["span",{"class":"sVt8B"},"$("],["span",{"class":"sScJk"},"date"],["span",{"class":"sZZnC"}," +%Y%m%d"],["span",{"class":"sVt8B"},")"],["span",{"class":"sZZnC"},".tar.gz"],["span",{"class":"sj4cs"}," -C"],["span",{"class":"sZZnC"}," /data/websopy"],["span",{"class":"sZZnC"}," uploads/\n"]]]],["h3",{"id":"执行升级"},"执行升级"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 1. 停止服务\ndocker-compose down\n\n# 2. 拉取新版本镜像\ndocker-compose pull\n\n# 3. 更新代码(如果使用 git 部署)\ngit fetch origin\ngit checkout v2.3.0\n\n# 4. 检查新版本配置变更\ngit diff v2.2.0 v2.3.0 -- .env.example\n\n# 5. 合并配置变更\nnano .env\n\n# 6. 启动服务\ndocker-compose up -d\n\n# 7. 执行数据库迁移\ndocker-compose run --rm api websopy migrate\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 1. 停止服务\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," down\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 2. 拉取新版本镜像\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," pull\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 3. 更新代码(如果使用 git 部署)\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," fetch"],["span",{"class":"sZZnC"}," origin\n"]],["span",{"class":"line","line":9},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," checkout"],["span",{"class":"sZZnC"}," v2.3.0\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"},"# 4. 检查新版本配置变更\n"]],["span",{"class":"line","line":12},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," diff"],["span",{"class":"sZZnC"}," v2.2.0"],["span",{"class":"sZZnC"}," v2.3.0"],["span",{"class":"sj4cs"}," --"],["span",{"class":"sZZnC"}," .env.example\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"sJ8bj"},"# 5. 合并配置变更\n"]],["span",{"class":"line","line":15},["span",{"class":"sScJk"},"nano"],["span",{"class":"sZZnC"}," .env\n"]],["span",{"class":"line","line":16},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":17},["span",{"class":"sJ8bj"},"# 6. 启动服务\n"]],["span",{"class":"line","line":18},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]],["span",{"class":"line","line":19},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":20},["span",{"class":"sJ8bj"},"# 7. 执行数据库迁移\n"]],["span",{"class":"line","line":21},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," run"],["span",{"class":"sj4cs"}," --rm"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," migrate\n"]]]],["h3",{"id":"验证升级"},"验证升级"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 检查服务状态\ndocker-compose ps\n\n# 检查 API 健康\ncurl http://localhost:3000/api/health\n\n# 检查版本号\ndocker-compose exec api websopy --version\n\n# 查看迁移日志\ndocker-compose logs api | grep -i migrate\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 检查服务状态\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 检查 API 健康\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"curl"],["span",{"class":"sZZnC"}," http://localhost:3000/api/health\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 检查版本号\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sj4cs"}," --version\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"# 查看迁移日志\n"]],["span",{"class":"line","line":11},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sZZnC"}," api"],["span",{"class":"szBVR"}," |"],["span",{"class":"sScJk"}," grep"],["span",{"class":"sj4cs"}," -i"],["span",{"class":"sZZnC"}," migrate\n"]]]],["h2",{"id":"数据库迁移"},"🔧 数据库迁移"],["h3",{"id":"手动迁移"},"手动迁移"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 查看待执行迁移\ndocker-compose run --rm api websopy migrate:status\n\n# 执行迁移\ndocker-compose run --rm api websopy migrate\n\n# 回滚上一个迁移\ndocker-compose run --rm api websopy migrate:rollback\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 查看待执行迁移\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," run"],["span",{"class":"sj4cs"}," --rm"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," migrate:status\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 执行迁移\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," run"],["span",{"class":"sj4cs"}," --rm"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," migrate\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 回滚上一个迁移\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," run"],["span",{"class":"sj4cs"}," --rm"],["span",{"class":"sZZnC"}," api"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," migrate:rollback\n"]]]],["h2",{"id":"️-紧急回滚"},"⤵️ 紧急回滚"],["h3",{"id":"自动回滚"},"自动回滚"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 如果启动失败,查看错误\ndocker-compose logs api\n\n# 回滚到上一个版本\ndocker-compose down\ngit checkout v2.2.0\ndocker-compose pull\ndocker-compose up -d\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 如果启动失败,查看错误\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," logs"],["span",{"class":"sZZnC"}," api\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 回滚到上一个版本\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," down\n"]],["span",{"class":"line","line":6},["span",{"class":"sScJk"},"git"],["span",{"class":"sZZnC"}," checkout"],["span",{"class":"sZZnC"}," v2.2.0\n"]],["span",{"class":"line","line":7},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," pull\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]]]],["h3",{"id":"恢复数据库"},"恢复数据库"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 停止服务\ndocker-compose down\n\n# 删除新数据库\ndocker-compose exec postgres dropdb -U websopy websopy\n\n# 创建空数据库\ndocker-compose exec postgres createdb -U websopy websopy\n\n# 恢复备份\ndocker exec -i $(docker-compose ps -q postgres) psql -U websopy < backups/db_backup_20240115.sql\n\n# 启动服务\ndocker-compose up -d\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 停止服务\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," down\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 删除新数据库\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," dropdb"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," websopy\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 创建空数据库\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sZZnC"}," createdb"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"sZZnC"}," websopy\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"# 恢复备份\n"]],["span",{"class":"line","line":11},["span",{"class":"sScJk"},"docker"],["span",{"class":"sZZnC"}," exec"],["span",{"class":"sj4cs"}," -i"],["span",{"class":"sVt8B"}," $("],["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," ps"],["span",{"class":"sj4cs"}," -q"],["span",{"class":"sZZnC"}," postgres"],["span",{"class":"sVt8B"},") "],["span",{"class":"sZZnC"},"psql"],["span",{"class":"sj4cs"}," -U"],["span",{"class":"sZZnC"}," websopy"],["span",{"class":"szBVR"}," <"],["span",{"class":"sZZnC"}," backups/db_backup_20240115.sql\n"]],["span",{"class":"line","line":12},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":13},["span",{"class":"sJ8bj"},"# 启动服务\n"]],["span",{"class":"line","line":14},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," up"],["span",{"class":"sj4cs"}," -d\n"]]]],["h2",{"id":"版本更新日志"},"📊 版本更新日志"],["h3",{"id":"v230最新"},"v2.3.0(最新)"],["p",{},["strong",{},"新增功能:"]],["ul",{},["li",{},"🚀 AI 流式输出优化,延迟降低 50%"],["li",{},"📊 新增数据看板组件"],["li",{},"🔔 支持自定义 Webhook 事件"]],["p",{},["strong",{},"Breaking Changes:"]],["ul",{},["li",{},"⚠️ API ",["code",{},"/ai/chat"]," 端点参数变更"],["li",{},"⚠️ 环境变量 ",["code",{},"AI_MODEL"]," 重命名为 ",["code",{},"DEFAULT_MODEL"]]],["h3",{"id":"v220"},"v2.2.0"],["p",{},["strong",{},"新增功能:"]],["ul",{},["li",{},"💬 多语言支持"],["li",{},"📱 移动端优化"],["li",{},"🔐 SSO 单点登录"]],["h3",{"id":"v210"},"v2.1.0"],["p",{},["strong",{},"新增功能:"]],["ul",{},["li",{},"🤖 AI Agent 功能"],["li",{},"📚 RAG 知识库"],["li",{},"⚡ 工作流自动化"]],["h2",{"id":"测试环境验证"},"🧪 测试环境验证"],["h3",{"id":"测试清单"},"测试清单"],["ul",{"className":["contains-task-list"]},["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 首页访问正常"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 用户登录/注册"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 主要功能操作"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," API 接口调用"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," Webhook 接收"],["li",{"className":["task-list-item"]},["input",{"disabled":true,"type":"checkbox"}]," 性能无明显下降"]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-迁移失败怎么办"},"Q: 迁移失败怎么办?"],["ol",{},["li",{},"停止所有服务"],["li",{},"恢复数据库备份"],["li",{},"检查迁移脚本错误"],["li",{},"联系技术支持"]],["h3",{"id":"q-镜像拉取失败"},"Q: 镜像拉取失败?"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 使用国内镜像源\nnano /etc/docker/daemon.json\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 使用国内镜像源\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"nano"],["span",{"class":"sZZnC"}," /etc/docker/daemon.json\n"]]]],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"{\n \"registry-mirrors\": [\"https://mirror.ccs.tencentyun.com\"]\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"}," \"registry-mirrors\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"sZZnC"},"\"https://mirror.ccs.tencentyun.com\""],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"}\n"]]]],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"sudo systemctl restart docker\ndocker-compose pull\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"sudo"],["span",{"class":"sZZnC"}," systemctl"],["span",{"class":"sZZnC"}," restart"],["span",{"class":"sZZnC"}," docker\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"docker-compose"],["span",{"class":"sZZnC"}," pull\n"]]]],["style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"️-升级前必读","depth":2,"text":"⚠️ 升级前必读","children":[{"id":"重要检查清单","depth":3,"text":"重要检查清单"},{"id":"版本兼容性","depth":3,"text":"版本兼容性"}]},{"id":"升级步骤","depth":2,"text":"🚀 升级步骤","children":[{"id":"准备工作","depth":3,"text":"准备工作"},{"id":"执行升级","depth":3,"text":"执行升级"},{"id":"验证升级","depth":3,"text":"验证升级"}]},{"id":"数据库迁移","depth":2,"text":"🔧 数据库迁移","children":[{"id":"手动迁移","depth":3,"text":"手动迁移"}]},{"id":"️-紧急回滚","depth":2,"text":"⤵️ 紧急回滚","children":[{"id":"自动回滚","depth":3,"text":"自动回滚"},{"id":"恢复数据库","depth":3,"text":"恢复数据库"}]},{"id":"版本更新日志","depth":2,"text":"📊 版本更新日志","children":[{"id":"v230最新","depth":3,"text":"v2.3.0(最新)"},{"id":"v220","depth":3,"text":"v2.2.0"},{"id":"v210","depth":3,"text":"v2.1.0"}]},{"id":"测试环境验证","depth":2,"text":"🧪 测试环境验证","children":[{"id":"测试清单","depth":3,"text":"测试清单"}]},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-迁移失败怎么办","depth":3,"text":"Q: 迁移失败怎么办?"},{"id":"q-镜像拉取失败","depth":3,"text":"Q: 镜像拉取失败?"}]}]}}', '平滑升级生产环境,数据库迁移方案,紧急回滚操作手册。', 'md', '{"category":"deploy","order":3}', 'true', '/docs/deploy/upgrade', '{"title":"版本升级与回滚","description":"平滑升级生产环境,数据库迁移方案,紧急回滚操作手册。"}', 'docs/deploy/upgrade', '11srh3Gbi3w-1nElqY5llMQiImDxTsYpCUFtqmAQbFA'); -- 11srh3Gbi3w-1nElqY5llMQiImDxTsYpCUFtqmAQbFA +INSERT INTO _content_docs VALUES ('docs/docs/getting-started/apikey.md', 'API Key 创建与管理', '{"type":"minimark","value":[["h1",{"id":"api-key-创建与管理"},"API Key 创建与管理"],["blockquote",{},["p",{},"在控制台创建 API Key,了解权限范围与速率限制,安全使用建议。"]],["h2",{"id":"什么是-api-key"},"🔑 什么是 API Key?"],["p",{},"API Key 是调用 Websopy API 的凭证,类似于「数字身份证」,用于:"],["ul",{},["li",{},"✅ 身份认证 - 证明你是平台用户"],["li",{},"✅ 权限控制 - 控制可以访问哪些资源"],["li",{},"✅ 用量统计 - 记录 API 调用情况"],["li",{},"✅ 计费依据 - 按使用量进行计费"]],["h2",{"id":"创建-api-key"},"📋 创建 API Key"],["h3",{"id":"步骤-1进入控制台"},"步骤 1:进入控制台"],["ol",{},["li",{},"登录 ",["a",{"href":"https://console.websopy.com","rel":["nofollow"]},"Websopy 控制台"]],["li",{},"导航到 ",["strong",{},"开发者中心 → API Key"]],["li",{},"点击 ",["strong",{},"创建新 Key"]]],["h3",{"id":"步骤-2配置-key"},"步骤 2:配置 Key"],["table",{},["thead",{},["tr",{},["th",{},"配置项"],["th",{},"说明"]]],["tbody",{},["tr",{},["td",{},["strong",{},"名称"]],["td",{},"给 Key 取个易识别的名字,如「生产环境」「测试用」"]],["tr",{},["td",{},["strong",{},"权限范围"]],["td",{},"选择 Key 允许的操作(见下文)"]],["tr",{},["td",{},["strong",{},"有效期"]],["td",{},"设置过期时间(可选)"]],["tr",{},["td",{},["strong",{},"IP 白名单"]],["td",{},"限制只有指定 IP 才能使用(可选)"]]]],["h3",{"id":"步骤-3保存-key"},"步骤 3:保存 Key"],["p",{},"⚠️ ",["strong",{},"重要"],":API Key 只显示一次,请立即:"],["ol",{},["li",{},"复制保存到安全位置"],["li",{},"设置环境变量"]],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# Linux/macOS\necho ''export WEBSOPY_API_KEY=\"ws_live_xxxxx\"'' >> ~/.bashrc\nsource ~/.bashrc\n\n# Windows PowerShell\n[Environment]::SetEnvironmentVariable(\"WEBSOPY_API_KEY\", \"ws_live_xxxxx\", \"User\")\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# Linux/macOS\n"]],["span",{"class":"line","line":2},["span",{"class":"sj4cs"},"echo"],["span",{"class":"sZZnC"}," ''export WEBSOPY_API_KEY=\"ws_live_xxxxx\"''"],["span",{"class":"szBVR"}," >>"],["span",{"class":"sZZnC"}," ~/.bashrc\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"},"source"],["span",{"class":"sZZnC"}," ~/.bashrc\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"},"# Windows PowerShell\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"[Environment]::SetEnvironmentVariable("],["span",{"class":"sScJk"},"\"WEBSOPY_API_KEY\""],["span",{"class":"sScJk"},","],["span",{"class":"sZZnC"}," \"ws_live_xxxxx\","],["span",{"class":"sZZnC"}," \"User\""],["span",{"class":"sVt8B"},")\n"]]]],["h2",{"id":"️-权限范围"},"🛡️ 权限范围"],["h3",{"id":"可用权限"},"可用权限"],["table",{},["thead",{},["tr",{},["th",{},"权限"],["th",{},"说明"],["th",{},"适用场景"]]],["tbody",{},["tr",{},["td",{},["code",{},"user:read"]],["td",{},"读取用户信息"],["td",{},"数据展示"]],["tr",{},["td",{},["code",{},"user:write"]],["td",{},"修改用户信息"],["td",{},"用户管理"]],["tr",{},["td",{},["code",{},"project:read"]],["td",{},"读取项目"],["td",{},"数据展示"]],["tr",{},["td",{},["code",{},"project:write"]],["td",{},"创建/修改/删除项目"],["td",{},"项目管理"]],["tr",{},["td",{},["code",{},"storage:read"]],["td",{},"读取文件"],["td",{},"文件读取"]],["tr",{},["td",{},["code",{},"storage:write"]],["td",{},"上传/删除文件"],["td",{},"文件管理"]],["tr",{},["td",{},["code",{},"ai:agent"]],["td",{},"使用 AI 智能体"],["td",{},"AI 功能"]],["tr",{},["td",{},["code",{},"ai:knowledge"]],["td",{},"管理知识库"],["td",{},"知识库管理"]],["tr",{},["td",{},["code",{},"payment:read"]],["td",{},"读取账单"],["td",{},"账单查看"]],["tr",{},["td",{},["code",{},"admin:*"]],["td",{},"所有权限"],["td",{},"⚠️ 仅管理员"]]]],["h3",{"id":"权限组合"},"权限组合"],["p",{},"推荐按最小权限原则配置:"],["pre",{"className":"language-json shiki shiki-themes github-light github-dark","code":"// 只读权限(安全)\n{\n \"permissions\": [\"user:read\", \"project:read\", \"storage:read\"]\n}\n\n// 读写权限(一般开发)\n{\n \"permissions\": [\"user:read\", \"user:write\", \"project:*\", \"storage:*\"]\n}\n\n// AI 功能\n{\n \"permissions\": [\"ai:agent\", \"ai:knowledge\"]\n}\n","language":"json","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 只读权限(安全)\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":3},["span",{"class":"sj4cs"}," \"permissions\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"sZZnC"},"\"user:read\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"project:read\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"storage:read\""],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":5},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"},"// 读写权限(一般开发)\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":8},["span",{"class":"sj4cs"}," \"permissions\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"sZZnC"},"\"user:read\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"user:write\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"project:*\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"storage:*\""],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":10},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":11},["span",{"class":"sJ8bj"},"// AI 功能\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"{\n"]],["span",{"class":"line","line":13},["span",{"class":"sj4cs"}," \"permissions\""],["span",{"class":"sVt8B"},": ["],["span",{"class":"sZZnC"},"\"ai:agent\""],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"\"ai:knowledge\""],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"ip-白名单"},"🚫 IP 白名单"],["p",{},"增强安全性,限制只有指定 IP 可以使用 Key:"],["ol",{},["li",{},"创建/编辑 Key 时开启「IP 白名单」"],["li",{},"添加允许的 IP 地址或 CIDR 范围"]],["pre",{"className":["language-text"],"code":"# 支持的格式\n203.0.113.1 # 单个 IP\n203.0.113.0/24 # IP 段\n203.0.113.1,198.51.100.0/24 # 多个,用逗号分隔\n","language":"text","meta":""},["code",{"__ignoreMap":""},"# 支持的格式\n203.0.113.1 # 单个 IP\n203.0.113.0/24 # IP 段\n203.0.113.1,198.51.100.0/24 # 多个,用逗号分隔\n"]],["h2",{"id":"️-速率限制"},"⏱️ 速率限制"],["table",{},["thead",{},["tr",{},["th",{},"套餐"],["th",{},"请求限制"]]],["tbody",{},["tr",{},["td",{},"免费版"],["td",{},"100 次/分钟"]],["tr",{},["td",{},"专业版"],["td",{},"1,000 次/分钟"]],["tr",{},["td",{},"企业版"],["td",{},"10,000 次/分钟"]]]],["h3",{"id":"查看当前用量"},"查看当前用量"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const client = new WebsopyClient({\n apiKey: process.env.WEBSOPY_API_KEY\n})\n\n// 获取当前配额\nconst quota = await client.account.getQuota()\nconsole.log(''今日剩余:'', quota.remaining)\nconsole.log(''重置时间:'', quota.resetAt)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":4},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"},"// 获取当前配额\n"]],["span",{"class":"line","line":6},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," quota"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.account."],["span",{"class":"sScJk"},"getQuota"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''今日剩余:''"],["span",{"class":"sVt8B"},", quota.remaining)\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''重置时间:''"],["span",{"class":"sVt8B"},", quota.resetAt)\n"]]]],["h3",{"id":"处理限流"},"处理限流"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"async function callWithRetry(fn, maxRetries = 3) {\n for (let i = 0; i < maxRetries; i++) {\n try {\n return await fn()\n } catch (error) {\n if (error.code === ''RATE_LIMIT_EXCEEDED'') {\n // 等待后重试\n await sleep(error.retryAfter * 1000)\n continue\n }\n throw error\n }\n }\n}\n\nfunction sleep(ms) {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," callWithRetry"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"fn"],["span",{"class":"sVt8B"},", "],["span",{"class":"s4XuR"},"maxRetries"],["span",{"class":"szBVR"}," ="],["span",{"class":"sj4cs"}," 3"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"}," for"],["span",{"class":"sVt8B"}," ("],["span",{"class":"szBVR"},"let"],["span",{"class":"sVt8B"}," i "],["span",{"class":"szBVR"},"="],["span",{"class":"sj4cs"}," 0"],["span",{"class":"sVt8B"},"; i "],["span",{"class":"szBVR"},"<"],["span",{"class":"sVt8B"}," maxRetries; i"],["span",{"class":"szBVR"},"++"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"}," try"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"}," return"],["span",{"class":"szBVR"}," await"],["span",{"class":"sScJk"}," fn"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"catch"],["span",{"class":"sVt8B"}," (error) {\n"]],["span",{"class":"line","line":6},["span",{"class":"szBVR"}," if"],["span",{"class":"sVt8B"}," (error.code "],["span",{"class":"szBVR"},"==="],["span",{"class":"sZZnC"}," ''RATE_LIMIT_EXCEEDED''"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"}," // 等待后重试\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"}," await"],["span",{"class":"sScJk"}," sleep"],["span",{"class":"sVt8B"},"(error.retryAfter "],["span",{"class":"szBVR"},"*"],["span",{"class":"sj4cs"}," 1000"],["span",{"class":"sVt8B"},")\n"]],["span",{"class":"line","line":9},["span",{"class":"szBVR"}," continue\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":11},["span",{"class":"szBVR"}," throw"],["span",{"class":"sVt8B"}," error\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":15},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":16},["span",{"class":"szBVR"},"function"],["span",{"class":"sScJk"}," sleep"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"ms"],["span",{"class":"sVt8B"},") {\n"]],["span",{"class":"line","line":17},["span",{"class":"szBVR"}," return"],["span",{"class":"szBVR"}," new"],["span",{"class":"sj4cs"}," Promise"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"resolve"],["span",{"class":"szBVR"}," =>"],["span",{"class":"sScJk"}," setTimeout"],["span",{"class":"sVt8B"},"(resolve, ms))\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"安全最佳实践"},"🔐 安全最佳实践"],["h3",{"id":"推荐做法"},"✅ 推荐做法"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 1. 使用环境变量,不硬编码\nconst client = new WebsopyClient({\n apiKey: process.env.WEBSOPY_API_KEY // ✅ 正确\n})\n\n// ❌ 危险:硬编码在代码中\nconst client = new WebsopyClient({\n apiKey: ''ws_live_xxxxx'' // ❌ 危险\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 1. 使用环境变量,不硬编码\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sJ8bj"}," // ✅ 正确\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"})\n"]],["span",{"class":"line","line":5},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":6},["span",{"class":"sJ8bj"},"// ❌ 危险:硬编码在代码中\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," apiKey: "],["span",{"class":"sZZnC"},"''ws_live_xxxxx''"],["span",{"class":"sJ8bj"}," // ❌ 危险\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"})\n"]]]],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 2. 区分不同环境的 Key\nconst client = new WebsopyClient({\n apiKey: process.env.NODE_ENV === ''production'' \n ? process.env.WEBSOPY_API_KEY_PROD \n : process.env.WEBSOPY_API_KEY_DEV\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 2. 区分不同环境的 Key\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"NODE_ENV"],["span",{"class":"szBVR"}," ==="],["span",{"class":"sZZnC"}," ''production''"],["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"}," ?"],["span",{"class":"sVt8B"}," process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY_PROD"],["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"}," :"],["span",{"class":"sVt8B"}," process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY_DEV\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"})\n"]]]],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 3. 前端使用受限 Key\nconst client = new WebsopyClient({\n apiKey: process.env.WEBSOPY_API_KEY_PUBLIC,\n // 前端 Key 应该只开只读权限\n allowedMethods: [''user.getProfile'', ''project.list'']\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 3. 前端使用受限 Key\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY_PUBLIC"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"}," // 前端 Key 应该只开只读权限\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," allowedMethods: ["],["span",{"class":"sZZnC"},"''user.getProfile''"],["span",{"class":"sVt8B"},", "],["span",{"class":"sZZnC"},"''project.list''"],["span",{"class":"sVt8B"},"]\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"避免事项"},"❌ 避免事项"],["ol",{},["li",{},["strong",{},"不要"],"将 Key 提交到代码仓库"],["li",{},["strong",{},"不要"],"在前端暴露有写权限的 Key"],["li",{},["strong",{},"不要"],"使用同一个 Key 处理所有业务"],["li",{},["strong",{},"不要"],"通过 URL 参数传递 Key"]],["pre",{"className":"language-gitignore shiki shiki-themes github-light github-dark","code":"# .gitignore\n.env\n.env.*\n*.local\n","language":"gitignore","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"# .gitignore\n"]],["span",{"class":"line","line":2},["span",{},".env\n"]],["span",{"class":"line","line":3},["span",{},".env.*\n"]],["span",{"class":"line","line":4},["span",{},"*.local\n"]]]],["h2",{"id":"key-轮换"},"🔄 Key 轮换"],["p",{},"定期更换 API Key 是个好习惯:"],["ol",{},["li",{},"在控制台创建新 Key"],["li",{},"更新所有使用旧 Key 的地方"],["li",{},"验证新 Key 正常工作"],["li",{},"禁用或删除旧 Key"]],["h2",{"id":"审计日志"},"📊 审计日志"],["p",{},"在控制台查看 API Key 的使用记录:"],["ul",{},["li",{},"调用时间、频率"],["li",{},"调用的接口"],["li",{},"请求来源 IP"],["li",{},"错误情况"]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"什么是-api-key","depth":2,"text":"🔑 什么是 API Key?"},{"id":"创建-api-key","depth":2,"text":"📋 创建 API Key","children":[{"id":"步骤-1进入控制台","depth":3,"text":"步骤 1:进入控制台"},{"id":"步骤-2配置-key","depth":3,"text":"步骤 2:配置 Key"},{"id":"步骤-3保存-key","depth":3,"text":"步骤 3:保存 Key"}]},{"id":"️-权限范围","depth":2,"text":"🛡️ 权限范围","children":[{"id":"可用权限","depth":3,"text":"可用权限"},{"id":"权限组合","depth":3,"text":"权限组合"}]},{"id":"ip-白名单","depth":2,"text":"🚫 IP 白名单"},{"id":"️-速率限制","depth":2,"text":"⏱️ 速率限制","children":[{"id":"查看当前用量","depth":3,"text":"查看当前用量"},{"id":"处理限流","depth":3,"text":"处理限流"}]},{"id":"安全最佳实践","depth":2,"text":"🔐 安全最佳实践","children":[{"id":"推荐做法","depth":3,"text":"✅ 推荐做法"},{"id":"避免事项","depth":3,"text":"❌ 避免事项"}]},{"id":"key-轮换","depth":2,"text":"🔄 Key 轮换"},{"id":"审计日志","depth":2,"text":"📊 审计日志"}]}}', '在控制台创建 API Key,了解权限范围与速率限制,安全使用建议。', 'md', '{"category":"getting-started","order":3}', 'true', '/docs/getting-started/apikey', '{"title":"API Key 创建与管理","description":"在控制台创建 API Key,了解权限范围与速率限制,安全使用建议。"}', 'docs/getting-started/apikey', 'fQFIkHHXSPhhlV3j4D80tdOAwNTjeCDNIiP8ku6c2Dc'); -- fQFIkHHXSPhhlV3j4D80tdOAwNTjeCDNIiP8ku6c2Dc +INSERT INTO _content_docs VALUES ('docs/docs/getting-started/quickstart.md', '5 分钟快速上手', '{"type":"minimark","value":[["h1",{"id":"_5-分钟快速上手"},"5 分钟快速上手"],["blockquote",{},["p",{},"本教程将带你完成 Websopy SDK 的安装、配置,并发送你的第一个 API 请求。"]],["h2",{"id":"前提条件"},"📋 前提条件"],["ul",{},["li",{},"Node.js 16.x 或更高版本"],["li",{},"npm 8.x 或 yarn 1.22+"],["li",{},"一个 Websopy 账户(",["a",{"href":"https://websopy.com/register","rel":["nofollow"]},"立即注册"],")"]],["h2",{"id":"开始"},"🚀 开始"],["h3",{"id":"第一步安装-sdk"},"第一步:安装 SDK"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"# 使用 npm\nnpm install @websopy/sdk\n\n# 或使用 yarn\nyarn add @websopy/sdk\n\n# 或使用 pnpm\npnpm add @websopy/sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"# 使用 npm\n"]],["span",{"class":"line","line":2},["span",{"class":"sScJk"},"npm"],["span",{"class":"sZZnC"}," install"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"# 或使用 yarn\n"]],["span",{"class":"line","line":5},["span",{"class":"sScJk"},"yarn"],["span",{"class":"sZZnC"}," add"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"# 或使用 pnpm\n"]],["span",{"class":"line","line":8},["span",{"class":"sScJk"},"pnpm"],["span",{"class":"sZZnC"}," add"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]]]],["h3",{"id":"第二步获取-api-key"},"第二步:获取 API Key"],["ol",{},["li",{},"登录 ",["a",{"href":"https://console.websopy.com","rel":["nofollow"]},"Websopy 控制台"]],["li",{},"进入 ",["strong",{},"开发者中心 → API Key"]],["li",{},"点击 ",["strong",{},"创建新 Key"]],["li",{},"选择权限范围(建议先选择「只读」权限测试)"],["li",{},"复制生成的 Key(注意:Key 只显示一次,请妥善保存)"]],["h3",{"id":"第三步初始化客户端"},"第三步:初始化客户端"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WebsopyClient } from ''@websopy/sdk''\n\nconst client = new WebsopyClient({\n apiKey: ''your-api-key-here'',\n // 可选:指定 API 端点\n baseUrl: ''https://api.websopy.com/v1''\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," apiKey: "],["span",{"class":"sZZnC"},"''your-api-key-here''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"}," // 可选:指定 API 端点\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," baseUrl: "],["span",{"class":"sZZnC"},"''https://api.websopy.com/v1''\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"第四步发送第一个请求"},"第四步:发送第一个请求"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"async function main() {\n try {\n // 获取用户信息\n const user = await client.user.getProfile()\n console.log(''当前用户:'', user.name)\n \n // 创建第一个项目\n const project = await client.project.create({\n name: ''我的第一个项目'',\n description: ''通过 API 创建''\n })\n console.log(''项目创建成功:'', project.id)\n \n // 获取项目列表\n const projects = await client.project.list()\n console.log(''项目总数:'', projects.total)\n } catch (error) {\n console.error(''请求失败:'', error.message)\n }\n}\n\nmain()\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," main"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"}," try"],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":3},["span",{"class":"sJ8bj"}," // 获取用户信息\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," user"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.user."],["span",{"class":"sScJk"},"getProfile"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''当前用户:''"],["span",{"class":"sVt8B"},", user.name)\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"}," // 创建第一个项目\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," project"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"create"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," name: "],["span",{"class":"sZZnC"},"''我的第一个项目''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," description: "],["span",{"class":"sZZnC"},"''通过 API 创建''\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''项目创建成功:''"],["span",{"class":"sVt8B"},", project.id)\n"]],["span",{"class":"line","line":13},["span",{"class":"sVt8B"}," \n"]],["span",{"class":"line","line":14},["span",{"class":"sJ8bj"}," // 获取项目列表\n"]],["span",{"class":"line","line":15},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," projects"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"list"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''项目总数:''"],["span",{"class":"sVt8B"},", projects.total)\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"catch"],["span",{"class":"sVt8B"}," (error) {\n"]],["span",{"class":"line","line":18},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"error"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''请求失败:''"],["span",{"class":"sVt8B"},", error.message)\n"]],["span",{"class":"line","line":19},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":21},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":22},["span",{"class":"sScJk"},"main"],["span",{"class":"sVt8B"},"()\n"]]]],["h3",{"id":"第五步运行代码"},"第五步:运行代码"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"npx ts-node your-script.ts\n# 或\nnode your-script.js\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"npx"],["span",{"class":"sZZnC"}," ts-node"],["span",{"class":"sZZnC"}," your-script.ts\n"]],["span",{"class":"line","line":2},["span",{"class":"sJ8bj"},"# 或\n"]],["span",{"class":"line","line":3},["span",{"class":"sScJk"},"node"],["span",{"class":"sZZnC"}," your-script.js\n"]]]],["p",{},["strong",{},"预期输出:"]],["pre",{"className":["language-text"],"code":"当前用户: 张三\n项目创建成功: proj_abc123xyz\n项目总数: 5\n","language":"text"},["code",{"__ignoreMap":""},"当前用户: 张三\n项目创建成功: proj_abc123xyz\n项目总数: 5\n"]],["h2",{"id":"恭喜"},"🎉 恭喜!"],["p",{},"你已经成功发送了第一个 API 请求。接下来你可以:"],["ul",{},["li",{},"📖 继续阅读 ",["a",{"href":"/developer/docs/getting-started/apikey"},"API Key 创建与管理"]],["li",{},"🔌 查看 ",["a",{"href":"/developer/docs/api/rest-api"},"REST API 完整参考"]],["li",{},"🤖 尝试 ",["a",{"href":"/developer/docs/ai/agent"},"AI 智能体接入"]]],["h2",{"id":"️-常见问题"},"⚠️ 常见问题"],["h3",{"id":"q-报-invalid-api-key-错误"},"Q: 报 \"Invalid API Key\" 错误?"],["p",{},"检查以下几点:"],["ol",{},["li",{},"API Key 是否正确复制(不要有空格)"],["li",{},"Key 是否已过期或被禁用"],["li",{},"Key 的权限范围是否包含当前操作"]],["h3",{"id":"q-报-rate-limit-exceeded-错误"},"Q: 报 \"Rate Limit Exceeded\" 错误?"],["p",{},"免费账户默认 100 次/分钟。如需更高配额,在控制台升级套餐。"],["h3",{"id":"q-如何开启调试模式"},"Q: 如何开启调试模式?"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const client = new WebsopyClient({\n apiKey: ''your-api-key'',\n debug: true // 打印详细请求日志\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," apiKey: "],["span",{"class":"sZZnC"},"''your-api-key''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," debug: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sJ8bj"}," // 打印详细请求日志\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"相关资源"},"📚 相关资源"],["ul",{},["li",{},["a",{"href":"https://github.com/websopy/sdk","rel":["nofollow"]},"SDK 源码仓库"]],["li",{},["a",{"href":"https://github.com/websopy/examples","rel":["nofollow"]},"示例代码集合"]],["li",{},["a",{"href":"https://status.websopy.com","rel":["nofollow"]},"API 状态页"]]],["style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"前提条件","depth":2,"text":"📋 前提条件"},{"id":"开始","depth":2,"text":"🚀 开始","children":[{"id":"第一步安装-sdk","depth":3,"text":"第一步:安装 SDK"},{"id":"第二步获取-api-key","depth":3,"text":"第二步:获取 API Key"},{"id":"第三步初始化客户端","depth":3,"text":"第三步:初始化客户端"},{"id":"第四步发送第一个请求","depth":3,"text":"第四步:发送第一个请求"},{"id":"第五步运行代码","depth":3,"text":"第五步:运行代码"}]},{"id":"恭喜","depth":2,"text":"🎉 恭喜!"},{"id":"️-常见问题","depth":2,"text":"⚠️ 常见问题","children":[{"id":"q-报-invalid-api-key-错误","depth":3,"text":"Q: 报 \"Invalid API Key\" 错误?"},{"id":"q-报-rate-limit-exceeded-错误","depth":3,"text":"Q: 报 \"Rate Limit Exceeded\" 错误?"},{"id":"q-如何开启调试模式","depth":3,"text":"Q: 如何开启调试模式?"}]},{"id":"相关资源","depth":2,"text":"📚 相关资源"}]}}', '安装 Websopy SDK、配置客户端,并发送你的第一个 API 请求。', 'md', '{"category":"getting-started","order":1}', 'true', '/docs/getting-started/quickstart', '{"title":"5 分钟快速上手","description":"安装 Websopy SDK、配置客户端,并发送你的第一个 API 请求。"}', 'docs/getting-started/quickstart', '4575Hr8iOEk8iSu56Q0rFEwsSUvUlE6sWzPVgMB-77A'); -- 4575Hr8iOEk8iSu56Q0rFEwsSUvUlE6sWzPVgMB-77A +INSERT INTO _content_docs VALUES ('docs/docs/getting-started/sdk-installation.md', '安装 SDK 与初始化', '{"type":"minimark","value":[["h1",{"id":"安装-sdk-与初始化"},"安装 SDK 与初始化"],["blockquote",{},["p",{},"详细指南:安装 @websopy/sdk,配置 WebsopyClient,发送第一个 API 请求。"]],["h2",{"id":"sdk-概述"},"📦 SDK 概述"],["p",{},"Websopy 提供多种语言的 SDK:"],["table",{},["thead",{},["tr",{},["th",{},"语言"],["th",{},"SDK"],["th",{},"源码"]]],["tbody",{},["tr",{},["td",{},"JavaScript/TypeScript"],["td",{},["code",{},"@websopy/sdk"]],["td",{},["a",{"href":"https://github.com/websopy/sdk-js","rel":["nofollow"]},"GitHub"]]],["tr",{},["td",{},"Python"],["td",{},["code",{},"websopy-sdk"]],["td",{},["a",{"href":"https://github.com/websopy/sdk-python","rel":["nofollow"]},"GitHub"]]],["tr",{},["td",{},"Go"],["td",{},["code",{},"github.com/websopy/sdk-go"]],["td",{},["a",{"href":"https://github.com/websopy/sdk-go","rel":["nofollow"]},"GitHub"]]],["tr",{},["td",{},"Java"],["td",{},["code",{},"com.websopy:sdk"]],["td",{},["a",{"href":"https://github.com/websopy/sdk-java","rel":["nofollow"]},"GitHub"]]]]],["p",{},"本教程以 JavaScript/TypeScript 为例。"],["h2",{"id":"安装"},"🚀 安装"],["h3",{"id":"npm"},"npm"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"npm install @websopy/sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"npm"],["span",{"class":"sZZnC"}," install"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]]]],["h3",{"id":"yarn"},"yarn"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"yarn add @websopy/sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"yarn"],["span",{"class":"sZZnC"}," add"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]]]],["h3",{"id":"pnpm"},"pnpm"],["pre",{"className":"language-bash shiki shiki-themes github-light github-dark","code":"pnpm add @websopy/sdk\n","language":"bash","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sScJk"},"pnpm"],["span",{"class":"sZZnC"}," add"],["span",{"class":"sZZnC"}," @websopy/sdk\n"]]]],["h3",{"id":"cdn浏览器端"},"CDN(浏览器端)"],["pre",{"className":"language-html shiki shiki-themes github-light github-dark","code":"\n","language":"html","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sVt8B"},"<"],["span",{"class":"s9eBZ"},"script"],["span",{"class":"sScJk"}," src"],["span",{"class":"sVt8B"},"="],["span",{"class":"sZZnC"},"\"https://unpkg.com/@websopy/sdk/dist/websopy.min.js\""],["span",{"class":"sVt8B"},">\n"]]]],["h2",{"id":"️-初始化配置"},"⚙️ 初始化配置"],["h3",{"id":"基本配置"},"基本配置"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WebsopyClient } from ''@websopy/sdk''\n\nconst client = new WebsopyClient({\n apiKey: ''ws_live_xxxxxxxxxxxx'',\n // API 版本(可选,默认 v1)\n version: ''v1'',\n // 超时时间(毫秒)\n timeout: 30000,\n // 重试次数\n retries: 3\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," apiKey: "],["span",{"class":"sZZnC"},"''ws_live_xxxxxxxxxxxx''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sJ8bj"}," // API 版本(可选,默认 v1)\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," version: "],["span",{"class":"sZZnC"},"''v1''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"}," // 超时时间(毫秒)\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," timeout: "],["span",{"class":"sj4cs"},"30000"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":9},["span",{"class":"sJ8bj"}," // 重试次数\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," retries: "],["span",{"class":"sj4cs"},"3\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"})\n"]]]],["h3",{"id":"多环境配置"},"多环境配置"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const config = {\n // 开发环境\n dev: {\n apiKey: ''ws_test_xxxxx'',\n baseUrl: ''https://api-dev.websopy.com/v1''\n },\n // 生产环境\n prod: {\n apiKey: process.env.WEBSOPY_API_KEY,\n baseUrl: ''https://api.websopy.com/v1''\n }\n}\n\nconst client = new WebsopyClient(\n process.env.NODE_ENV === ''production'' ? config.prod : config.dev\n)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," config"],["span",{"class":"szBVR"}," ="],["span",{"class":"sVt8B"}," {\n"]],["span",{"class":"line","line":2},["span",{"class":"sJ8bj"}," // 开发环境\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," dev: {\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," apiKey: "],["span",{"class":"sZZnC"},"''ws_test_xxxxx''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," baseUrl: "],["span",{"class":"sZZnC"},"''https://api-dev.websopy.com/v1''\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," },\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"}," // 生产环境\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"}," prod: {\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," baseUrl: "],["span",{"class":"sZZnC"},"''https://api.websopy.com/v1''\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"}," }\n"]],["span",{"class":"line","line":12},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":13},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":14},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"(\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"}," process.env."],["span",{"class":"sj4cs"},"NODE_ENV"],["span",{"class":"szBVR"}," ==="],["span",{"class":"sZZnC"}," ''production''"],["span",{"class":"szBVR"}," ?"],["span",{"class":"sVt8B"}," config.prod "],["span",{"class":"szBVR"},":"],["span",{"class":"sVt8B"}," config.dev\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"},")\n"]]]],["h3",{"id":"环境变量"},"环境变量"],["p",{},"创建 ",["code",{},".env"]," 文件:"],["pre",{"className":"language-env shiki shiki-themes github-light github-dark","code":"WEBSOPY_API_KEY=ws_live_xxxxxxxxxxxx\nWEBSOPY_BASE_URL=https://api.websopy.com/v1\nWEBSOPY_TIMEOUT=30000\n","language":"env","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{},"WEBSOPY_API_KEY=ws_live_xxxxxxxxxxxx\n"]],["span",{"class":"line","line":2},["span",{},"WEBSOPY_BASE_URL=https://api.websopy.com/v1\n"]],["span",{"class":"line","line":3},["span",{},"WEBSOPY_TIMEOUT=30000\n"]]]],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import ''dotenv/config''\nimport { WebsopyClient } from ''@websopy/sdk''\n\nconst client = new WebsopyClient({\n apiKey: process.env.WEBSOPY_API_KEY,\n baseUrl: process.env.WEBSOPY_BASE_URL\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sZZnC"}," ''dotenv/config''\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," baseUrl: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_BASE_URL\n"]],["span",{"class":"line","line":7},["span",{"class":"sVt8B"},"})\n"]]]],["h2",{"id":"api-模块"},"📚 API 模块"],["p",{},"SDK 按功能模块组织:"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// 用户管理\nclient.user\n\n// 项目管理\nclient.project\n\n// 文件存储\nclient.storage\n\n// AI 功能\nclient.ai\n\n// 支付功能\nclient.payment\n\n// Webhook\nclient.webhook\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// 用户管理\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"},"client.user\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"// 项目管理\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"client.project\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"sJ8bj"},"// 文件存储\n"]],["span",{"class":"line","line":8},["span",{"class":"sVt8B"},"client.storage\n"]],["span",{"class":"line","line":9},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":10},["span",{"class":"sJ8bj"},"// AI 功能\n"]],["span",{"class":"line","line":11},["span",{"class":"sVt8B"},"client.ai\n"]],["span",{"class":"line","line":12},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":13},["span",{"class":"sJ8bj"},"// 支付功能\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"},"client.payment\n"]],["span",{"class":"line","line":15},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":16},["span",{"class":"sJ8bj"},"// Webhook\n"]],["span",{"class":"line","line":17},["span",{"class":"sVt8B"},"client.webhook\n"]]]],["h2",{"id":"完整示例"},"🧪 完整示例"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import { WebsopyClient } from ''@websopy/sdk''\n\nasync function demo() {\n const client = new WebsopyClient({\n apiKey: process.env.WEBSOPY_API_KEY\n })\n\n // 1. 获取用户信息\n const user = await client.user.getProfile()\n console.log(''用户:'', user.name)\n\n // 2. 列出项目\n const { items: projects } = await client.project.list({\n limit: 10,\n status: ''active''\n })\n\n // 3. 创建项目\n const project = await client.project.create({\n name: ''新项目'',\n description: ''通过 SDK 创建''\n })\n\n // 4. 上传文件\n const file = await client.storage.upload({\n file: ''./demo.pdf'',\n folder: ''documents''\n })\n\n console.log(''文件上传成功:'', file.url)\n}\n\ndemo().catch(console.error)\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":2},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":3},["span",{"class":"szBVR"},"async"],["span",{"class":"szBVR"}," function"],["span",{"class":"sScJk"}," demo"],["span",{"class":"sVt8B"},"() {\n"]],["span",{"class":"line","line":4},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY\n"]],["span",{"class":"line","line":6},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":7},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":8},["span",{"class":"sJ8bj"}," // 1. 获取用户信息\n"]],["span",{"class":"line","line":9},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," user"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.user."],["span",{"class":"sScJk"},"getProfile"],["span",{"class":"sVt8B"},"()\n"]],["span",{"class":"line","line":10},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''用户:''"],["span",{"class":"sVt8B"},", user.name)\n"]],["span",{"class":"line","line":11},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":12},["span",{"class":"sJ8bj"}," // 2. 列出项目\n"]],["span",{"class":"line","line":13},["span",{"class":"szBVR"}," const"],["span",{"class":"sVt8B"}," { "],["span",{"class":"s4XuR"},"items"],["span",{"class":"sVt8B"},": "],["span",{"class":"sj4cs"},"projects"],["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"list"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":14},["span",{"class":"sVt8B"}," limit: "],["span",{"class":"sj4cs"},"10"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":15},["span",{"class":"sVt8B"}," status: "],["span",{"class":"sZZnC"},"''active''\n"]],["span",{"class":"line","line":16},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":17},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":18},["span",{"class":"sJ8bj"}," // 3. 创建项目\n"]],["span",{"class":"line","line":19},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," project"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"create"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":20},["span",{"class":"sVt8B"}," name: "],["span",{"class":"sZZnC"},"''新项目''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":21},["span",{"class":"sVt8B"}," description: "],["span",{"class":"sZZnC"},"''通过 SDK 创建''\n"]],["span",{"class":"line","line":22},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":23},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":24},["span",{"class":"sJ8bj"}," // 4. 上传文件\n"]],["span",{"class":"line","line":25},["span",{"class":"szBVR"}," const"],["span",{"class":"sj4cs"}," file"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," await"],["span",{"class":"sVt8B"}," client.storage."],["span",{"class":"sScJk"},"upload"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":26},["span",{"class":"sVt8B"}," file: "],["span",{"class":"sZZnC"},"''./demo.pdf''"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":27},["span",{"class":"sVt8B"}," folder: "],["span",{"class":"sZZnC"},"''documents''\n"]],["span",{"class":"line","line":28},["span",{"class":"sVt8B"}," })\n"]],["span",{"class":"line","line":29},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":30},["span",{"class":"sVt8B"}," console."],["span",{"class":"sScJk"},"log"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''文件上传成功:''"],["span",{"class":"sVt8B"},", file.url)\n"]],["span",{"class":"line","line":31},["span",{"class":"sVt8B"},"}\n"]],["span",{"class":"line","line":32},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":33},["span",{"class":"sScJk"},"demo"],["span",{"class":"sVt8B"},"()."],["span",{"class":"sScJk"},"catch"],["span",{"class":"sVt8B"},"(console.error)\n"]]]],["h2",{"id":"typescript-类型"},"🔧 TypeScript 类型"],["p",{},"SDK 提供完整的 TypeScript 类型定义:"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"import type { \n Project, \n User, \n CreateProjectOptions \n} from ''@websopy/sdk/types''\n\nfunction createProject(options: CreateProjectOptions): Promise {\n return client.project.create(options)\n}\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"import"],["span",{"class":"szBVR"}," type"],["span",{"class":"sVt8B"}," { \n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," Project, \n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," User, \n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"}," CreateProjectOptions \n"]],["span",{"class":"line","line":5},["span",{"class":"sVt8B"},"} "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk/types''\n"]],["span",{"class":"line","line":6},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":7},["span",{"class":"szBVR"},"function"],["span",{"class":"sScJk"}," createProject"],["span",{"class":"sVt8B"},"("],["span",{"class":"s4XuR"},"options"],["span",{"class":"szBVR"},":"],["span",{"class":"sScJk"}," CreateProjectOptions"],["span",{"class":"sVt8B"},")"],["span",{"class":"szBVR"},":"],["span",{"class":"sScJk"}," Promise"],["span",{"class":"sVt8B"},"<"],["span",{"class":"sScJk"},"Project"],["span",{"class":"sVt8B"},"> {\n"]],["span",{"class":"line","line":8},["span",{"class":"szBVR"}," return"],["span",{"class":"sVt8B"}," client.project."],["span",{"class":"sScJk"},"create"],["span",{"class":"sVt8B"},"(options)\n"]],["span",{"class":"line","line":9},["span",{"class":"sVt8B"},"}\n"]]]],["h2",{"id":"常见问题"},"❓ 常见问题"],["h3",{"id":"q-esm-和-commonjs-兼容"},"Q: ESM 和 CommonJS 兼容?"],["p",{},"是的,SDK 同时支持两种模块格式:"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"// ESM\nimport { WebsopyClient } from ''@websopy/sdk''\n\n// CommonJS\nconst { WebsopyClient } = require(''@websopy/sdk'')\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"sJ8bj"},"// ESM\n"]],["span",{"class":"line","line":2},["span",{"class":"szBVR"},"import"],["span",{"class":"sVt8B"}," { WebsopyClient } "],["span",{"class":"szBVR"},"from"],["span",{"class":"sZZnC"}," ''@websopy/sdk''\n"]],["span",{"class":"line","line":3},["span",{"emptyLinePlaceholder":true},"\n"]],["span",{"class":"line","line":4},["span",{"class":"sJ8bj"},"// CommonJS\n"]],["span",{"class":"line","line":5},["span",{"class":"szBVR"},"const"],["span",{"class":"sVt8B"}," { "],["span",{"class":"sj4cs"},"WebsopyClient"],["span",{"class":"sVt8B"}," } "],["span",{"class":"szBVR"},"="],["span",{"class":"sScJk"}," require"],["span",{"class":"sVt8B"},"("],["span",{"class":"sZZnC"},"''@websopy/sdk''"],["span",{"class":"sVt8B"},")\n"]]]],["h3",{"id":"q-如何调试"},"Q: 如何调试?"],["pre",{"className":"language-typescript shiki shiki-themes github-light github-dark","code":"const client = new WebsopyClient({\n apiKey: process.env.WEBSOPY_API_KEY,\n debug: true // 打印详细日志\n})\n","language":"typescript","meta":"","style":""},["code",{"__ignoreMap":""},["span",{"class":"line","line":1},["span",{"class":"szBVR"},"const"],["span",{"class":"sj4cs"}," client"],["span",{"class":"szBVR"}," ="],["span",{"class":"szBVR"}," new"],["span",{"class":"sScJk"}," WebsopyClient"],["span",{"class":"sVt8B"},"({\n"]],["span",{"class":"line","line":2},["span",{"class":"sVt8B"}," apiKey: process.env."],["span",{"class":"sj4cs"},"WEBSOPY_API_KEY"],["span",{"class":"sVt8B"},",\n"]],["span",{"class":"line","line":3},["span",{"class":"sVt8B"}," debug: "],["span",{"class":"sj4cs"},"true"],["span",{"class":"sJ8bj"}," // 打印详细日志\n"]],["span",{"class":"line","line":4},["span",{"class":"sVt8B"},"})\n"]]]],["style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}"]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"sdk-概述","depth":2,"text":"📦 SDK 概述"},{"id":"安装","depth":2,"text":"🚀 安装","children":[{"id":"npm","depth":3,"text":"npm"},{"id":"yarn","depth":3,"text":"yarn"},{"id":"pnpm","depth":3,"text":"pnpm"},{"id":"cdn浏览器端","depth":3,"text":"CDN(浏览器端)"}]},{"id":"️-初始化配置","depth":2,"text":"⚙️ 初始化配置","children":[{"id":"基本配置","depth":3,"text":"基本配置"},{"id":"多环境配置","depth":3,"text":"多环境配置"},{"id":"环境变量","depth":3,"text":"环境变量"}]},{"id":"api-模块","depth":2,"text":"📚 API 模块"},{"id":"完整示例","depth":2,"text":"🧪 完整示例"},{"id":"typescript-类型","depth":2,"text":"🔧 TypeScript 类型"},{"id":"常见问题","depth":2,"text":"❓ 常见问题","children":[{"id":"q-esm-和-commonjs-兼容","depth":3,"text":"Q: ESM 和 CommonJS 兼容?"},{"id":"q-如何调试","depth":3,"text":"Q: 如何调试?"}]}]}}', '详细指南:安装 @websopy/sdk,配置 WebsopyClient,发送第一个 API 请求。', 'md', '{"category":"getting-started","order":2}', 'true', '/docs/getting-started/sdk-installation', '{"title":"安装 SDK 与初始化","description":"详细指南:安装 @websopy/sdk,配置 WebsopyClient,发送第一个 API 请求。"}', 'docs/getting-started/sdk-installation', 'EKNThPWC-_GFUSshnSWFUOfjbjixZ-uyiP-PhVgh7Q8'); -- EKNThPWC-_GFUSshnSWFUOfjbjixZ-uyiP-PhVgh7Q8 +INSERT INTO _content_docs VALUES ('docs/docs/index.md', 'Websopy 开发文档', '{"type":"minimark","value":[["h1",{"id":"websopy-开发文档"},"📚 Websopy 开发文档"],["blockquote",{},["p",{},"欢迎来到 Websopy 开发者文档中心。在这里,你可以找到从快速上手到高级功能的所有开发资源。"]],["h2",{"id":"快速开始"},"🚀 快速开始"],["p",{},"新用户推荐从这里开始,5 分钟内体验平台核心功能。"],["ul",{},["li",{},["a",{"href":"/developer/docs/getting-started/quickstart"},"5 分钟快速上手"]," — 安装 SDK、获取 API Key、发送第一个请求"],["li",{},["a",{"href":"/developer/docs/getting-started/sdk-installation"},"安装 SDK 与初始化"]," — 多语言 SDK 安装与配置"],["li",{},["a",{"href":"/developer/docs/getting-started/apikey"},"API Key 创建与管理"]," — 创建、配置与安全最佳实践"]],["h2",{"id":"api-参考"},"🔌 API 参考"],["p",{},"学习如何调用平台 API,掌握数据交互。"],["ul",{},["li",{},["a",{"href":"/developer/docs/api/rest-api"},"REST API 完整参考"]," — 200+ 标准接口文档"],["li",{},["a",{"href":"/developer/docs/api/streaming"},"流式输出(SSE)接入"]," — AI 流式响应实现"],["li",{},["a",{"href":"/developer/docs/api/webhook"},"Webhook 事件接入"]," — 异步通知与回调处理"]],["h2",{"id":"ai-功能"},"🤖 AI 功能"],["p",{},"集成 AI 能力,构建智能应用。"],["ul",{},["li",{},["a",{"href":"/developer/docs/ai/agent"},"AI 智能体接入"]," — 知识库问答与多模型切换"],["li",{},["a",{"href":"/developer/docs/ai/rag"},"RAG 知识库搭建"]," — 企业级知识库问答系统"],["li",{},["a",{"href":"/developer/docs/ai/workflow"},"AI 工作流配置"]," — 定时任务与自动化业务流"]],["h2",{"id":"部署运维"},"🚢 部署运维"],["p",{},"私有化部署、升级与运维指南。"],["ul",{},["li",{},["a",{"href":"/developer/docs/deploy/docker"},"Docker Compose 部署"]," — 一键部署全套服务"],["li",{},["a",{"href":"/developer/docs/deploy/private-deploy"},"私有化部署完全指南"]," — HTTPS 配置与备份策略"],["li",{},["a",{"href":"/developer/docs/deploy/upgrade"},"版本升级与回滚"]," — 平滑升级与紧急回滚"]]],"toc":{"title":"","searchDepth":2,"depth":2,"links":[{"id":"快速开始","depth":2,"text":"🚀 快速开始"},{"id":"api-参考","depth":2,"text":"🔌 API 参考"},{"id":"ai-功能","depth":2,"text":"🤖 AI 功能"},{"id":"部署运维","depth":2,"text":"🚢 部署运维"}]}}', '从快速上手到深度定制,全面的开发指引与 API 参考。', 'md', '{}', 'true', '/docs', '{"title":"Websopy 开发文档","description":"从快速上手到深度定制,全面的开发指引与 API 参考。"}', 'docs/index', 'qEoSynz5hB-SQGtmZjVElCwLL5C7cF4uMYesuclKZW4'); -- qEoSynz5hB-SQGtmZjVElCwLL5C7cF4uMYesuclKZW4 +UPDATE _content_info SET ready = true WHERE id = 'checksum_docs'; -- meta \ No newline at end of file diff --git a/.nuxt/content/types.d.ts b/.nuxt/content/types.d.ts new file mode 100644 index 0000000..3a3d79d --- /dev/null +++ b/.nuxt/content/types.d.ts @@ -0,0 +1,21 @@ +import type { PageCollectionItemBase, DataCollectionItemBase } from '@nuxt/content' + +declare module '@nuxt/content' { + /* eslint-disable */ + /** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + + interface DocsCollectionItem extends PageCollectionItemBase {} + + + interface PageCollections { + docs: DocsCollectionItem + } + + interface Collections { + docs: DocsCollectionItem + } +} diff --git a/.nuxt/dev/index.mjs b/.nuxt/dev/index.mjs new file mode 100644 index 0000000..941462a --- /dev/null +++ b/.nuxt/dev/index.mjs @@ -0,0 +1,4271 @@ +import process from 'node:process';globalThis._importMeta_={url:import.meta.url,env:process.env};import { tmpdir } from 'node:os'; +import { defineEventHandler, handleCacheHeaders, splitCookiesString, createEvent, fetchWithEvent, isEvent, eventHandler, setHeaders, sendRedirect, proxyRequest, getRequestHeader, setResponseHeaders, setResponseStatus, send, getRequestHeaders, setResponseHeader, appendResponseHeader, getRequestURL, getResponseHeader, getResponseStatus, createError, getCookie, setCookie, sanitizeStatusCode, removeResponseHeader, getQuery as getQuery$1, readBody, getRouterParam, setHeader, createApp, createRouter as createRouter$1, toNodeListener, lazyEventHandler, getHeader, getResponseStatusText } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/h3@1.15.4/node_modules/h3/dist/index.mjs'; +import { Server } from 'node:http'; +import { resolve, dirname, join } from 'node:path'; +import nodeCrypto from 'node:crypto'; +import { parentPort, threadId } from 'node:worker_threads'; +import { escapeHtml } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/@vue+shared@3.5.26/node_modules/@vue/shared/dist/shared.cjs.js'; +import { createFetch, Headers as Headers$1, $fetch as $fetch$1 } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/ofetch@1.5.1/node_modules/ofetch/dist/node.mjs'; +import { createRenderer, getRequestDependencies, getPreloadLinks, getPrefetchLinks } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/vue-bundle-renderer@2.2.0/node_modules/vue-bundle-renderer/dist/runtime.mjs'; +import { parseURL, withoutBase, joinURL as joinURL$5, getQuery, withQuery, joinRelativeURL, parsePath, withoutTrailingSlash, withLeadingSlash, withTrailingSlash, decodePath } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/ufo@1.6.1/node_modules/ufo/dist/index.mjs'; +import destr, { destr as destr$1 } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/destr@2.0.5/node_modules/destr/dist/index.mjs'; +import { createHooks } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/hookable@5.5.3/node_modules/hookable/dist/index.mjs'; +import { fetchNodeRequestHandler, callNodeRequestHandler } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/node-mock-http@1.0.4/node_modules/node-mock-http/dist/index.mjs'; +import { createStorage, prefixStorage } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/unstorage@1.17.3_db0@0.3.4_better-sqlite3@12.8.0__ioredis@5.8.2/node_modules/unstorage/dist/index.mjs'; +import unstorage_47drivers_47fs from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/unstorage@1.17.3_db0@0.3.4_better-sqlite3@12.8.0__ioredis@5.8.2/node_modules/unstorage/drivers/fs.mjs'; +import { digest } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/ohash@2.0.11/node_modules/ohash/dist/index.mjs'; +import { klona } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/klona@2.0.6/node_modules/klona/dist/index.mjs'; +import defu, { defuFn, createDefu } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/defu@6.1.4/node_modules/defu/dist/defu.mjs'; +import { snakeCase } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/scule@1.3.0/node_modules/scule/dist/index.mjs'; +import { getContext } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/unctx@2.5.0/node_modules/unctx/dist/index.mjs'; +import { toRouteMatcher, createRouter } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/radix3@1.1.2/node_modules/radix3/dist/index.mjs'; +import { readFile } from 'node:fs/promises'; +import consola, { consola as consola$1 } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/index.mjs'; +import { ErrorParser } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/youch-core@0.3.3/node_modules/youch-core/build/index.js'; +import { Youch } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/youch@4.1.0-beta.13/node_modules/youch/build/index.js'; +import { SourceMapConsumer } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/source-map@0.7.6/node_modules/source-map/source-map.js'; +import { createRouterMatcher } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/vue-router@5.0.4_@vue+compiler-sfc@3.5.26_vue@3.5.26_typescript@5.9.3_/node_modules/vue-router/vue-router.node.mjs'; +import { AsyncLocalStorage } from 'node:async_hooks'; +import { stringify, uneval } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/devalue@5.6.1/node_modules/devalue/index.js'; +import { captureRawStackTrace, parseRawStackTrace } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/errx@0.1.0/node_modules/errx/dist/index.js'; +import { isVNode, toValue, isRef } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/vue@3.5.26_typescript@5.9.3/node_modules/vue/index.mjs'; +import { promises } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname as dirname$1, resolve as resolve$1, isAbsolute } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.mjs'; +import { createHead as createHead$1, propsToString, renderSSRHead } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/unhead@2.1.1/node_modules/unhead/dist/server.mjs'; +import process$1 from 'node:process'; +import { renderToString } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/vue@3.5.26_typescript@5.9.3/node_modules/vue/server-renderer/index.mjs'; +import { walkResolver } from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/unhead@2.1.1/node_modules/unhead/dist/utils.mjs'; +import localAdapter from 'file:///Users/gxwebsoft/VUE/tiantian-system/node_modules/.pnpm/db0@0.3.4_better-sqlite3@12.8.0/node_modules/db0/dist/connectors/better-sqlite3.mjs'; + +const serverAssets = [{"baseName":"server","dir":"/Users/gxwebsoft/VUE/tiantian-system/server/assets"}]; + +const assets$1 = createStorage(); + +for (const asset of serverAssets) { + assets$1.mount(asset.baseName, unstorage_47drivers_47fs({ base: asset.dir, ignore: (asset?.ignore || []) })); +} + +const storage$1 = createStorage({}); + +storage$1.mount('/assets', assets$1); + +storage$1.mount('root', unstorage_47drivers_47fs({"driver":"fs","readOnly":true,"base":"/Users/gxwebsoft/VUE/tiantian-system","watchOptions":{"ignored":[null]}})); +storage$1.mount('src', unstorage_47drivers_47fs({"driver":"fs","readOnly":true,"base":"/Users/gxwebsoft/VUE/tiantian-system/server","watchOptions":{"ignored":[null]}})); +storage$1.mount('build', unstorage_47drivers_47fs({"driver":"fs","readOnly":false,"base":"/Users/gxwebsoft/VUE/tiantian-system/.nuxt"})); +storage$1.mount('cache', unstorage_47drivers_47fs({"driver":"fs","readOnly":false,"base":"/Users/gxwebsoft/VUE/tiantian-system/.nuxt/cache"})); +storage$1.mount('data', unstorage_47drivers_47fs({"driver":"fs","base":"/Users/gxwebsoft/VUE/tiantian-system/.data/kv"})); + +function useStorage(base = "") { + return base ? prefixStorage(storage$1, base) : storage$1; +} + +const Hasher = /* @__PURE__ */ (() => { + class Hasher2 { + buff = ""; + #context = /* @__PURE__ */ new Map(); + write(str) { + this.buff += str; + } + dispatch(value) { + const type = value === null ? "null" : typeof value; + return this[type](value); + } + object(object) { + if (object && typeof object.toJSON === "function") { + return this.object(object.toJSON()); + } + const objString = Object.prototype.toString.call(object); + let objType = ""; + const objectLength = objString.length; + objType = objectLength < 10 ? "unknown:[" + objString + "]" : objString.slice(8, objectLength - 1); + objType = objType.toLowerCase(); + let objectNumber = null; + if ((objectNumber = this.#context.get(object)) === void 0) { + this.#context.set(object, this.#context.size); + } else { + return this.dispatch("[CIRCULAR:" + objectNumber + "]"); + } + if (typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(object)) { + this.write("buffer:"); + return this.write(object.toString("utf8")); + } + if (objType !== "object" && objType !== "function" && objType !== "asyncfunction") { + if (this[objType]) { + this[objType](object); + } else { + this.unknown(object, objType); + } + } else { + const keys = Object.keys(object).sort(); + const extraKeys = []; + this.write("object:" + (keys.length + extraKeys.length) + ":"); + const dispatchForKey = (key) => { + this.dispatch(key); + this.write(":"); + this.dispatch(object[key]); + this.write(","); + }; + for (const key of keys) { + dispatchForKey(key); + } + for (const key of extraKeys) { + dispatchForKey(key); + } + } + } + array(arr, unordered) { + unordered = unordered === void 0 ? false : unordered; + this.write("array:" + arr.length + ":"); + if (!unordered || arr.length <= 1) { + for (const entry of arr) { + this.dispatch(entry); + } + return; + } + const contextAdditions = /* @__PURE__ */ new Map(); + const entries = arr.map((entry) => { + const hasher = new Hasher2(); + hasher.dispatch(entry); + for (const [key, value] of hasher.#context) { + contextAdditions.set(key, value); + } + return hasher.toString(); + }); + this.#context = contextAdditions; + entries.sort(); + return this.array(entries, false); + } + date(date) { + return this.write("date:" + date.toJSON()); + } + symbol(sym) { + return this.write("symbol:" + sym.toString()); + } + unknown(value, type) { + this.write(type); + if (!value) { + return; + } + this.write(":"); + if (value && typeof value.entries === "function") { + return this.array( + [...value.entries()], + true + /* ordered */ + ); + } + } + error(err) { + return this.write("error:" + err.toString()); + } + boolean(bool) { + return this.write("bool:" + bool); + } + string(string) { + this.write("string:" + string.length + ":"); + this.write(string); + } + function(fn) { + this.write("fn:"); + if (isNativeFunction(fn)) { + this.dispatch("[native]"); + } else { + this.dispatch(fn.toString()); + } + } + number(number) { + return this.write("number:" + number); + } + null() { + return this.write("Null"); + } + undefined() { + return this.write("Undefined"); + } + regexp(regex) { + return this.write("regex:" + regex.toString()); + } + arraybuffer(arr) { + this.write("arraybuffer:"); + return this.dispatch(new Uint8Array(arr)); + } + url(url) { + return this.write("url:" + url.toString()); + } + map(map) { + this.write("map:"); + const arr = [...map]; + return this.array(arr, false); + } + set(set) { + this.write("set:"); + const arr = [...set]; + return this.array(arr, false); + } + bigint(number) { + return this.write("bigint:" + number.toString()); + } + } + for (const type of [ + "uint8array", + "uint8clampedarray", + "unt8array", + "uint16array", + "unt16array", + "uint32array", + "unt32array", + "float32array", + "float64array" + ]) { + Hasher2.prototype[type] = function(arr) { + this.write(type + ":"); + return this.array([...arr], false); + }; + } + function isNativeFunction(f) { + if (typeof f !== "function") { + return false; + } + return Function.prototype.toString.call(f).slice( + -15 + /* "[native code] }".length */ + ) === "[native code] }"; + } + return Hasher2; +})(); +function serialize(object) { + const hasher = new Hasher(); + hasher.dispatch(object); + return hasher.buff; +} +function hash(value) { + return digest(typeof value === "string" ? value : serialize(value)).replace(/[-_]/g, "").slice(0, 10); +} + +function defaultCacheOptions() { + return { + name: "_", + base: "/cache", + swr: true, + maxAge: 1 + }; +} +function defineCachedFunction(fn, opts = {}) { + opts = { ...defaultCacheOptions(), ...opts }; + const pending = {}; + const group = opts.group || "nitro/functions"; + const name = opts.name || fn.name || "_"; + const integrity = opts.integrity || hash([fn, opts]); + const validate = opts.validate || ((entry) => entry.value !== void 0); + async function get(key, resolver, shouldInvalidateCache, event) { + const cacheKey = [opts.base, group, name, key + ".json"].filter(Boolean).join(":").replace(/:\/$/, ":index"); + let entry = await useStorage().getItem(cacheKey).catch((error) => { + console.error(`[cache] Cache read error.`, error); + useNitroApp().captureError(error, { event, tags: ["cache"] }); + }) || {}; + if (typeof entry !== "object") { + entry = {}; + const error = new Error("Malformed data read from cache."); + console.error("[cache]", error); + useNitroApp().captureError(error, { event, tags: ["cache"] }); + } + const ttl = (opts.maxAge ?? 0) * 1e3; + if (ttl) { + entry.expires = Date.now() + ttl; + } + const expired = shouldInvalidateCache || entry.integrity !== integrity || ttl && Date.now() - (entry.mtime || 0) > ttl || validate(entry) === false; + const _resolve = async () => { + const isPending = pending[key]; + if (!isPending) { + if (entry.value !== void 0 && (opts.staleMaxAge || 0) >= 0 && opts.swr === false) { + entry.value = void 0; + entry.integrity = void 0; + entry.mtime = void 0; + entry.expires = void 0; + } + pending[key] = Promise.resolve(resolver()); + } + try { + entry.value = await pending[key]; + } catch (error) { + if (!isPending) { + delete pending[key]; + } + throw error; + } + if (!isPending) { + entry.mtime = Date.now(); + entry.integrity = integrity; + delete pending[key]; + if (validate(entry) !== false) { + let setOpts; + if (opts.maxAge && !opts.swr) { + setOpts = { ttl: opts.maxAge }; + } + const promise = useStorage().setItem(cacheKey, entry, setOpts).catch((error) => { + console.error(`[cache] Cache write error.`, error); + useNitroApp().captureError(error, { event, tags: ["cache"] }); + }); + if (event?.waitUntil) { + event.waitUntil(promise); + } + } + } + }; + const _resolvePromise = expired ? _resolve() : Promise.resolve(); + if (entry.value === void 0) { + await _resolvePromise; + } else if (expired && event && event.waitUntil) { + event.waitUntil(_resolvePromise); + } + if (opts.swr && validate(entry) !== false) { + _resolvePromise.catch((error) => { + console.error(`[cache] SWR handler error.`, error); + useNitroApp().captureError(error, { event, tags: ["cache"] }); + }); + return entry; + } + return _resolvePromise.then(() => entry); + } + return async (...args) => { + const shouldBypassCache = await opts.shouldBypassCache?.(...args); + if (shouldBypassCache) { + return fn(...args); + } + const key = await (opts.getKey || getKey)(...args); + const shouldInvalidateCache = await opts.shouldInvalidateCache?.(...args); + const entry = await get( + key, + () => fn(...args), + shouldInvalidateCache, + args[0] && isEvent(args[0]) ? args[0] : void 0 + ); + let value = entry.value; + if (opts.transform) { + value = await opts.transform(entry, ...args) || value; + } + return value; + }; +} +function cachedFunction(fn, opts = {}) { + return defineCachedFunction(fn, opts); +} +function getKey(...args) { + return args.length > 0 ? hash(args) : ""; +} +function escapeKey(key) { + return String(key).replace(/\W/g, ""); +} +function defineCachedEventHandler(handler, opts = defaultCacheOptions()) { + const variableHeaderNames = (opts.varies || []).filter(Boolean).map((h) => h.toLowerCase()).sort(); + const _opts = { + ...opts, + getKey: async (event) => { + const customKey = await opts.getKey?.(event); + if (customKey) { + return escapeKey(customKey); + } + const _path = event.node.req.originalUrl || event.node.req.url || event.path; + let _pathname; + try { + _pathname = escapeKey(decodeURI(parseURL(_path).pathname)).slice(0, 16) || "index"; + } catch { + _pathname = "-"; + } + const _hashedPath = `${_pathname}.${hash(_path)}`; + const _headers = variableHeaderNames.map((header) => [header, event.node.req.headers[header]]).map(([name, value]) => `${escapeKey(name)}.${hash(value)}`); + return [_hashedPath, ..._headers].join(":"); + }, + validate: (entry) => { + if (!entry.value) { + return false; + } + if (entry.value.code >= 400) { + return false; + } + if (entry.value.body === void 0) { + return false; + } + if (entry.value.headers.etag === "undefined" || entry.value.headers["last-modified"] === "undefined") { + return false; + } + return true; + }, + group: opts.group || "nitro/handlers", + integrity: opts.integrity || hash([handler, opts]) + }; + const _cachedHandler = cachedFunction( + async (incomingEvent) => { + const variableHeaders = {}; + for (const header of variableHeaderNames) { + const value = incomingEvent.node.req.headers[header]; + if (value !== void 0) { + variableHeaders[header] = value; + } + } + const reqProxy = cloneWithProxy(incomingEvent.node.req, { + headers: variableHeaders + }); + const resHeaders = {}; + let _resSendBody; + const resProxy = cloneWithProxy(incomingEvent.node.res, { + statusCode: 200, + writableEnded: false, + writableFinished: false, + headersSent: false, + closed: false, + getHeader(name) { + return resHeaders[name]; + }, + setHeader(name, value) { + resHeaders[name] = value; + return this; + }, + getHeaderNames() { + return Object.keys(resHeaders); + }, + hasHeader(name) { + return name in resHeaders; + }, + removeHeader(name) { + delete resHeaders[name]; + }, + getHeaders() { + return resHeaders; + }, + end(chunk, arg2, arg3) { + if (typeof chunk === "string") { + _resSendBody = chunk; + } + if (typeof arg2 === "function") { + arg2(); + } + if (typeof arg3 === "function") { + arg3(); + } + return this; + }, + write(chunk, arg2, arg3) { + if (typeof chunk === "string") { + _resSendBody = chunk; + } + if (typeof arg2 === "function") { + arg2(void 0); + } + if (typeof arg3 === "function") { + arg3(); + } + return true; + }, + writeHead(statusCode, headers2) { + this.statusCode = statusCode; + if (headers2) { + if (Array.isArray(headers2) || typeof headers2 === "string") { + throw new TypeError("Raw headers is not supported."); + } + for (const header in headers2) { + const value = headers2[header]; + if (value !== void 0) { + this.setHeader( + header, + value + ); + } + } + } + return this; + } + }); + const event = createEvent(reqProxy, resProxy); + event.fetch = (url, fetchOptions) => fetchWithEvent(event, url, fetchOptions, { + fetch: useNitroApp().localFetch + }); + event.$fetch = (url, fetchOptions) => fetchWithEvent(event, url, fetchOptions, { + fetch: globalThis.$fetch + }); + event.waitUntil = incomingEvent.waitUntil; + event.context = incomingEvent.context; + event.context.cache = { + options: _opts + }; + const body = await handler(event) || _resSendBody; + const headers = event.node.res.getHeaders(); + headers.etag = String( + headers.Etag || headers.etag || `W/"${hash(body)}"` + ); + headers["last-modified"] = String( + headers["Last-Modified"] || headers["last-modified"] || (/* @__PURE__ */ new Date()).toUTCString() + ); + const cacheControl = []; + if (opts.swr) { + if (opts.maxAge) { + cacheControl.push(`s-maxage=${opts.maxAge}`); + } + if (opts.staleMaxAge) { + cacheControl.push(`stale-while-revalidate=${opts.staleMaxAge}`); + } else { + cacheControl.push("stale-while-revalidate"); + } + } else if (opts.maxAge) { + cacheControl.push(`max-age=${opts.maxAge}`); + } + if (cacheControl.length > 0) { + headers["cache-control"] = cacheControl.join(", "); + } + const cacheEntry = { + code: event.node.res.statusCode, + headers, + body + }; + return cacheEntry; + }, + _opts + ); + return defineEventHandler(async (event) => { + if (opts.headersOnly) { + if (handleCacheHeaders(event, { maxAge: opts.maxAge })) { + return; + } + return handler(event); + } + const response = await _cachedHandler( + event + ); + if (event.node.res.headersSent || event.node.res.writableEnded) { + return response.body; + } + if (handleCacheHeaders(event, { + modifiedTime: new Date(response.headers["last-modified"]), + etag: response.headers.etag, + maxAge: opts.maxAge + })) { + return; + } + event.node.res.statusCode = response.code; + for (const name in response.headers) { + const value = response.headers[name]; + if (name === "set-cookie") { + event.node.res.appendHeader( + name, + splitCookiesString(value) + ); + } else { + if (value !== void 0) { + event.node.res.setHeader(name, value); + } + } + } + return response.body; + }); +} +function cloneWithProxy(obj, overrides) { + return new Proxy(obj, { + get(target, property, receiver) { + if (property in overrides) { + return overrides[property]; + } + return Reflect.get(target, property, receiver); + }, + set(target, property, value, receiver) { + if (property in overrides) { + overrides[property] = value; + return true; + } + return Reflect.set(target, property, value, receiver); + } + }); +} +const cachedEventHandler = defineCachedEventHandler; + +const inlineAppConfig = { + "nuxt": {} +}; + + + +const appConfig = defuFn(inlineAppConfig); + +function getEnv(key, opts) { + const envKey = snakeCase(key).toUpperCase(); + return destr( + process.env[opts.prefix + envKey] ?? process.env[opts.altPrefix + envKey] + ); +} +function _isObject(input) { + return typeof input === "object" && !Array.isArray(input); +} +function applyEnv(obj, opts, parentKey = "") { + for (const key in obj) { + const subKey = parentKey ? `${parentKey}_${key}` : key; + const envValue = getEnv(subKey, opts); + if (_isObject(obj[key])) { + if (_isObject(envValue)) { + obj[key] = { ...obj[key], ...envValue }; + applyEnv(obj[key], opts, subKey); + } else if (envValue === void 0) { + applyEnv(obj[key], opts, subKey); + } else { + obj[key] = envValue ?? obj[key]; + } + } else { + obj[key] = envValue ?? obj[key]; + } + if (opts.envExpansion && typeof obj[key] === "string") { + obj[key] = _expandFromEnv(obj[key]); + } + } + return obj; +} +const envExpandRx = /\{\{([^{}]*)\}\}/g; +function _expandFromEnv(value) { + return value.replace(envExpandRx, (match, key) => { + return process.env[key] || match; + }); +} + +const _inlineRuntimeConfig = { + "app": { + "baseURL": "/", + "buildId": "dev", + "buildAssetsDir": "/_nuxt/", + "cdnURL": "" + }, + "nitro": { + "envPrefix": "NUXT_", + "routeRules": { + "/__nuxt_error": { + "cache": false + }, + "/__nuxt_content/**": { + "robots": false, + "cache": false + }, + "/__nuxt_content/docs/sql_dump.txt": { + "prerender": true + } + } + }, + "public": { + "tenantId": "5", + "serverApiBase": "https://server.websoft.top/api", + "modulesApiBase": "https://mp-api.websoft.top/api", + "appApiBase": "https://websopy-api.websoft.top", + "mpApiBase": "https://mp-api.websoft.top", + "fileServerBase": "https://server.websoft.top", + "templateId": "5", + "ServerApi": "https://server.websoft.top/api", + "ApiBase": "https://mp-api.websoft.top/api", + "TenantId": "5", + "mdc": { + "components": { + "prose": true, + "map": {}, + "customElements": [] + }, + "headings": { + "anchorLinks": { + "h1": false, + "h2": true, + "h3": true, + "h4": true, + "h5": false, + "h6": false + } + }, + "highlight": { + "noApiRoute": true, + "highlighter": "shiki", + "theme": { + "default": "github-light", + "dark": "github-dark" + }, + "shikiEngine": "oniguruma", + "langs": [ + "js", + "jsx", + "json", + "ts", + "tsx", + "vue", + "css", + "html", + "bash", + "md", + "mdc", + "yaml" + ] + } + }, + "content": { + "wsUrl": "" + }, + "i18n": { + "baseUrl": "", + "defaultLocale": "zh-CN", + "rootRedirect": "", + "redirectStatusCode": 302, + "skipSettingLocaleOnNavigate": false, + "locales": [ + { + "code": "zh-CN", + "name": "简体中文", + "language": "" + }, + { + "code": "en", + "name": "English", + "language": "" + } + ], + "detectBrowserLanguage": { + "alwaysRedirect": true, + "cookieCrossOrigin": false, + "cookieDomain": "", + "cookieKey": "i18n_locale", + "cookieSecure": false, + "fallbackLocale": "zh-CN", + "redirectOn": "root", + "useCookie": true + }, + "experimental": { + "localeDetector": "", + "typedPages": true, + "typedOptionsAndMessages": false, + "alternateLinkCanonicalQueries": true, + "devCache": false, + "cacheLifetime": "", + "stripMessagesPayload": false, + "preload": false, + "strictSeo": false, + "nitroContextDetection": true, + "httpCacheDuration": 10 + }, + "domainLocales": { + "zh-CN": { + "domain": "" + }, + "en": { + "domain": "" + } + } + } + }, + "content": { + "databaseVersion": "v3.5.0", + "version": "3.12.0", + "database": { + "type": "sqlite", + "filename": "./contents.sqlite" + }, + "localDatabase": { + "type": "sqlite", + "filename": "/Users/gxwebsoft/VUE/tiantian-system/.data/content/contents.sqlite" + }, + "integrityCheck": true + } +}; +const envOptions = { + prefix: "NITRO_", + altPrefix: _inlineRuntimeConfig.nitro.envPrefix ?? process.env.NITRO_ENV_PREFIX ?? "_", + envExpansion: _inlineRuntimeConfig.nitro.envExpansion ?? process.env.NITRO_ENV_EXPANSION ?? false +}; +const _sharedRuntimeConfig = _deepFreeze( + applyEnv(klona(_inlineRuntimeConfig), envOptions) +); +function useRuntimeConfig(event) { + if (!event) { + return _sharedRuntimeConfig; + } + if (event.context.nitro.runtimeConfig) { + return event.context.nitro.runtimeConfig; + } + const runtimeConfig = klona(_inlineRuntimeConfig); + applyEnv(runtimeConfig, envOptions); + event.context.nitro.runtimeConfig = runtimeConfig; + return runtimeConfig; +} +_deepFreeze(klona(appConfig)); +function _deepFreeze(object) { + const propNames = Object.getOwnPropertyNames(object); + for (const name of propNames) { + const value = object[name]; + if (value && typeof value === "object") { + _deepFreeze(value); + } + } + return Object.freeze(object); +} +new Proxy(/* @__PURE__ */ Object.create(null), { + get: (_, prop) => { + console.warn( + "Please use `useRuntimeConfig()` instead of accessing config directly." + ); + const runtimeConfig = useRuntimeConfig(); + if (prop in runtimeConfig) { + return runtimeConfig[prop]; + } + return void 0; + } +}); + +getContext("nitro-app", { + asyncContext: false, + AsyncLocalStorage: void 0 +}); + +const config = useRuntimeConfig(); +const _routeRulesMatcher = toRouteMatcher( + createRouter({ routes: config.nitro.routeRules }) +); +function createRouteRulesHandler(ctx) { + return eventHandler((event) => { + const routeRules = getRouteRules(event); + if (routeRules.headers) { + setHeaders(event, routeRules.headers); + } + if (routeRules.redirect) { + let target = routeRules.redirect.to; + if (target.endsWith("/**")) { + let targetPath = event.path; + const strpBase = routeRules.redirect._redirectStripBase; + if (strpBase) { + targetPath = withoutBase(targetPath, strpBase); + } + target = joinURL$5(target.slice(0, -3), targetPath); + } else if (event.path.includes("?")) { + const query = getQuery(event.path); + target = withQuery(target, query); + } + return sendRedirect(event, target, routeRules.redirect.statusCode); + } + if (routeRules.proxy) { + let target = routeRules.proxy.to; + if (target.endsWith("/**")) { + let targetPath = event.path; + const strpBase = routeRules.proxy._proxyStripBase; + if (strpBase) { + targetPath = withoutBase(targetPath, strpBase); + } + target = joinURL$5(target.slice(0, -3), targetPath); + } else if (event.path.includes("?")) { + const query = getQuery(event.path); + target = withQuery(target, query); + } + return proxyRequest(event, target, { + fetch: ctx.localFetch, + ...routeRules.proxy + }); + } + }); +} +function getRouteRules(event) { + event.context._nitro = event.context._nitro || {}; + if (!event.context._nitro.routeRules) { + event.context._nitro.routeRules = getRouteRulesForPath( + withoutBase(event.path.split("?")[0], useRuntimeConfig().app.baseURL) + ); + } + return event.context._nitro.routeRules; +} +function getRouteRulesForPath(path) { + return defu({}, ..._routeRulesMatcher.matchAll(path).reverse()); +} + +function _captureError(error, type) { + console.error(`[${type}]`, error); + useNitroApp().captureError(error, { tags: [type] }); +} +function trapUnhandledNodeErrors() { + process.on( + "unhandledRejection", + (error) => _captureError(error, "unhandledRejection") + ); + process.on( + "uncaughtException", + (error) => _captureError(error, "uncaughtException") + ); +} +function joinHeaders(value) { + return Array.isArray(value) ? value.join(", ") : String(value); +} +function normalizeFetchResponse(response) { + if (!response.headers.has("set-cookie")) { + return response; + } + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers: normalizeCookieHeaders(response.headers) + }); +} +function normalizeCookieHeader(header = "") { + return splitCookiesString(joinHeaders(header)); +} +function normalizeCookieHeaders(headers) { + const outgoingHeaders = new Headers(); + for (const [name, header] of headers) { + if (name === "set-cookie") { + for (const cookie of normalizeCookieHeader(header)) { + outgoingHeaders.append("set-cookie", cookie); + } + } else { + outgoingHeaders.set(name, joinHeaders(header)); + } + } + return outgoingHeaders; +} + +function isJsonRequest(event) { + if (hasReqHeader(event, "accept", "text/html")) { + return false; + } + return hasReqHeader(event, "accept", "application/json") || hasReqHeader(event, "user-agent", "curl/") || hasReqHeader(event, "user-agent", "httpie/") || hasReqHeader(event, "sec-fetch-mode", "cors") || event.path.startsWith("/api/") || event.path.endsWith(".json"); +} +function hasReqHeader(event, name, includes) { + const value = getRequestHeader(event, name); + return value && typeof value === "string" && value.toLowerCase().includes(includes); +} + +const iframeStorageBridge = (nonce) => ( + /* js */ + ` +(function() { + const memoryStore = {}; + + const NONCE = ${JSON.stringify(nonce)} + + const mockStorage = { + getItem: function(key) { + return memoryStore[key] !== undefined ? memoryStore[key] : null; + }, + setItem: function(key, value) { + memoryStore[key] = String(value); + window.parent.postMessage({ + type: 'storage-set', + key: key, + value: String(value), + nonce: NONCE + }, '*'); + }, + removeItem: function(key) { + delete memoryStore[key]; + window.parent.postMessage({ + type: 'storage-remove', + key: key, + nonce: NONCE + }, '*'); + }, + clear: function() { + for (const key in memoryStore) { + delete memoryStore[key]; + } + window.parent.postMessage({ + type: 'storage-clear', + nonce: NONCE + }, '*'); + }, + key: function(index) { + const keys = Object.keys(memoryStore); + return keys[index] !== undefined ? keys[index] : null; + }, + get length() { + return Object.keys(memoryStore).length; + } + }; + + try { + Object.defineProperty(window, 'localStorage', { + value: mockStorage, + writable: false, + configurable: true + }); + } catch (e) { + window.localStorage = mockStorage; + } + + window.addEventListener('message', function(event) { + if (event.data.type === 'storage-sync-data' && event.data.nonce === NONCE) { + const data = event.data.data; + for (const key in data) { + if (Object.prototype.hasOwnProperty.call(data, key)) { + memoryStore[key] = data[key]; + } + } + if (typeof window.initTheme === 'function') { + window.initTheme(); + } + window.dispatchEvent(new Event('storage-ready')); + } + }); + + window.parent.postMessage({ + type: 'storage-sync-request', + nonce: NONCE + }, '*'); +})(); +` +); +const parentStorageBridge = (nonce) => ( + /* js */ + ` +(function() { + const host = document.querySelector('nuxt-error-overlay'); + if (!host) return; + + // Wait for shadow root to be attached + const checkShadow = setInterval(function() { + if (host.shadowRoot) { + clearInterval(checkShadow); + const iframe = host.shadowRoot.getElementById('frame'); + if (!iframe) return; + + const NONCE = ${JSON.stringify(nonce)} + + window.addEventListener('message', function(event) { + if (!event.data || event.data.nonce !== NONCE) return; + + const data = event.data; + + if (data.type === 'storage-set') { + localStorage.setItem(data.key, data.value); + } else if (data.type === 'storage-remove') { + localStorage.removeItem(data.key); + } else if (data.type === 'storage-clear') { + localStorage.clear(); + } else if (data.type === 'storage-sync-request') { + const allData = {}; + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i); + allData[key] = localStorage.getItem(key); + } + iframe.contentWindow.postMessage({ + type: 'storage-sync-data', + data: allData, + nonce: NONCE + }, '*'); + } + }); + } + }, 10); +})(); +` +); +const errorCSS = ( + /* css */ + ` +:host { + --preview-width: 240px; + --preview-height: 180px; + --base-width: 1200px; + --base-height: 900px; + --z-base: 999999998; + all: initial; + display: contents; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} +#frame { + position: fixed; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + border: none; + z-index: var(--z-base); +} +#frame[inert] { + right: 5px; + bottom: 5px; + left: auto; + top: auto; + width: var(--base-width); + height: var(--base-height); + transform: scale(calc(240 / 1200)); + transform-origin: bottom right; + overflow: hidden; + border-radius: calc(1200 * 8px / 240); +} +#preview { + position: fixed; + right: 5px; + bottom: 5px; + width: var(--preview-width); + height: var(--preview-height); + overflow: hidden; + border-radius: 8px; + pointer-events: none; + z-index: var(--z-base); + background: white; + display: none; +} +#frame:not([inert]) + #preview { + display: block; +} +#toggle { + position: fixed; + right: 5px; + bottom: 5px; + width: var(--preview-width); + height: var(--preview-height); + background: none; + border: 3px solid #00DC82; + border-radius: 8px; + cursor: pointer; + opacity: 0.8; + transition: opacity 0.2s, box-shadow 0.2s; + z-index: calc(var(--z-base) + 1); +} +#toggle:hover, +#toggle:focus { + opacity: 1; + box-shadow: 0 0 20px rgba(0, 220, 130, 0.6); +} +#toggle:focus-visible { + outline: 3px solid #00DC82; + outline-offset: 3px; + box-shadow: 0 0 24px rgba(0, 220, 130, 0.8); +} +@media (prefers-reduced-motion: reduce) { + #toggle { + transition: none; + } +} +` +); +function webComponentScript(base64HTML, startMinimized) { + return ( + /* js */ + ` + (function() { + try { + const host = document.querySelector('nuxt-error-overlay'); + if (!host) return; + + const shadow = host.attachShadow({ mode: 'open' }); + + // Create elements + const style = document.createElement('style'); + style.textContent = ${JSON.stringify(errorCSS)}; + + const iframe = document.createElement('iframe'); + iframe.id = 'frame'; + iframe.src = 'data:text/html;base64,${base64HTML}'; + iframe.title = 'Detailed error stack trace'; + iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin'); + + const preview = document.createElement('div'); + preview.id = 'preview'; + + const button = document.createElement('button'); + button.id = 'toggle'; + button.setAttribute('aria-expanded', 'true'); + button.setAttribute('type', 'button'); + button.innerHTML = 'Toggle detailed error view'; + + const liveRegion = document.createElement('div'); + liveRegion.setAttribute('role', 'status'); + liveRegion.setAttribute('aria-live', 'polite'); + liveRegion.className = 'sr-only'; + + // Update preview snapshot + function updatePreview() { + try { + let previewIframe = preview.querySelector('iframe'); + if (!previewIframe) { + previewIframe = document.createElement('iframe'); + previewIframe.style.cssText = 'width: 1200px; height: 900px; transform: scale(0.2); transform-origin: top left; border: none;'; + previewIframe.setAttribute('sandbox', 'allow-scripts allow-same-origin'); + preview.appendChild(previewIframe); + } + + const doctype = document.doctype ? '' : ''; + const cleanedHTML = document.documentElement.outerHTML + .replace(/]*>.*?<\\/nuxt-error-overlay>/gs, '') + .replace(/]*>.*?<\\/script>/gs, ''); + + const iframeDoc = previewIframe.contentDocument || previewIframe.contentWindow.document; + iframeDoc.open(); + iframeDoc.write(doctype + cleanedHTML); + iframeDoc.close(); + } catch (error) { + console.error('Failed to update preview:', error); + } + } + + function toggleView() { + const isMinimized = iframe.hasAttribute('inert'); + + if (isMinimized) { + updatePreview(); + iframe.removeAttribute('inert'); + button.setAttribute('aria-expanded', 'true'); + liveRegion.textContent = 'Showing detailed error view'; + setTimeout(function() { + try { iframe.contentWindow.focus(); } catch {} + }, 100); + } else { + iframe.setAttribute('inert', ''); + button.setAttribute('aria-expanded', 'false'); + liveRegion.textContent = 'Showing error page'; + button.focus(); + } + } + + button.onclick = toggleView; + + document.addEventListener('keydown', function(e) { + if ((e.key === 'Escape' || e.key === 'Esc') && !iframe.hasAttribute('inert')) { + toggleView(); + } + }); + + // Append to shadow DOM + shadow.appendChild(style); + shadow.appendChild(liveRegion); + shadow.appendChild(iframe); + shadow.appendChild(preview); + shadow.appendChild(button); + + if (${startMinimized}) { + iframe.setAttribute('inert', ''); + button.setAttribute('aria-expanded', 'false'); + } + + // Initialize preview + setTimeout(updatePreview, 100); + + } catch (error) { + console.error('Failed to initialize Nuxt error overlay:', error); + } + })(); + ` + ); +} +function generateErrorOverlayHTML(html, options) { + const nonce = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join(""); + const errorPage = html.replace("", ` - - diff --git a/app/pages/admin/account.vue b/app/pages/admin/account.vue new file mode 100644 index 0000000..79e9fb6 --- /dev/null +++ b/app/pages/admin/account.vue @@ -0,0 +1,247 @@ + + + + + diff --git a/app/pages/admin/developers.vue b/app/pages/admin/developers.vue index 9bc56b7..9529236 100644 --- a/app/pages/admin/developers.vue +++ b/app/pages/admin/developers.vue @@ -1,415 +1,234 @@ diff --git a/app/pages/admin/developers/audit.vue b/app/pages/admin/developers/audit.vue new file mode 100644 index 0000000..9aee227 --- /dev/null +++ b/app/pages/admin/developers/audit.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/app/pages/admin/enterprises.vue b/app/pages/admin/enterprises.vue new file mode 100644 index 0000000..1f047aa --- /dev/null +++ b/app/pages/admin/enterprises.vue @@ -0,0 +1,301 @@ + + + + + diff --git a/app/pages/admin/enterprises/detail.vue b/app/pages/admin/enterprises/detail.vue new file mode 100644 index 0000000..e512a9b --- /dev/null +++ b/app/pages/admin/enterprises/detail.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/app/pages/admin/finance.vue b/app/pages/admin/finance.vue new file mode 100644 index 0000000..50fbe12 --- /dev/null +++ b/app/pages/admin/finance.vue @@ -0,0 +1,267 @@ + + + + + diff --git a/app/pages/admin/finance/recharge.vue b/app/pages/admin/finance/recharge.vue new file mode 100644 index 0000000..debe9a7 --- /dev/null +++ b/app/pages/admin/finance/recharge.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/app/pages/admin/index.vue b/app/pages/admin/index.vue index 98f109d..c90ad7b 100644 --- a/app/pages/admin/index.vue +++ b/app/pages/admin/index.vue @@ -1,89 +1,157 @@ -