handoff-app 2.0.0-9 → 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 (303) hide show
  1. package/{Changelog.md → CHANGELOG.md} +85 -1
  2. package/{License.md → LICENSE.md} +1 -1
  3. package/README.md +813 -406
  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/cli/create.js +1 -2
  55. package/dist/commands/build/index.d.ts +1 -1
  56. package/dist/commands/build/index.js +1 -1
  57. package/dist/commands/utils.d.ts +3 -3
  58. package/dist/config/defaults.js +7 -4
  59. package/dist/config/from-env.d.ts +4 -0
  60. package/dist/config/from-env.js +38 -1
  61. package/dist/config/helpers.js +2 -2
  62. package/dist/config/index.d.ts +0 -1
  63. package/dist/config/index.js +1 -4
  64. package/dist/config/loader.js +26 -2
  65. package/dist/config/resolve-env.d.ts +2 -1
  66. package/dist/config/resolve-env.js +28 -12
  67. package/dist/config/runtime.js +1 -1
  68. package/dist/index.d.ts +12 -7
  69. package/dist/index.js +18 -22
  70. package/dist/nav/index.d.ts +2 -2
  71. package/dist/nav/registry.d.ts +3 -3
  72. package/dist/nav/registry.js +1 -1
  73. package/dist/nav/workspace.d.ts +3 -3
  74. package/dist/nav/workspace.js +1 -1
  75. package/dist/pipeline/figma.d.ts +13 -2
  76. package/dist/pipeline/figma.js +86 -46
  77. package/dist/pipeline/styles.js +1 -1
  78. package/dist/pipeline/validation.d.ts +1 -1
  79. package/dist/pipeline/validation.js +3 -3
  80. package/dist/providers.d.ts +10 -0
  81. package/dist/providers.js +13 -0
  82. package/dist/registry/asset-storage/define.d.ts +5 -5
  83. package/dist/registry/asset-storage/define.js +4 -4
  84. package/dist/registry/asset-storage/resolve.d.ts +9 -19
  85. package/dist/registry/asset-storage/resolve.js +33 -21
  86. package/dist/registry/asset-storage/types.d.ts +37 -17
  87. package/dist/registry/asset-storage/types.js +5 -5
  88. package/dist/registry/auth/ai-keys.d.ts +32 -0
  89. package/dist/registry/auth/ai-keys.js +69 -0
  90. package/dist/registry/auth/crypto.d.ts +17 -0
  91. package/dist/registry/auth/crypto.js +61 -1
  92. package/dist/registry/auth/index.d.ts +2 -1
  93. package/dist/registry/auth/index.js +11 -2
  94. package/dist/registry/checkout/index.d.ts +2 -1
  95. package/dist/registry/checkout/index.js +57 -127
  96. package/dist/registry/client.js +53 -17
  97. package/dist/registry/db/driver.js +3 -3
  98. package/dist/registry/db/schema.d.ts +261 -3
  99. package/dist/registry/db/schema.js +29 -4
  100. package/dist/registry/email/define.d.ts +10 -0
  101. package/dist/registry/email/define.js +13 -0
  102. package/dist/registry/email/providers/smtp.d.ts +10 -0
  103. package/dist/registry/email/providers/smtp.js +73 -0
  104. package/dist/registry/email/resolve.d.ts +28 -0
  105. package/dist/registry/email/resolve.js +74 -0
  106. package/dist/registry/email/types.d.ts +24 -0
  107. package/dist/registry/email/types.js +6 -0
  108. package/dist/registry/path.d.ts +2 -0
  109. package/dist/registry/path.js +11 -1
  110. package/dist/registry/publish/package.js +8 -0
  111. package/dist/registry/transfer.d.ts +4 -0
  112. package/dist/store/registry.d.ts +3 -3
  113. package/dist/store/registry.js +4 -4
  114. package/dist/transformers/preview/component/builder.d.ts +1 -9
  115. package/dist/transformers/preview/component/builder.js +17 -17
  116. package/dist/transformers/preview/component/css.d.ts +2 -1
  117. package/dist/transformers/preview/component/css.js +8 -5
  118. package/dist/transformers/preview/component/html.d.ts +3 -1
  119. package/dist/transformers/preview/component/html.js +6 -2
  120. package/dist/transformers/preview/component/javascript.d.ts +2 -1
  121. package/dist/transformers/preview/component/javascript.js +10 -4
  122. package/dist/transformers/utils/build.d.ts +5 -0
  123. package/dist/transformers/utils/build.js +21 -4
  124. package/dist/types/config.d.ts +129 -18
  125. package/dist/utils/path.d.ts +1 -5
  126. package/dist/utils/path.js +6 -23
  127. package/docs/api.md +6 -4
  128. package/docs/cli.md +275 -54
  129. package/drizzle/0007_add_ai_keys.sql +11 -0
  130. package/drizzle/0008_add_source_dir.sql +2 -0
  131. package/drizzle/meta/0007_snapshot.json +2013 -0
  132. package/drizzle/meta/0008_snapshot.json +2025 -0
  133. package/drizzle/meta/_journal.json +14 -0
  134. package/package.json +19 -8
  135. package/src/ai/README.md +42 -0
  136. package/src/ai/connections.ts +189 -0
  137. package/src/ai/define.ts +15 -0
  138. package/src/ai/types.ts +30 -0
  139. package/src/app/components/AiAssistant/AiAssistantPanel.tsx +144 -0
  140. package/src/app/components/AiAssistant/AiAssistantProvider.tsx +215 -0
  141. package/src/app/components/AiAssistant/AiConversation.tsx +737 -0
  142. package/src/app/components/AiAssistant/AiToolResult.tsx +99 -0
  143. package/src/app/components/AiAssistant/dockState.ts +86 -0
  144. package/src/app/components/AiAssistant/toolLabel.ts +24 -0
  145. package/src/app/components/AiAssistant/useAiChat.ts +147 -0
  146. package/src/app/components/AiAssistant/useAiConnections.ts +86 -0
  147. package/src/app/components/AiAssistant/usePageContext.ts +63 -0
  148. package/src/app/components/Auth/AccountLayout.tsx +58 -19
  149. package/src/app/components/Auth/AuthShell.tsx +27 -33
  150. package/src/app/components/Auth/RegistryInstallGate.tsx +4 -8
  151. package/src/app/components/Auth/installStatus.ts +29 -0
  152. package/src/app/components/Component/Preview.tsx +5 -2
  153. package/src/app/components/Foundations/ColorGrid.tsx +13 -14
  154. package/src/app/components/Layout/Header.tsx +21 -15
  155. package/src/app/components/Layout/Main.tsx +2 -2
  156. package/src/app/components/Markdown/MarkdownComponents.tsx +30 -32
  157. package/src/app/components/McpIntegration/McpConfigDialog.tsx +12 -51
  158. package/src/app/components/Navigation/MobileNav.tsx +2 -2
  159. package/src/app/components/Navigation/SideNav.tsx +1 -15
  160. package/src/app/components/context/NavProvider.tsx +7 -3
  161. package/src/app/components/ui/attachment.tsx +50 -0
  162. package/src/app/components/ui/bubble.tsx +57 -0
  163. package/src/app/components/ui/button.tsx +3 -1
  164. package/src/app/components/ui/confirm-dialog.tsx +87 -0
  165. package/src/app/components/ui/dialog.tsx +7 -2
  166. package/src/app/components/ui/marker.tsx +56 -0
  167. package/src/app/components/ui/sidebar.tsx +3 -1
  168. package/src/app/components/util/index.ts +3 -12
  169. package/src/app/css/index.css +64 -0
  170. package/src/app/lib/ai/auth.ts +33 -0
  171. package/src/app/lib/ai/context.ts +99 -0
  172. package/src/app/lib/ai/model.ts +79 -0
  173. package/src/app/lib/ai/prompt.ts +36 -0
  174. package/src/app/lib/ai/resolve.ts +97 -0
  175. package/src/app/lib/ai/tools.ts +120 -0
  176. package/src/app/lib/api/methods.ts +13 -0
  177. package/src/app/lib/asset-storage.ts +35 -36
  178. package/src/app/lib/auth/api.ts +4 -12
  179. package/src/app/lib/auth/email.ts +96 -23
  180. package/src/app/lib/docs-api/page-rendering.ts +1 -1
  181. package/src/app/lib/docs-api/registry.ts +2 -3
  182. package/src/app/lib/docs-api/runtime-config.ts +47 -21
  183. package/src/app/lib/mcp/components.ts +523 -0
  184. package/src/app/lib/mcp/page-url.ts +24 -0
  185. package/src/app/lib/mcp/pages.ts +84 -0
  186. package/src/app/lib/mcp/result.ts +33 -0
  187. package/src/app/lib/mcp/server.ts +39 -318
  188. package/src/app/lib/mcp/tokens.ts +334 -0
  189. package/src/app/lib/mcp/tool.ts +19 -0
  190. package/src/app/lib/registry-api/asset-transfer.ts +119 -11
  191. package/src/app/lib/registry-api/errors.ts +2 -0
  192. package/src/app/lib/registry-api/handler.ts +7 -1
  193. package/src/app/lib/registry-api/transfer.ts +28 -6
  194. package/src/app/lib/server-module.ts +34 -0
  195. package/src/app/lib/utils.ts +20 -0
  196. package/src/app/next.config.mjs +26 -24
  197. package/src/app/pages/[...slug]/index.tsx +2 -1
  198. package/src/app/pages/_app.tsx +6 -2
  199. package/src/app/pages/_document.tsx +6 -0
  200. package/src/app/pages/account/ai.tsx +183 -0
  201. package/src/app/pages/account/index.tsx +68 -68
  202. package/src/app/pages/account/tokens.tsx +37 -7
  203. package/src/app/pages/account/users.tsx +75 -15
  204. package/src/app/pages/api/account/ai/keys/[connectionId].ts +60 -0
  205. package/src/app/pages/api/account/ai/keys/index.ts +20 -0
  206. package/src/app/pages/api/admin/users/[id]/[action].ts +80 -11
  207. package/src/app/pages/api/admin/users/index.ts +2 -2
  208. package/src/app/pages/api/ai/chat.ts +115 -0
  209. package/src/app/pages/api/ai/connections.ts +23 -0
  210. package/src/app/pages/api/auth/request-reset.ts +14 -16
  211. package/src/app/pages/api/docs/nav.json.ts +1 -1
  212. package/src/app/pages/api/install.ts +3 -3
  213. package/src/app/pages/api/mcp.ts +6 -0
  214. package/src/app/pages/api/registry/transfer/assets/blobs/[hash]/complete.ts +11 -0
  215. package/src/app/pages/api/registry/transfer/assets/blobs/[hash]/upload.ts +12 -0
  216. package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +1 -1
  217. package/src/app/pages/cli/device.tsx +10 -5
  218. package/src/app/pages/foundations/colors.tsx +9 -8
  219. package/src/app/pages/foundations/index.tsx +3 -3
  220. package/src/app/pages/index.tsx +2 -2
  221. package/src/app/pages/install.tsx +7 -2
  222. package/src/app/pages/login.tsx +32 -27
  223. package/src/app/pages/reset-password.tsx +21 -20
  224. package/src/app/pages/system/component/[component]/index.tsx +2 -5
  225. package/src/app/pages/system/index.tsx +11 -11
  226. package/src/app/pages/system/pattern/[pattern]/index.tsx +2 -2
  227. package/src/app/pages/system/tokens/components/[component]/index.tsx +0 -4
  228. package/src/app-builder/README.md +2 -1
  229. package/src/app-builder/build.ts +218 -73
  230. package/src/app-builder/client-config.ts +3 -2
  231. package/src/app-builder/paths.ts +3 -22
  232. package/src/app-builder/static-export.ts +1 -1
  233. package/src/app-builder/vercel-output.ts +5 -4
  234. package/src/cache/README.md +4 -1
  235. package/src/cache/build-cache.ts +128 -43
  236. package/src/cache/build-inputs.ts +28 -0
  237. package/src/cache/index.ts +4 -0
  238. package/src/cli/create.ts +1 -2
  239. package/src/commands/build/index.ts +1 -1
  240. package/src/config/README.md +10 -9
  241. package/src/config/defaults.ts +7 -4
  242. package/src/config/from-env.ts +33 -0
  243. package/src/config/helpers.ts +1 -3
  244. package/src/config/index.ts +0 -3
  245. package/src/config/loader.ts +25 -3
  246. package/src/config/resolve-env.ts +28 -15
  247. package/src/config/runtime.ts +1 -1
  248. package/src/index.ts +33 -29
  249. package/src/nav/index.ts +2 -2
  250. package/src/nav/registry.ts +3 -3
  251. package/src/nav/workspace.ts +3 -3
  252. package/src/pipeline/README.md +1 -1
  253. package/src/pipeline/figma.ts +98 -49
  254. package/src/pipeline/styles.ts +1 -1
  255. package/src/pipeline/validation.ts +3 -3
  256. package/src/providers.ts +18 -0
  257. package/src/registry/asset-storage/define.ts +6 -6
  258. package/src/registry/asset-storage/resolve.ts +38 -37
  259. package/src/registry/asset-storage/types.ts +39 -17
  260. package/src/registry/auth/ai-keys.ts +62 -0
  261. package/src/registry/auth/crypto.ts +63 -1
  262. package/src/registry/auth/index.ts +11 -1
  263. package/src/registry/checkout/index.ts +60 -138
  264. package/src/registry/client.ts +60 -20
  265. package/src/registry/db/driver.ts +2 -2
  266. package/src/registry/db/schema.ts +49 -22
  267. package/src/registry/email/define.ts +15 -0
  268. package/src/registry/email/providers/smtp.ts +39 -0
  269. package/src/registry/email/resolve.ts +94 -0
  270. package/src/registry/email/types.ts +28 -0
  271. package/src/registry/path.ts +11 -0
  272. package/src/registry/publish/package.ts +9 -0
  273. package/src/registry/transfer.ts +4 -0
  274. package/src/store/registry.ts +7 -7
  275. package/src/transformers/preview/component/builder.ts +19 -25
  276. package/src/transformers/preview/component/css.ts +9 -4
  277. package/src/transformers/preview/component/html.ts +6 -2
  278. package/src/transformers/preview/component/javascript.ts +14 -4
  279. package/src/transformers/utils/build.ts +16 -3
  280. package/src/types/config.ts +142 -20
  281. package/src/utils/README.md +1 -1
  282. package/src/utils/path.ts +6 -29
  283. package/templates/default/handoff.config.js.tpl +10 -2
  284. package/templates/default/handoff.config.ts.tpl +10 -2
  285. package/templates/default/handoff.config.with-examples.js.tpl +10 -2
  286. package/templates/default/handoff.config.with-examples.ts.tpl +10 -2
  287. package/templates/default/package.json.tpl +2 -2
  288. package/.editorconfig +0 -19
  289. package/.eslintrc.json +0 -4
  290. package/.prettierignore +0 -0
  291. package/.prettierrc.json +0 -8
  292. package/.vscode/settings.json +0 -17
  293. package/dist/config/validator.d.ts +0 -9
  294. package/dist/config/validator.js +0 -24
  295. package/dist/registry/asset-storage/adapters/vercel-blob.d.ts +0 -17
  296. package/dist/registry/asset-storage/adapters/vercel-blob.js +0 -87
  297. package/src/app/components/old/Header.tsx +0 -89
  298. package/src/app/lib/mcp/shape.ts +0 -596
  299. package/src/app/pages/assets/fonts.tsx +0 -129
  300. package/src/app/pages/assets/index.tsx +0 -91
  301. package/src/app/pages/assets/logos.tsx +0 -75
  302. package/src/config/validator.ts +0 -22
  303. package/src/registry/asset-storage/adapters/vercel-blob.ts +0 -51
@@ -2,44 +2,34 @@
2
2
  * Asset storage settings resolution.
3
3
  *
4
4
  * `runtime.registry.assetStorage` selects the active provider for **new** uploads: the built-in
5
- * `database` inline default, the pre-packaged `vercel-blob` adapter, or a `custom` module. Mirrors
6
- * {@link import('../db/driver')}: only provider selection, module location, non-secret options, and
7
- * env-var *names* are ever persisted; secret *values* are read from `process.env` at request time.
5
+ * `database` inline default or a `custom` module. The build bakes the provider, the module location,
6
+ * and the options. An option literal is baked as it is. An environment reference stays `{ $env }`
7
+ * and is resolved at request time, before the custom provider factory runs.
8
8
  */
9
9
  import type { ResolvedConfig } from '../../types/config';
10
10
  import type { AssetStorageProvider } from '../db/schema';
11
- /** Which adapter implementation is active. */
12
- export type AssetStorageAdapterKind = 'database' | 'vercel-blob' | 'custom';
13
11
  /** The raw, authored settings block (a structural copy of the config type, resolvable from bake). */
14
12
  export interface AssetStorageSettings {
15
- adapter?: AssetStorageAdapterKind;
13
+ provider?: AssetStorageProvider;
16
14
  module?: string;
17
- tokenEnv?: string;
18
15
  maxInlineBytes?: number;
19
16
  options?: Record<string, unknown>;
20
17
  }
21
- /** Default adapter when none is configured. */
22
- export declare const DEFAULT_ASSET_STORAGE_ADAPTER: AssetStorageAdapterKind;
23
- /** Default env-var name holding the Vercel Blob read/write token. */
24
- export declare const DEFAULT_BLOB_TOKEN_ENV = "BLOB_READ_WRITE_TOKEN";
18
+ export declare const DEFAULT_ASSET_STORAGE_PROVIDER: AssetStorageProvider;
25
19
  /** Default max bytes kept inline in Postgres `bytea` (4 MB, under Vercel's ~4.5 MB function limit). */
26
20
  export declare const DEFAULT_MAX_INLINE_BYTES: number;
27
21
  /** Fully resolved asset storage settings. */
28
22
  export interface ResolvedAssetStorage {
29
- /** The active adapter implementation. */
30
- adapterKind: AssetStorageAdapterKind;
31
- /** Provider id recorded on blob rows written by the active adapter (drives read resolution). */
23
+ /** Recorded on each new blob row as its storage provider. */
32
24
  provider: AssetStorageProvider;
33
- /** For `custom`: the server-only adapter module path. */
25
+ /** For `custom`: the server-only provider module path. */
34
26
  module?: string;
35
- /** For `vercel-blob`: the env-var name holding the token. */
36
- tokenEnv: string;
37
27
  /** For `database`: the inline-content size ceiling. */
38
28
  maxInlineBytes: number;
39
- /** Non-secret adapter options. */
29
+ /** Provider options: literals and `{ $env }` references, never secret values. */
40
30
  options: Record<string, unknown>;
41
31
  }
42
32
  /** Resolve raw asset storage settings into a fully-defaulted shape. */
43
33
  export declare const resolveAssetStorageSettings: (settings: AssetStorageSettings | null | undefined) => ResolvedAssetStorage;
44
- /** Resolve the active asset storage settings from a loaded config (CLI/build side). */
34
+ /** Resolve and validate the asset storage block from a loaded config (CLI/build side). An unusable block fails the build. */
45
35
  export declare const resolveAssetStorageFromConfig: (config: ResolvedConfig | null | undefined) => ResolvedAssetStorage;
@@ -3,37 +3,49 @@
3
3
  * Asset storage settings resolution.
4
4
  *
5
5
  * `runtime.registry.assetStorage` selects the active provider for **new** uploads: the built-in
6
- * `database` inline default, the pre-packaged `vercel-blob` adapter, or a `custom` module. Mirrors
7
- * {@link import('../db/driver')}: only provider selection, module location, non-secret options, and
8
- * env-var *names* are ever persisted; secret *values* are read from `process.env` at request time.
6
+ * `database` inline default or a `custom` module. The build bakes the provider, the module location,
7
+ * and the options. An option literal is baked as it is. An environment reference stays `{ $env }`
8
+ * and is resolved at request time, before the custom provider factory runs.
9
9
  */
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.resolveAssetStorageFromConfig = exports.resolveAssetStorageSettings = exports.DEFAULT_MAX_INLINE_BYTES = exports.DEFAULT_BLOB_TOKEN_ENV = exports.DEFAULT_ASSET_STORAGE_ADAPTER = void 0;
12
- /** Default adapter when none is configured. */
13
- exports.DEFAULT_ASSET_STORAGE_ADAPTER = 'database';
14
- /** Default env-var name holding the Vercel Blob read/write token. */
15
- exports.DEFAULT_BLOB_TOKEN_ENV = 'BLOB_READ_WRITE_TOKEN';
11
+ exports.resolveAssetStorageFromConfig = exports.resolveAssetStorageSettings = exports.DEFAULT_MAX_INLINE_BYTES = exports.DEFAULT_ASSET_STORAGE_PROVIDER = void 0;
12
+ const errors_1 = require("../../config/errors");
13
+ const PROVIDERS = ['database', 'custom'];
14
+ exports.DEFAULT_ASSET_STORAGE_PROVIDER = 'database';
16
15
  /** Default max bytes kept inline in Postgres `bytea` (4 MB, under Vercel's ~4.5 MB function limit). */
17
16
  exports.DEFAULT_MAX_INLINE_BYTES = 4 * 1024 * 1024;
18
- /** The stable provider id recorded on blobs for a custom adapter (single custom provider at a time). */
19
- const customProviderId = (options) => {
20
- const id = typeof options.providerId === 'string' && options.providerId.trim() ? options.providerId.trim() : 'custom';
21
- return id;
22
- };
23
17
  /** Resolve raw asset storage settings into a fully-defaulted shape. */
24
18
  const resolveAssetStorageSettings = (settings) => {
25
- var _a, _b, _c, _d;
26
- const adapterKind = (_a = settings === null || settings === void 0 ? void 0 : settings.adapter) !== null && _a !== void 0 ? _a : exports.DEFAULT_ASSET_STORAGE_ADAPTER;
19
+ var _a, _b, _c;
20
+ const provider = (_a = settings === null || settings === void 0 ? void 0 : settings.provider) !== null && _a !== void 0 ? _a : exports.DEFAULT_ASSET_STORAGE_PROVIDER;
27
21
  const options = (_b = settings === null || settings === void 0 ? void 0 : settings.options) !== null && _b !== void 0 ? _b : {};
28
- const tokenEnv = ((_c = settings === null || settings === void 0 ? void 0 : settings.tokenEnv) === null || _c === void 0 ? void 0 : _c.trim()) || exports.DEFAULT_BLOB_TOKEN_ENV;
29
22
  const maxInlineBytes = typeof (settings === null || settings === void 0 ? void 0 : settings.maxInlineBytes) === 'number' && settings.maxInlineBytes > 0 ? settings.maxInlineBytes : exports.DEFAULT_MAX_INLINE_BYTES;
30
- const provider = adapterKind === 'vercel-blob' ? 'vercel-blob' : adapterKind === 'custom' ? customProviderId(options) : 'database';
31
- return { adapterKind, provider, module: ((_d = settings === null || settings === void 0 ? void 0 : settings.module) === null || _d === void 0 ? void 0 : _d.trim()) || undefined, tokenEnv, maxInlineBytes, options };
23
+ return { provider, module: ((_c = settings === null || settings === void 0 ? void 0 : settings.module) === null || _c === void 0 ? void 0 : _c.trim()) || undefined, maxInlineBytes, options };
32
24
  };
33
25
  exports.resolveAssetStorageSettings = resolveAssetStorageSettings;
34
- /** Resolve the active asset storage settings from a loaded config (CLI/build side). */
26
+ /** Resolve and validate the asset storage block from a loaded config (CLI/build side). An unusable block fails the build. */
35
27
  const resolveAssetStorageFromConfig = (config) => {
36
- var _a, _b, _c, _d, _e, _f;
37
- return (0, exports.resolveAssetStorageSettings)(Object.assign(Object.assign({}, (_b = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.registry) === null || _b === void 0 ? void 0 : _b.assetStorage), { tokenEnv: (_f = (_e = (_d = (_c = config === null || config === void 0 ? void 0 : config.runtime) === null || _c === void 0 ? void 0 : _c.registry) === null || _d === void 0 ? void 0 : _d.assetStorage) === null || _e === void 0 ? void 0 : _e.token) === null || _f === void 0 ? void 0 : _f.$env }));
28
+ var _a, _b, _c;
29
+ const settings = (_b = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.registry) === null || _b === void 0 ? void 0 : _b.assetStorage;
30
+ const fail = (problem) => {
31
+ throw new errors_1.HandoffConfigError(`Config "runtime.registry.assetStorage": ${problem}`);
32
+ };
33
+ const provider = (_c = settings === null || settings === void 0 ? void 0 : settings.provider) !== null && _c !== void 0 ? _c : exports.DEFAULT_ASSET_STORAGE_PROVIDER;
34
+ if (!PROVIDERS.includes(provider)) {
35
+ fail(`unknown provider ${JSON.stringify(provider)}. Use "database" or "custom".`);
36
+ }
37
+ const options = settings === null || settings === void 0 ? void 0 : settings.options;
38
+ if (options !== undefined && (options === null || typeof options !== 'object' || Array.isArray(options))) {
39
+ fail('"options" must be an object.');
40
+ }
41
+ const module = settings === null || settings === void 0 ? void 0 : settings.module;
42
+ if (provider === 'custom' && (typeof module !== 'string' || !module.trim())) {
43
+ fail('provider "custom" needs a "module" that default-exports a defineStorageProvider() result.');
44
+ }
45
+ const maxInlineBytes = settings === null || settings === void 0 ? void 0 : settings.maxInlineBytes;
46
+ if (maxInlineBytes !== undefined && (typeof maxInlineBytes !== 'number' || !Number.isInteger(maxInlineBytes) || maxInlineBytes <= 0)) {
47
+ fail('"maxInlineBytes" must be a positive whole number.');
48
+ }
49
+ return (0, exports.resolveAssetStorageSettings)(settings);
38
50
  };
39
51
  exports.resolveAssetStorageFromConfig = resolveAssetStorageFromConfig;
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Server-only asset storage contract for object-backed providers (Vercel Blob + custom
3
- * {@link defineAssetStorage} modules), so callers need no provider-specific logic. The built-in
4
- * `database` provider is the inline default: bytes live in the `asset_blobs.content` bytea column,
5
- * read/written directly by the registry, so it needs no adapter. Object providers record a
6
- * `storageRef` + provider id so reads resolve back through whichever provider stored the blob.
2
+ * Server-only asset storage contract for custom {@link defineStorageProvider} object storage modules.
3
+ * The built-in `database` provider is the inline default: bytes live in the `asset_blobs.content`
4
+ * bytea column, read/written directly by the registry, so it needs no module. Object providers
5
+ * record a `storageRef` + provider id so reads resolve back through whichever provider stored the
6
+ * blob.
7
7
  */
8
8
  /** Input for storing one content-addressed blob. */
9
- export interface AssetStorageInput {
9
+ export interface StorageInput {
10
10
  /** SHA-256 of the bytes (hex), the content identity, usable as a stable object key. */
11
11
  hash: string;
12
12
  bytes: Buffer;
@@ -17,7 +17,7 @@ export interface AssetStorageInput {
17
17
  * How a provider returns stored content: raw bytes, a readable stream, or a signed/redirect URL the
18
18
  * client can fetch directly (used to avoid routing large payloads through the serverless function).
19
19
  */
20
- export type AssetStorageReadResult = {
20
+ export type StorageReadResult = {
21
21
  kind: 'bytes';
22
22
  bytes: Buffer;
23
23
  contentType?: string;
@@ -29,23 +29,43 @@ export type AssetStorageReadResult = {
29
29
  kind: 'redirect';
30
30
  url: string;
31
31
  };
32
- /** The pluggable storage adapter contract for object-backed asset providers. */
33
- export interface AssetStorage {
32
+ /** Input for a direct upload of one blob from the CLI to storage. */
33
+ export interface AssetUploadInput {
34
+ /** SHA-256 of the bytes (hex). */
35
+ hash: string;
36
+ size: number;
37
+ contentType: string;
38
+ }
39
+ /** A signed URL the CLI sends the blob to with `PUT` and the given headers. */
40
+ export interface AssetUpload {
41
+ url: string;
42
+ headers?: Record<string, string>;
43
+ /** The reference to persist on the blob's `asset_blobs` row after the upload. */
44
+ storageRef: string;
45
+ }
46
+ /** The pluggable storage contract for object-backed asset providers. */
47
+ export interface StorageProvider {
34
48
  /** Store one blob and return the reference to persist on its `asset_blobs` row. */
35
- put(input: AssetStorageInput): Promise<{
49
+ put(input: StorageInput): Promise<{
36
50
  storageRef: string;
37
51
  }>;
52
+ /**
53
+ * Return a signed URL so the CLI uploads the blob directly to storage instead of through the
54
+ * registry, which avoids serverless request size limits. The URL must make storage reject bytes
55
+ * that do not match `hash`, for example with a signed SHA-256 checksum header.
56
+ */
57
+ createUpload?(input: AssetUploadInput): Promise<AssetUpload>;
38
58
  /** Resolve stored content by its `storageRef`. */
39
- get(storageRef: string): Promise<AssetStorageReadResult>;
59
+ get(storageRef: string): Promise<StorageReadResult>;
40
60
  /** Delete stored content by its `storageRef`. Should be retryable/idempotent. */
41
61
  delete(storageRef: string): Promise<void>;
42
62
  }
43
- /** Context passed to a custom adapter factory: its non-secret config options + the process env. */
44
- export interface AssetStorageContext {
45
- /** Non-secret options from `runtime.registry.assetStorage.options` (bucket env-var names, region, …). */
63
+ /** Context passed to a custom provider factory: its config options and the process env. */
64
+ export interface StorageProviderContext {
65
+ /** `runtime.registry.assetStorage.options`, with each `fromEnv()` reference replaced by its value. */
46
66
  options: Record<string, unknown>;
47
- /** The process environment. Read secret *values* here by the env-var *names* carried in options. */
67
+ /** The process environment. */
48
68
  env: NodeJS.ProcessEnv;
49
69
  }
50
- /** A custom adapter may export the adapter directly or a factory that builds it from its context. */
51
- export type AssetStorageFactory = (context: AssetStorageContext) => AssetStorage | Promise<AssetStorage>;
70
+ /** A custom provider module may export the provider directly or a factory that builds it from its context. */
71
+ export type StorageProviderFactory = (context: StorageProviderContext) => StorageProvider | Promise<StorageProvider>;
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  /**
3
- * Server-only asset storage contract for object-backed providers (Vercel Blob + custom
4
- * {@link defineAssetStorage} modules), so callers need no provider-specific logic. The built-in
5
- * `database` provider is the inline default: bytes live in the `asset_blobs.content` bytea column,
6
- * read/written directly by the registry, so it needs no adapter. Object providers record a
7
- * `storageRef` + provider id so reads resolve back through whichever provider stored the blob.
3
+ * Server-only asset storage contract for custom {@link defineStorageProvider} object storage modules.
4
+ * The built-in `database` provider is the inline default: bytes live in the `asset_blobs.content`
5
+ * bytea column, read/written directly by the registry, so it needs no module. Object providers
6
+ * record a `storageRef` + provider id so reads resolve back through whichever provider stored the
7
+ * blob.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,32 @@
1
+ import type { RegistryDatabase } from '../db/client';
2
+ /**
3
+ * Reader-supplied keys for connections the config declares with `credential: 'user'`.
4
+ *
5
+ * The key is write-only across the API boundary: once saved, a read reports only that a key exists.
6
+ * Only the chat route ever decrypts one, and only to send it to the connection's own endpoint.
7
+ */
8
+ /**
9
+ * Ids of the connections this reader has a *usable* key for. A row that no longer decrypts — written
10
+ * under a rotated `HANDOFF_AI_KEY_SECRET` — is left out, so the account page and the assistant agree
11
+ * that no key is in place instead of offering a key the provider would never receive.
12
+ */
13
+ export declare const listRegistryAiKeyConnections: (db: RegistryDatabase, userId: string) => Promise<string[]>;
14
+ /** Save or replace this reader's key for one connection. */
15
+ export declare const saveRegistryAiKey: (db: RegistryDatabase, input: {
16
+ userId: string;
17
+ connectionId: string;
18
+ key: string;
19
+ }) => Promise<void>;
20
+ /** Remove this reader's key for one connection. Returns whether a row was there to remove. */
21
+ export declare const deleteRegistryAiKey: (db: RegistryDatabase, input: {
22
+ userId: string;
23
+ connectionId: string;
24
+ }) => Promise<boolean>;
25
+ /**
26
+ * Read back one reader's key. A row that no longer decrypts reads as absent, so the reader is told
27
+ * to add a key rather than shown a provider error.
28
+ */
29
+ export declare const readRegistryAiKey: (db: RegistryDatabase, input: {
30
+ userId: string;
31
+ connectionId: string;
32
+ }) => Promise<string | null>;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.readRegistryAiKey = exports.deleteRegistryAiKey = exports.saveRegistryAiKey = exports.listRegistryAiKeyConnections = void 0;
13
+ const drizzle_orm_1 = require("drizzle-orm");
14
+ const schema_1 = require("../db/schema");
15
+ const crypto_1 = require("./crypto");
16
+ /**
17
+ * Reader-supplied keys for connections the config declares with `credential: 'user'`.
18
+ *
19
+ * The key is write-only across the API boundary: once saved, a read reports only that a key exists.
20
+ * Only the chat route ever decrypts one, and only to send it to the connection's own endpoint.
21
+ */
22
+ /**
23
+ * Ids of the connections this reader has a *usable* key for. A row that no longer decrypts — written
24
+ * under a rotated `HANDOFF_AI_KEY_SECRET` — is left out, so the account page and the assistant agree
25
+ * that no key is in place instead of offering a key the provider would never receive.
26
+ */
27
+ const listRegistryAiKeyConnections = (db, userId) => __awaiter(void 0, void 0, void 0, function* () {
28
+ const rows = yield db
29
+ .select({ connectionId: schema_1.registryAiKeys.connectionId, encryptedKey: schema_1.registryAiKeys.encryptedKey })
30
+ .from(schema_1.registryAiKeys)
31
+ .where((0, drizzle_orm_1.eq)(schema_1.registryAiKeys.userId, userId))
32
+ .orderBy(schema_1.registryAiKeys.connectionId);
33
+ return rows.filter((row) => (0, crypto_1.decryptSecret)(row.encryptedKey) !== null).map((row) => row.connectionId);
34
+ });
35
+ exports.listRegistryAiKeyConnections = listRegistryAiKeyConnections;
36
+ /** Save or replace this reader's key for one connection. */
37
+ const saveRegistryAiKey = (db, input) => __awaiter(void 0, void 0, void 0, function* () {
38
+ const encryptedKey = (0, crypto_1.encryptSecret)(input.key);
39
+ yield db
40
+ .insert(schema_1.registryAiKeys)
41
+ .values({ userId: input.userId, connectionId: input.connectionId, encryptedKey })
42
+ .onConflictDoUpdate({
43
+ target: [schema_1.registryAiKeys.userId, schema_1.registryAiKeys.connectionId],
44
+ set: { encryptedKey, updatedAt: new Date() },
45
+ });
46
+ });
47
+ exports.saveRegistryAiKey = saveRegistryAiKey;
48
+ /** Remove this reader's key for one connection. Returns whether a row was there to remove. */
49
+ const deleteRegistryAiKey = (db, input) => __awaiter(void 0, void 0, void 0, function* () {
50
+ const rows = yield db
51
+ .delete(schema_1.registryAiKeys)
52
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(schema_1.registryAiKeys.userId, input.userId), (0, drizzle_orm_1.eq)(schema_1.registryAiKeys.connectionId, input.connectionId)))
53
+ .returning({ connectionId: schema_1.registryAiKeys.connectionId });
54
+ return rows.length > 0;
55
+ });
56
+ exports.deleteRegistryAiKey = deleteRegistryAiKey;
57
+ /**
58
+ * Read back one reader's key. A row that no longer decrypts reads as absent, so the reader is told
59
+ * to add a key rather than shown a provider error.
60
+ */
61
+ const readRegistryAiKey = (db, input) => __awaiter(void 0, void 0, void 0, function* () {
62
+ const [row] = yield db
63
+ .select({ encryptedKey: schema_1.registryAiKeys.encryptedKey })
64
+ .from(schema_1.registryAiKeys)
65
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(schema_1.registryAiKeys.userId, input.userId), (0, drizzle_orm_1.eq)(schema_1.registryAiKeys.connectionId, input.connectionId)))
66
+ .limit(1);
67
+ return row ? (0, crypto_1.decryptSecret)(row.encryptedKey) : null;
68
+ });
69
+ exports.readRegistryAiKey = readRegistryAiKey;
@@ -2,3 +2,20 @@ export declare const hashSecret: (secret: string) => string;
2
2
  export declare const createOpaqueSecret: (byteLength?: number) => string;
3
3
  export declare const secretHashMatches: (secret: string, expectedHash: string) => boolean;
4
4
  export declare const normalizeEmail: (email: string) => string;
5
+ /** Env var holding the deployment secret that reader-supplied AI keys are encrypted with. */
6
+ export declare const AI_KEY_SECRET_ENV = "HANDOFF_AI_KEY_SECRET";
7
+ /** Thrown when a key must be encrypted but the deployment secret is missing or too short. */
8
+ export declare class MissingEncryptionSecretError extends Error {
9
+ constructor();
10
+ }
11
+ /**
12
+ * Encrypt a value that has to be read back, such as a reader's provider key. AES-256-GCM, with the
13
+ * salt, nonce and authentication tag carried in the payload so a row is self-describing.
14
+ */
15
+ export declare const encryptSecret: (plaintext: string) => string;
16
+ /**
17
+ * Decrypt a value written by {@link encryptSecret}. Returns `null` for anything that does not
18
+ * authenticate — a payload in another format, or one written under a secret that has since been
19
+ * rotated — so a stale row reads as "no key saved" instead of failing the request.
20
+ */
21
+ export declare const decryptSecret: (payload: string) => string | null;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizeEmail = exports.secretHashMatches = exports.createOpaqueSecret = exports.hashSecret = void 0;
3
+ exports.decryptSecret = exports.encryptSecret = exports.MissingEncryptionSecretError = exports.AI_KEY_SECRET_ENV = exports.normalizeEmail = exports.secretHashMatches = exports.createOpaqueSecret = exports.hashSecret = void 0;
4
4
  const node_crypto_1 = require("node:crypto");
5
5
  const hashSecret = (secret) => (0, node_crypto_1.createHash)('sha256').update(secret, 'utf8').digest('hex');
6
6
  exports.hashSecret = hashSecret;
@@ -14,3 +14,63 @@ const secretHashMatches = (secret, expectedHash) => {
14
14
  exports.secretHashMatches = secretHashMatches;
15
15
  const normalizeEmail = (email) => email.trim().toLowerCase();
16
16
  exports.normalizeEmail = normalizeEmail;
17
+ /** Env var holding the deployment secret that reader-supplied AI keys are encrypted with. */
18
+ exports.AI_KEY_SECRET_ENV = 'HANDOFF_AI_KEY_SECRET';
19
+ /** Shortest secret worth accepting. Matches the guidance the installer gives for `AUTH_SECRET`. */
20
+ const MIN_KEY_SECRET_LENGTH = 32;
21
+ /** Format marker, so a later algorithm is distinguishable from this one rather than guessed at. */
22
+ const ENCRYPTED_SECRET_VERSION = 'v1';
23
+ /** Thrown when a key must be encrypted but the deployment secret is missing or too short. */
24
+ class MissingEncryptionSecretError extends Error {
25
+ constructor() {
26
+ super(`Reader-supplied AI keys cannot be stored because ${exports.AI_KEY_SECRET_ENV} is not set. Set it to a ` +
27
+ `random value of at least ${MIN_KEY_SECRET_LENGTH} characters, or declare no connection with ` +
28
+ `"credential: 'user'".`);
29
+ this.name = 'MissingEncryptionSecretError';
30
+ }
31
+ }
32
+ exports.MissingEncryptionSecretError = MissingEncryptionSecretError;
33
+ /**
34
+ * Derive the record key. A per-record salt means two rows holding the same provider key produce
35
+ * different ciphertexts, and the fixed `info` label keeps this key distinct from anything else the
36
+ * same secret is ever used for.
37
+ */
38
+ const deriveKey = (salt) => {
39
+ var _a;
40
+ const secret = (_a = process.env[exports.AI_KEY_SECRET_ENV]) === null || _a === void 0 ? void 0 : _a.trim();
41
+ if (!secret || secret.length < MIN_KEY_SECRET_LENGTH)
42
+ throw new MissingEncryptionSecretError();
43
+ return Buffer.from((0, node_crypto_1.hkdfSync)('sha256', Buffer.from(secret, 'utf8'), salt, 'handoff-ai-key', 32));
44
+ };
45
+ /**
46
+ * Encrypt a value that has to be read back, such as a reader's provider key. AES-256-GCM, with the
47
+ * salt, nonce and authentication tag carried in the payload so a row is self-describing.
48
+ */
49
+ const encryptSecret = (plaintext) => {
50
+ const salt = (0, node_crypto_1.randomBytes)(16);
51
+ const iv = (0, node_crypto_1.randomBytes)(12);
52
+ const cipher = (0, node_crypto_1.createCipheriv)('aes-256-gcm', deriveKey(salt), iv);
53
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
54
+ const parts = [salt, iv, cipher.getAuthTag(), encrypted].map((part) => part.toString('base64url'));
55
+ return [ENCRYPTED_SECRET_VERSION, ...parts].join('.');
56
+ };
57
+ exports.encryptSecret = encryptSecret;
58
+ /**
59
+ * Decrypt a value written by {@link encryptSecret}. Returns `null` for anything that does not
60
+ * authenticate — a payload in another format, or one written under a secret that has since been
61
+ * rotated — so a stale row reads as "no key saved" instead of failing the request.
62
+ */
63
+ const decryptSecret = (payload) => {
64
+ const [version, salt, iv, tag, encrypted] = payload.split('.');
65
+ if (version !== ENCRYPTED_SECRET_VERSION || !salt || !iv || !tag || !encrypted)
66
+ return null;
67
+ try {
68
+ const decipher = (0, node_crypto_1.createDecipheriv)('aes-256-gcm', deriveKey(Buffer.from(salt, 'base64url')), Buffer.from(iv, 'base64url'));
69
+ decipher.setAuthTag(Buffer.from(tag, 'base64url'));
70
+ return Buffer.concat([decipher.update(Buffer.from(encrypted, 'base64url')), decipher.final()]).toString('utf8');
71
+ }
72
+ catch (_a) {
73
+ return null;
74
+ }
75
+ };
76
+ exports.decryptSecret = decryptSecret;
@@ -1,6 +1,7 @@
1
1
  export { createRegistryAccessToken, listRegistryAccessTokens, revokeRegistryAccessToken, revokeAllRegistryAccessTokens, authenticateRegistryAccessToken, formatRegistryAccessToken, parseRegistryAccessToken, normalizeRegistryScopes, expandRegistryScopes, resolveRegistryScope, registryRoleAllowsScopes, type RegistryAccessTokenSummary, type CreateRegistryAccessTokenResult, } from './access-tokens';
2
2
  export { createUserInvitation, resendUserInvitation, acceptUserInvitation, createPasswordReset, resetPassword, INVITATION_LIFETIME_MS, PASSWORD_RESET_LIFETIME_MS, type CreateUserInvitationResult, type ResendUserInvitationResult, type ConsumeAuthActionResult, } from './action-tokens';
3
- export { createOpaqueSecret, hashSecret, normalizeEmail, secretHashMatches } from './crypto';
3
+ export { AI_KEY_SECRET_ENV, MissingEncryptionSecretError, createOpaqueSecret, decryptSecret, encryptSecret, hashSecret, normalizeEmail, secretHashMatches, } from './crypto';
4
+ export { deleteRegistryAiKey, listRegistryAiKeyConnections, readRegistryAiKey, saveRegistryAiKey } from './ai-keys';
4
5
  export { buildGravatarUrl } from './gravatar';
5
6
  export { authenticateRegistrySyncSecret, resolveRegistrySyncSecret, SYNC_SECRET_ENV } from './sync-secret';
6
7
  export { createRegistryDeviceAuthorization, approveRegistryDeviceAuthorization, denyRegistryDeviceAuthorization, exchangeRegistryDeviceAuthorization, purgeExpiredRegistryDeviceAuthorizations, generateRegistryUserCode, normalizeRegistryUserCode, DEVICE_AUTHORIZATION_LIFETIME_SECONDS, DEVICE_AUTHORIZATION_POLL_INTERVAL_SECONDS, type CreateRegistryDeviceAuthorizationResult, type RegistryDeviceApprovalResult, type ExchangeRegistryDeviceAuthorizationResult, } from './device-authorizations';
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getRegistryUserById = exports.hashRateLimitIdentifier = exports.purgeExpiredAuthRateLimits = exports.clearAuthRateLimit = exports.consumeAuthRateLimit = exports.MAXIMUM_PASSWORD_LENGTH = exports.MINIMUM_PASSWORD_LENGTH = exports.validatePassword = exports.verifyPassword = exports.hashPassword = exports.REGISTRY_INSTALLATION_ID = exports.REGISTRY_AUTH_SCHEMA_VERSION = exports.installRegistry = exports.getRegistryInstallationState = exports.getRegistryInstallation = exports.DEVICE_AUTHORIZATION_POLL_INTERVAL_SECONDS = exports.DEVICE_AUTHORIZATION_LIFETIME_SECONDS = exports.normalizeRegistryUserCode = exports.generateRegistryUserCode = exports.purgeExpiredRegistryDeviceAuthorizations = exports.exchangeRegistryDeviceAuthorization = exports.denyRegistryDeviceAuthorization = exports.approveRegistryDeviceAuthorization = exports.createRegistryDeviceAuthorization = exports.SYNC_SECRET_ENV = exports.resolveRegistrySyncSecret = exports.authenticateRegistrySyncSecret = exports.buildGravatarUrl = exports.secretHashMatches = exports.normalizeEmail = exports.hashSecret = exports.createOpaqueSecret = exports.PASSWORD_RESET_LIFETIME_MS = exports.INVITATION_LIFETIME_MS = exports.resetPassword = exports.createPasswordReset = exports.acceptUserInvitation = exports.resendUserInvitation = exports.createUserInvitation = exports.registryRoleAllowsScopes = exports.resolveRegistryScope = exports.expandRegistryScopes = exports.normalizeRegistryScopes = exports.parseRegistryAccessToken = exports.formatRegistryAccessToken = exports.authenticateRegistryAccessToken = exports.revokeAllRegistryAccessTokens = exports.revokeRegistryAccessToken = exports.listRegistryAccessTokens = exports.createRegistryAccessToken = void 0;
4
- exports.validateRegistryImageUrl = exports.validateRegistryEmail = exports.validateRegistryDisplayName = exports.isTransmittableCredential = exports.isRegistryTokenPrincipal = exports.registryPrincipalHasScope = exports.scopesForRegistryRole = exports.REGISTRY_WRITE_SCOPE = exports.REGISTRY_READ_SCOPE = exports.setRegistryUserStatus = exports.updateRegistryUserRole = exports.updateRegistryUserProfile = exports.authenticateRegistryCredentials = exports.listRegistryUsers = void 0;
3
+ exports.verifyPassword = exports.hashPassword = exports.REGISTRY_INSTALLATION_ID = exports.REGISTRY_AUTH_SCHEMA_VERSION = exports.installRegistry = exports.getRegistryInstallationState = exports.getRegistryInstallation = exports.DEVICE_AUTHORIZATION_POLL_INTERVAL_SECONDS = exports.DEVICE_AUTHORIZATION_LIFETIME_SECONDS = exports.normalizeRegistryUserCode = exports.generateRegistryUserCode = exports.purgeExpiredRegistryDeviceAuthorizations = exports.exchangeRegistryDeviceAuthorization = exports.denyRegistryDeviceAuthorization = exports.approveRegistryDeviceAuthorization = exports.createRegistryDeviceAuthorization = exports.SYNC_SECRET_ENV = exports.resolveRegistrySyncSecret = exports.authenticateRegistrySyncSecret = exports.buildGravatarUrl = exports.saveRegistryAiKey = exports.readRegistryAiKey = exports.listRegistryAiKeyConnections = exports.deleteRegistryAiKey = exports.secretHashMatches = exports.normalizeEmail = exports.hashSecret = exports.encryptSecret = exports.decryptSecret = exports.createOpaqueSecret = exports.MissingEncryptionSecretError = exports.AI_KEY_SECRET_ENV = exports.PASSWORD_RESET_LIFETIME_MS = exports.INVITATION_LIFETIME_MS = exports.resetPassword = exports.createPasswordReset = exports.acceptUserInvitation = exports.resendUserInvitation = exports.createUserInvitation = exports.registryRoleAllowsScopes = exports.resolveRegistryScope = exports.expandRegistryScopes = exports.normalizeRegistryScopes = exports.parseRegistryAccessToken = exports.formatRegistryAccessToken = exports.authenticateRegistryAccessToken = exports.revokeAllRegistryAccessTokens = exports.revokeRegistryAccessToken = exports.listRegistryAccessTokens = exports.createRegistryAccessToken = void 0;
4
+ exports.validateRegistryImageUrl = exports.validateRegistryEmail = exports.validateRegistryDisplayName = exports.isTransmittableCredential = exports.isRegistryTokenPrincipal = exports.registryPrincipalHasScope = exports.scopesForRegistryRole = exports.REGISTRY_WRITE_SCOPE = exports.REGISTRY_READ_SCOPE = exports.setRegistryUserStatus = exports.updateRegistryUserRole = exports.updateRegistryUserProfile = exports.authenticateRegistryCredentials = exports.listRegistryUsers = exports.getRegistryUserById = exports.hashRateLimitIdentifier = exports.purgeExpiredAuthRateLimits = exports.clearAuthRateLimit = exports.consumeAuthRateLimit = exports.MAXIMUM_PASSWORD_LENGTH = exports.MINIMUM_PASSWORD_LENGTH = exports.validatePassword = void 0;
5
5
  var access_tokens_1 = require("./access-tokens");
6
6
  Object.defineProperty(exports, "createRegistryAccessToken", { enumerable: true, get: function () { return access_tokens_1.createRegistryAccessToken; } });
7
7
  Object.defineProperty(exports, "listRegistryAccessTokens", { enumerable: true, get: function () { return access_tokens_1.listRegistryAccessTokens; } });
@@ -23,10 +23,19 @@ Object.defineProperty(exports, "resetPassword", { enumerable: true, get: functio
23
23
  Object.defineProperty(exports, "INVITATION_LIFETIME_MS", { enumerable: true, get: function () { return action_tokens_1.INVITATION_LIFETIME_MS; } });
24
24
  Object.defineProperty(exports, "PASSWORD_RESET_LIFETIME_MS", { enumerable: true, get: function () { return action_tokens_1.PASSWORD_RESET_LIFETIME_MS; } });
25
25
  var crypto_1 = require("./crypto");
26
+ Object.defineProperty(exports, "AI_KEY_SECRET_ENV", { enumerable: true, get: function () { return crypto_1.AI_KEY_SECRET_ENV; } });
27
+ Object.defineProperty(exports, "MissingEncryptionSecretError", { enumerable: true, get: function () { return crypto_1.MissingEncryptionSecretError; } });
26
28
  Object.defineProperty(exports, "createOpaqueSecret", { enumerable: true, get: function () { return crypto_1.createOpaqueSecret; } });
29
+ Object.defineProperty(exports, "decryptSecret", { enumerable: true, get: function () { return crypto_1.decryptSecret; } });
30
+ Object.defineProperty(exports, "encryptSecret", { enumerable: true, get: function () { return crypto_1.encryptSecret; } });
27
31
  Object.defineProperty(exports, "hashSecret", { enumerable: true, get: function () { return crypto_1.hashSecret; } });
28
32
  Object.defineProperty(exports, "normalizeEmail", { enumerable: true, get: function () { return crypto_1.normalizeEmail; } });
29
33
  Object.defineProperty(exports, "secretHashMatches", { enumerable: true, get: function () { return crypto_1.secretHashMatches; } });
34
+ var ai_keys_1 = require("./ai-keys");
35
+ Object.defineProperty(exports, "deleteRegistryAiKey", { enumerable: true, get: function () { return ai_keys_1.deleteRegistryAiKey; } });
36
+ Object.defineProperty(exports, "listRegistryAiKeyConnections", { enumerable: true, get: function () { return ai_keys_1.listRegistryAiKeyConnections; } });
37
+ Object.defineProperty(exports, "readRegistryAiKey", { enumerable: true, get: function () { return ai_keys_1.readRegistryAiKey; } });
38
+ Object.defineProperty(exports, "saveRegistryAiKey", { enumerable: true, get: function () { return ai_keys_1.saveRegistryAiKey; } });
30
39
  var gravatar_1 = require("./gravatar");
31
40
  Object.defineProperty(exports, "buildGravatarUrl", { enumerable: true, get: function () { return gravatar_1.buildGravatarUrl; } });
32
41
  var sync_secret_1 = require("./sync-secret");
@@ -6,7 +6,8 @@
6
6
  * into the local workspace in standard authoring form. The local **declaration is synthesized
7
7
  * locally** in the configured `runtime.workspace.declarationFormat` — declarations are never read
8
8
  * from the registry (they are workspace-only). Identity is matched by stable `id`, so a checked-out
9
- * entity maps to the correct logical component/pattern and can be re-authored and re-published.
9
+ * entity maps to the correct logical component/pattern and can be re-authored and re-published. A
10
+ * new entity goes to the directory it was published from (`sourceDir`).
10
11
  *
11
12
  * Available only from a connected workspace (`runtime.mode: workspace` + a configured
12
13
  * `registryConnection`). Overwriting existing local files is explicit: a `--force` flag or an