handoff-app 1.2.2-7 → 2.0.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 (351) hide show
  1. package/Changelog.md +37 -15
  2. package/README.md +372 -118
  3. package/dist/app-builder/build.d.ts +41 -2
  4. package/dist/app-builder/build.js +455 -18
  5. package/dist/app-builder/client-config.d.ts +15 -2
  6. package/dist/app-builder/client-config.js +43 -4
  7. package/dist/app-builder/config-diff/snapshot.d.ts +1 -6
  8. package/dist/app-builder/config-diff/snapshot.js +2 -9
  9. package/dist/app-builder/index.d.ts +1 -1
  10. package/dist/app-builder/index.js +3 -1
  11. package/dist/app-builder/nav-shell.d.ts +23 -0
  12. package/dist/app-builder/nav-shell.js +80 -0
  13. package/dist/app-builder/paths.js +25 -1
  14. package/dist/app-builder/static-export.d.ts +17 -0
  15. package/dist/app-builder/static-export.js +206 -0
  16. package/dist/app-builder/vercel-output.d.ts +39 -0
  17. package/dist/app-builder/vercel-output.js +259 -0
  18. package/dist/app-builder/watchers/utils.d.ts +2 -0
  19. package/dist/app-builder/watchers.d.ts +14 -4
  20. package/dist/app-builder/watchers.js +123 -28
  21. package/dist/app-builder/websocket.js +1 -1
  22. package/dist/artifacts/index.d.ts +2 -0
  23. package/dist/artifacts/index.js +16 -0
  24. package/dist/artifacts/types.d.ts +136 -0
  25. package/dist/artifacts/types.js +24 -0
  26. package/dist/artifacts/url.d.ts +67 -0
  27. package/dist/artifacts/url.js +116 -0
  28. package/dist/cache/build-cache.js +48 -4
  29. package/dist/cli.js +0 -0
  30. package/dist/commands/build/app.js +1 -2
  31. package/dist/commands/build/index.d.ts +17 -0
  32. package/dist/commands/build/index.js +66 -0
  33. package/dist/commands/checkout/index.d.ts +24 -0
  34. package/dist/commands/checkout/index.js +71 -0
  35. package/dist/commands/db/migrate.d.ts +11 -0
  36. package/dist/commands/db/migrate.js +33 -0
  37. package/dist/commands/index.js +8 -0
  38. package/dist/commands/publish/index.d.ts +21 -0
  39. package/dist/commands/publish/index.js +68 -0
  40. package/dist/config/defaults.js +15 -1
  41. package/dist/config/loader.js +6 -1
  42. package/dist/config/normalizers/declaration.js +4 -1
  43. package/dist/config/normalizers/page.d.ts +18 -0
  44. package/dist/config/normalizers/page.js +34 -0
  45. package/dist/config/normalizers/pattern.js +7 -1
  46. package/dist/config/runtime.d.ts +4 -0
  47. package/dist/config/runtime.js +53 -5
  48. package/dist/index.d.ts +65 -1
  49. package/dist/index.js +123 -3
  50. package/dist/nav/index.d.ts +83 -0
  51. package/dist/nav/index.js +9 -0
  52. package/dist/nav/registry.d.ts +15 -0
  53. package/dist/nav/registry.js +42 -0
  54. package/dist/nav/resolver.d.ts +8 -0
  55. package/dist/nav/resolver.js +192 -0
  56. package/dist/nav/workspace.d.ts +18 -0
  57. package/dist/nav/workspace.js +103 -0
  58. package/dist/pipeline/styles.js +7 -35
  59. package/dist/pipeline/token-transformers.d.ts +45 -0
  60. package/dist/pipeline/token-transformers.js +71 -0
  61. package/dist/registry/asset-storage/adapters/vercel-blob.d.ts +17 -0
  62. package/dist/registry/asset-storage/adapters/vercel-blob.js +87 -0
  63. package/dist/registry/asset-storage/define.d.ts +10 -0
  64. package/dist/registry/asset-storage/define.js +13 -0
  65. package/dist/registry/asset-storage/resolve.d.ts +45 -0
  66. package/dist/registry/asset-storage/resolve.js +36 -0
  67. package/dist/registry/asset-storage/types.d.ts +51 -0
  68. package/dist/registry/asset-storage/types.js +9 -0
  69. package/dist/registry/assets/layout.d.ts +22 -0
  70. package/dist/registry/assets/layout.js +30 -0
  71. package/dist/registry/assets/sets.d.ts +18 -0
  72. package/dist/registry/assets/sets.js +44 -0
  73. package/dist/registry/assets/transfer.d.ts +45 -0
  74. package/dist/registry/assets/transfer.js +11 -0
  75. package/dist/registry/checkout/assets.d.ts +16 -0
  76. package/dist/registry/checkout/assets.js +150 -0
  77. package/dist/registry/checkout/index.d.ts +33 -0
  78. package/dist/registry/checkout/index.js +610 -0
  79. package/dist/registry/checkout/tokens.d.ts +15 -0
  80. package/dist/registry/checkout/tokens.js +171 -0
  81. package/dist/registry/client.d.ts +61 -0
  82. package/dist/registry/client.js +211 -0
  83. package/dist/registry/connection.d.ts +30 -0
  84. package/dist/registry/connection.js +36 -0
  85. package/dist/registry/db/adapter.d.ts +43 -0
  86. package/dist/registry/db/adapter.js +59 -0
  87. package/dist/registry/db/client.d.ts +35 -0
  88. package/dist/registry/db/client.js +94 -0
  89. package/dist/registry/db/index.d.ts +5 -0
  90. package/dist/registry/db/index.js +24 -0
  91. package/dist/registry/db/migrate.d.ts +23 -0
  92. package/dist/registry/db/migrate.js +64 -0
  93. package/dist/registry/db/schema.d.ts +4869 -0
  94. package/dist/registry/db/schema.js +347 -0
  95. package/dist/registry/path.d.ts +4 -0
  96. package/dist/registry/path.js +31 -0
  97. package/dist/registry/publish/artifacts.d.ts +16 -0
  98. package/dist/registry/publish/artifacts.js +132 -0
  99. package/dist/registry/publish/assets.d.ts +16 -0
  100. package/dist/registry/publish/assets.js +129 -0
  101. package/dist/registry/publish/errors.d.ts +5 -0
  102. package/dist/registry/publish/errors.js +26 -0
  103. package/dist/registry/publish/index.d.ts +27 -0
  104. package/dist/registry/publish/index.js +126 -0
  105. package/dist/registry/publish/package.d.ts +27 -0
  106. package/dist/registry/publish/package.js +257 -0
  107. package/dist/registry/publish/publish-build.d.ts +12 -0
  108. package/dist/registry/publish/publish-build.js +43 -0
  109. package/dist/registry/publish/tokens.d.ts +18 -0
  110. package/dist/registry/publish/tokens.js +112 -0
  111. package/dist/registry/tokens/sets.d.ts +59 -0
  112. package/dist/registry/tokens/sets.js +109 -0
  113. package/dist/registry/tokens/transfer.d.ts +48 -0
  114. package/dist/registry/tokens/transfer.js +10 -0
  115. package/dist/registry/transfer.d.ts +75 -0
  116. package/dist/registry/transfer.js +11 -0
  117. package/dist/store/filesystem-assets.d.ts +17 -0
  118. package/dist/store/filesystem-assets.js +147 -0
  119. package/dist/store/filesystem.d.ts +76 -0
  120. package/dist/store/filesystem.js +208 -0
  121. package/dist/store/index.d.ts +20 -0
  122. package/dist/store/index.js +38 -0
  123. package/dist/store/registry.d.ts +77 -0
  124. package/dist/store/registry.js +350 -0
  125. package/dist/store/source-files.d.ts +24 -0
  126. package/dist/store/source-files.js +147 -0
  127. package/dist/store/types.d.ts +185 -0
  128. package/dist/store/types.js +12 -0
  129. package/dist/transformers/plugins/csf-render.js +17 -8
  130. package/dist/transformers/plugins/handlebars-previews.js +10 -3
  131. package/dist/transformers/plugins/ssr-render.js +116 -49
  132. package/dist/transformers/preview/component/api.js +3 -1
  133. package/dist/transformers/preview/component/artifacts.js +8 -1
  134. package/dist/transformers/preview/component/builder.js +13 -5
  135. package/dist/transformers/preview/component/css.js +9 -1
  136. package/dist/transformers/preview/component/javascript.d.ts +9 -3
  137. package/dist/transformers/preview/component/javascript.js +45 -17
  138. package/dist/transformers/preview/component/shared-artifacts.d.ts +83 -0
  139. package/dist/transformers/preview/component/shared-artifacts.js +92 -0
  140. package/dist/transformers/preview/component.js +5 -2
  141. package/dist/transformers/preview/pattern/builder.js +28 -9
  142. package/dist/transformers/preview/pattern/html.d.ts +13 -10
  143. package/dist/transformers/preview/pattern/html.js +62 -27
  144. package/dist/transformers/preview/types.d.ts +38 -0
  145. package/dist/transformers/utils/handlebars.d.ts +3 -0
  146. package/dist/transformers/utils/handlebars.js +19 -5
  147. package/dist/types/config.d.ts +124 -31
  148. package/dist/utils/menu-shell.d.ts +60 -0
  149. package/dist/utils/menu-shell.js +221 -0
  150. package/dist/utils/stable-stringify.d.ts +2 -0
  151. package/dist/utils/stable-stringify.js +8 -0
  152. package/docs/cli.md +4 -2
  153. package/drizzle/0000_init_registry_storage.sql +95 -0
  154. package/drizzle/0001_add_review_metadata.sql +2 -0
  155. package/drizzle/0002_add_pages.sql +28 -0
  156. package/drizzle/0003_add_tokens.sql +29 -0
  157. package/drizzle/0004_add_assets.sql +37 -0
  158. package/drizzle/meta/0000_snapshot.json +642 -0
  159. package/drizzle/meta/0001_snapshot.json +654 -0
  160. package/drizzle/meta/0002_snapshot.json +835 -0
  161. package/drizzle/meta/0003_snapshot.json +1023 -0
  162. package/drizzle/meta/0004_snapshot.json +1252 -0
  163. package/drizzle/meta/_journal.json +41 -0
  164. package/drizzle.config.ts +16 -0
  165. package/package.json +10 -1
  166. package/src/app/components/Component/Preview.tsx +3 -2
  167. package/src/app/components/Component/RegistryActions.tsx +150 -0
  168. package/src/app/components/Foundations/DisplayLogo.tsx +11 -3
  169. package/src/app/components/Layout/Header.tsx +21 -3
  170. package/src/app/components/Layout/Main.tsx +11 -3
  171. package/src/app/components/Navigation/MainNav.tsx +4 -2
  172. package/src/app/components/Navigation/MobileNav.tsx +4 -2
  173. package/src/app/components/Navigation/SideNav.tsx +46 -11
  174. package/src/app/components/NotFound.tsx +24 -0
  175. package/src/app/components/context/NavProvider.tsx +71 -0
  176. package/src/app/components/old/Header.tsx +3 -3
  177. package/src/app/components/util/index.ts +203 -380
  178. package/src/app/components/util/useCollectionAssets.ts +125 -0
  179. package/src/app/components/util/useFoundationTokens.ts +67 -0
  180. package/src/app/generated/default-pages.json +1 -0
  181. package/src/app/generated/nav-shell.json +1 -0
  182. package/src/app/lib/api/query.ts +6 -0
  183. package/src/app/lib/api/redact.ts +46 -0
  184. package/src/app/lib/asset-storage.ts +81 -0
  185. package/src/app/lib/docs-api/artifacts.ts +116 -0
  186. package/src/app/lib/docs-api/backend.ts +151 -0
  187. package/src/app/lib/docs-api/errors.ts +52 -0
  188. package/src/app/lib/docs-api/handler.ts +34 -0
  189. package/src/app/lib/docs-api/index.ts +7 -0
  190. package/src/app/lib/docs-api/records.ts +189 -0
  191. package/src/app/lib/docs-api/registry.ts +130 -0
  192. package/src/app/lib/docs-api/runtime-config.ts +173 -0
  193. package/src/app/lib/docs-api/serve.ts +37 -0
  194. package/src/app/lib/docs-api/token-detail.ts +19 -0
  195. package/src/app/lib/registry-api/allowlist.ts +163 -0
  196. package/src/app/lib/registry-api/asset-transfer.ts +363 -0
  197. package/src/app/lib/registry-api/auth.ts +68 -0
  198. package/src/app/lib/registry-api/entity-routes.ts +197 -0
  199. package/src/app/lib/registry-api/errors.ts +51 -0
  200. package/src/app/lib/registry-api/files.ts +135 -0
  201. package/src/app/lib/registry-api/handler.ts +96 -0
  202. package/src/app/lib/registry-api/index.ts +4 -0
  203. package/src/app/lib/registry-api/meta.ts +87 -0
  204. package/src/app/lib/registry-api/revalidate.ts +36 -0
  205. package/src/app/lib/registry-api/store.ts +348 -0
  206. package/src/app/lib/registry-api/token-transfer.ts +231 -0
  207. package/src/app/lib/registry-api/transfer.ts +513 -0
  208. package/src/app/lib/registry-api/validation.ts +74 -0
  209. package/src/app/lib/registry-connection.ts +58 -0
  210. package/src/app/lib/utils.ts +14 -0
  211. package/src/app/next.config.mjs +72 -13
  212. package/src/app/pages/[...slug]/index.tsx +74 -20
  213. package/src/app/pages/_app.tsx +5 -2
  214. package/src/app/pages/api/docs/artifacts/[...artifactPath].ts +16 -0
  215. package/src/app/pages/api/docs/assets/[collection]/[...path].ts +50 -0
  216. package/src/app/pages/api/docs/assets/[collection]/index.ts +22 -0
  217. package/src/app/pages/api/docs/components/[id]/assets/[asset].ts +33 -0
  218. package/src/app/pages/api/docs/components/[id]/inspect/[previewId].ts +20 -0
  219. package/src/app/pages/api/docs/components/[id]/previews/[previewId].ts +21 -0
  220. package/src/app/pages/api/docs/components/[id].ts +24 -0
  221. package/src/app/pages/api/docs/components.json.ts +12 -0
  222. package/src/app/pages/api/docs/nav.json.ts +48 -0
  223. package/src/app/pages/api/docs/patterns/[id]/preview.ts +19 -0
  224. package/src/app/pages/api/docs/patterns/[id].ts +24 -0
  225. package/src/app/pages/api/docs/patterns.json.ts +12 -0
  226. package/src/app/pages/api/docs/tokens/components/[id].ts +30 -0
  227. package/src/app/pages/api/docs/tokens/foundations/[type].ts +32 -0
  228. package/src/app/pages/api/registry/components/[id]/files/[...filePath].ts +19 -0
  229. package/src/app/pages/api/registry/components/[id]/files/index.ts +19 -0
  230. package/src/app/pages/api/registry/components/[id].ts +20 -0
  231. package/src/app/pages/api/registry/components/index.ts +19 -0
  232. package/src/app/pages/api/registry/health.ts +20 -0
  233. package/src/app/pages/api/registry/patterns/[id]/files/[...filePath].ts +19 -0
  234. package/src/app/pages/api/registry/patterns/[id]/files/index.ts +19 -0
  235. package/src/app/pages/api/registry/patterns/[id].ts +20 -0
  236. package/src/app/pages/api/registry/patterns/index.ts +19 -0
  237. package/src/app/pages/api/registry/transfer/[kind]/[id].ts +39 -0
  238. package/src/app/pages/api/registry/transfer/assets/[collection].ts +24 -0
  239. package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +23 -0
  240. package/src/app/pages/api/registry/transfer/assets/blobs/have.ts +11 -0
  241. package/src/app/pages/api/registry/transfer/assets/index.ts +10 -0
  242. package/src/app/pages/api/registry/transfer/tokens/[...setId].ts +26 -0
  243. package/src/app/pages/api/registry/transfer/tokens/index.ts +11 -0
  244. package/src/app/pages/assets/fonts.tsx +41 -17
  245. package/src/app/pages/assets/index.tsx +2 -2
  246. package/src/app/pages/assets/logos.tsx +6 -3
  247. package/src/app/pages/foundations/colors.tsx +18 -8
  248. package/src/app/pages/foundations/effects.tsx +18 -8
  249. package/src/app/pages/foundations/icons/[name]/index.tsx +28 -16
  250. package/src/app/pages/foundations/icons/index.tsx +18 -12
  251. package/src/app/pages/foundations/index.tsx +1 -1
  252. package/src/app/pages/foundations/logo.tsx +12 -8
  253. package/src/app/pages/foundations/typography.tsx +19 -9
  254. package/src/app/pages/index.tsx +1 -1
  255. package/src/app/pages/system/component/[component]/index.tsx +87 -17
  256. package/src/app/pages/system/index.tsx +13 -4
  257. package/src/app/pages/system/pattern/[pattern]/index.tsx +70 -14
  258. package/src/app/pages/system/tokens/components/[component]/index.tsx +42 -14
  259. package/src/app/pages/system/tokens/foundations/colors.tsx +7 -5
  260. package/src/app/pages/system/tokens/foundations/effects.tsx +7 -5
  261. package/src/app/pages/system/tokens/foundations/typography.tsx +8 -4
  262. package/src/app/tsconfig.json +2 -3
  263. package/src/app-builder/build.ts +555 -11
  264. package/src/app-builder/client-config.ts +61 -4
  265. package/src/app-builder/config-diff/snapshot.ts +1 -11
  266. package/src/app-builder/index.ts +1 -1
  267. package/src/app-builder/nav-shell.ts +74 -0
  268. package/src/app-builder/paths.ts +27 -1
  269. package/src/app-builder/static-export.ts +242 -0
  270. package/src/app-builder/vercel-output.ts +297 -0
  271. package/src/app-builder/watchers/utils.ts +2 -0
  272. package/src/app-builder/watchers.ts +149 -25
  273. package/src/app-builder/websocket.ts +2 -2
  274. package/src/artifacts/README.md +14 -0
  275. package/src/artifacts/index.ts +24 -0
  276. package/src/artifacts/types.ts +146 -0
  277. package/src/artifacts/url.ts +122 -0
  278. package/src/cache/build-cache.ts +47 -2
  279. package/src/commands/build/app.ts +1 -2
  280. package/src/commands/build/index.ts +61 -0
  281. package/src/commands/checkout/index.ts +66 -0
  282. package/src/commands/db/migrate.ts +25 -0
  283. package/src/commands/index.ts +8 -0
  284. package/src/commands/publish/index.ts +63 -0
  285. package/src/config/defaults.ts +15 -0
  286. package/src/config/loader.ts +10 -1
  287. package/src/config/normalizers/declaration.ts +3 -0
  288. package/src/config/normalizers/page.ts +45 -0
  289. package/src/config/normalizers/pattern.ts +4 -1
  290. package/src/config/runtime.ts +48 -2
  291. package/src/index.ts +126 -3
  292. package/src/nav/index.ts +94 -0
  293. package/src/nav/registry.ts +54 -0
  294. package/src/nav/resolver.ts +217 -0
  295. package/src/nav/workspace.ts +87 -0
  296. package/src/pipeline/styles.ts +4 -35
  297. package/src/pipeline/token-transformers.ts +97 -0
  298. package/src/registry/asset-storage/adapters/vercel-blob.ts +51 -0
  299. package/src/registry/asset-storage/define.ts +15 -0
  300. package/src/registry/asset-storage/resolve.ts +72 -0
  301. package/src/registry/asset-storage/types.ts +46 -0
  302. package/src/registry/assets/layout.ts +38 -0
  303. package/src/registry/assets/sets.ts +48 -0
  304. package/src/registry/assets/transfer.ts +50 -0
  305. package/src/registry/checkout/assets.ts +126 -0
  306. package/src/registry/checkout/index.ts +596 -0
  307. package/src/registry/checkout/tokens.ts +152 -0
  308. package/src/registry/client.ts +234 -0
  309. package/src/registry/connection.ts +50 -0
  310. package/src/registry/db/adapter.ts +74 -0
  311. package/src/registry/db/client.ts +88 -0
  312. package/src/registry/db/index.ts +35 -0
  313. package/src/registry/db/migrate.ts +56 -0
  314. package/src/registry/db/schema.ts +444 -0
  315. package/src/registry/path.ts +26 -0
  316. package/src/registry/publish/artifacts.ts +147 -0
  317. package/src/registry/publish/assets.ts +129 -0
  318. package/src/registry/publish/errors.ts +34 -0
  319. package/src/registry/publish/index.ts +128 -0
  320. package/src/registry/publish/package.ts +272 -0
  321. package/src/registry/publish/publish-build.ts +51 -0
  322. package/src/registry/publish/tokens.ts +119 -0
  323. package/src/registry/tokens/sets.ts +132 -0
  324. package/src/registry/tokens/transfer.ts +53 -0
  325. package/src/registry/transfer.ts +82 -0
  326. package/src/store/filesystem-assets.ts +152 -0
  327. package/src/store/filesystem.ts +237 -0
  328. package/src/store/index.ts +62 -0
  329. package/src/store/registry.ts +334 -0
  330. package/src/store/source-files.ts +155 -0
  331. package/src/store/types.ts +210 -0
  332. package/src/transformers/plugins/csf-render.ts +31 -7
  333. package/src/transformers/plugins/handlebars-previews.ts +22 -3
  334. package/src/transformers/plugins/ssr-render.ts +145 -57
  335. package/src/transformers/preview/component/api.ts +2 -1
  336. package/src/transformers/preview/component/artifacts.ts +10 -1
  337. package/src/transformers/preview/component/builder.ts +9 -2
  338. package/src/transformers/preview/component/css.ts +10 -1
  339. package/src/transformers/preview/component/javascript.ts +55 -20
  340. package/src/transformers/preview/component/shared-artifacts.ts +146 -0
  341. package/src/transformers/preview/component.ts +5 -2
  342. package/src/transformers/preview/pattern/builder.ts +33 -7
  343. package/src/transformers/preview/pattern/html.ts +71 -27
  344. package/src/transformers/preview/types.ts +42 -0
  345. package/src/transformers/utils/handlebars.ts +31 -5
  346. package/src/types/config.ts +129 -31
  347. package/src/utils/menu-shell.ts +241 -0
  348. package/src/utils/stable-stringify.ts +7 -0
  349. package/templates/default/package.json.tpl +1 -1
  350. package/handoff.config.js +0 -90
  351. package/src/app/components/ComponentSearch.tsx +0 -93
@@ -0,0 +1,259 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.writeRegistryVercelOutput = exports.writeStaticVercelOutput = exports.getVercelOutputPath = void 0;
16
+ const fs_extra_1 = __importDefault(require("fs-extra"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const logger_1 = require("../utils/logger");
19
+ /**
20
+ * Vercel Build Output API layout.
21
+ *
22
+ * `--package vercel` emits the Vercel Build Output API directory (`.vercel/output`) instead of the
23
+ * sites-directory deliverable. This module is the single seam that produces that layout; it is
24
+ * invoked as the final-assembly branch from the build functions and never re-stages or re-runs Next.
25
+ *
26
+ * Hard constraint: `.vercel/output` must live at the **repo root** (`handoff.workingPath`) with that
27
+ * exact name. Vercel ignores any `sitesOutputDirectory`-style override for this packaging.
28
+ */
29
+ /** Build Output API config version emitted in `.vercel/output/config.json`. */
30
+ const BUILD_OUTPUT_API_VERSION = 3;
31
+ /** Absolute path of the `.vercel/output` directory at the repo root. */
32
+ const getVercelOutputPath = (handoff) => path_1.default.resolve(handoff.workingPath, '.vercel', 'output');
33
+ exports.getVercelOutputPath = getVercelOutputPath;
34
+ /**
35
+ * Resolve the app base path exactly as `next.config.mjs`'s `resolveBasePath` does, so the emitted
36
+ * `config.json` reflects the same `basePath` the static export was built with. Empty string means no
37
+ * base path (the Build Output API omits the field rather than carrying an empty value).
38
+ */
39
+ const resolveBasePath = (rawBasePath) => {
40
+ if (!rawBasePath) {
41
+ return '';
42
+ }
43
+ const trimmed = rawBasePath.replace(/^\/+|\/+$/g, '');
44
+ return trimmed ? `/${trimmed}` : '';
45
+ };
46
+ /**
47
+ * Lay a materialized static export under `.vercel/output/static/` and write a minimal Build Output
48
+ * API v3 `config.json` carrying the app's `trailingSlash` and resolved `basePath`. Pure CDN files —
49
+ * no functions, no database.
50
+ *
51
+ * @param exportDir Absolute path of the materialized static export (the same content the static
52
+ * target writes to `out/<projectId>`).
53
+ */
54
+ const writeStaticVercelOutput = (handoff, exportDir) => __awaiter(void 0, void 0, void 0, function* () {
55
+ var _a, _b;
56
+ const outputPath = (0, exports.getVercelOutputPath)(handoff);
57
+ yield fs_extra_1.default.remove(outputPath);
58
+ yield fs_extra_1.default.ensureDir(outputPath);
59
+ // Lay the export under static/ — pure CDN files, served directly by Vercel.
60
+ const staticDir = path_1.default.join(outputPath, 'static');
61
+ yield fs_extra_1.default.copy(exportDir, staticDir, { overwrite: true });
62
+ // The staged Next app sets `trailingSlash: true` (src/app/next.config.mjs); the registry/static
63
+ // exports inherit it. Carry it and the resolved base path so the static deploy serves correct URLs.
64
+ const basePath = resolveBasePath((_b = (_a = handoff.config) === null || _a === void 0 ? void 0 : _a.app) === null || _b === void 0 ? void 0 : _b.base_path);
65
+ const config = {
66
+ version: BUILD_OUTPUT_API_VERSION,
67
+ trailingSlash: true,
68
+ };
69
+ if (basePath) {
70
+ config.basePath = basePath;
71
+ }
72
+ yield fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'config.json'), `${JSON.stringify(config, null, 2)}\n`);
73
+ logger_1.Logger.success(`Packaged static Vercel Build Output API artifact at ${outputPath} (static/ + config.json).`);
74
+ });
75
+ exports.writeStaticVercelOutput = writeStaticVercelOutput;
76
+ /**
77
+ * Node.js runtime identifier baked into the registry function's `.vc-config.json`. The `pg` adapter
78
+ * (and the Neon serverless driver in its Node fallback) need the Node.js runtime, not the edge
79
+ * runtime — this is the required baseline. Vercel resolves the patch
80
+ * version within this major; pinning the major keeps the artifact stable.
81
+ */
82
+ const VERCEL_NODE_RUNTIME = 'nodejs20.x';
83
+ /** Name (sans `.func`) of the single registry function. Served at `/` and the catch-all route. */
84
+ const REGISTRY_FUNCTION_NAME = 'index';
85
+ /** Handler file the Node launcher executes; wraps the Next standalone server as a request listener. */
86
+ const REGISTRY_FUNCTION_HANDLER = 'index.js';
87
+ /** Catch-all docs pages may be overridden by registry records and must always reach the function. */
88
+ const MUTABLE_REGISTRY_PAGE_SRC_ROUTE = '/[...slug]';
89
+ /**
90
+ * Node launcher emitted into the registry function directory. The Next `standalone` `server.js`
91
+ * binds a port via `startServer`, which is not the Vercel Node function contract (a module exporting
92
+ * a `(req, res)` request listener). This launcher reuses the exact same request pipeline that
93
+ * `startServer` boots — the router-server handler from `next/dist/server/lib/start-server` — but
94
+ * without the port bind, so it serves requests identically to `node server.js`.
95
+ *
96
+ * Why not the public `next().getRequestHandler()`: that handler resolves page/document and `/api`
97
+ * routes, but does NOT resolve on-demand `/_next/data/<buildId>/…json` requests for
98
+ * `fallback:'blocking'` pages — it 404s them. That broke client-side `<Link>` navigation to the
99
+ * component/pattern detail pages (their data fetch went to the function and came back 404, which the
100
+ * Next router then turns into a hard navigation). `getRequestHandlers` returns the full router-server
101
+ * handler (data-route resolution, dynamic param extraction, `trailingSlash` redirects), so on-demand
102
+ * data routes resolve the same way they do under the standalone server. `minimalMode:false` keeps
103
+ * the function doing full in-process routing (the catch-all route forwards everything here).
104
+ *
105
+ * Runtime mode, adapter, and the DB env-var *name* are already baked into the resolved config the
106
+ * standalone build wrote to `.next/required-server-files.json`; the connection-string value is still
107
+ * read from the named env var at request time, never baked.
108
+ */
109
+ const REGISTRY_FUNCTION_LAUNCHER = `// Generated by handoff-app (\`build --target registry --package vercel\`). Do not edit.
110
+ // Wraps the Next.js standalone server as a Vercel Build Output API Node function.
111
+ process.env.NODE_ENV = 'production';
112
+ process.chdir(__dirname);
113
+
114
+ const requiredServerFiles = require('./.next/required-server-files.json');
115
+ const nextConfig = requiredServerFiles.config;
116
+
117
+ // The standalone runtime reads its resolved config from this env var (mirrors standalone server.js).
118
+ process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig);
119
+
120
+ // require('next') first so its module hooks are installed before pulling the internal server lib,
121
+ // matching the require order of the generated standalone server.js.
122
+ require('next');
123
+ const { getRequestHandlers } = require('next/dist/server/lib/start-server');
124
+
125
+ // Initialize the router-server handler once on cold start and reuse it across warm invocations.
126
+ // This is the same handler the standalone server.js uses; it does NOT bind a port (the port bind
127
+ // lives in startServer, which we never call), so it fits the (req, res) Node function contract.
128
+ let handlersPromise;
129
+ const ready = () =>
130
+ (handlersPromise =
131
+ handlersPromise ||
132
+ getRequestHandlers({
133
+ dir: __dirname,
134
+ port: parseInt(process.env.PORT, 10) || 3000,
135
+ hostname: process.env.HOSTNAME || 'localhost',
136
+ isDev: false,
137
+ minimalMode: false,
138
+ }));
139
+
140
+ module.exports = async (req, res) => {
141
+ const { requestHandler } = await ready();
142
+ return requestHandler(req, res);
143
+ };
144
+ `;
145
+ /**
146
+ * Copy the genuinely-static prerendered pages into the Edge CDN layer (`static/`) so their HTML and
147
+ * `_next/data` JSON are served directly by the CDN instead of invoking the single registry function.
148
+ * This is a load/latency optimization, not a correctness requirement: the function (see the launcher)
149
+ * now resolves on-demand data routes itself, so anything not copied here still resolves via the
150
+ * catch-all.
151
+ *
152
+ * Routes materialized from the mutable docs catch-all also appear in `routes` when package defaults
153
+ * are prerendered. They are identified by `srcRoute` and deliberately left behind the function so a
154
+ * published DB record can override the fallback. Other `fallback:'blocking'` dynamic routes are
155
+ * absent and naturally reach the function. Immutable pages — e.g. the header's `<Link href="/">`
156
+ * prefetch of `/_next/data/<buildId>/index.json` — are served straight from the CDN.
157
+ *
158
+ * No-op when nothing is prerendered (empty `routes`). Paths are emitted base-path-less, matching the
159
+ * existing `_next/static` copy and the registry route table.
160
+ */
161
+ const copyPrerenderedStaticPages = (appPath, staticOutDir) => __awaiter(void 0, void 0, void 0, function* () {
162
+ var _a;
163
+ const nextDir = path_1.default.resolve(appPath, '.next');
164
+ const manifestPath = path_1.default.join(nextDir, 'prerender-manifest.json');
165
+ const buildIdPath = path_1.default.join(nextDir, 'BUILD_ID');
166
+ if (!fs_extra_1.default.existsSync(manifestPath) || !fs_extra_1.default.existsSync(buildIdPath)) {
167
+ return;
168
+ }
169
+ const manifest = (yield fs_extra_1.default.readJson(manifestPath));
170
+ const routes = (_a = manifest.routes) !== null && _a !== void 0 ? _a : {};
171
+ const serverPages = path_1.default.join(nextDir, 'server', 'pages');
172
+ let copied = 0;
173
+ for (const [route, routeConfig] of Object.entries(routes)) {
174
+ // A static copy would win at the Build Output API filesystem route and permanently hide a
175
+ // published override (and its on-demand revalidation) from the registry function.
176
+ if (routeConfig.srcRoute === MUTABLE_REGISTRY_PAGE_SRC_ROUTE) {
177
+ continue;
178
+ }
179
+ // `.next/server/pages/<rel>.{html,json}` — `/` maps to `index`, nested routes keep their path.
180
+ const rel = route === '/' ? 'index' : route.replace(/^\/+/, '');
181
+ const htmlSrc = path_1.default.join(serverPages, `${rel}.html`);
182
+ const jsonSrc = path_1.default.join(serverPages, `${rel}.json`);
183
+ if (fs_extra_1.default.existsSync(htmlSrc)) {
184
+ // trailingSlash:true → serve as `<route>/index.html`; `/` → `static/index.html`.
185
+ const htmlDestDir = route === '/' ? staticOutDir : path_1.default.join(staticOutDir, rel);
186
+ yield fs_extra_1.default.ensureDir(htmlDestDir);
187
+ yield fs_extra_1.default.copy(htmlSrc, path_1.default.join(htmlDestDir, 'index.html'), { overwrite: true });
188
+ }
189
+ // The data URL (with the build's BUILD_ID baked in) comes from the manifest's `dataRoute`.
190
+ const dataRoute = routeConfig.dataRoute;
191
+ if (dataRoute && fs_extra_1.default.existsSync(jsonSrc)) {
192
+ const jsonDest = path_1.default.join(staticOutDir, dataRoute.replace(/^\/+/, ''));
193
+ yield fs_extra_1.default.ensureDir(path_1.default.dirname(jsonDest));
194
+ yield fs_extra_1.default.copy(jsonSrc, jsonDest, { overwrite: true });
195
+ copied += 1;
196
+ }
197
+ }
198
+ logger_1.Logger.info(`Copied ${copied} prerendered static page data file(s) into the Edge CDN layer.`);
199
+ });
200
+ /**
201
+ * Package the dynamic registry app as the Vercel Build Output API directory. Lays the traced
202
+ * standalone bundle into a single Node function (`functions/index.func/`)
203
+ * wrapping the Next standalone server, copies the immutable static assets + public tree under
204
+ * `static/` for the Edge CDN, and writes a route table that serves static files first and routes
205
+ * everything else (SSR pages, the docs read API, the registry API) to the function.
206
+ *
207
+ * Hard constraint: `.vercel/output` lives at the repo root with that exact name (see module header).
208
+ */
209
+ const writeRegistryVercelOutput = (handoff, options) => __awaiter(void 0, void 0, void 0, function* () {
210
+ const { appPath, standaloneRoot, assembleStandalone } = options;
211
+ const outputPath = (0, exports.getVercelOutputPath)(handoff);
212
+ yield fs_extra_1.default.remove(outputPath);
213
+ yield fs_extra_1.default.ensureDir(outputPath);
214
+ // The function directory *is* the standalone bundle root: the traced server + node_modules, the
215
+ // server entry flattened to its root, and `.next/static` + public + runtime config beside it. The
216
+ // launcher constructs a NextServer from this directory, so it needs the full standalone layout.
217
+ const functionDir = path_1.default.join(outputPath, 'functions', `${REGISTRY_FUNCTION_NAME}.func`);
218
+ yield fs_extra_1.default.ensureDir(functionDir);
219
+ yield assembleStandalone(handoff, appPath, standaloneRoot, functionDir);
220
+ // The standalone `server.js` binds a port; replace the entry with the Build Output API Node
221
+ // launcher (a `(req, res)` request listener) and declare the Node runtime so the pg/Neon drivers
222
+ // work. `server.js` is left in place (harmless, unused) to keep the bundle a valid standalone too.
223
+ yield fs_extra_1.default.writeFile(path_1.default.join(functionDir, REGISTRY_FUNCTION_HANDLER), REGISTRY_FUNCTION_LAUNCHER);
224
+ const functionConfig = {
225
+ runtime: VERCEL_NODE_RUNTIME,
226
+ handler: REGISTRY_FUNCTION_HANDLER,
227
+ launcherType: 'Nodejs',
228
+ };
229
+ yield fs_extra_1.default.writeFile(path_1.default.join(functionDir, '.vc-config.json'), `${JSON.stringify(functionConfig, null, 2)}\n`);
230
+ // Serve the app's immutable assets straight from the Edge CDN. `_next/static` is content-hashed and
231
+ // public files sit at the URL root; copying them under `static/` lets the route table satisfy them
232
+ // via `handle: filesystem` before the catch-all reaches the function.
233
+ const staticOutDir = path_1.default.join(outputPath, 'static');
234
+ yield fs_extra_1.default.ensureDir(staticOutDir);
235
+ const nextStaticSrc = path_1.default.resolve(appPath, '.next', 'static');
236
+ if (fs_extra_1.default.existsSync(nextStaticSrc)) {
237
+ yield fs_extra_1.default.copy(nextStaticSrc, path_1.default.join(staticOutDir, '_next', 'static'), { overwrite: true });
238
+ }
239
+ const publicSrc = path_1.default.resolve(appPath, 'public');
240
+ if (fs_extra_1.default.existsSync(publicSrc)) {
241
+ yield fs_extra_1.default.copy(publicSrc, staticOutDir, { overwrite: true });
242
+ }
243
+ // Serve genuinely-static prerendered pages (HTML + `_next/data` JSON) from the CDN as an
244
+ // optimization so they skip the function. Dynamic `fallback:'blocking'` pages are not copied (their
245
+ // data is live), and the function now resolves their on-demand `_next/data` routes itself.
246
+ yield copyPrerenderedStaticPages(appPath, staticOutDir);
247
+ // Route table: try static files first (`handle: filesystem` serves anything copied into static/),
248
+ // then route every remaining request — SSR/on-demand pages, their `/_next/data/*` routes,
249
+ // /api/docs/*, /api/registry/* — to the single function. The `.func` suffix is dropped from the
250
+ // URL, so `index.func` is reached via `/index`.
251
+ const config = {
252
+ version: BUILD_OUTPUT_API_VERSION,
253
+ routes: [{ handle: 'filesystem' }, { src: '/(.*)', dest: `/${REGISTRY_FUNCTION_NAME}` }],
254
+ };
255
+ yield fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'config.json'), `${JSON.stringify(config, null, 2)}\n`);
256
+ logger_1.Logger.success(`Packaged registry Vercel Build Output API artifact at ${outputPath} ` +
257
+ `(functions/${REGISTRY_FUNCTION_NAME}.func + static/ + config.json).`);
258
+ });
259
+ exports.writeRegistryVercelOutput = writeRegistryVercelOutput;
@@ -5,6 +5,8 @@ export interface WatcherState {
5
5
  runtimeComponentsWatcher: chokidar.FSWatcher | null;
6
6
  runtimeConfigurationWatcher: chokidar.FSWatcher | null;
7
7
  componentDirectoriesWatcher: chokidar.FSWatcher | null;
8
+ /** Watches entries.patterns parent directories for newly created pattern subdirectories. */
9
+ patternDirectoriesWatcher: chokidar.FSWatcher | null;
8
10
  }
9
11
  /**
10
12
  * Schedules a handler for execution with mutual exclusion and per-source
@@ -36,9 +36,19 @@ export declare const watchRuntimeComponents: (handoff: Handoff, state: WatcherSt
36
36
  */
37
37
  export declare const watchRuntimeConfiguration: (handoff: Handoff, state: WatcherState) => void;
38
38
  /**
39
- * Watches the parent component directories from config.entries.components
40
- * for new components being added. When a new config file (e.g. button.json)
41
- * appears in a new subdirectory, reloads the runtime config and restarts
42
- * the component/configuration watchers so the new component is picked up.
39
+ * Watches the parent component directories from config.entries.components for
40
+ * new components being added. When a new config file appears in a new
41
+ * subdirectory, reloads the runtime config, restarts the component and
42
+ * configuration watchers, then builds the new component and any patterns that
43
+ * reference it.
43
44
  */
44
45
  export declare const watchComponentDirectories: (handoff: Handoff, state: WatcherState, chokidarConfig: chokidar.WatchOptions) => void;
46
+ /**
47
+ * Watches the parent pattern directories from config.entries.patterns for new
48
+ * patterns being added. The rebuild sequence intentionally differs from
49
+ * watchComponentDirectories because the dependency arrow is reversed: a new
50
+ * pattern references existing components, so we rebuild only the preview
51
+ * segment of those components (to produce the __pattern_* HTML files that
52
+ * injectPatternPreviews registered) before composing the pattern itself.
53
+ */
54
+ export declare const watchPatternDirectories: (handoff: Handoff, state: WatcherState, chokidarConfig: chokidar.WatchOptions) => void;
@@ -35,10 +35,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.watchComponentDirectories = exports.watchRuntimeConfiguration = exports.watchRuntimeComponents = exports.watchGlobalEntries = exports.watchPages = exports.watchAppSource = exports.watchPublicDirectory = exports.mapEntryTypeToSegment = exports.getRuntimeComponentsPathsToWatch = void 0;
38
+ exports.watchPatternDirectories = exports.watchComponentDirectories = exports.watchRuntimeConfiguration = exports.watchRuntimeComponents = exports.watchGlobalEntries = exports.watchPages = exports.watchAppSource = exports.watchPublicDirectory = exports.mapEntryTypeToSegment = exports.getRuntimeComponentsPathsToWatch = void 0;
39
39
  const chokidar_1 = __importDefault(require("chokidar"));
40
40
  const fs_extra_1 = __importDefault(require("fs-extra"));
41
41
  const path_1 = __importDefault(require("path"));
42
+ const patterns_1 = require("../pipeline/patterns");
42
43
  const builder_1 = __importStar(require("../transformers/preview/component/builder"));
43
44
  const css_1 = require("../transformers/preview/component/css");
44
45
  const javascript_1 = require("../transformers/preview/component/javascript");
@@ -226,6 +227,15 @@ const watchRuntimeComponents = (handoff, state, runtimeComponentPathsToWatch) =>
226
227
  }
227
228
  };
228
229
  exports.watchRuntimeComponents = watchRuntimeComponents;
230
+ const rebuildPatternComponentPreviews = (handoff, patternId) => __awaiter(void 0, void 0, void 0, function* () {
231
+ var _a, _b, _c, _d;
232
+ const pattern = (_c = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.patterns) === null || _c === void 0 ? void 0 : _c[patternId];
233
+ if (!((_d = pattern === null || pattern === void 0 ? void 0 : pattern.components) === null || _d === void 0 ? void 0 : _d.length))
234
+ return;
235
+ for (const ref of pattern.components) {
236
+ yield (0, builder_1.default)(handoff, ref.id, builder_1.ComponentSegment.Previews);
237
+ }
238
+ });
229
239
  /**
230
240
  * Watches the runtime configuration for changes.
231
241
  *
@@ -269,6 +279,9 @@ const watchRuntimeConfiguration = (handoff, state) => {
269
279
  else if (handle) {
270
280
  yield handle.apply(handoff, entryAfter === null || entryAfter === void 0 ? void 0 : entryAfter.entityId);
271
281
  }
282
+ else if ((entryAfter === null || entryAfter === void 0 ? void 0 : entryAfter.kind) === 'pattern') {
283
+ yield rebuildPatternComponentPreviews(handoff, entryAfter.entityId);
284
+ }
272
285
  else {
273
286
  const effectiveId = (_a = entryAfter === null || entryAfter === void 0 ? void 0 : entryAfter.entityId) !== null && _a !== void 0 ? _a : path_1.default.basename(path_1.default.dirname(changedFile));
274
287
  yield (0, builder_1.default)(handoff, effectiveId);
@@ -286,56 +299,138 @@ const watchRuntimeConfiguration = (handoff, state) => {
286
299
  };
287
300
  exports.watchRuntimeConfiguration = watchRuntimeConfiguration;
288
301
  /**
289
- * Watches the parent component directories from config.entries.components
290
- * for new components being added. When a new config file (e.g. button.json)
291
- * appears in a new subdirectory, reloads the runtime config and restarts
292
- * the component/configuration watchers so the new component is picked up.
302
+ * Shared factory for watching a parent directory for newly created entity
303
+ * subdirectories (components or patterns). Handles the common scaffolding so
304
+ * that callers only describe what differs for their entity kind:
305
+ *
306
+ * - which config-entry paths to watch
307
+ * - how to read the current known ids after a reload
308
+ * - which WatcherState slot to use
309
+ * - a log label for the entity kind
310
+ * - the rebuild work to run once the runtime config is fresh
293
311
  */
294
- const watchComponentDirectories = (handoff, state, chokidarConfig) => {
295
- var _a, _b, _c, _d, _e;
296
- if (state.componentDirectoriesWatcher) {
297
- state.componentDirectoriesWatcher.close();
312
+ const watchEntityDirectories = (handoff, state, chokidarConfig, options) => {
313
+ const { getConfigPaths, getKnownIds, getWatcher, setWatcher, scheduleKeyPrefix, entityLabel, onDetected } = options;
314
+ const existingWatcher = getWatcher(state);
315
+ if (existingWatcher) {
316
+ existingWatcher.close();
298
317
  }
299
- const componentPaths = (_b = (_a = handoff.config.entries) === null || _a === void 0 ? void 0 : _a.components) !== null && _b !== void 0 ? _b : [];
300
- if (componentPaths.length === 0)
318
+ const configPaths = getConfigPaths(handoff);
319
+ if (configPaths.length === 0)
301
320
  return;
302
321
  const dirsToWatch = [];
303
- for (const componentPath of componentPaths) {
304
- const resolved = path_1.default.resolve(handoff.workingPath, componentPath);
322
+ for (const configPath of configPaths) {
323
+ const resolved = path_1.default.resolve(handoff.workingPath, configPath);
305
324
  if (fs_extra_1.default.existsSync(resolved) && fs_extra_1.default.statSync(resolved).isDirectory()) {
306
325
  dirsToWatch.push(resolved);
307
326
  }
308
327
  }
309
328
  if (dirsToWatch.length === 0)
310
329
  return;
311
- const knownComponents = new Set(Object.keys((_e = (_d = (_c = handoff.runtimeConfig) === null || _c === void 0 ? void 0 : _c.entries) === null || _d === void 0 ? void 0 : _d.components) !== null && _e !== void 0 ? _e : {}));
312
- state.componentDirectoriesWatcher = chokidar_1.default.watch(dirsToWatch, Object.assign(Object.assign({}, chokidarConfig), { depth: 1 }));
313
- state.componentDirectoriesWatcher.on('add', (file) => __awaiter(void 0, void 0, void 0, function* () {
330
+ // Snapshot known ids at watch startup so we only react to genuinely new
331
+ // entities, not to file changes inside already-known directories.
332
+ const knownIds = new Set(getKnownIds(handoff));
333
+ const watcher = chokidar_1.default.watch(dirsToWatch, Object.assign(Object.assign({}, chokidarConfig), { depth: 1 }));
334
+ setWatcher(state, watcher);
335
+ watcher.on('add', (file) => __awaiter(void 0, void 0, void 0, function* () {
314
336
  const basename = path_1.default.basename(file);
315
337
  const dirName = path_1.default.basename(path_1.default.dirname(file));
316
- const isConfigFile = basename.endsWith('.json') || basename.endsWith('.js') || basename.endsWith('.cjs');
317
- const isNewComponent = isConfigFile && basename.startsWith(dirName) && !knownComponents.has(dirName);
318
- if (!isNewComponent)
338
+ // Only react to the primary declaration file for the directory (e.g.
339
+ // button.json, button.js, or button.handoff.ts inside a button/ subdir).
340
+ // The basename.startsWith(dirName) guard below ensures .ts here only
341
+ // ever matches files named after their parent directory, not arbitrary
342
+ // TypeScript source files.
343
+ const isConfigFile = basename.endsWith('.json') || basename.endsWith('.js') || basename.endsWith('.cjs') || basename.endsWith('.ts');
344
+ const isNewEntity = isConfigFile && basename.startsWith(dirName) && !knownIds.has(dirName);
345
+ if (!isNewEntity)
319
346
  return;
320
- yield (0, utils_1.scheduleHandler)(state, `newComponent:${dirName}`, () => __awaiter(void 0, void 0, void 0, function* () {
321
- var _a, _b, _c;
347
+ yield (0, utils_1.scheduleHandler)(state, `${scheduleKeyPrefix}:${dirName}`, () => __awaiter(void 0, void 0, void 0, function* () {
322
348
  try {
323
- logger_1.Logger.warn(`New component detected: ${dirName}. Reloading configuration...`);
349
+ logger_1.Logger.warn(`New ${entityLabel} detected: ${dirName}. Reloading configuration...`);
350
+ // Snapshot ids before reload so we can tell whether the new entity
351
+ // was successfully registered afterwards.
352
+ const idsBefore = new Set(getKnownIds(handoff));
324
353
  handoff.reload();
325
- knownComponents.add(dirName);
326
- for (const id of Object.keys((_c = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.components) !== null && _c !== void 0 ? _c : {})) {
327
- knownComponents.add(id);
354
+ // Refresh from the post-reload runtime config so any ids that were
355
+ // discovered alongside the new entity are also marked as known.
356
+ const idsAfter = getKnownIds(handoff);
357
+ const addedIds = idsAfter.filter((id) => !idsBefore.has(id));
358
+ for (const id of idsAfter) {
359
+ knownIds.add(id);
328
360
  }
329
361
  yield (0, client_config_1.persistClientConfig)(handoff);
362
+ // Re-register file watchers so the new config file and any runtime
363
+ // files it introduces are covered going forward. This must happen even
364
+ // when the file failed to parse so that watchRuntimeConfiguration can
365
+ // trigger a retry the moment the file is saved with valid content.
330
366
  (0, exports.watchRuntimeComponents)(handoff, state, (0, component_1.getRuntimeComponentsPathsToWatch)(handoff));
331
367
  (0, exports.watchRuntimeConfiguration)(handoff, state);
332
- yield (0, builder_1.default)(handoff, dirName);
333
- yield (0, config_diff_1.runAllFinalizers)(handoff, { patternRebuildComponentIds: [dirName] });
368
+ // If no new ids appeared after reload the file was empty or invalid.
369
+ // Skip the build — watchRuntimeConfiguration will fire when it is saved.
370
+ if (addedIds.length === 0) {
371
+ logger_1.Logger.warn(`${entityLabel} "${dirName}" config is empty or incomplete — build will run automatically once the file is saved.`);
372
+ return;
373
+ }
374
+ yield onDetected(handoff, { dirName, addedIds });
334
375
  }
335
376
  catch (e) {
336
- logger_1.Logger.error('Error processing new component:', e);
377
+ logger_1.Logger.error(`Error processing new ${entityLabel}:`, e);
337
378
  }
338
379
  }));
339
380
  }));
340
381
  };
382
+ /**
383
+ * Watches the parent component directories from config.entries.components for
384
+ * new components being added. When a new config file appears in a new
385
+ * subdirectory, reloads the runtime config, restarts the component and
386
+ * configuration watchers, then builds the new component and any patterns that
387
+ * reference it.
388
+ */
389
+ const watchComponentDirectories = (handoff, state, chokidarConfig) => {
390
+ watchEntityDirectories(handoff, state, chokidarConfig, {
391
+ getConfigPaths: (h) => { var _a, _b; return (_b = (_a = h.config.entries) === null || _a === void 0 ? void 0 : _a.components) !== null && _b !== void 0 ? _b : []; },
392
+ getKnownIds: (h) => { var _a, _b, _c; return Object.keys((_c = (_b = (_a = h.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.components) !== null && _c !== void 0 ? _c : {}); },
393
+ getWatcher: (s) => s.componentDirectoriesWatcher,
394
+ setWatcher: (s, w) => { s.componentDirectoriesWatcher = w; },
395
+ scheduleKeyPrefix: 'newComponent',
396
+ entityLabel: 'component',
397
+ onDetected: (handoff_1, _a) => __awaiter(void 0, [handoff_1, _a], void 0, function* (handoff, { addedIds }) {
398
+ for (const componentId of addedIds) {
399
+ yield (0, builder_1.default)(handoff, componentId);
400
+ yield (0, config_diff_1.runAllFinalizers)(handoff, { patternRebuildComponentIds: [componentId] });
401
+ }
402
+ }),
403
+ });
404
+ };
341
405
  exports.watchComponentDirectories = watchComponentDirectories;
406
+ /**
407
+ * Watches the parent pattern directories from config.entries.patterns for new
408
+ * patterns being added. The rebuild sequence intentionally differs from
409
+ * watchComponentDirectories because the dependency arrow is reversed: a new
410
+ * pattern references existing components, so we rebuild only the preview
411
+ * segment of those components (to produce the __pattern_* HTML files that
412
+ * injectPatternPreviews registered) before composing the pattern itself.
413
+ */
414
+ const watchPatternDirectories = (handoff, state, chokidarConfig) => {
415
+ watchEntityDirectories(handoff, state, chokidarConfig, {
416
+ getConfigPaths: (h) => { var _a, _b; return (_b = (_a = h.config.entries) === null || _a === void 0 ? void 0 : _a.patterns) !== null && _b !== void 0 ? _b : []; },
417
+ getKnownIds: (h) => { var _a, _b, _c; return Object.keys((_c = (_b = (_a = h.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.patterns) !== null && _c !== void 0 ? _c : {}); },
418
+ getWatcher: (s) => s.patternDirectoriesWatcher,
419
+ setWatcher: (s, w) => { s.patternDirectoriesWatcher = w; },
420
+ scheduleKeyPrefix: 'newPattern',
421
+ entityLabel: 'pattern',
422
+ onDetected: (handoff_1, _a) => __awaiter(void 0, [handoff_1, _a], void 0, function* (handoff, { addedIds }) {
423
+ // Rebuild only the previews segment for each component the new pattern
424
+ // references. Their JS/CSS/structure are unchanged — only the new
425
+ // synthetic preview HTML files need to be generated so that buildPatterns
426
+ // can assemble the pattern from them.
427
+ for (const patternId of addedIds) {
428
+ yield rebuildPatternComponentPreviews(handoff, patternId);
429
+ }
430
+ // Build only the new pattern directly rather than going through
431
+ // runAllFinalizers, which would rebuild all patterns unnecessarily.
432
+ yield (0, patterns_1.buildPatterns)(handoff, { onlyPatternIds: new Set(addedIds) });
433
+ }),
434
+ });
435
+ };
436
+ exports.watchPatternDirectories = watchPatternDirectories;
@@ -21,7 +21,7 @@ const logger_1 = require("../utils/logger");
21
21
  */
22
22
  const createWebSocketServer = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (port = 3001) {
23
23
  logger_1.Logger.info(`Starting WebSocket server for live reload on port ${port}…`);
24
- const wss = new ws_1.WebSocket.Server({ port });
24
+ const wss = new ws_1.WebSocketServer({ port });
25
25
  wss.on('listening', () => {
26
26
  logger_1.Logger.info(`WebSocket server listening on ws://localhost:${port} (live reload)`);
27
27
  });
@@ -0,0 +1,2 @@
1
+ export { ARTIFACT_METADATA_PATH, REACT_PREVIEW_FORMAT_VERSION, SHARED_MAIN_CSS_ARTIFACT_PATH, SHARED_MAIN_JS_ARTIFACT_PATH, SHARED_STYLES_CSS_ARTIFACT_PATH, type ArtifactBuildMetadata, type ArtifactBuildStatus, type ArtifactDescriptor, type ArtifactKind, type ArtifactOwnerKind, type ArtifactReference, type ArtifactReferenceKind, type ArtifactSizeDiagnostics, } from './types';
2
+ export { ARTIFACTS_ROUTE_SEGMENT, ASSETS_ROUTE_SEGMENT, buildArtifactUrl, buildAssetDownloadUrl, buildAssetUrl, normalizeBasePath, } from './url';
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeBasePath = exports.buildAssetUrl = exports.buildAssetDownloadUrl = exports.buildArtifactUrl = exports.ASSETS_ROUTE_SEGMENT = exports.ARTIFACTS_ROUTE_SEGMENT = exports.SHARED_STYLES_CSS_ARTIFACT_PATH = exports.SHARED_MAIN_JS_ARTIFACT_PATH = exports.SHARED_MAIN_CSS_ARTIFACT_PATH = exports.REACT_PREVIEW_FORMAT_VERSION = exports.ARTIFACT_METADATA_PATH = void 0;
4
+ var types_1 = require("./types");
5
+ Object.defineProperty(exports, "ARTIFACT_METADATA_PATH", { enumerable: true, get: function () { return types_1.ARTIFACT_METADATA_PATH; } });
6
+ Object.defineProperty(exports, "REACT_PREVIEW_FORMAT_VERSION", { enumerable: true, get: function () { return types_1.REACT_PREVIEW_FORMAT_VERSION; } });
7
+ Object.defineProperty(exports, "SHARED_MAIN_CSS_ARTIFACT_PATH", { enumerable: true, get: function () { return types_1.SHARED_MAIN_CSS_ARTIFACT_PATH; } });
8
+ Object.defineProperty(exports, "SHARED_MAIN_JS_ARTIFACT_PATH", { enumerable: true, get: function () { return types_1.SHARED_MAIN_JS_ARTIFACT_PATH; } });
9
+ Object.defineProperty(exports, "SHARED_STYLES_CSS_ARTIFACT_PATH", { enumerable: true, get: function () { return types_1.SHARED_STYLES_CSS_ARTIFACT_PATH; } });
10
+ var url_1 = require("./url");
11
+ Object.defineProperty(exports, "ARTIFACTS_ROUTE_SEGMENT", { enumerable: true, get: function () { return url_1.ARTIFACTS_ROUTE_SEGMENT; } });
12
+ Object.defineProperty(exports, "ASSETS_ROUTE_SEGMENT", { enumerable: true, get: function () { return url_1.ASSETS_ROUTE_SEGMENT; } });
13
+ Object.defineProperty(exports, "buildArtifactUrl", { enumerable: true, get: function () { return url_1.buildArtifactUrl; } });
14
+ Object.defineProperty(exports, "buildAssetDownloadUrl", { enumerable: true, get: function () { return url_1.buildAssetDownloadUrl; } });
15
+ Object.defineProperty(exports, "buildAssetUrl", { enumerable: true, get: function () { return url_1.buildAssetUrl; } });
16
+ Object.defineProperty(exports, "normalizeBasePath", { enumerable: true, get: function () { return url_1.normalizeBasePath; } });