handoff-app 2.0.0-5 → 2.0.0-7

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 (201) hide show
  1. package/README.md +174 -41
  2. package/UPGRADE.md +198 -0
  3. package/config/config.template.js +1 -4
  4. package/config/config.template.ts +1 -2
  5. package/dist/app-builder/build.js +11 -6
  6. package/dist/app-builder/client-config.js +1 -0
  7. package/dist/app-builder/config-diff/strategies/pattern.js +3 -3
  8. package/dist/app-builder/watchers/component.js +5 -5
  9. package/dist/app-builder/watchers/utils.d.ts +2 -3
  10. package/dist/app-builder/watchers.d.ts +8 -15
  11. package/dist/app-builder/watchers.js +53 -54
  12. package/dist/cache/build-cache.js +18 -22
  13. package/dist/catalog/define.d.ts +6 -0
  14. package/dist/catalog/define.js +72 -0
  15. package/dist/catalog/implementation.d.ts +27 -0
  16. package/dist/catalog/implementation.js +133 -0
  17. package/dist/catalog/index.d.ts +6 -0
  18. package/dist/catalog/index.js +22 -0
  19. package/dist/catalog/normalize.d.ts +16 -0
  20. package/dist/catalog/normalize.js +115 -0
  21. package/dist/catalog/previews.d.ts +18 -0
  22. package/dist/catalog/previews.js +106 -0
  23. package/dist/catalog/renderers.d.ts +43 -0
  24. package/dist/catalog/renderers.js +62 -0
  25. package/dist/catalog/types.d.ts +63 -0
  26. package/dist/cli/make.d.ts +0 -5
  27. package/dist/cli/make.js +22 -67
  28. package/dist/cli/scaffold.js +25 -33
  29. package/dist/commands/checkout/index.d.ts +7 -4
  30. package/dist/commands/checkout/index.js +9 -6
  31. package/dist/commands/compat/push-args.d.ts +2 -2
  32. package/dist/commands/index.js +0 -2
  33. package/dist/commands/publish/index.d.ts +9 -6
  34. package/dist/commands/publish/index.js +11 -8
  35. package/dist/commands/pull/index.js +1 -1
  36. package/dist/commands/push/index.js +1 -1
  37. package/dist/commands/utils.d.ts +15 -4
  38. package/dist/commands/utils.js +19 -6
  39. package/dist/config/catalog-include.d.ts +43 -0
  40. package/dist/config/catalog-include.js +203 -0
  41. package/dist/config/defaults.d.ts +2 -0
  42. package/dist/config/defaults.js +4 -1
  43. package/dist/config/index.d.ts +3 -3
  44. package/dist/config/index.js +6 -5
  45. package/dist/config/loader.js +9 -1
  46. package/dist/config/runtime.d.ts +5 -6
  47. package/dist/config/runtime.js +154 -154
  48. package/dist/handlebars.d.ts +9 -0
  49. package/dist/handlebars.js +16 -0
  50. package/dist/index.d.ts +15 -4
  51. package/dist/index.js +29 -15
  52. package/dist/pattern.d.ts +7 -0
  53. package/dist/pattern.js +13 -0
  54. package/dist/react.d.ts +43 -0
  55. package/dist/react.js +11 -0
  56. package/dist/registry/asset-storage/define.d.ts +1 -1
  57. package/dist/registry/asset-storage/define.js +1 -1
  58. package/dist/registry/checkout/index.d.ts +9 -0
  59. package/dist/registry/checkout/index.js +335 -149
  60. package/dist/registry/db/schema.d.ts +34 -0
  61. package/dist/registry/db/schema.js +2 -0
  62. package/dist/registry/publish/index.d.ts +13 -2
  63. package/dist/registry/publish/index.js +109 -25
  64. package/dist/registry/publish/package.js +14 -1
  65. package/dist/registry/selection.d.ts +20 -0
  66. package/dist/registry/selection.js +37 -1
  67. package/dist/store/filesystem.d.ts +1 -1
  68. package/dist/store/filesystem.js +7 -7
  69. package/dist/store/registry.js +24 -3
  70. package/dist/transformers/plugins/csf-render.js +4 -2
  71. package/dist/transformers/plugins/ssr-render.js +14 -5
  72. package/dist/transformers/preview/component/api.d.ts +8 -0
  73. package/dist/transformers/preview/component/api.js +11 -15
  74. package/dist/transformers/preview/component/artifacts.d.ts +1 -1
  75. package/dist/transformers/preview/component/artifacts.js +11 -7
  76. package/dist/transformers/preview/component/builder.js +15 -18
  77. package/dist/transformers/preview/component/css.d.ts +2 -0
  78. package/dist/transformers/preview/component/css.js +8 -11
  79. package/dist/transformers/preview/component/html.js +18 -16
  80. package/dist/transformers/preview/component/javascript.js +2 -4
  81. package/dist/transformers/preview/pattern/builder.js +31 -18
  82. package/dist/transformers/preview/types.d.ts +15 -1
  83. package/dist/types/config.d.ts +36 -11
  84. package/docs/api.md +3 -0
  85. package/docs/cli.md +1 -1
  86. package/drizzle/0006_add_component_source_format.sql +3 -0
  87. package/drizzle/meta/0006_snapshot.json +1941 -0
  88. package/drizzle/meta/_journal.json +8 -1
  89. package/package.json +37 -2
  90. package/src/app/components/Component/Preview.tsx +36 -50
  91. package/src/app/components/CopyToClipboard.tsx +27 -26
  92. package/src/app/components/Layout/Header.tsx +4 -12
  93. package/src/app/components/Layout/RuntimeModeBadge.tsx +18 -0
  94. package/src/app/components/Markdown/CodeHighlight.tsx +73 -70
  95. package/src/app/components/McpIntegration/McpConfigDialog.tsx +349 -0
  96. package/src/app/components/McpIntegration/McpIcon.tsx +10 -0
  97. package/src/app/components/Navigation/MobileNav.tsx +3 -1
  98. package/src/app/components/context/PreviewContext.tsx +5 -5
  99. package/src/app/components/ui/dialog.tsx +73 -0
  100. package/src/app/components/util/index.ts +7 -15
  101. package/src/app/lib/docs-api/backend.ts +5 -1
  102. package/src/app/lib/docs-api/page-discovery.ts +1 -6
  103. package/src/app/lib/docs-api/page-rendering.ts +21 -1
  104. package/src/app/lib/docs-api/records.ts +25 -10
  105. package/src/app/lib/docs-api/registry.ts +4 -2
  106. package/src/app/lib/docs-api/runtime-config.ts +5 -0
  107. package/src/app/lib/docs-api/search.ts +7 -2
  108. package/src/app/lib/mcp/auth.ts +64 -0
  109. package/src/app/lib/mcp/index.ts +2 -0
  110. package/src/app/lib/mcp/server.ts +343 -0
  111. package/src/app/lib/mcp/shape.ts +596 -0
  112. package/src/app/lib/registry-api/transfer.ts +7 -5
  113. package/src/app/next.config.mjs +3 -0
  114. package/src/app/pages/[...slug]/index.tsx +16 -30
  115. package/src/app/pages/api/mcp.ts +56 -0
  116. package/src/app/pages/index.tsx +10 -9
  117. package/src/app-builder/build.ts +12 -8
  118. package/src/app-builder/client-config.ts +2 -1
  119. package/src/app-builder/config-diff/strategies/pattern.ts +1 -1
  120. package/src/app-builder/watchers/component.ts +3 -3
  121. package/src/app-builder/watchers/utils.ts +2 -3
  122. package/src/app-builder/watchers.ts +46 -50
  123. package/src/cache/build-cache.ts +11 -14
  124. package/src/catalog/README.md +92 -0
  125. package/src/catalog/define.ts +79 -0
  126. package/src/catalog/implementation.ts +145 -0
  127. package/src/catalog/index.ts +31 -0
  128. package/src/catalog/normalize.ts +143 -0
  129. package/src/catalog/previews.ts +111 -0
  130. package/src/catalog/renderers.ts +94 -0
  131. package/src/catalog/types.ts +74 -0
  132. package/src/cli/README.md +1 -1
  133. package/src/cli/make.ts +20 -72
  134. package/src/cli/scaffold.ts +25 -31
  135. package/src/commands/README.md +1 -1
  136. package/src/commands/checkout/index.ts +17 -7
  137. package/src/commands/compat/push-args.ts +2 -2
  138. package/src/commands/index.ts +0 -2
  139. package/src/commands/publish/index.ts +19 -9
  140. package/src/commands/pull/index.ts +2 -2
  141. package/src/commands/push/index.ts +2 -2
  142. package/src/commands/utils.ts +22 -7
  143. package/src/config/README.md +2 -1
  144. package/src/config/catalog-include.ts +227 -0
  145. package/src/config/defaults.ts +3 -0
  146. package/src/config/index.ts +4 -4
  147. package/src/config/loader.ts +12 -0
  148. package/src/config/runtime.ts +186 -191
  149. package/src/handlebars.ts +18 -0
  150. package/src/index.ts +39 -26
  151. package/src/pattern.ts +14 -0
  152. package/src/react.ts +52 -0
  153. package/src/registry/asset-storage/define.ts +1 -1
  154. package/src/registry/checkout/index.ts +416 -152
  155. package/src/registry/db/schema.ts +2 -0
  156. package/src/registry/publish/index.ts +123 -26
  157. package/src/registry/publish/package.ts +14 -1
  158. package/src/registry/selection.ts +44 -0
  159. package/src/store/filesystem.ts +4 -4
  160. package/src/store/registry.ts +13 -2
  161. package/src/transformers/plugins/csf-render.ts +4 -2
  162. package/src/transformers/plugins/ssr-render.ts +15 -5
  163. package/src/transformers/preview/component/api.ts +13 -1
  164. package/src/transformers/preview/component/artifacts.ts +8 -4
  165. package/src/transformers/preview/component/builder.ts +17 -4
  166. package/src/transformers/preview/component/css.ts +6 -10
  167. package/src/transformers/preview/component/html.ts +30 -19
  168. package/src/transformers/preview/component/javascript.ts +1 -3
  169. package/src/transformers/preview/pattern/builder.ts +33 -20
  170. package/src/transformers/preview/types.ts +15 -1
  171. package/src/types/config.ts +38 -11
  172. package/templates/default/README.md.tpl +10 -0
  173. package/templates/default/components/button/button.react.handoff.js.tpl +19 -23
  174. package/templates/default/components/button/button.react.handoff.ts.tpl +22 -22
  175. package/templates/default/handoff.config.js.tpl +11 -18
  176. package/templates/default/handoff.config.ts.tpl +11 -18
  177. package/templates/default/handoff.config.with-examples.js.tpl +12 -16
  178. package/templates/default/handoff.config.with-examples.ts.tpl +12 -16
  179. package/config/templates/component/template.json +0 -49
  180. package/config/templates/template.html +0 -7
  181. package/dist/commands/make/template.d.ts +0 -8
  182. package/dist/commands/make/template.js +0 -43
  183. package/dist/config/entries.d.ts +0 -47
  184. package/dist/config/entries.js +0 -162
  185. package/dist/config/normalizers/declaration.d.ts +0 -11
  186. package/dist/config/normalizers/declaration.js +0 -122
  187. package/dist/config/normalizers/pattern.d.ts +0 -8
  188. package/dist/config/normalizers/pattern.js +0 -41
  189. package/dist/declarations/helpers.d.ts +0 -6
  190. package/dist/declarations/helpers.js +0 -19
  191. package/dist/declarations/index.d.ts +0 -2
  192. package/dist/declarations/index.js +0 -9
  193. package/dist/declarations/types.d.ts +0 -60
  194. package/src/commands/make/template.ts +0 -46
  195. package/src/config/entries.ts +0 -175
  196. package/src/config/normalizers/declaration.ts +0 -179
  197. package/src/config/normalizers/pattern.ts +0 -59
  198. package/src/declarations/helpers.ts +0 -36
  199. package/src/declarations/index.ts +0 -19
  200. package/src/declarations/types.ts +0 -70
  201. /package/dist/{declarations → catalog}/types.js +0 -0
@@ -36,19 +36,12 @@ 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 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.
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.
39
+ * Watches `catalog.include` directories for a new item. A single watcher covers implementations
40
+ * and compositions; the declaration determines which pipeline builds the item.
41
+ *
42
+ * The rebuild differs by kind, and the dependency arrow is reversed between them. A new item with
43
+ * an implementation builds itself, then the compositions that reference it. A new composition
44
+ * rebuilds the preview segment of the items it references, so the synthetic `__pattern_*` HTML
45
+ * exists, and only then composes itself.
53
46
  */
54
- export declare const watchPatternDirectories: (handoff: Handoff, state: WatcherState, chokidarConfig: chokidar.WatchOptions) => void;
47
+ export declare const watchCatalogDirectories: (handoff: Handoff, state: WatcherState, chokidarConfig: chokidar.WatchOptions) => void;
@@ -35,7 +35,7 @@ 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.watchPatternDirectories = exports.watchComponentDirectories = exports.watchRuntimeConfiguration = exports.watchRuntimeComponents = exports.watchGlobalEntries = exports.watchPages = exports.watchAppSource = exports.watchPublicDirectory = exports.mapEntryTypeToSegment = exports.getRuntimeComponentsPathsToWatch = void 0;
38
+ exports.watchCatalogDirectories = 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"));
@@ -228,9 +228,9 @@ const watchRuntimeComponents = (handoff, state, runtimeComponentPathsToWatch) =>
228
228
  };
229
229
  exports.watchRuntimeComponents = watchRuntimeComponents;
230
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))
231
+ var _a, _b;
232
+ const pattern = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.patterns[patternId];
233
+ if (!((_b = pattern === null || pattern === void 0 ? void 0 : pattern.components) === null || _b === void 0 ? void 0 : _b.length))
234
234
  return;
235
235
  for (const ref of pattern.components) {
236
236
  yield (0, builder_1.default)(handoff, ref.id, builder_1.ComponentSegment.Previews);
@@ -273,9 +273,21 @@ const watchRuntimeConfiguration = (handoff, state) => {
273
273
  const normalizedMainConfig = handoff.getMainConfigFilePath()
274
274
  ? (0, path_2.normalizePathForCompare)(handoff.getMainConfigFilePath())
275
275
  : undefined;
276
+ const kindChanged = !!entryBefore && !!entryAfter && entryBefore.kind !== entryAfter.kind;
276
277
  if (normalizedMainConfig && normalizedChanged === normalizedMainConfig) {
277
278
  yield (0, builder_1.default)(handoff);
278
279
  }
280
+ else if (kindChanged) {
281
+ // The declaration switched between an implementation and a composition. A targeted
282
+ // rebuild would leave the previous lane's summary entry and artifacts behind, so
283
+ // rebuild everything and let the finalizers re-sync.
284
+ yield (0, builder_1.default)(handoff);
285
+ }
286
+ else if ((entryAfter === null || entryAfter === void 0 ? void 0 : entryAfter.kind) === 'unknown') {
287
+ // The file did not parse. It stays watched, so the next valid save rebuilds it.
288
+ // Guessing a lane here would rebuild the wrong entity.
289
+ logger_1.Logger.warn(`Declaration is not valid yet; skipping rebuild: ${changedFile}`);
290
+ }
279
291
  else if (handle) {
280
292
  yield handle.apply(handoff, entryAfter === null || entryAfter === void 0 ? void 0 : entryAfter.entityId);
281
293
  }
@@ -319,9 +331,14 @@ const watchEntityDirectories = (handoff, state, chokidarConfig, options) => {
319
331
  if (configPaths.length === 0)
320
332
  return;
321
333
  const dirsToWatch = [];
334
+ const seenDirs = new Set();
322
335
  for (const configPath of configPaths) {
323
336
  const resolved = path_1.default.resolve(handoff.workingPath, configPath);
337
+ const key = (0, path_2.normalizePathForCompare)(resolved);
338
+ if (seenDirs.has(key))
339
+ continue;
324
340
  if (fs_extra_1.default.existsSync(resolved) && fs_extra_1.default.statSync(resolved).isDirectory()) {
341
+ seenDirs.add(key);
325
342
  dirsToWatch.push(resolved);
326
343
  }
327
344
  }
@@ -335,13 +352,8 @@ const watchEntityDirectories = (handoff, state, chokidarConfig, options) => {
335
352
  watcher.on('add', (file) => __awaiter(void 0, void 0, void 0, function* () {
336
353
  const basename = path_1.default.basename(file);
337
354
  const dirName = path_1.default.basename(path_1.default.dirname(file));
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);
355
+ const isConfigFile = /\.handoff\.(ts|js|cjs)$/.test(basename);
356
+ const isNewEntity = isConfigFile && !knownIds.has(dirName);
345
357
  if (!isNewEntity)
346
358
  return;
347
359
  yield (0, utils_1.scheduleHandler)(state, `${scheduleKeyPrefix}:${dirName}`, () => __awaiter(void 0, void 0, void 0, function* () {
@@ -380,57 +392,44 @@ const watchEntityDirectories = (handoff, state, chokidarConfig, options) => {
380
392
  }));
381
393
  };
382
394
  /**
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.
395
+ * Watches `catalog.include` directories for a new item. A single watcher covers implementations
396
+ * and compositions; the declaration determines which pipeline builds the item.
397
+ *
398
+ * The rebuild differs by kind, and the dependency arrow is reversed between them. A new item with
399
+ * an implementation builds itself, then the compositions that reference it. A new composition
400
+ * rebuilds the preview segment of the items it references, so the synthetic `__pattern_*` HTML
401
+ * exists, and only then composes itself.
388
402
  */
389
- const watchComponentDirectories = (handoff, state, chokidarConfig) => {
403
+ const watchCatalogDirectories = (handoff, state, chokidarConfig) => {
390
404
  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',
405
+ getConfigPaths: (h) => { var _a, _b; return [...((_b = (_a = h.config.catalog) === null || _a === void 0 ? void 0 : _a.include) !== null && _b !== void 0 ? _b : [])]; },
406
+ getKnownIds: (h) => {
407
+ var _a, _b, _c, _d;
408
+ return [
409
+ ...Object.keys((_b = (_a = h.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {}),
410
+ ...Object.keys((_d = (_c = h.runtimeConfig) === null || _c === void 0 ? void 0 : _c.entities.patterns) !== null && _d !== void 0 ? _d : {}),
411
+ ];
412
+ },
413
+ getWatcher: (s) => s.catalogDirectoriesWatcher,
414
+ setWatcher: (s, w) => {
415
+ s.catalogDirectoriesWatcher = w;
416
+ },
417
+ scheduleKeyPrefix: 'newCatalogItem',
418
+ entityLabel: 'catalog item',
397
419
  onDetected: (handoff_1, _a) => __awaiter(void 0, [handoff_1, _a], void 0, function* (handoff, { addedIds }) {
398
- for (const componentId of addedIds) {
420
+ const addedComponentIds = addedIds.filter((id) => { var _a; return !!((_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components[id]); });
421
+ const addedPatternIds = addedIds.filter((id) => { var _a; return !!((_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.patterns[id]); });
422
+ for (const componentId of addedComponentIds) {
399
423
  yield (0, builder_1.default)(handoff, componentId);
400
424
  yield (0, config_diff_1.runAllFinalizers)(handoff, { patternRebuildComponentIds: [componentId] });
401
425
  }
402
- }),
403
- });
404
- };
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) {
426
+ for (const patternId of addedPatternIds) {
428
427
  yield rebuildPatternComponentPreviews(handoff, patternId);
429
428
  }
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) });
429
+ if (addedPatternIds.length > 0) {
430
+ yield (0, patterns_1.buildPatterns)(handoff, { onlyPatternIds: new Set(addedPatternIds) });
431
+ }
433
432
  }),
434
433
  });
435
434
  };
436
- exports.watchPatternDirectories = watchPatternDirectories;
435
+ exports.watchCatalogDirectories = watchCatalogDirectories;
@@ -136,14 +136,20 @@ function haveGlobalDepsChanged(cached, current) {
136
136
  * Gets all file paths that should be tracked for a component
137
137
  */
138
138
  function getComponentFilePaths(handoff, componentId) {
139
- var _a, _b, _c, _d, _e, _f, _g;
140
- const runtimeComponent = (_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 ? void 0 : _c[componentId];
139
+ var _a, _b, _c, _d;
140
+ const runtimeComponent = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components[componentId];
141
141
  if (!runtimeComponent) {
142
142
  return { files: [] };
143
143
  }
144
144
  const files = [];
145
145
  let templateDir;
146
146
  const componentDirs = new Set();
147
+ // A catalog item declares its previews in the declaration file, and its implementation can sit
148
+ // outside the item directory. The directories derived from `entries` below can therefore miss the
149
+ // declaration, which would leave a preview edit uncached.
150
+ if (runtimeComponent.path) {
151
+ componentDirs.add((0, path_2.normalizePathForCompare)(runtimeComponent.path));
152
+ }
147
153
  // Add entry files and infer component directories from resolved entry paths
148
154
  const entries = runtimeComponent.entries;
149
155
  if (entries) {
@@ -169,7 +175,7 @@ function getComponentFilePaths(handoff, componentId) {
169
175
  componentDirs.add((0, path_2.normalizePathForCompare)(path_1.default.dirname(templatePath)));
170
176
  }
171
177
  }
172
- catch (_h) {
178
+ catch (_e) {
173
179
  // File doesn't exist, still add to track
174
180
  files.push(templatePath);
175
181
  componentDirs.add((0, path_2.normalizePathForCompare)(path_1.default.dirname(templatePath)));
@@ -178,19 +184,9 @@ function getComponentFilePaths(handoff, componentId) {
178
184
  }
179
185
  // Find the config file path for this component using exact config filename + directory matching.
180
186
  const configPaths = handoff.getConfigFilePaths();
181
- const expectedConfigFileNames = new Set([
182
- `${componentId}.handoff.ts`,
183
- `${componentId}.handoff.js`,
184
- `${componentId}.handoff.cjs`,
185
- `${componentId}.handoff.json`,
186
- `${componentId}.json`,
187
- `${componentId}.js`,
188
- `${componentId}.cjs`,
189
- ]);
190
187
  const matchingConfigPath = configPaths.find((configPath) => {
191
188
  const configFileName = path_1.default.basename(configPath);
192
- const isModernDeclaration = /\.handoff\.(ts|js|cjs|json)$/.test(configFileName);
193
- if (!expectedConfigFileNames.has(configFileName) && !isModernDeclaration) {
189
+ if (!/\.handoff\.(ts|js|cjs)$/.test(configFileName)) {
194
190
  return false;
195
191
  }
196
192
  if (componentDirs.size === 0) {
@@ -208,7 +204,7 @@ function getComponentFilePaths(handoff, componentId) {
208
204
  // what processComponents must render. Without tracking these files here, the
209
205
  // cache would incorrectly consider the component unchanged and skip the preview
210
206
  // rebuild, leaving buildPatterns unable to find the required HTML fragments.
211
- const runtimePatterns = (_f = (_e = (_d = handoff.runtimeConfig) === null || _d === void 0 ? void 0 : _d.entries) === null || _e === void 0 ? void 0 : _e.patterns) !== null && _f !== void 0 ? _f : {};
207
+ const runtimePatterns = (_c = (_b = handoff.runtimeConfig) === null || _b === void 0 ? void 0 : _b.entities.patterns) !== null && _c !== void 0 ? _c : {};
212
208
  for (const configPath of configPaths) {
213
209
  const entry = handoff.getConfigFileEntry(configPath);
214
210
  if ((entry === null || entry === void 0 ? void 0 : entry.kind) !== 'pattern')
@@ -216,7 +212,7 @@ function getComponentFilePaths(handoff, componentId) {
216
212
  const pattern = runtimePatterns[entry.entityId];
217
213
  if (!pattern)
218
214
  continue;
219
- if ((_g = pattern.components) === null || _g === void 0 ? void 0 : _g.some((ref) => ref.id === componentId)) {
215
+ if ((_d = pattern.components) === null || _d === void 0 ? void 0 : _d.some((ref) => ref.id === componentId)) {
220
216
  files.push(configPath);
221
217
  }
222
218
  }
@@ -280,24 +276,24 @@ function hasComponentChanged(cached, current) {
280
276
  */
281
277
  function checkOutputExists(handoff, componentId) {
282
278
  return __awaiter(this, void 0, void 0, function* () {
283
- var _a, _b, _c, _d, _e, _f;
279
+ var _a, _b, _c, _d;
284
280
  const outputDirectory = path_1.default.resolve(handoff.workingPath, 'public/api/component');
285
281
  const componentPath = path_1.default.resolve(outputDirectory, `${componentId}.json`);
286
282
  if (!(yield fs_extra_1.default.pathExists(componentPath))) {
287
283
  return false;
288
284
  }
289
- const runtimeComponent = (_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 ? void 0 : _c[componentId];
285
+ const runtimeComponent = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components[componentId];
290
286
  const previewIds = new Set([
291
- ...Object.keys((_d = runtimeComponent === null || runtimeComponent === void 0 ? void 0 : runtimeComponent.previews) !== null && _d !== void 0 ? _d : {}),
292
- ...Object.keys((_e = runtimeComponent === null || runtimeComponent === void 0 ? void 0 : runtimeComponent.internalPatternPreviews) !== null && _e !== void 0 ? _e : {}),
287
+ ...Object.keys((_b = runtimeComponent === null || runtimeComponent === void 0 ? void 0 : runtimeComponent.previews) !== null && _b !== void 0 ? _b : {}),
288
+ ...Object.keys((_c = runtimeComponent === null || runtimeComponent === void 0 ? void 0 : runtimeComponent.internalPatternPreviews) !== null && _c !== void 0 ? _c : {}),
293
289
  ]);
294
290
  try {
295
291
  const component = yield fs_extra_1.default.readJson(componentPath);
296
- for (const previewId of Object.keys((_f = component === null || component === void 0 ? void 0 : component.previews) !== null && _f !== void 0 ? _f : {})) {
292
+ for (const previewId of Object.keys((_d = component === null || component === void 0 ? void 0 : component.previews) !== null && _d !== void 0 ? _d : {})) {
297
293
  previewIds.add(previewId);
298
294
  }
299
295
  }
300
- catch (_g) {
296
+ catch (_e) {
301
297
  return false;
302
298
  }
303
299
  for (const previewId of previewIds) {
@@ -0,0 +1,6 @@
1
+ import { type RendererKind } from './renderers';
2
+ import type { CatalogItem, CatalogItemInput } from './types';
3
+ /** Keeps declarations as plain data that the loader can read without evaluating Handoff. */
4
+ export declare const createCatalogItem: <TArgs = Record<string, unknown>>(input: CatalogItemInput, renderer?: RendererKind) => CatalogItem<TArgs>;
5
+ /** Validate module declarations too, because JavaScript callers have no compile-time checks. */
6
+ export declare function validateCatalogItem(value: unknown): asserts value is CatalogItem;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCatalogItem = void 0;
4
+ exports.validateCatalogItem = validateCatalogItem;
5
+ const renderers_1 = require("./renderers");
6
+ const MISSING_RENDERER_HELP = "An implementation needs a renderer. Import defineCatalogItem from 'handoff-app/react' or 'handoff-app/handlebars'.";
7
+ /** Handles the shared implementation forms here so renderer entry points only supply types and a renderer. */
8
+ const stampImplementation = (implementation, renderer) => {
9
+ if (typeof implementation === 'string') {
10
+ return { renderer, file: implementation };
11
+ }
12
+ const descriptor = implementation;
13
+ if (descriptor && typeof descriptor === 'object' && typeof descriptor.format === 'string' && typeof descriptor.file === 'string') {
14
+ return { renderer, format: descriptor.format, file: descriptor.file };
15
+ }
16
+ return { renderer, value: implementation };
17
+ };
18
+ /** Keeps declarations as plain data that the loader can read without evaluating Handoff. */
19
+ const createCatalogItem = (input, renderer) => {
20
+ const hasImplementation = input.implementation !== undefined && input.implementation !== null;
21
+ const hasComposition = Array.isArray(input.composition) && input.composition.length > 0;
22
+ if (hasImplementation && hasComposition) {
23
+ throw new Error('A catalog item declares either "implementation" or "composition", not both.');
24
+ }
25
+ if (!hasImplementation && !hasComposition) {
26
+ throw new Error('A catalog item must declare "implementation" or "composition".');
27
+ }
28
+ if (!hasImplementation) {
29
+ validateCatalogItem(input);
30
+ return input;
31
+ }
32
+ if (!renderer) {
33
+ throw new Error(MISSING_RENDERER_HELP);
34
+ }
35
+ const item = Object.assign(Object.assign({}, input), { implementation: stampImplementation(input.implementation, renderer) });
36
+ validateCatalogItem(item);
37
+ return item;
38
+ };
39
+ exports.createCatalogItem = createCatalogItem;
40
+ /** Validate module declarations too, because JavaScript callers have no compile-time checks. */
41
+ function validateCatalogItem(value) {
42
+ const help = ' Use defineCatalogItem. See UPGRADE.md#catalog-items.';
43
+ if (!value || typeof value !== 'object' || Array.isArray(value))
44
+ throw new Error('Invalid catalog item.' + help);
45
+ const item = value;
46
+ for (const key of ['previews', 'components', 'renderer', 'sourceFormat', 'should_do', 'should_not_do', 'title']) {
47
+ if (key in item)
48
+ throw new Error(`Catalog field "${key}" is no longer supported.` + help);
49
+ }
50
+ for (const key of ['component', 'story', 'template']) {
51
+ if (item.entries && key in item.entries)
52
+ throw new Error(`entries.${key} was removed. Use implementation.` + help);
53
+ }
54
+ if (item.composition !== undefined) {
55
+ if (item.implementation !== undefined || !Array.isArray(item.composition) || !item.composition.length) {
56
+ throw new Error('Declare either an implementation or a non-empty composition.' + help);
57
+ }
58
+ for (const ref of item.composition) {
59
+ if (!ref || typeof ref.ref !== 'string' || !ref.ref.trim() || 'id' in ref) {
60
+ throw new Error('Composition members require "ref", the catalog item id.' + help);
61
+ }
62
+ }
63
+ return;
64
+ }
65
+ const source = item.implementation;
66
+ if (!source || !(0, renderers_1.isRendererKind)(source.renderer))
67
+ throw new Error('implementation must state a supported renderer.' + help);
68
+ if (source.format !== undefined &&
69
+ (!(0, renderers_1.isSourceFormat)(source.format) || !renderers_1.SOURCE_FORMATS[source.format].renderers.includes(source.renderer))) {
70
+ throw new Error('implementation.format is not supported by this renderer.' + help);
71
+ }
72
+ }
@@ -0,0 +1,27 @@
1
+ /** A source file plus the export the implementation is bound to. */
2
+ export type ResolvedSource = {
3
+ file: string;
4
+ /** `default`, a named export, or `*` for a namespace import. */
5
+ exportName: string;
6
+ };
7
+ /**
8
+ * Resolves a relative module specifier to a file. Node and bundlers probe extensions and index
9
+ * files; `path.resolve` alone does not. A bare specifier (a package, or a tsconfig path alias) is
10
+ * not resolvable against the workspace, so it returns undefined.
11
+ */
12
+ export declare const resolveModulePath: (specifier: string, fromFile: string) => string | undefined;
13
+ /**
14
+ * Resolves the value a property is bound to back to its source file.
15
+ *
16
+ * Two callers use this: `implementation:` inside a catalog declaration, and `component:` inside a
17
+ * CSF meta object. In both cases only the value is authored, so the file has to be recovered from
18
+ * the import that produced it.
19
+ */
20
+ export declare const resolvePropertySource: (sourcePath: string, property: string) => ResolvedSource | undefined;
21
+ /**
22
+ * Last-resort lookup when the import cannot be resolved: the single component file sitting next to
23
+ * the declaration. Story files and the declaration itself are excluded.
24
+ */
25
+ export declare const findSiblingComponentFile: (directory: string, declarationPath: string) => string | undefined;
26
+ /** True when `file` sits inside `directory`. Publish rejects any path that escapes the entity directory. */
27
+ export declare const isInsideDirectory: (file: string, directory: string) => boolean;
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isInsideDirectory = exports.findSiblingComponentFile = exports.resolvePropertySource = exports.resolveModulePath = void 0;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const CANDIDATE_EXTENSIONS = ['.tsx', '.jsx', '.ts', '.js', '.mjs', '.cjs'];
10
+ const isStoryFile = (filePath) => /\.stories\.(jsx|tsx|js|ts)$/.test(filePath);
11
+ /**
12
+ * Resolves a relative module specifier to a file. Node and bundlers probe extensions and index
13
+ * files; `path.resolve` alone does not. A bare specifier (a package, or a tsconfig path alias) is
14
+ * not resolvable against the workspace, so it returns undefined.
15
+ */
16
+ const resolveModulePath = (specifier, fromFile) => {
17
+ if (!specifier.startsWith('.') && !path_1.default.isAbsolute(specifier))
18
+ return undefined;
19
+ const base = path_1.default.resolve(path_1.default.dirname(fromFile), specifier);
20
+ if (fs_extra_1.default.existsSync(base) && fs_extra_1.default.statSync(base).isFile())
21
+ return base;
22
+ for (const extension of CANDIDATE_EXTENSIONS) {
23
+ const candidate = `${base}${extension}`;
24
+ if (fs_extra_1.default.existsSync(candidate))
25
+ return candidate;
26
+ }
27
+ for (const extension of CANDIDATE_EXTENSIONS) {
28
+ const candidate = path_1.default.join(base, `index${extension}`);
29
+ if (fs_extra_1.default.existsSync(candidate))
30
+ return candidate;
31
+ }
32
+ return undefined;
33
+ };
34
+ exports.resolveModulePath = resolveModulePath;
35
+ /** Reads the identifier a property is bound to, e.g. `implementation: Button` or `component: UI.Card`. */
36
+ const readPropertyIdentifier = (sourceCode, property) => {
37
+ const match = sourceCode.match(new RegExp(`\\b${property}\\s*:\\s*([A-Za-z_$][\\w$]*(?:\\.[A-Za-z_$][\\w$]*)*)\\s*(?![\\w$(])`));
38
+ return match === null || match === void 0 ? void 0 : match[1];
39
+ };
40
+ /** Finds which export of an import clause is bound to `localName`. */
41
+ const matchImportClause = (clause, localName) => {
42
+ const namespaceMatch = clause.match(/\*\s+as\s+([A-Za-z_$][\w$]*)/);
43
+ if ((namespaceMatch === null || namespaceMatch === void 0 ? void 0 : namespaceMatch[1]) === localName)
44
+ return '*';
45
+ const bracesMatch = clause.match(/\{([\s\S]*)\}/);
46
+ if (bracesMatch) {
47
+ for (const rawSpecifier of bracesMatch[1].split(',')) {
48
+ const specifier = rawSpecifier.trim().replace(/^type\s+/, '');
49
+ if (!specifier)
50
+ continue;
51
+ const aliased = specifier.match(/^([A-Za-z_$][\w$]*)\s+as\s+([A-Za-z_$][\w$]*)$/);
52
+ if (aliased) {
53
+ if (aliased[2] === localName)
54
+ return aliased[1];
55
+ continue;
56
+ }
57
+ if (specifier === localName)
58
+ return specifier;
59
+ }
60
+ }
61
+ const defaultBinding = clause.split(',')[0].trim();
62
+ if (/^[A-Za-z_$][\w$]*$/.test(defaultBinding) && defaultBinding === localName)
63
+ return 'default';
64
+ return undefined;
65
+ };
66
+ const findBinding = (sourceCode, localName) => {
67
+ var _a;
68
+ for (const match of sourceCode.matchAll(/import\s+([\s\S]*?)\s+from\s*['"]([^'"]+)['"]/g)) {
69
+ const exportName = matchImportClause(match[1].trim(), localName);
70
+ if (exportName)
71
+ return { specifier: match[2], exportName };
72
+ }
73
+ const requireBinding = sourceCode.match(new RegExp(`(?:const|let|var)\\s+${localName}\\s*=\\s*require\\(\\s*['"]([^'"]+)['"]\\s*\\)(?:\\.([A-Za-z_$][\\w$]*))?`));
74
+ if (requireBinding) {
75
+ return { specifier: requireBinding[1], exportName: (_a = requireBinding[2]) !== null && _a !== void 0 ? _a : '*' };
76
+ }
77
+ const requireNamed = sourceCode.match(new RegExp(`(?:const|let|var)\\s*\\{[^}]*\\b${localName}\\b[^}]*\\}\\s*=\\s*require\\(\\s*['"]([^'"]+)['"]\\s*\\)`));
78
+ if (requireNamed) {
79
+ return { specifier: requireNamed[1], exportName: localName };
80
+ }
81
+ return undefined;
82
+ };
83
+ /**
84
+ * Resolves the value a property is bound to back to its source file.
85
+ *
86
+ * Two callers use this: `implementation:` inside a catalog declaration, and `component:` inside a
87
+ * CSF meta object. In both cases only the value is authored, so the file has to be recovered from
88
+ * the import that produced it.
89
+ */
90
+ const resolvePropertySource = (sourcePath, property) => {
91
+ let sourceCode;
92
+ try {
93
+ sourceCode = fs_extra_1.default.readFileSync(sourcePath, 'utf8');
94
+ }
95
+ catch (_a) {
96
+ return undefined;
97
+ }
98
+ const identifier = readPropertyIdentifier(sourceCode, property);
99
+ if (!identifier)
100
+ return undefined;
101
+ const [localName, ...memberPath] = identifier.split('.');
102
+ const binding = findBinding(sourceCode, localName);
103
+ if (!binding)
104
+ return undefined;
105
+ const file = (0, exports.resolveModulePath)(binding.specifier, sourcePath);
106
+ if (!file)
107
+ return undefined;
108
+ // `UI.Button` names the export directly; a namespace import on its own has no single export.
109
+ const exportName = memberPath.length ? memberPath[memberPath.length - 1] : binding.exportName;
110
+ return { file, exportName: exportName === '*' ? 'default' : exportName };
111
+ };
112
+ exports.resolvePropertySource = resolvePropertySource;
113
+ /**
114
+ * Last-resort lookup when the import cannot be resolved: the single component file sitting next to
115
+ * the declaration. Story files and the declaration itself are excluded.
116
+ */
117
+ const findSiblingComponentFile = (directory, declarationPath) => {
118
+ if (!fs_extra_1.default.existsSync(directory))
119
+ return undefined;
120
+ const candidates = fs_extra_1.default
121
+ .readdirSync(directory)
122
+ .filter((name) => /\.(tsx|jsx)$/.test(name) && !isStoryFile(name))
123
+ .map((name) => path_1.default.resolve(directory, name))
124
+ .filter((file) => file !== path_1.default.resolve(declarationPath));
125
+ return candidates.length === 1 ? candidates[0] : undefined;
126
+ };
127
+ exports.findSiblingComponentFile = findSiblingComponentFile;
128
+ /** True when `file` sits inside `directory`. Publish rejects any path that escapes the entity directory. */
129
+ const isInsideDirectory = (file, directory) => {
130
+ const relative = path_1.default.relative(directory, file);
131
+ return !!relative && !relative.startsWith('..') && !path_1.default.isAbsolute(relative);
132
+ };
133
+ exports.isInsideDirectory = isInsideDirectory;
@@ -0,0 +1,6 @@
1
+ export { createCatalogItem, validateCatalogItem } from './define';
2
+ export { findSiblingComponentFile, isInsideDirectory, resolveModulePath, resolvePropertySource, type ResolvedSource, } from './implementation';
3
+ export { normalizeCatalogItem, type CatalogNormalizeResult } from './normalize';
4
+ export { entryKeyFor, moduleFor, sourceForFile, type ComponentSource, type EntryKey, type RendererKind, type SourceFormat, } from './renderers';
5
+ export { createCatalogPreviews, orderPreviews, readExportOrder, readExportOrderFromSource } from './previews';
6
+ export type { CatalogItem, CatalogItemEntries, CatalogItemInput, CatalogItemMeta, CatalogPreview, CompositionRef, CsfSource, NormalizedImplementation, Preview, SourceDescriptor, } from './types';
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readExportOrderFromSource = exports.readExportOrder = exports.orderPreviews = exports.createCatalogPreviews = exports.sourceForFile = exports.moduleFor = exports.entryKeyFor = exports.normalizeCatalogItem = exports.resolvePropertySource = exports.resolveModulePath = exports.isInsideDirectory = exports.findSiblingComponentFile = exports.validateCatalogItem = exports.createCatalogItem = void 0;
4
+ var define_1 = require("./define");
5
+ Object.defineProperty(exports, "createCatalogItem", { enumerable: true, get: function () { return define_1.createCatalogItem; } });
6
+ Object.defineProperty(exports, "validateCatalogItem", { enumerable: true, get: function () { return define_1.validateCatalogItem; } });
7
+ var implementation_1 = require("./implementation");
8
+ Object.defineProperty(exports, "findSiblingComponentFile", { enumerable: true, get: function () { return implementation_1.findSiblingComponentFile; } });
9
+ Object.defineProperty(exports, "isInsideDirectory", { enumerable: true, get: function () { return implementation_1.isInsideDirectory; } });
10
+ Object.defineProperty(exports, "resolveModulePath", { enumerable: true, get: function () { return implementation_1.resolveModulePath; } });
11
+ Object.defineProperty(exports, "resolvePropertySource", { enumerable: true, get: function () { return implementation_1.resolvePropertySource; } });
12
+ var normalize_1 = require("./normalize");
13
+ Object.defineProperty(exports, "normalizeCatalogItem", { enumerable: true, get: function () { return normalize_1.normalizeCatalogItem; } });
14
+ var renderers_1 = require("./renderers");
15
+ Object.defineProperty(exports, "entryKeyFor", { enumerable: true, get: function () { return renderers_1.entryKeyFor; } });
16
+ Object.defineProperty(exports, "moduleFor", { enumerable: true, get: function () { return renderers_1.moduleFor; } });
17
+ Object.defineProperty(exports, "sourceForFile", { enumerable: true, get: function () { return renderers_1.sourceForFile; } });
18
+ var previews_1 = require("./previews");
19
+ Object.defineProperty(exports, "createCatalogPreviews", { enumerable: true, get: function () { return previews_1.createCatalogPreviews; } });
20
+ Object.defineProperty(exports, "orderPreviews", { enumerable: true, get: function () { return previews_1.orderPreviews; } });
21
+ Object.defineProperty(exports, "readExportOrder", { enumerable: true, get: function () { return previews_1.readExportOrder; } });
22
+ Object.defineProperty(exports, "readExportOrderFromSource", { enumerable: true, get: function () { return previews_1.readExportOrderFromSource; } });
@@ -0,0 +1,16 @@
1
+ import type { ComponentListObject, PatternListObject } from '../transformers/preview/types';
2
+ type NormalizeOptions = {
3
+ declarationPath: string;
4
+ fallbackId: string;
5
+ warn: (message: string) => void;
6
+ };
7
+ export type CatalogNormalizeResult = {
8
+ kind: 'component';
9
+ item: ComponentListObject;
10
+ } | {
11
+ kind: 'pattern';
12
+ item: PatternListObject;
13
+ };
14
+ /** Maps the authoring contract directly into the runtime read model. */
15
+ export declare const normalizeCatalogItem: (moduleExports: Record<string, unknown>, options: NormalizeOptions) => CatalogNormalizeResult;
16
+ export {};