handoff-app 2.0.0-0 → 2.0.0-10

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 (555) hide show
  1. package/AGENTS.md +7 -0
  2. package/CLAUDE.md +7 -0
  3. package/README.md +732 -304
  4. package/UPGRADE.md +218 -0
  5. package/config/config.template.js +1 -4
  6. package/config/config.template.ts +1 -2
  7. package/config/docs/foundations/colors/guidelines.md +9 -0
  8. package/config/docs/foundations/effects/guidelines.md +9 -0
  9. package/config/docs/foundations/effects/resources.md +9 -0
  10. package/config/docs/foundations/grid.md +10 -0
  11. package/config/docs/foundations/icons/guidelines.md +9 -0
  12. package/config/docs/foundations/images/guidelines.md +9 -0
  13. package/config/docs/foundations/images/resources.md +9 -0
  14. package/config/docs/foundations/images.md +10 -0
  15. package/config/docs/foundations/logo/resources.md +9 -0
  16. package/config/docs/foundations/typography/guidelines.md +9 -0
  17. package/config/docs/foundations/typography/resources.md +9 -0
  18. package/config/docs/foundations.md +5 -3
  19. package/dist/ai/connections.d.ts +64 -0
  20. package/dist/ai/connections.js +136 -0
  21. package/dist/ai/define.d.ts +10 -0
  22. package/dist/ai/define.js +13 -0
  23. package/dist/ai/types.d.ts +27 -0
  24. package/dist/ai/types.js +10 -0
  25. package/dist/app-builder/build.d.ts +12 -0
  26. package/dist/app-builder/build.js +227 -69
  27. package/dist/app-builder/client-config.js +16 -12
  28. package/dist/app-builder/config-diff/strategies/pattern.js +3 -3
  29. package/dist/app-builder/nav-shell.js +8 -15
  30. package/dist/app-builder/paths.js +23 -1
  31. package/dist/app-builder/static-export.js +25 -0
  32. package/dist/app-builder/vercel-output.js +6 -6
  33. package/dist/app-builder/watchers/component.js +5 -5
  34. package/dist/app-builder/watchers/utils.d.ts +2 -3
  35. package/dist/app-builder/watchers.d.ts +8 -15
  36. package/dist/app-builder/watchers.js +70 -61
  37. package/dist/artifacts/index.d.ts +1 -1
  38. package/dist/artifacts/index.js +4 -1
  39. package/dist/artifacts/url.d.ts +18 -0
  40. package/dist/artifacts/url.js +31 -1
  41. package/dist/cache/build-cache.js +23 -23
  42. package/dist/catalog/define.d.ts +6 -0
  43. package/dist/catalog/define.js +72 -0
  44. package/dist/catalog/implementation.d.ts +27 -0
  45. package/dist/catalog/implementation.js +133 -0
  46. package/dist/catalog/index.d.ts +6 -0
  47. package/dist/catalog/index.js +22 -0
  48. package/dist/catalog/normalize.d.ts +16 -0
  49. package/dist/catalog/normalize.js +118 -0
  50. package/dist/catalog/previews.d.ts +18 -0
  51. package/dist/catalog/previews.js +107 -0
  52. package/dist/catalog/renderers.d.ts +43 -0
  53. package/dist/catalog/renderers.js +62 -0
  54. package/dist/catalog/types.d.ts +71 -0
  55. package/dist/cli/auth/browser.d.ts +2 -0
  56. package/dist/cli/auth/browser.js +33 -0
  57. package/dist/cli/auth/device.d.ts +16 -0
  58. package/dist/cli/auth/device.js +158 -0
  59. package/dist/cli/auth/store.d.ts +38 -0
  60. package/dist/cli/auth/store.js +199 -0
  61. package/dist/cli/create.js +48 -3
  62. package/dist/cli/make.d.ts +0 -5
  63. package/dist/cli/make.js +24 -69
  64. package/dist/cli/scaffold.js +39 -181
  65. package/dist/cli.js +39 -7
  66. package/dist/commands/build/app.js +1 -5
  67. package/dist/commands/build/components.js +1 -5
  68. package/dist/commands/build/index.js +1 -5
  69. package/dist/commands/checkout/index.d.ts +18 -12
  70. package/dist/commands/checkout/index.js +19 -59
  71. package/dist/commands/compat/deprecations.d.ts +46 -0
  72. package/dist/commands/compat/deprecations.js +62 -0
  73. package/dist/commands/compat/push-args.d.ts +48 -0
  74. package/dist/commands/compat/push-args.js +73 -0
  75. package/dist/commands/db/migrate.js +1 -5
  76. package/dist/commands/dev/index.js +1 -5
  77. package/dist/commands/eject/config.js +1 -5
  78. package/dist/commands/eject/pages.js +1 -5
  79. package/dist/commands/eject/theme.js +1 -5
  80. package/dist/commands/fetch/index.js +1 -5
  81. package/dist/commands/index.js +8 -2
  82. package/dist/commands/login/index.d.ts +13 -0
  83. package/dist/commands/login/index.js +61 -0
  84. package/dist/commands/logout/index.d.ts +12 -0
  85. package/dist/commands/logout/index.js +89 -0
  86. package/dist/commands/make/component.js +1 -5
  87. package/dist/commands/make/page.js +3 -7
  88. package/dist/commands/publish/index.d.ts +21 -11
  89. package/dist/commands/publish/index.js +22 -58
  90. package/dist/commands/pull/index.d.ts +13 -0
  91. package/dist/commands/pull/index.js +20 -0
  92. package/dist/commands/push/index.d.ts +23 -0
  93. package/dist/commands/push/index.js +58 -0
  94. package/dist/commands/scaffold/index.js +1 -5
  95. package/dist/commands/start/index.js +1 -5
  96. package/dist/commands/types.d.ts +12 -0
  97. package/dist/commands/utils.d.ts +100 -1
  98. package/dist/commands/utils.js +103 -2
  99. package/dist/commands/validate/components.js +1 -5
  100. package/dist/config/catalog-include.d.ts +43 -0
  101. package/dist/config/catalog-include.js +203 -0
  102. package/dist/config/defaults.d.ts +4 -2
  103. package/dist/config/defaults.js +58 -49
  104. package/dist/config/env.d.ts +9 -0
  105. package/dist/config/env.js +43 -0
  106. package/dist/config/errors.d.ts +4 -0
  107. package/dist/config/errors.js +11 -0
  108. package/dist/config/from-env.d.ts +24 -0
  109. package/dist/config/from-env.js +7 -0
  110. package/dist/config/helpers.d.ts +2 -0
  111. package/dist/config/helpers.js +3 -1
  112. package/dist/config/index.d.ts +6 -2
  113. package/dist/config/index.js +12 -1
  114. package/dist/config/loader.d.ts +40 -9
  115. package/dist/config/loader.js +148 -35
  116. package/dist/config/normalizers/page.d.ts +4 -4
  117. package/dist/config/normalizers/page.js +2 -2
  118. package/dist/config/resolve-env.d.ts +6 -0
  119. package/dist/config/resolve-env.js +115 -0
  120. package/dist/config/runtime.d.ts +15 -16
  121. package/dist/config/runtime.js +178 -196
  122. package/dist/config/validator.d.ts +2 -2
  123. package/dist/config/validator.js +2 -4
  124. package/dist/handlebars.d.ts +17 -0
  125. package/dist/handlebars.js +16 -0
  126. package/dist/index.d.ts +120 -27
  127. package/dist/index.js +242 -53
  128. package/dist/nav/resolver.js +3 -1
  129. package/dist/nav/workspace.js +2 -2
  130. package/dist/pattern.d.ts +7 -0
  131. package/dist/pattern.js +13 -0
  132. package/dist/pipeline/index.d.ts +1 -1
  133. package/dist/pipeline/index.js +1 -1
  134. package/dist/react.d.ts +43 -0
  135. package/dist/react.js +11 -0
  136. package/dist/registry/asset-storage/adapters/vercel-blob.js +1 -1
  137. package/dist/registry/asset-storage/define.d.ts +1 -1
  138. package/dist/registry/asset-storage/define.js +1 -1
  139. package/dist/registry/asset-storage/resolve.d.ts +3 -3
  140. package/dist/registry/asset-storage/resolve.js +5 -2
  141. package/dist/registry/auth/access-tokens.d.ts +54 -0
  142. package/dist/registry/auth/access-tokens.js +191 -0
  143. package/dist/registry/auth/action-tokens.d.ts +66 -0
  144. package/dist/registry/auth/action-tokens.js +178 -0
  145. package/dist/registry/auth/ai-keys.d.ts +32 -0
  146. package/dist/registry/auth/ai-keys.js +69 -0
  147. package/dist/registry/auth/crypto.d.ts +21 -0
  148. package/dist/registry/auth/crypto.js +76 -0
  149. package/dist/registry/auth/database.d.ts +7 -0
  150. package/dist/registry/auth/database.js +22 -0
  151. package/dist/registry/auth/device-authorizations.d.ts +51 -0
  152. package/dist/registry/auth/device-authorizations.js +170 -0
  153. package/dist/registry/auth/gravatar.d.ts +1 -0
  154. package/dist/registry/auth/gravatar.js +8 -0
  155. package/dist/registry/auth/index.d.ts +13 -0
  156. package/dist/registry/auth/index.js +89 -0
  157. package/dist/registry/auth/installation.d.ts +42 -0
  158. package/dist/registry/auth/installation.js +105 -0
  159. package/dist/registry/auth/password.d.ts +12 -0
  160. package/dist/registry/auth/password.js +58 -0
  161. package/dist/registry/auth/rate-limits.d.ts +22 -0
  162. package/dist/registry/auth/rate-limits.js +75 -0
  163. package/dist/registry/auth/sync-secret.d.ts +27 -0
  164. package/dist/registry/auth/sync-secret.js +65 -0
  165. package/dist/registry/auth/types.d.ts +45 -0
  166. package/dist/registry/auth/types.js +11 -0
  167. package/dist/registry/auth/user-record.d.ts +13 -0
  168. package/dist/registry/auth/user-record.js +16 -0
  169. package/dist/registry/auth/users.d.ts +31 -0
  170. package/dist/registry/auth/users.js +135 -0
  171. package/dist/registry/auth/validation.d.ts +14 -0
  172. package/dist/registry/auth/validation.js +45 -0
  173. package/dist/registry/checkout/assets.d.ts +1 -1
  174. package/dist/registry/checkout/assets.js +25 -8
  175. package/dist/registry/checkout/index.d.ts +27 -6
  176. package/dist/registry/checkout/index.js +479 -131
  177. package/dist/registry/checkout/tokens.d.ts +1 -1
  178. package/dist/registry/checkout/tokens.js +16 -7
  179. package/dist/registry/client.d.ts +2 -1
  180. package/dist/registry/client.js +8 -0
  181. package/dist/registry/connection.d.ts +34 -11
  182. package/dist/registry/connection.js +77 -18
  183. package/dist/registry/content-kinds.d.ts +27 -0
  184. package/dist/registry/content-kinds.js +33 -0
  185. package/dist/registry/db/client.d.ts +14 -9
  186. package/dist/registry/db/client.js +22 -9
  187. package/dist/registry/db/driver.d.ts +39 -0
  188. package/dist/registry/db/driver.js +50 -0
  189. package/dist/registry/db/index.d.ts +2 -2
  190. package/dist/registry/db/index.js +14 -9
  191. package/dist/registry/db/migrate.d.ts +1 -1
  192. package/dist/registry/db/migrate.js +5 -5
  193. package/dist/registry/db/schema.d.ts +2992 -963
  194. package/dist/registry/db/schema.js +158 -8
  195. package/dist/registry/publish/assets.d.ts +2 -2
  196. package/dist/registry/publish/assets.js +46 -35
  197. package/dist/registry/publish/errors.js +3 -3
  198. package/dist/registry/publish/index.d.ts +45 -3
  199. package/dist/registry/publish/index.js +247 -24
  200. package/dist/registry/publish/package.js +14 -1
  201. package/dist/registry/publish/tokens.d.ts +2 -2
  202. package/dist/registry/publish/tokens.js +30 -24
  203. package/dist/registry/selection.d.ts +32 -0
  204. package/dist/registry/selection.js +58 -0
  205. package/dist/registry/transfer.d.ts +13 -0
  206. package/dist/store/filesystem.d.ts +3 -3
  207. package/dist/store/filesystem.js +7 -7
  208. package/dist/store/registry.d.ts +48 -0
  209. package/dist/store/registry.js +99 -15
  210. package/dist/transformers/plugins/csf-render.js +4 -2
  211. package/dist/transformers/plugins/ssr-render.js +52 -18
  212. package/dist/transformers/preview/component/api.d.ts +8 -0
  213. package/dist/transformers/preview/component/api.js +11 -15
  214. package/dist/transformers/preview/component/artifacts.d.ts +1 -1
  215. package/dist/transformers/preview/component/artifacts.js +11 -7
  216. package/dist/transformers/preview/component/builder.js +15 -18
  217. package/dist/transformers/preview/component/css.d.ts +3 -0
  218. package/dist/transformers/preview/component/css.js +93 -58
  219. package/dist/transformers/preview/component/html.js +18 -16
  220. package/dist/transformers/preview/component/javascript.js +2 -4
  221. package/dist/transformers/preview/pattern/builder.js +31 -18
  222. package/dist/transformers/preview/pattern/html.js +3 -1
  223. package/dist/transformers/preview/types.d.ts +30 -3
  224. package/dist/transformers/utils/build.d.ts +19 -0
  225. package/dist/transformers/utils/build.js +83 -1
  226. package/dist/transformers/utils/module.js +2 -1
  227. package/dist/types/config.d.ts +156 -45
  228. package/dist/utils/markdown.d.ts +10 -0
  229. package/dist/utils/markdown.js +17 -0
  230. package/dist/utils/menu-shell.js +14 -7
  231. package/dist/utils/pages.d.ts +22 -0
  232. package/dist/utils/pages.js +73 -0
  233. package/dist/utils/path.d.ts +5 -0
  234. package/dist/utils/path.js +9 -0
  235. package/docs/api.md +35 -3
  236. package/docs/cli.md +6 -2
  237. package/drizzle/0002_add_pages.sql +5 -3
  238. package/drizzle/0005_add_registry_auth.sql +95 -0
  239. package/drizzle/0006_add_component_source_format.sql +3 -0
  240. package/drizzle/0007_add_ai_keys.sql +11 -0
  241. package/drizzle/meta/0002_snapshot.json +17 -8
  242. package/drizzle/meta/0003_snapshot.json +17 -8
  243. package/drizzle/meta/0004_snapshot.json +17 -8
  244. package/drizzle/meta/0005_snapshot.json +1935 -0
  245. package/drizzle/meta/0006_snapshot.json +1941 -0
  246. package/drizzle/meta/0007_snapshot.json +2013 -0
  247. package/drizzle/meta/_journal.json +21 -0
  248. package/drizzle.config.ts +1 -1
  249. package/package.json +44 -5
  250. package/src/ai/README.md +42 -0
  251. package/src/ai/connections.ts +172 -0
  252. package/src/ai/define.ts +15 -0
  253. package/src/ai/types.ts +31 -0
  254. package/src/app/components/AiAssistant/AiAssistantPanel.tsx +144 -0
  255. package/src/app/components/AiAssistant/AiAssistantProvider.tsx +215 -0
  256. package/src/app/components/AiAssistant/AiConversation.tsx +674 -0
  257. package/src/app/components/AiAssistant/AiToolResult.tsx +99 -0
  258. package/src/app/components/AiAssistant/dockState.ts +86 -0
  259. package/src/app/components/AiAssistant/toolLabel.ts +22 -0
  260. package/src/app/components/AiAssistant/useAiChat.ts +147 -0
  261. package/src/app/components/AiAssistant/useAiConnections.ts +86 -0
  262. package/src/app/components/AiAssistant/usePageContext.ts +59 -0
  263. package/src/app/components/Auth/AccountLayout.tsx +124 -0
  264. package/src/app/components/Auth/AuthControls.tsx +99 -0
  265. package/src/app/components/Auth/AuthShell.tsx +73 -0
  266. package/src/app/components/Auth/RegistryInstallGate.tsx +23 -0
  267. package/src/app/components/Auth/RegistrySessionProvider.tsx +15 -0
  268. package/src/app/components/Auth/api.ts +20 -0
  269. package/src/app/components/Component/PageSliceResolver.tsx +1 -0
  270. package/src/app/components/Component/Preview.tsx +406 -226
  271. package/src/app/components/Component/slices/ComponentDisplaySlice.tsx +4 -0
  272. package/src/app/components/CopyToClipboard.tsx +27 -26
  273. package/src/app/components/Foundations/DisplayLogo.tsx +8 -2
  274. package/src/app/components/Layout/Header.tsx +10 -14
  275. package/src/app/components/Layout/RuntimeModeBadge.tsx +18 -0
  276. package/src/app/components/Markdown/CodeHighlight.tsx +73 -70
  277. package/src/app/components/Markdown/MarkdownComponents.tsx +30 -32
  278. package/src/app/components/McpIntegration/McpConfigDialog.tsx +349 -0
  279. package/src/app/components/McpIntegration/McpIcon.tsx +10 -0
  280. package/src/app/components/Navigation/MobileNav.tsx +7 -1
  281. package/src/app/components/Navigation/SideNav.tsx +1 -15
  282. package/src/app/components/context/PreviewContext.tsx +5 -5
  283. package/src/app/components/ui/attachment.tsx +50 -0
  284. package/src/app/components/ui/bubble.tsx +57 -0
  285. package/src/app/components/ui/button.tsx +3 -1
  286. package/src/app/components/ui/dialog.tsx +73 -0
  287. package/src/app/components/ui/marker.tsx +56 -0
  288. package/src/app/components/ui/sidebar.tsx +3 -1
  289. package/src/app/components/util/index.ts +14 -38
  290. package/src/app/css/index.css +64 -0
  291. package/src/app/lib/ai/auth.ts +33 -0
  292. package/src/app/lib/ai/context.ts +96 -0
  293. package/src/app/lib/ai/model.ts +85 -0
  294. package/src/app/lib/ai/prompt.ts +36 -0
  295. package/src/app/lib/ai/resolve.ts +97 -0
  296. package/src/app/lib/ai/tools.ts +120 -0
  297. package/src/app/lib/api/methods.ts +13 -0
  298. package/src/app/lib/auth/api.ts +105 -0
  299. package/src/app/lib/auth/config.ts +175 -0
  300. package/src/app/lib/auth/email.ts +34 -0
  301. package/src/app/lib/docs-api/backend.ts +16 -1
  302. package/src/app/lib/docs-api/errors.ts +8 -7
  303. package/src/app/lib/docs-api/handler.ts +2 -3
  304. package/src/app/lib/docs-api/index.ts +2 -0
  305. package/src/app/lib/docs-api/page-discovery.ts +121 -0
  306. package/src/app/lib/docs-api/page-rendering.ts +37 -0
  307. package/src/app/lib/docs-api/page-search.ts +191 -0
  308. package/src/app/lib/docs-api/records.ts +31 -24
  309. package/src/app/lib/docs-api/registry.ts +92 -11
  310. package/src/app/lib/docs-api/runtime-config.ts +42 -35
  311. package/src/app/lib/docs-api/search.ts +120 -0
  312. package/src/app/lib/mcp/auth.ts +64 -0
  313. package/src/app/lib/mcp/index.ts +2 -0
  314. package/src/app/lib/mcp/server.ts +357 -0
  315. package/src/app/lib/mcp/shape.ts +628 -0
  316. package/src/app/lib/registry-api/allowlist.ts +7 -5
  317. package/src/app/lib/registry-api/asset-transfer.ts +58 -31
  318. package/src/app/lib/registry-api/auth.ts +108 -45
  319. package/src/app/lib/registry-api/entity-routes.ts +17 -7
  320. package/src/app/lib/registry-api/errors.ts +12 -6
  321. package/src/app/lib/registry-api/handler.ts +22 -19
  322. package/src/app/lib/registry-api/meta.ts +4 -0
  323. package/src/app/lib/registry-api/revalidate.ts +31 -12
  324. package/src/app/lib/registry-api/store.ts +89 -26
  325. package/src/app/lib/registry-api/sync-compat.ts +166 -0
  326. package/src/app/lib/registry-api/token-transfer.ts +45 -13
  327. package/src/app/lib/registry-api/transfer-batch.ts +116 -0
  328. package/src/app/lib/registry-api/transfer.ts +99 -41
  329. package/src/app/lib/registry-api/validation.ts +33 -1
  330. package/src/app/lib/registry-connection.ts +2 -2
  331. package/src/app/lib/utils.ts +13 -0
  332. package/src/app/next.config.mjs +62 -16
  333. package/src/app/pages/[...slug]/index.tsx +52 -51
  334. package/src/app/pages/_app.tsx +14 -4
  335. package/src/app/pages/_document.tsx +6 -0
  336. package/src/app/pages/account/ai.tsx +162 -0
  337. package/src/app/pages/account/index.tsx +148 -0
  338. package/src/app/pages/account/tokens.tsx +232 -0
  339. package/src/app/pages/account/users.tsx +310 -0
  340. package/src/app/pages/api/account/ai/keys/[connectionId].ts +60 -0
  341. package/src/app/pages/api/account/ai/keys/index.ts +20 -0
  342. package/src/app/pages/api/account/index.ts +26 -0
  343. package/src/app/pages/api/account/tokens/[id].ts +17 -0
  344. package/src/app/pages/api/account/tokens/index.ts +35 -0
  345. package/src/app/pages/api/admin/users/[id]/[action].ts +89 -0
  346. package/src/app/pages/api/admin/users/index.ts +53 -0
  347. package/src/app/pages/api/ai/chat.ts +115 -0
  348. package/src/app/pages/api/ai/connections.ts +23 -0
  349. package/src/app/pages/api/auth/[...nextauth].ts +4 -0
  350. package/src/app/pages/api/auth/request-reset.ts +53 -0
  351. package/src/app/pages/api/auth/reset-password.ts +29 -0
  352. package/src/app/pages/api/docs/search/pages.json.ts +25 -0
  353. package/src/app/pages/api/install.ts +102 -0
  354. package/src/app/pages/api/mcp.ts +56 -0
  355. package/src/app/pages/api/oauth/device/approve.ts +23 -0
  356. package/src/app/pages/api/oauth/device/index.ts +41 -0
  357. package/src/app/pages/api/oauth/revoke.ts +31 -0
  358. package/src/app/pages/api/oauth/token.ts +31 -0
  359. package/src/app/pages/api/registry/components/[id]/files/[...filePath].ts +1 -1
  360. package/src/app/pages/api/registry/components/[id].ts +2 -2
  361. package/src/app/pages/api/registry/components/index.ts +1 -1
  362. package/src/app/pages/api/registry/health.ts +4 -3
  363. package/src/app/pages/api/registry/pages/[...id].ts +20 -0
  364. package/src/app/pages/api/registry/pages/index.ts +19 -0
  365. package/src/app/pages/api/registry/patterns/[id]/files/[...filePath].ts +1 -1
  366. package/src/app/pages/api/registry/patterns/[id].ts +2 -2
  367. package/src/app/pages/api/registry/patterns/index.ts +1 -1
  368. package/src/app/pages/api/registry/transfer/[kind]/[id].ts +3 -3
  369. package/src/app/pages/api/registry/transfer/[kind]/index.ts +21 -0
  370. package/src/app/pages/api/registry/transfer/assets/[collection].ts +2 -1
  371. package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +2 -1
  372. package/src/app/pages/api/registry/transfer/assets/blobs/have.ts +2 -2
  373. package/src/app/pages/api/registry/transfer/tokens/[...setId].ts +2 -2
  374. package/src/app/pages/api/sync/upload.ts +21 -0
  375. package/src/app/pages/assets/logos.tsx +4 -1
  376. package/src/app/pages/cli/device.tsx +143 -0
  377. package/src/app/pages/foundations/icons/index.tsx +7 -5
  378. package/src/app/pages/foundations/icons/{[name] → library/[name]}/index.tsx +8 -8
  379. package/src/app/pages/foundations/logo.tsx +5 -4
  380. package/src/app/pages/index/index.tsx +14 -0
  381. package/src/app/pages/index.tsx +31 -5
  382. package/src/app/pages/install.tsx +336 -0
  383. package/src/app/pages/login.tsx +117 -0
  384. package/src/app/pages/reset-password.tsx +159 -0
  385. package/src/app/types/next-auth.d.ts +27 -0
  386. package/src/app-builder/build.ts +225 -86
  387. package/src/app-builder/client-config.ts +18 -14
  388. package/src/app-builder/config-diff/strategies/pattern.ts +1 -1
  389. package/src/app-builder/nav-shell.ts +8 -13
  390. package/src/app-builder/paths.ts +25 -1
  391. package/src/app-builder/static-export.ts +27 -0
  392. package/src/app-builder/vercel-output.ts +6 -6
  393. package/src/app-builder/watchers/component.ts +3 -3
  394. package/src/app-builder/watchers/utils.ts +2 -3
  395. package/src/app-builder/watchers.ts +63 -57
  396. package/src/artifacts/index.ts +8 -1
  397. package/src/artifacts/url.ts +32 -0
  398. package/src/cache/build-cache.ts +16 -15
  399. package/src/catalog/README.md +95 -0
  400. package/src/catalog/define.ts +79 -0
  401. package/src/catalog/implementation.ts +145 -0
  402. package/src/catalog/index.ts +31 -0
  403. package/src/catalog/normalize.ts +145 -0
  404. package/src/catalog/previews.ts +114 -0
  405. package/src/catalog/renderers.ts +94 -0
  406. package/src/catalog/types.ts +82 -0
  407. package/src/cli/README.md +1 -1
  408. package/src/cli/auth/browser.ts +29 -0
  409. package/src/cli/auth/device.ts +186 -0
  410. package/src/cli/auth/store.ts +194 -0
  411. package/src/cli/create.ts +58 -3
  412. package/src/cli/make.ts +22 -74
  413. package/src/cli/scaffold.ts +39 -222
  414. package/src/cli.ts +31 -7
  415. package/src/commands/README.md +1 -1
  416. package/src/commands/build/app.ts +2 -3
  417. package/src/commands/build/components.ts +2 -3
  418. package/src/commands/build/index.ts +2 -3
  419. package/src/commands/checkout/index.ts +29 -50
  420. package/src/commands/compat/deprecations.ts +79 -0
  421. package/src/commands/compat/push-args.ts +106 -0
  422. package/src/commands/db/migrate.ts +2 -3
  423. package/src/commands/dev/index.ts +2 -3
  424. package/src/commands/eject/config.ts +2 -3
  425. package/src/commands/eject/pages.ts +2 -3
  426. package/src/commands/eject/theme.ts +2 -3
  427. package/src/commands/fetch/index.ts +2 -3
  428. package/src/commands/index.ts +8 -2
  429. package/src/commands/login/index.ts +61 -0
  430. package/src/commands/logout/index.ts +104 -0
  431. package/src/commands/make/component.ts +2 -3
  432. package/src/commands/make/page.ts +4 -5
  433. package/src/commands/publish/index.ts +32 -49
  434. package/src/commands/pull/index.ts +32 -0
  435. package/src/commands/push/index.ts +115 -0
  436. package/src/commands/scaffold/index.ts +2 -3
  437. package/src/commands/start/index.ts +2 -3
  438. package/src/commands/types.ts +13 -1
  439. package/src/commands/utils.ts +107 -2
  440. package/src/commands/validate/components.ts +2 -3
  441. package/src/config/README.md +63 -2
  442. package/src/config/catalog-include.ts +227 -0
  443. package/src/config/defaults.ts +26 -13
  444. package/src/config/env.ts +41 -0
  445. package/src/config/errors.ts +7 -0
  446. package/src/config/from-env.ts +26 -0
  447. package/src/config/helpers.ts +4 -2
  448. package/src/config/index.ts +10 -2
  449. package/src/config/loader.ts +208 -43
  450. package/src/config/normalizers/page.ts +4 -4
  451. package/src/config/resolve-env.ts +107 -0
  452. package/src/config/runtime.ts +212 -226
  453. package/src/config/validator.ts +4 -6
  454. package/src/handlebars.ts +24 -0
  455. package/src/index.d.ts +2 -2
  456. package/src/index.ts +325 -72
  457. package/src/nav/resolver.ts +3 -1
  458. package/src/nav/workspace.ts +2 -2
  459. package/src/pattern.ts +14 -0
  460. package/src/pipeline/index.ts +1 -1
  461. package/src/react.ts +52 -0
  462. package/src/registry/asset-storage/adapters/vercel-blob.ts +1 -1
  463. package/src/registry/asset-storage/define.ts +1 -1
  464. package/src/registry/asset-storage/resolve.ts +7 -4
  465. package/src/registry/auth/access-tokens.ts +222 -0
  466. package/src/registry/auth/action-tokens.ts +225 -0
  467. package/src/registry/auth/ai-keys.ts +62 -0
  468. package/src/registry/auth/crypto.ts +75 -0
  469. package/src/registry/auth/database.ts +15 -0
  470. package/src/registry/auth/device-authorizations.ts +223 -0
  471. package/src/registry/auth/gravatar.ts +6 -0
  472. package/src/registry/auth/index.ts +105 -0
  473. package/src/registry/auth/installation.ts +117 -0
  474. package/src/registry/auth/password.ts +46 -0
  475. package/src/registry/auth/rate-limits.ts +84 -0
  476. package/src/registry/auth/sync-secret.ts +67 -0
  477. package/src/registry/auth/types.ts +57 -0
  478. package/src/registry/auth/user-record.ts +25 -0
  479. package/src/registry/auth/users.ts +145 -0
  480. package/src/registry/auth/validation.ts +42 -0
  481. package/src/registry/checkout/assets.ts +28 -9
  482. package/src/registry/checkout/index.ts +582 -130
  483. package/src/registry/checkout/tokens.ts +16 -8
  484. package/src/registry/client.ts +7 -1
  485. package/src/registry/connection.ts +91 -19
  486. package/src/registry/content-kinds.ts +39 -0
  487. package/src/registry/db/client.ts +34 -14
  488. package/src/registry/db/driver.ts +66 -0
  489. package/src/registry/db/index.ts +16 -5
  490. package/src/registry/db/migrate.ts +5 -5
  491. package/src/registry/db/schema.ts +225 -25
  492. package/src/registry/publish/assets.ts +47 -37
  493. package/src/registry/publish/errors.ts +3 -3
  494. package/src/registry/publish/index.ts +286 -27
  495. package/src/registry/publish/package.ts +14 -1
  496. package/src/registry/publish/tokens.ts +35 -26
  497. package/src/registry/selection.ts +63 -0
  498. package/src/registry/transfer.ts +14 -0
  499. package/src/store/filesystem.ts +6 -6
  500. package/src/store/registry.ts +131 -15
  501. package/src/transformers/plugins/csf-render.ts +4 -2
  502. package/src/transformers/plugins/ssr-render.ts +66 -19
  503. package/src/transformers/preview/component/api.ts +13 -1
  504. package/src/transformers/preview/component/artifacts.ts +8 -4
  505. package/src/transformers/preview/component/builder.ts +17 -4
  506. package/src/transformers/preview/component/css.ts +99 -60
  507. package/src/transformers/preview/component/html.ts +30 -19
  508. package/src/transformers/preview/component/javascript.ts +1 -3
  509. package/src/transformers/preview/pattern/builder.ts +33 -20
  510. package/src/transformers/preview/pattern/html.ts +3 -1
  511. package/src/transformers/preview/types.ts +31 -3
  512. package/src/transformers/utils/build.ts +80 -0
  513. package/src/transformers/utils/module.ts +4 -2
  514. package/src/types/config.ts +168 -45
  515. package/src/utils/README.md +1 -0
  516. package/src/utils/markdown.ts +11 -0
  517. package/src/utils/menu-shell.ts +14 -7
  518. package/src/utils/pages.ts +52 -0
  519. package/src/utils/path.ts +15 -6
  520. package/templates/default/README.md.tpl +68 -1
  521. package/templates/default/components/button/button.react.handoff.js.tpl +19 -23
  522. package/templates/default/components/button/button.react.handoff.ts.tpl +22 -22
  523. package/templates/default/env.tpl +10 -0
  524. package/templates/default/gitignore.tpl +26 -3
  525. package/templates/default/handoff.config.js.tpl +21 -166
  526. package/templates/default/handoff.config.ts.tpl +21 -150
  527. package/templates/default/handoff.config.with-examples.js.tpl +22 -164
  528. package/templates/default/handoff.config.with-examples.ts.tpl +22 -148
  529. package/templates/default/package.json.tpl +6 -1
  530. package/templates/default/vercel.json.tpl +4 -0
  531. package/config/docs/foundations/logos.md +0 -7
  532. package/config/templates/component/template.json +0 -49
  533. package/config/templates/template.html +0 -7
  534. package/dist/commands/make/template.d.ts +0 -8
  535. package/dist/commands/make/template.js +0 -47
  536. package/dist/config/normalizers/declaration.d.ts +0 -11
  537. package/dist/config/normalizers/declaration.js +0 -122
  538. package/dist/config/normalizers/pattern.d.ts +0 -8
  539. package/dist/config/normalizers/pattern.js +0 -41
  540. package/dist/declarations/helpers.d.ts +0 -6
  541. package/dist/declarations/helpers.js +0 -19
  542. package/dist/declarations/index.d.ts +0 -2
  543. package/dist/declarations/index.js +0 -9
  544. package/dist/declarations/types.d.ts +0 -60
  545. package/dist/registry/db/adapter.d.ts +0 -43
  546. package/dist/registry/db/adapter.js +0 -59
  547. package/src/app/lib/api/redact.ts +0 -46
  548. package/src/commands/make/template.ts +0 -47
  549. package/src/config/normalizers/declaration.ts +0 -179
  550. package/src/config/normalizers/pattern.ts +0 -59
  551. package/src/declarations/helpers.ts +0 -36
  552. package/src/declarations/index.ts +0 -19
  553. package/src/declarations/types.ts +0 -70
  554. package/src/registry/db/adapter.ts +0 -74
  555. /package/dist/{declarations → catalog}/types.js +0 -0
@@ -36,6 +36,18 @@ export declare class HandoffBuildError extends Error {
36
36
  * deployable, so it is not keyed by project id.
37
37
  */
38
38
  export declare const getRegistryBuildOutputPath: (handoff: Handoff) => string;
39
+ /**
40
+ * Root for Next's file tracing. Every traced path in the standalone bundle is relative to this root.
41
+ *
42
+ * The tracer copies only the files inside this root. It must contain the staged app (see
43
+ * {@link getAppPath}), or Next emits no standalone bundle. It must also contain every
44
+ * `node_modules` that the required runtime dependencies resolve from, or the bundle cannot start
45
+ * (see {@link assertRegistryRuntimeDepsTraced}).
46
+ *
47
+ * `workingPath` satisfies both conditions only when handoff-app is installed in the same package as
48
+ * the config, and nothing is hoisted above it.
49
+ */
50
+ export declare const resolveRegistryTracingRoot: (handoff: Handoff) => string;
39
51
  /**
40
52
  * Build the Next.js documentation application for the resolved target. The `static` target builds
41
53
  * and exports the local workspace (default); the `registry` target packages the deployable dynamic
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
26
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
27
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -12,17 +35,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
36
  };
14
37
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.devApp = exports.watchApp = exports.getRegistryBuildOutputPath = exports.HandoffBuildError = exports.DEFAULT_BUILD_TARGET = void 0;
38
+ exports.devApp = exports.watchApp = exports.resolveRegistryTracingRoot = exports.getRegistryBuildOutputPath = exports.HandoffBuildError = exports.DEFAULT_BUILD_TARGET = void 0;
39
+ const p = __importStar(require("@clack/prompts"));
16
40
  const cross_spawn_1 = __importDefault(require("cross-spawn"));
17
41
  const fs_extra_1 = __importDefault(require("fs-extra"));
18
42
  const path_1 = __importDefault(require("path"));
43
+ const connections_1 = require("../ai/connections");
44
+ const config_1 = require("../config");
19
45
  const components_1 = require("../pipeline/components");
20
46
  const patterns_1 = require("../pipeline/patterns");
47
+ const resolve_1 = require("../registry/asset-storage/resolve");
48
+ const driver_1 = require("../registry/db/driver");
21
49
  const builder_1 = __importDefault(require("../transformers/preview/component/builder"));
22
50
  const css_1 = require("../transformers/preview/component/css");
23
51
  const javascript_1 = require("../transformers/preview/component/javascript");
24
- const adapter_1 = require("../registry/db/adapter");
25
- const resolve_1 = require("../registry/asset-storage/resolve");
26
52
  const logger_1 = require("../utils/logger");
27
53
  const client_config_1 = require("./client-config");
28
54
  const nav_shell_1 = require("./nav-shell");
@@ -78,6 +104,51 @@ const assertStaticBuildAllowed = (handoff) => {
78
104
  'or package the registry app with `handoff-app build --target registry`.');
79
105
  }
80
106
  };
107
+ /**
108
+ * Run the Next.js production build while keeping its delayed output out of the successful CLI flow.
109
+ * Captured output is replayed only when the child fails so compiler diagnostics remain available.
110
+ */
111
+ const runNextBuild = (appPath, target, errorLabel) => __awaiter(void 0, void 0, void 0, function* () {
112
+ const spinner = p.spinner();
113
+ spinner.start('Building Next.js app...');
114
+ const stdout = [];
115
+ const stderr = [];
116
+ yield new Promise((resolve, reject) => {
117
+ var _a, _b;
118
+ const buildProcess = (0, cross_spawn_1.default)('npx', ['next', 'build'], {
119
+ cwd: appPath,
120
+ stdio: ['inherit', 'pipe', 'pipe'],
121
+ env: Object.assign(Object.assign({}, process.env), { NODE_ENV: 'production', HANDOFF_BUILD_TARGET: target }),
122
+ });
123
+ (_a = buildProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (chunk) => stdout.push(Buffer.from(chunk)));
124
+ (_b = buildProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (chunk) => stderr.push(Buffer.from(chunk)));
125
+ let settled = false;
126
+ const fail = (message) => {
127
+ if (settled)
128
+ return;
129
+ settled = true;
130
+ spinner.stop('Next.js app build failed');
131
+ logger_1.Logger.childProcessBuffer(Buffer.concat(stdout));
132
+ logger_1.Logger.childProcessBuffer(Buffer.concat(stderr));
133
+ reject(new Error(message));
134
+ };
135
+ buildProcess.once('error', (error) => {
136
+ fail(`${errorLabel} failed to start\nSpawn error: ${error.message}`);
137
+ });
138
+ buildProcess.once('close', (code, signal) => {
139
+ if (settled)
140
+ return;
141
+ if (code === 0) {
142
+ settled = true;
143
+ spinner.stop('Next.js app built successfully');
144
+ resolve();
145
+ return;
146
+ }
147
+ const reason = signal ? ` because it was terminated by signal ${signal}` : ` with exit code ${code}`;
148
+ fail(`${errorLabel} failed${reason}`);
149
+ });
150
+ });
151
+ });
81
152
  /**
82
153
  * Output directory for the packaged registry app. Lives under the configurable sites output
83
154
  * directory (`sitesOutputDirectory`, default `out`) alongside the static target's `out/<projectId>`
@@ -87,6 +158,45 @@ const assertStaticBuildAllowed = (handoff) => {
87
158
  */
88
159
  const getRegistryBuildOutputPath = (handoff) => path_1.default.resolve(handoff.workingPath, handoff.sitesDirectory, 'registry');
89
160
  exports.getRegistryBuildOutputPath = getRegistryBuildOutputPath;
161
+ const commonAncestorPath = (paths) => {
162
+ const [first, ...rest] = paths.map((entry) => path_1.default.resolve(entry).split(path_1.default.sep));
163
+ let shared = first;
164
+ for (const candidate of rest) {
165
+ const next = [];
166
+ for (let index = 0; index < Math.min(shared.length, candidate.length) && shared[index] === candidate[index]; index += 1) {
167
+ next.push(shared[index]);
168
+ }
169
+ shared = next;
170
+ }
171
+ return shared.join(path_1.default.sep) || path_1.default.sep;
172
+ };
173
+ /**
174
+ * Root for Next's file tracing. Every traced path in the standalone bundle is relative to this root.
175
+ *
176
+ * The tracer copies only the files inside this root. It must contain the staged app (see
177
+ * {@link getAppPath}), or Next emits no standalone bundle. It must also contain every
178
+ * `node_modules` that the required runtime dependencies resolve from, or the bundle cannot start
179
+ * (see {@link assertRegistryRuntimeDepsTraced}).
180
+ *
181
+ * `workingPath` satisfies both conditions only when handoff-app is installed in the same package as
182
+ * the config, and nothing is hoisted above it.
183
+ */
184
+ const resolveRegistryTracingRoot = (handoff) => {
185
+ const anchors = [path_1.default.resolve(handoff.workingPath), path_1.default.resolve(handoff.modulePath)];
186
+ // Resolve each module instead of assuming its location. A hoisted or linked dependency otherwise
187
+ // drops out of the trace.
188
+ for (const moduleName of getRequiredRegistryRuntimeModules(handoff)) {
189
+ try {
190
+ const resolved = require.resolve(`${moduleName}/package.json`, { paths: [handoff.modulePath, handoff.workingPath] });
191
+ anchors.push(fs_extra_1.default.realpathSync(path_1.default.dirname(resolved)));
192
+ }
193
+ catch (_a) {
194
+ // The assertion after assembly reports a module that does not resolve.
195
+ }
196
+ }
197
+ return commonAncestorPath(anchors);
198
+ };
199
+ exports.resolveRegistryTracingRoot = resolveRegistryTracingRoot;
90
200
  /**
91
201
  * Performs cleanup of the application directory by removing the existing app directory if it exists.
92
202
  */
@@ -103,7 +213,7 @@ const cleanupAppDirectory = (handoff) => __awaiter(void 0, void 0, void 0, funct
103
213
  * @returns The path to the prepared application directory
104
214
  */
105
215
  const initializeProjectApp = (handoff_1, ...args_1) => __awaiter(void 0, [handoff_1, ...args_1], void 0, function* (handoff, options = {}) {
106
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
216
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
107
217
  const includeWorkspaceArtifacts = (_a = options.includeWorkspaceArtifacts) !== null && _a !== void 0 ? _a : true;
108
218
  const runtimeMode = (_e = (_b = options.runtimeModeOverride) !== null && _b !== void 0 ? _b : (_d = (_c = handoff.config) === null || _c === void 0 ? void 0 : _c.runtime) === null || _d === void 0 ? void 0 : _d.mode) !== null && _e !== void 0 ? _e : 'workspace';
109
219
  const srcPath = path_1.default.resolve(handoff.modulePath, 'src', 'app');
@@ -142,14 +252,16 @@ const initializeProjectApp = (handoff_1, ...args_1) => __awaiter(void 0, [handof
142
252
  const escapedProjectId = escapeForSingleQuotedJsString(handoffProjectId);
143
253
  const escapedWorkingPath = escapeForSingleQuotedJsString(handoffWorkingPath);
144
254
  const escapedModulePath = escapeForSingleQuotedJsString(handoffModulePath);
255
+ // Baked here so the template and the assembly step use the same root.
256
+ const escapedTracingRoot = escapeForSingleQuotedJsString((0, exports.resolveRegistryTracingRoot)(handoff));
145
257
  const escapedExportPath = escapeForSingleQuotedJsString(handoffExportPath);
146
258
  const escapedWebsocketPort = escapeForSingleQuotedJsString(String(handoffWebsocketPort));
147
259
  // Resolved runtime mode + registry connection inputs (names only) baked into the Next bundle so the
148
260
  // deployed registry app resolves its mode/DB env-var name without any build-machine filesystem.
149
261
  const escapedRuntimeMode = escapeForSingleQuotedJsString(runtimeMode);
150
- const escapedRegistryAdapter = escapeForSingleQuotedJsString((0, adapter_1.resolveRegistryAdapter)(handoff.config));
151
- const escapedDatabaseUrlEnv = escapeForSingleQuotedJsString((0, adapter_1.resolveDatabaseUrlEnv)(handoff.config));
152
- const escapedApiTokenEnv = escapeForSingleQuotedJsString((0, adapter_1.resolveApiTokenEnv)(handoff.config));
262
+ const escapedMcpEnabled = escapeForSingleQuotedJsString(String((0, config_1.isMcpEnabled)(handoff.config)));
263
+ const escapedRegistryDriver = escapeForSingleQuotedJsString((0, driver_1.resolveRegistryDriver)(handoff.config));
264
+ const escapedDatabaseUrlEnv = escapeForSingleQuotedJsString((0, driver_1.resolveDatabaseUrlEnv)(handoff.config));
153
265
  // Asset storage selection baked (provider + module + env-var names + non-secret options JSON).
154
266
  const assetStorage = (0, resolve_1.resolveAssetStorageFromConfig)(handoff.config);
155
267
  const escapedAssetStorageAdapter = escapeForSingleQuotedJsString(assetStorage.adapterKind);
@@ -157,22 +269,35 @@ const initializeProjectApp = (handoff_1, ...args_1) => __awaiter(void 0, [handof
157
269
  const escapedAssetStorageTokenEnv = escapeForSingleQuotedJsString(assetStorage.tokenEnv);
158
270
  const escapedAssetStorageMaxInline = escapeForSingleQuotedJsString(String(assetStorage.maxInlineBytes));
159
271
  const escapedAssetStorageOptions = escapeForSingleQuotedJsString(JSON.stringify((_k = assetStorage.options) !== null && _k !== void 0 ? _k : {}));
272
+ // AI assistant selection baked (enabled flag + declared connections + default model). Connections
273
+ // carry env-var names and non-secret options only; keys are read from their named env var at
274
+ // request time, and a deployment can extend or replace the list through HANDOFF_AI_CONNECTIONS.
275
+ const ai = (0, connections_1.resolveAiFromConfig)(handoff.config);
276
+ const escapedAiEnabled = escapeForSingleQuotedJsString(String(ai.enabled));
277
+ const escapedAiConnections = escapeForSingleQuotedJsString(JSON.stringify(ai.connections));
278
+ const escapedAiDefaultModel = escapeForSingleQuotedJsString((_l = ai.defaultModel) !== null && _l !== void 0 ? _l : '');
279
+ const escapedAiProviderModules = escapeForSingleQuotedJsString(JSON.stringify(ai.connections.map((connection) => connection.module).filter((module) => Boolean(module))));
160
280
  const placeholderValues = {
161
281
  '%HANDOFF_PROJECT_ID%': escapedProjectId,
162
282
  '%HANDOFF_APP_BASE_PATH%': escapedAppBasePath,
163
283
  '%HANDOFF_WORKING_PATH%': escapedWorkingPath,
164
284
  '%HANDOFF_MODULE_PATH%': escapedModulePath,
285
+ '%HANDOFF_TRACING_ROOT%': escapedTracingRoot,
165
286
  '%HANDOFF_EXPORT_PATH%': escapedExportPath,
166
287
  '%HANDOFF_WEBSOCKET_PORT%': escapedWebsocketPort,
167
288
  '%HANDOFF_RUNTIME_MODE%': escapedRuntimeMode,
168
- '%HANDOFF_REGISTRY_ADAPTER%': escapedRegistryAdapter,
289
+ '%HANDOFF_MCP_ENABLED%': escapedMcpEnabled,
290
+ '%HANDOFF_REGISTRY_DRIVER%': escapedRegistryDriver,
169
291
  '%HANDOFF_REGISTRY_DATABASE_URL_ENV%': escapedDatabaseUrlEnv,
170
- '%HANDOFF_REGISTRY_API_TOKEN_ENV%': escapedApiTokenEnv,
171
292
  '%HANDOFF_ASSET_STORAGE_ADAPTER%': escapedAssetStorageAdapter,
172
293
  '%HANDOFF_ASSET_STORAGE_MODULE%': escapedAssetStorageModule,
173
294
  '%HANDOFF_ASSET_STORAGE_TOKEN_ENV%': escapedAssetStorageTokenEnv,
174
295
  '%HANDOFF_ASSET_STORAGE_MAX_INLINE_BYTES%': escapedAssetStorageMaxInline,
175
296
  '%HANDOFF_ASSET_STORAGE_OPTIONS%': escapedAssetStorageOptions,
297
+ '%HANDOFF_AI_ENABLED%': escapedAiEnabled,
298
+ '%HANDOFF_AI_BAKED_CONNECTIONS%': escapedAiConnections,
299
+ '%HANDOFF_AI_DEFAULT_MODEL%': escapedAiDefaultModel,
300
+ '%HANDOFF_AI_PROVIDER_MODULES%': escapedAiProviderModules,
176
301
  };
177
302
  let nextConfigContent = yield fs_extra_1.default.readFile(nextConfigPath, 'utf-8');
178
303
  for (const [placeholder, value] of Object.entries(placeholderValues)) {
@@ -216,20 +341,7 @@ const buildApp = (handoff_1, ...args_1) => __awaiter(void 0, [handoff_1, ...args
216
341
  (0, static_export_1.validateReferencedArtifacts)(handoff);
217
342
  // Build app. The static target drives Next's `output: 'export'` via HANDOFF_BUILD_TARGET so the
218
343
  // export gate is tied to the resolved target, not to NODE_ENV.
219
- const buildResult = cross_spawn_1.default.sync('npx', ['next', 'build'], {
220
- cwd: appPath,
221
- stdio: ['inherit', 'pipe', 'pipe'],
222
- env: Object.assign(Object.assign({}, process.env), { NODE_ENV: 'production', HANDOFF_BUILD_TARGET: target }),
223
- });
224
- logger_1.Logger.childProcessBuffer(buildResult.stdout);
225
- logger_1.Logger.childProcessBuffer(buildResult.stderr);
226
- if (buildResult.status !== 0) {
227
- let errorMsg = `Next.js build failed with exit code ${buildResult.status}`;
228
- if (buildResult.error) {
229
- errorMsg += `\nSpawn error: ${buildResult.error.message}`;
230
- }
231
- throw new Error(errorMsg);
232
- }
344
+ yield runNextBuild(appPath, target, 'Next.js build');
233
345
  // Reproduce the docs read API (`/api/docs/*`) as route-shaped static files in the export output,
234
346
  // since `output: 'export'` disables the live API routes.
235
347
  const exportDir = path_1.default.resolve(appPath, 'out');
@@ -280,7 +392,22 @@ const findStandaloneServerDir = (root) => {
280
392
  * Write a deployment guide next to the packaged registry app describing how to run it on Vercel,
281
393
  * a custom Node server, or in a container, and which env vars it requires at deploy time.
282
394
  */
283
- const writeRegistryDeploymentReadme = (outputRoot, entryRelativePath, databaseUrlEnv) => __awaiter(void 0, void 0, void 0, function* () {
395
+ const writeRegistryDeploymentReadme = (outputRoot, entryRelativePath, databaseUrlEnv, ai) => __awaiter(void 0, void 0, void 0, function* () {
396
+ const serviceKeyEnvs = [...new Set(ai.connections.map((connection) => connection.apiKeyEnv).filter(Boolean))];
397
+ const needsKeySecret = ai.connections.some((connection) => connection.credential === 'user');
398
+ const aiSection = !ai.enabled
399
+ ? ''
400
+ : `
401
+ ## AI assistant
402
+
403
+ This build serves the docs assistant at \`/api/ai/*\`.
404
+
405
+ ${serviceKeyEnvs.map((name) => `- \`${name}\` — API key for a declared AI connection, read at request time.`).join('\n') || '- No service-key connection is declared, so no provider key is required here.'}
406
+ ${needsKeySecret ? '- `HANDOFF_AI_KEY_SECRET` — a long, random secret that encrypts the API keys readers save for themselves. Readers cannot save a key without it.\n' : ''}
407
+ \`HANDOFF_AI_CONNECTIONS\` optionally carries a JSON array of connections, read at request time and
408
+ merged over the list this build baked in, keyed by \`id\`. Use it to add or repoint a provider
409
+ without rebuilding.
410
+ `;
284
411
  const readme = `# Handoff Registry App
285
412
 
286
413
  A self-contained, deployable Next.js **standalone** build produced by
@@ -295,8 +422,12 @@ and \`.next/static/\` already copied alongside so the server serves them.
295
422
  ## Required environment variables (supplied at deploy time, never baked in)
296
423
 
297
424
  - \`${databaseUrlEnv}\` — PostgreSQL/Neon connection string, read at request time.
298
- - \`HANDOFF_REGISTRY_API_TOKEN\` — bearer token for registry management mutations (if used).
425
+ - \`AUTH_SECRET\` — a long, random secret used to sign browser sessions.
426
+ - \`AUTH_URL\` — the canonical public registry URL, including the configured base path.
299
427
 
428
+ Optional email delivery uses \`RESEND_API_KEY\` and \`AUTH_FROM_EMAIL\`. Without them, invitation
429
+ links are shown once to an administrator for manual delivery.
430
+ ${aiSection}
300
431
  ## Database migrations
301
432
 
302
433
  Apply migrations from the \`handoff-app\` CLI as a controlled release step (e.g. in your CI/CD
@@ -306,10 +437,33 @@ pipeline) before deploying new code:
306
437
  ${databaseUrlEnv}="postgres://…" handoff-app db:migrate
307
438
  \`\`\`
308
439
 
309
- \`db:migrate\` reads your project config + DB env vars, resolves the same database adapter the app was
440
+ \`db:migrate\` reads your project config + DB env vars, resolves the same database driver the app was
310
441
  built with, and applies the package-owned migration set. It runs independently of \`build\` and of
311
442
  starting the server, so run it as a release/one-shot job.
312
443
 
444
+ ## Complete the one-time installation
445
+
446
+ After migrations and deployment, open \`/install\` immediately and create the initial administrator.
447
+ The installer verifies the deployment but never changes the schema. An exposed, uninstalled registry
448
+ can be claimed by its first visitor, so do not leave this step unattended.
449
+
450
+ Once installation completes, sign in and authorize a workspace. Either approve the CLI in the
451
+ browser:
452
+
453
+ \`\`\`bash
454
+ handoff-app login --url https://registry.example.com
455
+ \`\`\`
456
+
457
+ or create a token under Account > Access tokens and set it in the workspace environment:
458
+
459
+ \`\`\`bash
460
+ HANDOFF_REGISTRY_URL=https://registry.example.com
461
+ HANDOFF_REGISTRY_ACCESS_TOKEN=hnd_…
462
+ \`\`\`
463
+
464
+ Both produce the same revocable, user-owned credential. The former
465
+ \`HANDOFF_REGISTRY_API_TOKEN\` fixed server secret is no longer accepted.
466
+
313
467
  ## Run it (self-hosting)
314
468
 
315
469
  Standalone is the documented artifact for self-hosting on a Node.js server, VPS, Docker, or
@@ -352,15 +506,25 @@ containers, custom Node servers, and other non-Vercel hosts.
352
506
  });
353
507
  /**
354
508
  * Resolve the set of npm packages the packaged registry app must be able to `require`/`import` at
355
- * runtime, given the configured database adapter. `next`/`react`/`react-dom` run the server and React
356
- * runtime; `drizzle-orm` backs both the request-time DB client and the migration runner; the driver
357
- * is adapter-specific (the Neon serverless driver also needs `ws` for its Node WebSocket transport).
509
+ * runtime, given the configured database driver. `next`/`react`/`react-dom` run the server and React
510
+ * runtime; `drizzle-orm` backs both the request-time DB client and the migration runner; the MCP SDK
511
+ * (and its `zod` peer) is only needed when `/api/mcp/` is enabled; the driver package is
512
+ * driver-specific (the Neon serverless driver also needs `ws` for its Node WebSocket transport).
358
513
  */
359
514
  const getRequiredRegistryRuntimeModules = (handoff) => {
360
515
  var _a;
361
- const base = ['next', 'react', 'react-dom', 'drizzle-orm'];
362
- const adapter = (0, adapter_1.resolveRegistryAdapter)(handoff.config);
363
- const driver = adapter === 'neon' ? ['@neondatabase/serverless', 'ws'] : ['pg'];
516
+ const base = ['next', 'next-auth', 'react', 'react-dom', 'drizzle-orm'];
517
+ const ai = (0, connections_1.resolveAiFromConfig)(handoff.config);
518
+ // The assistant runs the MCP tools in-process, so it needs the MCP SDK whether or not the HTTP
519
+ // endpoint is served.
520
+ if ((0, config_1.isMcpEnabled)(handoff.config) || ai.enabled) {
521
+ base.push('@modelcontextprotocol/sdk', 'zod');
522
+ }
523
+ if (ai.enabled) {
524
+ base.push('ai', '@ai-sdk/openai-compatible');
525
+ }
526
+ const driver = (0, driver_1.resolveRegistryDriver)(handoff.config);
527
+ const driverModules = driver === 'neon' ? ['@neondatabase/serverless', 'ws'] : ['pg'];
364
528
  // Asset-storage SDKs the deployed registry must be able to load at request time. The pre-packaged
365
529
  // Vercel Blob adapter needs `@vercel/blob`; a custom adapter may declare its installed SDK
366
530
  // package(s) via `assetStorage.options.sdkModules` so the trace/assertion covers them.
@@ -373,7 +537,7 @@ const getRequiredRegistryRuntimeModules = (handoff) => {
373
537
  if (Array.isArray(sdkModules)) {
374
538
  storage.push(...sdkModules.filter((mod) => typeof mod === 'string'));
375
539
  }
376
- return [...base, ...driver, ...storage];
540
+ return [...base, ...driverModules, ...storage];
377
541
  };
378
542
  /**
379
543
  * Build-time guard against the empty-`node_modules` regression (the artifact would otherwise boot-fail
@@ -411,14 +575,11 @@ const assertRegistryRuntimeDepsTraced = (handoff, entryDir) => {
411
575
  */
412
576
  const assembleRegistryStandalone = (handoff, appPath, standaloneRoot, entryDir) => __awaiter(void 0, void 0, void 0, function* () {
413
577
  yield fs_extra_1.default.copy(standaloneRoot, entryDir, { overwrite: true });
414
- // Locate the server entry within the assembled package. Standalone tracing is rooted at the
415
- // consumer project root (`workingPath`, see next.config.mjs), so every traced file is laid out at
416
- // its path *relative to `workingPath`*. The staged app lives at `<workingPath>/node_modules/
417
- // handoff-app/.handoff/<projectId>`, so the server entry lands nested at that same relative path
418
- // *underneath* the traced `node_modules`. Resolve it deterministically; the recursive fallback
419
- // skips `node_modules` (so it cannot find this nested entry) and only covers a hypothetical
420
- // non-nested layout.
421
- const relAppDir = path_1.default.relative(handoff.workingPath, appPath);
578
+ // Locate the server entry in the assembled package. Traced files keep their path relative to the
579
+ // tracing root, so the server entry nests under the traced `node_modules`. The recursive fallback
580
+ // skips `node_modules`, so it covers only a non-nested layout.
581
+ const tracingRoot = (0, exports.resolveRegistryTracingRoot)(handoff);
582
+ const relAppDir = path_1.default.relative(tracingRoot, appPath);
422
583
  let serverDir = path_1.default.resolve(entryDir, relAppDir);
423
584
  if (!fs_extra_1.default.existsSync(path_1.default.join(serverDir, 'server.js'))) {
424
585
  const located = findStandaloneServerDir(entryDir);
@@ -438,7 +599,7 @@ const assembleRegistryStandalone = (handoff, appPath, standaloneRoot, entryDir)
438
599
  // so we must NOT remove the first path segment (`node_modules`) — that would delete every traced
439
600
  // dependency. Remove only the `.handoff` staging container (the parent of the staged app dir),
440
601
  // leaving `node_modules/` and the real `node_modules/handoff-app/` package intact.
441
- const stagingContainer = path_1.default.resolve(entryDir, path_1.default.relative(handoff.workingPath, path_1.default.dirname(appPath)));
602
+ const stagingContainer = path_1.default.resolve(entryDir, path_1.default.relative(tracingRoot, path_1.default.dirname(appPath)));
442
603
  if (path_1.default.basename(stagingContainer) === '.handoff' && fs_extra_1.default.existsSync(stagingContainer)) {
443
604
  yield fs_extra_1.default.remove(stagingContainer);
444
605
  }
@@ -461,6 +622,16 @@ const assembleRegistryStandalone = (handoff, appPath, standaloneRoot, entryDir)
461
622
  yield fs_extra_1.default.copy(src, path_1.default.join(entryDir, configFile), { overwrite: true });
462
623
  }
463
624
  }
625
+ // Next copies the `package.json` of the tracing root into the bundle without change. The generated
626
+ // `server.js` is CommonJS, so an ESM manifest stops the bundle from starting. That manifest also
627
+ // names scripts and dev dependencies that the bundle does not ship.
628
+ const manifestPath = path_1.default.join(entryDir, 'package.json');
629
+ const inheritedManifest = (yield fs_extra_1.default.pathExists(manifestPath))
630
+ ? yield fs_extra_1.default.readJson(manifestPath).catch(() => ({}))
631
+ : {};
632
+ delete inheritedManifest.scripts;
633
+ delete inheritedManifest.devDependencies;
634
+ yield fs_extra_1.default.writeJson(manifestPath, Object.assign(Object.assign({}, inheritedManifest), { type: 'commonjs' }), { spaces: 2 });
464
635
  // Fail loudly at build time if the trace did not capture the runtime deps, rather than shipping a
465
636
  // broken artifact that only crashes on an isolated deploy. Covers both deliverables (this is the
466
637
  // shared assembly step for `standalone` and `vercel`).
@@ -482,7 +653,7 @@ const assembleRegistryStandalone = (handoff, appPath, standaloneRoot, entryDir)
482
653
  * - `vercel` → the Vercel Build Output API directory (`.vercel/output`) at the repo root: the
483
654
  * traced bundle wrapped as a Node function plus CDN static assets and a route table.
484
655
  *
485
- * Mode is forced to `registry`; the database adapter is honored from config (single-sourced so build
656
+ * Mode is forced to `registry`; the database driver is honored from config (single-sourced so build
486
657
  * and `db:migrate` never diverge). No connection-string value is ever baked — only env-var *names*.
487
658
  */
488
659
  const buildRegistryApp = (handoff_1, ...args_1) => __awaiter(void 0, [handoff_1, ...args_1], void 0, function* (handoff, buildPackage = 'standalone') {
@@ -495,15 +666,15 @@ const buildRegistryApp = (handoff_1, ...args_1) => __awaiter(void 0, [handoff_1,
495
666
  if (sourceMode !== 'registry') {
496
667
  logger_1.Logger.info(`Source runtime.mode is "${sourceMode}"; forcing "registry" mode in the packaged registry app.`);
497
668
  }
498
- // The adapter stays single-sourced from config (never flipped by the package flag), so build and
669
+ // The driver stays single-sourced from config (never flipped by the package flag), so build and
499
670
  // `db:migrate` always resolve the same one. `pg` uses long-lived TCP connections that pool poorly on
500
671
  // serverless; warn (non-fatally) so the operator points DATABASE_URL at a pooled endpoint or selects
501
- // the Neon adapter. The connection-string value is not available at build time, so this cannot be
672
+ // the Neon driver. The connection-string value is not available at build time, so this cannot be
502
673
  // validated — it is guidance only and never fails the build.
503
- if (buildPackage === 'vercel' && (0, adapter_1.resolveRegistryAdapter)(handoff.config) === 'pg') {
504
- logger_1.Logger.warn('Registry Vercel build uses the "pg" adapter (standard TCP connections), which pools poorly on ' +
674
+ if (buildPackage === 'vercel' && (0, driver_1.resolveRegistryDriver)(handoff.config) === 'pg') {
675
+ logger_1.Logger.warn('Registry Vercel build uses the "pg" driver (standard TCP connections), which pools poorly on ' +
505
676
  'serverless and can exhaust the database connection limit. Point DATABASE_URL at a pooled endpoint ' +
506
- '(PgBouncer / transaction pooling), or set runtime.registry.database.adapter: "neon" for a ' +
677
+ '(PgBouncer / transaction pooling), or set runtime.registry.database.driver: "neon" for a ' +
507
678
  'serverless-native HTTP/WebSocket driver. The build will continue.');
508
679
  }
509
680
  // Stage the app without any workspace-derived artifacts — the registry serves from the database.
@@ -524,27 +695,16 @@ const buildRegistryApp = (handoff_1, ...args_1) => __awaiter(void 0, [handoff_1,
524
695
  yield fs_extra_1.default.remove((0, vercel_output_1.getVercelOutputPath)(handoff));
525
696
  // Build the dynamic app. `output: 'standalone'` (driven by HANDOFF_BUILD_TARGET) traces the runtime
526
697
  // and the selected Postgres/Neon driver into a self-contained bundle — never a static export.
527
- const buildResult = cross_spawn_1.default.sync('npx', ['next', 'build'], {
528
- cwd: appPath,
529
- stdio: ['inherit', 'pipe', 'pipe'],
530
- env: Object.assign(Object.assign({}, process.env), { NODE_ENV: 'production', HANDOFF_BUILD_TARGET: 'registry' }),
531
- });
532
- logger_1.Logger.childProcessBuffer(buildResult.stdout);
533
- logger_1.Logger.childProcessBuffer(buildResult.stderr);
534
- if (buildResult.status !== 0) {
535
- let errorMsg = `Registry app build failed with exit code ${buildResult.status}`;
536
- if (buildResult.error) {
537
- errorMsg += `\nSpawn error: ${buildResult.error.message}`;
538
- }
539
- throw new Error(errorMsg);
540
- }
698
+ yield runNextBuild(appPath, 'registry', 'Registry app build');
541
699
  // Assemble the deployable package. Standalone tracing is rooted at the package (modulePath), so the
542
700
  // app's traced files land under `<relAppDir>` inside the standalone tree; static assets and public
543
701
  // files are not traced and must be copied alongside the server entry.
544
702
  const standaloneRoot = path_1.default.resolve(appPath, '.next', 'standalone');
545
703
  if (!fs_extra_1.default.existsSync(standaloneRoot)) {
546
- throw new Error(`Registry build did not produce a standalone bundle at "${standaloneRoot}". Ensure the registry ` +
547
- 'build target sets Next `output: "standalone"`.');
704
+ throw new Error(`Registry build did not produce a standalone bundle at "${standaloneRoot}". Next emits one only ` +
705
+ `when the app being built sits inside \`outputFileTracingRoot\` (resolved here to ` +
706
+ `"${(0, exports.resolveRegistryTracingRoot)(handoff)}"), so check that the staged app at "${appPath}" is ` +
707
+ 'inside that root, and that the registry build target still sets Next `output: "standalone"`.');
548
708
  }
549
709
  // Final assembly branches on the resolved package. Both lay out
550
710
  // the same traced standalone bundle; they differ only in where it lands and how it is wrapped.
@@ -561,7 +721,7 @@ const buildRegistryApp = (handoff_1, ...args_1) => __awaiter(void 0, [handoff_1,
561
721
  // `handoff-app` source/CLI (`handoff-app db:migrate`) as a controlled release step (e.g. CI/CD),
562
722
  // never from the deployed bundle. See the generated README for the migrate-then-deploy flow.
563
723
  const entryRelativePath = path_1.default.relative(output, serverEntry).split(path_1.default.sep).join('/');
564
- yield writeRegistryDeploymentReadme(output, entryRelativePath, (0, adapter_1.resolveDatabaseUrlEnv)(handoff.config));
724
+ yield writeRegistryDeploymentReadme(output, entryRelativePath, (0, driver_1.resolveDatabaseUrlEnv)(handoff.config), (0, connections_1.resolveAiFromConfig)(handoff.config));
565
725
  logger_1.Logger.success(`Packaged registry app at ${output} (start: \`node ${entryRelativePath}\`, migrate: \`handoff-app db:migrate\`).`);
566
726
  });
567
727
  /**
@@ -628,14 +788,12 @@ const watchApp = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
628
788
  pendingHandlers: new Map(),
629
789
  runtimeComponentsWatcher: null,
630
790
  runtimeConfigurationWatcher: null,
631
- componentDirectoriesWatcher: null,
632
- patternDirectoriesWatcher: null,
791
+ catalogDirectoriesWatcher: null,
633
792
  };
634
793
  (0, watchers_1.watchPublicDirectory)(handoff, wss, state, chokidarConfig);
635
794
  (0, watchers_1.watchRuntimeComponents)(handoff, state, (0, watchers_1.getRuntimeComponentsPathsToWatch)(handoff));
636
795
  (0, watchers_1.watchRuntimeConfiguration)(handoff, state);
637
- (0, watchers_1.watchComponentDirectories)(handoff, state, chokidarConfig);
638
- (0, watchers_1.watchPatternDirectories)(handoff, state, chokidarConfig);
796
+ (0, watchers_1.watchCatalogDirectories)(handoff, state, chokidarConfig);
639
797
  (0, watchers_1.watchGlobalEntries)(handoff, state, chokidarConfig);
640
798
  (0, watchers_1.watchPages)(handoff, chokidarConfig);
641
799
  });
@@ -17,7 +17,8 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
17
17
  const path_1 = __importDefault(require("path"));
18
18
  const config_1 = require("../config");
19
19
  const resolve_1 = require("../registry/asset-storage/resolve");
20
- const adapter_1 = require("../registry/db/adapter");
20
+ const connection_1 = require("../registry/connection");
21
+ const driver_1 = require("../registry/db/driver");
21
22
  const paths_1 = require("./paths");
22
23
  /**
23
24
  * Publishes the tokens API files to the public directory.
@@ -55,7 +56,7 @@ exports.generateTokensApi = generateTokensApi;
55
56
  * Build the server-only runtime config consumed by the docs read API.
56
57
  *
57
58
  * The browser-facing `client.config.json` carries only the resolved mode; the server additionally
58
- * needs the registry connection *inputs* (selected adapter + the *name* of the database-URL env
59
+ * needs the registry connection *inputs* (selected driver + the *name* of the database-URL env
59
60
  * var) to back the registry-mode docs read API. These are non-secret — the connection-string value
60
61
  * itself is never persisted, only resolved from the env var at request time.
61
62
  */
@@ -64,10 +65,10 @@ const buildServerRuntimeConfig = (config, modeOverride) => {
64
65
  const assetStorage = (0, resolve_1.resolveAssetStorageFromConfig)(config);
65
66
  return {
66
67
  mode: (_b = modeOverride !== null && modeOverride !== void 0 ? modeOverride : (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : 'workspace',
68
+ mcp: (0, config_1.isMcpEnabled)(config),
67
69
  registry: {
68
- adapter: (0, adapter_1.resolveRegistryAdapter)(config),
69
- databaseUrlEnv: (0, adapter_1.resolveDatabaseUrlEnv)(config),
70
- apiTokenEnv: (0, adapter_1.resolveApiTokenEnv)(config),
70
+ driver: (0, driver_1.resolveRegistryDriver)(config),
71
+ databaseUrlEnv: (0, driver_1.resolveDatabaseUrlEnv)(config),
71
72
  },
72
73
  assetStorage: {
73
74
  adapter: assetStorage.adapterKind,
@@ -84,17 +85,20 @@ const buildServerRuntimeConfig = (config, modeOverride) => {
84
85
  * connection inputs from. Both are always written together so they never drift.
85
86
  */
86
87
  const persistClientConfig = (handoff_1, ...args_1) => __awaiter(void 0, [handoff_1, ...args_1], void 0, function* (handoff, options = {}) {
88
+ var _a;
87
89
  const appPath = (0, paths_1.getAppPath)(handoff);
88
90
  // Ensure directory exists
89
91
  yield fs_extra_1.default.ensureDir(appPath);
90
92
  const clientConfig = (0, config_1.getClientConfig)(handoff.config);
91
- if (options.runtimeModeOverride) {
92
- // A forced registry mode (the registry build target) is never a connected workspace, so the
93
- // baked client config must report `connected: false` even when packaged from a connected
94
- // workspace project.
95
- const connected = options.runtimeModeOverride === 'registry' ? false : clientConfig.runtime.connected;
96
- clientConfig.runtime = Object.assign(Object.assign({}, clientConfig.runtime), { mode: options.runtimeModeOverride, connected });
97
- }
93
+ const mode = (_a = options.runtimeModeOverride) !== null && _a !== void 0 ? _a : clientConfig.runtime.mode;
94
+ // A registry build target is never a connected workspace, so it must bake `connected: false`
95
+ // even when packaged from a connected project. Otherwise a workspace is connected whenever a
96
+ // registry URL resolves — from config/env or a saved device login — so `login` alone surfaces
97
+ // the publish/checkout UI without also requiring HANDOFF_REGISTRY_URL.
98
+ const connected = mode === 'registry'
99
+ ? false
100
+ : Boolean((yield (0, connection_1.resolveAuthenticatedRegistryConnection)(handoff.config, handoff.workingPath, handoff.getProfile())).url);
101
+ clientConfig.runtime = Object.assign(Object.assign({}, clientConfig.runtime), { mode, connected });
98
102
  yield fs_extra_1.default.writeJson(path_1.default.resolve(appPath, 'client.config.json'), { config: clientConfig }, { spaces: 2 });
99
103
  yield fs_extra_1.default.writeJson(path_1.default.resolve(appPath, 'runtime.server.json'), buildServerRuntimeConfig(handoff.config, options.runtimeModeOverride), { spaces: 2 });
100
104
  });
@@ -43,12 +43,12 @@ const snapshot_1 = require("../snapshot");
43
43
  * components. Outer key is component id, inner key is synthetic preview key.
44
44
  */
45
45
  const snapshotPatternSynthetics = (handoff, patternId) => {
46
- var _a, _b, _c, _d;
47
- const components = (_c = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.components) !== null && _c !== void 0 ? _c : {};
46
+ var _a, _b, _c;
47
+ const components = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {};
48
48
  const prefix = `__pattern_${patternId}_`;
49
49
  const result = new Map();
50
50
  for (const [componentId, component] of Object.entries(components)) {
51
- const previews = (_d = component.internalPatternPreviews) !== null && _d !== void 0 ? _d : {};
51
+ const previews = (_c = component.internalPatternPreviews) !== null && _c !== void 0 ? _c : {};
52
52
  const entries = new Map();
53
53
  for (const [key, preview] of Object.entries(previews)) {
54
54
  if (key.startsWith(prefix)) {
@@ -14,10 +14,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.generateNavShell = exports.generateDefaultPages = exports.DEFAULT_PAGES_RELATIVE_PATH = exports.NAV_SHELL_RELATIVE_PATH = void 0;
16
16
  const fs_extra_1 = __importDefault(require("fs-extra"));
17
- const gray_matter_1 = __importDefault(require("gray-matter"));
18
17
  const path_1 = __importDefault(require("path"));
18
+ const markdown_1 = require("../utils/markdown");
19
19
  const menu_shell_1 = require("../utils/menu-shell");
20
20
  const logger_1 = require("../utils/logger");
21
+ const pages_1 = require("../utils/pages");
21
22
  /**
22
23
  * Relative path (within the staged Next app) of the baked navigation shell. The docs read API
23
24
  * (`pages/api/docs/nav.json.ts`) imports this statically so it is bundled into the route chunk and
@@ -27,21 +28,13 @@ const logger_1 = require("../utils/logger");
27
28
  exports.NAV_SHELL_RELATIVE_PATH = path_1.default.join('generated', 'nav-shell.json');
28
29
  /** Baked package-default markdown used as the registry catch-all's runtime fallback. */
29
30
  exports.DEFAULT_PAGES_RELATIVE_PATH = path_1.default.join('generated', 'default-pages.json');
30
- /** Recursively collect package docs (except dedicated index routes) by their catch-all id. */
31
- const collectDefaultPages = (root, relativeParts = []) => {
32
- if (!fs_extra_1.default.existsSync(root))
33
- return {};
31
+ /** Collect package defaults for registry fallbacks, including the dedicated root home page. */
32
+ const collectDefaultPages = (root) => {
34
33
  const pages = {};
35
- for (const entry of fs_extra_1.default.readdirSync(root)) {
36
- const absolutePath = path_1.default.join(root, entry);
37
- if (fs_extra_1.default.lstatSync(absolutePath).isDirectory()) {
38
- Object.assign(pages, collectDefaultPages(absolutePath, [...relativeParts, entry]));
39
- }
40
- else if (entry.endsWith('.md') && entry !== 'index.md') {
41
- const id = [...relativeParts, entry.replace(/\.md$/, '')].join('/');
42
- const { data, content } = (0, gray_matter_1.default)(fs_extra_1.default.readFileSync(absolutePath, 'utf8'));
43
- pages[id] = { metadata: data, content };
44
- }
34
+ for (const segments of (0, pages_1.collectPageSlugSegments)(root, { includeRootIndex: true })) {
35
+ const id = segments.join('/');
36
+ const { data, content } = (0, markdown_1.parseMarkdown)(fs_extra_1.default.readFileSync(path_1.default.resolve(root, `${id}.md`), 'utf8'));
37
+ pages[id] = { metadata: data, content };
45
38
  }
46
39
  return pages;
47
40
  };