handoff-app 2.0.0-1 → 2.0.0-3

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 (219) hide show
  1. package/README.md +170 -91
  2. package/config/docs/foundations/colors/guidelines.md +9 -0
  3. package/config/docs/foundations/effects/guidelines.md +9 -0
  4. package/config/docs/foundations/effects/resources.md +9 -0
  5. package/config/docs/foundations/grid.md +10 -0
  6. package/config/docs/foundations/icons/guidelines.md +9 -0
  7. package/config/docs/foundations/images/guidelines.md +9 -0
  8. package/config/docs/foundations/images/resources.md +9 -0
  9. package/config/docs/foundations/images.md +10 -0
  10. package/config/docs/foundations/logo/resources.md +9 -0
  11. package/config/docs/foundations/typography/guidelines.md +9 -0
  12. package/config/docs/foundations/typography/resources.md +9 -0
  13. package/config/docs/foundations.md +5 -3
  14. package/dist/app-builder/build.js +109 -49
  15. package/dist/app-builder/client-config.js +13 -12
  16. package/dist/app-builder/paths.js +7 -9
  17. package/dist/app-builder/static-export.js +6 -6
  18. package/dist/app-builder/vercel-output.js +2 -2
  19. package/dist/artifacts/url.d.ts +7 -7
  20. package/dist/artifacts/url.js +7 -7
  21. package/dist/cli/auth/browser.d.ts +2 -0
  22. package/dist/cli/auth/browser.js +33 -0
  23. package/dist/cli/auth/device.d.ts +11 -0
  24. package/dist/cli/auth/device.js +155 -0
  25. package/dist/cli/auth/store.d.ts +29 -0
  26. package/dist/cli/auth/store.js +146 -0
  27. package/dist/cli/create.js +48 -3
  28. package/dist/cli/scaffold.js +20 -154
  29. package/dist/commands/checkout/index.d.ts +6 -6
  30. package/dist/commands/checkout/index.js +8 -12
  31. package/dist/commands/index.js +4 -0
  32. package/dist/commands/login/index.d.ts +8 -0
  33. package/dist/commands/login/index.js +53 -0
  34. package/dist/commands/logout/index.d.ts +7 -0
  35. package/dist/commands/logout/index.js +54 -0
  36. package/dist/commands/publish/index.d.ts +6 -5
  37. package/dist/commands/publish/index.js +8 -11
  38. package/dist/commands/utils.d.ts +6 -0
  39. package/dist/commands/utils.js +9 -1
  40. package/dist/config/entries.d.ts +47 -0
  41. package/dist/config/entries.js +162 -0
  42. package/dist/config/index.d.ts +2 -0
  43. package/dist/config/index.js +5 -1
  44. package/dist/config/runtime.d.ts +9 -9
  45. package/dist/config/runtime.js +15 -15
  46. package/dist/index.d.ts +12 -8
  47. package/dist/index.js +26 -10
  48. package/dist/registry/asset-storage/resolve.d.ts +1 -1
  49. package/dist/registry/asset-storage/resolve.js +1 -1
  50. package/dist/registry/auth/access-tokens.d.ts +46 -0
  51. package/dist/registry/auth/access-tokens.js +165 -0
  52. package/dist/registry/auth/action-tokens.d.ts +66 -0
  53. package/dist/registry/auth/action-tokens.js +178 -0
  54. package/dist/registry/auth/crypto.d.ts +4 -0
  55. package/dist/registry/auth/crypto.js +16 -0
  56. package/dist/registry/auth/database.d.ts +7 -0
  57. package/dist/registry/auth/database.js +22 -0
  58. package/dist/registry/auth/device-authorizations.d.ts +51 -0
  59. package/dist/registry/auth/device-authorizations.js +170 -0
  60. package/dist/registry/auth/gravatar.d.ts +1 -0
  61. package/dist/registry/auth/gravatar.js +8 -0
  62. package/dist/registry/auth/index.d.ts +11 -0
  63. package/dist/registry/auth/index.js +72 -0
  64. package/dist/registry/auth/installation.d.ts +42 -0
  65. package/dist/registry/auth/installation.js +105 -0
  66. package/dist/registry/auth/password.d.ts +12 -0
  67. package/dist/registry/auth/password.js +58 -0
  68. package/dist/registry/auth/rate-limits.d.ts +22 -0
  69. package/dist/registry/auth/rate-limits.js +75 -0
  70. package/dist/registry/auth/types.d.ts +26 -0
  71. package/dist/registry/auth/types.js +9 -0
  72. package/dist/registry/auth/user-record.d.ts +13 -0
  73. package/dist/registry/auth/user-record.js +16 -0
  74. package/dist/registry/auth/users.d.ts +31 -0
  75. package/dist/registry/auth/users.js +135 -0
  76. package/dist/registry/auth/validation.d.ts +3 -0
  77. package/dist/registry/auth/validation.js +28 -0
  78. package/dist/registry/checkout/assets.js +4 -2
  79. package/dist/registry/checkout/index.d.ts +11 -6
  80. package/dist/registry/checkout/index.js +159 -30
  81. package/dist/registry/checkout/tokens.js +4 -2
  82. package/dist/registry/client.d.ts +2 -1
  83. package/dist/registry/client.js +8 -0
  84. package/dist/registry/connection.d.ts +9 -0
  85. package/dist/registry/connection.js +29 -1
  86. package/dist/registry/db/client.d.ts +9 -9
  87. package/dist/registry/db/client.js +7 -7
  88. package/dist/registry/db/driver.d.ts +46 -0
  89. package/dist/registry/db/{adapter.js → driver.js} +22 -19
  90. package/dist/registry/db/index.d.ts +2 -2
  91. package/dist/registry/db/index.js +15 -9
  92. package/dist/registry/db/migrate.d.ts +1 -1
  93. package/dist/registry/db/migrate.js +5 -5
  94. package/dist/registry/db/schema.d.ts +2521 -750
  95. package/dist/registry/db/schema.js +126 -1
  96. package/dist/registry/publish/assets.js +1 -1
  97. package/dist/registry/publish/errors.js +3 -3
  98. package/dist/registry/publish/index.d.ts +9 -2
  99. package/dist/registry/publish/index.js +96 -10
  100. package/dist/registry/publish/tokens.js +1 -1
  101. package/dist/registry/transfer.d.ts +13 -0
  102. package/dist/types/config.d.ts +11 -4
  103. package/docs/cli.md +4 -0
  104. package/drizzle/0005_add_registry_auth.sql +95 -0
  105. package/drizzle/meta/0005_snapshot.json +1926 -0
  106. package/drizzle/meta/_journal.json +8 -1
  107. package/drizzle.config.ts +1 -1
  108. package/package.json +5 -4
  109. package/src/app/components/Auth/AccountLayout.tsx +87 -0
  110. package/src/app/components/Auth/AuthControls.tsx +99 -0
  111. package/src/app/components/Auth/AuthShell.tsx +73 -0
  112. package/src/app/components/Auth/RegistryInstallGate.tsx +23 -0
  113. package/src/app/components/Auth/RegistrySessionProvider.tsx +15 -0
  114. package/src/app/components/Auth/api.ts +20 -0
  115. package/src/app/components/Foundations/DisplayLogo.tsx +3 -3
  116. package/src/app/components/Layout/Header.tsx +2 -0
  117. package/src/app/components/Navigation/MobileNav.tsx +2 -0
  118. package/src/app/lib/auth/api.ts +113 -0
  119. package/src/app/lib/auth/config.ts +175 -0
  120. package/src/app/lib/auth/email.ts +34 -0
  121. package/src/app/lib/docs-api/runtime-config.ts +10 -24
  122. package/src/app/lib/registry-api/auth.ts +29 -46
  123. package/src/app/lib/registry-api/errors.ts +2 -2
  124. package/src/app/lib/registry-api/handler.ts +19 -14
  125. package/src/app/lib/registry-api/token-transfer.ts +1 -1
  126. package/src/app/lib/registry-api/transfer.ts +31 -2
  127. package/src/app/lib/registry-connection.ts +2 -2
  128. package/src/app/next.config.mjs +13 -4
  129. package/src/app/pages/_app.tsx +10 -4
  130. package/src/app/pages/account/index.tsx +153 -0
  131. package/src/app/pages/account/tokens.tsx +230 -0
  132. package/src/app/pages/account/users.tsx +310 -0
  133. package/src/app/pages/api/account/index.ts +26 -0
  134. package/src/app/pages/api/account/tokens/[id].ts +17 -0
  135. package/src/app/pages/api/account/tokens/index.ts +44 -0
  136. package/src/app/pages/api/admin/users/[id]/[action].ts +89 -0
  137. package/src/app/pages/api/admin/users/index.ts +53 -0
  138. package/src/app/pages/api/auth/[...nextauth].ts +4 -0
  139. package/src/app/pages/api/auth/request-reset.ts +53 -0
  140. package/src/app/pages/api/auth/reset-password.ts +29 -0
  141. package/src/app/pages/api/install.ts +102 -0
  142. package/src/app/pages/api/oauth/device/approve.ts +23 -0
  143. package/src/app/pages/api/oauth/device/index.ts +41 -0
  144. package/src/app/pages/api/oauth/revoke.ts +24 -0
  145. package/src/app/pages/api/oauth/token.ts +31 -0
  146. package/src/app/pages/api/registry/health.ts +4 -3
  147. package/src/app/pages/api/registry/transfer/[kind]/[id].ts +3 -3
  148. package/src/app/pages/api/registry/transfer/[kind]/index.ts +21 -0
  149. package/src/app/pages/api/registry/transfer/assets/[collection].ts +2 -1
  150. package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +2 -1
  151. package/src/app/pages/api/registry/transfer/tokens/[...setId].ts +2 -2
  152. package/src/app/pages/cli/device.tsx +143 -0
  153. package/src/app/pages/foundations/icons/index.tsx +2 -2
  154. package/src/app/pages/foundations/icons/{[name] → library/[name]}/index.tsx +6 -6
  155. package/src/app/pages/install.tsx +336 -0
  156. package/src/app/pages/login.tsx +117 -0
  157. package/src/app/pages/reset-password.tsx +159 -0
  158. package/src/app/types/next-auth.d.ts +27 -0
  159. package/src/app-builder/build.ts +96 -59
  160. package/src/app-builder/client-config.ts +12 -11
  161. package/src/app-builder/paths.ts +7 -9
  162. package/src/app-builder/static-export.ts +6 -6
  163. package/src/app-builder/vercel-output.ts +2 -2
  164. package/src/artifacts/url.ts +7 -7
  165. package/src/cli/auth/browser.ts +29 -0
  166. package/src/cli/auth/device.ts +181 -0
  167. package/src/cli/auth/store.ts +137 -0
  168. package/src/cli/create.ts +58 -3
  169. package/src/cli/scaffold.ts +20 -197
  170. package/src/commands/checkout/index.ts +10 -15
  171. package/src/commands/index.ts +4 -0
  172. package/src/commands/login/index.ts +48 -0
  173. package/src/commands/logout/index.ts +51 -0
  174. package/src/commands/publish/index.ts +10 -14
  175. package/src/commands/utils.ts +12 -0
  176. package/src/config/entries.ts +175 -0
  177. package/src/config/index.ts +4 -0
  178. package/src/config/runtime.ts +15 -14
  179. package/src/index.ts +26 -12
  180. package/src/registry/asset-storage/resolve.ts +1 -1
  181. package/src/registry/auth/access-tokens.ts +198 -0
  182. package/src/registry/auth/action-tokens.ts +225 -0
  183. package/src/registry/auth/crypto.ts +13 -0
  184. package/src/registry/auth/database.ts +15 -0
  185. package/src/registry/auth/device-authorizations.ts +223 -0
  186. package/src/registry/auth/gravatar.ts +6 -0
  187. package/src/registry/auth/index.ts +89 -0
  188. package/src/registry/auth/installation.ts +117 -0
  189. package/src/registry/auth/password.ts +46 -0
  190. package/src/registry/auth/rate-limits.ts +84 -0
  191. package/src/registry/auth/types.ts +34 -0
  192. package/src/registry/auth/user-record.ts +25 -0
  193. package/src/registry/auth/users.ts +145 -0
  194. package/src/registry/auth/validation.ts +24 -0
  195. package/src/registry/checkout/assets.ts +4 -2
  196. package/src/registry/checkout/index.ts +182 -30
  197. package/src/registry/checkout/tokens.ts +4 -2
  198. package/src/registry/client.ts +7 -1
  199. package/src/registry/connection.ts +23 -0
  200. package/src/registry/db/client.ts +12 -12
  201. package/src/registry/db/{adapter.ts → driver.ts} +24 -21
  202. package/src/registry/db/index.ts +16 -4
  203. package/src/registry/db/migrate.ts +5 -5
  204. package/src/registry/db/schema.ts +174 -1
  205. package/src/registry/publish/assets.ts +1 -1
  206. package/src/registry/publish/errors.ts +3 -3
  207. package/src/registry/publish/index.ts +108 -10
  208. package/src/registry/publish/tokens.ts +1 -1
  209. package/src/registry/transfer.ts +14 -0
  210. package/src/types/config.ts +11 -4
  211. package/templates/default/README.md.tpl +58 -1
  212. package/templates/default/gitignore.tpl +19 -3
  213. package/templates/default/handoff.config.js.tpl +13 -0
  214. package/templates/default/handoff.config.ts.tpl +13 -0
  215. package/templates/default/handoff.config.with-examples.js.tpl +13 -0
  216. package/templates/default/handoff.config.with-examples.ts.tpl +13 -0
  217. package/templates/default/package.json.tpl +2 -1
  218. package/templates/default/vercel.json.tpl +4 -0
  219. package/dist/registry/db/adapter.d.ts +0 -43
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * Connected-workspace checkout orchestration.
4
4
  *
5
- * `checkout <component|pattern> <id>` reads a normalized registry record and its registry-safe
5
+ * `checkout <components|patterns> <id>` reads a normalized registry record and its registry-safe
6
6
  * source files from the connected registry through the shared registry client, then writes them
7
7
  * into the local workspace in standard authoring form. The local **declaration is synthesized
8
8
  * locally** in the configured `runtime.workspace.declarationFormat` — declarations are never read
@@ -60,10 +60,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
60
60
  return (mod && mod.__esModule) ? mod : { "default": mod };
61
61
  };
62
62
  Object.defineProperty(exports, "__esModule", { value: true });
63
- exports.checkoutEntity = exports.resolveConnectionOrThrow = exports.CheckoutError = void 0;
63
+ exports.checkoutEntities = exports.checkoutEntity = exports.resolveConnectionOrThrow = exports.CheckoutError = void 0;
64
64
  const p = __importStar(require("@clack/prompts"));
65
65
  const fs_extra_1 = __importDefault(require("fs-extra"));
66
66
  const path_1 = __importDefault(require("path"));
67
+ const entries_1 = require("../../config/entries");
67
68
  const runtime_1 = require("../../config/runtime");
68
69
  const logger_1 = require("../../utils/logger");
69
70
  const client_1 = require("../client");
@@ -92,24 +93,24 @@ const COMPONENT_EXTENSION = /\.(tsx|jsx|ts|js|cjs|mjs)$/i;
92
93
  * host has no local workspace to write into) and a resolved registry URL + access token. Throws an
93
94
  * actionable {@link CheckoutError} naming the exact misconfiguration.
94
95
  */
95
- const resolveConnectionOrThrow = (handoff) => {
96
+ const resolveConnectionOrThrow = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
96
97
  var _a, _b, _c;
97
98
  const mode = (_c = (_b = (_a = handoff.config) === null || _a === void 0 ? void 0 : _a.runtime) === null || _b === void 0 ? void 0 : _b.mode) !== null && _c !== void 0 ? _c : 'workspace';
98
99
  if (mode !== 'workspace') {
99
100
  throw new CheckoutError(`checkout is only available from a connected workspace (runtime.mode: "workspace"); this project is "${mode}". ` +
100
101
  'A registry host stores and serves entities; it has no local workspace to check them out into.');
101
102
  }
102
- const connection = (0, connection_1.resolveRegistryConnection)(handoff.config);
103
+ const connection = yield (0, connection_1.resolveAuthenticatedRegistryConnection)(handoff.config, handoff.workingPath);
103
104
  if (!connection.url) {
104
- throw new CheckoutError(`No registry URL is configured. Set runtime.registryConnection.url, or the "${connection.urlEnv}" environment variable, ` +
105
- 'to the base URL of the registry to checkout from.');
105
+ throw new CheckoutError(`No registry is configured. Run \`handoff-app login --url <registry-url>\`, set runtime.registryConnection.url, ` +
106
+ `or set the "${connection.urlEnv}" environment variable to the base URL of the registry to checkout from.`);
106
107
  }
107
108
  if (!connection.accessToken) {
108
- throw new CheckoutError(`No registry access token is configured. Set the "${connection.accessTokenEnv}" environment variable to the ` +
109
- "registry's bearer token to authorize checkout.");
109
+ throw new CheckoutError(`No registry access token is configured. Run \`handoff-app login --url ${connection.url}\`, or set the ` +
110
+ `"${connection.accessTokenEnv}" environment variable to a user-issued token for CI.`);
110
111
  }
111
112
  return connection;
112
- };
113
+ });
113
114
  exports.resolveConnectionOrThrow = resolveConnectionOrThrow;
114
115
  /** Map a registry client error to an actionable checkout message. */
115
116
  const describeFetchFailure = (error, kind, id, registryUrl) => {
@@ -119,28 +120,69 @@ const describeFetchFailure = (error, kind, id, registryUrl) => {
119
120
  case 'runtime_mode_conflict':
120
121
  return `The registry at ${registryUrl} is not running in registry mode, so it cannot serve a checkout: ${error.message}`;
121
122
  case 'unauthorized':
122
- return `The registry rejected the access token (401). Check the configured access token matches the registry's token.`;
123
+ return `The registry rejected the access token (401). Run \`handoff-app login --url ${registryUrl}\` again, or replace the user-issued CI token.`;
124
+ case 'forbidden':
125
+ return `The registry token does not have permission to checkout this content (403). Authorize a token with registry:read access.`;
123
126
  default:
124
127
  return error.message;
125
128
  }
126
129
  };
127
130
  /**
128
- * Resolve the local directory the entity is written into: an already-checked-out / locally-declared
129
- * entity keeps its existing source directory (matched by stable `id`); otherwise it lands under the
130
- * first configured `entries.{components|patterns}` root (falling back to `components`/`patterns`).
131
+ * Ask the user which collection directory a new entity should land in when the config is ambiguous.
132
+ * Under `--force` (or any non-interactive run) there's no one to ask, so we fail with an actionable
133
+ * message rather than guessing a root.
131
134
  */
132
- const resolveTargetDir = (handoff, kind, id) => __awaiter(void 0, void 0, void 0, function* () {
135
+ const promptForCollectionRoot = (handoff, kind, roots) => __awaiter(void 0, void 0, void 0, function* () {
136
+ const relative = (root) => path_1.default.relative(handoff.workingPath, root) || '.';
137
+ if (handoff.force) {
138
+ throw new CheckoutError(`Cannot determine where to checkout the ${kind}: entries.${kind}s declares individual ${kind}s under different ` +
139
+ `directories (${roots.map(relative).join(', ')}). Declare a single collection directory in handoff.config, ` +
140
+ `or run checkout without --force to choose interactively.`);
141
+ }
142
+ const choice = yield p.select({
143
+ message: `Where should the new ${kind} be checked out?`,
144
+ options: roots.map((root) => ({ value: root, label: relative(root) })),
145
+ initialValue: roots[0],
146
+ });
147
+ if (p.isCancel(choice)) {
148
+ throw new CheckoutError('Checkout cancelled; no target directory chosen.');
149
+ }
150
+ return choice;
151
+ });
152
+ /**
153
+ * Resolve the collection directory a new entity is cloned into from the configured
154
+ * `entries.{components|patterns}`. Each entry is either a collection directory (used as-is) or a
155
+ * single declared entity directory, in which case its parent is the collection root so the new
156
+ * entity lands as a sibling rather than nested inside. Different parents mean the config is
157
+ * ambiguous, so we ask the user; with nothing configured we fall back to the default subdir.
158
+ */
159
+ const resolveCollectionRoot = (handoff, kind) => __awaiter(void 0, void 0, void 0, function* () {
133
160
  var _a, _b, _c, _d;
161
+ const configuredRoots = kind === 'component' ? (_b = (_a = handoff.config) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.components : (_d = (_c = handoff.config) === null || _c === void 0 ? void 0 : _c.entries) === null || _d === void 0 ? void 0 : _d.patterns;
162
+ if (!(configuredRoots === null || configuredRoots === void 0 ? void 0 : configuredRoots.length)) {
163
+ return path_1.default.resolve(handoff.workingPath, DEFAULT_ENTITY_DIR[kind]);
164
+ }
165
+ const roots = [
166
+ ...new Set(configuredRoots.map((entry) => {
167
+ const resolved = path_1.default.resolve(handoff.workingPath, entry);
168
+ return (0, runtime_1.isComponentDirectory)(resolved) ? path_1.default.dirname(resolved) : resolved;
169
+ })),
170
+ ];
171
+ return roots.length === 1 ? roots[0] : promptForCollectionRoot(handoff, kind, roots);
172
+ });
173
+ /**
174
+ * Resolve the local directory the entity is written into. An already-checked-out or locally-declared
175
+ * entity keeps its existing source directory (matched by stable `id`); otherwise it lands as a
176
+ * sibling under its configured collection root (see {@link resolveCollectionRoot}).
177
+ */
178
+ const resolveTargetDir = (handoff, kind, id) => __awaiter(void 0, void 0, void 0, function* () {
134
179
  const store = kind === 'component' ? handoff.store.components : handoff.store.patterns;
135
180
  const existing = yield store.get(id);
136
181
  const existingDir = existing === null || existing === void 0 ? void 0 : existing.path;
137
182
  if (existingDir) {
138
183
  return existingDir;
139
184
  }
140
- const configuredRoots = kind === 'component' ? (_b = (_a = handoff.config) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.components : (_d = (_c = handoff.config) === null || _c === void 0 ? void 0 : _c.entries) === null || _d === void 0 ? void 0 : _d.patterns;
141
- const root = (configuredRoots === null || configuredRoots === void 0 ? void 0 : configuredRoots.length)
142
- ? path_1.default.resolve(handoff.workingPath, configuredRoots[0])
143
- : path_1.default.resolve(handoff.workingPath, DEFAULT_ENTITY_DIR[kind]);
185
+ const root = yield resolveCollectionRoot(handoff, kind);
144
186
  const targetDir = (0, path_2.resolvePathWithin)(root, id);
145
187
  if (!targetDir) {
146
188
  throw new CheckoutError(`Cannot checkout ${kind} with unsafe id "${id}".`);
@@ -551,33 +593,33 @@ const checkoutPage = (handoff, id, payload) => __awaiter(void 0, void 0, void 0,
551
593
  logger_1.Logger.success(`Checked out page "${id}" into ${path_1.default.relative(handoff.workingPath, pagesRoot) || '.'} ` + `(${payload.files.length} markdown file(s)).`);
552
594
  });
553
595
  /**
554
- * Checkout a single component or pattern from a connected workspace: precondition checks → fetch the
555
- * normalized record + source files → resolve the local target → explicit-overwrite guard → write
556
- * source files and synthesize the local declaration. Throws {@link CheckoutError} with actionable
557
- * messaging on any precondition or fetch failure.
596
+ * Checkout one entity through an already-resolved client: precondition checks → fetch the normalized
597
+ * record + source files → resolve the local target → explicit-overwrite guard → write source files
598
+ * and synthesize the local declaration. Shared by the single-id and bulk entry points so both behave
599
+ * identically. Throws {@link CheckoutError} with actionable messaging on any precondition or fetch
600
+ * failure.
558
601
  */
559
- const checkoutEntity = (handoff, kind, id) => __awaiter(void 0, void 0, void 0, function* () {
602
+ const checkoutSingle = (handoff, kind, id, client, registryUrl) => __awaiter(void 0, void 0, void 0, function* () {
560
603
  const validId = kind === 'page' ? (0, path_2.isSafeRelativePath)(id) : (0, path_2.isSafePathSegment)(id);
561
604
  if (!validId) {
562
605
  throw new CheckoutError(`Cannot checkout ${kind} with unsafe id "${id}".`);
563
606
  }
564
- const connection = (0, exports.resolveConnectionOrThrow)(handoff);
565
- logger_1.Logger.info(`Fetching ${kind} "${id}" from ${connection.url}…`);
566
- const client = (0, client_1.createRegistryClient)({ baseUrl: connection.url, accessToken: connection.accessToken });
607
+ logger_1.Logger.info(`Fetching ${kind} "${id}" from ${registryUrl}…`);
567
608
  let payload;
568
609
  try {
569
610
  payload = yield client.checkout(kind, id);
570
611
  }
571
612
  catch (error) {
572
613
  if (error instanceof client_1.RegistryClientError) {
573
- throw new CheckoutError(describeFetchFailure(error, kind, id, connection.url));
614
+ throw new CheckoutError(describeFetchFailure(error, kind, id, registryUrl));
574
615
  }
575
616
  throw error;
576
617
  }
577
- // Pages round-trip as a single verbatim `.md` with no declaration synthesis.
618
+ // Pages round-trip as a single verbatim `.md` with no declaration synthesis, and aren't
619
+ // declared in `entries`, so there's nothing to register.
578
620
  if (kind === 'page') {
579
621
  yield checkoutPage(handoff, id, payload);
580
- return;
622
+ return null;
581
623
  }
582
624
  const targetDir = yield resolveTargetDir(handoff, kind, id);
583
625
  const format = resolveDeclarationFormat(handoff, targetDir);
@@ -594,7 +636,7 @@ const checkoutEntity = (handoff, kind, id) => __awaiter(void 0, void 0, void 0,
594
636
  const conflicts = [...sourceTargets.map((entry) => entry.absolutePath), declarationPath].filter((file) => fs_extra_1.default.existsSync(file));
595
637
  if (!(yield confirmOverwrite(handoff, conflicts))) {
596
638
  logger_1.Logger.warn(`Checkout of ${kind} "${id}" cancelled; no files were written.`);
597
- return;
639
+ return null;
598
640
  }
599
641
  yield fs_extra_1.default.ensureDir(targetDir);
600
642
  const written = [];
@@ -606,5 +648,92 @@ const checkoutEntity = (handoff, kind, id) => __awaiter(void 0, void 0, void 0,
606
648
  written.push(declarationPath);
607
649
  logger_1.Logger.success(`Checked out ${kind} "${id}" into ${path_1.default.relative(handoff.workingPath, targetDir) || '.'} ` +
608
650
  `(${payload.files.length} source file(s) + ${declarationFileName}).`);
651
+ return targetDir;
652
+ });
653
+ /**
654
+ * Declare freshly checked-out entities in `entries.{components|patterns}` so the workspace build
655
+ * picks them up. Ones already covered by a collection directory load on their own and are left
656
+ * alone; the rest are added to the config automatically. If the config can't be edited (a computed
657
+ * or unusual `entries` array), we print the paths for the user to add so nothing is silently orphaned.
658
+ */
659
+ const registerCheckedOut = (handoff, kind, targetDirs) => __awaiter(void 0, void 0, void 0, function* () {
660
+ if (kind === 'page') {
661
+ return;
662
+ }
663
+ const entryKind = kind === 'component' ? 'components' : 'patterns';
664
+ const uncovered = targetDirs.filter((dir) => !(0, entries_1.isEntryCovered)(handoff, entryKind, dir));
665
+ if (uncovered.length === 0) {
666
+ return;
667
+ }
668
+ const result = yield (0, entries_1.writeEntries)(handoff, entryKind, uncovered);
669
+ if (result.status === 'added') {
670
+ const where = result.configPath ? path_1.default.relative(handoff.workingPath, result.configPath) || path_1.default.basename(result.configPath) : 'handoff.config';
671
+ logger_1.Logger.success(`Updated ${where} with ${result.added.length} ${entryKind} path(s).`);
672
+ return;
673
+ }
674
+ const where = result.configPath ? path_1.default.relative(handoff.workingPath, result.configPath) : 'handoff.config';
675
+ logger_1.Logger.warn(`Could not update ${where} automatically. Add these to entries.${entryKind} manually:`);
676
+ result.pending.forEach((rel) => logger_1.Logger.warn(` - ${rel}`));
677
+ });
678
+ /**
679
+ * Checkout a single component, pattern, or page from the connected registry into this workspace.
680
+ * Overwriting existing local files requires `--force` or an interactive confirmation.
681
+ */
682
+ const checkoutEntity = (handoff, kind, id) => __awaiter(void 0, void 0, void 0, function* () {
683
+ const connection = yield (0, exports.resolveConnectionOrThrow)(handoff);
684
+ const client = (0, client_1.createRegistryClient)({ baseUrl: connection.url, accessToken: connection.accessToken });
685
+ const targetDir = yield checkoutSingle(handoff, kind, id, client, connection.url);
686
+ if (targetDir) {
687
+ yield registerCheckedOut(handoff, kind, [targetDir]);
688
+ }
609
689
  });
610
690
  exports.checkoutEntity = checkoutEntity;
691
+ /**
692
+ * Checkout every published component, pattern, or page of the kind into this workspace. Enumerates
693
+ * the registry's published ids, then checks each out through the shared client. A per-entity failure
694
+ * is collected and never aborts the rest; the run throws at the end if any entity failed. Overwrite
695
+ * prompting is per entity (skipped under `--force`).
696
+ */
697
+ const checkoutEntities = (handoff, kind) => __awaiter(void 0, void 0, void 0, function* () {
698
+ const connection = yield (0, exports.resolveConnectionOrThrow)(handoff);
699
+ const client = (0, client_1.createRegistryClient)({ baseUrl: connection.url, accessToken: connection.accessToken });
700
+ let summaries;
701
+ try {
702
+ summaries = yield client.listEntities(kind);
703
+ }
704
+ catch (error) {
705
+ if (error instanceof client_1.RegistryClientError) {
706
+ throw new CheckoutError(`Could not list ${kind}s from the registry at ${connection.url}: ${error.message}`);
707
+ }
708
+ throw error;
709
+ }
710
+ if (summaries.length === 0) {
711
+ logger_1.Logger.success(`No ${kind}s are published in the registry; nothing to checkout.`);
712
+ return;
713
+ }
714
+ let checkedOut = 0;
715
+ const failed = [];
716
+ const targetDirs = [];
717
+ for (const { id } of summaries) {
718
+ try {
719
+ const targetDir = yield checkoutSingle(handoff, kind, id, client, connection.url);
720
+ if (targetDir) {
721
+ targetDirs.push(targetDir);
722
+ }
723
+ checkedOut += 1;
724
+ }
725
+ catch (error) {
726
+ failed.push({ id, message: error instanceof Error ? error.message : String(error) });
727
+ }
728
+ }
729
+ // Register everything checked out in one pass, so the config is edited (and confirmed) once.
730
+ yield registerCheckedOut(handoff, kind, targetDirs);
731
+ logger_1.Logger.success(`${kind[0].toUpperCase()}${kind.slice(1)}s checkout complete — ${checkedOut} checked out${failed.length ? `, ${failed.length} failed` : ''}.`);
732
+ if (failed.length > 0) {
733
+ for (const failure of failed) {
734
+ logger_1.Logger.error(` - ${failure.id}: ${failure.message}`);
735
+ }
736
+ throw new CheckoutError(`${failed.length} ${kind}(s) failed to checkout.`);
737
+ }
738
+ });
739
+ exports.checkoutEntities = checkoutEntities;
@@ -61,7 +61,9 @@ const describeFetchFailure = (error, target, registryUrl) => {
61
61
  case 'runtime_mode_conflict':
62
62
  return `The registry at ${registryUrl} is not running in registry mode, so it cannot serve a checkout: ${error.message}`;
63
63
  case 'unauthorized':
64
- return `The registry rejected the access token (401). Check the configured access token matches the registry's token.`;
64
+ return `The registry rejected the access token (401). Run \`handoff-app login --url ${registryUrl}\` again, or replace the user-issued CI token.`;
65
+ case 'forbidden':
66
+ return `The registry token does not have permission to checkout design tokens (403). Authorize a token with registry:read access.`;
65
67
  default:
66
68
  return error.message;
67
69
  }
@@ -99,7 +101,7 @@ const checkoutTokens = (handoff, setId) => __awaiter(void 0, void 0, void 0, fun
99
101
  if (setId && !(0, sets_1.isTokenSetId)(setId)) {
100
102
  throw new index_1.CheckoutError(`Unknown or unsafe token set id "${setId}".`);
101
103
  }
102
- const connection = (0, index_1.resolveConnectionOrThrow)(handoff);
104
+ const connection = yield (0, index_1.resolveConnectionOrThrow)(handoff);
103
105
  const client = (0, client_1.createRegistryClient)({ baseUrl: connection.url, accessToken: connection.accessToken });
104
106
  let ids;
105
107
  if (setId) {
@@ -7,7 +7,7 @@
7
7
  * surface a clear message instead of a raw fetch failure. Transport is the global `fetch` (Node 18+
8
8
  * and the browser both provide it), so this module stays runtime-agnostic.
9
9
  */
10
- import type { CheckoutPayload, TransferEntityKind, TransferPackage } from './transfer';
10
+ import type { CheckoutPayload, EntitySummary, TransferEntityKind, TransferPackage } from './transfer';
11
11
  import type { TokenSetCheckoutPayload, TokenSetSummary, TokenSetTransferPackage } from './tokens/transfer';
12
12
  import type { AssetCollectionCheckoutPayload, AssetCollectionSummary, AssetCollectionTransferPackage } from './assets/transfer';
13
13
  /** Standard registry response envelope. */
@@ -44,6 +44,7 @@ export interface RegistryClientOptions {
44
44
  export interface RegistryClient {
45
45
  publish(kind: TransferEntityKind, id: string, pkg: TransferPackage): Promise<RegistryEnvelope>;
46
46
  checkout(kind: TransferEntityKind, id: string): Promise<CheckoutPayload>;
47
+ listEntities(kind: TransferEntityKind): Promise<EntitySummary[]>;
47
48
  listTokenSets(): Promise<TokenSetSummary[]>;
48
49
  publishTokens(pkg: TokenSetTransferPackage): Promise<RegistryEnvelope>;
49
50
  checkoutTokens(id: string): Promise<TokenSetCheckoutPayload>;
@@ -115,6 +115,14 @@ const createRegistryClient = ({ baseUrl, accessToken }) => {
115
115
  return envelope.data;
116
116
  });
117
117
  },
118
+ /** List the registry's entities of one kind (id + build hashes) for skip-unchanged / bulk checkout. */
119
+ listEntities(kind) {
120
+ return __awaiter(this, void 0, void 0, function* () {
121
+ var _a, _b;
122
+ const envelope = yield request('GET', `/api/registry/transfer/${kind}`);
123
+ return (_b = (_a = envelope.data) === null || _a === void 0 ? void 0 : _a.entities) !== null && _b !== void 0 ? _b : [];
124
+ });
125
+ },
118
126
  /** List the registry's token sets (id + kind + source hash) for skip-unchanged / bulk checkout. */
119
127
  listTokenSets() {
120
128
  return __awaiter(this, void 0, void 0, function* () {
@@ -28,3 +28,12 @@ export interface ResolvedRegistryConnection {
28
28
  * Callers inspect the resolved URL and access token to surface specific configuration errors.
29
29
  */
30
30
  export declare const resolveRegistryConnection: (config: Config | null | undefined) => ResolvedRegistryConnection;
31
+ /**
32
+ * Resolve the same connection for an authenticated CLI operation, letting a saved device login fill
33
+ * in what the environment does not provide. A valid login supplies both the registry URL and the
34
+ * access token, so `handoff-app login` alone is enough to publish and checkout. Environment values
35
+ * keep precedence for deterministic CI: `HANDOFF_REGISTRY_URL` (or inline config) wins over the
36
+ * saved URL, and `HANDOFF_REGISTRY_ACCESS_TOKEN` wins over the saved token. The saved token only
37
+ * applies to the URL it was issued for.
38
+ */
39
+ export declare const resolveAuthenticatedRegistryConnection: (config: Config | null | undefined, workingPath?: string) => Promise<ResolvedRegistryConnection>;
@@ -8,8 +8,18 @@
8
8
  * access token is always read from an env-var name (never persisted as a value). This is the single
9
9
  * source the publish (and later checkout) client reads its target + credentials from.
10
10
  */
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
11
20
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.resolveRegistryConnection = exports.DEFAULT_REGISTRY_ACCESS_TOKEN_ENV = exports.DEFAULT_REGISTRY_URL_ENV = void 0;
21
+ exports.resolveAuthenticatedRegistryConnection = exports.resolveRegistryConnection = exports.DEFAULT_REGISTRY_ACCESS_TOKEN_ENV = exports.DEFAULT_REGISTRY_URL_ENV = void 0;
22
+ const store_1 = require("../cli/auth/store");
13
23
  /** Default env-var name holding the remote registry base URL. */
14
24
  exports.DEFAULT_REGISTRY_URL_ENV = 'HANDOFF_REGISTRY_URL';
15
25
  /** Default env-var name holding the connected-workspace access token. */
@@ -34,3 +44,21 @@ const resolveRegistryConnection = (config) => {
34
44
  };
35
45
  };
36
46
  exports.resolveRegistryConnection = resolveRegistryConnection;
47
+ /**
48
+ * Resolve the same connection for an authenticated CLI operation, letting a saved device login fill
49
+ * in what the environment does not provide. A valid login supplies both the registry URL and the
50
+ * access token, so `handoff-app login` alone is enough to publish and checkout. Environment values
51
+ * keep precedence for deterministic CI: `HANDOFF_REGISTRY_URL` (or inline config) wins over the
52
+ * saved URL, and `HANDOFF_REGISTRY_ACCESS_TOKEN` wins over the saved token. The saved token only
53
+ * applies to the URL it was issued for.
54
+ */
55
+ const resolveAuthenticatedRegistryConnection = (config_1, ...args_1) => __awaiter(void 0, [config_1, ...args_1], void 0, function* (config, workingPath = process.cwd()) {
56
+ const connection = (0, exports.resolveRegistryConnection)(config);
57
+ const auth = yield (0, store_1.readCliAuth)(workingPath);
58
+ if (!(0, store_1.cliAuthTokenIsValid)(auth))
59
+ return connection;
60
+ const url = connection.url || auth.remoteUrl;
61
+ const accessToken = connection.accessToken || ((0, store_1.cliAuthMatchesRegistry)(auth, url) ? auth.accessToken : '');
62
+ return Object.assign(Object.assign({}, connection), { url, accessToken });
63
+ });
64
+ exports.resolveAuthenticatedRegistryConnection = resolveAuthenticatedRegistryConnection;
@@ -1,21 +1,21 @@
1
1
  /**
2
2
  * Bundled Drizzle client + migrator for the registry database.
3
3
  *
4
- * The package ships both built-in adapters (`pg` and `neon`) and the Drizzle client/migrator, so a
4
+ * The package ships both built-in drivers (`pg` and `neon`) and the Drizzle client/migrator, so a
5
5
  * consuming project needs no global Drizzle install or separate CLI. Driver modules are loaded
6
- * lazily (dynamic import) for the selected adapter only, so workspace dev/build never pulls the
6
+ * lazily (dynamic import) for the selected driver only, so workspace dev/build never pulls the
7
7
  * Postgres/Neon drivers into memory when the registry is not in use.
8
8
  */
9
9
  import type { NeonDatabase } from 'drizzle-orm/neon-serverless';
10
10
  import type { NodePgDatabase } from 'drizzle-orm/node-postgres';
11
- import type { RegistryDatabaseAdapter } from './adapter';
11
+ import type { RegistryDatabaseDriver } from './driver';
12
12
  import * as schema from './schema';
13
- /** Typed Drizzle database over the registry schema, regardless of which adapter backs it. */
13
+ /** Typed Drizzle database over the registry schema, regardless of which driver backs it. */
14
14
  export type RegistryDatabase = NodePgDatabase<typeof schema> | NeonDatabase<typeof schema>;
15
15
  /** A live registry database connection plus its lifecycle operations. */
16
16
  export interface RegistryDbConnection {
17
- /** Selected adapter that produced this connection. */
18
- adapter: RegistryDatabaseAdapter;
17
+ /** Selected driver that produced this connection. */
18
+ driver: RegistryDatabaseDriver;
19
19
  /** Typed Drizzle database. */
20
20
  db: RegistryDatabase;
21
21
  /** Apply the package-owned migrations found in `migrationsFolder`. */
@@ -24,12 +24,12 @@ export interface RegistryDbConnection {
24
24
  close(): Promise<void>;
25
25
  }
26
26
  export interface CreateRegistryDbConnectionParams {
27
- adapter: RegistryDatabaseAdapter;
27
+ driver: RegistryDatabaseDriver;
28
28
  connectionString: string;
29
29
  }
30
30
  /**
31
- * Create a registry database connection for the resolved adapter. Both adapters target the
31
+ * Create a registry database connection for the resolved driver. Both drivers target the
32
32
  * Postgres dialect and share the same schema, so the returned connection is interchangeable for
33
33
  * migration and (later) the registry store.
34
34
  */
35
- export declare const createRegistryDbConnection: ({ adapter, connectionString, }: CreateRegistryDbConnectionParams) => Promise<RegistryDbConnection>;
35
+ export declare const createRegistryDbConnection: ({ driver, connectionString, }: CreateRegistryDbConnectionParams) => Promise<RegistryDbConnection>;
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * Bundled Drizzle client + migrator for the registry database.
4
4
  *
5
- * The package ships both built-in adapters (`pg` and `neon`) and the Drizzle client/migrator, so a
5
+ * The package ships both built-in drivers (`pg` and `neon`) and the Drizzle client/migrator, so a
6
6
  * consuming project needs no global Drizzle install or separate CLI. Driver modules are loaded
7
- * lazily (dynamic import) for the selected adapter only, so workspace dev/build never pulls the
7
+ * lazily (dynamic import) for the selected driver only, so workspace dev/build never pulls the
8
8
  * Postgres/Neon drivers into memory when the registry is not in use.
9
9
  */
10
10
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
@@ -43,13 +43,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
43
43
  exports.createRegistryDbConnection = void 0;
44
44
  const schema = __importStar(require("./schema"));
45
45
  /**
46
- * Create a registry database connection for the resolved adapter. Both adapters target the
46
+ * Create a registry database connection for the resolved driver. Both drivers target the
47
47
  * Postgres dialect and share the same schema, so the returned connection is interchangeable for
48
48
  * migration and (later) the registry store.
49
49
  */
50
- const createRegistryDbConnection = (_a) => __awaiter(void 0, [_a], void 0, function* ({ adapter, connectionString, }) {
50
+ const createRegistryDbConnection = (_a) => __awaiter(void 0, [_a], void 0, function* ({ driver, connectionString, }) {
51
51
  var _b;
52
- if (adapter === 'neon') {
52
+ if (driver === 'neon') {
53
53
  const { Pool, neonConfig } = yield Promise.resolve().then(() => __importStar(require('@neondatabase/serverless')));
54
54
  // Neon's serverless driver needs a WebSocket constructor in Node; reuse the bundled `ws`.
55
55
  const ws = yield Promise.resolve().then(() => __importStar(require('ws')));
@@ -66,7 +66,7 @@ const createRegistryDbConnection = (_a) => __awaiter(void 0, [_a], void 0, funct
66
66
  }
67
67
  const db = drizzle(pool, { schema });
68
68
  return {
69
- adapter,
69
+ driver,
70
70
  db,
71
71
  migrate: (migrationsFolder) => migrate(db, { migrationsFolder }),
72
72
  close: () => pool.end(),
@@ -85,7 +85,7 @@ const createRegistryDbConnection = (_a) => __awaiter(void 0, [_a], void 0, funct
85
85
  }
86
86
  const db = drizzle(pool, { schema });
87
87
  return {
88
- adapter,
88
+ driver,
89
89
  db,
90
90
  migrate: (migrationsFolder) => migrate(db, { migrationsFolder }),
91
91
  close: () => pool.end(),
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Registry database driver resolution.
3
+ *
4
+ * PostgreSQL is the supported database. `runtime.registry.database.driver` selects one of two
5
+ * built-in connection drivers shipped with the `handoff-app` package — `pg` (default) and `neon` —
6
+ * both targeting the same Postgres dialect over one package-owned schema and migration set. The
7
+ * driver picks *how* to connect, not *which* database engine to use. `build --target registry` and
8
+ * `db:migrate` resolve the **same** driver so build and migration never diverge. Connection
9
+ * credentials are referenced by environment-variable name only and resolved to a value at runtime;
10
+ * the value is never stored in config.
11
+ */
12
+ import type { Config } from '../../types/config';
13
+ /** Built-in registry database connection driver. Both ship with the package and target Postgres. */
14
+ export type RegistryDatabaseDriver = 'pg' | 'neon';
15
+ /** Default env-var name holding the database connection string. */
16
+ export declare const DEFAULT_DATABASE_URL_ENV = "DATABASE_URL";
17
+ /** @deprecated Fixed registry server secrets are no longer authorized. */
18
+ export declare const DEFAULT_REGISTRY_API_TOKEN_ENV = "HANDOFF_REGISTRY_API_TOKEN";
19
+ /** Default registry database driver when none is configured. */
20
+ export declare const DEFAULT_REGISTRY_DRIVER: RegistryDatabaseDriver;
21
+ /** Fully resolved registry database connection inputs. */
22
+ export interface ResolvedRegistryDatabase {
23
+ /** Selected built-in driver. */
24
+ driver: RegistryDatabaseDriver;
25
+ /** Name of the env var the connection string was read from. */
26
+ databaseUrlEnv: string;
27
+ /** Resolved connection string (never persisted in config). */
28
+ connectionString: string;
29
+ }
30
+ /** Resolve the env-var name holding the database URL (defaults to `DATABASE_URL`). */
31
+ export declare const resolveDatabaseUrlEnv: (config: Config | null | undefined) => string;
32
+ /**
33
+ * Resolve the legacy fixed-token env-var name for configuration compatibility.
34
+ *
35
+ * @deprecated The returned env var is intentionally ignored by registry authorization. Use a
36
+ * user-issued access token or `handoff-app login`.
37
+ */
38
+ export declare const resolveApiTokenEnv: (config: Config | null | undefined) => string;
39
+ /** Resolve the configured registry database driver (defaults to `pg`). */
40
+ export declare const resolveRegistryDriver: (config: Config | null | undefined) => RegistryDatabaseDriver;
41
+ /**
42
+ * Resolve the registry database connection from config + environment. Throws an actionable error
43
+ * when the configured env var is unset so the CLI can surface a clear "missing database URL"
44
+ * message instead of failing deep inside the driver.
45
+ */
46
+ export declare const resolveRegistryDatabase: (config: Config | null | undefined) => ResolvedRegistryDatabase;
@@ -1,21 +1,23 @@
1
1
  "use strict";
2
2
  /**
3
- * Registry database adapter resolution.
3
+ * Registry database driver resolution.
4
4
  *
5
- * `runtime.registry.database.adapter` selects one of two built-in adapters shipped with the
6
- * `handoff-app` package — `pg` (default) and `neon` — both targeting the Postgres dialect.
7
- * `build --target registry` and `db:migrate` resolve the **same** adapter so build and migration
8
- * never diverge. Connection credentials are referenced by environment-variable name only and
9
- * resolved to a value at runtime; the value is never stored in config.
5
+ * PostgreSQL is the supported database. `runtime.registry.database.driver` selects one of two
6
+ * built-in connection drivers shipped with the `handoff-app` package — `pg` (default) and `neon` —
7
+ * both targeting the same Postgres dialect over one package-owned schema and migration set. The
8
+ * driver picks *how* to connect, not *which* database engine to use. `build --target registry` and
9
+ * `db:migrate` resolve the **same** driver so build and migration never diverge. Connection
10
+ * credentials are referenced by environment-variable name only and resolved to a value at runtime;
11
+ * the value is never stored in config.
10
12
  */
11
13
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.resolveRegistryDatabase = exports.resolveRegistryAdapter = exports.resolveApiTokenEnv = exports.resolveDatabaseUrlEnv = exports.DEFAULT_REGISTRY_ADAPTER = exports.DEFAULT_REGISTRY_API_TOKEN_ENV = exports.DEFAULT_DATABASE_URL_ENV = void 0;
14
+ exports.resolveRegistryDatabase = exports.resolveRegistryDriver = exports.resolveApiTokenEnv = exports.resolveDatabaseUrlEnv = exports.DEFAULT_REGISTRY_DRIVER = exports.DEFAULT_REGISTRY_API_TOKEN_ENV = exports.DEFAULT_DATABASE_URL_ENV = void 0;
13
15
  /** Default env-var name holding the database connection string. */
14
16
  exports.DEFAULT_DATABASE_URL_ENV = 'DATABASE_URL';
15
- /** Default env-var name holding the registry management API bearer token. */
17
+ /** @deprecated Fixed registry server secrets are no longer authorized. */
16
18
  exports.DEFAULT_REGISTRY_API_TOKEN_ENV = 'HANDOFF_REGISTRY_API_TOKEN';
17
- /** Default registry database adapter when none is configured. */
18
- exports.DEFAULT_REGISTRY_ADAPTER = 'pg';
19
+ /** Default registry database driver when none is configured. */
20
+ exports.DEFAULT_REGISTRY_DRIVER = 'pg';
19
21
  /** Resolve the env-var name holding the database URL (defaults to `DATABASE_URL`). */
20
22
  const resolveDatabaseUrlEnv = (config) => {
21
23
  var _a, _b, _c;
@@ -24,9 +26,10 @@ const resolveDatabaseUrlEnv = (config) => {
24
26
  };
25
27
  exports.resolveDatabaseUrlEnv = resolveDatabaseUrlEnv;
26
28
  /**
27
- * Resolve the env-var *name* holding the registry management API bearer token (defaults to
28
- * `HANDOFF_REGISTRY_API_TOKEN`). Like the database URL, only the name is ever persisted — the token
29
- * value is resolved from the environment at request time and never written to config.
29
+ * Resolve the legacy fixed-token env-var name for configuration compatibility.
30
+ *
31
+ * @deprecated The returned env var is intentionally ignored by registry authorization. Use a
32
+ * user-issued access token or `handoff-app login`.
30
33
  */
31
34
  const resolveApiTokenEnv = (config) => {
32
35
  var _a, _b, _c;
@@ -34,12 +37,12 @@ const resolveApiTokenEnv = (config) => {
34
37
  return configured || exports.DEFAULT_REGISTRY_API_TOKEN_ENV;
35
38
  };
36
39
  exports.resolveApiTokenEnv = resolveApiTokenEnv;
37
- /** Resolve the configured registry adapter (defaults to `pg`). */
38
- const resolveRegistryAdapter = (config) => {
40
+ /** Resolve the configured registry database driver (defaults to `pg`). */
41
+ const resolveRegistryDriver = (config) => {
39
42
  var _a, _b, _c, _d;
40
- return (_d = (_c = (_b = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.registry) === null || _b === void 0 ? void 0 : _b.database) === null || _c === void 0 ? void 0 : _c.adapter) !== null && _d !== void 0 ? _d : exports.DEFAULT_REGISTRY_ADAPTER;
43
+ return (_d = (_c = (_b = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.registry) === null || _b === void 0 ? void 0 : _b.database) === null || _c === void 0 ? void 0 : _c.driver) !== null && _d !== void 0 ? _d : exports.DEFAULT_REGISTRY_DRIVER;
41
44
  };
42
- exports.resolveRegistryAdapter = resolveRegistryAdapter;
45
+ exports.resolveRegistryDriver = resolveRegistryDriver;
43
46
  /**
44
47
  * Resolve the registry database connection from config + environment. Throws an actionable error
45
48
  * when the configured env var is unset so the CLI can surface a clear "missing database URL"
@@ -47,13 +50,13 @@ exports.resolveRegistryAdapter = resolveRegistryAdapter;
47
50
  */
48
51
  const resolveRegistryDatabase = (config) => {
49
52
  var _a;
50
- const adapter = (0, exports.resolveRegistryAdapter)(config);
53
+ const driver = (0, exports.resolveRegistryDriver)(config);
51
54
  const databaseUrlEnv = (0, exports.resolveDatabaseUrlEnv)(config);
52
55
  const connectionString = (_a = process.env[databaseUrlEnv]) === null || _a === void 0 ? void 0 : _a.trim();
53
56
  if (!connectionString) {
54
57
  throw new Error(`Registry database URL is not configured. Set the "${databaseUrlEnv}" environment variable to a ` +
55
58
  `PostgreSQL connection string (or change "runtime.registry.databaseUrlEnv" to point at the env var you use).`);
56
59
  }
57
- return { adapter, databaseUrlEnv, connectionString };
60
+ return { driver, databaseUrlEnv, connectionString };
58
61
  };
59
62
  exports.resolveRegistryDatabase = resolveRegistryDatabase;
@@ -1,5 +1,5 @@
1
- export { buildMetadata, componentFiles, components, docsArtifacts, patternFiles, patterns, registrySchema, type BuildMetadataEntityKind, type DocsArtifactEntityKind, type RegistryReviewMetadata, } from './schema';
1
+ export { buildMetadata, componentFiles, components, docsArtifacts, patternFiles, patterns, registryAccessTokens, registryAuthActionTokens, registryAuthRateLimits, registryDeviceAuthorizations, registryInstallations, registrySchema, registryUsers, type BuildMetadataEntityKind, type DocsArtifactEntityKind, type RegistryAccessScope, type RegistryAuthActionPurpose, type RegistryDeviceAuthorizationStatus, type RegistryRateLimitBucket, type RegistryReviewMetadata, type RegistryUserRole, type RegistryUserStatus, } from './schema';
2
2
  export type { ArtifactBuildStatus as RegistryBuildStatus } from '../../artifacts/types';
3
- export { DEFAULT_DATABASE_URL_ENV, DEFAULT_REGISTRY_ADAPTER, DEFAULT_REGISTRY_API_TOKEN_ENV, resolveApiTokenEnv, resolveDatabaseUrlEnv, resolveRegistryAdapter, resolveRegistryDatabase, type RegistryDatabaseAdapter, type ResolvedRegistryDatabase, } from './adapter';
3
+ export { DEFAULT_DATABASE_URL_ENV, DEFAULT_REGISTRY_DRIVER, DEFAULT_REGISTRY_API_TOKEN_ENV, resolveApiTokenEnv, resolveDatabaseUrlEnv, resolveRegistryDriver, resolveRegistryDatabase, type RegistryDatabaseDriver, type ResolvedRegistryDatabase, } from './driver';
4
4
  export { createRegistryDbConnection, type CreateRegistryDbConnectionParams, type RegistryDatabase, type RegistryDbConnection, } from './client';
5
5
  export { getMigrationsFolder, runRegistryMigrations } from './migrate';