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
@@ -5,6 +5,8 @@ export interface CliAuth {
5
5
  /** Epoch milliseconds after which the token must not be used. */
6
6
  expiresAtMs: number;
7
7
  }
8
+ /** Name a login is saved under when no profile is selected. */
9
+ export declare const DEFAULT_LOGIN_PROFILE = "default";
8
10
  /**
9
11
  * Canonicalize a registry URL for both HTTP requests and exact credential matching.
10
12
  * Base paths are retained; query strings, fragments, credentials, and trailing slashes are not.
@@ -17,13 +19,20 @@ export declare const normalizeRegistryUrl: (value: string) => string;
17
19
  */
18
20
  export declare const assertRegistryOriginUrl: (baseUrl: string, candidate: string) => string;
19
21
  export declare const cliAuthFilePath: (workingPath: string) => string;
20
- /** Invalid or partial credential files are treated as unauthenticated. */
21
- export declare const readCliAuth: (workingPath: string) => Promise<CliAuth | null>;
22
+ /** Every saved login, keyed by profile name. A missing or unreadable file reads as no logins. */
23
+ export declare const readCliLogins: (workingPath: string) => Promise<Record<string, CliAuth>>;
24
+ /** The login saved under one profile name. Never falls back to another profile. */
25
+ export declare const readCliAuth: (workingPath: string, profile?: string) => Promise<CliAuth | null>;
22
26
  /**
23
- * Atomically replace the credential file. Restrictive permissions are best-effort on platforms
24
- * whose filesystems do not support POSIX modes.
27
+ * Profile names that have a saved login. Synchronous because config loading is, and the loader needs
28
+ * these names to decide whether a selected profile resolves.
25
29
  */
26
- export declare const writeCliAuth: (workingPath: string, auth: CliAuth) => Promise<void>;
27
- export declare const clearCliAuth: (workingPath: string) => Promise<void>;
30
+ export declare const loginProfileNames: (workingPath: string) => string[];
31
+ /** Save the login for one profile and leave the other profiles in place. */
32
+ export declare const writeCliAuth: (workingPath: string, auth: CliAuth, profile?: string) => Promise<void>;
33
+ /** Remove the login for one profile, and the file itself once no login is left. */
34
+ export declare const clearCliAuth: (workingPath: string, profile?: string) => Promise<void>;
35
+ /** Remove every saved login. */
36
+ export declare const clearAllCliAuth: (workingPath: string) => Promise<void>;
28
37
  export declare const cliAuthMatchesRegistry: (auth: CliAuth | null, remoteUrl: string) => boolean;
29
38
  export declare const cliAuthTokenIsValid: (auth: CliAuth | null, skewMs?: number) => boolean;
@@ -12,9 +12,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.cliAuthTokenIsValid = exports.cliAuthMatchesRegistry = exports.clearCliAuth = exports.writeCliAuth = exports.readCliAuth = exports.cliAuthFilePath = exports.assertRegistryOriginUrl = exports.normalizeRegistryUrl = void 0;
15
+ exports.cliAuthTokenIsValid = exports.cliAuthMatchesRegistry = exports.clearAllCliAuth = exports.clearCliAuth = exports.writeCliAuth = exports.loginProfileNames = exports.readCliAuth = exports.readCliLogins = exports.cliAuthFilePath = exports.assertRegistryOriginUrl = exports.normalizeRegistryUrl = exports.DEFAULT_LOGIN_PROFILE = void 0;
16
16
  const fs_extra_1 = __importDefault(require("fs-extra"));
17
17
  const path_1 = __importDefault(require("path"));
18
+ /** Name a login is saved under when no profile is selected. */
19
+ exports.DEFAULT_LOGIN_PROFILE = 'default';
18
20
  const AUTH_DIRECTORY = '.handoff';
19
21
  const AUTH_FILE = 'cli-auth.json';
20
22
  /**
@@ -63,38 +65,71 @@ const assertRegistryOriginUrl = (baseUrl, candidate) => {
63
65
  exports.assertRegistryOriginUrl = assertRegistryOriginUrl;
64
66
  const cliAuthFilePath = (workingPath) => path_1.default.resolve(workingPath, AUTH_DIRECTORY, AUTH_FILE);
65
67
  exports.cliAuthFilePath = cliAuthFilePath;
66
- const isCliAuth = (value) => {
68
+ /** An invalid or partial entry reads as no login, so one bad entry cannot hide the others. */
69
+ const toCliAuth = (value) => {
67
70
  if (!value || typeof value !== 'object')
68
- return false;
71
+ return null;
69
72
  const auth = value;
70
- return (typeof auth.remoteUrl === 'string' &&
71
- typeof auth.accessToken === 'string' &&
72
- auth.accessToken.length > 0 &&
73
- typeof auth.expiresAtMs === 'number' &&
74
- Number.isFinite(auth.expiresAtMs));
75
- };
76
- /** Invalid or partial credential files are treated as unauthenticated. */
77
- const readCliAuth = (workingPath) => __awaiter(void 0, void 0, void 0, function* () {
73
+ if (typeof auth.remoteUrl !== 'string')
74
+ return null;
75
+ if (typeof auth.accessToken !== 'string' || auth.accessToken.length === 0)
76
+ return null;
77
+ if (typeof auth.expiresAtMs !== 'number' || !Number.isFinite(auth.expiresAtMs))
78
+ return null;
78
79
  try {
79
- const value = (yield fs_extra_1.default.readJson((0, exports.cliAuthFilePath)(workingPath)));
80
- if (!isCliAuth(value))
81
- return null;
82
- return Object.assign(Object.assign({}, value), { remoteUrl: (0, exports.normalizeRegistryUrl)(value.remoteUrl) });
80
+ return { remoteUrl: (0, exports.normalizeRegistryUrl)(auth.remoteUrl), accessToken: auth.accessToken, expiresAtMs: auth.expiresAtMs };
83
81
  }
84
82
  catch (_a) {
85
83
  return null;
86
84
  }
85
+ };
86
+ const toLogins = (value) => {
87
+ const logins = value === null || value === void 0 ? void 0 : value.logins;
88
+ if (!logins || typeof logins !== 'object')
89
+ return {};
90
+ const result = {};
91
+ for (const [profile, entry] of Object.entries(logins)) {
92
+ const auth = toCliAuth(entry);
93
+ if (auth)
94
+ result[profile] = auth;
95
+ }
96
+ return result;
97
+ };
98
+ /** Every saved login, keyed by profile name. A missing or unreadable file reads as no logins. */
99
+ const readCliLogins = (workingPath) => __awaiter(void 0, void 0, void 0, function* () {
100
+ try {
101
+ return toLogins((yield fs_extra_1.default.readJson((0, exports.cliAuthFilePath)(workingPath))));
102
+ }
103
+ catch (_a) {
104
+ return {};
105
+ }
87
106
  });
107
+ exports.readCliLogins = readCliLogins;
108
+ /** The login saved under one profile name. Never falls back to another profile. */
109
+ const readCliAuth = (workingPath_1, ...args_1) => __awaiter(void 0, [workingPath_1, ...args_1], void 0, function* (workingPath, profile = exports.DEFAULT_LOGIN_PROFILE) { var _a; return (_a = (yield (0, exports.readCliLogins)(workingPath))[profile]) !== null && _a !== void 0 ? _a : null; });
88
110
  exports.readCliAuth = readCliAuth;
111
+ /**
112
+ * Profile names that have a saved login. Synchronous because config loading is, and the loader needs
113
+ * these names to decide whether a selected profile resolves.
114
+ */
115
+ const loginProfileNames = (workingPath) => {
116
+ try {
117
+ return Object.keys(toLogins(fs_extra_1.default.readJsonSync((0, exports.cliAuthFilePath)(workingPath))));
118
+ }
119
+ catch (_a) {
120
+ return [];
121
+ }
122
+ };
123
+ exports.loginProfileNames = loginProfileNames;
89
124
  /**
90
125
  * Atomically replace the credential file. Restrictive permissions are best-effort on platforms
91
126
  * whose filesystems do not support POSIX modes.
92
127
  */
93
- const writeCliAuth = (workingPath, auth) => __awaiter(void 0, void 0, void 0, function* () {
128
+ const writeCliLogins = (workingPath, logins) => __awaiter(void 0, void 0, void 0, function* () {
94
129
  const filePath = (0, exports.cliAuthFilePath)(workingPath);
95
130
  const directory = path_1.default.dirname(filePath);
96
131
  const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
97
- const value = Object.assign(Object.assign({}, auth), { remoteUrl: (0, exports.normalizeRegistryUrl)(auth.remoteUrl) });
132
+ const value = { logins };
98
133
  yield fs_extra_1.default.ensureDir(directory, 0o700);
99
134
  try {
100
135
  yield fs_extra_1.default.chmod(directory, 0o700);
@@ -123,14 +158,32 @@ const writeCliAuth = (workingPath, auth) => __awaiter(void 0, void 0, void 0, fu
123
158
  throw error;
124
159
  }
125
160
  });
161
+ /** Save the login for one profile and leave the other profiles in place. */
162
+ const writeCliAuth = (workingPath_1, auth_1, ...args_1) => __awaiter(void 0, [workingPath_1, auth_1, ...args_1], void 0, function* (workingPath, auth, profile = exports.DEFAULT_LOGIN_PROFILE) {
163
+ const logins = yield (0, exports.readCliLogins)(workingPath);
164
+ logins[profile] = Object.assign(Object.assign({}, auth), { remoteUrl: (0, exports.normalizeRegistryUrl)(auth.remoteUrl) });
165
+ yield writeCliLogins(workingPath, logins);
166
+ });
126
167
  exports.writeCliAuth = writeCliAuth;
127
- const clearCliAuth = (workingPath) => __awaiter(void 0, void 0, void 0, function* () {
168
+ /** Remove the login for one profile, and the file itself once no login is left. */
169
+ const clearCliAuth = (workingPath_1, ...args_1) => __awaiter(void 0, [workingPath_1, ...args_1], void 0, function* (workingPath, profile = exports.DEFAULT_LOGIN_PROFILE) {
170
+ const logins = yield (0, exports.readCliLogins)(workingPath);
171
+ delete logins[profile];
172
+ if (Object.keys(logins).length === 0) {
173
+ yield (0, exports.clearAllCliAuth)(workingPath);
174
+ return;
175
+ }
176
+ yield writeCliLogins(workingPath, logins);
177
+ });
178
+ exports.clearCliAuth = clearCliAuth;
179
+ /** Remove every saved login. */
180
+ const clearAllCliAuth = (workingPath) => __awaiter(void 0, void 0, void 0, function* () {
128
181
  const filePath = (0, exports.cliAuthFilePath)(workingPath);
129
182
  if (yield fs_extra_1.default.pathExists(filePath)) {
130
183
  yield fs_extra_1.default.remove(filePath);
131
184
  }
132
185
  });
133
- exports.clearCliAuth = clearCliAuth;
186
+ exports.clearAllCliAuth = clearAllCliAuth;
134
187
  const cliAuthMatchesRegistry = (auth, remoteUrl) => {
135
188
  if (!auth)
136
189
  return false;
@@ -1,9 +1,4 @@
1
1
  import Handoff from '../index';
2
- /**
3
- * Make a new exportable component
4
- * @param handoff
5
- */
6
- export declare const makeTemplate: (handoff: Handoff, component: string, state: string) => Promise<Handoff>;
7
2
  /**
8
3
  * Make a new docs page
9
4
  * @param handoff
package/dist/cli/make.js CHANGED
@@ -35,54 +35,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.makeComponent = exports.makePage = exports.makeTemplate = void 0;
38
+ exports.makeComponent = exports.makePage = void 0;
39
+ const catalog_include_1 = require("../config/catalog-include");
40
+ const runtime_1 = require("../config/runtime");
39
41
  const p = __importStar(require("@clack/prompts"));
40
42
  const fs_extra_1 = __importDefault(require("fs-extra"));
41
43
  const path_1 = __importDefault(require("path"));
42
44
  const logger_1 = require("../utils/logger");
43
- /**
44
- * Make a new exportable component
45
- * @param handoff
46
- */
47
- const makeTemplate = (handoff, component, state) => __awaiter(void 0, void 0, void 0, function* () {
48
- var _a, _b;
49
- if (!((_b = (_a = handoff === null || handoff === void 0 ? void 0 : handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.templates)) {
50
- logger_1.Logger.error(`Runtime config does not specify entry for templates.`);
51
- return;
52
- }
53
- if (!component) {
54
- logger_1.Logger.error(`Template component must be set`);
55
- return;
56
- }
57
- if (!state) {
58
- state = 'default';
59
- }
60
- if (!/^[a-z0-9]+$/i.test(component)) {
61
- logger_1.Logger.error(`Template component must be alphanumeric and may contain dashes or underscores`);
62
- return;
63
- }
64
- if (!/^[a-z0-9]+$/i.test(state)) {
65
- logger_1.Logger.error(`Template state must be alphanumeric and may contain dashes or underscores`);
66
- return;
67
- }
68
- const workingPath = path_1.default.resolve(handoff.runtimeConfig.entries.templates, component);
69
- if (!fs_extra_1.default.existsSync(workingPath)) {
70
- fs_extra_1.default.mkdirSync(workingPath, { recursive: true });
71
- }
72
- const target = path_1.default.resolve(workingPath, `${state}.html`);
73
- if (fs_extra_1.default.existsSync(target)) {
74
- if (!handoff.force) {
75
- logger_1.Logger.warn(`'${state}' already exists as custom template. Use the --force flag revert it to default.`);
76
- return;
77
- }
78
- }
79
- const templatePath = path_1.default.resolve(path_1.default.join(handoff.modulePath, 'config/templates', 'template.html'));
80
- const template = fs_extra_1.default.readFileSync(templatePath, 'utf8');
81
- fs_extra_1.default.writeFileSync(target, template);
82
- logger_1.Logger.success(`New template ${state}.html was created in ${workingPath}`);
83
- return handoff;
84
- });
85
- exports.makeTemplate = makeTemplate;
86
45
  /**
87
46
  * Make a new docs page
88
47
  * @param handoff
@@ -136,22 +95,15 @@ exports.makePage = makePage;
136
95
  */
137
96
  const DEFAULT_COMPONENTS_DIR = 'components';
138
97
  const makeComponent = (handoff, name) => __awaiter(void 0, void 0, void 0, function* () {
139
- var _a, _b, _c;
98
+ var _a, _b;
140
99
  if (!name) {
141
100
  logger_1.Logger.error(`Component name must be set`);
142
101
  return;
143
102
  }
144
103
  name = name.replace('.html', '');
145
- let componentsRoot;
146
- if ((_c = (_b = (_a = handoff.config) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.components) === null || _c === void 0 ? void 0 : _c.length) {
147
- componentsRoot = path_1.default.resolve(handoff.workingPath, handoff.config.entries.components[0]);
148
- }
149
- else {
150
- componentsRoot = path_1.default.resolve(handoff.workingPath, DEFAULT_COMPONENTS_DIR);
151
- logger_1.Logger.warn(`No entries.components configured in handoff.config.*. ` +
152
- `Scaffolding into "${DEFAULT_COMPONENTS_DIR}/". ` +
153
- `Add this path to entries.components in your config so the build picks it up.`);
154
- }
104
+ const configuredRoot = (_b = (_a = handoff.config.catalog) === null || _a === void 0 ? void 0 : _a.include) === null || _b === void 0 ? void 0 : _b[0];
105
+ const root = path_1.default.resolve(handoff.workingPath, configuredRoot !== null && configuredRoot !== void 0 ? configuredRoot : DEFAULT_COMPONENTS_DIR);
106
+ const componentsRoot = (0, runtime_1.isComponentDirectory)(root) ? path_1.default.dirname(root) : root;
155
107
  let workingPath = path_1.default.resolve(componentsRoot, name);
156
108
  if (!fs_extra_1.default.existsSync(workingPath)) {
157
109
  fs_extra_1.default.mkdirSync(workingPath, { recursive: true });
@@ -188,34 +140,37 @@ const makeComponent = (handoff, name) => __awaiter(void 0, void 0, void 0, funct
188
140
  const scssTemplate = fs_extra_1.default.readFileSync(scssPath, 'utf8');
189
141
  fs_extra_1.default.writeFileSync(path_1.default.resolve(workingPath, `${name}.scss`), scssTemplate);
190
142
  }
191
- const declarationEntries = [`template: './${name}.hbs'`];
143
+ // `implementation` names the template, so `entries` carries only supporting files.
144
+ const declarationEntries = [];
192
145
  if (writeJSFile === true) {
193
146
  declarationEntries.push(`js: './${name}.js'`);
194
147
  }
195
148
  if (writeSassFile === true) {
196
149
  declarationEntries.push(`scss: './${name}.scss'`);
197
150
  }
198
- const declarationContent = `const { defineHandlebarsComponent } = require('handoff-app');
151
+ const entriesBlock = declarationEntries.length ? `\n entries: {\n ${declarationEntries.join(',\n ')}\n },` : '';
152
+ const declarationContent = `const { defineCatalogItem } = require('handoff-app/handlebars');
199
153
 
200
- module.exports = defineHandlebarsComponent({
154
+ exports.default = defineCatalogItem({
201
155
  id: '${name}',
202
156
  name: '',
203
157
  description: '',
204
158
  group: '',
205
159
  type: 'element',
206
- entries: {
207
- ${declarationEntries.join(',\n ')}
208
- },
209
- previews: {
210
- default: {
211
- title: 'Default',
212
- args: {}
213
- }
214
- }
160
+ implementation: './${name}.hbs',${entriesBlock}
215
161
  });
162
+
163
+ exports.Default = {
164
+ args: {},
165
+ };
216
166
  `;
217
167
  fs_extra_1.default.writeFileSync(path_1.default.resolve(workingPath, `${name}.handoff.js`), declarationContent);
218
168
  logger_1.Logger.success(`New component declaration ${name}.handoff.js was created in ${workingPath}`);
169
+ if (!(0, catalog_include_1.isIncluded)(handoff, workingPath)) {
170
+ const result = yield (0, catalog_include_1.addToCatalog)(handoff, [workingPath]);
171
+ if (result.status === 'unsupported')
172
+ logger_1.Logger.warn(`Add ${result.pending.join(', ')} to catalog.include in handoff.config.`);
173
+ }
219
174
  return handoff;
220
175
  });
221
176
  exports.makeComponent = makeComponent;
@@ -40,7 +40,7 @@ const p = __importStar(require("@clack/prompts"));
40
40
  const chalk_1 = __importDefault(require("chalk"));
41
41
  const fs_extra_1 = __importDefault(require("fs-extra"));
42
42
  const path_1 = __importDefault(require("path"));
43
- const entries_1 = require("../config/entries");
43
+ const catalog_include_1 = require("../config/catalog-include");
44
44
  // Constants
45
45
  const COMPONENTS_DIR = 'components';
46
46
  const DEFAULT_GROUPS = [
@@ -63,49 +63,41 @@ const toTitleCase = (str) => {
63
63
  * Generate the component JS stub content
64
64
  */
65
65
  const generateComponentStub = (config) => {
66
+ // `implementation` names the source, so `entries` carries only supporting files.
66
67
  const entriesLines = [];
67
- if (config.generateTsx) {
68
- entriesLines.push(` component: './${config.name}.tsx',`);
69
- }
70
- else {
71
- entriesLines.push(` template: './${config.name}.hbs',`);
72
- }
73
68
  if (config.generateScss) {
74
69
  entriesLines.push(` scss: './${config.name}.scss',`);
75
70
  }
71
+ const entriesBlock = entriesLines.length ? `\n entries: {\n${entriesLines.join('\n')}\n },` : '';
76
72
  const commonMetadata = ` id: "${config.name}",
77
73
  name: "${config.title}",
78
74
  description: "${config.description}",
79
75
  group: "${config.group}",
80
76
  type: "element",
81
77
  figmaComponentId: "${config.name}",`;
78
+ const previewExport = `
79
+ exports.Default = {
80
+ args: {},
81
+ };
82
+ `;
82
83
  if (config.generateTsx) {
83
- return `const { defineReactComponent } = require('handoff-app');
84
- const ${toTitleCase(config.name).replace(/\s/g, '')} = require('./${config.name}').default;
84
+ const identifier = toTitleCase(config.name).replace(/\s/g, '');
85
+ return `const { defineCatalogItem } = require('handoff-app/react');
86
+ const ${identifier} = require('./${config.name}').default;
85
87
 
86
- module.exports = defineReactComponent(${toTitleCase(config.name).replace(/\s/g, '')}, {
88
+ exports.default = defineCatalogItem({
87
89
  ${commonMetadata}
88
- entries: {
89
- ${entriesLines.join('\n')}
90
- },
91
- previews: {
92
- default: { title: "Default", args: {} }
93
- }
90
+ implementation: ${identifier},${entriesBlock}
94
91
  });
95
- `;
92
+ ${previewExport}`;
96
93
  }
97
- return `const { defineHandlebarsComponent } = require('handoff-app');
94
+ return `const { defineCatalogItem } = require('handoff-app/handlebars');
98
95
 
99
- module.exports = defineHandlebarsComponent({
96
+ exports.default = defineCatalogItem({
100
97
  ${commonMetadata}
101
- entries: {
102
- ${entriesLines.join('\n')}
103
- },
104
- previews: {
105
- default: { title: "Default", args: {} }
106
- }
98
+ implementation: './${config.name}.hbs',${entriesBlock}
107
99
  });
108
- `;
100
+ ${previewExport}`;
109
101
  };
110
102
  /**
111
103
  * Generate a basic React component stub with variant props
@@ -179,8 +171,8 @@ const getFigmaComponents = (handoff) => __awaiter(void 0, void 0, void 0, functi
179
171
  * Get list of registered component IDs from runtime config
180
172
  */
181
173
  const getRegisteredComponentIds = (handoff) => {
182
- var _a, _b;
183
- const components = ((_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.components) || {};
174
+ var _a;
175
+ const components = ((_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) || {};
184
176
  return Object.keys(components);
185
177
  };
186
178
  /**
@@ -385,22 +377,22 @@ const runScaffold = (handoff) => __awaiter(void 0, void 0, void 0, function* ()
385
377
  console.log(chalk_1.default.dim(` ${relativePath}`));
386
378
  }
387
379
  // Update config if requested. Components already covered by a collection directory auto-load,
388
- // so we only write the uncovered ones into entries.components.
380
+ // so we only write the unlisted ones into catalog.include.
389
381
  if (updateConfig) {
390
382
  const componentDirs = componentNames.map((name) => path_1.default.resolve(handoff.workingPath, COMPONENTS_DIR, name));
391
- const uncovered = componentDirs.filter((dir) => !(0, entries_1.isEntryCovered)(handoff, 'components', dir));
392
- if (uncovered.length === 0) {
383
+ const unlisted = componentDirs.filter((dir) => !(0, catalog_include_1.isIncluded)(handoff, dir));
384
+ if (unlisted.length === 0) {
393
385
  p.log.info(`Config already covers these components - they'll auto-load`);
394
386
  }
395
387
  else {
396
- const result = yield (0, entries_1.writeEntries)(handoff, 'components', uncovered);
388
+ const result = yield (0, catalog_include_1.addToCatalog)(handoff, unlisted);
397
389
  if (result.status === 'added') {
398
390
  const configFileName = result.configPath ? path_1.default.basename(result.configPath) : 'handoff.config.json';
399
391
  p.log.success(`Updated ${configFileName} with component paths`);
400
392
  }
401
393
  else {
402
394
  const where = result.configPath ? path_1.default.relative(handoff.workingPath, result.configPath) : 'handoff.config';
403
- p.log.warn(`Could not automatically update ${where}. Please manually add these paths to entries.components:`);
395
+ p.log.warn(`Could not automatically update ${where}. Please manually add these paths to catalog.include:`);
404
396
  for (const rel of result.pending) {
405
397
  console.log(chalk_1.default.yellow(` '${rel}'`));
406
398
  }
@@ -6,10 +6,13 @@ export interface CheckoutArgs extends SharedArgs {
6
6
  id?: string[];
7
7
  }
8
8
  /**
9
- * `handoff-app checkout <components|patterns|pages> [id...]` pulls entities from the connected
10
- * registry into this workspace, writing their source files in standard authoring form and
11
- * synthesizing local declarations. Pass ids to pull only those entities, or omit them for every
12
- * published entity of that kind.
9
+ * `handoff-app checkout <catalog|pages> [id...]` pulls entities from the connected registry into this
10
+ * workspace, writing their source files in standard authoring form and synthesizing local
11
+ * declarations. Pass ids to pull only those entities, or omit them for every published entity of that
12
+ * kind.
13
+ *
14
+ * `catalog` covers every published catalog item. The lane an item was published into is looked up in
15
+ * the registry, so an id is enough and no lane is named here.
13
16
  *
14
17
  * `handoff-app checkout tokens [setId...]` pulls every published token set, or only the named ones,
15
18
  * reconstructing `tokens.json` and restoring the generated token files.
@@ -2,10 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const utils_1 = require("../utils");
4
4
  /**
5
- * `handoff-app checkout <components|patterns|pages> [id...]` pulls entities from the connected
6
- * registry into this workspace, writing their source files in standard authoring form and
7
- * synthesizing local declarations. Pass ids to pull only those entities, or omit them for every
8
- * published entity of that kind.
5
+ * `handoff-app checkout <catalog|pages> [id...]` pulls entities from the connected registry into this
6
+ * workspace, writing their source files in standard authoring form and synthesizing local
7
+ * declarations. Pass ids to pull only those entities, or omit them for every published entity of that
8
+ * kind.
9
+ *
10
+ * `catalog` covers every published catalog item. The lane an item was published into is looked up in
11
+ * the registry, so an id is enough and no lane is named here.
9
12
  *
10
13
  * `handoff-app checkout tokens [setId...]` pulls every published token set, or only the named ones,
11
14
  * reconstructing `tokens.json` and restoring the generated token files.
@@ -21,8 +24,8 @@ const utils_1 = require("../utils");
21
24
  */
22
25
  const command = {
23
26
  command: 'checkout <type> [id..]',
24
- describe: 'Pull components, patterns, pages, design tokens, or assets from the connected registry into this workspace',
25
- builder: (yargs) => (0, utils_1.withTargetPositionals)((0, utils_1.getCheckoutOptions)(yargs), 'checkout'),
27
+ describe: 'Pull catalog items, pages, design tokens, or assets from the connected registry into this workspace',
28
+ builder: (yargs) => (0, utils_1.withTargetPositionals)((0, utils_1.getCheckoutOptions)(yargs), 'checkout', utils_1.REGISTRY_TARGET_KINDS),
26
29
  handler: (args) => (0, utils_1.runRegistryCommand)(args, (handoff) => (0, utils_1.runTarget)(handoff, args.type, args.id, 'checkout')),
27
30
  };
28
31
  exports.default = command;
@@ -7,11 +7,11 @@
7
7
  * {@link Handoff.publishAll}, so no orchestration lives here.
8
8
  */
9
9
  import { type RegistryEntityKind } from '../../registry/content-kinds';
10
- import type { RegistryTargetKind } from '../utils';
10
+ import type { CompatTargetKind } from '../utils';
11
11
  import type { ContentTarget } from '../../index';
12
12
  /** The documented `push` / `pull` arguments read here. */
13
13
  export interface CompatTargetArgs {
14
- type?: RegistryTargetKind;
14
+ type?: CompatTargetKind;
15
15
  id?: string[];
16
16
  components?: string[];
17
17
  patterns?: string[];
@@ -19,7 +19,6 @@ const login_1 = __importDefault(require("./login"));
19
19
  const logout_1 = __importDefault(require("./logout"));
20
20
  const component_1 = __importDefault(require("./make/component"));
21
21
  const page_1 = __importDefault(require("./make/page"));
22
- const template_1 = __importDefault(require("./make/template"));
23
22
  const pull_1 = __importDefault(require("./pull"));
24
23
  const publish_1 = __importDefault(require("./publish"));
25
24
  const push_1 = require("./push");
@@ -42,7 +41,6 @@ exports.commands = [
42
41
  logout_1.default,
43
42
  page_1.default,
44
43
  component_1.default,
45
- template_1.default,
46
44
  publish_1.default,
47
45
  pull_1.default,
48
46
  ...push_1.pushCommands,
@@ -4,5 +4,10 @@ export interface LoginArgs extends SharedArgs {
4
4
  url?: string;
5
5
  browser?: boolean;
6
6
  }
7
+ /**
8
+ * Saves one registry credential per profile, so a workspace can hold a login for every registry it
9
+ * publishes to. The name is independent of the config profiles, and `login` is the one command that
10
+ * accepts a profile nothing else knows yet.
11
+ */
7
12
  declare const command: CommandModule<{}, LoginArgs>;
8
13
  export default command;
@@ -14,6 +14,11 @@ const store_1 = require("../../cli/auth/store");
14
14
  const connection_1 = require("../../registry/connection");
15
15
  const logger_1 = require("../../utils/logger");
16
16
  const utils_1 = require("../utils");
17
+ /**
18
+ * Saves one registry credential per profile, so a workspace can hold a login for every registry it
19
+ * publishes to. The name is independent of the config profiles, and `login` is the one command that
20
+ * accepts a profile nothing else knows yet.
21
+ */
17
22
  const command = {
18
23
  command: 'login',
19
24
  describe: 'Sign in to a registry using browser device authorization',
@@ -28,17 +33,24 @@ const command = {
28
33
  describe: 'Open the approval URL in the default browser (disable with --no-browser)',
29
34
  }),
30
35
  handler: (args) => __awaiter(void 0, void 0, void 0, function* () {
31
- var _a;
32
- const handoff = (0, utils_1.createHandoff)(args);
36
+ var _a, _b;
37
+ const handoff = (0, utils_1.createHandoff)(args, { profileWithoutConfig: 'any' });
38
+ const profile = (_a = handoff.getProfile()) !== null && _a !== void 0 ? _a : store_1.DEFAULT_LOGIN_PROFILE;
33
39
  try {
34
40
  const configured = (0, connection_1.resolveRegistryConnection)(handoff.config);
35
- const remoteUrl = ((_a = args.url) === null || _a === void 0 ? void 0 : _a.trim()) || configured.url;
41
+ // Resolved in the order publish and checkout use, so a login always targets the registry those
42
+ // commands would reach.
43
+ const saved = yield (0, store_1.readCliAuth)(handoff.workingPath, profile);
44
+ const remoteUrl = ((_b = args.url) === null || _b === void 0 ? void 0 : _b.trim()) || configured.url || (saved === null || saved === void 0 ? void 0 : saved.remoteUrl);
36
45
  if (!remoteUrl) {
37
46
  throw new Error(`Pass --url <registry-url>, configure runtime.registryConnection.url, or set "${configured.urlEnv}".`);
38
47
  }
39
- yield (0, device_1.loginWithDevice)(handoff.workingPath, remoteUrl, { openBrowser: args.browser !== false });
40
- logger_1.Logger.success(`Logged in. Credentials saved to ${(0, store_1.cliAuthFilePath)(handoff.workingPath)}.`);
41
- logger_1.Logger.info('Publish and checkout commands will use this login for the matching registry URL.');
48
+ yield (0, device_1.loginWithDevice)(handoff.workingPath, remoteUrl, { openBrowser: args.browser !== false, profile });
49
+ const named = profile === store_1.DEFAULT_LOGIN_PROFILE ? '' : ` under profile "${profile}"`;
50
+ logger_1.Logger.success(`Logged in. Credentials saved to ${(0, store_1.cliAuthFilePath)(handoff.workingPath)}${named}.`);
51
+ logger_1.Logger.info(profile === store_1.DEFAULT_LOGIN_PROFILE
52
+ ? 'Publish and checkout commands will use this login for the matching registry URL.'
53
+ : `Publish and checkout commands will use this login when they run with --profile ${profile}.`);
42
54
  }
43
55
  catch (error) {
44
56
  logger_1.Logger.error(error instanceof Error ? error.message : String(error));
@@ -2,6 +2,11 @@ import { CommandModule } from 'yargs';
2
2
  import { SharedArgs } from '../types';
3
3
  export interface LogoutArgs extends SharedArgs {
4
4
  url?: string;
5
+ all?: boolean;
5
6
  }
7
+ /**
8
+ * `handoff-app logout` removes the login of the selected profile, leaving every other profile signed
9
+ * in. `--all` removes them all.
10
+ */
6
11
  declare const command: CommandModule<{}, LogoutArgs>;
7
12
  export default command;