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
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getClientConfig = exports.defaultConfig = void 0;
3
+ exports.getClientConfig = exports.defaultConfig = exports.isMcpEnabled = void 0;
4
4
  const connection_1 = require("../registry/connection");
5
+ /** Whether the MCP endpoint is served. On unless `runtime.mcp` is explicitly `false`. */
6
+ const isMcpEnabled = (config) => { var _a; return ((_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.mcp) !== false; };
7
+ exports.isMcpEnabled = isMcpEnabled;
5
8
  const defaultConfig = () => {
6
9
  var _a, _b, _c, _d;
7
10
  return ({
@@ -1,9 +1,9 @@
1
- export { defaultConfig, getClientConfig } from './defaults';
1
+ export { defaultConfig, getClientConfig, isMcpEnabled } from './defaults';
2
2
  export type { ImageStyle } from './defaults';
3
3
  export { HandoffConfigError, initConfig, initConfigWithMetadata } from './loader';
4
4
  export type { ConfigLoadContext } from './loader';
5
5
  export { defineConfig } from './helpers';
6
6
  export { initRuntimeConfig } from './runtime';
7
7
  export { validateConfig } from './validator';
8
- export { isEntryCovered, writeEntries } from './entries';
9
- export type { EntryKind, WriteEntriesResult } from './entries';
8
+ export { addToCatalog, isIncluded } from './catalog-include';
9
+ export type { AddToCatalogResult } from './catalog-include';
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.writeEntries = exports.isEntryCovered = exports.validateConfig = exports.initRuntimeConfig = exports.defineConfig = exports.initConfigWithMetadata = exports.initConfig = exports.HandoffConfigError = exports.getClientConfig = exports.defaultConfig = void 0;
3
+ exports.isIncluded = exports.addToCatalog = exports.validateConfig = exports.initRuntimeConfig = exports.defineConfig = exports.initConfigWithMetadata = exports.initConfig = exports.HandoffConfigError = exports.isMcpEnabled = exports.getClientConfig = exports.defaultConfig = void 0;
4
4
  // Config defaults and client config
5
5
  var defaults_1 = require("./defaults");
6
6
  Object.defineProperty(exports, "defaultConfig", { enumerable: true, get: function () { return defaults_1.defaultConfig; } });
7
7
  Object.defineProperty(exports, "getClientConfig", { enumerable: true, get: function () { return defaults_1.getClientConfig; } });
8
+ Object.defineProperty(exports, "isMcpEnabled", { enumerable: true, get: function () { return defaults_1.isMcpEnabled; } });
8
9
  // Config file loading
9
10
  var loader_1 = require("./loader");
10
11
  Object.defineProperty(exports, "HandoffConfigError", { enumerable: true, get: function () { return loader_1.HandoffConfigError; } });
@@ -19,7 +20,7 @@ Object.defineProperty(exports, "initRuntimeConfig", { enumerable: true, get: fun
19
20
  // Config validation
20
21
  var validator_1 = require("./validator");
21
22
  Object.defineProperty(exports, "validateConfig", { enumerable: true, get: function () { return validator_1.validateConfig; } });
22
- // Registering directory-list entries (components/patterns)
23
- var entries_1 = require("./entries");
24
- Object.defineProperty(exports, "isEntryCovered", { enumerable: true, get: function () { return entries_1.isEntryCovered; } });
25
- Object.defineProperty(exports, "writeEntries", { enumerable: true, get: function () { return entries_1.writeEntries; } });
23
+ // Registering catalog item directories under `catalog.include`
24
+ var catalog_include_1 = require("./catalog-include");
25
+ Object.defineProperty(exports, "addToCatalog", { enumerable: true, get: function () { return catalog_include_1.addToCatalog; } });
26
+ Object.defineProperty(exports, "isIncluded", { enumerable: true, get: function () { return catalog_include_1.isIncluded; } });
@@ -104,7 +104,7 @@ const resolveConfigFilePath = (workingPath, requestedPath) => {
104
104
  * Loads the handoff configuration for the given working directory and returns metadata.
105
105
  */
106
106
  const initConfigWithMetadata = (configOverride, context) => {
107
- var _a;
107
+ var _a, _b, _c;
108
108
  let config = {};
109
109
  const { selected: configPath, ignored } = resolveConfigFilePath((_a = context === null || context === void 0 ? void 0 : context.workingPath) !== null && _a !== void 0 ? _a : (0, path_2.resolveWorkingPath)(), context === null || context === void 0 ? void 0 : context.configPath);
110
110
  if (ignored.length > 0 && configPath) {
@@ -123,6 +123,14 @@ const initConfigWithMetadata = (configOverride, context) => {
123
123
  }
124
124
  });
125
125
  }
126
+ const entries = config.entries;
127
+ if (entries && ('components' in entries || 'patterns' in entries)) {
128
+ throw new HandoffConfigError('entries.components and entries.patterns were removed. Use catalog.include. See UPGRADE.md#catalog-items.');
129
+ }
130
+ const format = (_c = (_b = config.runtime) === null || _b === void 0 ? void 0 : _b.workspace) === null || _c === void 0 ? void 0 : _c.declarationFormat;
131
+ if (format !== undefined && !['ts', 'js', 'cjs'].includes(format)) {
132
+ throw new HandoffConfigError('Item declarations support ts, js, and cjs. Convert JSON declarations to defineCatalogItem. See UPGRADE.md#catalog-items.');
133
+ }
126
134
  const defaults = (0, defaults_1.defaultConfig)();
127
135
  // Top-level merge stays shallow to preserve 1.x semantics, except for the `runtime`
128
136
  // block which is deep-merged so a partial user `runtime` (e.g. only `mode`) does not
@@ -12,6 +12,10 @@ type DeclarationResolution = {
12
12
  fileName: string;
13
13
  };
14
14
  export declare const resolveComponentDeclaration: (componentDir: string, componentBaseName: string) => DeclarationResolution | null;
15
+ /**
16
+ * Expands catalog.include into item directories and removes duplicate paths.
17
+ */
18
+ export declare const getCatalogItemDirectories: (config: Config, workingPath: string) => string[];
15
19
  /**
16
20
  * Initializes the runtime configuration by resolving component entries,
17
21
  * SCSS/JS paths, and transformer options from the handoff config.
@@ -22,7 +26,7 @@ export declare const resolveComponentDeclaration: (componentDir: string, compone
22
26
  export declare const initRuntimeConfig: (handoff: HandoffContext) => [runtimeConfig: RuntimeConfig, configs: string[], configFileIndex: Map<string, ConfigFileEntry>];
23
27
  /**
24
28
  * True when `searchPath` is itself a single component directory: it holds a declaration file named
25
- * after the directory (`{dirname}.handoff.*`, or a legacy `{dirname}.{json,js,cjs}`). This is what
29
+ * with a .handoff.ts, .handoff.js, or .handoff.cjs suffix. This is what
26
30
  * separates a declared component from a collection directory.
27
31
  */
28
32
  export declare const isComponentDirectory: (searchPath: string) => boolean;
@@ -34,11 +38,6 @@ export declare const isComponentDirectory: (searchPath: string) => boolean;
34
38
  * @returns Paths to the component directories.
35
39
  */
36
40
  export declare const getComponentsForPath: (searchPath: string) => string[];
37
- /**
38
- * Generic directory discovery for both components and patterns.
39
- * Reuses the same logic as getComponentsForPath.
40
- */
41
- export declare const getItemsForPath: (searchPath: string) => string[];
42
41
  /**
43
42
  * Recursively converts all keys and string values in an object to lowercase.
44
43
  */
@@ -3,11 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.toLowerCaseKeysAndValues = exports.getItemsForPath = exports.getComponentsForPath = exports.isComponentDirectory = exports.initRuntimeConfig = exports.resolveComponentDeclaration = void 0;
6
+ exports.toLowerCaseKeysAndValues = exports.getComponentsForPath = exports.isComponentDirectory = exports.initRuntimeConfig = exports.getCatalogItemDirectories = exports.resolveComponentDeclaration = void 0;
7
7
  const esbuild_1 = __importDefault(require("esbuild"));
8
8
  const fs_extra_1 = __importDefault(require("fs-extra"));
9
9
  const module_1 = require("module");
10
10
  const path_1 = __importDefault(require("path"));
11
+ const catalog_1 = require("../catalog");
11
12
  const content_kinds_1 = require("../registry/content-kinds");
12
13
  const csf_1 = require("../transformers/utils/csf");
13
14
  const module_2 = require("../transformers/utils/module");
@@ -15,51 +16,31 @@ const logger_1 = require("../utils/logger");
15
16
  const markdown_1 = require("../utils/markdown");
16
17
  const pages_1 = require("../utils/pages");
17
18
  const path_2 = require("../utils/path");
18
- const declaration_1 = require("./normalizers/declaration");
19
19
  const page_1 = require("./normalizers/page");
20
- const pattern_1 = require("./normalizers/pattern");
21
- const MODERN_EXTENSIONS = ['ts', 'js', 'cjs', 'json'];
22
- const getLegacyDeclarationFiles = (componentBaseName) => [
23
- `${componentBaseName}.json`,
24
- `${componentBaseName}.js`,
25
- `${componentBaseName}.cjs`,
26
- ];
27
- const getModernDeclarationFiles = (componentBaseName) => MODERN_EXTENSIONS.map((ext) => `${componentBaseName}.handoff.${ext}`);
28
- const findPreferredModernDeclaration = (componentDir, componentBaseName) => {
29
- const exactCandidates = getModernDeclarationFiles(componentBaseName);
20
+ const DECLARATION_EXTENSIONS = ['ts', 'js', 'cjs'];
21
+ const getDeclarationFiles = (componentBaseName) => DECLARATION_EXTENSIONS.map((ext) => `${componentBaseName}.handoff.${ext}`);
22
+ const findPreferredDeclaration = (componentDir, componentBaseName) => {
23
+ const exactCandidates = getDeclarationFiles(componentBaseName);
30
24
  const exactMatch = exactCandidates.find((candidate) => fs_extra_1.default.existsSync(path_1.default.resolve(componentDir, candidate)));
31
25
  if (exactMatch)
32
26
  return exactMatch;
33
27
  const allFiles = fs_extra_1.default.existsSync(componentDir) ? fs_extra_1.default.readdirSync(componentDir) : [];
34
- const modernFiles = allFiles
35
- .filter((file) => /\.handoff\.(ts|js|cjs|json)$/.test(file))
36
- .sort((a, b) => a.localeCompare(b));
37
- if (!modernFiles.length)
28
+ const declarationFiles = allFiles.filter((file) => /\.handoff\.(ts|js|cjs)$/.test(file)).sort((a, b) => a.localeCompare(b));
29
+ if (!declarationFiles.length)
38
30
  return undefined;
39
- for (const ext of MODERN_EXTENSIONS) {
40
- const extMatch = modernFiles.find((file) => file.endsWith(`.handoff.${ext}`));
31
+ for (const ext of DECLARATION_EXTENSIONS) {
32
+ const extMatch = declarationFiles.find((file) => file.endsWith(`.handoff.${ext}`));
41
33
  if (extMatch)
42
34
  return extMatch;
43
35
  }
44
- return modernFiles[0];
36
+ return declarationFiles[0];
45
37
  };
46
38
  const resolveComponentDeclaration = (componentDir, componentBaseName) => {
47
- const modernMatch = findPreferredModernDeclaration(componentDir, componentBaseName);
48
- const legacyFiles = getLegacyDeclarationFiles(componentBaseName);
49
- const legacyMatch = legacyFiles.find((candidate) => fs_extra_1.default.existsSync(path_1.default.resolve(componentDir, candidate)));
50
- if (modernMatch) {
51
- if (legacyMatch) {
52
- logger_1.Logger.warn(`Both modern and legacy declarations found in "${componentDir}". Using "${modernMatch}" and ignoring "${legacyMatch}".`);
53
- }
54
- return { fileName: modernMatch };
55
- }
56
- if (legacyMatch) {
57
- return { fileName: legacyMatch };
58
- }
59
- return null;
39
+ const declarationMatch = findPreferredDeclaration(componentDir, componentBaseName);
40
+ return declarationMatch ? { fileName: declarationMatch } : null;
60
41
  };
61
42
  exports.resolveComponentDeclaration = resolveComponentDeclaration;
62
- const evaluateTypeScriptDeclaration = (filePath, handoffModulePath) => {
43
+ const evaluateDeclaration = (filePath, handoffModulePath) => {
63
44
  var _a, _b;
64
45
  const buildResult = esbuild_1.default.buildSync({
65
46
  entryPoints: [filePath],
@@ -91,26 +72,16 @@ const evaluateTypeScriptDeclaration = (filePath, handoffModulePath) => {
91
72
  evaluator(runtimeRequire, mod, mod.exports, filePath, path_1.default.dirname(filePath));
92
73
  return mod.exports;
93
74
  };
94
- const loadDeclarationFile = (filePath, handoffModulePath) => {
95
- if (filePath.endsWith('.json')) {
96
- const componentJson = fs_extra_1.default.readFileSync(filePath, 'utf8');
97
- return JSON.parse(componentJson);
98
- }
99
- if (filePath.endsWith('.ts')) {
100
- return evaluateTypeScriptDeclaration(filePath, handoffModulePath);
101
- }
102
- // Invalidate require cache to ensure fresh read
103
- delete require.cache[require.resolve(filePath)];
104
- return require(filePath);
105
- };
75
+ const loadDeclarationFile = evaluateDeclaration;
106
76
  const discoverCsfPreviews = (component, handoff) => {
107
77
  var _a;
108
- if (component.renderer !== 'csf' || !((_a = component.entries) === null || _a === void 0 ? void 0 : _a.template)) {
78
+ if (component.sourceFormat !== 'csf' || !((_a = component.entries) === null || _a === void 0 ? void 0 : _a.template)) {
109
79
  return component.previews;
110
80
  }
111
81
  try {
112
82
  const loaded = (0, module_2.buildAndEvaluateModuleSync)(component.entries.template, handoff);
113
- const discoveredPreviews = (0, csf_1.createCsfStoryPreviews)(loaded.exports);
83
+ // esbuild emits its export map alphabetically, so story order comes from the source text.
84
+ const discoveredPreviews = (0, catalog_1.orderPreviews)((0, csf_1.createCsfStoryPreviews)(loaded.exports), (0, catalog_1.readExportOrder)(component.entries.template));
114
85
  if (Object.keys(discoveredPreviews).length === 0) {
115
86
  logger_1.Logger.warn(`No named stories found in CSF file for "${component.id}": ${component.entries.template}`);
116
87
  return component.previews;
@@ -123,6 +94,49 @@ const discoverCsfPreviews = (component, handoff) => {
123
94
  return component.previews;
124
95
  }
125
96
  };
97
+ /**
98
+ * Expands catalog.include into item directories and removes duplicate paths.
99
+ */
100
+ const getCatalogItemDirectories = (config, workingPath) => {
101
+ var _a, _b;
102
+ const registered = [...((_b = (_a = config.catalog) === null || _a === void 0 ? void 0 : _a.include) !== null && _b !== void 0 ? _b : [])];
103
+ const seen = new Set();
104
+ const directories = [];
105
+ for (const included of registered) {
106
+ for (const directory of (0, exports.getComponentsForPath)(path_1.default.resolve(workingPath, included))) {
107
+ const key = (0, path_2.normalizePathForCompare)(directory);
108
+ if (seen.has(key))
109
+ continue;
110
+ seen.add(key);
111
+ directories.push(directory);
112
+ }
113
+ }
114
+ return directories;
115
+ };
116
+ exports.getCatalogItemDirectories = getCatalogItemDirectories;
117
+ /**
118
+ * Records the React component a CSF file documents, so it is watched, documented, and published.
119
+ * `csf-render` reads `meta.component` as a value; only the source text says which file it came
120
+ * from. A component outside the item directory is left unrecorded, because publish rejects a
121
+ * source path that escapes the entity directory.
122
+ */
123
+ const resolveCsfComponentSource = (component) => {
124
+ var _a, _b;
125
+ if (component.sourceFormat !== 'csf')
126
+ return;
127
+ const storyPath = (_a = component.entries) === null || _a === void 0 ? void 0 : _a.story;
128
+ if (!storyPath || ((_b = component.entries) === null || _b === void 0 ? void 0 : _b.component))
129
+ return;
130
+ const resolved = (0, catalog_1.resolvePropertySource)(storyPath, 'component');
131
+ if (!resolved)
132
+ return;
133
+ if (!(0, catalog_1.isInsideDirectory)(resolved.file, component.path)) {
134
+ logger_1.Logger.warn(`Catalog item "${component.id}" documents a component at "${resolved.file}", outside "${component.path}". ` +
135
+ `Previews still build, but that file is not published. Move it into the item directory to publish it.`);
136
+ return;
137
+ }
138
+ component.entries.component = resolved.file;
139
+ };
126
140
  /**
127
141
  * Initializes the runtime configuration by resolving component entries,
128
142
  * SCSS/JS paths, and transformer options from the handoff config.
@@ -131,8 +145,8 @@ const discoverCsfPreviews = (component, handoff) => {
131
145
  * @returns A tuple of [RuntimeConfig, configFilePaths, configFileIndex].
132
146
  */
133
147
  const initRuntimeConfig = (handoff) => {
134
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
135
- var _l;
148
+ var _a, _b, _c, _d, _e, _f;
149
+ var _g;
136
150
  const configFiles = [];
137
151
  const configFileIndex = new Map();
138
152
  const result = {
@@ -140,103 +154,96 @@ const initRuntimeConfig = (handoff) => {
140
154
  entries: {
141
155
  scss: undefined,
142
156
  js: undefined,
157
+ },
158
+ entities: {
143
159
  components: {},
144
160
  patterns: {},
145
161
  pages: {},
146
162
  },
163
+ duplicateCatalogIds: [],
147
164
  };
165
+ // The id addresses artifacts, transfer routes and docs URLs, so it has to resolve to one item.
166
+ // Components and patterns share one namespace, so one map covers both lanes.
167
+ const declaredIds = new Map();
148
168
  if (!!((_a = handoff.config.entries) === null || _a === void 0 ? void 0 : _a.scss)) {
149
169
  result.entries.scss = path_1.default.resolve(handoff.workingPath, (_b = handoff.config.entries) === null || _b === void 0 ? void 0 : _b.scss);
150
170
  }
151
171
  if (!!((_c = handoff.config.entries) === null || _c === void 0 ? void 0 : _c.js)) {
152
172
  result.entries.js = path_1.default.resolve(handoff.workingPath, (_d = handoff.config.entries) === null || _d === void 0 ? void 0 : _d.js);
153
173
  }
154
- if ((_f = (_e = handoff.config.entries) === null || _e === void 0 ? void 0 : _e.components) === null || _f === void 0 ? void 0 : _f.length) {
155
- const componentPaths = handoff.config.entries.components.flatMap(exports.getComponentsForPath);
156
- for (const componentPath of componentPaths) {
157
- const resolvedComponentPath = path_1.default.resolve(handoff.workingPath, componentPath);
158
- const componentBaseName = path_1.default.basename(resolvedComponentPath);
159
- const declaration = (0, exports.resolveComponentDeclaration)(resolvedComponentPath, componentBaseName);
160
- if (!declaration) {
161
- const modernFiles = getModernDeclarationFiles(componentBaseName);
162
- const legacyFiles = getLegacyDeclarationFiles(componentBaseName);
163
- logger_1.Logger.warn(`Missing config: ${path_1.default.resolve(resolvedComponentPath, [...modernFiles, ...legacyFiles].join(' or '))}`);
164
- continue;
165
- }
166
- const resolvedComponentConfigPath = path_1.default.resolve(resolvedComponentPath, declaration.fileName);
167
- configFiles.push(resolvedComponentConfigPath);
168
- let component;
169
- try {
170
- const importedDeclaration = loadDeclarationFile(resolvedComponentConfigPath, handoff.modulePath);
171
- const rawComponent = importedDeclaration.default || importedDeclaration;
172
- component = (0, declaration_1.normalizeComponentDeclaration)(rawComponent, {
173
- declarationPath: resolvedComponentConfigPath,
174
- fallbackId: componentBaseName,
175
- warn: (message) => logger_1.Logger.warn(message),
176
- });
177
- }
178
- catch (err) {
179
- logger_1.Logger.error(`Failed to read or parse config: ${resolvedComponentConfigPath}`, err);
180
- continue;
181
- }
182
- // Initialize options with safe defaults
183
- component.options || (component.options = {
184
- transformer: { defaults: {}, replace: {} },
174
+ // A directory's lane depends on what its declaration holds, not on which config key registered
175
+ // it, so the declaration is loaded before the lane is chosen.
176
+ for (const itemPath of (0, exports.getCatalogItemDirectories)(handoff.config, handoff.workingPath)) {
177
+ const itemBaseName = path_1.default.basename(itemPath);
178
+ const declaration = (0, exports.resolveComponentDeclaration)(itemPath, itemBaseName);
179
+ if (!declaration) {
180
+ const declarationFiles = getDeclarationFiles(itemBaseName);
181
+ logger_1.Logger.warn(`Missing catalog declaration (use .handoff.ts, .handoff.js, or .handoff.cjs; see UPGRADE.md#catalog-items): ${path_1.default.resolve(itemPath, declarationFiles.join(' or '))}`);
182
+ continue;
183
+ }
184
+ const declarationPath = path_1.default.resolve(itemPath, declaration.fileName);
185
+ const indexKey = (0, path_2.normalizePathForCompare)(declarationPath);
186
+ configFiles.push(declarationPath);
187
+ // A declaration can be mid-edit under `start`, so every failure is a warning and the file is
188
+ // retried on the next save. The index records it with an unknown kind, so a watcher does not
189
+ // guess the wrong lane.
190
+ const skip = (message, error) => {
191
+ // The message carries the authoring error, so it belongs in the warning rather than in a
192
+ // debug line the default log level hides.
193
+ const detail = error instanceof Error && error.message ? ` — ${error.message}` : '';
194
+ logger_1.Logger.warn(`${message}: ${declarationPath}${detail}`);
195
+ logger_1.Logger.debug('Declaration parse detail:', error);
196
+ configFileIndex.set(indexKey, { kind: 'unknown', entityId: itemBaseName });
197
+ };
198
+ let classified;
199
+ try {
200
+ const moduleExports = loadDeclarationFile(declarationPath, handoff.modulePath);
201
+ classified = (0, catalog_1.normalizeCatalogItem)(moduleExports, {
202
+ declarationPath,
203
+ fallbackId: itemBaseName,
204
+ warn: (message) => logger_1.Logger.warn(message),
185
205
  });
186
- (_l = component.options).transformer || (_l.transformer = { defaults: {}, replace: {} });
187
- const transformer = component.options.transformer;
188
- (_g = transformer.cssRootClass) !== null && _g !== void 0 ? _g : (transformer.cssRootClass = null);
189
- (_h = transformer.tokenNameSegments) !== null && _h !== void 0 ? _h : (transformer.tokenNameSegments = null);
190
- // Normalize keys and values to lowercase
191
- transformer.defaults = (0, exports.toLowerCaseKeysAndValues)(Object.assign({}, transformer.defaults));
192
- transformer.replace = (0, exports.toLowerCaseKeysAndValues)(Object.assign({}, transformer.replace));
193
- // Save transformer config
194
- result.options[component.id] = transformer;
195
- // Discover CSF stories early so patterns can resolve stories like normal previews.
196
- component.previews = discoverCsfPreviews(component, handoff);
197
- // Save full component entry
198
- result.entries.components[component.id] = component;
199
- configFileIndex.set((0, path_2.normalizePathForCompare)(resolvedComponentConfigPath), { kind: 'component', entityId: component.id });
200
206
  }
201
- }
202
- // -------------------------------------------------------------------------
203
- // Load pattern declarations
204
- // -------------------------------------------------------------------------
205
- if ((_k = (_j = handoff.config.entries) === null || _j === void 0 ? void 0 : _j.patterns) === null || _k === void 0 ? void 0 : _k.length) {
206
- const patternPaths = handoff.config.entries.patterns.flatMap(exports.getItemsForPath);
207
- for (const patternPath of patternPaths) {
208
- const resolvedPatternPath = path_1.default.resolve(handoff.workingPath, patternPath);
209
- const patternBaseName = path_1.default.basename(resolvedPatternPath);
210
- const declaration = (0, exports.resolveComponentDeclaration)(resolvedPatternPath, patternBaseName);
211
- if (!declaration) {
212
- const modernFiles = getModernDeclarationFiles(patternBaseName);
213
- const legacyFiles = getLegacyDeclarationFiles(patternBaseName);
214
- logger_1.Logger.warn(`Missing pattern config: ${path_1.default.resolve(resolvedPatternPath, [...modernFiles, ...legacyFiles].join(' or '))}`);
215
- continue;
216
- }
217
- const resolvedPatternConfigPath = path_1.default.resolve(resolvedPatternPath, declaration.fileName);
218
- configFiles.push(resolvedPatternConfigPath);
219
- let pattern;
220
- try {
221
- const importedDeclaration = loadDeclarationFile(resolvedPatternConfigPath, handoff.modulePath);
222
- const rawPattern = importedDeclaration.default || importedDeclaration;
223
- pattern = (0, pattern_1.normalizePatternDeclaration)(rawPattern, {
224
- declarationPath: resolvedPatternConfigPath,
225
- fallbackId: patternBaseName,
226
- });
227
- }
228
- catch (err) {
229
- // Treat as a warning rather than an error: the file may be empty or
230
- // mid-edit. It is already tracked in configFiles above, so
231
- // watchRuntimeConfiguration will pick it up once the file is saved
232
- // with valid content.
233
- logger_1.Logger.warn(`Pattern config skipped (incomplete or invalid) — will retry on next save: ${resolvedPatternConfigPath}`);
234
- logger_1.Logger.debug(`Pattern parse detail:`, err);
235
- continue;
236
- }
237
- configFileIndex.set((0, path_2.normalizePathForCompare)(resolvedPatternConfigPath), { kind: 'pattern', entityId: pattern.id });
238
- result.entries.patterns[pattern.id] = pattern;
207
+ catch (err) {
208
+ skip('Declaration skipped (incomplete or invalid) — will retry on next save', err);
209
+ continue;
239
210
  }
211
+ const takenBy = declaredIds.get(classified.item.id);
212
+ if (takenBy) {
213
+ logger_1.Logger.warn(`Catalog id "${classified.item.id}" is already declared by ${takenBy}. Skipping ${declarationPath}. ` +
214
+ `Give each catalog item a unique id.`);
215
+ result.duplicateCatalogIds.push({ id: classified.item.id, kept: takenBy, skipped: declarationPath });
216
+ // An unknown kind makes the watcher skip a rebuild. Any other kind rebuilds the item that owns the id.
217
+ configFileIndex.set(indexKey, { kind: 'unknown', entityId: classified.item.id });
218
+ continue;
219
+ }
220
+ declaredIds.set(classified.item.id, declarationPath);
221
+ if (classified.kind === 'pattern') {
222
+ const pattern = classified.item;
223
+ configFileIndex.set(indexKey, { kind: 'pattern', entityId: pattern.id });
224
+ result.entities.patterns[pattern.id] = pattern;
225
+ continue;
226
+ }
227
+ const component = classified.item;
228
+ // Initialize options with safe defaults
229
+ component.options || (component.options = {
230
+ transformer: { defaults: {}, replace: {} },
231
+ });
232
+ (_g = component.options).transformer || (_g.transformer = { defaults: {}, replace: {} });
233
+ const transformer = component.options.transformer;
234
+ (_e = transformer.cssRootClass) !== null && _e !== void 0 ? _e : (transformer.cssRootClass = null);
235
+ (_f = transformer.tokenNameSegments) !== null && _f !== void 0 ? _f : (transformer.tokenNameSegments = null);
236
+ // Normalize keys and values to lowercase
237
+ transformer.defaults = (0, exports.toLowerCaseKeysAndValues)(Object.assign({}, transformer.defaults));
238
+ transformer.replace = (0, exports.toLowerCaseKeysAndValues)(Object.assign({}, transformer.replace));
239
+ // Save transformer config
240
+ result.options[component.id] = transformer;
241
+ // Discover CSF stories early so compositions can resolve stories like normal previews.
242
+ component.previews = discoverCsfPreviews(component, handoff);
243
+ resolveCsfComponentSource(component);
244
+ // Save full component entry
245
+ result.entities.components[component.id] = component;
246
+ configFileIndex.set(indexKey, { kind: 'component', entityId: component.id });
240
247
  }
241
248
  // -------------------------------------------------------------------------
242
249
  // Discover markdown pages
@@ -252,7 +259,7 @@ const initRuntimeConfig = (handoff) => {
252
259
  const { data: frontmatter } = (0, markdown_1.parseMarkdown)(fs_extra_1.default.readFileSync(sourcePath, 'utf-8'));
253
260
  const routePath = slug === content_kinds_1.HOME_PAGE_ID ? content_kinds_1.HOME_PAGE_PATH : `/${slug}`;
254
261
  const page = (0, page_1.normalizePageDeclaration)(frontmatter, { id: slug, routePath, sourcePath });
255
- result.entries.pages[page.id] = page;
262
+ result.entities.pages[page.id] = page;
256
263
  }
257
264
  catch (err) {
258
265
  logger_1.Logger.warn(`Page skipped (unreadable or invalid frontmatter): ${sourcePath}`);
@@ -268,7 +275,7 @@ const initRuntimeConfig = (handoff) => {
268
275
  exports.initRuntimeConfig = initRuntimeConfig;
269
276
  /**
270
277
  * True when `searchPath` is itself a single component directory: it holds a declaration file named
271
- * after the directory (`{dirname}.handoff.*`, or a legacy `{dirname}.{json,js,cjs}`). This is what
278
+ * with a .handoff.ts, .handoff.js, or .handoff.cjs suffix. This is what
272
279
  * separates a declared component from a collection directory.
273
280
  */
274
281
  const isComponentDirectory = (searchPath) => !!(0, exports.resolveComponentDeclaration)(searchPath, path_1.default.basename(searchPath));
@@ -301,14 +308,6 @@ const getComponentsForPath = (searchPath) => {
301
308
  return [searchPath];
302
309
  };
303
310
  exports.getComponentsForPath = getComponentsForPath;
304
- /**
305
- * Generic directory discovery for both components and patterns.
306
- * Reuses the same logic as getComponentsForPath.
307
- */
308
- const getItemsForPath = (searchPath) => {
309
- return (0, exports.getComponentsForPath)(searchPath);
310
- };
311
- exports.getItemsForPath = getItemsForPath;
312
311
  /**
313
312
  * After both components and patterns are loaded, this function iterates all
314
313
  * pattern component refs and auto-registers synthetic preview entries on the
@@ -316,30 +315,32 @@ exports.getItemsForPath = getItemsForPath;
316
315
  *
317
316
  * This ensures the component build renders every preview needed by patterns
318
317
  * so that pattern composition is purely file I/O (no rendering).
318
+ *
319
+ * A ref that does not resolve records its reason in `unresolvedReason`. Nothing is logged here.
320
+ * Discovery runs for every command, and only the pattern build knows whether a ref is skipped or
321
+ * composed from a fallback. `buildPattern` reports it.
319
322
  */
320
323
  const injectPatternPreviews = (result) => {
321
- var _a, _b, _c, _d, _e, _f;
322
- const patterns = (_b = (_a = result.entries) === null || _a === void 0 ? void 0 : _a.patterns) !== null && _b !== void 0 ? _b : {};
323
- const components = (_d = (_c = result.entries) === null || _c === void 0 ? void 0 : _c.components) !== null && _d !== void 0 ? _d : {};
324
+ var _a, _b;
325
+ const patterns = result.entities.patterns;
326
+ const components = result.entities.components;
324
327
  for (const [patternId, pattern] of Object.entries(patterns)) {
325
328
  for (let i = 0; i < pattern.components.length; i++) {
326
329
  const ref = pattern.components[i];
327
330
  const component = components[ref.id];
328
331
  if (!component) {
329
- const error = `Pattern "${patternId}" references component "${ref.id}" which is not declared. This fragment will be skipped.`;
330
- logger_1.Logger.warn(error);
331
332
  ref.resolved = false;
333
+ ref.unresolvedReason = `component "${ref.id}" is not declared`;
332
334
  continue;
333
335
  }
334
336
  // Case 1: only preview, no args -> use the existing preview as-is
335
337
  if (ref.preview && !ref.args) {
336
- if ((_e = component.previews) === null || _e === void 0 ? void 0 : _e[ref.preview]) {
338
+ if ((_a = component.previews) === null || _a === void 0 ? void 0 : _a[ref.preview]) {
337
339
  ref.resolved = true;
338
340
  }
339
341
  else {
340
- const error = `Pattern "${patternId}" references preview "${ref.preview}" on component "${ref.id}" which does not exist. This fragment may be skipped.`;
341
- logger_1.Logger.warn(error);
342
342
  ref.resolved = false;
343
+ ref.unresolvedReason = `preview "${ref.preview}" of component "${ref.id}" is not declared`;
343
344
  }
344
345
  ref.resolvedPreview = ref.preview;
345
346
  continue;
@@ -353,22 +354,21 @@ const injectPatternPreviews = (result) => {
353
354
  ref.resolved = true;
354
355
  }
355
356
  else {
356
- logger_1.Logger.warn(`Pattern "${patternId}" component ref "${ref.id}" has neither "preview" nor "args", and the component has no previews. This fragment will be skipped.`);
357
357
  ref.resolved = false;
358
+ ref.unresolvedReason = `component "${ref.id}" has no previews, and the ref names no "preview" or "args"`;
358
359
  }
359
360
  continue;
360
361
  }
361
362
  // Case 3: args present (with or without preview base) -> create synthetic preview
362
363
  let resolvedValues = {};
363
364
  if (ref.preview) {
364
- const basePreview = (_f = component.previews) === null || _f === void 0 ? void 0 : _f[ref.preview];
365
+ const basePreview = (_b = component.previews) === null || _b === void 0 ? void 0 : _b[ref.preview];
365
366
  if (basePreview) {
366
367
  resolvedValues = Object.assign({}, basePreview.values);
367
368
  }
368
369
  else {
369
- const error = `Pattern "${patternId}" references preview "${ref.preview}" on component "${ref.id}" which does not exist. Using args only.`;
370
- logger_1.Logger.warn(error);
371
370
  ref.resolved = false;
371
+ ref.unresolvedReason = `preview "${ref.preview}" of component "${ref.id}" is not declared, so only "args" were used`;
372
372
  }
373
373
  }
374
374
  resolvedValues = Object.assign(Object.assign({}, resolvedValues), ref.args);
@@ -0,0 +1,9 @@
1
+ import type { CatalogItem, CatalogItemMeta } from './catalog/types';
2
+ export type { CatalogItem, CatalogItemMeta, CatalogPreview, CompositionRef, Preview, SourceDescriptor } from './catalog/types';
3
+ /**
4
+ * Declares a Handlebars catalog item. `implementation` is the path to its `.hbs` template. The
5
+ * renderer comes from this module, so the build fails an item whose file does not match it.
6
+ */
7
+ export declare const defineCatalogItem: <TArgs = Record<string, unknown>>(input: CatalogItemMeta & {
8
+ implementation: string;
9
+ }) => CatalogItem<TArgs>;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defineCatalogItem = void 0;
4
+ /**
5
+ * Handlebars catalog items.
6
+ *
7
+ * A template carries no type information, so arguments default to `Record<string, unknown>`. Pass
8
+ * an argument type to check previews: `defineCatalogItem<BadgeArgs>`.
9
+ */
10
+ const define_1 = require("./catalog/define");
11
+ /**
12
+ * Declares a Handlebars catalog item. `implementation` is the path to its `.hbs` template. The
13
+ * renderer comes from this module, so the build fails an item whose file does not match it.
14
+ */
15
+ const defineCatalogItem = (input) => (0, define_1.createCatalogItem)(input, 'handlebars');
16
+ exports.defineCatalogItem = defineCatalogItem;
package/dist/index.d.ts CHANGED
@@ -90,6 +90,20 @@ declare class Handoff {
90
90
  * client never enters the docs app bundle.
91
91
  */
92
92
  checkout(kind: TransferEntityKind, id?: string | string[]): Promise<Handoff>;
93
+ /**
94
+ * Publish the catalog items declared in this connected workspace to the configured remote registry:
95
+ * every one, or only the named ids. An item takes the component lane or the pattern lane depending
96
+ * on whether it declares an implementation or a composition, so the lane is resolved from the
97
+ * workspace rather than named by the caller. One build covers both lanes. The publish module is
98
+ * loaded lazily so the registry client and build code never enter the docs app bundle.
99
+ */
100
+ publishCatalog(id?: string | string[]): Promise<Handoff>;
101
+ /**
102
+ * Checkout published catalog items from the connected remote registry into this workspace: every
103
+ * one, or only the named ids. The lane an item was published into is looked up in the registry.
104
+ * Mirrors {@link publishCatalog}.
105
+ */
106
+ checkoutCatalog(id?: string | string[]): Promise<Handoff>;
93
107
  /**
94
108
  * Publish design token sets from this connected workspace to the configured remote registry. Runs a
95
109
  * fresh token build (Figma extract + style transformers), discovers the logical sets, and uploads
@@ -140,7 +154,6 @@ declare class Handoff {
140
154
  ejectConfig(): Promise<Handoff>;
141
155
  ejectPages(): Promise<Handoff>;
142
156
  ejectTheme(): Promise<Handoff>;
143
- makeTemplate(component: string, state: string): Promise<Handoff>;
144
157
  makePage(name: string, parent: string): Promise<Handoff>;
145
158
  makeComponent(name: string): Promise<Handoff>;
146
159
  start(): Promise<Handoff>;
@@ -215,12 +228,10 @@ declare class Handoff {
215
228
  */
216
229
  private readJsonFile;
217
230
  }
218
- export type { ComponentObject as Component } from './transformers/preview/types';
219
231
  export type { Config, RegisterHandlebarsHelpersContext } from './types/config';
220
232
  export { defineConfig } from './config';
221
- export { defineComponent, defineCsfComponent, defineHandlebarsComponent, definePattern, defineReactComponent, } from './declarations';
233
+ export type { CatalogItem, CatalogItemEntries, CatalogItemInput, CatalogItemMeta, CatalogPreview, CompositionRef, Preview, SourceDescriptor, SourceFormat, RendererKind, } from './catalog';
222
234
  export { defineAssetStorage } from './registry/asset-storage/define';
223
235
  export type { AssetStorage, AssetStorageContext, AssetStorageFactory, AssetStorageInput, AssetStorageReadResult, } from './registry/asset-storage/types';
224
- export type { CsfDeclarationConfig, DeclarationPreview, GenericDeclarationConfig, GenericPatternDeclarationConfig, HandlebarsDeclarationConfig, PatternComponentRef, ReactDeclarationConfig, RendererKind, } from './declarations';
225
236
  export { Transformers as CoreTransformers, TransformerUtils as CoreTransformerUtils, Types as CoreTypes } from 'handoff-core';
226
237
  export default Handoff;