@agent-native/core 0.79.2 → 0.79.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +30 -0
  3. package/corpus/core/docs/content/locales/zh-TW/a2a-protocol.md +392 -0
  4. package/corpus/core/docs/content/locales/zh-TW/actions.md +583 -0
  5. package/corpus/core/docs/content/locales/zh-TW/agent-mentions.md +164 -0
  6. package/corpus/core/docs/content/locales/zh-TW/agent-surfaces.md +397 -0
  7. package/corpus/core/docs/content/locales/zh-TW/agent-teams.md +171 -0
  8. package/corpus/core/docs/content/locales/zh-TW/agent-web-surfaces.md +161 -0
  9. package/corpus/core/docs/content/locales/zh-TW/audit-log.md +111 -0
  10. package/corpus/core/docs/content/locales/zh-TW/authentication.md +332 -0
  11. package/corpus/core/docs/content/locales/zh-TW/automations.md +268 -0
  12. package/corpus/core/docs/content/locales/zh-TW/blueprint-installer.md +83 -0
  13. package/corpus/core/docs/content/locales/zh-TW/cli-adapters.md +129 -0
  14. package/corpus/core/docs/content/locales/zh-TW/client.md +398 -0
  15. package/corpus/core/docs/content/locales/zh-TW/cloneable-saas.md +114 -0
  16. package/corpus/core/docs/content/locales/zh-TW/code-agents-ui.md +436 -0
  17. package/corpus/core/docs/content/locales/zh-TW/components.md +368 -0
  18. package/corpus/core/docs/content/locales/zh-TW/context-awareness.md +373 -0
  19. package/corpus/core/docs/content/locales/zh-TW/creating-templates.md +411 -0
  20. package/corpus/core/docs/content/locales/zh-TW/cross-app-sso.md +188 -0
  21. package/corpus/core/docs/content/locales/zh-TW/database.md +183 -0
  22. package/corpus/core/docs/content/locales/zh-TW/deployment.md +348 -0
  23. package/corpus/core/docs/content/locales/zh-TW/dispatch.md +146 -0
  24. package/corpus/core/docs/content/locales/zh-TW/drop-in-agent.md +260 -0
  25. package/corpus/core/docs/content/locales/zh-TW/durable-resume.md +65 -0
  26. package/corpus/core/docs/content/locales/zh-TW/embedding-sdk.md +597 -0
  27. package/corpus/core/docs/content/locales/zh-TW/evals.md +155 -0
  28. package/corpus/core/docs/content/locales/zh-TW/extensions.md +360 -0
  29. package/corpus/core/docs/content/locales/zh-TW/external-agents.md +619 -0
  30. package/corpus/core/docs/content/locales/zh-TW/faq.md +142 -0
  31. package/corpus/core/docs/content/locales/zh-TW/file-uploads.md +122 -0
  32. package/corpus/core/docs/content/locales/zh-TW/frames.md +153 -0
  33. package/corpus/core/docs/content/locales/zh-TW/getting-started.md +199 -0
  34. package/corpus/core/docs/content/locales/zh-TW/harness-agents.md +349 -0
  35. package/corpus/core/docs/content/locales/zh-TW/human-approval.md +86 -0
  36. package/corpus/core/docs/content/locales/zh-TW/internationalization.md +147 -0
  37. package/corpus/core/docs/content/locales/zh-TW/key-concepts.md +312 -0
  38. package/corpus/core/docs/content/locales/zh-TW/local-file-mode.md +433 -0
  39. package/corpus/core/docs/content/locales/zh-TW/mcp-apps.md +147 -0
  40. package/corpus/core/docs/content/locales/zh-TW/mcp-clients.md +330 -0
  41. package/corpus/core/docs/content/locales/zh-TW/mcp-protocol.md +279 -0
  42. package/corpus/core/docs/content/locales/zh-TW/messaging.md +461 -0
  43. package/corpus/core/docs/content/locales/zh-TW/migration-workbench.md +33 -0
  44. package/corpus/core/docs/content/locales/zh-TW/multi-app-workspace.md +312 -0
  45. package/corpus/core/docs/content/locales/zh-TW/multi-tenancy.md +52 -0
  46. package/corpus/core/docs/content/locales/zh-TW/native-chat-ui.md +321 -0
  47. package/corpus/core/docs/content/locales/zh-TW/notifications.md +231 -0
  48. package/corpus/core/docs/content/locales/zh-TW/observability.md +294 -0
  49. package/corpus/core/docs/content/locales/zh-TW/observational-memory.md +77 -0
  50. package/corpus/core/docs/content/locales/zh-TW/onboarding.md +216 -0
  51. package/corpus/core/docs/content/locales/zh-TW/plan-plugin.md +200 -0
  52. package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.md +384 -0
  53. package/corpus/core/docs/content/locales/zh-TW/processors.md +106 -0
  54. package/corpus/core/docs/content/locales/zh-TW/progress.md +199 -0
  55. package/corpus/core/docs/content/locales/zh-TW/pure-agent-apps.md +39 -0
  56. package/corpus/core/docs/content/locales/zh-TW/real-time-collaboration.md +680 -0
  57. package/corpus/core/docs/content/locales/zh-TW/recurring-jobs.md +142 -0
  58. package/corpus/core/docs/content/locales/zh-TW/routing.md +79 -0
  59. package/corpus/core/docs/content/locales/zh-TW/sandbox-adapters.md +227 -0
  60. package/corpus/core/docs/content/locales/zh-TW/security.md +330 -0
  61. package/corpus/core/docs/content/locales/zh-TW/server.md +265 -0
  62. package/corpus/core/docs/content/locales/zh-TW/sharing.md +219 -0
  63. package/corpus/core/docs/content/locales/zh-TW/skills-guide.md +281 -0
  64. package/corpus/core/docs/content/locales/zh-TW/template-analytics.md +259 -0
  65. package/corpus/core/docs/content/locales/zh-TW/template-assets.md +303 -0
  66. package/corpus/core/docs/content/locales/zh-TW/template-brain.md +324 -0
  67. package/corpus/core/docs/content/locales/zh-TW/template-calendar.md +194 -0
  68. package/corpus/core/docs/content/locales/zh-TW/template-chat.md +129 -0
  69. package/corpus/core/docs/content/locales/zh-TW/template-clips.md +368 -0
  70. package/corpus/core/docs/content/locales/zh-TW/template-content.md +402 -0
  71. package/corpus/core/docs/content/locales/zh-TW/template-design.md +173 -0
  72. package/corpus/core/docs/content/locales/zh-TW/template-dispatch.md +220 -0
  73. package/corpus/core/docs/content/locales/zh-TW/template-forms.md +178 -0
  74. package/corpus/core/docs/content/locales/zh-TW/template-mail.md +239 -0
  75. package/corpus/core/docs/content/locales/zh-TW/template-plan.md +814 -0
  76. package/corpus/core/docs/content/locales/zh-TW/template-slides.md +293 -0
  77. package/corpus/core/docs/content/locales/zh-TW/template-videos.md +222 -0
  78. package/corpus/core/docs/content/locales/zh-TW/tracking.md +236 -0
  79. package/corpus/core/docs/content/locales/zh-TW/using-your-agent.md +71 -0
  80. package/corpus/core/docs/content/locales/zh-TW/voice-input.md +81 -0
  81. package/corpus/core/docs/content/locales/zh-TW/what-is-agent-native.md +202 -0
  82. package/corpus/core/docs/content/locales/zh-TW/workspace-connections.md +321 -0
  83. package/corpus/core/docs/content/locales/zh-TW/workspace-management.md +175 -0
  84. package/corpus/core/docs/content/locales/zh-TW/workspace.md +323 -0
  85. package/corpus/core/docs/content/locales/zh-TW/writing-agent-instructions.md +173 -0
  86. package/corpus/core/package.json +2 -2
  87. package/corpus/core/scripts/check-dist-imports.mjs +35 -0
  88. package/corpus/core/src/client/ErrorBoundary.tsx +10 -0
  89. package/corpus/core/src/client/FeedbackButton.tsx +12 -0
  90. package/corpus/core/src/client/blocks/library/block-copy.ts +32 -0
  91. package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +33 -0
  92. package/corpus/core/src/client/i18n.tsx +6 -1
  93. package/corpus/core/src/localization/actions/set-localization-preference.ts +2 -1
  94. package/corpus/core/src/localization/default-messages.ts +492 -0
  95. package/corpus/core/src/localization/shared.ts +45 -0
  96. package/corpus/core/src/server/agent-chat-plugin.ts +38 -0
  97. package/corpus/core/src/server/onboarding-html.ts +99 -0
  98. package/corpus/core/src/templates/default/app/i18n/index.ts +2 -0
  99. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +466 -0
  100. package/corpus/core/src/templates/default/app/root.tsx +8 -0
  101. package/corpus/templates/analytics/app/i18n/index.ts +2 -0
  102. package/corpus/templates/analytics/app/i18n/zh-TW.ts +818 -0
  103. package/corpus/templates/analytics/app/i18n-data.ts +9 -0
  104. package/corpus/templates/assets/app/i18n/index.ts +2 -0
  105. package/corpus/templates/assets/app/i18n/zh-TW.ts +860 -0
  106. package/corpus/templates/assets/app/i18n-data.ts +3 -0
  107. package/corpus/templates/brain/app/i18n/index.ts +2 -0
  108. package/corpus/templates/brain/app/i18n/zh-TW.ts +709 -0
  109. package/corpus/templates/brain/app/i18n-data.ts +3 -0
  110. package/corpus/templates/calendar/app/i18n/zh-TW.ts +836 -0
  111. package/corpus/templates/calendar/app/i18n-data.ts +4 -0
  112. package/corpus/templates/chat/app/i18n/index.ts +2 -0
  113. package/corpus/templates/chat/app/i18n/zh-TW.ts +67 -0
  114. package/corpus/templates/chat/app/i18n-data.ts +3 -0
  115. package/corpus/templates/clips/app/i18n/index.ts +2 -0
  116. package/corpus/templates/clips/app/i18n/zh-TW.ts +1280 -0
  117. package/corpus/templates/content/app/i18n/index.ts +2 -0
  118. package/corpus/templates/content/app/i18n/zh-TW.ts +906 -0
  119. package/corpus/templates/content/app/i18n-data.ts +4 -0
  120. package/corpus/templates/design/app/i18n/index.ts +2 -0
  121. package/corpus/templates/design/app/i18n/zh-TW.ts +517 -0
  122. package/corpus/templates/design/app/i18n-data.ts +6 -0
  123. package/corpus/templates/dispatch/app/i18n/index.ts +2 -0
  124. package/corpus/templates/dispatch/app/i18n/zh-TW.ts +195 -0
  125. package/corpus/templates/dispatch/app/i18n-data.ts +3 -0
  126. package/corpus/templates/forms/app/i18n/index.ts +2 -0
  127. package/corpus/templates/forms/app/i18n/zh-TW.ts +349 -0
  128. package/corpus/templates/macros/app/i18n/index.ts +2 -0
  129. package/corpus/templates/macros/app/i18n/zh-TW.ts +224 -0
  130. package/corpus/templates/mail/app/i18n/index.ts +2 -0
  131. package/corpus/templates/mail/app/i18n/zh-TW.ts +562 -0
  132. package/corpus/templates/mail/app/root.tsx +6 -0
  133. package/corpus/templates/plan/app/i18n/index.ts +2 -0
  134. package/corpus/templates/plan/app/i18n/zh-TW.ts +712 -0
  135. package/corpus/templates/slides/app/i18n/index.ts +2 -0
  136. package/corpus/templates/slides/app/i18n/zh-TW.ts +531 -0
  137. package/corpus/templates/videos/app/i18n/index.ts +2 -0
  138. package/corpus/templates/videos/app/i18n/zh-TW.ts +435 -0
  139. package/dist/client/ErrorBoundary.d.ts.map +1 -1
  140. package/dist/client/ErrorBoundary.js +10 -0
  141. package/dist/client/ErrorBoundary.js.map +1 -1
  142. package/dist/client/FeedbackButton.d.ts.map +1 -1
  143. package/dist/client/FeedbackButton.js +12 -0
  144. package/dist/client/FeedbackButton.js.map +1 -1
  145. package/dist/client/blocks/library/block-copy.d.ts.map +1 -1
  146. package/dist/client/blocks/library/block-copy.js +32 -0
  147. package/dist/client/blocks/library/block-copy.js.map +1 -1
  148. package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
  149. package/dist/client/extensions/ExtensionsSidebarSection.js +32 -0
  150. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  151. package/dist/client/i18n.d.ts.map +1 -1
  152. package/dist/client/i18n.js +6 -1
  153. package/dist/client/i18n.js.map +1 -1
  154. package/dist/collab/routes.d.ts +2 -2
  155. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  156. package/dist/localization/actions/set-localization-preference.d.ts.map +1 -1
  157. package/dist/localization/actions/set-localization-preference.js +2 -2
  158. package/dist/localization/actions/set-localization-preference.js.map +1 -1
  159. package/dist/localization/default-messages.d.ts +443 -0
  160. package/dist/localization/default-messages.d.ts.map +1 -0
  161. package/dist/localization/default-messages.js +448 -0
  162. package/dist/localization/default-messages.js.map +1 -0
  163. package/dist/localization/shared.d.ts +1 -1
  164. package/dist/localization/shared.d.ts.map +1 -1
  165. package/dist/localization/shared.js +43 -0
  166. package/dist/localization/shared.js.map +1 -1
  167. package/dist/notifications/routes.d.ts +2 -2
  168. package/dist/observability/routes.d.ts +7 -7
  169. package/dist/progress/routes.d.ts +1 -1
  170. package/dist/resources/handlers.d.ts +3 -3
  171. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  172. package/dist/server/agent-chat-plugin.js +39 -0
  173. package/dist/server/agent-chat-plugin.js.map +1 -1
  174. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  175. package/dist/server/onboarding-html.d.ts.map +1 -1
  176. package/dist/server/onboarding-html.js +96 -0
  177. package/dist/server/onboarding-html.js.map +1 -1
  178. package/dist/server/transcribe-voice.d.ts +1 -1
  179. package/dist/templates/default/app/i18n/index.ts +2 -0
  180. package/dist/templates/default/app/i18n/zh-TW.ts +466 -0
  181. package/dist/templates/default/app/root.tsx +8 -0
  182. package/docs/content/locales/zh-TW/a2a-protocol.md +392 -0
  183. package/docs/content/locales/zh-TW/actions.md +583 -0
  184. package/docs/content/locales/zh-TW/agent-mentions.md +164 -0
  185. package/docs/content/locales/zh-TW/agent-surfaces.md +397 -0
  186. package/docs/content/locales/zh-TW/agent-teams.md +171 -0
  187. package/docs/content/locales/zh-TW/agent-web-surfaces.md +161 -0
  188. package/docs/content/locales/zh-TW/audit-log.md +111 -0
  189. package/docs/content/locales/zh-TW/authentication.md +332 -0
  190. package/docs/content/locales/zh-TW/automations.md +268 -0
  191. package/docs/content/locales/zh-TW/blueprint-installer.md +83 -0
  192. package/docs/content/locales/zh-TW/cli-adapters.md +129 -0
  193. package/docs/content/locales/zh-TW/client.md +398 -0
  194. package/docs/content/locales/zh-TW/cloneable-saas.md +114 -0
  195. package/docs/content/locales/zh-TW/code-agents-ui.md +436 -0
  196. package/docs/content/locales/zh-TW/components.md +368 -0
  197. package/docs/content/locales/zh-TW/context-awareness.md +373 -0
  198. package/docs/content/locales/zh-TW/creating-templates.md +411 -0
  199. package/docs/content/locales/zh-TW/cross-app-sso.md +188 -0
  200. package/docs/content/locales/zh-TW/database.md +183 -0
  201. package/docs/content/locales/zh-TW/deployment.md +348 -0
  202. package/docs/content/locales/zh-TW/dispatch.md +146 -0
  203. package/docs/content/locales/zh-TW/drop-in-agent.md +260 -0
  204. package/docs/content/locales/zh-TW/durable-resume.md +65 -0
  205. package/docs/content/locales/zh-TW/embedding-sdk.md +597 -0
  206. package/docs/content/locales/zh-TW/evals.md +155 -0
  207. package/docs/content/locales/zh-TW/extensions.md +360 -0
  208. package/docs/content/locales/zh-TW/external-agents.md +619 -0
  209. package/docs/content/locales/zh-TW/faq.md +142 -0
  210. package/docs/content/locales/zh-TW/file-uploads.md +122 -0
  211. package/docs/content/locales/zh-TW/frames.md +153 -0
  212. package/docs/content/locales/zh-TW/getting-started.md +199 -0
  213. package/docs/content/locales/zh-TW/harness-agents.md +349 -0
  214. package/docs/content/locales/zh-TW/human-approval.md +86 -0
  215. package/docs/content/locales/zh-TW/internationalization.md +147 -0
  216. package/docs/content/locales/zh-TW/key-concepts.md +312 -0
  217. package/docs/content/locales/zh-TW/local-file-mode.md +433 -0
  218. package/docs/content/locales/zh-TW/mcp-apps.md +147 -0
  219. package/docs/content/locales/zh-TW/mcp-clients.md +330 -0
  220. package/docs/content/locales/zh-TW/mcp-protocol.md +279 -0
  221. package/docs/content/locales/zh-TW/messaging.md +461 -0
  222. package/docs/content/locales/zh-TW/migration-workbench.md +33 -0
  223. package/docs/content/locales/zh-TW/multi-app-workspace.md +312 -0
  224. package/docs/content/locales/zh-TW/multi-tenancy.md +52 -0
  225. package/docs/content/locales/zh-TW/native-chat-ui.md +321 -0
  226. package/docs/content/locales/zh-TW/notifications.md +231 -0
  227. package/docs/content/locales/zh-TW/observability.md +294 -0
  228. package/docs/content/locales/zh-TW/observational-memory.md +77 -0
  229. package/docs/content/locales/zh-TW/onboarding.md +216 -0
  230. package/docs/content/locales/zh-TW/plan-plugin.md +200 -0
  231. package/docs/content/locales/zh-TW/pr-visual-recap.md +384 -0
  232. package/docs/content/locales/zh-TW/processors.md +106 -0
  233. package/docs/content/locales/zh-TW/progress.md +199 -0
  234. package/docs/content/locales/zh-TW/pure-agent-apps.md +39 -0
  235. package/docs/content/locales/zh-TW/real-time-collaboration.md +680 -0
  236. package/docs/content/locales/zh-TW/recurring-jobs.md +142 -0
  237. package/docs/content/locales/zh-TW/routing.md +79 -0
  238. package/docs/content/locales/zh-TW/sandbox-adapters.md +227 -0
  239. package/docs/content/locales/zh-TW/security.md +330 -0
  240. package/docs/content/locales/zh-TW/server.md +265 -0
  241. package/docs/content/locales/zh-TW/sharing.md +219 -0
  242. package/docs/content/locales/zh-TW/skills-guide.md +281 -0
  243. package/docs/content/locales/zh-TW/template-analytics.md +259 -0
  244. package/docs/content/locales/zh-TW/template-assets.md +303 -0
  245. package/docs/content/locales/zh-TW/template-brain.md +324 -0
  246. package/docs/content/locales/zh-TW/template-calendar.md +194 -0
  247. package/docs/content/locales/zh-TW/template-chat.md +129 -0
  248. package/docs/content/locales/zh-TW/template-clips.md +368 -0
  249. package/docs/content/locales/zh-TW/template-content.md +402 -0
  250. package/docs/content/locales/zh-TW/template-design.md +173 -0
  251. package/docs/content/locales/zh-TW/template-dispatch.md +220 -0
  252. package/docs/content/locales/zh-TW/template-forms.md +178 -0
  253. package/docs/content/locales/zh-TW/template-mail.md +239 -0
  254. package/docs/content/locales/zh-TW/template-plan.md +814 -0
  255. package/docs/content/locales/zh-TW/template-slides.md +293 -0
  256. package/docs/content/locales/zh-TW/template-videos.md +222 -0
  257. package/docs/content/locales/zh-TW/tracking.md +236 -0
  258. package/docs/content/locales/zh-TW/using-your-agent.md +71 -0
  259. package/docs/content/locales/zh-TW/voice-input.md +81 -0
  260. package/docs/content/locales/zh-TW/what-is-agent-native.md +202 -0
  261. package/docs/content/locales/zh-TW/workspace-connections.md +321 -0
  262. package/docs/content/locales/zh-TW/workspace-management.md +175 -0
  263. package/docs/content/locales/zh-TW/workspace.md +323 -0
  264. package/docs/content/locales/zh-TW/writing-agent-instructions.md +173 -0
  265. package/package.json +2 -2
  266. package/src/templates/default/app/i18n/index.ts +2 -0
  267. package/src/templates/default/app/i18n/zh-TW.ts +466 -0
  268. package/src/templates/default/app/root.tsx +8 -0
@@ -0,0 +1,330 @@
1
+ ---
2
+ title: "安全"
3
+ description: "代理原生應用的安全模型:輸入驗證、SQL 注入預防、XSS、資料範圍、機密管理和驗證模式。"
4
+ ---
5
+
6
+ # 安全
7
+
8
+ 代理本機應用程式預設設計為安全的。該框架提供多層自動保護 - 您可以獲得 SQL 級資料隔離、參數化查詢、輸入驗證和開箱即用的驗證。
9
+
10
+ ## 你免費得到什么,以及你擁有什么 {#what-you-own}
11
+
12
+ ```an-diagram title="層層防守" summary="該框架擁有大部分威脅面;您擁有兩件事——標記表以確定範圍和驗證外部輸入。"
13
+ {
14
+ "html": "<div class=\"sec-layers\"><div class=\"diagram-card free\"><span class=\"diagram-pill ok\">由框架擁有</span><small class=\"diagram-muted\">SQL isolation &middot; parameterized queries &middot; XSS escaping &middot; auth guard &middot; CSRF cookies &middot; secret encryption</small></div><div class=\"diagram-card you\"><span class=\"diagram-pill warn\">由你掌控</span><small class=\"diagram-muted\">A. tag tables with ownableColumns() &amp; route through access guards<br>B. give every action a Zod schema &amp; send user URLs through the SSRF guard</small></div></div>",
15
+ "css": ".sec-layers{display:flex;flex-direction:column;gap:12px}.sec-layers .diagram-card{display:flex;flex-direction:column;gap:6px;padding:14px 16px}"
16
+ }
17
+ ```
18
+
19
+ 當您建置標準模式時,框架已經為您處理了大部分威脅面:
20
+
21
+ - **資料隔離** — 代理 SQL 被重寫,因此它只能看到目前使用者(和活動組織)的行。參見[Data Scoping](#data-scoping)。
22
+ - **SQL 注入** — `db-query`/`db-exec` 和 Drizzle 始終進行參數化。參見[SQL Injection Prevention](#sql-injection)。
23
+ - **XSS** — React 自動轉義、TipTap 和 `react-markdown` 消毒。參見[XSS Prevention](#xss)。
24
+ - **Auth & CSRF** — 每個 `defineAction` 都受到驗證保護; cookie 是 `httpOnly` + `SameSite=lax`。參見[Authentication](#auth)。
25
+ - **秘密加密** — 憑證和保管庫靜態加密。參見[Secrets Management](#secrets)。
26
+
27
+ 這留下了一個你實際上必須考慮的小表面:
28
+
29
+ - **A。標記您的表以進行範圍界定。**通過 [`ownableColumns()`](#data-scoping) 新增 `owner_email`(以及用於團隊資料的 `org_id`),並通過 [access guards](#access-guards) 路由 Drizzle 讀/寫。
30
+ - **B。驗證並路由外部輸入。** 為每個操作指定一個 Zod [`schema:`](#input-validation),並通過 [SSRF guard](#ssrf) 發送使用者/代理 URL 的任何伺服器端獲取。
31
+
32
+ 正確設定這兩個,其餘的都是預設值。 [Production Checklist](#production-checklist) 是發貨前的一頁面確認。
33
+
34
+ ## 設計安全 {#secure-by-design}
35
+
36
+ 當您使用標準模式時,框架架構可以防止常見漏洞:
37
+
38
+ | 漏洞 | 框架保護 |
39
+ | -------- | ------------------------------------------------------------ |
40
+ | SQL注入 | `db-query`/`db-exec` 和 Drizzle ORM 中的參數化查詢 |
41
+ | XSS | React 自動轉義 JSX; TipTap 清理富文本 |
42
+ | 資料泄露 | 通過臨時視圖進行 SQL 級別範圍界定(`owner_email`、`org_id`) |
43
+ | 繞過驗證 | Auth Guard 自動保護所有 `defineAction` 端點 |
44
+ | 輸入注入 | `defineAction` 中的 Zod 架構驗證 |
45
+ | CSRF | `SameSite=lax` + `httpOnly` cookie |
46
+ | 秘密曝光 | `.env` gitignored;靜態加密的憑證和保管庫 (AES-256-GCM) |
47
+ | SSRF | `ssrfSafeFetch` 阻止內部/元資料目標 + 重新導向重新綁定 |
48
+
49
+ ## 輸入驗證 {#input-validation}
50
+
51
+ 將 `defineAction` 與 Zod `schema:` 一起用於每個操作。該框架會在程式碼執行之前自動驗證輸入:
52
+
53
+ ```ts
54
+ import { z } from "zod";
55
+ import { defineAction } from "@agent-native/core/action";
56
+
57
+ export default defineAction({
58
+ description: "Create a note",
59
+ schema: z.object({
60
+ title: z.string().min(1).max(200).describe("Note title"),
61
+ content: z.string().optional().describe("Note body"),
62
+ }),
63
+ run: async (args) => {
64
+ // args is guaranteed valid — invalid input never reaches here
65
+ },
66
+ });
67
+ ```
68
+
69
+ 無效輸入返回明確的錯誤訊息(HTTP 為 400,代理呼叫為結構化錯誤)。舊版 `parameters:` 格式不提供執行時驗證。
70
+
71
+ ## SQL 預防注入 {#sql-injection}
72
+
73
+ 框架的 `db-query` 和 `db-exec` 工具使用參數化查詢。使用者輸入作為參數傳遞,從未插入到 SQL 字串中:
74
+
75
+ ```ts
76
+ // SAFE — parameterized query (framework default)
77
+ await exec({ sql: "INSERT INTO notes (title) VALUES (?)", args: [title] });
78
+
79
+ // SAFE — Drizzle ORM (always generates parameterized queries)
80
+ await db.insert(notes).values({ title, ownerEmail: email });
81
+
82
+ // DANGEROUS — string concatenation (never do this)
83
+ await exec(`INSERT INTO notes (title) VALUES ('${title}')`);
84
+ ```
85
+
86
+ ```an-callout
87
+ {
88
+ "tone": "risk",
89
+ "body": "切勿通過字串連線或範本文字建置 SQL。將使用者輸入作為 `args` 傳遞到 `exec` / `db-query`,或使用 Drizzle - 兩者都始終參數化。 `pnpm guards` 檢查在 CI 時捕獲無範圍和串聯的查詢。"
90
+ }
91
+ ```
92
+
93
+ ## XSS預防 {#xss}
94
+
95
+ React 自動轉義所有 JSX 表達式。附加指南:
96
+
97
+ - 切勿將 `dangerouslySetInnerHTML` 與使用者控制的內容一起使用
98
+ - 切勿使用 `innerHTML`、`eval()` 或 `document.write()`
99
+ - 對於富文本編輯,請使用 TipTap(框架依賴項)——它通過其架構進行清理
100
+ - 對於渲染 markdown,請使用 `react-markdown` — 它安全地轉換為 React 元素
101
+
102
+ ## 伺服器端獲取(SSRF) {#ssrf}
103
+
104
+ 使用者或代理控制的 URL 的任何伺服器端 `fetch` 都必須經過框架 SSRF 防護,或者它可以指向雲端元資料(`169.254.169.254`)、`localhost` 或內部服務:
105
+
106
+ ```ts
107
+ import { ssrfSafeFetch } from "@agent-native/core/extensions/url-safety";
108
+
109
+ const res = await ssrfSafeFetch(userProvidedUrl, {}, { maxRedirects: 3 });
110
+ ```
111
+
112
+ `ssrfSafeFetch` 阻止私人/內部目標,在連線時重新檢查解析的 IP(DNS 重新綁定),並重新驗證每個重新導向躍點,以便公開 URL 無法重新導向到私人網路。擴充功能 iframe 代理、`upload-image` 和設計權杖匯入器都通過它進行路由。對於僅飛行前檢查,請使用 `isBlockedExtensionUrlWithDns(url)` 和 `redirect: "manual"`。
113
+
114
+ ## 資料範圍 {#data-scoping}
115
+
116
+ 在正式環境中,框架自動將代理 SQL 查詢限制為目前使用者的資料。這是在 SQL 級別強制執行的——代理無法繞過它。本節是範圍界定管道的規範參考; [Authentication](/docs/authentication) 和 [Multi-Tenancy](/docs/multi-tenancy) 檔案連結位於此處,了解相關機制。
117
+
118
+ ### 範圍管道 {#scoping-pipeline}
119
+
120
+ 從經過驗證的工作階段到代理執行的 SQL 的流量範圍:
121
+
122
+ ```
123
+ session.orgId → AGENT_ORG_ID → SQL row scoping
124
+ ```
125
+
126
+ ```an-diagram title="範圍界定管道" summary="代理 SQL 從不直接接觸基表 - 它讀取範圍為目前標識的臨時視圖,因此裸表名稱只能返回擁有的行。"
127
+ {
128
+ "html": "<div class=\"scope-pipe\"><div class=\"diagram-node\">已登入工作階段<br><small class=\"diagram-muted\">email &middot; orgId</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-node\">Request context<br><small class=\"diagram-muted\">AGENT_ORG_ID</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-box\">Temporary VIEW<br><small class=\"diagram-muted\">WHERE owner_email = ? AND org_id = ?</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-node ok\">代理 SQL<br><small class=\"diagram-muted\">bare table names only</small></div></div>",
129
+ "css": ".scope-pipe{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.scope-pipe .diagram-node{display:flex;flex-direction:column;gap:2px;padding:10px 14px}.scope-pipe .diagram-arrow{font-size:22px;line-height:1}"
130
+ }
131
+ ```
132
+
133
+ 登入工作階段攜帶 `email` 和(當組織處於活動狀態時)`orgId`。該框架從該工作階段建立請求上下文,將活動組織暴露給代理 SQL 作為 `AGENT_ORG_ID`,並重寫每個查詢,以便它只能看到目前身分擁有的行。無論查詢來自 UI、操作還是代理,都適用相同的路徑 - 代理無法讀取使用者不是其成員的組織的資料。
134
+
135
+ ### 每使用者範圍 (`owner_email`)
136
+
137
+ 每個包含使用者特定資料的表**必須**有一個 `owner_email` 文本列。使用駝峰命名法 Drizzle 屬性名稱 — `accessFilter` 讀取為 `resourceTable.ownerEmail`:
138
+
139
+ ```ts
140
+ import {
141
+ table,
142
+ text,
143
+ integer,
144
+ ownableColumns,
145
+ } from "@agent-native/core/db/schema";
146
+
147
+ // Minimal: just the owner column
148
+ export const notes = table("notes", {
149
+ id: text("id").primaryKey(),
150
+ title: text("title").notNull(),
151
+ content: text("content"),
152
+ ownerEmail: text("owner_email").notNull(), // REQUIRED — camelCase property
153
+ });
154
+
155
+ // Or use ownableColumns() to add owner_email + org_id + visibility in one call
156
+ export const notes = table("notes", {
157
+ id: text("id").primaryKey(),
158
+ title: text("title").notNull(),
159
+ content: text("content"),
160
+ ...ownableColumns(),
161
+ });
162
+ ```
163
+
164
+ 該框架建立臨時 SQL 視圖來自動過濾查詢:
165
+
166
+ ```sql
167
+ CREATE TEMPORARY VIEW "notes" AS
168
+ SELECT * FROM main."notes"
169
+ WHERE "owner_email" = 'alice@example.com';
170
+ ```
171
+
172
+ 當該列尚不存在時,INSERT 語句會自動注入 `owner_email`。
173
+
174
+ `db-query` / `db-exec` 工具拒絕模式限定的表引用(`public.<table>`、`main.<table>`)——限定名稱解析為基表,並會繞過上面的臨時視圖。代理使用裸表名稱;範圍會自動應用。
175
+
176
+ ### 每個組織範圍界定 (`org_id`)
177
+
178
+ 對於團隊共用資料的多使用者應用,請新增 `org_id` 列。當兩列都存在時,查詢的範圍為:`WHERE owner_email = ? AND org_id = ?`。
179
+
180
+ `ownableColumns()` 架構助手在一次調用中新增了 `owner_email`、`org_id` 和 `visibility`,因此新的租戶感知表預設會獲得完整的作用域契約:
181
+
182
+ ```ts
183
+ import { table, text, ownableColumns } from "@agent-native/core/db/schema";
184
+
185
+ export const projects = table("projects", {
186
+ id: text("id").primaryKey(),
187
+ title: text("title").notNull(),
188
+ ...ownableColumns(), // adds owner_email + org_id + visibility
189
+ });
190
+ ```
191
+
192
+ ```an-schema title="What ownableColumns() adds" summary="這三列使表具有租戶意識且可共用。"
193
+ {
194
+ "entities": [
195
+ {
196
+ "id": "ownable",
197
+ "name": "ownable resource",
198
+ "note": "Any table that spreads ...ownableColumns()",
199
+ "fields": [
200
+ { "name": "owner_email", "type": "text", "nullable": false, "note": "Creator. Auto-filled by write actions; auto-injected on INSERT." },
201
+ { "name": "org_id", "type": "text", "nullable": true, "note": "所有者在建立時的活動組織。推動組織可見性檢查。" },
202
+ { "name": "visibility", "type": "enum", "nullable": false, "note": "私人|組織| public — 粗略預設值,預設為私人。" }
203
+ ]
204
+ }
205
+ ]
206
+ }
207
+ ```
208
+
209
+ ### actions中的存取守衛 {#access-guards}
210
+
211
+ 原始代理 SQL 的範圍受上述臨時視圖的限制。直接查詢 Drizzle 的操作程式碼應通過框架的存取幫助程序,以便讀取和寫入保持在目前身分範圍內:
212
+
213
+ - **`accessFilter`** — 返回 `WHERE` 謂詞,該謂詞將查詢限制為目前使用者/組織可能看到的行。在列表/讀取查詢中使用它。
214
+ - **`resolveAccess`** — 解析目前請求的有效存取範圍(所有者、組織、共用)。
215
+ - **`assertAccess`** — 保護寫入或單紀錄讀取,如果目前標識無法作用於目標行,則拋出異常。
216
+
217
+ 使用 `ownableColumns()` 建置的表需要這些範圍內的讀取和寫入;自訂 Nitro 路由必須在查詢可擁有資料之前建立請求上下文。 `guard-no-unscoped-queries` 檢查(通過 `pnpm guards` 執行)在 CI 時強制執行此操作。完整幫手API見`sharing`技能。
218
+
219
+ ### 驗證
220
+
221
+ ```bash
222
+ pnpm action db-check-scoping # 檢查所有表都有owner_email
223
+ pnpm action db-check-scoping --require-org # 還需要 org_id
224
+ ```
225
+
226
+ ## 秘密管理 {#secrets}
227
+
228
+ | 秘密型別 | 存儲位置 |
229
+ | ---------------------------- | -------------------------------------------------- |
230
+ | 部署級金鑰(每個應用一個) | `.env` 檔案(gitignored,僅伺服器端) |
231
+ | 每使用者/每組織 API 金鑰 | `saveCredential` / `resolveCredential`(靜態加密) |
232
+ | 註冊機密(側邊欄保管庫) | `app_secrets`保管庫(靜態加密) |
233
+ | OAuth 代幣(Google、GitHub) | `oauth_tokens` 通過 `saveOAuthTokens()` 存儲 |
234
+ | 工作階段權杖 | 自動(Better Auth 可以處理此問題) |
235
+
236
+ 每使用者/每組織憑證和保管庫使用 AES-256-GCM 進行靜態加密,並由 `SECRETS_ENCRYPTION_KEY` 加密(回退到 `BETTER_AUTH_SECRET`);如果沒有一個,正式環境就無法開始。要就地加密任何預先存在的明文憑證行,請執行 `pnpm action db-migrate-encrypt-credentials`(冪等、非破壞性)。
237
+
238
+ 切勿將機密存儲在 `settings`、`application_state`、來源程式碼或操作回應中。使用上面的憑證/保險庫 API - 它們處理加密和每使用者範圍。
239
+
240
+ ## 驗證 {#auth}
241
+
242
+ 驗證是自動的。有關完整設定,請參閱 [Authentication](/docs/authentication) 檔案。
243
+
244
+ **安全要點:**
245
+
246
+ - `defineAction` 端點由驗證防護自動保護
247
+ - 自訂`/api/`路由必須調用`getSession(event)`並檢查結果
248
+ - 狀態更改操作應使用 POST(actions 的預設值)
249
+ - `SameSite=lax` + `httpOnly` cookie 可阻止大多數 CSRF 攻擊
250
+
251
+ ## A2A驗證 {#a2a-identity}
252
+
253
+ 當應用通過 A2A 協議相互調用時,它們會使用使用共用金鑰簽名的 JWT 權杖來驗證身分:
254
+
255
+ ```bash
256
+ A2A_SECRET=your-shared-secret-at-least-32-chars
257
+ ```
258
+
259
+ 1. 應用程式A簽署包含`sub: "steve@example.com"`的JWT
260
+ 2. 應用程式 B 使用相同的金鑰驗證 JWT 簽名
261
+ 3. 應用程式 B 將經過驗證的 `sub` 聲明讀取到請求上下文中
262
+ 4. 資料範圍適用 - 應用程式 B 僅顯示 Steve 的資料
263
+
264
+ 如果正式環境中沒有 `A2A_SECRET`,每個 A2A 端點和 `/_agent-native/integrations/process-task` 自觸發端點都會返回 **503**。在每個調用或接收 A2A 流量的應用程式上設定它。 (對於本機開發,框架仍然允許未經驗證的調用。)
265
+
266
+ ## 入站Webhooks {#webhooks}
267
+
268
+ 入站 webhook 處理程序(Resend、SendGrid、Slack、Telegram、WhatsApp、Recall.ai、Deepgram、Zoom、Google Docs Pub/Sub)預設在正式環境中拒絕偽造請求:當缺少相應的簽名秘密環境變數時,處理程序返回 401,而不是接受和分派。
269
+
270
+ 這以前是“警告並接受”的立場 - 設定您可能會丟失的秘密,或者選取僅針對本機開發人員使用 `AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1` 恢復舊行為。請參閱 [Messaging](/docs/messaging#env-vars) 了解每個整合簽名秘密變數。
271
+
272
+ ## 正式環境清單 {#production-checklist}
273
+
274
+ ### 驗證和秘密
275
+
276
+ - [ ] `BETTER_AUTH_SECRET` 設定為隨機 32+ 字符字串 (`openssl rand -hex 32`),除非這是從 `A2A_SECRET` 派生的託管工作區部署
277
+ - [ ] `OAUTH_STATE_SECRET` 設定為單獨的隨機 32+ 字符字串(不要重複使用 `BETTER_AUTH_SECRET`) - 請參閱 [OAuth State Signing](#oauth-state)
278
+ - [ ] 在調用或接收 A2A 流量的每個應用程式上設定 `A2A_SECRET` — 請參閱 [A2A Identity Verification](#a2a-identity)
279
+ - [ ] `SECRETS_ENCRYPTION_KEY` 設定(或依賴 `BETTER_AUTH_SECRET` 後備) - 請參閱 [Secrets Management](#secrets)
280
+ - [ ] `AUTH_SKIP_EMAIL_VERIFICATION` 在正式環境中**未**設定(或僅在 QA 預覽部署中設定)
281
+
282
+ ### Webhook 秘密(為您使用的整合設定秘密)
283
+
284
+ - [ ] 為每個啟用的入站整合設定簽名金鑰 - 有關每個整合列表,請參閱 [Inbound Webhooks](#webhooks) 和 [Messaging](/docs/messaging#env-vars)
285
+ - [ ] `AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS` 未在產品中設定
286
+
287
+ ### 架構
288
+
289
+ - [ ] 每個面向使用者的表都有 `owner_email`,多使用者表也有 `org_id` — 請參閱 [Data Scoping](#data-scoping)
290
+ - [ ] Ownable-table 讀/寫通過 [access guards](#access-guards)
291
+ - [ ] 所有 actions 都使用 `defineAction` 和 Zod `schema:` — 參見 [Input Validation](#input-validation)
292
+ - [ ] 使用者/代理 URL 的伺服器端獲取通過 `ssrfSafeFetch` — 請參閱 [SSRF](#ssrf)
293
+ - [ ] 沒有包含使用者內容的 `dangerouslySetInnerHTML`(或通過 DOMPurify 執行輸出)
294
+ - [ ] 沒有字串連線 SQL
295
+ - [ ] `pnpm guards` 幹淨(`guard-no-unscoped-queries`、`guard-no-env-credentials`、`guard-no-env-mutation`、`guard-no-localhost-fallback`、`guard-no-unscoped-credentials`、`guard-no-drizzle-push`)
296
+ - [ ] 使用兩個使用者帳戶進行測試以驗證資料隔離
297
+
298
+ ### 其他強化
299
+
300
+ - [ ] `AGENT_NATIVE_DEBUG_ERRORS` 在真實產品中**未**設定(僅在偵錯預覽中)
301
+ - [ ] `AGENT_NATIVE_KEYS_WORKSPACE_FALLBACK` **未**設定,除非您的組織實際上共用工作區金鑰 - 請參閱 [Cross-User Tooling Secrets](#tooling-secrets)
302
+ - [] 在多租戶部署中,**使用者自帶 `ANTHROPIC_API_KEY`** - 框架拒絕回退到部署級別環境變數
303
+
304
+ ---
305
+
306
+ 以下部分介紹了您只能在特定部署中使用的利基環境標志。大多數應用程式從不接觸它們。
307
+
308
+ ## OAuth 狀態簽名 {#oauth-state}
309
+
310
+ OAuth 流(Google、Atlassian、Zoom)使用專用的 HMAC 金鑰簽署其狀態信封:
311
+
312
+ ```bash
313
+ OAUTH_STATE_SECRET=$(openssl rand -hex 32)
314
+ ```
315
+
316
+ 這曾經退回到 `GOOGLE_CLIENT_SECRET`(與 Google 共用的憑證)——Google 秘密的泄露會讓攻擊者偽造 OAuth 狀態信封。專用金鑰獨立於任何第三方秘密。如果 `OAUTH_STATE_SECRET` 未設定,則框架回退到 `BETTER_AUTH_SECRET`;託管工作區部署還可以從已經需要的 `A2A_SECRET` 派生專用 OAuth 金鑰。如果這些伺服器機密均不可用,OAuth 流程將在正式環境中失敗。
317
+
318
+ `redirect_uri` 查詢參數也會根據允許清單(同來源 + 框架 `/_agent-native/...` 路徑)進行驗證。範本中的自訂 OAuth 流應在簽署狀態之前使用框架的 `isAllowedOAuthRedirectUri()` 幫助程序。
319
+
320
+ ## 跨使用者工具秘密 {#tooling-secrets}
321
+
322
+ 預設情況下,引用 `${keys.NAME}` 的工具和自動化會解析每個使用者的機密。在此版本中,工作區範圍回退預設情況下處於關閉狀態 - 惡意組織成員可能會植入工作區 `OPENAI_API_KEY` 並獲取其他成員的 API 調用。
323
+
324
+ 如果您的組織真正共用工作區範圍的金鑰(例如單個公司 Stripe 金鑰),請選取恢復舊行為:
325
+
326
+ ```bash
327
+ AGENT_NATIVE_KEYS_WORKSPACE_FALLBACK=1
328
+ ```
329
+
330
+ 無論此標志如何,工作空間範圍的秘密寫入仍然需要組織所有者/管理員角色。
@@ -0,0 +1,265 @@
1
+ ---
2
+ title: "伺服器"
3
+ description: "Nitro 伺服器路由、外掛、框架安裝的路由、請求上下文和 SQL 支持的同步。"
4
+ ---
5
+
6
+ # 伺服器
7
+
8
+ 代理本機應用程式使用 [Nitro](https://nitro.build) 作為伺服器路由和外掛。大多數產品行為應該存在於 [Actions](/docs/actions) 中;自訂路由適用於 actions 不適合的協議表面:上傳、流式傳輸、公開頁面、webhooks、OAuth 回呼和特定於提供者的 API。
9
+
10
+ ```an-diagram title="伺服器上執行什么" summary="操作是預設的。自訂檔案路由和框架安裝的路由共用相同的 Nitro 應用程式和相同的 SQL 資料庫。"
11
+ {
12
+ "html": "<div class=\"diagram-server\"><div class=\"diagram-col entry\"><div class=\"diagram-node\">瀏覽器 / UI</div><div class=\"diagram-node\">代理循環</div><div class=\"diagram-node\">外部用戶端<br><small class=\"diagram-muted\">HTTP · MCP · A2A</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-panel\" data-rough><strong>Nitro 伺服器</strong><div class=\"diagram-row\"><span class=\"diagram-pill accent\">Actions</span><small class=\"diagram-muted\">預設表面</small></div><div class=\"diagram-row\"><span class=\"diagram-pill\">/_agent-native/*</span><small class=\"diagram-muted\">framework routes</small></div><div class=\"diagram-row\"><span class=\"diagram-pill\">/api/*</span><small class=\"diagram-muted\">custom file routes</small></div><div class=\"diagram-row\"><span class=\"diagram-pill\">plugins</span><small class=\"diagram-muted\">啟動:遷移、工作</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-box\" data-rough>SQL 資料庫<br><small class=\"diagram-muted\">Drizzle · 協調點</small></div></div>",
13
+ "css": ".diagram-server{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.diagram-server .diagram-col{display:flex;flex-direction:column;gap:10px}.diagram-server .diagram-panel{display:flex;flex-direction:column;gap:8px;padding:14px 16px}.diagram-server .diagram-row{display:flex;align-items:center;gap:8px}.diagram-server .diagram-arrow{font-size:22px;line-height:1}"
14
+ }
15
+ ```
16
+
17
+ ## 基於檔案的路由 {#file-based-routes}
18
+
19
+ `server/routes/` 和 Nitro 中的路由將檔案名對應到方法和路徑:
20
+
21
+ ```text
22
+ server/routes/
23
+ api/
24
+ health.get.ts -> GET /api/health
25
+ uploads.post.ts -> POST /api/uploads
26
+ webhooks/
27
+ stripe.post.ts -> POST /api/webhooks/stripe
28
+ [...page].get.ts -> SSR catch-all for public pages
29
+ ```
30
+
31
+ 每條路由匯出一個`defineEventHandler`:
32
+
33
+ ```ts
34
+ // server/routes/api/health.get.ts
35
+ import { defineEventHandler } from "h3";
36
+
37
+ export default defineEventHandler(() => ({
38
+ ok: true,
39
+ service: "my-template",
40
+ }));
41
+ ```
42
+
43
+ ### 路由命名約定 {#route-naming-conventions}
44
+
45
+ | 檔案名模式 | HTTP方法 | 範例路徑 |
46
+ | ------------------ | -------- | ------------------------- |
47
+ | `index.get.ts` | GET | `/api/items` |
48
+ | `index.post.ts` | POST | `/api/items` |
49
+ | `[id].get.ts` | GET | `/api/items/:id` |
50
+ | `[id].patch.ts` | PATCH | `/api/items/:id` |
51
+ | `[id].delete.ts` | DELETE | `/api/items/:id` |
52
+ | `[...slug].get.ts` | GET | `/api/items/*` 或包羅萬象 |
53
+
54
+ ## 首選 Actions 進行應用操作 {#actions-first}
55
+
56
+ 如果 UI 和代理都需要執行某些操作,請定義操作而不是自訂 API 路由。 Actions自動變成:
57
+
58
+ - 代理工具。
59
+ - 型別化前端掛鉤。
60
+ - `/_agent-native/actions/:name`下的HTTP端點。
61
+ - MCP 和 A2A 可調用工具。
62
+ - CLI 用於開發的指令。
63
+
64
+ 僅當您需要路由型協議或二進制/流行為時才使用自訂 `/api/*` 路由。參見[Actions](/docs/actions)。
65
+
66
+ ## 一次性文本完成 {#complete-text}
67
+
68
+ 大多數人工智能工作應通過代理聊天進行,以便使用者可以檢視、引導和審核
69
+ 發生了什么。對於有意不需要的窄伺服器端轉換
70
+ 工具、聊天紀錄或執行狀態,使用 `completeText()` 作為顯式轉義
71
+ 孵化。
72
+
73
+ ```ts
74
+ // actions/classify-message.ts
75
+ import { defineAction } from "@agent-native/core/action";
76
+ import { completeText } from "@agent-native/core/server";
77
+ import { z } from "zod";
78
+
79
+ export default defineAction({
80
+ description: "Classify a short message",
81
+ schema: z.object({ body: z.string() }),
82
+ run: async ({ body }) => {
83
+ const result = await completeText({
84
+ systemPrompt:
85
+ "Return exactly one label: urgent, follow-up, waiting, or archive.",
86
+ input: body,
87
+ maxOutputTokens: 16,
88
+ temperature: 0,
89
+ });
90
+
91
+ return { label: result.text.trim() };
92
+ },
93
+ });
94
+ ```
95
+
96
+ `completeText()` 通過與代理相同的設定引擎層執行
97
+ 聊天,包括 Builder、Anthropic、AI SDK 提供者、使用者/應用模型預設值,
98
+ 請求範圍的秘密和引擎規範化的錯誤。它僅適用於伺服器;不要
99
+ 從用戶端程式碼調用模型提供者。如果操作是面向使用者的,則將其包裝起來
100
+ 在一個操作中,以便 UI 和代理共用相同的功能。
101
+
102
+ ## 請求上下文和存取 {#request-context}
103
+
104
+ Actions 由框架自動安裝並與請求上下文一起執行。自訂路線則不然。如果自訂路由讀取或寫入可擁有的資源,則載入工作階段並包裝工作:
105
+
106
+ ```an-annotated-code title="將自訂路由範圍限定為請求使用者"
107
+ {
108
+ "filename": "server/routes/api/projects.get.ts",
109
+ "language": "ts",
110
+ "code": "import { defineEventHandler, createError } from \"h3\";\nimport { getSession, runWithRequestContext } from \"@agent-native/core/server\";\nimport { getDb } from \"../../db/index.js\";\nimport { accessFilter } from \"@agent-native/core/sharing\";\nimport * as schema from \"../../db/schema\";\n\nexport default defineEventHandler(async (event) => {\n const session = await getSession(event);\n if (!session?.email) {\n throw createError({ statusCode: 401, statusMessage: \"Unauthorized\" });\n }\n\n return runWithRequestContext(\n { userEmail: session.email, orgId: session.orgId },\n async () => {\n const db = getDb();\n return db\n .select()\n .from(schema.projects)\n .where(accessFilter(schema.projects, schema.project分享s));\n },\n );\n});",
111
+ "annotations": [
112
+ {
113
+ "lines": "7-10",
114
+ "label": "自訂路由沒有自動上下文",
115
+ "note": "與操作不同,檔案路由必須載入工作階段本身,並且在沒有經過驗證的使用者時無法關閉。"
116
+ },
117
+ {
118
+ "lines": "12-13",
119
+ "label": "建立請求上下文",
120
+ "note": "`runWithRequestContext` 使 user/org 在工作期間可供範圍界定助手使用。"
121
+ },
122
+ {
123
+ "lines": "18-19",
124
+ "label": "範圍可擁有的讀取",
125
+ "note": "`accessFilter` constrains the query to rows the caller may see. Never run an unscoped `db.select().from(ownableTable)` here."
126
+ }
127
+ ]
128
+ }
129
+ ```
130
+
131
+ `getDb`是通過`server/db/index.ts`中的`createGetDb(schema)`為每個應用程式建立的,因此自訂路由從範本(`../../db/index.js`)匯入,而不是從`@agent-native/core/db`匯入;見[Database — Where the DB Client Lives](/docs/database#db-client)。不要在自訂路由中執行無作用域的 `db.select().from(ownableTable)`。
132
+
133
+ ## 伺服器外掛 {#server-plugins}
134
+
135
+ 外掛位於 `server/plugins/` 中並在啟動時執行。將它們用於遷移、提供程序設定、重複作業、整合適配器和框架外掛設定。
136
+
137
+ ```ts
138
+ // server/plugins/db.ts
139
+ import { runMigrations } from "@agent-native/core/db";
140
+
141
+ export default runMigrations(
142
+ [
143
+ {
144
+ version: 1,
145
+ sql: `CREATE TABLE IF NOT EXISTS projects (
146
+ id TEXT PRIMARY KEY,
147
+ title TEXT NOT NULL,
148
+ owner_email TEXT NOT NULL,
149
+ org_id TEXT,
150
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
151
+ )`,
152
+ },
153
+ ],
154
+ { table: "my_app_migrations" },
155
+ );
156
+ ```
157
+
158
+ 遷移必須是累加的。切勿將破壞性的 SQL 放入啟動外掛中。
159
+
160
+ ## 框架安裝路由 {#framework-routes}
161
+
162
+ 框架在`/_agent-native/`下掛載自己的路由。將該命名空間視為保留。
163
+
164
+ | 路由前綴 | 目的 |
165
+ | -------------------------------- | ---------------------------------------------------------------- |
166
+ | `/_agent-native/actions/:name` | 操作 HTTP 端點 |
167
+ | `/_agent-native/agent-chat` | 代理聊天循環 |
168
+ | `/_agent-native/poll` | SQL 支持的 UI 同步 |
169
+ | `/_agent-native/resources/*` | 工作區資源 |
170
+ | `/_agent-native/extensions/*` | 執行時擴充功能和擴充功能代理(舊別名:`/_agent-native/tools/*`) |
171
+ | `/_agent-native/integrations/*` | 訊息傳遞/webhook 整合 |
172
+ | `/_agent-native/a2a` | 代理到代理 JSON-RPC |
173
+ | `/_agent-native/mcp` | MCP端點 |
174
+ | `/_agent-native/onboarding/*` | 設定清單 |
175
+ | `/_agent-native/observability/*` | 跟蹤、意見回饋、評估、實驗 |
176
+ | `/_agent-native/file-upload` | 檔案上傳提供程序端點 |
177
+
178
+ 自訂應用路由應使用 `/api/*`、公開應用路徑或不與 `/_agent-native/` 衝突的提供者特定回調路徑。
179
+
180
+ ## SQL 支持的同步 {#sync}
181
+
182
+ 代理本機不依賴於檔案系統觀察程序或粘性內存狀態。當 actions 或框架助手更改資料時,資料庫同步版本會遞增。用戶端 `useDbSync()` 掛鉤輪詢 `/_agent-native/poll` 並使 React 查詢快取無效。
183
+
184
+ 這適用於無伺服器和多執行個體部署,因為資料庫是協調點。如果您在 actions 之外編寫自訂突變,請使用框架助手或發出適當的同步失效,以便開啟 UI 刷新。
185
+
186
+ ```an-diagram title="SQL-backed 同步循環" summary="沒有觀察者,沒有粘性狀態。寫入會碰撞 SQL 中的版本;每個用戶端都會輪詢版本並重新獲取。"
187
+ {
188
+ "html": "<div class=\"diagram-sync\"><div class=\"diagram-box\" data-rough>Action / 輔助函數<br><small class=\"diagram-muted\">mutates data</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-panel\" data-rough><strong>SQL 資料庫</strong><small class=\"diagram-muted\">sync version increments</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&larr;</div><div class=\"diagram-col\"><div class=\"diagram-node\">useDbSync()<br><small class=\"diagram-muted\">polls /_agent-native/poll</small></div><div class=\"diagram-pill ok\">invalidate caches &rarr; UI refreshes</div></div></div>",
189
+ "css": ".diagram-sync{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.diagram-sync .diagram-col{display:flex;flex-direction:column;gap:8px;align-items:flex-start}.diagram-sync .diagram-arrow{font-size:22px;line-height:1}"
190
+ }
191
+ ```
192
+
193
+ ```an-api title="輪詢端點" method="GET" path="/_agent-native/poll"
194
+ {
195
+ "method": "GET",
196
+ "path": "/_agent-native/poll",
197
+ "summary": "返回目前的每個來源資料庫同步版本,以便用戶端可以檢測更改。",
198
+ "description": "`useDbSync()` calls this on an interval (and falls back to it when SSE is unavailable). When a returned version is higher than the client's last-seen value, the matching React Query caches are invalidated and refetch.",
199
+ "auth": "Session cookie (request-scoped identity)",
200
+ "responses": [
201
+ { "status": "200", "description": "Current sync versions keyed by source." }
202
+ ]
203
+ }
204
+ ```
205
+
206
+ ## Webhooks {#webhooks}
207
+
208
+ 入站 webhooks 應驗證、保留並快速返回。長時間執行的代理工作應使用整合佇列模式:
209
+
210
+ 1. 驗證平台簽名或質詢。
211
+ 2. 將持久工作插入SQL。
212
+ 3. 自觸發簽名的處理器路由。
213
+ 4. 立即返回 200。
214
+ 5. 讓新的處理器執行執行代理循環並發布結果。
215
+
216
+ ```an-diagram title="整合佇列模式" summary="Webhook 處理程序以毫秒為單位返回;單獨的簽名執行執行緩慢的代理工作。"
217
+ {
218
+ "html": "<div class=\"diagram-webhook\"><div class=\"diagram-box\" data-rough>入站 webhook<br><small class=\"diagram-muted\">Slack · Stripe · email</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-panel\" data-rough><strong>Handler</strong><div class=\"diagram-step\"><span class=\"diagram-pill\">1</span><small class=\"diagram-muted\">verify signature</small></div><div class=\"diagram-step\"><span class=\"diagram-pill\">2</span><small class=\"diagram-muted\">將工作寫入 SQL</small></div><div class=\"diagram-step\"><span class=\"diagram-pill\">3</span><small class=\"diagram-muted\">self-fire processor</small></div><div class=\"diagram-step\"><span class=\"diagram-pill ok\">4</span><small class=\"diagram-muted\">return 200 now</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-box\" data-rough>Signed processor<br><small class=\"diagram-muted\">執行代理循環並發布結果</small></div></div>",
219
+ "css": ".diagram-webhook{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.diagram-webhook .diagram-panel{display:flex;flex-direction:column;gap:6px;padding:14px 16px}.diagram-webhook .diagram-step{display:flex;align-items:center;gap:8px}.diagram-webhook .diagram-arrow{font-size:22px;line-height:1}"
220
+ }
221
+ ```
222
+
223
+ > [!WARNING]
224
+ > 不要依賴返回回應後未等待的承諾 — 無伺服器主機會凍結執行。請參閱 [Messaging](/docs/messaging) 以了解規範整合佇列。
225
+
226
+ ## 高級:逃生艙口 {#advanced-escape-hatches}
227
+
228
+ 大多數範本永遠不需要這些。 Nitro 檔案路由和框架的代理
229
+ 聊天外掛已經連線應用伺服器和正式環境代理處理程序。
230
+ 僅在外部建置自訂伺服器整合時才使用它們
231
+ 標準範本外掛堆堆疊。
232
+
233
+ ### 編程式 H3 伺服器 {#create-server}
234
+
235
+ 對於直接需要 H3 應用的自訂包或測試,`createServer()`
236
+ 返回預設定的應用程式和路由器:
237
+
238
+ ```ts
239
+ import { createServer } from "@agent-native/core/server";
240
+ import { defineEventHandler } from "h3";
241
+
242
+ const { app, router } = createServer();
243
+
244
+ router.get(
245
+ "/api/health",
246
+ defineEventHandler(() => ({ ok: true })),
247
+ );
248
+ ```
249
+
250
+ ### 正式環境代理處理程序 {#agent-handler}
251
+
252
+ 框架的代理聊天外掛已安裝正式環境代理處理程序
253
+ 用於範本。僅在建置時直接調用`createProductionAgentHandler()`
254
+ 標準範本外掛堆堆疊之外的自訂伺服器整合 -
255
+ 否則通過`AGENTS.md`、skills、actions和
256
+ 代理聊天外掛。
257
+
258
+ ```ts
259
+ import { createProductionAgentHandler } from "@agent-native/core/server";
260
+
261
+ const handler = createProductionAgentHandler({
262
+ scripts,
263
+ systemPrompt: "You are the app agent...",
264
+ });
265
+ ```