handoff-app 2.0.0-8 → 2.0.0

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 (322) hide show
  1. package/{Changelog.md → CHANGELOG.md} +85 -1
  2. package/{License.md → LICENSE.md} +1 -1
  3. package/README.md +816 -393
  4. package/RECIPES.md +975 -0
  5. package/UPGRADE.md +57 -9
  6. package/components.json +20 -20
  7. package/config/docs/foundations/colors/guidelines.md +0 -1
  8. package/config/docs/foundations/colors.md +0 -1
  9. package/config/docs/foundations/effects/guidelines.md +0 -1
  10. package/config/docs/foundations/effects/resources.md +0 -1
  11. package/config/docs/foundations/effects.md +0 -1
  12. package/config/docs/foundations/fonts.md +0 -1
  13. package/config/docs/foundations/grid.md +0 -1
  14. package/config/docs/foundations/icon.md +0 -1
  15. package/config/docs/foundations/icons/guidelines.md +0 -1
  16. package/config/docs/foundations/icons.md +0 -1
  17. package/config/docs/foundations/images/guidelines.md +0 -1
  18. package/config/docs/foundations/images/resources.md +0 -1
  19. package/config/docs/foundations/images.md +0 -1
  20. package/config/docs/foundations/logo/resources.md +0 -1
  21. package/config/docs/foundations/logo.md +0 -1
  22. package/config/docs/foundations/typography/guidelines.md +0 -1
  23. package/config/docs/foundations/typography/resources.md +0 -1
  24. package/config/docs/foundations/typography.md +0 -1
  25. package/config/docs/foundations.md +0 -1
  26. package/config/docs/guidelines.md +0 -1
  27. package/config/docs/index.md +0 -1
  28. package/config/docs/system/tokens/foundations/colors.md +0 -4
  29. package/config/docs/system/tokens/foundations/effects.md +0 -4
  30. package/config/docs/system/tokens/foundations/typography.md +0 -2
  31. package/config/docs/system.md +0 -2
  32. package/config/templates/page.md +2 -1
  33. package/config/templates/page.mdx +2 -1
  34. package/dist/ai/connections.d.ts +66 -0
  35. package/dist/ai/connections.js +149 -0
  36. package/dist/ai/define.d.ts +10 -0
  37. package/dist/ai/define.js +13 -0
  38. package/dist/ai/types.d.ts +26 -0
  39. package/dist/ai/types.js +10 -0
  40. package/dist/app-builder/build.d.ts +14 -7
  41. package/dist/app-builder/build.js +195 -66
  42. package/dist/app-builder/client-config.js +3 -2
  43. package/dist/app-builder/paths.d.ts +0 -12
  44. package/dist/app-builder/paths.js +3 -20
  45. package/dist/app-builder/static-export.js +1 -1
  46. package/dist/app-builder/vercel-output.d.ts +1 -1
  47. package/dist/app-builder/vercel-output.js +5 -4
  48. package/dist/cache/build-cache.d.ts +27 -4
  49. package/dist/cache/build-cache.js +114 -47
  50. package/dist/cache/build-inputs.d.ts +13 -0
  51. package/dist/cache/build-inputs.js +19 -0
  52. package/dist/cache/index.d.ts +2 -1
  53. package/dist/cache/index.js +5 -1
  54. package/dist/catalog/normalize.js +3 -0
  55. package/dist/catalog/previews.js +5 -4
  56. package/dist/catalog/types.d.ts +8 -0
  57. package/dist/cli/create.js +1 -2
  58. package/dist/commands/build/index.d.ts +1 -1
  59. package/dist/commands/build/index.js +1 -1
  60. package/dist/commands/utils.d.ts +3 -3
  61. package/dist/config/defaults.js +7 -4
  62. package/dist/config/from-env.d.ts +4 -0
  63. package/dist/config/from-env.js +38 -1
  64. package/dist/config/helpers.js +2 -2
  65. package/dist/config/index.d.ts +0 -1
  66. package/dist/config/index.js +1 -4
  67. package/dist/config/loader.js +28 -2
  68. package/dist/config/resolve-env.d.ts +2 -1
  69. package/dist/config/resolve-env.js +28 -12
  70. package/dist/config/runtime.js +9 -11
  71. package/dist/handlebars.d.ts +10 -2
  72. package/dist/index.d.ts +12 -7
  73. package/dist/index.js +18 -22
  74. package/dist/nav/index.d.ts +2 -2
  75. package/dist/nav/registry.d.ts +3 -3
  76. package/dist/nav/registry.js +1 -1
  77. package/dist/nav/workspace.d.ts +3 -3
  78. package/dist/nav/workspace.js +1 -1
  79. package/dist/pipeline/figma.d.ts +13 -2
  80. package/dist/pipeline/figma.js +86 -46
  81. package/dist/pipeline/styles.js +1 -1
  82. package/dist/pipeline/validation.d.ts +1 -1
  83. package/dist/pipeline/validation.js +3 -3
  84. package/dist/providers.d.ts +10 -0
  85. package/dist/providers.js +13 -0
  86. package/dist/registry/asset-storage/define.d.ts +5 -5
  87. package/dist/registry/asset-storage/define.js +4 -4
  88. package/dist/registry/asset-storage/resolve.d.ts +9 -19
  89. package/dist/registry/asset-storage/resolve.js +33 -21
  90. package/dist/registry/asset-storage/types.d.ts +37 -17
  91. package/dist/registry/asset-storage/types.js +5 -5
  92. package/dist/registry/auth/ai-keys.d.ts +32 -0
  93. package/dist/registry/auth/ai-keys.js +69 -0
  94. package/dist/registry/auth/crypto.d.ts +17 -0
  95. package/dist/registry/auth/crypto.js +61 -1
  96. package/dist/registry/auth/index.d.ts +2 -1
  97. package/dist/registry/auth/index.js +11 -2
  98. package/dist/registry/checkout/index.d.ts +2 -1
  99. package/dist/registry/checkout/index.js +57 -127
  100. package/dist/registry/client.js +53 -17
  101. package/dist/registry/db/driver.js +3 -3
  102. package/dist/registry/db/schema.d.ts +261 -3
  103. package/dist/registry/db/schema.js +29 -4
  104. package/dist/registry/email/define.d.ts +10 -0
  105. package/dist/registry/email/define.js +13 -0
  106. package/dist/registry/email/providers/smtp.d.ts +10 -0
  107. package/dist/registry/email/providers/smtp.js +73 -0
  108. package/dist/registry/email/resolve.d.ts +28 -0
  109. package/dist/registry/email/resolve.js +74 -0
  110. package/dist/registry/email/types.d.ts +24 -0
  111. package/dist/registry/email/types.js +6 -0
  112. package/dist/registry/path.d.ts +2 -0
  113. package/dist/registry/path.js +11 -1
  114. package/dist/registry/publish/package.js +8 -0
  115. package/dist/registry/transfer.d.ts +4 -0
  116. package/dist/store/registry.d.ts +3 -3
  117. package/dist/store/registry.js +4 -4
  118. package/dist/transformers/plugins/ssr-render.js +40 -15
  119. package/dist/transformers/preview/component/builder.d.ts +1 -9
  120. package/dist/transformers/preview/component/builder.js +17 -17
  121. package/dist/transformers/preview/component/css.d.ts +3 -1
  122. package/dist/transformers/preview/component/css.js +92 -51
  123. package/dist/transformers/preview/component/html.d.ts +3 -1
  124. package/dist/transformers/preview/component/html.js +6 -2
  125. package/dist/transformers/preview/component/javascript.d.ts +2 -1
  126. package/dist/transformers/preview/component/javascript.js +10 -4
  127. package/dist/transformers/preview/pattern/html.js +3 -1
  128. package/dist/transformers/preview/types.d.ts +13 -0
  129. package/dist/transformers/utils/build.d.ts +24 -0
  130. package/dist/transformers/utils/build.js +100 -1
  131. package/dist/transformers/utils/module.js +2 -1
  132. package/dist/types/config.d.ts +135 -18
  133. package/dist/utils/path.d.ts +1 -5
  134. package/dist/utils/path.js +6 -23
  135. package/docs/api.md +6 -4
  136. package/docs/cli.md +275 -54
  137. package/drizzle/0007_add_ai_keys.sql +11 -0
  138. package/drizzle/0008_add_source_dir.sql +2 -0
  139. package/drizzle/meta/0007_snapshot.json +2013 -0
  140. package/drizzle/meta/0008_snapshot.json +2025 -0
  141. package/drizzle/meta/_journal.json +14 -0
  142. package/package.json +19 -8
  143. package/src/ai/README.md +42 -0
  144. package/src/ai/connections.ts +189 -0
  145. package/src/ai/define.ts +15 -0
  146. package/src/ai/types.ts +30 -0
  147. package/src/app/components/AiAssistant/AiAssistantPanel.tsx +144 -0
  148. package/src/app/components/AiAssistant/AiAssistantProvider.tsx +215 -0
  149. package/src/app/components/AiAssistant/AiConversation.tsx +737 -0
  150. package/src/app/components/AiAssistant/AiToolResult.tsx +99 -0
  151. package/src/app/components/AiAssistant/dockState.ts +86 -0
  152. package/src/app/components/AiAssistant/toolLabel.ts +24 -0
  153. package/src/app/components/AiAssistant/useAiChat.ts +147 -0
  154. package/src/app/components/AiAssistant/useAiConnections.ts +86 -0
  155. package/src/app/components/AiAssistant/usePageContext.ts +63 -0
  156. package/src/app/components/Auth/AccountLayout.tsx +58 -19
  157. package/src/app/components/Auth/AuthShell.tsx +27 -33
  158. package/src/app/components/Auth/RegistryInstallGate.tsx +4 -8
  159. package/src/app/components/Auth/installStatus.ts +29 -0
  160. package/src/app/components/Component/PageSliceResolver.tsx +1 -0
  161. package/src/app/components/Component/Preview.tsx +383 -189
  162. package/src/app/components/Component/slices/ComponentDisplaySlice.tsx +4 -0
  163. package/src/app/components/Foundations/ColorGrid.tsx +13 -14
  164. package/src/app/components/Layout/Header.tsx +21 -15
  165. package/src/app/components/Layout/Main.tsx +2 -2
  166. package/src/app/components/Markdown/MarkdownComponents.tsx +30 -32
  167. package/src/app/components/McpIntegration/McpConfigDialog.tsx +12 -51
  168. package/src/app/components/Navigation/MobileNav.tsx +2 -2
  169. package/src/app/components/Navigation/SideNav.tsx +1 -15
  170. package/src/app/components/context/NavProvider.tsx +7 -3
  171. package/src/app/components/ui/attachment.tsx +50 -0
  172. package/src/app/components/ui/bubble.tsx +57 -0
  173. package/src/app/components/ui/button.tsx +3 -1
  174. package/src/app/components/ui/confirm-dialog.tsx +87 -0
  175. package/src/app/components/ui/dialog.tsx +7 -2
  176. package/src/app/components/ui/marker.tsx +56 -0
  177. package/src/app/components/ui/sidebar.tsx +3 -1
  178. package/src/app/components/util/index.ts +3 -12
  179. package/src/app/css/index.css +64 -0
  180. package/src/app/lib/ai/auth.ts +33 -0
  181. package/src/app/lib/ai/context.ts +99 -0
  182. package/src/app/lib/ai/model.ts +79 -0
  183. package/src/app/lib/ai/prompt.ts +36 -0
  184. package/src/app/lib/ai/resolve.ts +97 -0
  185. package/src/app/lib/ai/tools.ts +120 -0
  186. package/src/app/lib/api/methods.ts +13 -0
  187. package/src/app/lib/asset-storage.ts +35 -36
  188. package/src/app/lib/auth/api.ts +4 -12
  189. package/src/app/lib/auth/email.ts +96 -23
  190. package/src/app/lib/docs-api/page-rendering.ts +1 -1
  191. package/src/app/lib/docs-api/registry.ts +2 -3
  192. package/src/app/lib/docs-api/runtime-config.ts +47 -21
  193. package/src/app/lib/mcp/components.ts +523 -0
  194. package/src/app/lib/mcp/page-url.ts +24 -0
  195. package/src/app/lib/mcp/pages.ts +84 -0
  196. package/src/app/lib/mcp/result.ts +33 -0
  197. package/src/app/lib/mcp/server.ts +39 -318
  198. package/src/app/lib/mcp/tokens.ts +334 -0
  199. package/src/app/lib/mcp/tool.ts +19 -0
  200. package/src/app/lib/registry-api/asset-transfer.ts +119 -11
  201. package/src/app/lib/registry-api/errors.ts +2 -0
  202. package/src/app/lib/registry-api/handler.ts +7 -1
  203. package/src/app/lib/registry-api/transfer.ts +28 -6
  204. package/src/app/lib/server-module.ts +34 -0
  205. package/src/app/lib/utils.ts +20 -0
  206. package/src/app/next.config.mjs +26 -24
  207. package/src/app/pages/[...slug]/index.tsx +2 -1
  208. package/src/app/pages/_app.tsx +6 -2
  209. package/src/app/pages/_document.tsx +6 -0
  210. package/src/app/pages/account/ai.tsx +183 -0
  211. package/src/app/pages/account/index.tsx +68 -68
  212. package/src/app/pages/account/tokens.tsx +37 -7
  213. package/src/app/pages/account/users.tsx +75 -15
  214. package/src/app/pages/api/account/ai/keys/[connectionId].ts +60 -0
  215. package/src/app/pages/api/account/ai/keys/index.ts +20 -0
  216. package/src/app/pages/api/admin/users/[id]/[action].ts +80 -11
  217. package/src/app/pages/api/admin/users/index.ts +2 -2
  218. package/src/app/pages/api/ai/chat.ts +115 -0
  219. package/src/app/pages/api/ai/connections.ts +23 -0
  220. package/src/app/pages/api/auth/request-reset.ts +14 -16
  221. package/src/app/pages/api/docs/nav.json.ts +1 -1
  222. package/src/app/pages/api/install.ts +3 -3
  223. package/src/app/pages/api/mcp.ts +6 -0
  224. package/src/app/pages/api/registry/transfer/assets/blobs/[hash]/complete.ts +11 -0
  225. package/src/app/pages/api/registry/transfer/assets/blobs/[hash]/upload.ts +12 -0
  226. package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +1 -1
  227. package/src/app/pages/cli/device.tsx +10 -5
  228. package/src/app/pages/foundations/colors.tsx +9 -8
  229. package/src/app/pages/foundations/index.tsx +3 -3
  230. package/src/app/pages/index.tsx +2 -2
  231. package/src/app/pages/install.tsx +7 -2
  232. package/src/app/pages/login.tsx +32 -27
  233. package/src/app/pages/reset-password.tsx +21 -20
  234. package/src/app/pages/system/component/[component]/index.tsx +2 -5
  235. package/src/app/pages/system/index.tsx +11 -11
  236. package/src/app/pages/system/pattern/[pattern]/index.tsx +2 -2
  237. package/src/app/pages/system/tokens/components/[component]/index.tsx +0 -4
  238. package/src/app-builder/README.md +2 -1
  239. package/src/app-builder/build.ts +218 -73
  240. package/src/app-builder/client-config.ts +3 -2
  241. package/src/app-builder/paths.ts +3 -22
  242. package/src/app-builder/static-export.ts +1 -1
  243. package/src/app-builder/vercel-output.ts +5 -4
  244. package/src/cache/README.md +4 -1
  245. package/src/cache/build-cache.ts +128 -43
  246. package/src/cache/build-inputs.ts +28 -0
  247. package/src/cache/index.ts +4 -0
  248. package/src/catalog/README.md +3 -0
  249. package/src/catalog/normalize.ts +2 -0
  250. package/src/catalog/previews.ts +6 -3
  251. package/src/catalog/types.ts +8 -0
  252. package/src/cli/create.ts +1 -2
  253. package/src/commands/build/index.ts +1 -1
  254. package/src/config/README.md +10 -9
  255. package/src/config/defaults.ts +7 -4
  256. package/src/config/from-env.ts +33 -0
  257. package/src/config/helpers.ts +1 -3
  258. package/src/config/index.ts +0 -3
  259. package/src/config/loader.ts +27 -3
  260. package/src/config/resolve-env.ts +28 -15
  261. package/src/config/runtime.ts +10 -5
  262. package/src/handlebars.ts +8 -2
  263. package/src/index.ts +33 -29
  264. package/src/nav/index.ts +2 -2
  265. package/src/nav/registry.ts +3 -3
  266. package/src/nav/workspace.ts +3 -3
  267. package/src/pipeline/README.md +1 -1
  268. package/src/pipeline/figma.ts +98 -49
  269. package/src/pipeline/styles.ts +1 -1
  270. package/src/pipeline/validation.ts +3 -3
  271. package/src/providers.ts +18 -0
  272. package/src/registry/asset-storage/define.ts +6 -6
  273. package/src/registry/asset-storage/resolve.ts +38 -37
  274. package/src/registry/asset-storage/types.ts +39 -17
  275. package/src/registry/auth/ai-keys.ts +62 -0
  276. package/src/registry/auth/crypto.ts +63 -1
  277. package/src/registry/auth/index.ts +11 -1
  278. package/src/registry/checkout/index.ts +60 -138
  279. package/src/registry/client.ts +60 -20
  280. package/src/registry/db/driver.ts +2 -2
  281. package/src/registry/db/schema.ts +49 -22
  282. package/src/registry/email/define.ts +15 -0
  283. package/src/registry/email/providers/smtp.ts +39 -0
  284. package/src/registry/email/resolve.ts +94 -0
  285. package/src/registry/email/types.ts +28 -0
  286. package/src/registry/path.ts +11 -0
  287. package/src/registry/publish/package.ts +9 -0
  288. package/src/registry/transfer.ts +4 -0
  289. package/src/store/registry.ts +7 -7
  290. package/src/transformers/plugins/ssr-render.ts +53 -16
  291. package/src/transformers/preview/component/builder.ts +19 -25
  292. package/src/transformers/preview/component/css.ts +101 -53
  293. package/src/transformers/preview/component/html.ts +6 -2
  294. package/src/transformers/preview/component/javascript.ts +14 -4
  295. package/src/transformers/preview/pattern/html.ts +3 -1
  296. package/src/transformers/preview/types.ts +14 -0
  297. package/src/transformers/utils/build.ts +93 -0
  298. package/src/transformers/utils/module.ts +4 -2
  299. package/src/types/config.ts +148 -20
  300. package/src/utils/README.md +1 -1
  301. package/src/utils/path.ts +6 -29
  302. package/templates/default/handoff.config.js.tpl +10 -2
  303. package/templates/default/handoff.config.ts.tpl +10 -2
  304. package/templates/default/handoff.config.with-examples.js.tpl +10 -2
  305. package/templates/default/handoff.config.with-examples.ts.tpl +10 -2
  306. package/templates/default/package.json.tpl +2 -2
  307. package/.editorconfig +0 -19
  308. package/.eslintrc.json +0 -4
  309. package/.prettierignore +0 -0
  310. package/.prettierrc.json +0 -8
  311. package/.vscode/settings.json +0 -17
  312. package/dist/config/validator.d.ts +0 -9
  313. package/dist/config/validator.js +0 -24
  314. package/dist/registry/asset-storage/adapters/vercel-blob.d.ts +0 -17
  315. package/dist/registry/asset-storage/adapters/vercel-blob.js +0 -87
  316. package/src/app/components/old/Header.tsx +0 -89
  317. package/src/app/lib/mcp/shape.ts +0 -596
  318. package/src/app/pages/assets/fonts.tsx +0 -129
  319. package/src/app/pages/assets/index.tsx +0 -91
  320. package/src/app/pages/assets/logos.tsx +0 -75
  321. package/src/config/validator.ts +0 -22
  322. package/src/registry/asset-storage/adapters/vercel-blob.ts +0 -51
package/UPGRADE.md CHANGED
@@ -18,29 +18,54 @@ Each feature section identifies the affected projects and the required changes.
18
18
 
19
19
  | Change | Affected projects |
20
20
  | --- | --- |
21
- | [Figma token environment references](#figma-token-environment-references) | Projects that put a Figma token directly in config |
21
+ | [Node.js 22](#nodejs-22) | All projects |
22
+ | [Figma settings](#figma-settings) | Projects that set Figma values in config |
22
23
  | [Catalog items](#catalog-items) | Projects with component or pattern declarations |
24
+ | [Output directories](#output-directories) | Projects that deploy the static build, commit `exported/`, or use a `public-<projectId>` directory |
23
25
 
24
26
  <!-- Add future breaking changes as feature sections before "Verify the upgrade". Add each section to this table. -->
25
27
 
26
- ### Figma token environment references
28
+ ### Node.js 22
27
29
 
28
- `devAccessToken` and its legacy spelling `dev_access_token` now accept only an environment reference.
30
+ Handoff 2.x.x requires Node.js 22 or newer and npm 10 or newer. Version 1.x.x supported Node.js 16.
31
+ Update Node.js, CI images, and hosting runtimes before you install the new package.
32
+
33
+ Projects created by `handoff-app init` in version 1.x.x declare the old minimum in `package.json`.
34
+ Change it to:
35
+
36
+ ```json
37
+ "engines": {
38
+ "node": ">=22",
39
+ "npm": ">=10"
40
+ }
41
+ ```
42
+
43
+ ### Figma settings
44
+
45
+ The Figma file ID and access token moved to `integrations.figma`.
46
+ The top-level `figmaProjectId`, `figma_project_id`, `devAccessToken`, and `dev_access_token` were removed, and Handoff ignores them.
47
+ If you use `HANDOFF_FIGMA_PROJECT_ID` and `HANDOFF_DEV_ACCESS_TOKEN` and do not set Figma values in config, no change is required.
48
+
49
+ The access token accepts only an environment reference.
29
50
  A literal token throws `HandoffConfigError`, including in JavaScript and JSON configs.
30
- Move the token to the environment and replace the literal:
51
+ Replace the old keys. Move a literal token to the environment:
31
52
 
32
53
  ```ts
33
54
  import { defineConfig, fromEnv } from 'handoff-app';
34
55
 
35
56
  export default defineConfig({
36
- devAccessToken: fromEnv('HANDOFF_DEV_ACCESS_TOKEN'),
57
+ integrations: {
58
+ figma: {
59
+ projectId: 'your-figma-file-id',
60
+ accessToken: fromEnv('HANDOFF_DEV_ACCESS_TOKEN'),
61
+ },
62
+ },
37
63
  });
38
64
  ```
39
65
 
40
- For JSON, use `"devAccessToken": { "$env": "HANDOFF_DEV_ACCESS_TOKEN" }`.
41
- If you already use `HANDOFF_DEV_ACCESS_TOKEN` and omit the config property, no change is required.
42
- Environment references resolve after profile merging. Higher-layer literals still override default
43
- environment seeds for properties that allow literals, such as output directories.
66
+ For JSON, use `"accessToken": { "$env": "HANDOFF_DEV_ACCESS_TOKEN" }`.
67
+ Environment references resolve after profile merging. A profile can change one value, such as `integrations.figma.projectId`, and keep the other.
68
+ A literal in a higher layer, such as `projectId: 'your-figma-file-id'`, overrides the default environment variable.
44
69
 
45
70
  ### Catalog items
46
71
 
@@ -201,6 +226,29 @@ CSF uses `renderer: 'react'` with `format: 'csf'` inside `implementation`.
201
226
  Checkout writes only catalog declarations.
202
227
  Registry records require explicit renderer and source-format metadata where applicable.
203
228
 
229
+ ### Output directories
230
+
231
+ Version 1.x.x put the static site and the fetched tokens in a directory named after `<projectId>`.
232
+ `<projectId>` was the Figma file ID, or a name made from the project path when no Figma file was set.
233
+ Version 2.x.x uses fixed directory names:
234
+
235
+ | Content | 1.x.x | 2.x.x |
236
+ | --- | --- | --- |
237
+ | Static site from `handoff-app build` | `out/<projectId>` | `out/static` |
238
+ | Tokens and assets from `fetch` and `checkout` | `exported/<projectId>` | `exported` |
239
+ | Project-specific public files | `public-<projectId>` | Removed. Use `public` |
240
+
241
+ Do these steps:
242
+
243
+ 1. Update deploy scripts and CI steps that read `out/<projectId>`.
244
+ If you set `sitesOutputDirectory` or `HANDOFF_SITES_DIR`, the site is in `static` below that directory.
245
+ 2. Move the contents of `exported/<projectId>` up to `exported`, or run `npm run fetch` again.
246
+ Then remove `exported/<projectId>` and commit the result.
247
+ 3. Merge the files from `public-<projectId>` into `public`, then remove `public-<projectId>`.
248
+
249
+ A repository that builds more than one Figma file gets one `out/static` and one `exported` directory.
250
+ Set `HANDOFF_SITES_DIR` and `HANDOFF_OUTPUT_DIR`, or the matching config values in a profile, to a different directory for each build.
251
+
204
252
  ### Verify the upgrade
205
253
 
206
254
  After you apply the required migrations, verify the project:
package/components.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
- "$schema": "https://ui.shadcn.com/schema.json",
3
- "style": "new-york",
4
- "rsc": false,
5
- "tsx": true,
6
- "tailwind": {
7
- "config": "tailwind.config.ts",
8
- "css": "src/app/css/index.css",
9
- "baseColor": "zinc",
10
- "cssVariables": true,
11
- "prefix": ""
12
- },
13
- "aliases": {
14
- "components": "src/app/components",
15
- "utils": "src/app/lib/utils",
16
- "ui": "src/app/components/ui",
17
- "lib": "src/app/lib",
18
- "hooks": "src/app/hooks"
19
- },
20
- "iconLibrary": "lucide"
21
- }
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "tailwind.config.ts",
8
+ "css": "src/app/css/index.css",
9
+ "baseColor": "zinc",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "src/app/components",
15
+ "utils": "src/app/lib/utils",
16
+ "ui": "src/app/components/ui",
17
+ "lib": "src/app/lib",
18
+ "hooks": "src/app/hooks"
19
+ },
20
+ "iconLibrary": "lucide"
21
+ }
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Color Guidelines
3
3
  description: How to apply the color palette consistently and accessibly across products.
4
- metaTitle: 'Color Guidelines | Handoff Design System'
5
4
  metaDescription: 'How to apply the color palette consistently and accessibly across products.'
6
5
  ---
7
6
 
@@ -2,6 +2,5 @@
2
2
  title: Colors
3
3
  description: Color system built out of main brand colors and adjusted for variety of interfaces.
4
4
  image: hero-colors
5
- metaTitle: 'Colors | Handoff Design System'
6
5
  metaDescription: 'Color system built out of main brand colors and adjusted for variety of interfaces.'
7
6
  ---
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Effects Guidelines
3
3
  description: When and how to apply shadows, blurs, and elevation across the interface.
4
- metaTitle: 'Effects Guidelines | Handoff Design System'
5
4
  metaDescription: 'When and how to apply shadows, blurs, and elevation across the interface.'
6
5
  ---
7
6
 
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Effects Resources
3
3
  description: Reference values and assets for reproducing the brand's effects in any tool.
4
- metaTitle: 'Effects Resources | Handoff Design System'
5
4
  metaDescription: 'Reference values and assets for reproducing effects in any tool.'
6
5
  ---
7
6
 
@@ -2,7 +2,6 @@
2
2
  title: Effects
3
3
  description: Effects are Drop Shadows, Inner Shadows and Blur Effects.
4
4
  image: hero-effects
5
- metaTitle: 'Effects | Handoff Design System'
6
5
  metaDescription: 'Effects are Drop Shadows, Inner Shadows and Blur Effects.'
7
6
  ---
8
7
 
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Fonts
3
3
  description: Approved library of font families that are approved and licensed for use across the organization.
4
- metaTitle: Fonts | Handoff Design System
5
4
  metaDescription: Font families are packaged as assets that can be used across platforms.
6
5
  ---
7
6
 
@@ -2,7 +2,6 @@
2
2
  title: Grid
3
3
  description: Layout grid and spacing system that keeps compositions aligned and balanced.
4
4
  image: hero-design
5
- metaTitle: 'Grid | Handoff Design System'
6
5
  metaDescription: 'Layout grid and spacing system that keeps compositions aligned and balanced.'
7
6
  ---
8
7
 
@@ -1,6 +1,5 @@
1
1
  ---
2
2
  title: Icon Library
3
3
  description: Set of icons used to provide users with a way to process information faster and instinctively recognize actions signified by the icon.
4
- metaTitle: 'Icon Library | Handoff Design System'
5
4
  metaDescription: 'Set of icons used to provide users with a way to process information faster and instinctively recognize actions signified by the icon.'
6
5
  ---
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Icon Guidelines
3
3
  description: Sizing, spacing, and usage rules that keep the icon set consistent.
4
- metaTitle: 'Icon Guidelines | Handoff Design System'
5
4
  metaDescription: 'Sizing, spacing, and usage rules that keep the icon set consistent.'
6
5
  ---
7
6
 
@@ -1,6 +1,5 @@
1
1
  ---
2
2
  title: Icon Library
3
3
  description: Set of icons used to provide users with a way to process information faster and instinctively recognize actions signified by the icon.
4
- metaTitle: 'Icon Library | Handoff Design System'
5
4
  metaDescription: 'Set of icons used to provide users with a way to process information faster and instinctively recognize actions signified by the icon.'
6
5
  ---
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Image Guidelines
3
3
  description: How to select, crop, and treat imagery so it stays on brand.
4
- metaTitle: 'Image Guidelines | Handoff Design System'
5
4
  metaDescription: 'How to select, crop, and treat imagery so it stays on brand.'
6
5
  ---
7
6
 
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Image Resources
3
3
  description: Source files and downloads for approved photography and illustration.
4
- metaTitle: 'Image Resources | Handoff Design System'
5
4
  metaDescription: 'Source files and downloads for approved photography and illustration.'
6
5
  ---
7
6
 
@@ -2,7 +2,6 @@
2
2
  title: Images
3
3
  description: Photography and illustration style that shapes how the brand looks and feels.
4
4
  image: hero-design
5
- metaTitle: 'Images | Handoff Design System'
6
5
  metaDescription: 'Photography and illustration style that shapes how the brand looks and feels.'
7
6
  ---
8
7
 
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Logo Resources
3
3
  description: Downloadable logo files and everything teams need to represent the brand correctly.
4
- metaTitle: 'Logo Resources | Handoff Design System'
5
4
  metaDescription: 'Downloadable logo files and everything teams need to represent the brand correctly.'
6
5
  ---
7
6
 
@@ -2,6 +2,5 @@
2
2
  title: Logos
3
3
  description: Show the logos used for promoting public identification and recognition.
4
4
  image: react
5
- metaTitle: 'Logos | Handoff Design System'
6
5
  metaDescription: 'Show the logos used for promoting public identification and recognition.'
7
6
  ---
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Typography Guidelines
3
3
  description: Best practices for type scale, hierarchy, and readability across the system.
4
- metaTitle: 'Typography Guidelines | Handoff Design System'
5
4
  metaDescription: 'Best practices for type scale, hierarchy, and readability across the system.'
6
5
  ---
7
6
 
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Typography Resources
3
3
  description: Font files, licenses, and assets needed to work with the brand typography.
4
- metaTitle: 'Typography Resources | Handoff Design System'
5
4
  metaDescription: 'Font files, licenses, and assets needed to work with the brand typography.'
6
5
  ---
7
6
 
@@ -2,7 +2,6 @@
2
2
  title: Typography
3
3
  description: Typographic system establishes scale, sizes and weight of text.
4
4
  image: hero-design
5
- metaTitle: 'Typography | Handoff Design System'
6
5
  metaDescription: 'Typographic system establishes scale, sizes and weight of text.'
7
6
  ---
8
7
 
@@ -4,7 +4,6 @@ description: Set of design principles and visual guidelines that define the bran
4
4
  weight: 0
5
5
  image: hero-design
6
6
  menuTitle: 'Foundations'
7
- metaTitle: 'Design Foundations | Handoff Design System'
8
7
  metaDescription: 'Set of design principles and visual guidelines that define the brand across every experience'
9
8
  enabled: true
10
9
  menu:
@@ -4,7 +4,6 @@ description: How to build out a robust project built on the designs, tokens, and
4
4
  weight: 10
5
5
  image: hero-components
6
6
  menuTitle: 'Guidelines'
7
- metaTitle: 'Guidelines | Handoff Design System'
8
7
  metaDescription: 'How to build out a robust project built on the designs, tokens, and components documented here.'
9
8
  enabled: true
10
9
  menu:
@@ -3,7 +3,6 @@ title: 'Handoff Design System for building better user experiences.'
3
3
  description: This is a sample page where you could insert a style guide.
4
4
  weight: -5
5
5
  menuTitle: 'Handoff'
6
- metaTitle: 'Style Guide | Handoff Design System'
7
6
  metaDescription: 'A sample page in the handoff design system, in markdown'
8
7
  enabled: true
9
8
  ---
@@ -7,10 +7,6 @@ description: |
7
7
  weight: 5
8
8
  image: hero-components
9
9
  menuTitle: 'Colors'
10
- metaTitle: 'Colors | Handoff Design System'
11
- metaDescription: |
12
- Element that represents a control that provides a menu of options, collection
13
- of UI components used.'
14
10
  enabled: true
15
11
  menu:
16
12
  - title: Design System
@@ -4,10 +4,6 @@ description: Effects are the shadows and insets pulled automatically from Figma
4
4
  weight: 5
5
5
  image: hero-components
6
6
  menuTitle: 'Effects'
7
- metaTitle: 'Effects | Handoff Design System'
8
- metaDescription: |
9
- Element that represents a control that provides a menu of options, collection
10
- of UI components used.
11
7
  enabled: true
12
8
  menu:
13
9
  - title: Design System
@@ -9,8 +9,6 @@ description: |
9
9
  weight: 5
10
10
  image: hero-components
11
11
  menuTitle: 'Typography'
12
- metaTitle: 'Typography | Handoff Design System'
13
- metaDescription: 'Element that represents a control that provides a menu of options, collection of UI components used.'
14
12
  enabled: true
15
13
  menu:
16
14
  - title: Design System
@@ -4,8 +4,6 @@ description: Library of production-ready UI components built to deliver consiste
4
4
  weight: 5
5
5
  image: hero-components
6
6
  menuTitle: 'Design System'
7
- metaTitle: 'Design System | Handoff Design System'
8
- metaDescription: 'Element that represents a control that provides a menu of options, collection of UI components used.'
9
7
  enabled: true
10
8
  menu:
11
9
  - title: Design System
@@ -3,7 +3,8 @@ title: 'The visible title of the page.'
3
3
  description: A description of the page.
4
4
  weight: 0
5
5
  menuTitle: 'Menu Title'
6
- metaTitle: 'Meta Title'
6
+ # metaTitle replaces the whole browser title. Without it, the title is "<title> | <app.title>".
7
+ # metaTitle: 'Meta Title'
7
8
  metaDescription: 'Insert a meta description'
8
9
  enabled: true
9
10
  ---
@@ -3,7 +3,8 @@ title: 'The visible title of the page.'
3
3
  description: A description of the page.
4
4
  weight: 0
5
5
  menuTitle: 'Menu Title'
6
- metaTitle: 'Meta Title'
6
+ # metaTitle replaces the whole browser title. Without it, the title is "<title> | <app.title>".
7
+ # metaTitle: 'Meta Title'
7
8
  metaDescription: 'Insert a meta description'
8
9
  enabled: true
9
10
  ---
@@ -0,0 +1,66 @@
1
+ /**
2
+ * AI connection resolution.
3
+ *
4
+ * `runtime.ai.connections` declares the whole surface a reader can reach. Mirrors
5
+ * {@link import('../registry/asset-storage/resolve')}: only provider selection, module location,
6
+ * non-secret options, and env-var *names* are ever persisted; secret *values* are read from
7
+ * `process.env` at request time.
8
+ *
9
+ * The list is deployment data rather than build shape, so `HANDOFF_AI_CONNECTIONS` can extend or
10
+ * replace the baked list at request time. A registry is built once and redeployed many times, and a
11
+ * new gateway should not need a rebuild.
12
+ */
13
+ import type { AiCredentialKind, ResolvedConfig } from '../types/config';
14
+ /** A connection as it is baked and read back: env-var names, never secret values. */
15
+ export interface AiConnectionSettings {
16
+ id: string;
17
+ label: string;
18
+ baseUrl?: string;
19
+ module?: string;
20
+ /** Name of the env var holding the deployment's own key. Its presence marks a service connection. */
21
+ apiKeyEnv?: string;
22
+ credential?: 'user';
23
+ models?: string[];
24
+ options?: Record<string, unknown>;
25
+ }
26
+ /** The resolved AI block: whether this build serves the assistant, and what it can reach. */
27
+ export interface AiSettings {
28
+ enabled: boolean;
29
+ connections: AiConnectionSettings[];
30
+ defaultModel?: string;
31
+ }
32
+ /**
33
+ * Which of the three credential states a connection declares. Derived from the declaration, never
34
+ * from a missing key: without the explicit `user` state, a connection that needs a reader's key
35
+ * would be indistinguishable from one that needs none.
36
+ */
37
+ export declare const aiCredentialKind: (connection: AiConnectionSettings) => AiCredentialKind;
38
+ /** Split `<connectionId>/<model>`. Only the first slash separates them, since model ids carry slashes. */
39
+ export declare const parseAiModelId: (value: string) => {
40
+ connectionId: string;
41
+ model: string;
42
+ } | null;
43
+ /** Join a connection id and a model into the address the client sends back. */
44
+ export declare const formatAiModelId: (connectionId: string, model: string) => string;
45
+ /**
46
+ * Merge a deployment-supplied list over the baked one by `id`: a matching id replaces the baked
47
+ * connection outright, and a new id is appended. Replacement rather than a field-wise merge, so a
48
+ * deployment that repoints a gateway cannot leave a stale model list or key name behind.
49
+ *
50
+ * A deployment-supplied connection can use only a `module` that the build includes.
51
+ */
52
+ export declare const mergeAiConnections: (baked: readonly AiConnectionSettings[], overrides: readonly AiConnectionSettings[]) => AiConnectionSettings[];
53
+ /** Parse the `HANDOFF_AI_CONNECTIONS` JSON array. A malformed value is ignored rather than fatal. */
54
+ export declare const parseAiConnections: (raw: string | undefined) => AiConnectionSettings[];
55
+ /**
56
+ * Whether this build serves the assistant. The `ai` block is the opt-in; `enabled: false` turns it
57
+ * back off. Config-only and baked, like `runtime.mcp`.
58
+ */
59
+ export declare const isAiEnabled: (config: Pick<ResolvedConfig, "runtime"> | null | undefined) => boolean;
60
+ /**
61
+ * Resolve the AI settings from a loaded config (CLI/build side).
62
+ *
63
+ * An authored connection that cannot be used fails the build rather than disappearing. A deployment
64
+ * list stays lenient by contrast: a bad `HANDOFF_AI_CONNECTIONS` entry must not take the server down.
65
+ */
66
+ export declare const resolveAiFromConfig: (config: ResolvedConfig | null | undefined) => AiSettings;
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ /**
3
+ * AI connection resolution.
4
+ *
5
+ * `runtime.ai.connections` declares the whole surface a reader can reach. Mirrors
6
+ * {@link import('../registry/asset-storage/resolve')}: only provider selection, module location,
7
+ * non-secret options, and env-var *names* are ever persisted; secret *values* are read from
8
+ * `process.env` at request time.
9
+ *
10
+ * The list is deployment data rather than build shape, so `HANDOFF_AI_CONNECTIONS` can extend or
11
+ * replace the baked list at request time. A registry is built once and redeployed many times, and a
12
+ * new gateway should not need a rebuild.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.resolveAiFromConfig = exports.isAiEnabled = exports.parseAiConnections = exports.mergeAiConnections = exports.formatAiModelId = exports.parseAiModelId = exports.aiCredentialKind = void 0;
16
+ const errors_1 = require("../config/errors");
17
+ /** A connection id addresses a model as `<id>/<model>`, so it cannot itself contain a slash. */
18
+ const isUsableId = (id) => typeof id === 'string' && id.trim().length > 0 && !id.includes('/');
19
+ /**
20
+ * Which of the three credential states a connection declares. Derived from the declaration, never
21
+ * from a missing key: without the explicit `user` state, a connection that needs a reader's key
22
+ * would be indistinguishable from one that needs none.
23
+ */
24
+ const aiCredentialKind = (connection) => {
25
+ if (connection.credential === 'user')
26
+ return 'user';
27
+ return connection.apiKeyEnv ? 'service' : 'none';
28
+ };
29
+ exports.aiCredentialKind = aiCredentialKind;
30
+ /** Split `<connectionId>/<model>`. Only the first slash separates them, since model ids carry slashes. */
31
+ const parseAiModelId = (value) => {
32
+ const separator = value.indexOf('/');
33
+ if (separator <= 0 || separator === value.length - 1)
34
+ return null;
35
+ return { connectionId: value.slice(0, separator), model: value.slice(separator + 1) };
36
+ };
37
+ exports.parseAiModelId = parseAiModelId;
38
+ /** Join a connection id and a model into the address the client sends back. */
39
+ const formatAiModelId = (connectionId, model) => `${connectionId}/${model}`;
40
+ exports.formatAiModelId = formatAiModelId;
41
+ /** Normalize one authored or deployment-supplied connection, dropping anything unusable. */
42
+ const toConnectionSettings = (input) => {
43
+ if (!input || typeof input !== 'object' || Array.isArray(input))
44
+ return null;
45
+ const raw = input;
46
+ if (!isUsableId(raw.id))
47
+ return null;
48
+ const baseUrl = typeof raw.baseUrl === 'string' ? raw.baseUrl.trim() : undefined;
49
+ const module = typeof raw.module === 'string' ? raw.module.trim() : undefined;
50
+ if (!baseUrl && !module)
51
+ return null;
52
+ // An authored config carries `apiKey` as a deferred `{ $env }` reference; a baked or
53
+ // deployment-supplied list carries the name it resolved to.
54
+ const reference = raw.apiKey;
55
+ const apiKeyEnv = typeof raw.apiKeyEnv === 'string' && raw.apiKeyEnv.trim()
56
+ ? raw.apiKeyEnv.trim()
57
+ : typeof (reference === null || reference === void 0 ? void 0 : reference.$env) === 'string'
58
+ ? reference.$env
59
+ : undefined;
60
+ // A repeated model would be two picker entries for one choice, so the first occurrence wins.
61
+ const models = Array.isArray(raw.models)
62
+ ? [...new Set(raw.models.filter((model) => typeof model === 'string' && !!model.trim()).map((model) => model.trim()))]
63
+ : [];
64
+ const options = raw.options && typeof raw.options === 'object' && !Array.isArray(raw.options) ? raw.options : undefined;
65
+ return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ id: raw.id.trim(), label: typeof raw.label === 'string' && raw.label.trim() ? raw.label.trim() : raw.id.trim() }, (baseUrl ? { baseUrl } : {})), (module ? { module } : {})), (apiKeyEnv ? { apiKeyEnv } : {})), (raw.credential === 'user' ? { credential: 'user' } : {})), (models.length ? { models } : {})), (options ? { options } : {}));
66
+ };
67
+ /** Normalize a declared list, keeping the first entry for any repeated id. */
68
+ const toConnectionList = (input) => {
69
+ const byId = new Map();
70
+ for (const entry of input !== null && input !== void 0 ? input : []) {
71
+ const connection = toConnectionSettings(entry);
72
+ if (connection && !byId.has(connection.id))
73
+ byId.set(connection.id, connection);
74
+ }
75
+ return [...byId.values()];
76
+ };
77
+ const ignoredOverrides = new Set();
78
+ /**
79
+ * Merge a deployment-supplied list over the baked one by `id`: a matching id replaces the baked
80
+ * connection outright, and a new id is appended. Replacement rather than a field-wise merge, so a
81
+ * deployment that repoints a gateway cannot leave a stale model list or key name behind.
82
+ *
83
+ * A deployment-supplied connection can use only a `module` that the build includes.
84
+ */
85
+ const mergeAiConnections = (baked, overrides) => {
86
+ const byId = new Map(baked.map((connection) => [connection.id, connection]));
87
+ const bakedModules = new Set(baked.map((connection) => connection.module).filter(Boolean));
88
+ for (const connection of overrides) {
89
+ if (connection.module && !bakedModules.has(connection.module)) {
90
+ if (!ignoredOverrides.has(connection.id)) {
91
+ ignoredOverrides.add(connection.id);
92
+ console.warn(`HANDOFF_AI_CONNECTIONS: connection "${connection.id}" is ignored, because the build does not include its module ` +
93
+ `"${connection.module}". Declare the connection in runtime.ai.connections.`);
94
+ }
95
+ continue;
96
+ }
97
+ byId.set(connection.id, connection);
98
+ }
99
+ return [...byId.values()];
100
+ };
101
+ exports.mergeAiConnections = mergeAiConnections;
102
+ /** Parse the `HANDOFF_AI_CONNECTIONS` JSON array. A malformed value is ignored rather than fatal. */
103
+ const parseAiConnections = (raw) => {
104
+ if (!(raw === null || raw === void 0 ? void 0 : raw.trim()))
105
+ return [];
106
+ try {
107
+ const parsed = JSON.parse(raw);
108
+ return Array.isArray(parsed) ? toConnectionList(parsed) : [];
109
+ }
110
+ catch (_a) {
111
+ return [];
112
+ }
113
+ };
114
+ exports.parseAiConnections = parseAiConnections;
115
+ /**
116
+ * Whether this build serves the assistant. The `ai` block is the opt-in; `enabled: false` turns it
117
+ * back off. Config-only and baked, like `runtime.mcp`.
118
+ */
119
+ const isAiEnabled = (config) => { var _a, _b, _c; return Boolean((_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.ai) && ((_c = (_b = config === null || config === void 0 ? void 0 : config.runtime) === null || _b === void 0 ? void 0 : _b.ai) === null || _c === void 0 ? void 0 : _c.enabled) !== false; };
120
+ exports.isAiEnabled = isAiEnabled;
121
+ /**
122
+ * Resolve the AI settings from a loaded config (CLI/build side).
123
+ *
124
+ * An authored connection that cannot be used fails the build rather than disappearing. A deployment
125
+ * list stays lenient by contrast: a bad `HANDOFF_AI_CONNECTIONS` entry must not take the server down.
126
+ */
127
+ const resolveAiFromConfig = (config) => {
128
+ var _a, _b, _c, _d, _e, _f;
129
+ const authored = ((_c = (_b = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.ai) === null || _b === void 0 ? void 0 : _b.connections) !== null && _c !== void 0 ? _c : []);
130
+ const fail = (problem, ids) => {
131
+ throw new errors_1.HandoffConfigError(`Config "runtime.ai.connections": ${problem} (${ids.map((id) => JSON.stringify(id !== null && id !== void 0 ? id : null)).join(', ')}).`);
132
+ };
133
+ const normalized = authored.map((connection) => ({ authored: connection, settings: toConnectionSettings(connection) }));
134
+ const unusable = normalized.filter((entry) => !entry.settings);
135
+ if (unusable.length > 0) {
136
+ fail('every connection needs an "id" without a slash, and either a "baseUrl" or a "module"', unusable.map((entry) => { var _a; return (_a = entry.authored) === null || _a === void 0 ? void 0 : _a.id; }));
137
+ }
138
+ const ids = normalized.map((entry) => entry.settings.id);
139
+ const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
140
+ if (duplicates.length > 0) {
141
+ fail('a connection id must be unique, because it is half of every model address', duplicates);
142
+ }
143
+ return {
144
+ enabled: (0, exports.isAiEnabled)(config),
145
+ connections: normalized.map((entry) => entry.settings),
146
+ defaultModel: ((_f = (_e = (_d = config === null || config === void 0 ? void 0 : config.runtime) === null || _d === void 0 ? void 0 : _d.ai) === null || _e === void 0 ? void 0 : _e.defaultModel) === null || _f === void 0 ? void 0 : _f.trim()) || undefined,
147
+ };
148
+ };
149
+ exports.resolveAiFromConfig = resolveAiFromConfig;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Typed identity helper for custom AI providers (mirrors `defineStorageProvider`): a consumer
3
+ * default-exports its result from a **server-only** module and points a connection's `module` at
4
+ * it. It must be its own module (not an inline `defineConfig` function) so the build can trace it
5
+ * into the deployed registry. The default export may be the provider object, or a factory
6
+ * `(context) => AiProvider` when it needs its options, env or the resolved key.
7
+ */
8
+ import type { AiProvider, AiProviderFactory } from './types';
9
+ export declare function defineAiProvider(provider: AiProvider): AiProvider;
10
+ export declare function defineAiProvider(factory: AiProviderFactory): AiProviderFactory;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**
3
+ * Typed identity helper for custom AI providers (mirrors `defineStorageProvider`): a consumer
4
+ * default-exports its result from a **server-only** module and points a connection's `module` at
5
+ * it. It must be its own module (not an inline `defineConfig` function) so the build can trace it
6
+ * into the deployed registry. The default export may be the provider object, or a factory
7
+ * `(context) => AiProvider` when it needs its options, env or the resolved key.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.defineAiProvider = defineAiProvider;
11
+ function defineAiProvider(input) {
12
+ return input;
13
+ }