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
@@ -1,4 +1,5 @@
1
1
  'use client';
2
+ import { buildArtifactUrl } from '@handoff/artifacts/url';
2
3
  import { PatternListObject } from '@handoff/transformers/preview/types';
3
4
  import { startCase } from 'lodash';
4
5
  import React, { useCallback, useEffect, useState } from 'react';
@@ -7,6 +8,7 @@ import rehypeRaw from 'rehype-raw';
7
8
  import Layout from '../../../../components/Layout/Main';
8
9
  import { MarkdownComponents } from '../../../../components/Markdown/MarkdownComponents';
9
10
  import PrevNextNav from '../../../../components/Navigation/PrevNextNav';
11
+ import NotFound from '../../../../components/NotFound';
10
12
  import HeadersType from '../../../../components/Typography/Headers';
11
13
  import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '../../../../components/ui/accordion';
12
14
  import { Badge } from '../../../../components/ui/badge';
@@ -15,9 +17,9 @@ import {
15
17
  DocumentationProps,
16
18
  fetchPatterns,
17
19
  getClientRuntimeConfig,
18
- getCurrentSection,
20
+ getNavProps,
19
21
  IParams,
20
- staticBuildMenu,
22
+ isRegistryRuntime,
21
23
  } from '../../../../components/util';
22
24
 
23
25
  type PatternNavItem = { id: string; title: string; description: string; group: string };
@@ -89,18 +91,29 @@ const getArgSummary = (args?: Record<string, unknown>) => {
89
91
  };
90
92
 
91
93
  export async function getStaticPaths() {
94
+ // Registry content is mutable at runtime and may be empty/unreachable at build time, so resolve
95
+ // pattern pages on demand against the live DB instead of freezing the path list to the build
96
+ // snapshot. The static-export target stays fully prerendered (`fallback: false`).
97
+ if (isRegistryRuntime()) {
98
+ return { paths: [], fallback: 'blocking' as const };
99
+ }
92
100
  return {
93
- paths: fetchPatterns()?.map((p) => ({ params: { pattern: p.id } })) ?? [],
101
+ paths: (await fetchPatterns()).map((p) => ({ params: { pattern: p.id } })),
94
102
  fallback: false,
95
103
  };
96
104
  }
97
105
 
98
106
  export const getStaticProps = async (context: { params: IParams }) => {
99
107
  const { pattern: patternId } = context.params;
100
- const patterns = fetchPatterns() ?? [];
101
- const menu = staticBuildMenu();
102
- const config = getClientRuntimeConfig();
108
+ const patterns = await fetchPatterns();
103
109
  const patternData = patterns.find((p) => p.id === patternId);
110
+ // Under `fallback: 'blocking'` this runs on demand for arbitrary ids; surface a real 404 for ids
111
+ // that do not exist in the active mode.
112
+ if (!patternData) {
113
+ return { notFound: true };
114
+ }
115
+ const navProps = await getNavProps('/system');
116
+ const config = getClientRuntimeConfig();
104
117
 
105
118
  const sameGroupPatterns = patterns.filter((p) => p.group === patternData?.group);
106
119
  const groupIndex = sameGroupPatterns.findIndex((p) => p.id === patternId);
@@ -112,9 +125,8 @@ export const getStaticProps = async (context: { params: IParams }) => {
112
125
  return {
113
126
  props: {
114
127
  id: patternId,
115
- menu,
128
+ ...navProps,
116
129
  config,
117
- current: getCurrentSection(menu, '/system') ?? [],
118
130
  metadata: {
119
131
  title: fallbackTitle,
120
132
  description: patternData?.description || '',
@@ -130,6 +142,7 @@ export const getStaticProps = async (context: { params: IParams }) => {
130
142
  const PatternPage = ({ menu, metadata, current, id, config, previousPattern, nextPattern }: PatternPageProps) => {
131
143
  const [pattern, setPattern] = useState<PatternListObject | undefined>(undefined);
132
144
  const [fetchError, setFetchError] = useState<string | undefined>(undefined);
145
+ const [patternNotFound, setPatternNotFound] = useState(false);
133
146
  const [iframeHeight, setIframeHeight] = useState('400px');
134
147
  const iframeRef = React.useRef<HTMLIFrameElement>(null);
135
148
 
@@ -145,13 +158,20 @@ const PatternPage = ({ menu, metadata, current, id, config, previousPattern, nex
145
158
  const controller = new AbortController();
146
159
  setPattern(undefined);
147
160
  setFetchError(undefined);
161
+ setPatternNotFound(false);
148
162
 
149
- fetch(`${normalizedBasePath}/api/pattern/${id}.json`, { signal: controller.signal })
163
+ fetch(buildArtifactUrl(`pattern/${id}.json`, appBasePath), { signal: controller.signal })
150
164
  .then((res) => {
165
+ if (res.status === 404) {
166
+ setPatternNotFound(true);
167
+ return null;
168
+ }
151
169
  if (!res.ok) throw new Error(`Failed to load pattern: ${res.status} ${res.statusText}`);
152
170
  return res.json();
153
171
  })
154
- .then((data) => setPattern(data as PatternListObject))
172
+ .then((data) => {
173
+ if (data) setPattern(data as PatternListObject);
174
+ })
155
175
  .catch((err) => {
156
176
  if (err.name !== 'AbortError') {
157
177
  setFetchError(err instanceof Error ? err.message : 'Failed to load pattern data.');
@@ -159,7 +179,7 @@ const PatternPage = ({ menu, metadata, current, id, config, previousPattern, nex
159
179
  });
160
180
 
161
181
  return () => controller.abort();
162
- }, [id, normalizedBasePath]);
182
+ }, [id, appBasePath]);
163
183
 
164
184
  const onIframeLoad = useCallback(() => {
165
185
  if (iframeRef.current?.contentWindow?.document?.body) {
@@ -167,8 +187,44 @@ const PatternPage = ({ menu, metadata, current, id, config, previousPattern, nex
167
187
  }
168
188
  }, []);
169
189
 
170
- if (fetchError) return <p className="p-4 text-red-500">{fetchError}</p>;
171
- if (!pattern) return <p>Loading...</p>;
190
+ if (patternNotFound) {
191
+ return (
192
+ <Layout config={config} menu={menu} current={current} metadata={{ ...metadata, title: '404 - Page Not Found', metaTitle: '404 - Page Not Found' }}>
193
+ <div className="flex min-h-[60vh] flex-col items-center justify-center">
194
+ <NotFound />
195
+ </div>
196
+ </Layout>
197
+ );
198
+ }
199
+
200
+ if (fetchError) {
201
+ return (
202
+ <Layout config={config} menu={menu} current={current} metadata={metadata}>
203
+ <div className="flex min-h-[60vh] flex-col items-center justify-center gap-2">
204
+ <p className="text-lg font-semibold text-gray-700 dark:text-gray-300">Something went wrong</p>
205
+ <p className="text-sm text-red-500">{fetchError}</p>
206
+ </div>
207
+ </Layout>
208
+ );
209
+ }
210
+
211
+ if (!pattern) {
212
+ return (
213
+ <Layout config={config} menu={menu} current={current} metadata={metadata}>
214
+ <div className="flex flex-col gap-3 pb-14" aria-busy="true" aria-live="polite">
215
+ <small className="text-sm font-medium text-sky-600 dark:text-gray-300">Patterns</small>
216
+ <HeadersType.H1>{metadata.title}</HeadersType.H1>
217
+ {metadata.description && (
218
+ <div className="prose max-w-[800px] text-xl font-light leading-relaxed text-gray-600 dark:text-gray-300">
219
+ <ReactMarkdown components={MarkdownComponents} rehypePlugins={[rehypeRaw]}>
220
+ {metadata.description}
221
+ </ReactMarkdown>
222
+ </div>
223
+ )}
224
+ </div>
225
+ </Layout>
226
+ );
227
+ }
172
228
 
173
229
  return (
174
230
  <Layout config={config} menu={menu} current={current} metadata={metadata}>
@@ -217,7 +273,7 @@ const PatternPage = ({ menu, metadata, current, id, config, previousPattern, nex
217
273
  display: 'block',
218
274
  border: 'none',
219
275
  }}
220
- src={`${normalizedBasePath}/api/pattern/${pattern.url}`}
276
+ src={buildArtifactUrl(`pattern/${pattern.url}`, appBasePath)}
221
277
  />
222
278
  ) : (
223
279
  <div className="flex items-center justify-center p-8 text-sm text-gray-500">No preview available for this pattern.</div>
@@ -8,13 +8,15 @@ import HeadersType from '../../../../../components/Typography/Headers';
8
8
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../../../../components/ui/table';
9
9
  import {
10
10
  ComponentDocumentationProps,
11
- fetchCompDocPageMarkdown,
12
11
  fetchComponents,
12
+ fetchComponentTokens,
13
+ fetchCompDocPageMarkdown,
14
+ fetchLocalComponents,
13
15
  getClientRuntimeConfig,
14
16
  getTokens,
15
17
  IParams,
18
+ isRegistryRuntime,
16
19
  reduceSlugToString,
17
- staticBuildMenu,
18
20
  } from '../../../../../components/util';
19
21
  import { getComponentInstanceScssTokens, tokenReferenceFormat } from '../../../../../components/util/token';
20
22
  import { filterOutNull } from '../../../../../lib/utils';
@@ -24,39 +26,65 @@ import { filterOutNull } from '../../../../../lib/utils';
24
26
  * @returns
25
27
  */
26
28
  export async function getStaticPaths() {
29
+ // In registry mode component token sets are published to the DB (possibly after this app was
30
+ // deployed), so paths cannot be frozen at build time — resolve them on demand.
31
+ if (isRegistryRuntime()) {
32
+ return { paths: [], fallback: 'blocking' };
33
+ }
27
34
  return {
28
- paths: fetchComponents()?.map((exportable) => ({ params: { component: exportable.id } })) ?? [],
35
+ paths: fetchLocalComponents()?.map((exportable) => ({ params: { component: exportable.id } })) ?? [],
29
36
  fallback: false, // can also be true or 'blocking'
30
37
  };
31
38
  }
32
39
 
33
40
  export const getStaticProps = async (context) => {
34
41
  const { component } = context.params as IParams;
35
- // get previews for components on this page
36
- const menu = staticBuildMenu();
37
42
  const config = getClientRuntimeConfig();
38
43
  const componentSlug = reduceSlugToString(component);
39
- const tokens = getTokens();
40
- const componentObject = tokens?.components?.[componentSlug!] ?? null;
41
- const markdownProps = fetchCompDocPageMarkdown('docs/', `/system/${componentSlug}`, `/system`).props;
42
- const componentData = fetchComponents()?.find((c) => c.id === componentSlug);
44
+ const markdownProps = (await fetchCompDocPageMarkdown('docs/', `/system/${componentSlug}`, `/system`)).props;
45
+
46
+ let componentObject: CoreTypes.IFileComponentObject | null = null;
47
+ let displayName: string | undefined;
48
+ let description: string | undefined;
49
+
50
+ if (isRegistryRuntime()) {
51
+ // Registry mode: source the token set and its generated download strings from the DB-backed docs
52
+ // read API (mutable, publishable after deploy). Unknown ids resolve to a clean not-found.
53
+ const detail = await fetchComponentTokens(componentSlug!);
54
+ if (!detail) {
55
+ return { notFound: true };
56
+ }
57
+ componentObject = detail.component;
58
+ markdownProps.scss = detail.scss;
59
+ markdownProps.css = detail.css;
60
+ markdownProps.styleDictionary = detail.styleDictionary;
61
+ markdownProps.types = detail.types;
62
+ const record = (await fetchComponents()).find((c) => c.id === componentSlug);
63
+ displayName = record?.title;
64
+ description = record?.description;
65
+ } else {
66
+ const tokens = getTokens();
67
+ componentObject = tokens?.components?.[componentSlug!] ?? null;
68
+ const componentData = fetchLocalComponents()?.find((c) => c.id === componentSlug);
69
+ displayName = componentData?.name;
70
+ description = componentData?.description;
71
+ }
43
72
 
44
- const fallbackTitle = componentData?.name || startCase(componentSlug);
73
+ const fallbackTitle = displayName || startCase(componentSlug);
45
74
  const fallbackMetaTitle = `${fallbackTitle}${config?.app?.client ? ` | ${config.app.client} Design System` : ''}`;
46
75
 
47
76
  markdownProps.metadata = {
48
77
  ...markdownProps.metadata,
49
- title: componentData?.name || markdownProps.metadata.title || startCase(componentSlug),
50
- description: markdownProps.metadata.description || componentData?.description || '',
78
+ title: displayName || markdownProps.metadata.title || startCase(componentSlug),
79
+ description: markdownProps.metadata.description || description || '',
51
80
  metaTitle: markdownProps.metadata.metaTitle || fallbackMetaTitle,
52
- metaDescription: markdownProps.metadata.metaDescription || componentData?.description || '',
81
+ metaDescription: markdownProps.metadata.metaDescription || description || '',
53
82
  };
54
83
 
55
84
  return {
56
85
  props: {
57
86
  id: component,
58
87
  component: componentObject ?? {},
59
- menu,
60
88
  config,
61
89
  ...markdownProps,
62
90
  },
@@ -9,7 +9,8 @@ import { MarkdownComponents, remarkCodeMeta } from '../../../../components/Markd
9
9
  import AnchorNav from '../../../../components/Navigation/AnchorNav';
10
10
  import HeadersType from '../../../../components/Typography/Headers';
11
11
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../../../components/ui/table';
12
- import { fetchDocPageMarkdown, FoundationDocumentationProps, getClientRuntimeConfig, getTokens } from '../../../../components/util';
12
+ import { fetchDocPageMarkdown, FoundationDocumentationProps, getClientRuntimeConfig, getTokens, buildTimeFoundationDesign } from '../../../../components/util';
13
+ import { useFoundationTokens } from '../../../../components/util/useFoundationTokens';
13
14
 
14
15
  /**
15
16
  * This statically renders content from the markdown, creating menu and providing
@@ -25,8 +26,8 @@ export const getStaticProps: GetStaticProps = async () => {
25
26
  ...{
26
27
  props: {
27
28
  config,
28
- ...fetchDocPageMarkdown('docs/', 'system/tokens/foundations/colors', `/system`).props,
29
- design: getTokens().localStyles,
29
+ ...(await fetchDocPageMarkdown('docs/', 'system/tokens/foundations/colors', `/system`)).props,
30
+ design: buildTimeFoundationDesign(),
30
31
  } as FoundationDocumentationProps,
31
32
  },
32
33
  };
@@ -66,8 +67,9 @@ const ColorGroupTable = ({ colors }: { group: string; colors: CoreTypes.IColorOb
66
67
  * @param param0
67
68
  * @returns
68
69
  */
69
- const ComponentsPage = ({ content, menu, metadata, current, config, design }: FoundationDocumentationProps) => {
70
- // Fetch components from api
70
+ const ComponentsPage = ({ content, menu, metadata, current, config, design: designProp }: FoundationDocumentationProps) => {
71
+ // In registry mode the build-time `design` is empty; hydrate it from the docs read API on mount.
72
+ const { design } = useFoundationTokens('colors', { design: designProp });
71
73
 
72
74
  const colorGroups = Object.fromEntries(
73
75
  Object.entries(groupBy(design.color, 'group'))
@@ -9,7 +9,8 @@ import { MarkdownComponents, remarkCodeMeta } from '../../../../components/Markd
9
9
  import AnchorNav from '../../../../components/Navigation/AnchorNav';
10
10
  import HeadersType from '../../../../components/Typography/Headers';
11
11
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../../../components/ui/table';
12
- import { fetchDocPageMarkdown, FoundationDocumentationProps, getClientRuntimeConfig, getTokens } from '../../../../components/util';
12
+ import { fetchDocPageMarkdown, FoundationDocumentationProps, getClientRuntimeConfig, getTokens, buildTimeFoundationDesign } from '../../../../components/util';
13
+ import { useFoundationTokens } from '../../../../components/util/useFoundationTokens';
13
14
 
14
15
  /**
15
16
  * This statically renders content from the markdown, creating menu and providing
@@ -25,8 +26,8 @@ export const getStaticProps: GetStaticProps = async () => {
25
26
  ...{
26
27
  props: {
27
28
  config,
28
- ...fetchDocPageMarkdown('docs/', 'system/tokens/foundations/effects', `/system`).props,
29
- design: getTokens().localStyles,
29
+ ...(await fetchDocPageMarkdown('docs/', 'system/tokens/foundations/effects', `/system`)).props,
30
+ design: buildTimeFoundationDesign(),
30
31
  } as FoundationDocumentationProps,
31
32
  },
32
33
  };
@@ -60,8 +61,9 @@ const EffectsTable = ({ effects }: { group: string; effects: CoreTypes.IEffectOb
60
61
  * @param param0
61
62
  * @returns
62
63
  */
63
- const ComponentsPage = ({ content, menu, metadata, current, config, design }: FoundationDocumentationProps) => {
64
- // Fetch components from api
64
+ const ComponentsPage = ({ content, menu, metadata, current, config, design: designProp }: FoundationDocumentationProps) => {
65
+ // In registry mode the build-time `design` is empty; hydrate it from the docs read API on mount.
66
+ const { design } = useFoundationTokens('effects', { design: designProp });
65
67
 
66
68
  const effectGroups = Object.fromEntries(
67
69
  Object.entries(groupBy(design.effect, 'group')).map(([groupKey, effects]) => {
@@ -10,7 +10,8 @@ import { MarkdownComponents, remarkCodeMeta } from '../../../../components/Markd
10
10
  import AnchorNav from '../../../../components/Navigation/AnchorNav';
11
11
  import HeadersType from '../../../../components/Typography/Headers';
12
12
  import { Table, TableBody, TableCell, TableRow } from '../../../../components/ui/table';
13
- import { fetchDocPageMarkdown, FoundationDocumentationProps, getClientRuntimeConfig, getTokens } from '../../../../components/util';
13
+ import { fetchDocPageMarkdown, FoundationDocumentationProps, getClientRuntimeConfig, getTokens, buildTimeFoundationDesign } from '../../../../components/util';
14
+ import { useFoundationTokens } from '../../../../components/util/useFoundationTokens';
14
15
 
15
16
  /**
16
17
  * This statically renders content from the markdown, creating menu and providing
@@ -26,8 +27,8 @@ export const getStaticProps: GetStaticProps = async () => {
26
27
  ...{
27
28
  props: {
28
29
  config,
29
- ...fetchDocPageMarkdown('docs/', 'system/tokens/foundations/typography', `/system`).props,
30
- design: getTokens().localStyles,
30
+ ...(await fetchDocPageMarkdown('docs/', 'system/tokens/foundations/typography', `/system`)).props,
31
+ design: buildTimeFoundationDesign(),
31
32
  } as FoundationDocumentationProps,
32
33
  },
33
34
  };
@@ -84,7 +85,10 @@ const FontsTable = ({ types }: { types: CoreTypes.ITypographyObject[] }) => {
84
85
  * @param param0
85
86
  * @returns
86
87
  */
87
- const ComponentsPage = ({ content, menu, metadata, current, config, design }: FoundationDocumentationProps) => {
88
+ const ComponentsPage = ({ content, menu, metadata, current, config, design: designProp }: FoundationDocumentationProps) => {
89
+ // In registry mode the build-time `design` is empty; hydrate it from the docs read API on mount.
90
+ const { design } = useFoundationTokens('typography', { design: designProp });
91
+
88
92
  const typography = design.typography.slice().sort((a, b) => {
89
93
  const l = (config?.app?.type_sort ?? []).indexOf(a.name) >>> 0;
90
94
  const r = (config?.app?.type_sort ?? []).indexOf(b.name) >>> 0;
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "baseUrl": "",
4
- "target": "es5",
3
+ "target": "es2017",
5
4
  "lib": ["dom", "dom.iterable", "esnext"],
6
5
  "allowJs": true,
7
6
  "skipLibCheck": true,
@@ -11,7 +10,7 @@
11
10
  "noEmit": true,
12
11
  "esModuleInterop": true,
13
12
  "module": "esnext",
14
- "moduleResolution": "node",
13
+ "moduleResolution": "bundler",
15
14
  "resolveJsonModule": true,
16
15
  "isolatedModules": true,
17
16
  "jsx": "preserve",