handoff-app 2.0.0-9 → 2.0.1

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 (312) hide show
  1. package/AGENTS.md +90 -1
  2. package/{Changelog.md → CHANGELOG.md} +105 -1
  3. package/CLAUDE.md +92 -1
  4. package/{License.md → LICENSE.md} +1 -1
  5. package/README.md +818 -406
  6. package/RECIPES.md +975 -0
  7. package/UPGRADE.md +57 -9
  8. package/components.json +20 -20
  9. package/config/docs/foundations/colors/guidelines.md +0 -1
  10. package/config/docs/foundations/colors.md +0 -1
  11. package/config/docs/foundations/effects/guidelines.md +0 -1
  12. package/config/docs/foundations/effects/resources.md +0 -1
  13. package/config/docs/foundations/effects.md +0 -1
  14. package/config/docs/foundations/fonts.md +0 -1
  15. package/config/docs/foundations/grid.md +0 -1
  16. package/config/docs/foundations/icon.md +0 -1
  17. package/config/docs/foundations/icons/guidelines.md +0 -1
  18. package/config/docs/foundations/icons.md +0 -1
  19. package/config/docs/foundations/images/guidelines.md +0 -1
  20. package/config/docs/foundations/images/resources.md +0 -1
  21. package/config/docs/foundations/images.md +0 -1
  22. package/config/docs/foundations/logo/resources.md +0 -1
  23. package/config/docs/foundations/logo.md +0 -1
  24. package/config/docs/foundations/typography/guidelines.md +0 -1
  25. package/config/docs/foundations/typography/resources.md +0 -1
  26. package/config/docs/foundations/typography.md +0 -1
  27. package/config/docs/foundations.md +0 -1
  28. package/config/docs/guidelines.md +0 -1
  29. package/config/docs/index.md +0 -1
  30. package/config/docs/system/tokens/foundations/colors.md +0 -4
  31. package/config/docs/system/tokens/foundations/effects.md +0 -4
  32. package/config/docs/system/tokens/foundations/typography.md +0 -2
  33. package/config/docs/system.md +0 -2
  34. package/config/templates/page.md +2 -1
  35. package/config/templates/page.mdx +2 -1
  36. package/dist/ai/connections.d.ts +66 -0
  37. package/dist/ai/connections.js +149 -0
  38. package/dist/ai/define.d.ts +10 -0
  39. package/dist/ai/define.js +13 -0
  40. package/dist/ai/types.d.ts +26 -0
  41. package/dist/ai/types.js +10 -0
  42. package/dist/app-builder/build.d.ts +14 -7
  43. package/dist/app-builder/build.js +195 -66
  44. package/dist/app-builder/client-config.js +3 -2
  45. package/dist/app-builder/paths.d.ts +0 -12
  46. package/dist/app-builder/paths.js +3 -20
  47. package/dist/app-builder/static-export.js +1 -1
  48. package/dist/app-builder/vercel-output.d.ts +1 -1
  49. package/dist/app-builder/vercel-output.js +5 -4
  50. package/dist/cache/build-cache.d.ts +27 -4
  51. package/dist/cache/build-cache.js +114 -47
  52. package/dist/cache/build-inputs.d.ts +13 -0
  53. package/dist/cache/build-inputs.js +19 -0
  54. package/dist/cache/index.d.ts +2 -1
  55. package/dist/cache/index.js +5 -1
  56. package/dist/cli/create.js +1 -2
  57. package/dist/cli.js +1 -1
  58. package/dist/commands/build/index.d.ts +1 -1
  59. package/dist/commands/build/index.js +1 -1
  60. package/dist/commands/utils.d.ts +3 -3
  61. package/dist/config/defaults.js +7 -4
  62. package/dist/config/from-env.d.ts +4 -0
  63. package/dist/config/from-env.js +38 -1
  64. package/dist/config/helpers.js +2 -2
  65. package/dist/config/index.d.ts +0 -1
  66. package/dist/config/index.js +1 -4
  67. package/dist/config/loader.js +26 -2
  68. package/dist/config/resolve-env.d.ts +2 -1
  69. package/dist/config/resolve-env.js +28 -12
  70. package/dist/config/runtime.js +1 -1
  71. package/dist/index.d.ts +12 -7
  72. package/dist/index.js +18 -22
  73. package/dist/nav/index.d.ts +2 -2
  74. package/dist/nav/registry.d.ts +3 -3
  75. package/dist/nav/registry.js +1 -1
  76. package/dist/nav/workspace.d.ts +3 -3
  77. package/dist/nav/workspace.js +1 -1
  78. package/dist/pipeline/figma.d.ts +13 -2
  79. package/dist/pipeline/figma.js +86 -46
  80. package/dist/pipeline/styles.js +1 -1
  81. package/dist/pipeline/validation.d.ts +1 -1
  82. package/dist/pipeline/validation.js +3 -3
  83. package/dist/providers.d.ts +10 -0
  84. package/dist/providers.js +13 -0
  85. package/dist/registry/asset-storage/define.d.ts +5 -5
  86. package/dist/registry/asset-storage/define.js +4 -4
  87. package/dist/registry/asset-storage/resolve.d.ts +9 -19
  88. package/dist/registry/asset-storage/resolve.js +33 -21
  89. package/dist/registry/asset-storage/types.d.ts +37 -17
  90. package/dist/registry/asset-storage/types.js +5 -5
  91. package/dist/registry/auth/ai-keys.d.ts +32 -0
  92. package/dist/registry/auth/ai-keys.js +69 -0
  93. package/dist/registry/auth/crypto.d.ts +17 -0
  94. package/dist/registry/auth/crypto.js +61 -1
  95. package/dist/registry/auth/index.d.ts +2 -1
  96. package/dist/registry/auth/index.js +11 -2
  97. package/dist/registry/checkout/index.d.ts +2 -1
  98. package/dist/registry/checkout/index.js +57 -127
  99. package/dist/registry/client.js +53 -17
  100. package/dist/registry/db/driver.js +3 -3
  101. package/dist/registry/db/schema.d.ts +261 -3
  102. package/dist/registry/db/schema.js +29 -4
  103. package/dist/registry/email/define.d.ts +10 -0
  104. package/dist/registry/email/define.js +13 -0
  105. package/dist/registry/email/providers/smtp.d.ts +10 -0
  106. package/dist/registry/email/providers/smtp.js +73 -0
  107. package/dist/registry/email/resolve.d.ts +28 -0
  108. package/dist/registry/email/resolve.js +74 -0
  109. package/dist/registry/email/types.d.ts +24 -0
  110. package/dist/registry/email/types.js +6 -0
  111. package/dist/registry/path.d.ts +2 -0
  112. package/dist/registry/path.js +11 -1
  113. package/dist/registry/publish/errors.js +4 -0
  114. package/dist/registry/publish/index.js +2 -0
  115. package/dist/registry/publish/package.d.ts +6 -0
  116. package/dist/registry/publish/package.js +29 -1
  117. package/dist/registry/transfer.d.ts +4 -0
  118. package/dist/store/registry.d.ts +3 -3
  119. package/dist/store/registry.js +4 -4
  120. package/dist/transformers/preview/component/builder.d.ts +1 -9
  121. package/dist/transformers/preview/component/builder.js +17 -17
  122. package/dist/transformers/preview/component/css.d.ts +2 -1
  123. package/dist/transformers/preview/component/css.js +8 -5
  124. package/dist/transformers/preview/component/html.d.ts +3 -1
  125. package/dist/transformers/preview/component/html.js +6 -2
  126. package/dist/transformers/preview/component/javascript.d.ts +2 -1
  127. package/dist/transformers/preview/component/javascript.js +10 -4
  128. package/dist/transformers/utils/build.d.ts +9 -0
  129. package/dist/transformers/utils/build.js +27 -5
  130. package/dist/types/config.d.ts +129 -18
  131. package/dist/utils/path.d.ts +1 -5
  132. package/dist/utils/path.js +6 -23
  133. package/docs/api.md +6 -4
  134. package/docs/cli.md +275 -54
  135. package/drizzle/0007_add_ai_keys.sql +11 -0
  136. package/drizzle/0008_add_source_dir.sql +2 -0
  137. package/drizzle/meta/0007_snapshot.json +2013 -0
  138. package/drizzle/meta/0008_snapshot.json +2025 -0
  139. package/drizzle/meta/_journal.json +14 -0
  140. package/package.json +19 -8
  141. package/src/ai/README.md +42 -0
  142. package/src/ai/connections.ts +189 -0
  143. package/src/ai/define.ts +15 -0
  144. package/src/ai/types.ts +30 -0
  145. package/src/app/components/AiAssistant/AiAssistantPanel.tsx +144 -0
  146. package/src/app/components/AiAssistant/AiAssistantProvider.tsx +215 -0
  147. package/src/app/components/AiAssistant/AiConversation.tsx +737 -0
  148. package/src/app/components/AiAssistant/AiToolResult.tsx +99 -0
  149. package/src/app/components/AiAssistant/dockState.ts +86 -0
  150. package/src/app/components/AiAssistant/toolLabel.ts +24 -0
  151. package/src/app/components/AiAssistant/useAiChat.ts +147 -0
  152. package/src/app/components/AiAssistant/useAiConnections.ts +86 -0
  153. package/src/app/components/AiAssistant/usePageContext.ts +63 -0
  154. package/src/app/components/Auth/AccountLayout.tsx +58 -19
  155. package/src/app/components/Auth/AuthShell.tsx +27 -33
  156. package/src/app/components/Auth/RegistryInstallGate.tsx +4 -8
  157. package/src/app/components/Auth/installStatus.ts +29 -0
  158. package/src/app/components/Component/Preview.tsx +5 -2
  159. package/src/app/components/Foundations/ColorGrid.tsx +13 -14
  160. package/src/app/components/Layout/Header.tsx +21 -15
  161. package/src/app/components/Layout/Main.tsx +2 -2
  162. package/src/app/components/Markdown/MarkdownComponents.tsx +30 -32
  163. package/src/app/components/McpIntegration/McpConfigDialog.tsx +12 -51
  164. package/src/app/components/Navigation/MobileNav.tsx +2 -2
  165. package/src/app/components/Navigation/SideNav.tsx +1 -15
  166. package/src/app/components/context/NavProvider.tsx +7 -3
  167. package/src/app/components/ui/attachment.tsx +50 -0
  168. package/src/app/components/ui/bubble.tsx +57 -0
  169. package/src/app/components/ui/button.tsx +3 -1
  170. package/src/app/components/ui/confirm-dialog.tsx +87 -0
  171. package/src/app/components/ui/dialog.tsx +7 -2
  172. package/src/app/components/ui/marker.tsx +56 -0
  173. package/src/app/components/ui/sidebar.tsx +3 -1
  174. package/src/app/components/util/index.ts +3 -12
  175. package/src/app/css/index.css +64 -0
  176. package/src/app/lib/ai/auth.ts +33 -0
  177. package/src/app/lib/ai/context.ts +99 -0
  178. package/src/app/lib/ai/model.ts +79 -0
  179. package/src/app/lib/ai/prompt.ts +36 -0
  180. package/src/app/lib/ai/resolve.ts +97 -0
  181. package/src/app/lib/ai/tools.ts +120 -0
  182. package/src/app/lib/api/methods.ts +13 -0
  183. package/src/app/lib/asset-storage.ts +35 -36
  184. package/src/app/lib/auth/api.ts +4 -12
  185. package/src/app/lib/auth/email.ts +96 -23
  186. package/src/app/lib/docs-api/page-rendering.ts +1 -1
  187. package/src/app/lib/docs-api/registry.ts +2 -3
  188. package/src/app/lib/docs-api/runtime-config.ts +47 -21
  189. package/src/app/lib/mcp/components.ts +523 -0
  190. package/src/app/lib/mcp/page-url.ts +24 -0
  191. package/src/app/lib/mcp/pages.ts +84 -0
  192. package/src/app/lib/mcp/result.ts +33 -0
  193. package/src/app/lib/mcp/server.ts +39 -318
  194. package/src/app/lib/mcp/tokens.ts +334 -0
  195. package/src/app/lib/mcp/tool.ts +19 -0
  196. package/src/app/lib/registry-api/asset-transfer.ts +119 -11
  197. package/src/app/lib/registry-api/errors.ts +2 -0
  198. package/src/app/lib/registry-api/handler.ts +7 -1
  199. package/src/app/lib/registry-api/transfer.ts +28 -6
  200. package/src/app/lib/server-module.ts +34 -0
  201. package/src/app/lib/utils.ts +20 -0
  202. package/src/app/next.config.mjs +26 -24
  203. package/src/app/pages/[...slug]/index.tsx +2 -1
  204. package/src/app/pages/_app.tsx +6 -2
  205. package/src/app/pages/_document.tsx +6 -0
  206. package/src/app/pages/account/ai.tsx +183 -0
  207. package/src/app/pages/account/index.tsx +68 -68
  208. package/src/app/pages/account/tokens.tsx +37 -7
  209. package/src/app/pages/account/users.tsx +75 -15
  210. package/src/app/pages/api/account/ai/keys/[connectionId].ts +60 -0
  211. package/src/app/pages/api/account/ai/keys/index.ts +20 -0
  212. package/src/app/pages/api/admin/users/[id]/[action].ts +80 -11
  213. package/src/app/pages/api/admin/users/index.ts +2 -2
  214. package/src/app/pages/api/ai/chat.ts +115 -0
  215. package/src/app/pages/api/ai/connections.ts +23 -0
  216. package/src/app/pages/api/auth/request-reset.ts +14 -16
  217. package/src/app/pages/api/docs/nav.json.ts +1 -1
  218. package/src/app/pages/api/install.ts +3 -3
  219. package/src/app/pages/api/mcp.ts +6 -0
  220. package/src/app/pages/api/registry/transfer/assets/blobs/[hash]/complete.ts +11 -0
  221. package/src/app/pages/api/registry/transfer/assets/blobs/[hash]/upload.ts +12 -0
  222. package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +1 -1
  223. package/src/app/pages/cli/device.tsx +10 -5
  224. package/src/app/pages/foundations/colors.tsx +9 -8
  225. package/src/app/pages/foundations/index.tsx +3 -3
  226. package/src/app/pages/index.tsx +2 -2
  227. package/src/app/pages/install.tsx +7 -2
  228. package/src/app/pages/login.tsx +32 -27
  229. package/src/app/pages/reset-password.tsx +21 -20
  230. package/src/app/pages/system/component/[component]/index.tsx +2 -5
  231. package/src/app/pages/system/index.tsx +11 -11
  232. package/src/app/pages/system/pattern/[pattern]/index.tsx +2 -2
  233. package/src/app/pages/system/tokens/components/[component]/index.tsx +0 -4
  234. package/src/app-builder/README.md +2 -1
  235. package/src/app-builder/build.ts +218 -73
  236. package/src/app-builder/client-config.ts +3 -2
  237. package/src/app-builder/paths.ts +3 -22
  238. package/src/app-builder/static-export.ts +1 -1
  239. package/src/app-builder/vercel-output.ts +5 -4
  240. package/src/cache/README.md +4 -1
  241. package/src/cache/build-cache.ts +128 -43
  242. package/src/cache/build-inputs.ts +28 -0
  243. package/src/cache/index.ts +4 -0
  244. package/src/cli/create.ts +1 -2
  245. package/src/cli.ts +1 -1
  246. package/src/commands/build/index.ts +1 -1
  247. package/src/config/README.md +10 -9
  248. package/src/config/defaults.ts +7 -4
  249. package/src/config/from-env.ts +33 -0
  250. package/src/config/helpers.ts +1 -3
  251. package/src/config/index.ts +0 -3
  252. package/src/config/loader.ts +25 -3
  253. package/src/config/resolve-env.ts +28 -15
  254. package/src/config/runtime.ts +1 -1
  255. package/src/index.ts +33 -29
  256. package/src/nav/index.ts +2 -2
  257. package/src/nav/registry.ts +3 -3
  258. package/src/nav/workspace.ts +3 -3
  259. package/src/pipeline/README.md +1 -1
  260. package/src/pipeline/figma.ts +98 -49
  261. package/src/pipeline/styles.ts +1 -1
  262. package/src/pipeline/validation.ts +3 -3
  263. package/src/providers.ts +18 -0
  264. package/src/registry/asset-storage/define.ts +6 -6
  265. package/src/registry/asset-storage/resolve.ts +38 -37
  266. package/src/registry/asset-storage/types.ts +39 -17
  267. package/src/registry/auth/ai-keys.ts +62 -0
  268. package/src/registry/auth/crypto.ts +63 -1
  269. package/src/registry/auth/index.ts +11 -1
  270. package/src/registry/checkout/index.ts +60 -138
  271. package/src/registry/client.ts +60 -20
  272. package/src/registry/db/driver.ts +2 -2
  273. package/src/registry/db/schema.ts +49 -22
  274. package/src/registry/email/define.ts +15 -0
  275. package/src/registry/email/providers/smtp.ts +39 -0
  276. package/src/registry/email/resolve.ts +94 -0
  277. package/src/registry/email/types.ts +28 -0
  278. package/src/registry/path.ts +11 -0
  279. package/src/registry/publish/errors.ts +4 -0
  280. package/src/registry/publish/index.ts +3 -1
  281. package/src/registry/publish/package.ts +33 -0
  282. package/src/registry/transfer.ts +4 -0
  283. package/src/store/registry.ts +7 -7
  284. package/src/transformers/preview/component/builder.ts +19 -25
  285. package/src/transformers/preview/component/css.ts +9 -4
  286. package/src/transformers/preview/component/html.ts +6 -2
  287. package/src/transformers/preview/component/javascript.ts +14 -4
  288. package/src/transformers/utils/build.ts +22 -4
  289. package/src/types/config.ts +142 -20
  290. package/src/utils/README.md +1 -1
  291. package/src/utils/path.ts +6 -29
  292. package/templates/default/handoff.config.js.tpl +10 -2
  293. package/templates/default/handoff.config.ts.tpl +10 -2
  294. package/templates/default/handoff.config.with-examples.js.tpl +10 -2
  295. package/templates/default/handoff.config.with-examples.ts.tpl +10 -2
  296. package/templates/default/package.json.tpl +2 -2
  297. package/.editorconfig +0 -19
  298. package/.eslintrc.json +0 -4
  299. package/.prettierignore +0 -0
  300. package/.prettierrc.json +0 -8
  301. package/.vscode/settings.json +0 -17
  302. package/dist/config/validator.d.ts +0 -9
  303. package/dist/config/validator.js +0 -24
  304. package/dist/registry/asset-storage/adapters/vercel-blob.d.ts +0 -17
  305. package/dist/registry/asset-storage/adapters/vercel-blob.js +0 -87
  306. package/src/app/components/old/Header.tsx +0 -89
  307. package/src/app/lib/mcp/shape.ts +0 -596
  308. package/src/app/pages/assets/fonts.tsx +0 -129
  309. package/src/app/pages/assets/index.tsx +0 -91
  310. package/src/app/pages/assets/logos.tsx +0 -75
  311. package/src/config/validator.ts +0 -22
  312. package/src/registry/asset-storage/adapters/vercel-blob.ts +0 -51
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.resolvePathWithin = exports.isSafePathSegment = exports.normalizeRelativePath = exports.isSafeRelativePath = void 0;
6
+ exports.resolvePathWithin = exports.isSafePathSegment = exports.isWorkspaceRelativePath = exports.normalizeRelativePath = exports.isSafeRelativePath = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const isSafeRelativePath = (value) => {
9
9
  if (typeof value !== 'string' || value.trim() === '') {
@@ -18,6 +18,16 @@ const isSafeRelativePath = (value) => {
18
18
  exports.isSafeRelativePath = isSafeRelativePath;
19
19
  const normalizeRelativePath = (value) => value.replace(/\\/g, '/');
20
20
  exports.normalizeRelativePath = normalizeRelativePath;
21
+ /** Unlike {@link isSafeRelativePath}, it can start with `../`. */
22
+ const isWorkspaceRelativePath = (value) => typeof value === 'string' &&
23
+ value !== '' &&
24
+ value !== '.' &&
25
+ !value.includes('\0') &&
26
+ !value.includes('\\') &&
27
+ !value.startsWith('/') &&
28
+ !/^[a-zA-Z]:/.test(value) &&
29
+ path_1.default.posix.normalize(value) === value;
30
+ exports.isWorkspaceRelativePath = isWorkspaceRelativePath;
21
31
  const isSafePathSegment = (value) => typeof value === 'string' && value === value.trim() && (0, exports.isSafeRelativePath)(value) && !(0, exports.normalizeRelativePath)(value).includes('/');
22
32
  exports.isSafePathSegment = isSafePathSegment;
23
33
  const resolvePathWithin = (root, value) => {
@@ -4,6 +4,10 @@ exports.describePublishError = exports.describeUploadFailure = void 0;
4
4
  const client_1 = require("../client");
5
5
  /** Map registry error codes to the actionable messages used by publish commands. */
6
6
  const describeUploadFailure = (error, registryUrl, rejectedPayload) => {
7
+ // An oversized body is rejected by the platform or body parser, so the response has no error envelope.
8
+ if (error.status === 413) {
9
+ return `The registry at ${registryUrl} rejected the ${rejectedPayload} as too large (413). Reduce the size of its largest files and publish again.`;
10
+ }
7
11
  switch (error.code) {
8
12
  case 'runtime_mode_conflict':
9
13
  return `The registry at ${registryUrl} is not running in registry mode, so it cannot accept publishes: ${error.message}`;
@@ -160,6 +160,7 @@ const publishEntity = (handoff, kind, id) => __awaiter(void 0, void 0, void 0, f
160
160
  }
161
161
  const pkg = yield (0, package_1.buildPublishPackage)(handoff, kind, id);
162
162
  (0, package_1.assertRequiredArtifactsPresent)(pkg);
163
+ (0, package_1.assertPackageWithinUploadLimit)(kind, id, pkg);
163
164
  const contents = `${pkg.artifacts.length} artifact(s), ${pkg.files.length} source file(s)`;
164
165
  if (!client) {
165
166
  logger_1.Logger.info(`Would publish ${kind} "${id}" (${contents}).`);
@@ -251,6 +252,7 @@ const uploadEntities = (handoff, transport, kind, ids) => __awaiter(void 0, void
251
252
  try {
252
253
  const pkg = yield (0, package_1.buildPublishPackage)(handoff, kind, id);
253
254
  (0, package_1.assertRequiredArtifactsPresent)(pkg);
255
+ (0, package_1.assertPackageWithinUploadLimit)(kind, id, pkg);
254
256
  const remoteHash = remoteHashById.get(id);
255
257
  const localHash = entityHash(pkg.build);
256
258
  if (!handoff.force && remoteHash && localHash && remoteHash === localHash) {
@@ -23,5 +23,11 @@ export declare class PublishPackageError extends Error {
23
23
  * upload, so a publish fails locally (no network call) on a missing required artifact.
24
24
  */
25
25
  export declare const assertRequiredArtifactsPresent: (pkg: TransferPackage) => void;
26
+ /**
27
+ * The largest publish request body the registry accepts. Vercel rejects a larger function body with
28
+ * `413 FUNCTION_PAYLOAD_TOO_LARGE`, and the transfer route's `bodyParser.sizeLimit` matches it.
29
+ */
30
+ export declare const MAX_PUBLISH_BODY_BYTES = 4500000;
31
+ export declare const assertPackageWithinUploadLimit: (kind: TransferEntityKind, id: string, pkg: TransferPackage) => void;
26
32
  /** Assemble the publish package for an entity from the generated `public/api` artifacts. */
27
33
  export declare const buildPublishPackage: (handoff: Handoff, kind: TransferEntityKind, id: string) => Promise<TransferPackage>;
@@ -37,7 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
38
  };
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
- exports.buildPublishPackage = exports.assertRequiredArtifactsPresent = exports.PublishPackageError = void 0;
40
+ exports.buildPublishPackage = exports.assertPackageWithinUploadLimit = exports.MAX_PUBLISH_BODY_BYTES = exports.assertRequiredArtifactsPresent = exports.PublishPackageError = void 0;
41
41
  const fs_extra_1 = __importDefault(require("fs-extra"));
42
42
  const path_1 = __importDefault(require("path"));
43
43
  const source_files_1 = require("../../store/source-files");
@@ -97,6 +97,12 @@ const enrichItem = (handoff, kind, id, summary) => __awaiter(void 0, void 0, voi
97
97
  }
98
98
  return item;
99
99
  });
100
+ const findSourceDir = (handoff, kind, id) => __awaiter(void 0, void 0, void 0, function* () {
101
+ const runtime = kind === 'component' ? yield handoff.store.components.get(id) : yield handoff.store.patterns.get(id);
102
+ const sourceDir = runtime === null || runtime === void 0 ? void 0 : runtime.path;
103
+ const relativeDir = sourceDir ? path_1.default.relative(handoff.workingPath, sourceDir) : '';
104
+ return relativeDir && !path_1.default.isAbsolute(relativeDir) ? relativeDir.split(path_1.default.sep).join('/') : undefined;
105
+ });
100
106
  /** Map an entity's related source files to transfer files, dropping workspace-only declarations. */
101
107
  const collectSourceFiles = (handoff, kind, id) => __awaiter(void 0, void 0, void 0, function* () {
102
108
  const store = kind === 'component' ? handoff.store.components : kind === 'pattern' ? handoff.store.patterns : handoff.store.pages;
@@ -164,6 +170,7 @@ const buildComponentPackage = (handoff, id) => __awaiter(void 0, void 0, void 0,
164
170
  const artifacts = Array.from(byPath.values());
165
171
  return {
166
172
  item: yield enrichItem(handoff, 'component', id, summary),
173
+ sourceDir: yield findSourceDir(handoff, 'component', id),
167
174
  files: yield collectSourceFiles(handoff, 'component', id),
168
175
  artifacts,
169
176
  build: createArtifactBuild(artifacts),
@@ -206,6 +213,7 @@ const buildPatternPackage = (handoff, id) => __awaiter(void 0, void 0, void 0, f
206
213
  const artifacts = Array.from(byPath.values());
207
214
  return {
208
215
  item: yield enrichItem(handoff, 'pattern', id, summary),
216
+ sourceDir: yield findSourceDir(handoff, 'pattern', id),
209
217
  files: yield collectSourceFiles(handoff, 'pattern', id),
210
218
  artifacts,
211
219
  build: createArtifactBuild(artifacts),
@@ -261,6 +269,26 @@ const assertRequiredArtifactsPresent = (pkg) => {
261
269
  }
262
270
  };
263
271
  exports.assertRequiredArtifactsPresent = assertRequiredArtifactsPresent;
272
+ /**
273
+ * The largest publish request body the registry accepts. Vercel rejects a larger function body with
274
+ * `413 FUNCTION_PAYLOAD_TOO_LARGE`, and the transfer route's `bodyParser.sizeLimit` matches it.
275
+ */
276
+ exports.MAX_PUBLISH_BODY_BYTES = 4500000;
277
+ const formatMegabytes = (bytes) => `${(bytes / 1000000).toFixed(1)} MB`;
278
+ const assertPackageWithinUploadLimit = (kind, id, pkg) => {
279
+ const size = Buffer.byteLength(JSON.stringify(pkg));
280
+ if (size <= exports.MAX_PUBLISH_BODY_BYTES)
281
+ return;
282
+ const largest = [...pkg.artifacts, ...pkg.files]
283
+ .map((entry) => ({ path: entry.path, size: Buffer.byteLength(entry.content) }))
284
+ .sort((a, b) => b.size - a.size)
285
+ .slice(0, 3)
286
+ .map((entry) => ` - ${entry.path} (${formatMegabytes(entry.size)})`)
287
+ .join('\n');
288
+ throw new PublishPackageError(`The ${kind} "${id}" package is ${formatMegabytes(size)}; the registry accepts at most ` +
289
+ `${formatMegabytes(exports.MAX_PUBLISH_BODY_BYTES)} per publish. Largest entries:\n${largest}`);
290
+ };
291
+ exports.assertPackageWithinUploadLimit = assertPackageWithinUploadLimit;
264
292
  /** Assemble the publish package for an entity from the generated `public/api` artifacts. */
265
293
  const buildPublishPackage = (handoff, kind, id) => kind === 'component'
266
294
  ? buildComponentPackage(handoff, id)
@@ -59,6 +59,8 @@ export interface TransferBuild {
59
59
  export interface TransferPackage {
60
60
  /** Normalized component, pattern, or page record stored as the served record. */
61
61
  item: Record<string, unknown>;
62
+ /** Workspace-relative entity directory, for components and patterns. It can start with `../`. */
63
+ sourceDir?: string;
62
64
  files: TransferFile[];
63
65
  artifacts: TransferArtifact[];
64
66
  build: TransferBuild;
@@ -71,6 +73,8 @@ export interface CheckoutPayload {
71
73
  kind: TransferEntityKind;
72
74
  /** Normalized record used to reconstruct the entity. */
73
75
  item: Record<string, unknown>;
76
+ /** The published {@link TransferPackage.sourceDir}. */
77
+ sourceDir?: string;
74
78
  files: TransferFile[];
75
79
  }
76
80
  /**
@@ -13,7 +13,7 @@
13
13
  * - Reads never materialize source files or run the build pipeline — every record and file is
14
14
  * returned exactly as it was published.
15
15
  */
16
- import type { AssetStorage } from '../registry/asset-storage/types';
16
+ import type { StorageProvider } from '../registry/asset-storage/types';
17
17
  import type { RegistryDatabase } from '../registry/db/client';
18
18
  import { type AssetStorageProvider } from '../registry/db/schema';
19
19
  import type { ComponentListObject, PageListObject, PatternListObject } from '../transformers/preview/types';
@@ -22,11 +22,11 @@ import type { AssetContentResource, AssetMetadata, AssetStore, ComponentStore, H
22
22
  export interface RegistryStoreContext {
23
23
  db: RegistryDatabase;
24
24
  /**
25
- * Resolve the {@link AssetStorage} adapter for a blob's recorded provider (or `null` for the inline
25
+ * Resolve the {@link StorageProvider} for a blob's recorded provider (or `null` for the inline
26
26
  * `database` provider). Injected by the app runtime so `src/store` stays free of app-side imports;
27
27
  * when omitted, only inline DB-backed asset content is resolvable.
28
28
  */
29
- resolveAssetAdapter?: (provider: AssetStorageProvider) => Promise<AssetStorage | null>;
29
+ resolveStorageProvider?: (provider: AssetStorageProvider) => Promise<StorageProvider | null>;
30
30
  }
31
31
  export declare class RegistryComponentStore implements ComponentStore {
32
32
  private readonly context;
@@ -404,14 +404,14 @@ class RegistryAssetStore {
404
404
  return Object.assign(Object.assign({}, base), { body: Buffer.from(row.blobContent) });
405
405
  }
406
406
  // Object-backed - resolve through the provider that stored it.
407
- if (!row.storageRef || !this.context.resolveAssetAdapter) {
407
+ if (!row.storageRef || !this.context.resolveStorageProvider) {
408
408
  return null;
409
409
  }
410
- const adapter = yield this.context.resolveAssetAdapter(row.storageProvider);
411
- if (!adapter) {
410
+ const storage = yield this.context.resolveStorageProvider(row.storageProvider);
411
+ if (!storage) {
412
412
  return null;
413
413
  }
414
- const result = yield adapter.get(row.storageRef);
414
+ const result = yield storage.get(row.storageRef);
415
415
  if (result.kind === 'redirect') {
416
416
  return Object.assign(Object.assign({}, base), { redirectUrl: result.url });
417
417
  }
@@ -9,20 +9,12 @@ export declare enum ComponentSegment {
9
9
  Previews = "previews",
10
10
  Validation = "validation"
11
11
  }
12
- /**
13
- * Options for processing components
14
- */
15
- export interface ProcessComponentsOptions {
16
- /** Enable caching to skip unchanged components */
17
- useCache?: boolean;
18
- }
19
12
  /**
20
13
  * Process components and generate their code, styles, and previews
21
14
  * @param handoff - The Handoff instance containing configuration and state
22
15
  * @param id - Optional component ID to process a specific component
23
16
  * @param segmentToProcess - Optional segment to update
24
- * @param options - Optional processing options including cache settings
25
17
  * @returns Promise resolving to an array of processed components
26
18
  */
27
- export declare function processComponents(handoff: Handoff, id?: string, segmentToProcess?: ComponentSegment, options?: ProcessComponentsOptions): Promise<ComponentListObject[]>;
19
+ export declare function processComponents(handoff: Handoff, id?: string, segmentToProcess?: ComponentSegment): Promise<ComponentListObject[]>;
28
20
  export default processComponents;
@@ -153,12 +153,11 @@ const createComponentBuildPlan = (segmentToProcess, existingData) => {
153
153
  * @param handoff - The Handoff instance containing configuration and state
154
154
  * @param id - Optional component ID to process a specific component
155
155
  * @param segmentToProcess - Optional segment to update
156
- * @param options - Optional processing options including cache settings
157
156
  * @returns Promise resolving to an array of processed components
158
157
  */
159
- function processComponents(handoff, id, segmentToProcess, options) {
158
+ function processComponents(handoff, id, segmentToProcess) {
160
159
  return __awaiter(this, void 0, void 0, function* () {
161
- var _a, _b, _c, _d;
160
+ var _a, _b, _c, _d, _e;
162
161
  const result = [];
163
162
  const documentationObject = yield handoff.getDocumentationObject();
164
163
  const components = (_a = documentationObject === null || documentationObject === void 0 ? void 0 : documentationObject.components) !== null && _a !== void 0 ? _a : {};
@@ -177,17 +176,16 @@ function processComponents(handoff, id, segmentToProcess, options) {
177
176
  yield (0, artifacts_1.syncComponentArtifacts)(handoff, [id]);
178
177
  return [];
179
178
  }
180
- // Determine which components need building based on cache (when enabled)
179
+ // Determine which components need building based on cache
181
180
  let componentsToBuild;
182
181
  let cache = null;
183
182
  let currentGlobalDeps = {};
184
183
  const componentFileStatesMap = new Map();
185
184
  // Only use caching when:
186
- // - useCache option is enabled
187
185
  // - No specific component ID is requested (full build scenario)
188
186
  // - No specific segment is requested (full build scenario)
189
187
  // - Force flag is not set
190
- const shouldUseCache = (options === null || options === void 0 ? void 0 : options.useCache) && !id && !segmentToProcess && !handoff.force;
188
+ const shouldUseCache = !id && !segmentToProcess && !handoff.force;
191
189
  if (shouldUseCache) {
192
190
  logger_1.Logger.debug('Loading build cache...');
193
191
  cache = yield (0, cache_1.loadBuildCache)(handoff);
@@ -209,7 +207,7 @@ function processComponents(handoff, id, segmentToProcess, options) {
209
207
  logger_1.Logger.info(`Component '${componentId}': new component, will build`);
210
208
  componentsToBuild.add(componentId);
211
209
  }
212
- else if ((0, cache_1.hasComponentChanged)(cachedEntry, currentFileStates)) {
210
+ else if (yield (0, cache_1.hasComponentChanged)(cachedEntry, currentFileStates)) {
213
211
  logger_1.Logger.info(`Component '${componentId}': source files changed, will rebuild`);
214
212
  componentsToBuild.add(componentId);
215
213
  }
@@ -329,6 +327,7 @@ function processComponents(handoff, id, segmentToProcess, options) {
329
327
  }
330
328
  // Components should always have at least one preview variation.
331
329
  ensureDefaultPreview(data);
330
+ const inputs = shouldUseCache ? (0, cache_1.createBuildInputs)() : undefined;
332
331
  const runsViteBuildSteps = buildPlan.js || buildPlan.css || buildPlan.previews;
333
332
  let viteBuildStartedAtMs = 0;
334
333
  if (runsViteBuildSteps) {
@@ -337,15 +336,15 @@ function processComponents(handoff, id, segmentToProcess, options) {
337
336
  }
338
337
  // Build JS if needed (new build, validation missing, or explicit segment request).
339
338
  if (buildPlan.js) {
340
- data = yield (0, javascript_1.default)(data, handoff);
339
+ data = yield (0, javascript_1.default)(data, handoff, inputs);
341
340
  }
342
341
  // Build CSS if needed.
343
342
  if (buildPlan.css) {
344
- data = yield (0, css_1.default)(data, handoff);
343
+ data = yield (0, css_1.default)(data, handoff, inputs);
345
344
  }
346
345
  // Build previews (HTML, snapshots, etc) if needed.
347
346
  if (buildPlan.previews) {
348
- data = yield (0, html_1.default)(Object.assign(Object.assign({}, data), { previews: getBuildPreviews(data) }), handoff, components);
347
+ data = yield (0, html_1.default)(Object.assign(Object.assign({}, data), { previews: getBuildPreviews(data) }), handoff, components, inputs);
349
348
  }
350
349
  if (runsViteBuildSteps) {
351
350
  const elapsedMs = Date.now() - viteBuildStartedAtMs;
@@ -371,18 +370,19 @@ function processComponents(handoff, id, segmentToProcess, options) {
371
370
  // Add to the cumulative results, to later update the global components summary file.
372
371
  result.push(summary);
373
372
  // Update cache entry for this component after successful build
374
- if (shouldUseCache) {
373
+ if (shouldUseCache && inputs) {
375
374
  if (!cache) {
376
375
  cache = (0, cache_1.createEmptyCache)();
377
376
  }
378
- const fileStates = componentFileStatesMap.get(runtimeComponentId);
379
- if (fileStates) {
380
- (0, cache_1.updateComponentCacheEntry)(cache, runtimeComponentId, fileStates);
377
+ // Compute file states if not already computed (e.g., when global deps changed)
378
+ const fileStates = (_e = componentFileStatesMap.get(runtimeComponentId)) !== null && _e !== void 0 ? _e : (yield (0, cache_1.computeComponentFileStates)(handoff, runtimeComponentId));
379
+ const inputStates = yield (0, cache_1.computeBuildInputStates)(handoff, runtimeComponentId, inputs);
380
+ if (inputStates) {
381
+ (0, cache_1.updateComponentCacheEntry)(cache, runtimeComponentId, fileStates, inputStates);
381
382
  }
382
383
  else {
383
- // Compute file states if not already computed (e.g., when global deps changed)
384
- const computedFileStates = yield (0, cache_1.computeComponentFileStates)(handoff, runtimeComponentId);
385
- (0, cache_1.updateComponentCacheEntry)(cache, runtimeComponentId, computedFileStates);
384
+ // An incomplete list can miss a changed file, so the next run builds this component again.
385
+ delete cache.components[runtimeComponentId];
386
386
  }
387
387
  }
388
388
  }
@@ -1,8 +1,9 @@
1
+ import { BuildInputs } from '../../../cache/build-inputs';
1
2
  import Handoff from '../../../index';
2
3
  import { TransformComponentTokensResult } from '../types';
3
4
  export declare const MAIN_COMPONENT_CSS_FILE = "main.css";
4
5
  export declare const SHARED_COMPONENT_CSS_FILE = "shared.css";
5
- declare const buildComponentCss: (data: TransformComponentTokensResult, handoff: Handoff) => Promise<{
6
+ declare const buildComponentCss: (data: TransformComponentTokensResult, handoff: Handoff, inputs?: BuildInputs) => Promise<{
6
7
  id: string;
7
8
  type?: import("../types").ComponentType;
8
9
  image?: string;
@@ -16,6 +16,7 @@ exports.buildMainCss = exports.SHARED_COMPONENT_CSS_FILE = exports.MAIN_COMPONEN
16
16
  const fs_extra_1 = __importDefault(require("fs-extra"));
17
17
  const path_1 = __importDefault(require("path"));
18
18
  const vite_1 = require("vite");
19
+ const build_inputs_1 = require("../../../cache/build-inputs");
19
20
  const duration_1 = require("../../../utils/duration");
20
21
  const logger_1 = require("../../../utils/logger");
21
22
  const build_1 = require("../../utils/build");
@@ -33,8 +34,9 @@ exports.SHARED_COMPONENT_CSS_FILE = 'shared.css';
33
34
  * @param options.outputFilename - The name of the output file
34
35
  * @param options.loadPaths - Array of paths for SASS to look for imports
35
36
  * @param options.handoff - The Handoff configuration object
37
+ * @param options.inputs - Collects the files that the build reads, for the build cache
36
38
  */
37
- const buildCssBundle = (_a) => __awaiter(void 0, [_a], void 0, function* ({ entry, outputPath, outputFilename, loadPaths, handoff, }) {
39
+ const buildCssBundle = (_a) => __awaiter(void 0, [_a], void 0, function* ({ entry, outputPath, outputFilename, loadPaths, handoff, inputs, }) {
38
40
  var _b, _c;
39
41
  // Store the current NODE_ENV value
40
42
  const oldNodeEnv = process.env.NODE_ENV;
@@ -73,7 +75,7 @@ const buildCssBundle = (_a) => __awaiter(void 0, [_a], void 0, function* ({ entr
73
75
  if ((_c = (_b = handoff === null || handoff === void 0 ? void 0 : handoff.config) === null || _b === void 0 ? void 0 : _b.hooks) === null || _c === void 0 ? void 0 : _c.cssBuildConfig) {
74
76
  viteConfig = handoff.config.hooks.cssBuildConfig(viteConfig);
75
77
  }
76
- yield (0, vite_1.build)(viteConfig);
78
+ yield (0, vite_1.build)((0, build_inputs_1.withBuildInputs)(viteConfig, inputs));
77
79
  }
78
80
  catch (e) {
79
81
  logger_1.Logger.error(`Failed to build CSS for "${entry}"`);
@@ -124,7 +126,7 @@ const writeCombinedStyleEntry = (sources, outputPath, id) => __awaiter(void 0, v
124
126
  yield fs_extra_1.default.outputFile(entryPath, `${rules.join('\n')}\n`);
125
127
  return entryPath;
126
128
  });
127
- const buildComponentCss = (data, handoff) => __awaiter(void 0, void 0, void 0, function* () {
129
+ const buildComponentCss = (data, handoff, inputs) => __awaiter(void 0, void 0, void 0, function* () {
128
130
  var _a, _b, _c;
129
131
  const id = data.id;
130
132
  logger_1.Logger.debug(`buildComponentCss`, id);
@@ -154,7 +156,7 @@ const buildComponentCss = (data, handoff) => __awaiter(void 0, void 0, void 0, f
154
156
  // Setup SASS load paths
155
157
  const loadPaths = [
156
158
  path_1.default.resolve(handoff.workingPath),
157
- path_1.default.resolve(handoff.workingPath, handoff.exportsDirectory, handoff.getProjectId()),
159
+ handoff.getOutputPath(),
158
160
  path_1.default.resolve(handoff.workingPath, 'node_modules'),
159
161
  ];
160
162
  if ((_c = (_b = handoff.runtimeConfig) === null || _b === void 0 ? void 0 : _b.entries) === null || _c === void 0 ? void 0 : _c.scss) {
@@ -166,6 +168,7 @@ const buildComponentCss = (data, handoff) => __awaiter(void 0, void 0, void 0, f
166
168
  outputFilename: `${id}.css`,
167
169
  loadPaths,
168
170
  handoff,
171
+ inputs,
169
172
  });
170
173
  // Read the built CSS
171
174
  if (fs_extra_1.default.existsSync(builtCssPath)) {
@@ -217,7 +220,7 @@ const buildMainCss = (handoff) => __awaiter(void 0, void 0, void 0, function* ()
217
220
  const loadPaths = [
218
221
  path_1.default.dirname(scssEntry),
219
222
  path_1.default.resolve(handoff.workingPath),
220
- path_1.default.resolve(handoff.workingPath, handoff.exportsDirectory, handoff.getProjectId()),
223
+ handoff.getOutputPath(),
221
224
  path_1.default.resolve(handoff.workingPath, 'node_modules'),
222
225
  ];
223
226
  yield buildCssBundle({
@@ -1,4 +1,5 @@
1
1
  import { Types as CoreTypes } from 'handoff-core';
2
+ import { BuildInputs } from '../../../cache/build-inputs';
2
3
  import Handoff from '../../../index';
3
4
  import { TransformComponentTokensResult } from '../types';
4
5
  /**
@@ -7,6 +8,7 @@ import { TransformComponentTokensResult } from '../types';
7
8
  * @param data - The result of transforming component tokens.
8
9
  * @param handoff - The Handoff configuration object.
9
10
  * @param components - Optional file components object.
11
+ * @param inputs - Collects the files that the build reads, for the build cache.
10
12
  * @returns A promise that resolves to the transformed component tokens result.
11
13
  * @throws Will throw an error if the Vite build process fails.
12
14
  *
@@ -15,5 +17,5 @@ import { TransformComponentTokensResult } from '../types';
15
17
  * const result = await buildPreviews(transformedData, handoffConfig, fileComponents);
16
18
  * ```
17
19
  */
18
- export declare const buildPreviews: (data: TransformComponentTokensResult, handoff: Handoff, components?: CoreTypes.IDocumentationObject["components"]) => Promise<TransformComponentTokensResult>;
20
+ export declare const buildPreviews: (data: TransformComponentTokensResult, handoff: Handoff, components?: CoreTypes.IDocumentationObject["components"], inputs?: BuildInputs) => Promise<TransformComponentTokensResult>;
19
21
  export default buildPreviews;
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.buildPreviews = void 0;
16
16
  const plugin_react_1 = __importDefault(require("@vitejs/plugin-react"));
17
17
  const vite_1 = require("vite");
18
+ const build_inputs_1 = require("../../../cache/build-inputs");
18
19
  const logger_1 = require("../../../utils/logger");
19
20
  const plugins_1 = require("../../plugins");
20
21
  const vite_config_1 = __importDefault(require("../../vite-config"));
@@ -37,6 +38,7 @@ const RENDERER_PLUGINS = {
37
38
  * @param data - The result of transforming component tokens.
38
39
  * @param handoff - The Handoff configuration object.
39
40
  * @param components - Optional file components object.
41
+ * @param inputs - Collects the files that the build reads, for the build cache.
40
42
  * @returns A promise that resolves to the transformed component tokens result.
41
43
  * @throws Will throw an error if the Vite build process fails.
42
44
  *
@@ -45,7 +47,7 @@ const RENDERER_PLUGINS = {
45
47
  * const result = await buildPreviews(transformedData, handoffConfig, fileComponents);
46
48
  * ```
47
49
  */
48
- const buildPreviews = (data, handoff, components) => __awaiter(void 0, void 0, void 0, function* () {
50
+ const buildPreviews = (data, handoff, components, inputs) => __awaiter(void 0, void 0, void 0, function* () {
49
51
  var _a, _b, _c;
50
52
  if (!((_a = data.entries) === null || _a === void 0 ? void 0 : _a.template))
51
53
  return data;
@@ -75,9 +77,11 @@ const buildPreviews = (data, handoff, components) => __awaiter(void 0, void 0, v
75
77
  if ((_c = (_b = handoff === null || handoff === void 0 ? void 0 : handoff.config) === null || _b === void 0 ? void 0 : _b.hooks) === null || _c === void 0 ? void 0 : _c.htmlBuildConfig) {
76
78
  viteConfig = handoff.config.hooks.htmlBuildConfig(viteConfig);
77
79
  }
78
- yield (0, vite_1.build)(viteConfig);
80
+ yield (0, vite_1.build)((0, build_inputs_1.withBuildInputs)(viteConfig, inputs));
79
81
  }
80
82
  catch (error) {
83
+ if (inputs)
84
+ inputs.failed = true;
81
85
  logger_1.Logger.error(`Error building component previews: ${data.entries.template}`, error);
82
86
  }
83
87
  finally {
@@ -1,3 +1,4 @@
1
+ import { BuildInputs } from '../../../cache/build-inputs';
1
2
  import Handoff from '../../../index';
2
3
  import { TransformComponentTokensResult } from '../types';
3
4
  export declare const MAIN_COMPONENT_JS_FILE = "main.js";
@@ -10,7 +11,7 @@ export declare const MAIN_COMPONENT_JS_FILE = "main.js";
10
11
  * @param handoff - The Handoff configuration object
11
12
  * @returns The updated component transformation result with JavaScript data
12
13
  */
13
- export declare const buildComponentJs: (data: TransformComponentTokensResult, handoff: Handoff) => Promise<TransformComponentTokensResult>;
14
+ export declare const buildComponentJs: (data: TransformComponentTokensResult, handoff: Handoff, inputs?: BuildInputs) => Promise<TransformComponentTokensResult>;
14
15
  /**
15
16
  * Builds the global preview script artifact (`component/main.js`) from the configured workspace JS
16
17
  * entry.
@@ -16,6 +16,7 @@ exports.buildMainJS = exports.buildComponentJs = exports.MAIN_COMPONENT_JS_FILE
16
16
  const fs_extra_1 = __importDefault(require("fs-extra"));
17
17
  const path_1 = __importDefault(require("path"));
18
18
  const vite_1 = require("vite");
19
+ const build_inputs_1 = require("../../../cache/build-inputs");
19
20
  const duration_1 = require("../../../utils/duration");
20
21
  const logger_1 = require("../../../utils/logger");
21
22
  const vite_config_1 = __importDefault(require("../../vite-config"));
@@ -28,8 +29,9 @@ exports.MAIN_COMPONENT_JS_FILE = 'main.js';
28
29
  * @param options.entry - The entry file path for the bundle
29
30
  * @param options.outputPath - The directory where the bundle will be output
30
31
  * @param options.outputFilename - The name of the output file
32
+ * @param inputs - Collects the files that the build reads, for the build cache
31
33
  */
32
- const buildJsBundle = (_a, handoff_1) => __awaiter(void 0, [_a, handoff_1], void 0, function* ({ entry, outputPath, outputFilename, format = 'cjs', }, handoff) {
34
+ const buildJsBundle = (_a, handoff_1, inputs_1) => __awaiter(void 0, [_a, handoff_1, inputs_1], void 0, function* ({ entry, outputPath, outputFilename, format = 'cjs', }, handoff, inputs) {
33
35
  var _b, _c, _d;
34
36
  const absEntryPath = path_1.default.resolve(entry);
35
37
  // Store the current NODE_ENV value before vite build
@@ -51,7 +53,7 @@ const buildJsBundle = (_a, handoff_1) => __awaiter(void 0, [_a, handoff_1], void
51
53
  if ((_d = (_c = handoff === null || handoff === void 0 ? void 0 : handoff.config) === null || _c === void 0 ? void 0 : _c.hooks) === null || _d === void 0 ? void 0 : _d.jsBuildConfig) {
52
54
  viteConfig = handoff.config.hooks.jsBuildConfig(viteConfig);
53
55
  }
54
- yield (0, vite_1.build)(viteConfig);
56
+ yield (0, vite_1.build)((0, build_inputs_1.withBuildInputs)(viteConfig, inputs));
55
57
  }
56
58
  finally {
57
59
  // Restore the original NODE_ENV value after vite build completes
@@ -74,7 +76,7 @@ const buildJsBundle = (_a, handoff_1) => __awaiter(void 0, [_a, handoff_1], void
74
76
  * @param handoff - The Handoff configuration object
75
77
  * @returns The updated component transformation result with JavaScript data
76
78
  */
77
- const buildComponentJs = (data, handoff) => __awaiter(void 0, void 0, void 0, function* () {
79
+ const buildComponentJs = (data, handoff, inputs) => __awaiter(void 0, void 0, void 0, function* () {
78
80
  var _a;
79
81
  const id = data.id;
80
82
  const outputPath = (0, component_1.getComponentOutputPath)(handoff);
@@ -97,9 +99,11 @@ const buildComponentJs = (data, handoff) => __awaiter(void 0, void 0, void 0, fu
97
99
  entry,
98
100
  outputPath,
99
101
  outputFilename: `${id}.js`,
100
- }, handoff);
102
+ }, handoff, inputs);
101
103
  }
102
104
  catch (e) {
105
+ if (inputs)
106
+ inputs.failed = true;
103
107
  logger_1.Logger.error(`Failed to bundle JS for component "${id}" (${id}.js):`, e);
104
108
  return data;
105
109
  }
@@ -113,6 +117,8 @@ const buildComponentJs = (data, handoff) => __awaiter(void 0, void 0, void 0, fu
113
117
  }
114
118
  }
115
119
  catch (e) {
120
+ if (inputs)
121
+ inputs.failed = true;
116
122
  logger_1.Logger.error(`JS build failed for component "${id}":`, e);
117
123
  }
118
124
  return data;
@@ -15,6 +15,10 @@ export declare const STYLE_IMPORT_LOADERS: Record<string, esbuild.Loader>;
15
15
  export declare const DEFAULT_SSR_BUILD_CONFIG: esbuild.BuildOptions;
16
16
  /**
17
17
  * Default esbuild configuration for client builds
18
+ *
19
+ * Production React, minified: each client bundle carries its own React copy, and a publish uploads it
20
+ * with the component and with every pattern that uses it. A development build quickly pushes a pattern
21
+ * past serverless request body limits.
18
22
  */
19
23
  export declare const DEFAULT_CLIENT_BUILD_CONFIG: esbuild.BuildOptions;
20
24
  /** Apply after a consumer hook: a hook that replaces `loader` would otherwise drop these. */
@@ -26,6 +30,11 @@ export declare function withStyleLoaders<T extends esbuild.BuildOptions>(config:
26
30
  * declared entry.
27
31
  */
28
32
  export declare function collectStyleImports(entryPath: string, handoff: any): Promise<string[]>;
33
+ /**
34
+ * Every file in the module graph of an entry, stylesheets included, or `null` when the graph does
35
+ * not build.
36
+ */
37
+ export declare function collectModuleInputs(entryPath: string, handoff: any): Promise<string[] | null>;
29
38
  /**
30
39
  * Resolves a module from multiple search directories
31
40
  * @param id - Module ID to resolve
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.DEFAULT_CLIENT_BUILD_CONFIG = exports.DEFAULT_SSR_BUILD_CONFIG = exports.STYLE_IMPORT_LOADERS = void 0;
16
16
  exports.withStyleLoaders = withStyleLoaders;
17
17
  exports.collectStyleImports = collectStyleImports;
18
+ exports.collectModuleInputs = collectModuleInputs;
18
19
  exports.resolveModule = resolveModule;
19
20
  exports.createReactResolvePlugin = createReactResolvePlugin;
20
21
  const esbuild_1 = __importDefault(require("esbuild"));
@@ -44,6 +45,10 @@ exports.DEFAULT_SSR_BUILD_CONFIG = {
44
45
  };
45
46
  /**
46
47
  * Default esbuild configuration for client builds
48
+ *
49
+ * Production React, minified: each client bundle carries its own React copy, and a publish uploads it
50
+ * with the component and with every pattern that uses it. A development build quickly pushes a pattern
51
+ * past serverless request body limits.
47
52
  */
48
53
  exports.DEFAULT_CLIENT_BUILD_CONFIG = {
49
54
  bundle: true,
@@ -52,7 +57,8 @@ exports.DEFAULT_CLIENT_BUILD_CONFIG = {
52
57
  platform: 'browser',
53
58
  jsx: 'automatic',
54
59
  sourcemap: false,
55
- minify: false,
60
+ minify: true,
61
+ define: { 'process.env.NODE_ENV': '"production"' },
56
62
  loader: exports.STYLE_IMPORT_LOADERS,
57
63
  };
58
64
  /** Apply after a consumer hook: a hook that replaces `loader` would otherwise drop these. */
@@ -98,17 +104,33 @@ function orderStyleImports(metafile, entryPath) {
98
104
  */
99
105
  function collectStyleImports(entryPath, handoff) {
100
106
  return __awaiter(this, void 0, void 0, function* () {
101
- var _a, _b;
107
+ const metafile = yield buildModuleGraph(entryPath, handoff);
108
+ return metafile ? orderStyleImports(metafile, entryPath) : [];
109
+ });
110
+ }
111
+ /**
112
+ * Every file in the module graph of an entry, stylesheets included, or `null` when the graph does
113
+ * not build.
114
+ */
115
+ function collectModuleInputs(entryPath, handoff) {
116
+ return __awaiter(this, void 0, void 0, function* () {
117
+ const metafile = yield buildModuleGraph(entryPath, handoff);
118
+ return metafile ? Object.keys(metafile.inputs).map((input) => path_1.default.resolve(input)) : null;
119
+ });
120
+ }
121
+ function buildModuleGraph(entryPath, handoff) {
122
+ return __awaiter(this, void 0, void 0, function* () {
123
+ var _a, _b, _c;
102
124
  const baseConfig = Object.assign(Object.assign({}, exports.DEFAULT_SSR_BUILD_CONFIG), { entryPoints: [entryPath], logLevel: 'silent' });
103
125
  const hookedConfig = ((_b = (_a = handoff === null || handoff === void 0 ? void 0 : handoff.config) === null || _a === void 0 ? void 0 : _a.hooks) === null || _b === void 0 ? void 0 : _b.ssrBuildConfig) ? handoff.config.hooks.ssrBuildConfig(baseConfig) : baseConfig;
104
126
  try {
105
127
  // The `empty` loader keeps stylesheets out of the JavaScript, and the metafile still records
106
128
  // them as inputs, so the graph carries the order.
107
129
  const result = yield esbuild_1.default.build(Object.assign(Object.assign({}, withStyleLoaders(hookedConfig)), { metafile: true }));
108
- return result.metafile ? orderStyleImports(result.metafile, entryPath) : [];
130
+ return (_c = result.metafile) !== null && _c !== void 0 ? _c : null;
109
131
  }
110
- catch (_c) {
111
- return [];
132
+ catch (_d) {
133
+ return null;
112
134
  }
113
135
  });
114
136
  }