handoff-app 2.0.0-6 → 2.0.0-8

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 (233) hide show
  1. package/README.md +240 -52
  2. package/UPGRADE.md +218 -0
  3. package/config/config.template.js +1 -4
  4. package/config/config.template.ts +1 -2
  5. package/dist/app-builder/build.js +12 -6
  6. package/dist/app-builder/client-config.js +3 -1
  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 +70 -61
  12. package/dist/cache/build-cache.js +23 -23
  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/auth/device.d.ts +6 -1
  27. package/dist/cli/auth/device.js +5 -2
  28. package/dist/cli/auth/store.d.ts +15 -6
  29. package/dist/cli/auth/store.js +72 -19
  30. package/dist/cli/make.d.ts +0 -5
  31. package/dist/cli/make.js +22 -67
  32. package/dist/cli/scaffold.js +25 -33
  33. package/dist/commands/checkout/index.d.ts +7 -4
  34. package/dist/commands/checkout/index.js +9 -6
  35. package/dist/commands/compat/push-args.d.ts +2 -2
  36. package/dist/commands/index.js +0 -2
  37. package/dist/commands/login/index.d.ts +5 -0
  38. package/dist/commands/login/index.js +18 -6
  39. package/dist/commands/logout/index.d.ts +5 -0
  40. package/dist/commands/logout/index.js +54 -15
  41. package/dist/commands/publish/index.d.ts +9 -6
  42. package/dist/commands/publish/index.js +11 -8
  43. package/dist/commands/pull/index.js +1 -1
  44. package/dist/commands/push/index.js +1 -1
  45. package/dist/commands/types.d.ts +2 -0
  46. package/dist/commands/utils.d.ts +36 -11
  47. package/dist/commands/utils.js +30 -16
  48. package/dist/config/catalog-include.d.ts +43 -0
  49. package/dist/config/catalog-include.js +203 -0
  50. package/dist/config/defaults.d.ts +3 -3
  51. package/dist/config/defaults.js +54 -48
  52. package/dist/config/env.d.ts +9 -0
  53. package/dist/config/env.js +43 -0
  54. package/dist/config/errors.d.ts +4 -0
  55. package/dist/config/errors.js +11 -0
  56. package/dist/config/from-env.d.ts +24 -0
  57. package/dist/config/from-env.js +7 -0
  58. package/dist/config/helpers.d.ts +2 -0
  59. package/dist/config/helpers.js +3 -1
  60. package/dist/config/index.d.ts +4 -3
  61. package/dist/config/index.js +10 -5
  62. package/dist/config/loader.d.ts +29 -11
  63. package/dist/config/loader.js +126 -45
  64. package/dist/config/resolve-env.d.ts +5 -0
  65. package/dist/config/resolve-env.js +102 -0
  66. package/dist/config/runtime.d.ts +7 -8
  67. package/dist/config/runtime.js +154 -154
  68. package/dist/config/validator.d.ts +2 -2
  69. package/dist/config/validator.js +2 -4
  70. package/dist/handlebars.d.ts +9 -0
  71. package/dist/handlebars.js +16 -0
  72. package/dist/index.d.ts +48 -8
  73. package/dist/index.js +88 -30
  74. package/dist/pattern.d.ts +7 -0
  75. package/dist/pattern.js +13 -0
  76. package/dist/pipeline/index.d.ts +1 -1
  77. package/dist/pipeline/index.js +1 -1
  78. package/dist/react.d.ts +43 -0
  79. package/dist/react.js +11 -0
  80. package/dist/registry/asset-storage/adapters/vercel-blob.js +1 -1
  81. package/dist/registry/asset-storage/define.d.ts +1 -1
  82. package/dist/registry/asset-storage/define.js +1 -1
  83. package/dist/registry/asset-storage/resolve.d.ts +2 -2
  84. package/dist/registry/asset-storage/resolve.js +4 -1
  85. package/dist/registry/checkout/index.d.ts +9 -0
  86. package/dist/registry/checkout/index.js +339 -153
  87. package/dist/registry/connection.d.ts +28 -24
  88. package/dist/registry/connection.js +53 -67
  89. package/dist/registry/db/driver.d.ts +4 -11
  90. package/dist/registry/db/driver.js +4 -16
  91. package/dist/registry/db/index.d.ts +1 -1
  92. package/dist/registry/db/index.js +1 -2
  93. package/dist/registry/db/schema.d.ts +34 -0
  94. package/dist/registry/db/schema.js +2 -0
  95. package/dist/registry/publish/index.d.ts +13 -2
  96. package/dist/registry/publish/index.js +113 -29
  97. package/dist/registry/publish/package.js +14 -1
  98. package/dist/registry/selection.d.ts +20 -0
  99. package/dist/registry/selection.js +37 -1
  100. package/dist/store/filesystem.d.ts +3 -3
  101. package/dist/store/filesystem.js +7 -7
  102. package/dist/store/registry.js +24 -3
  103. package/dist/transformers/plugins/csf-render.js +4 -2
  104. package/dist/transformers/plugins/ssr-render.js +14 -5
  105. package/dist/transformers/preview/component/api.d.ts +8 -0
  106. package/dist/transformers/preview/component/api.js +11 -15
  107. package/dist/transformers/preview/component/artifacts.d.ts +1 -1
  108. package/dist/transformers/preview/component/artifacts.js +11 -7
  109. package/dist/transformers/preview/component/builder.js +15 -18
  110. package/dist/transformers/preview/component/css.d.ts +2 -0
  111. package/dist/transformers/preview/component/css.js +8 -11
  112. package/dist/transformers/preview/component/html.js +18 -16
  113. package/dist/transformers/preview/component/javascript.js +2 -4
  114. package/dist/transformers/preview/pattern/builder.js +31 -18
  115. package/dist/transformers/preview/types.d.ts +15 -1
  116. package/dist/types/config.d.ts +77 -40
  117. package/docs/api.md +34 -0
  118. package/docs/cli.md +3 -3
  119. package/drizzle/0006_add_component_source_format.sql +3 -0
  120. package/drizzle/meta/0006_snapshot.json +1941 -0
  121. package/drizzle/meta/_journal.json +8 -1
  122. package/package.json +34 -1
  123. package/src/app/components/Component/Preview.tsx +36 -50
  124. package/src/app/components/Markdown/CodeHighlight.tsx +73 -70
  125. package/src/app/components/context/PreviewContext.tsx +5 -5
  126. package/src/app/components/util/index.ts +7 -15
  127. package/src/app/lib/mcp/shape.ts +6 -5
  128. package/src/app/lib/registry-api/transfer.ts +7 -5
  129. package/src/app/pages/account/tokens.tsx +3 -1
  130. package/src/app-builder/build.ts +13 -8
  131. package/src/app-builder/client-config.ts +5 -3
  132. package/src/app-builder/config-diff/strategies/pattern.ts +1 -1
  133. package/src/app-builder/watchers/component.ts +3 -3
  134. package/src/app-builder/watchers/utils.ts +2 -3
  135. package/src/app-builder/watchers.ts +63 -57
  136. package/src/cache/build-cache.ts +16 -15
  137. package/src/catalog/README.md +92 -0
  138. package/src/catalog/define.ts +79 -0
  139. package/src/catalog/implementation.ts +145 -0
  140. package/src/catalog/index.ts +31 -0
  141. package/src/catalog/normalize.ts +143 -0
  142. package/src/catalog/previews.ts +111 -0
  143. package/src/catalog/renderers.ts +94 -0
  144. package/src/catalog/types.ts +74 -0
  145. package/src/cli/README.md +1 -1
  146. package/src/cli/auth/device.ts +8 -3
  147. package/src/cli/auth/store.ts +75 -18
  148. package/src/cli/make.ts +20 -72
  149. package/src/cli/scaffold.ts +25 -31
  150. package/src/commands/README.md +1 -1
  151. package/src/commands/checkout/index.ts +17 -7
  152. package/src/commands/compat/push-args.ts +2 -2
  153. package/src/commands/index.ts +0 -2
  154. package/src/commands/login/index.ts +20 -6
  155. package/src/commands/logout/index.ts +74 -20
  156. package/src/commands/publish/index.ts +19 -9
  157. package/src/commands/pull/index.ts +2 -2
  158. package/src/commands/push/index.ts +2 -2
  159. package/src/commands/types.ts +2 -0
  160. package/src/commands/utils.ts +36 -12
  161. package/src/config/README.md +63 -2
  162. package/src/config/catalog-include.ts +227 -0
  163. package/src/config/defaults.ts +24 -14
  164. package/src/config/env.ts +41 -0
  165. package/src/config/errors.ts +7 -0
  166. package/src/config/from-env.ts +26 -0
  167. package/src/config/helpers.ts +4 -2
  168. package/src/config/index.ts +7 -4
  169. package/src/config/loader.ts +168 -50
  170. package/src/config/resolve-env.ts +94 -0
  171. package/src/config/runtime.ts +188 -193
  172. package/src/config/validator.ts +4 -6
  173. package/src/handlebars.ts +18 -0
  174. package/src/index.d.ts +2 -2
  175. package/src/index.ts +124 -34
  176. package/src/pattern.ts +14 -0
  177. package/src/pipeline/index.ts +1 -1
  178. package/src/react.ts +52 -0
  179. package/src/registry/asset-storage/adapters/vercel-blob.ts +1 -1
  180. package/src/registry/asset-storage/define.ts +1 -1
  181. package/src/registry/asset-storage/resolve.ts +6 -3
  182. package/src/registry/checkout/index.ts +421 -157
  183. package/src/registry/connection.ts +72 -71
  184. package/src/registry/db/driver.ts +6 -17
  185. package/src/registry/db/index.ts +0 -1
  186. package/src/registry/db/schema.ts +2 -0
  187. package/src/registry/publish/index.ts +128 -31
  188. package/src/registry/publish/package.ts +14 -1
  189. package/src/registry/selection.ts +44 -0
  190. package/src/store/filesystem.ts +6 -6
  191. package/src/store/registry.ts +13 -2
  192. package/src/transformers/plugins/csf-render.ts +4 -2
  193. package/src/transformers/plugins/ssr-render.ts +15 -5
  194. package/src/transformers/preview/component/api.ts +13 -1
  195. package/src/transformers/preview/component/artifacts.ts +8 -4
  196. package/src/transformers/preview/component/builder.ts +17 -4
  197. package/src/transformers/preview/component/css.ts +6 -10
  198. package/src/transformers/preview/component/html.ts +30 -19
  199. package/src/transformers/preview/component/javascript.ts +1 -3
  200. package/src/transformers/preview/pattern/builder.ts +33 -20
  201. package/src/transformers/preview/types.ts +15 -1
  202. package/src/types/config.ts +76 -40
  203. package/templates/default/components/button/button.react.handoff.js.tpl +19 -23
  204. package/templates/default/components/button/button.react.handoff.ts.tpl +22 -22
  205. package/templates/default/env.tpl +10 -0
  206. package/templates/default/gitignore.tpl +7 -0
  207. package/templates/default/handoff.config.js.tpl +21 -182
  208. package/templates/default/handoff.config.ts.tpl +21 -166
  209. package/templates/default/handoff.config.with-examples.js.tpl +22 -180
  210. package/templates/default/handoff.config.with-examples.ts.tpl +22 -164
  211. package/config/templates/component/template.json +0 -49
  212. package/config/templates/template.html +0 -7
  213. package/dist/commands/make/template.d.ts +0 -8
  214. package/dist/commands/make/template.js +0 -43
  215. package/dist/config/entries.d.ts +0 -47
  216. package/dist/config/entries.js +0 -162
  217. package/dist/config/normalizers/declaration.d.ts +0 -11
  218. package/dist/config/normalizers/declaration.js +0 -122
  219. package/dist/config/normalizers/pattern.d.ts +0 -8
  220. package/dist/config/normalizers/pattern.js +0 -41
  221. package/dist/declarations/helpers.d.ts +0 -6
  222. package/dist/declarations/helpers.js +0 -19
  223. package/dist/declarations/index.d.ts +0 -2
  224. package/dist/declarations/index.js +0 -9
  225. package/dist/declarations/types.d.ts +0 -60
  226. package/src/commands/make/template.ts +0 -46
  227. package/src/config/entries.ts +0 -175
  228. package/src/config/normalizers/declaration.ts +0 -179
  229. package/src/config/normalizers/pattern.ts +0 -59
  230. package/src/declarations/helpers.ts +0 -36
  231. package/src/declarations/index.ts +0 -19
  232. package/src/declarations/types.ts +0 -70
  233. /package/dist/{declarations → catalog}/types.js +0 -0
@@ -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 {};
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.normalizeCatalogItem = void 0;
18
+ const lodash_1 = require("lodash");
19
+ const path_1 = __importDefault(require("path"));
20
+ const define_1 = require("./define");
21
+ const implementation_1 = require("./implementation");
22
+ const previews_1 = require("./previews");
23
+ const renderers_1 = require("./renderers");
24
+ /** Imported component values need a file path recovered from the declaration source. */
25
+ const resolveImplementation = (item, options) => {
26
+ const stamped = item.implementation;
27
+ const source = { renderer: stamped.renderer, sourceFormat: stamped.format };
28
+ if (stamped.file) {
29
+ return Object.assign(Object.assign({}, source), { file: stamped.file });
30
+ }
31
+ const declarationDir = path_1.default.dirname(options.declarationPath);
32
+ const resolved = (0, implementation_1.resolvePropertySource)(options.declarationPath, 'implementation');
33
+ if (resolved) {
34
+ if (!(0, implementation_1.isInsideDirectory)(resolved.file, declarationDir)) {
35
+ options.warn(`Catalog item "${options.fallbackId}" resolves its implementation to "${resolved.file}", outside "${declarationDir}". ` +
36
+ `Previews still build, but the item cannot be published. Move the file into the item directory to publish it.`);
37
+ }
38
+ return Object.assign(Object.assign({}, source), { file: resolved.file, exportName: resolved.exportName });
39
+ }
40
+ const sibling = (0, implementation_1.findSiblingComponentFile)(declarationDir, options.declarationPath);
41
+ if (sibling) {
42
+ options.warn(`Catalog item "${options.fallbackId}" in "${options.declarationPath}" could not resolve the import behind ` +
43
+ `"implementation". Using "${path_1.default.basename(sibling)}". Set "implementation" to the file path to be explicit.`);
44
+ return Object.assign(Object.assign({}, source), { file: sibling });
45
+ }
46
+ options.warn(`Catalog item "${options.fallbackId}" in "${options.declarationPath}" could not resolve the import behind ` +
47
+ `"implementation". Set "implementation" to the file path instead of the imported value.`);
48
+ return source;
49
+ };
50
+ const quotedList = (values) => values.map((value) => `"${value}"`).join(' or ');
51
+ /** Maps the authoring contract directly into the runtime read model. */
52
+ const normalizeCatalogItem = (moduleExports, options) => {
53
+ var _a, _b, _c;
54
+ const item = (_a = moduleExports.default) !== null && _a !== void 0 ? _a : moduleExports;
55
+ (0, define_1.validateCatalogItem)(item);
56
+ const { implementation, composition, __args, name, shouldDo, shouldNotDo } = item, meta = __rest(item, ["implementation", "composition", "__args", "name", "shouldDo", "shouldNotDo"]);
57
+ const id = typeof meta.id === 'string' && meta.id.trim() ? meta.id.trim() : options.fallbackId;
58
+ const title = name || (0, lodash_1.startCase)(id);
59
+ const directory = path_1.default.dirname(options.declarationPath);
60
+ if (composition) {
61
+ return {
62
+ kind: 'pattern',
63
+ item: {
64
+ id,
65
+ title,
66
+ path: directory,
67
+ description: meta.description,
68
+ group: meta.group,
69
+ tags: meta.tags,
70
+ components: composition.map((ref) => ({
71
+ id: ref.ref.trim(),
72
+ preview: typeof ref.preview === 'string' ? ref.preview.trim() : undefined,
73
+ args: ref.args ? Object.assign({}, ref.args) : undefined,
74
+ })),
75
+ },
76
+ };
77
+ }
78
+ const source = resolveImplementation(item, options);
79
+ const entries = {};
80
+ for (const [key, value] of Object.entries((_b = meta.entries) !== null && _b !== void 0 ? _b : {})) {
81
+ if (value)
82
+ entries[key] = path_1.default.resolve(directory, value);
83
+ }
84
+ const entryKey = (0, renderers_1.entryKeyFor)(source.renderer, source.sourceFormat);
85
+ if (!source.file) {
86
+ throw new Error(`Catalog item "${id}" needs an implementation file. Set implementation to a file path.`);
87
+ }
88
+ entries[entryKey] = path_1.default.resolve(directory, source.file);
89
+ // Existing builders consume template as the primary build input for every renderer.
90
+ entries.template = entries[entryKey];
91
+ // A wrong renderer builds a broken preview without failing on its own, so a mismatch is fatal.
92
+ // `config/runtime.ts` turns the throw into a skipped item that retries on the next save.
93
+ const claim = (0, renderers_1.sourceForFile)(source.file);
94
+ if (claim && !claim.renderers.includes(source.renderer)) {
95
+ throw new Error(`Catalog item "${id}" declares renderer "${source.renderer}", but "${source.file}" is a ${quotedList(claim.renderers)} source. ` +
96
+ `Declare it from ${quotedList(claim.renderers.map(renderers_1.moduleFor))}.`);
97
+ }
98
+ // Only a suffix that names a format is conclusive. A `.stories.tsx` file is always CSF, while a
99
+ // plain `.tsx` file says nothing about its format.
100
+ const fileFormat = claim === null || claim === void 0 ? void 0 : claim.format;
101
+ // The comparison narrows a single-format union to `never`, so read the helper first.
102
+ const fileFormatHelper = fileFormat && renderers_1.SOURCE_FORMATS[fileFormat].helper;
103
+ if (fileFormat && fileFormat !== source.sourceFormat) {
104
+ throw new Error(`Catalog item "${id}" declares "${source.file}" as a plain source, but it is a "${fileFormat}" source. ` +
105
+ `Wrap it with ${fileFormatHelper}() from "${(0, renderers_1.moduleFor)(source.renderer)}".`);
106
+ }
107
+ if (((_c = meta.page) === null || _c === void 0 ? void 0 : _c.slices) && !Array.isArray(meta.page.slices)) {
108
+ throw new Error(`Catalog item "${id}" has invalid page.slices; expected an array.`);
109
+ }
110
+ return {
111
+ kind: 'component',
112
+ item: Object.assign(Object.assign(Object.assign(Object.assign({}, meta), { id, title: name || '', path: directory, should_do: shouldDo, should_not_do: shouldNotDo, renderer: source.renderer, sourceFormat: source.sourceFormat, entries }), (source.exportName && source.exportName !== 'default' ? { componentExport: source.exportName } : {})), { previews: (0, previews_1.createCatalogPreviews)(moduleExports, options.declarationPath) }),
113
+ };
114
+ };
115
+ exports.normalizeCatalogItem = normalizeCatalogItem;
@@ -0,0 +1,18 @@
1
+ import type { OptionalPreviewRender } from '../transformers/preview/types';
2
+ /**
3
+ * Exported names in the order the source declares them.
4
+ *
5
+ * The evaluated module cannot supply this order. esbuild emits its export map alphabetically, and
6
+ * an ESM namespace object has sorted keys by specification.
7
+ */
8
+ export declare const readExportOrderFromSource: (sourceCode: string) => string[];
9
+ /** Exported names in source order, or an empty list when the file cannot be read. */
10
+ export declare const readExportOrder: (filePath: string) => string[];
11
+ /**
12
+ * Re-keys previews into the given order. A preview the order does not mention is placed after the
13
+ * ordered ones, so an export form the parser does not recognize falls back to the evaluated order
14
+ * rather than dropping the preview.
15
+ */
16
+ export declare const orderPreviews: <T>(previews: Record<string, T>, order: string[]) => Record<string, T>;
17
+ /** Collects the named exports of a declaration module as previews, in declaration order. */
18
+ export declare const createCatalogPreviews: (moduleExports: Record<string, unknown>, declarationPath?: string) => Record<string, OptionalPreviewRender>;
@@ -0,0 +1,106 @@
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.createCatalogPreviews = exports.orderPreviews = exports.readExportOrder = exports.readExportOrderFromSource = void 0;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const lodash_1 = require("lodash");
9
+ /**
10
+ * A declaration module exports more than previews: the item itself, the implementation it
11
+ * re-exports, helper values. Accept only a plain object that owns `args` or `name`, so an exported
12
+ * component or helper is never mistaken for a preview.
13
+ *
14
+ * `getCsfStoryEntries` does not fit here: on a CSF file every named export is a story, and on a
15
+ * declaration file it is not.
16
+ */
17
+ const isPreviewDeclaration = (value) => {
18
+ if (!value || typeof value !== 'object' || Array.isArray(value))
19
+ return false;
20
+ return Object.prototype.hasOwnProperty.call(value, 'args') || Object.prototype.hasOwnProperty.call(value, 'name');
21
+ };
22
+ /** Matches an exported binding, an export list, or a CommonJS export assignment. */
23
+ const EXPORT_PATTERNS = [
24
+ { pattern: /\bexport\s+(?:async\s+)?(?:const|let|var|function\s*\*?|class)\s+([A-Za-z_$][\w$]*)/g },
25
+ { pattern: /\bexport\s*(?!type[\s{])\{([^}]*)\}/g, list: true },
26
+ { pattern: /\bexports\.([A-Za-z_$][\w$]*)\s*=/g },
27
+ ];
28
+ /** Reads the exported name an export-list specifier binds: `A as B` exports `B`, `A` exports `A`. */
29
+ const readExportedName = (specifier) => {
30
+ const name = specifier.trim().replace(/^type\s+/, '');
31
+ if (!name)
32
+ return undefined;
33
+ const aliased = name.match(/^[A-Za-z_$][\w$]*\s+as\s+([A-Za-z_$][\w$]*)$/);
34
+ if (aliased)
35
+ return aliased[1];
36
+ return /^[A-Za-z_$][\w$]*$/.test(name) ? name : undefined;
37
+ };
38
+ /**
39
+ * Exported names in the order the source declares them.
40
+ *
41
+ * The evaluated module cannot supply this order. esbuild emits its export map alphabetically, and
42
+ * an ESM namespace object has sorted keys by specification.
43
+ */
44
+ const readExportOrderFromSource = (sourceCode) => {
45
+ const found = [];
46
+ for (const { pattern, list } of EXPORT_PATTERNS) {
47
+ for (const match of sourceCode.matchAll(pattern)) {
48
+ const names = list ? match[1].split(',').map(readExportedName) : [match[1]];
49
+ names.forEach((name, offset) => {
50
+ if (name)
51
+ found.push({ index: match.index + offset, name });
52
+ });
53
+ }
54
+ }
55
+ const order = [];
56
+ const seen = new Set();
57
+ for (const { name } of found.sort((a, b) => a.index - b.index)) {
58
+ if (seen.has(name))
59
+ continue;
60
+ seen.add(name);
61
+ order.push(name);
62
+ }
63
+ return order;
64
+ };
65
+ exports.readExportOrderFromSource = readExportOrderFromSource;
66
+ /** Exported names in source order, or an empty list when the file cannot be read. */
67
+ const readExportOrder = (filePath) => {
68
+ try {
69
+ return (0, exports.readExportOrderFromSource)(fs_extra_1.default.readFileSync(filePath, 'utf8'));
70
+ }
71
+ catch (_a) {
72
+ return [];
73
+ }
74
+ };
75
+ exports.readExportOrder = readExportOrder;
76
+ /**
77
+ * Re-keys previews into the given order. A preview the order does not mention is placed after the
78
+ * ordered ones, so an export form the parser does not recognize falls back to the evaluated order
79
+ * rather than dropping the preview.
80
+ */
81
+ const orderPreviews = (previews, order) => {
82
+ if (order.length === 0)
83
+ return previews;
84
+ const ranked = new Set(order.filter((name) => name in previews));
85
+ const rest = Object.keys(previews).filter((name) => !ranked.has(name));
86
+ return Object.fromEntries([...ranked, ...rest].map((name) => [name, previews[name]]));
87
+ };
88
+ exports.orderPreviews = orderPreviews;
89
+ /** Collects the named exports of a declaration module as previews, in declaration order. */
90
+ const createCatalogPreviews = (moduleExports, declarationPath) => {
91
+ var _a, _b;
92
+ const previews = {};
93
+ for (const [exportName, value] of Object.entries(moduleExports !== null && moduleExports !== void 0 ? moduleExports : {})) {
94
+ if (exportName === 'default' || exportName === '__esModule')
95
+ continue;
96
+ if (!isPreviewDeclaration(value))
97
+ continue;
98
+ if (value && typeof value === 'object' && ('values' in value || 'title' in value)) {
99
+ throw new Error(`Preview "${exportName}" uses removed fields. Use args and name. See UPGRADE.md#catalog-items.`);
100
+ }
101
+ const preview = value;
102
+ previews[exportName] = Object.assign({ title: preview.name || (0, lodash_1.startCase)(exportName), values: Object.assign({}, ((_a = preview.args) !== null && _a !== void 0 ? _a : {})), url: (_b = preview.url) !== null && _b !== void 0 ? _b : '' }, (preview.usage ? { usage: preview.usage } : {}));
103
+ }
104
+ return declarationPath ? (0, exports.orderPreviews)(previews, (0, exports.readExportOrder)(declarationPath)) : previews;
105
+ };
106
+ exports.createCatalogPreviews = createCatalogPreviews;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * This module has no runtime imports, so every layer can use the renderer registry.
3
+ * Import it directly to avoid the catalog barrel dependencies, including `fs-extra`.
4
+ */
5
+ /** Add a renderer only with its preview support. */
6
+ export type RendererKind = 'react' | 'handlebars';
7
+ /** How an implementation file is written, independent of the renderer that renders it. */
8
+ export type SourceFormat = 'csf';
9
+ /** Key in `entries` that holds an implementation file. */
10
+ export type EntryKey = 'component' | 'template' | 'story';
11
+ export type ComponentSource = {
12
+ renderer: RendererKind;
13
+ sourceFormat?: SourceFormat;
14
+ };
15
+ type RendererDefinition = {
16
+ /** Declaration module that supplies this renderer. */
17
+ module: string;
18
+ /** Entry key normalization writes the implementation file to. */
19
+ entryKey: EntryKey;
20
+ };
21
+ type SourceFormatDefinition = {
22
+ /** Renderers this format applies to. */
23
+ renderers: RendererKind[];
24
+ entryKey: EntryKey;
25
+ /** Export of the renderer module that declares an implementation in this format. */
26
+ helper: string;
27
+ };
28
+ export declare const RENDERERS: Record<RendererKind, RendererDefinition>;
29
+ export declare const SOURCE_FORMATS: Record<SourceFormat, SourceFormatDefinition>;
30
+ /** Which renderers can own a file name, and the source format the name implies. */
31
+ export type SourceClaim = {
32
+ renderers: RendererKind[];
33
+ format?: SourceFormat;
34
+ };
35
+ export declare const isRendererKind: (value: unknown) => value is RendererKind;
36
+ export declare const isSourceFormat: (value: unknown) => value is SourceFormat;
37
+ /** What the file name says about a source, matched case-insensitively. Undefined when no suffix claims it. */
38
+ export declare const sourceForFile: (file: string | undefined) => SourceClaim | undefined;
39
+ /** Entry key normalization records the implementation file under, if the renderer is registered. */
40
+ export declare const entryKeyFor: (renderer: RendererKind | undefined, sourceFormat?: SourceFormat) => EntryKey | undefined;
41
+ /** Declaration module that supplies a renderer, or undefined when it has no module of its own. */
42
+ export declare const moduleFor: (renderer: RendererKind | undefined) => string | undefined;
43
+ export {};
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * This module has no runtime imports, so every layer can use the renderer registry.
4
+ * Import it directly to avoid the catalog barrel dependencies, including `fs-extra`.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.moduleFor = exports.entryKeyFor = exports.sourceForFile = exports.isSourceFormat = exports.isRendererKind = exports.SOURCE_FORMATS = exports.RENDERERS = void 0;
8
+ exports.RENDERERS = {
9
+ react: {
10
+ module: 'handoff-app/react',
11
+ entryKey: 'component',
12
+ },
13
+ handlebars: {
14
+ module: 'handoff-app/handlebars',
15
+ entryKey: 'template',
16
+ },
17
+ };
18
+ exports.SOURCE_FORMATS = {
19
+ csf: {
20
+ renderers: ['react'],
21
+ entryKey: 'story',
22
+ helper: 'fromCSF',
23
+ },
24
+ };
25
+ /**
26
+ * This table never decides a renderer. The declaration states it, and the table only checks the
27
+ * implementation file against it. Keying by suffix keeps one row per file name: a suffix that more
28
+ * than one renderer owns lists them all, and a duplicate key is a compile error. A file that no
29
+ * row claims is not checked.
30
+ */
31
+ const SOURCE_SUFFIXES = {
32
+ '.stories.tsx': { renderers: ['react'], format: 'csf' },
33
+ '.stories.jsx': { renderers: ['react'], format: 'csf' },
34
+ '.stories.ts': { renderers: ['react'], format: 'csf' },
35
+ '.stories.js': { renderers: ['react'], format: 'csf' },
36
+ '.tsx': { renderers: ['react'] },
37
+ '.jsx': { renderers: ['react'] },
38
+ '.hbs': { renderers: ['handlebars'] },
39
+ };
40
+ /** Longest first, so `.stories.tsx` reads as a CSF source rather than a plain React source. */
41
+ const SUFFIXES_BY_LENGTH = Object.keys(SOURCE_SUFFIXES).sort((first, second) => second.length - first.length);
42
+ const RENDERER_KINDS = Object.keys(exports.RENDERERS);
43
+ const SOURCE_FORMAT_KINDS = Object.keys(exports.SOURCE_FORMATS);
44
+ const isRendererKind = (value) => RENDERER_KINDS.includes(value);
45
+ exports.isRendererKind = isRendererKind;
46
+ const isSourceFormat = (value) => SOURCE_FORMAT_KINDS.includes(value);
47
+ exports.isSourceFormat = isSourceFormat;
48
+ /** What the file name says about a source, matched case-insensitively. Undefined when no suffix claims it. */
49
+ const sourceForFile = (file) => {
50
+ if (!file)
51
+ return undefined;
52
+ const lowerCased = file.toLowerCase();
53
+ const suffix = SUFFIXES_BY_LENGTH.find((candidate) => lowerCased.endsWith(candidate));
54
+ return suffix ? SOURCE_SUFFIXES[suffix] : undefined;
55
+ };
56
+ exports.sourceForFile = sourceForFile;
57
+ /** Entry key normalization records the implementation file under, if the renderer is registered. */
58
+ const entryKeyFor = (renderer, sourceFormat) => { var _a, _b; return sourceFormat ? (_a = exports.SOURCE_FORMATS[sourceFormat]) === null || _a === void 0 ? void 0 : _a.entryKey : renderer ? (_b = exports.RENDERERS[renderer]) === null || _b === void 0 ? void 0 : _b.entryKey : undefined; };
59
+ exports.entryKeyFor = entryKeyFor;
60
+ /** Declaration module that supplies a renderer, or undefined when it has no module of its own. */
61
+ const moduleFor = (renderer) => { var _a; return (renderer ? (_a = exports.RENDERERS[renderer]) === null || _a === void 0 ? void 0 : _a.module : undefined); };
62
+ exports.moduleFor = moduleFor;
@@ -0,0 +1,63 @@
1
+ import type { RendererKind, SourceFormat } from './renderers';
2
+ import type { ComponentObject } from '../transformers/preview/types';
3
+ /**
4
+ * How an implementation file is written. `fromCSF('./Button.stories.tsx')` is shorthand for
5
+ * `{ format: 'csf', file: './Button.stories.tsx' }`.
6
+ */
7
+ export type SourceDescriptor<TFormat extends string = string> = {
8
+ format: TFormat;
9
+ file: string;
10
+ };
11
+ export type CsfSource = SourceDescriptor<'csf'>;
12
+ /** The loader recovers the file for an imported component in `value` from the declaration source. */
13
+ export type NormalizedImplementation = {
14
+ renderer: RendererKind;
15
+ format?: SourceFormat;
16
+ file?: string;
17
+ value?: unknown;
18
+ };
19
+ export type CatalogItemEntries = Pick<NonNullable<ComponentObject['entries']>, 'js' | 'scss' | 'schema' | 'templates'>;
20
+ /**
21
+ * Metadata a catalog item can carry. `type` and `categories` are free-form classification, so a
22
+ * term such as atom, element, or block goes there.
23
+ */
24
+ export type CatalogItemMeta = Partial<Omit<ComponentObject, 'previews' | 'previewOrder' | 'entries' | 'title' | 'should_do' | 'should_not_do' | 'renderer' | 'sourceFormat' | 'componentExport'>> & {
25
+ id?: string;
26
+ name?: string;
27
+ description?: string;
28
+ group?: string;
29
+ entries?: CatalogItemEntries;
30
+ shouldDo?: string[];
31
+ shouldNotDo?: string[];
32
+ };
33
+ /** One member of a composition. `ref` is the id of another catalog item. */
34
+ export type CompositionRef = {
35
+ ref: string;
36
+ preview?: string;
37
+ args?: Record<string, unknown>;
38
+ };
39
+ /** A named preview, exported next to the catalog item it belongs to. */
40
+ export type CatalogPreview<TArgs = Record<string, unknown>> = {
41
+ /** Display title. Defaults to a start-cased form of the export name. */
42
+ name?: string;
43
+ args?: TArgs;
44
+ usage?: string;
45
+ url?: string;
46
+ };
47
+ /**
48
+ * `__args` exists only in the type system so `Preview<typeof item>` can infer the preview argument type.
49
+ */
50
+ export type CatalogItem<TArgs = Record<string, unknown>> = CatalogItemMeta & {
51
+ implementation?: unknown;
52
+ composition?: CompositionRef[];
53
+ readonly __args?: TArgs;
54
+ };
55
+ /** Preview type for a catalog item, with its argument type applied. */
56
+ export type Preview<TItem> = TItem extends {
57
+ readonly __args?: infer TArgs;
58
+ } ? CatalogPreview<Partial<NonNullable<TArgs>>> : never;
59
+ /** Input accepted by every `defineCatalogItem` entry point. */
60
+ export type CatalogItemInput = CatalogItemMeta & {
61
+ implementation?: unknown;
62
+ composition?: CompositionRef[];
63
+ };
@@ -1,8 +1,13 @@
1
1
  import { type CliAuth } from './store';
2
2
  export interface LoginOptions {
3
3
  openBrowser?: boolean;
4
+ /** Profile the issued credential is saved under. Omitted, it is the default profile. */
5
+ profile?: string;
4
6
  }
5
- /** Complete the device grant and persist the one-time plaintext access token for this workspace. */
7
+ /**
8
+ * Complete the device grant and persist the one-time plaintext access token for this workspace,
9
+ * under the selected profile.
10
+ */
6
11
  export declare const loginWithDevice: (workingPath: string, remoteUrl: string, options?: LoginOptions) => Promise<CliAuth>;
7
12
  /**
8
13
  * Best-effort remote revocation. The caller must clear the local credential regardless of failure.
@@ -53,7 +53,10 @@ const shouldOpenBrowser = (options) => {
53
53
  return process.env.HANDOFF_LOGIN_NO_BROWSER !== '1' && process.env.HANDOFF_LOGIN_NO_BROWSER !== 'true';
54
54
  };
55
55
  const positiveNumberOr = (value, fallback) => typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : fallback;
56
- /** Complete the device grant and persist the one-time plaintext access token for this workspace. */
56
+ /**
57
+ * Complete the device grant and persist the one-time plaintext access token for this workspace,
58
+ * under the selected profile.
59
+ */
57
60
  const loginWithDevice = (workingPath_1, remoteUrl_1, ...args_1) => __awaiter(void 0, [workingPath_1, remoteUrl_1, ...args_1], void 0, function* (workingPath, remoteUrl, options = {}) {
58
61
  const baseUrl = (0, store_1.normalizeRegistryUrl)(remoteUrl);
59
62
  let deviceResponse;
@@ -115,7 +118,7 @@ const loginWithDevice = (workingPath_1, remoteUrl_1, ...args_1) => __awaiter(voi
115
118
  accessToken: token.access_token,
116
119
  expiresAtMs: Date.now() + expiresIn * 1000,
117
120
  };
118
- yield (0, store_1.writeCliAuth)(workingPath, auth);
121
+ yield (0, store_1.writeCliAuth)(workingPath, auth, options.profile);
119
122
  return auth;
120
123
  }
121
124
  const failure = responseError(token);