@agentxm/registry-client 0.28.4-bootstrap.0

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 (53) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +9 -0
  3. package/dist/src/__generated__/registry-client.d.ts +6501 -0
  4. package/dist/src/__generated__/registry-client.js +2270 -0
  5. package/dist/src/admin-client.d.ts +181 -0
  6. package/dist/src/admin-client.js +165 -0
  7. package/dist/src/archive-cache.d.ts +46 -0
  8. package/dist/src/archive-cache.js +179 -0
  9. package/dist/src/atomic-write.d.ts +49 -0
  10. package/dist/src/atomic-write.js +60 -0
  11. package/dist/src/axm-package-meta.d.ts +31 -0
  12. package/dist/src/axm-package-meta.js +31 -0
  13. package/dist/src/cache-root.d.ts +11 -0
  14. package/dist/src/cache-root.js +43 -0
  15. package/dist/src/client.d.ts +270 -0
  16. package/dist/src/client.js +43 -0
  17. package/dist/src/deprecation-warning.d.ts +3 -0
  18. package/dist/src/deprecation-warning.js +16 -0
  19. package/dist/src/error-mapping.d.ts +82 -0
  20. package/dist/src/error-mapping.js +186 -0
  21. package/dist/src/errors.d.ts +107 -0
  22. package/dist/src/errors.js +98 -0
  23. package/dist/src/failure-mapping.d.ts +14 -0
  24. package/dist/src/failure-mapping.js +100 -0
  25. package/dist/src/fs-helpers.d.ts +12 -0
  26. package/dist/src/fs-helpers.js +13 -0
  27. package/dist/src/index.d.ts +33 -0
  28. package/dist/src/index.js +37 -0
  29. package/dist/src/integrity.d.ts +13 -0
  30. package/dist/src/integrity.js +17 -0
  31. package/dist/src/local-client.d.ts +24 -0
  32. package/dist/src/local-client.js +815 -0
  33. package/dist/src/network.d.ts +6 -0
  34. package/dist/src/network.js +6 -0
  35. package/dist/src/path-safety.d.ts +18 -0
  36. package/dist/src/path-safety.js +26 -0
  37. package/dist/src/purl-match.d.ts +28 -0
  38. package/dist/src/purl-match.js +35 -0
  39. package/dist/src/registry-url.d.ts +14 -0
  40. package/dist/src/registry-url.js +12 -0
  41. package/dist/src/remote-client.d.ts +27 -0
  42. package/dist/src/remote-client.js +725 -0
  43. package/dist/src/request-policy.d.ts +29 -0
  44. package/dist/src/request-policy.js +190 -0
  45. package/dist/src/response-body.d.ts +11 -0
  46. package/dist/src/response-body.js +32 -0
  47. package/dist/src/retry-after.d.ts +9 -0
  48. package/dist/src/retry-after.js +28 -0
  49. package/dist/src/translate.d.ts +20 -0
  50. package/dist/src/translate.js +170 -0
  51. package/dist/src/utils.d.ts +60 -0
  52. package/dist/src/utils.js +187 -0
  53. package/package.json +55 -0
@@ -0,0 +1,725 @@
1
+ // @effect-diagnostics anyUnknownInErrorContext:off — generated HTTP response errors are translated to typed registry failures by this registry adapter
2
+ /**
3
+ * Remote HTTPS registry client.
4
+ *
5
+ * Implements `RegistryClient` by delegating HTTP transport to the generated
6
+ * registry client and mapping all errors to the typed registry failure
7
+ * vocabulary with per-operation categories.
8
+ *
9
+ * @experimental This API is unstable and may change without notice.
10
+ * @packageDocumentation
11
+ */
12
+ import * as HttpClient from "effect/unstable/http/HttpClient";
13
+ import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
14
+ import * as Effect from "effect/Effect";
15
+ import * as Option from "effect/Option";
16
+ import * as Schema from "effect/Schema";
17
+ import { sanitizeSuggestedAction, } from "@agentxm/registry-protocol/unstable/suggested-action";
18
+ import { parseExtensionFqnParts, toExtensionTypePlural, } from "@agentxm/extension-model/unstable/extensions/common";
19
+ import { decodeExtensionNameSync, toAuthor, ExtensionTypeSchema, } from "@agentxm/extension-model/unstable/extensions";
20
+ import { decodeHandleSync } from "@agentxm/extension-model/unstable/extensions/handle";
21
+ import { CompanionPackageSchema } from "@agentxm/extension-model/unstable/package-urls";
22
+ import { PackageUrlSchema, } from "@agentxm/extension-model/unstable/packaging/package-url";
23
+ import { packagesToPackageUrlParts, ExtensionIndexSchema, } from "@agentxm/registry-protocol/unstable/registry/schema";
24
+ import { DiscoverPackagesResponseSchema } from "@agentxm/registry-protocol/unstable/registry/discover-schema";
25
+ import { decodeVersionSync } from "@agentxm/extension-model/unstable/version-constraints";
26
+ import { extensionLifecycleWarnings, pluralizeType, resolveVersionEntry } from "./utils.js";
27
+ import { isRegistryClientError, hasTagSuffix, getTag } from "./error-mapping.js";
28
+ import { RegistryOperationFailed, RegistryRequestFailed, withRegistrySemantics, } from "./errors.js";
29
+ import { captureRegistryErrorResponseBodies, mapRegistryFailure } from "./failure-mapping.js";
30
+ import { executeRegistryRequest, PUBLISH_REGISTRY_REQUEST_POLICY, } from "./request-policy.js";
31
+ import * as GeneratedRegistryClient from "./__generated__/registry-client.js";
32
+ // Reuse the established four-request cap from publish transport. Named and
33
+ // list discovery share the same registry service and must not multiply it via
34
+ // nested traversals.
35
+ const REGISTRY_READ_CONCURRENCY = 4;
36
+ const SETTLEMENT_READ_REQUEST_POLICY = {
37
+ requestTimeout: "10 seconds",
38
+ totalDeadline: "10 seconds",
39
+ maxAttempts: 1,
40
+ initialBackoff: "200 millis",
41
+ maxBackoff: "2 seconds",
42
+ };
43
+ import { PreviewPublicationSetResponseSchema, validatePublicationDescriptors, validatePublicationSetResponse, } from "@agentxm/registry-protocol/unstable/registry/publication-set";
44
+ // -----------------------------------------------------------------------------
45
+ // Type Mapping Helpers
46
+ // -----------------------------------------------------------------------------
47
+ const decodeExtensionType = Schema.decodeUnknownSync(ExtensionTypeSchema);
48
+ const decodeExtensionIndex = Schema.decodeUnknownSync(Schema.toType(ExtensionIndexSchema));
49
+ const decodeCompanionPackages = Schema.decodeUnknownSync(Schema.Array(CompanionPackageSchema));
50
+ const encodePackageUrl = Schema.encodeSync(PackageUrlSchema);
51
+ const normalizeRegistrySuggestedAction = (suggestion) => sanitizeSuggestedAction({
52
+ description: suggestion.description,
53
+ ...(suggestion.cmd === undefined || suggestion.cmd === null ? {} : { cmd: suggestion.cmd }),
54
+ ...(suggestion.url === undefined || suggestion.url === null ? {} : { url: suggestion.url }),
55
+ });
56
+ /**
57
+ * Narrow a string to ExtensionType via Schema validation.
58
+ * The generated client uses a wider union than our domain type;
59
+ * this validates the value is within our supported subset.
60
+ */
61
+ const narrowExtensionType = (type) => decodeExtensionType(type);
62
+ const decodePublicationSetResponse = Schema.decodeUnknownSync(PreviewPublicationSetResponseSchema);
63
+ const encodePublicationSetRequest = (args) => ({
64
+ contract: args.contract,
65
+ candidates: args.candidates.map((descriptor) => ({
66
+ target: descriptor.target,
67
+ participation: descriptor.participation,
68
+ ...(descriptor.archiveSha256Hex === undefined
69
+ ? {}
70
+ : { archiveSha256Hex: descriptor.archiveSha256Hex }),
71
+ visibility: descriptor.visibility,
72
+ ...(descriptor.pack === undefined ? {} : { pack: descriptor.pack }),
73
+ })),
74
+ });
75
+ /**
76
+ * Map the generated ExtensionsGet200 response to our domain ExtensionIndex type.
77
+ *
78
+ * Validates against the type side of ExtensionIndexSchema, so timestamps the
79
+ * generated client already decoded to DateTime.Utc flow through without an
80
+ * encode/re-decode round-trip. Companion packages are the one remaining
81
+ * wire-form field (versionRange strings), so they decode via the wire schema.
82
+ */
83
+ const mapToExtensionIndex = (response) => decodeExtensionIndex({
84
+ name: response.name,
85
+ owner: response.owner,
86
+ type: narrowExtensionType(response.type),
87
+ publisherBindingId: response.publisher_binding_id,
88
+ description: response.description ?? undefined,
89
+ repository: response.repository ?? undefined,
90
+ license: response.license ?? undefined,
91
+ authors: response.authors === null || response.authors === undefined
92
+ ? undefined
93
+ : response.authors.map((a) => ({
94
+ name: a.name ?? "",
95
+ email: a.email ?? undefined,
96
+ url: a.url ?? undefined,
97
+ })),
98
+ visibility: response.visibility ?? undefined,
99
+ deprecation: response.deprecation === null
100
+ ? null
101
+ : response.deprecation.message !== undefined && response.deprecation.message !== null
102
+ ? {
103
+ deprecatedAt: response.deprecation.deprecatedAt,
104
+ message: response.deprecation.message,
105
+ ...(response.deprecation.replacement === undefined ||
106
+ response.deprecation.replacement === null
107
+ ? {}
108
+ : {
109
+ replacement: response.deprecation.replacement.status === "available"
110
+ ? response.deprecation.replacement
111
+ : {
112
+ status: "unavailable",
113
+ ...(response.deprecation.replacement.fqn === undefined ||
114
+ response.deprecation.replacement.fqn === null
115
+ ? {}
116
+ : { fqn: response.deprecation.replacement.fqn }),
117
+ },
118
+ }),
119
+ }
120
+ : {
121
+ deprecatedAt: response.deprecation.deprecatedAt,
122
+ replacement: response.deprecation.replacement?.status === "available"
123
+ ? response.deprecation.replacement
124
+ : {
125
+ status: "unavailable",
126
+ ...(response.deprecation.replacement?.fqn === undefined ||
127
+ response.deprecation.replacement.fqn === null
128
+ ? {}
129
+ : { fqn: response.deprecation.replacement.fqn }),
130
+ },
131
+ },
132
+ versions: response.versions.map((v) => ({
133
+ version: v.version,
134
+ published: v.published,
135
+ integrity: v.integrity,
136
+ dependencies: v.dependencies === null ? undefined : v.dependencies,
137
+ packages: v.packages === null || v.packages === undefined
138
+ ? undefined
139
+ : decodeCompanionPackages(v.packages),
140
+ yankedAt: v.yanked_at ?? undefined,
141
+ yankCategory: v.yank_category ?? undefined,
142
+ yankNotice: v.yank_notice ?? undefined,
143
+ })),
144
+ });
145
+ /**
146
+ * Convert an ExtensionIndex + version constraint to a RegistryExtensionManifest.
147
+ */
148
+ const toRegistryManifest = (index, versionRange) => {
149
+ const selected = resolveVersionEntry(index.versions, versionRange);
150
+ if (Option.isNone(selected))
151
+ return Option.none();
152
+ const latest = selected.value;
153
+ const lifecycleWarnings = extensionLifecycleWarnings(index, latest);
154
+ return Option.some({
155
+ owner: index.owner,
156
+ type: index.type,
157
+ name: index.name,
158
+ publisherBindingId: index.publisherBindingId,
159
+ description: Option.fromUndefinedOr(index.description),
160
+ repository: Option.fromUndefinedOr(index.repository),
161
+ bugs: Option.fromUndefinedOr(index.bugs),
162
+ license: Option.fromUndefinedOr(index.license),
163
+ authors: index.authors === undefined ? [] : index.authors.map((author) => toAuthor(author)),
164
+ dependencies: latest.dependencies ?? {},
165
+ version: latest.version,
166
+ integrity: latest.integrity,
167
+ packages: packagesToPackageUrlParts(latest.packages),
168
+ ...(index.deprecation === null ? {} : { deprecation: index.deprecation }),
169
+ ...(lifecycleWarnings.length === 0 ? {} : { lifecycleWarnings }),
170
+ });
171
+ };
172
+ // -----------------------------------------------------------------------------
173
+ // Remote Registry Client
174
+ // -----------------------------------------------------------------------------
175
+ const remoteDiscoveryTypes = [
176
+ "skill",
177
+ "mcp-server",
178
+ "subagent",
179
+ "pack",
180
+ ];
181
+ const packageIdentity = (parts) => ({
182
+ type: parts.type,
183
+ name: parts.name,
184
+ ...(parts.namespace === undefined ? {} : { namespace: parts.namespace }),
185
+ ...(parts.qualifiers === undefined ? {} : { qualifiers: parts.qualifiers }),
186
+ ...(parts.subpath === undefined ? {} : { subpath: parts.subpath }),
187
+ });
188
+ const extensionDeclarationToDiscoveryRef = (value) => {
189
+ const parts = parseExtensionFqnParts(value.ref);
190
+ if (parts === undefined) {
191
+ return undefined;
192
+ }
193
+ return {
194
+ ref: `${parts.owner}/${toExtensionTypePlural(parts.type)}/${parts.name}`,
195
+ ...(value.versionRange === undefined || value.versionRange === null
196
+ ? {}
197
+ : { versionRange: value.versionRange }),
198
+ };
199
+ };
200
+ const registryRequestMetadata = (method, url) => ({
201
+ service: "registry",
202
+ method,
203
+ url,
204
+ });
205
+ /**
206
+ * Creates a remote HTTPS registry client.
207
+ *
208
+ * Uses the generated registry client for all HTTP transport and maps
209
+ * generated errors to typed registry failure categories per-operation.
210
+ *
211
+ * @param baseUrl - Base URL of the remote registry (e.g. `https://registry.example.com`)
212
+ * @param httpClient - Effect HttpClient instance for making HTTP requests
213
+ *
214
+ * @experimental This API is unstable and may change without notice.
215
+ */
216
+ export const createRemoteRegistryClient = (baseUrl, httpClient, archiveCache, requestPolicy) => {
217
+ const remoteHttpClient = captureRegistryErrorResponseBodies(httpClient.pipe(HttpClient.mapRequest(HttpClientRequest.prependUrl(baseUrl))));
218
+ const client = GeneratedRegistryClient.make(remoteHttpClient);
219
+ const verificationArchiveClient = GeneratedRegistryClient.make(remoteHttpClient, {
220
+ transformClient: (baseClient) => Effect.succeed(baseClient.pipe(HttpClient.mapRequest(HttpClientRequest.setHeader("x-agentxm-usage-purpose", "verification")))),
221
+ });
222
+ const executeRemoteRequest = (effect, args) => executeRegistryRequest(effect, {
223
+ operation: args.operation,
224
+ request: registryRequestMetadata(args.method, new URL(args.path, baseUrl).href),
225
+ replaySafety: args.replaySafety,
226
+ mapError: args.mapError,
227
+ ...(requestPolicy === undefined && args.policy === undefined
228
+ ? {}
229
+ : { policy: requestPolicy ?? args.policy }),
230
+ });
231
+ const safe = { kind: "safe" };
232
+ const mutation = { kind: "mutation" };
233
+ const mapFailure = (error, context) => mapRegistryFailure(error, {
234
+ baseUrl,
235
+ requestConstructionDetail: "Could not construct the Registry request.",
236
+ ...context,
237
+ });
238
+ // ---------------------------------------------------------------------------
239
+ // getExtensionIndex
240
+ // ---------------------------------------------------------------------------
241
+ const getExtensionIndex = (args) => executeRemoteRequest(client.ExtensionsGet(args.owner, pluralizeType(args.type), args.name, undefined).pipe(
242
+ // Resolve the HTTP outcome first (404 → absent), then decode the index in
243
+ // the effect so a schema-drift SchemaError is mapped through the error
244
+ // channel (mapDiscoveryError's isSchemaError branch) instead of throwing
245
+ // an uncatchable defect out of Effect.map.
246
+ Effect.map((response) => Option.some(response)), Effect.catch((e) => isRegistryClientError("ExtensionsGet404")(e)
247
+ ? Effect.succeed(Option.none())
248
+ : Effect.fail(e))), {
249
+ operation: "get extension index",
250
+ method: "GET",
251
+ path: `/v1/extensions/${args.owner}/${pluralizeType(args.type)}/${args.name}`,
252
+ replaySafety: safe,
253
+ mapError: (error) => mapDiscoveryError(error, "REGISTRY_REMOTE_DISCOVERY"),
254
+ }).pipe(Effect.flatMap((response) => {
255
+ if (Option.isNone(response)) {
256
+ return Effect.succeed(Option.none());
257
+ }
258
+ const responseValue = response.value;
259
+ if (responseValue === undefined) {
260
+ return Effect.fail(new RegistryRequestFailed({
261
+ category: "internal",
262
+ detail: "Remote Registry returned an extension index without a body",
263
+ }));
264
+ }
265
+ return Effect.try({
266
+ try: () => Option.some(mapToExtensionIndex(responseValue)),
267
+ catch: (cause) => mapDiscoveryError(cause, "REGISTRY_REMOTE_DISCOVERY"),
268
+ });
269
+ }));
270
+ const getExactExtensionVersion = (args) => {
271
+ const exactClient = GeneratedRegistryClient.make(remoteHttpClient, {
272
+ transformClient: (baseClient) => Effect.succeed(args.accessToken === undefined
273
+ ? baseClient
274
+ : baseClient.pipe(HttpClient.mapRequest(HttpClientRequest.bearerToken(args.accessToken)))),
275
+ });
276
+ return executeRemoteRequest(exactClient
277
+ .ExtensionsGetVersion(args.owner, pluralizeType(args.type), args.name, args.version, undefined)
278
+ .pipe(Effect.map((response) => Option.some({
279
+ owner: decodeHandleSync(response.owner),
280
+ type: narrowExtensionType(response.type),
281
+ name: decodeExtensionNameSync(response.name),
282
+ version: decodeVersionSync(response.version),
283
+ integrity: response.integrity,
284
+ status: response.status,
285
+ })), Effect.catch((error) => isRegistryClientError("ExtensionsGetVersion404")(error)
286
+ ? Effect.succeed(Option.none())
287
+ : Effect.fail(error))), {
288
+ operation: "get exact extension version",
289
+ method: "GET",
290
+ path: `/v1/extensions/${args.owner}/${pluralizeType(args.type)}/${args.name}/${args.version}`,
291
+ replaySafety: safe,
292
+ mapError: (error) => mapDiscoveryError(error, "REGISTRY_REMOTE_DISCOVERY"),
293
+ policy: SETTLEMENT_READ_REQUEST_POLICY,
294
+ });
295
+ };
296
+ /**
297
+ * Map all discovery/read errors to typed registry failures.
298
+ */
299
+ const mapDiscoveryError = (e, _prefix) => {
300
+ return mapFailure(e, {
301
+ networkDetail: "Failed to connect to remote registry discovery endpoint",
302
+ incompatibleDetail: "Remote discovery response does not match expected schema",
303
+ fallbackDetail: "Remote discovery failed",
304
+ });
305
+ };
306
+ // ---------------------------------------------------------------------------
307
+ // getExtensionsByScope
308
+ // ---------------------------------------------------------------------------
309
+ const getExtensionsByScope = (args) => Effect.gen(function* () {
310
+ let allExtensions;
311
+ const owner = args.owner;
312
+ if (args.names.length === 0 || owner === "*") {
313
+ // List mode: fetch owner listing, then fan-out to get full indexes
314
+ allExtensions = yield* getListModeExtensions(args);
315
+ if (args.names.length > 0) {
316
+ const nameSet = new Set(args.names);
317
+ const requestedTypes = new Set(args.types);
318
+ allExtensions = allExtensions.filter((entry) => nameSet.has(entry.name) &&
319
+ (requestedTypes.size === 0 || requestedTypes.has(entry.type)));
320
+ }
321
+ }
322
+ else {
323
+ // Named mode: fetch each name+type combination
324
+ const requestedTypes = args.types.length > 0 ? args.types : remoteDiscoveryTypes;
325
+ const requests = args.names.flatMap((name) => requestedTypes.map((type) => ({ name, type })));
326
+ const maybeEntries = yield* Effect.forEach(requests, ({ name, type }) => Effect.sync(() => {
327
+ try {
328
+ return decodeExtensionNameSync(name);
329
+ }
330
+ catch {
331
+ return undefined;
332
+ }
333
+ }).pipe(Effect.flatMap((decodedName) => decodedName === undefined
334
+ ? Effect.succeed(Option.none())
335
+ : getExtensionIndex({ owner, type, name: decodedName }))), { concurrency: REGISTRY_READ_CONCURRENCY });
336
+ allExtensions = maybeEntries.flatMap((entry) => Option.match(entry, {
337
+ onNone: () => [],
338
+ onSome: (value) => Option.match(toRegistryManifest(value, Option.none()), {
339
+ onNone: () => [],
340
+ onSome: (manifest) => [manifest],
341
+ }),
342
+ }));
343
+ }
344
+ const total = allExtensions.length;
345
+ const sliced = allExtensions.slice(args.offset);
346
+ const extensions = Option.match(args.limit, {
347
+ onNone: () => sliced,
348
+ onSome: (limit) => sliced.slice(0, limit),
349
+ });
350
+ return { extensions, total };
351
+ });
352
+ const getListModeExtensions = (args) => Effect.gen(function* () {
353
+ // Fetch extension lists by type
354
+ const listResults = args.types.length === 0
355
+ ? [yield* fetchExtensionList(args.owner)]
356
+ : yield* Effect.forEach(args.types, (type) => fetchExtensionListByType(args.owner, type), { concurrency: REGISTRY_READ_CONCURRENCY });
357
+ const summaries = listResults.flat();
358
+ // Fetch full indexes for each extension
359
+ const maybeEntries = yield* Effect.forEach(summaries, (summary) => getExtensionIndex({
360
+ owner: decodeHandleSync(summary.owner),
361
+ type: narrowExtensionType(summary.type),
362
+ name: decodeExtensionNameSync(summary.name),
363
+ }), { concurrency: REGISTRY_READ_CONCURRENCY });
364
+ const allExtensions = maybeEntries.flatMap((entry) => Option.match(entry, {
365
+ onNone: () => [],
366
+ onSome: (value) => Option.match(toRegistryManifest(value, Option.none()), {
367
+ onNone: () => [],
368
+ onSome: (manifest) => [manifest],
369
+ }),
370
+ }));
371
+ const sorted = [...allExtensions].sort((a, b) => {
372
+ if (a.owner !== b.owner)
373
+ return a.owner.localeCompare(b.owner);
374
+ if (a.name !== b.name)
375
+ return a.name.localeCompare(b.name);
376
+ return a.type.localeCompare(b.type);
377
+ });
378
+ return sorted;
379
+ });
380
+ const fetchExtensionList = (owner) => executeRemoteRequest(client.ExtensionsListByOwner(owner, undefined), {
381
+ operation: "list owner extensions",
382
+ method: "GET",
383
+ path: `/v1/extensions/${owner}`,
384
+ replaySafety: safe,
385
+ mapError: (error) => mapDiscoveryError(error, "REGISTRY_REMOTE_DISCOVERY"),
386
+ }).pipe(Effect.map((response) => response.extensions));
387
+ const fetchExtensionListByType = (owner, type) => executeRemoteRequest(client.ExtensionsListByType(owner, pluralizeType(type), undefined), {
388
+ operation: "list owner extensions by type",
389
+ method: "GET",
390
+ path: `/v1/extensions/${owner}/${pluralizeType(type)}`,
391
+ replaySafety: safe,
392
+ mapError: (error) => mapDiscoveryError(error, "REGISTRY_REMOTE_DISCOVERY"),
393
+ }).pipe(Effect.map((response) => response.extensions));
394
+ // ---------------------------------------------------------------------------
395
+ // ownerExists
396
+ // ---------------------------------------------------------------------------
397
+ const ownerExists = (owner) => executeRemoteRequest(client.OwnersGetOwner(owner, undefined).pipe(Effect.as({ exists: true }), Effect.catch((e) => {
398
+ // 404 → not found
399
+ if (hasTagSuffix(e, "404")) {
400
+ return Effect.succeed({ exists: false });
401
+ }
402
+ return Effect.fail(e);
403
+ })), {
404
+ operation: "get owner",
405
+ method: "GET",
406
+ path: `/v1/owners/${owner}`,
407
+ replaySafety: safe,
408
+ mapError: mapOwnerExistsError,
409
+ });
410
+ /**
411
+ * Map ownerExists errors to typed registry failures.
412
+ */
413
+ const mapOwnerExistsError = (e) => {
414
+ return mapFailure(e, {
415
+ networkDetail: "Failed to connect to remote registry owner endpoint",
416
+ incompatibleDetail: "Remote owner endpoint response does not match expected schema",
417
+ fallbackDetail: "Remote owner check failed",
418
+ });
419
+ };
420
+ // ---------------------------------------------------------------------------
421
+ // getExtensionPackage
422
+ // ---------------------------------------------------------------------------
423
+ const getExtensionPackage = (args) => Effect.gen(function* () {
424
+ // Step 1: Fetch extension index
425
+ const indexResult = yield* executeRemoteRequest(client.ExtensionsGet(args.owner, pluralizeType(args.type), args.name, undefined), {
426
+ operation: "get package index",
427
+ method: "GET",
428
+ path: `/v1/extensions/${args.owner}/${pluralizeType(args.type)}/${args.name}`,
429
+ replaySafety: safe,
430
+ mapError: mapPackageFetchError,
431
+ });
432
+ if (indexResult === undefined) {
433
+ return yield* new RegistryRequestFailed({
434
+ category: "internal",
435
+ detail: "Remote Registry returned a package index without a body",
436
+ });
437
+ }
438
+ const index = yield* Effect.try({
439
+ try: () => mapToExtensionIndex(indexResult),
440
+ catch: (cause) => mapDiscoveryError(cause, "REGISTRY_REMOTE_DISCOVERY"),
441
+ });
442
+ // Step 2: Resolve version
443
+ const resolvedEntry = resolveVersionEntry(index.versions, args.version);
444
+ if (Option.isNone(resolvedEntry)) {
445
+ return yield* new RegistryOperationFailed({
446
+ category: "not_found",
447
+ detail: "Requested package version is not available in remote index",
448
+ });
449
+ }
450
+ if (archiveCache !== undefined) {
451
+ const cached = yield* archiveCache.read(resolvedEntry.value.integrity);
452
+ if (Option.isSome(cached)) {
453
+ const warnings = extensionLifecycleWarnings(index, resolvedEntry.value);
454
+ return {
455
+ archive: cached.value,
456
+ ...(warnings.length === 0 ? {} : { warnings }),
457
+ };
458
+ }
459
+ }
460
+ // Step 3: Download archive
461
+ const archiveClient = args.usagePurpose === "verification" ? verificationArchiveClient : client;
462
+ const archive = yield* executeRemoteRequest(archiveClient.ExtensionsDownloadArchive(args.owner, pluralizeType(args.type), args.name, resolvedEntry.value.version, undefined), {
463
+ operation: "download package archive",
464
+ method: "GET",
465
+ path: `/v1/extensions/${args.owner}/${pluralizeType(args.type)}/${args.name}/${resolvedEntry.value.version}/archive`,
466
+ replaySafety: safe,
467
+ mapError: mapArchiveFetchError,
468
+ });
469
+ if (archiveCache !== undefined) {
470
+ yield* archiveCache.write(resolvedEntry.value.integrity, archive);
471
+ }
472
+ const warnings = extensionLifecycleWarnings(index, resolvedEntry.value);
473
+ return {
474
+ archive,
475
+ ...(warnings.length === 0 ? {} : { warnings }),
476
+ };
477
+ });
478
+ /**
479
+ * Map errors from the index fetch step of getExtensionPackage.
480
+ */
481
+ const mapPackageFetchError = (e) => {
482
+ const mapped = mapFailure(e, {
483
+ networkDetail: "Failed to connect to remote registry package endpoint",
484
+ incompatibleDetail: "Remote package index response does not match expected schema",
485
+ fallbackDetail: "Remote package index request failed",
486
+ });
487
+ return mapped.metadata?.response?.status === 404
488
+ ? withRegistrySemantics(mapped, {
489
+ category: "not_found",
490
+ detail: "Remote package index was not found",
491
+ })
492
+ : mapped;
493
+ };
494
+ /**
495
+ * Map errors from the archive download step of getExtensionPackage.
496
+ */
497
+ const mapArchiveFetchError = (e) => {
498
+ const mapped = mapFailure(e, {
499
+ networkDetail: "Failed to connect to remote registry package archive endpoint",
500
+ incompatibleDetail: "Failed to read remote package archive response",
501
+ fallbackDetail: "Remote package archive request failed",
502
+ });
503
+ return mapped.metadata?.response?.status === 404
504
+ ? withRegistrySemantics(mapped, {
505
+ category: "not_found",
506
+ detail: "Remote package archive was not found",
507
+ })
508
+ : mapped;
509
+ };
510
+ // ---------------------------------------------------------------------------
511
+ // extensionExists
512
+ // ---------------------------------------------------------------------------
513
+ const extensionExists = (args) => executeRemoteRequest(client.ExtensionsHead(args.owner, pluralizeType(args.type), args.name, undefined).pipe(Effect.map(() => ({ exists: true })), Effect.catch((e) => {
514
+ if (getTag(e) === "404") {
515
+ return Effect.succeed({ exists: false });
516
+ }
517
+ return Effect.fail(e);
518
+ })), {
519
+ operation: "check extension",
520
+ method: "HEAD",
521
+ path: `/v1/extensions/${args.owner}/${pluralizeType(args.type)}/${args.name}`,
522
+ replaySafety: safe,
523
+ mapError: mapExtensionExistsError,
524
+ });
525
+ /**
526
+ * Map extensionExists errors to typed registry failures.
527
+ */
528
+ const mapExtensionExistsError = (e) => {
529
+ return mapFailure(e, {
530
+ networkDetail: "Failed to connect to remote registry extension check endpoint",
531
+ incompatibleDetail: "Remote extension check response does not match expected schema",
532
+ fallbackDetail: "Remote extension check failed",
533
+ });
534
+ };
535
+ // ---------------------------------------------------------------------------
536
+ // publishExtension
537
+ // ---------------------------------------------------------------------------
538
+ const publishExtension = (args) => {
539
+ if (args.condition === undefined ||
540
+ args.publicationSetDigest === undefined ||
541
+ args.publicationDescriptorDigest === undefined) {
542
+ return Effect.fail(new RegistryOperationFailed({
543
+ category: "validation",
544
+ detail: "Remote publish requires an admitted publication-set preview.",
545
+ suggestions: [{ description: "Preview the complete publication set before uploading." }],
546
+ }));
547
+ }
548
+ const contentDigest = args.metadata.integrity.startsWith("sha512-")
549
+ ? `sha-512=:${args.metadata.integrity.slice("sha512-".length)}:`
550
+ : args.metadata.integrity;
551
+ const publishClient = GeneratedRegistryClient.make(remoteHttpClient, {
552
+ transformClient: (baseClient) => Effect.succeed(baseClient.pipe(HttpClient.mapRequest((request) => {
553
+ const archiveRequest = request.pipe(HttpClientRequest.bodyUint8Array(args.archive, "application/zip"), HttpClientRequest.setHeaders({
554
+ "content-digest": contentDigest,
555
+ "content-length": String(args.archive.byteLength),
556
+ }));
557
+ return args.accessToken === undefined
558
+ ? archiveRequest
559
+ : HttpClientRequest.bearerToken(archiveRequest, args.accessToken);
560
+ }))),
561
+ });
562
+ return executeRemoteRequest(publishClient
563
+ .ExtensionsPublishVersion(args.owner, pluralizeType(args.type), args.name, args.version, {
564
+ params: {
565
+ "if-match": args.condition,
566
+ "x-axm-publication-set-digest": args.publicationSetDigest,
567
+ "x-axm-publication-descriptor-digest": args.publicationDescriptorDigest,
568
+ "x-axm-visibility-input": JSON.stringify(args.visibilityInput),
569
+ ...(args.visibility === undefined ? {} : { visibility: args.visibility.value }),
570
+ },
571
+ })
572
+ .pipe(Effect.map((response) => ({
573
+ published: true,
574
+ owner: decodeHandleSync(response.owner),
575
+ type: narrowExtensionType(response.type),
576
+ name: decodeExtensionNameSync(response.name),
577
+ version: decodeVersionSync(response.version),
578
+ integrity: response.integrity,
579
+ status: response.publish_status,
580
+ visibility: response.visibility,
581
+ links: response.links,
582
+ warnings: response.warnings.map((warning) => ({
583
+ ruleId: warning.ruleId,
584
+ severity: "warning",
585
+ message: warning.message,
586
+ suggestions: warning.suggestions.map(normalizeRegistrySuggestedAction),
587
+ })),
588
+ }))), {
589
+ operation: "publish extension version",
590
+ method: "PUT",
591
+ path: `/v1/extensions/${args.owner}/${pluralizeType(args.type)}/${args.name}/${args.version}`,
592
+ replaySafety: mutation,
593
+ mapError: mapPublishError,
594
+ policy: PUBLISH_REGISTRY_REQUEST_POLICY,
595
+ });
596
+ };
597
+ const previewExtensionPublishes = (args) => executeRemoteRequest(client
598
+ .PublishPreviewsPreviewExtensionPublishes({
599
+ payload: encodePublicationSetRequest(args),
600
+ config: undefined,
601
+ })
602
+ .pipe(Effect.flatMap((response) => Effect.try({
603
+ try: () => validatePublicationSetResponse(validatePublicationDescriptors(args.candidates), decodePublicationSetResponse(response)),
604
+ catch: (cause) => new RegistryRequestFailed({
605
+ category: "internal",
606
+ detail: "The registry returned an incompatible publication-set preview.",
607
+ cause,
608
+ }),
609
+ }))), {
610
+ operation: "preview extension publishes",
611
+ method: "POST",
612
+ path: "/v1/publish-previews",
613
+ replaySafety: safe,
614
+ mapError: (error) => mapFailure(error, {
615
+ networkDetail: "Failed to connect to the publish preview endpoint",
616
+ incompatibleDetail: "The registry returned an incompatible authoritative publish preview.",
617
+ fallbackDetail: "Publish preview failed",
618
+ }),
619
+ });
620
+ const updateExtensionVisibility = (args) => {
621
+ const target = parseExtensionFqnParts(args.target);
622
+ if (target === undefined) {
623
+ return Effect.fail(new RegistryOperationFailed({
624
+ category: "validation",
625
+ detail: `Invalid extension target: ${args.target}`,
626
+ }));
627
+ }
628
+ const payload = {
629
+ target: args.target,
630
+ visibility: args.visibility,
631
+ authority: args.authority,
632
+ revision: args.revision,
633
+ ...(args.verification === undefined ? {} : { verification: args.verification }),
634
+ };
635
+ return executeRemoteRequest(client.ExtensionsUpdateVisibility(target.owner, pluralizeType(target.type), target.name, {
636
+ params: {
637
+ "if-match": args.revision,
638
+ ...(args.verification === undefined
639
+ ? {}
640
+ : { "x-axm-step-up-request": args.verification }),
641
+ },
642
+ payload,
643
+ config: undefined,
644
+ }), {
645
+ operation: "update extension visibility",
646
+ method: "PATCH",
647
+ path: `/v1/extensions/${target.owner}/${pluralizeType(target.type)}/${target.name}`,
648
+ replaySafety: mutation,
649
+ mapError: (error) => mapFailure(error, {
650
+ networkDetail: "Failed to connect to extension visibility endpoint",
651
+ incompatibleDetail: "Extension visibility response does not match the expected schema.",
652
+ fallbackDetail: "Remote extension visibility update failed",
653
+ }),
654
+ });
655
+ };
656
+ const getExtensionVisibility = (args) => executeRemoteRequest(client.ExtensionsGetVisibility(args.owner, pluralizeType(args.type), args.name, {
657
+ ...(args.intent === null
658
+ ? {}
659
+ : {
660
+ params: {
661
+ intent_visibility: args.intent.value,
662
+ intent_source: args.intent.source,
663
+ intent_fingerprint: args.intent.fingerprint,
664
+ },
665
+ }),
666
+ config: undefined,
667
+ }), {
668
+ operation: "get extension visibility",
669
+ method: "GET",
670
+ path: `/v1/extensions/${args.owner}/${pluralizeType(args.type)}/${args.name}/visibility`,
671
+ replaySafety: safe,
672
+ mapError: (error) => mapFailure(error, {
673
+ networkDetail: "Failed to connect to extension visibility endpoint",
674
+ incompatibleDetail: "Extension visibility response does not match the expected schema.",
675
+ fallbackDetail: "Remote extension visibility evaluation failed",
676
+ }),
677
+ });
678
+ /**
679
+ * Map all publish error types through the shared Registry boundary.
680
+ */
681
+ const mapPublishError = (e) => mapFailure(e, {
682
+ networkDetail: "Remote registry is unreachable",
683
+ incompatibleDetail: "The registry returned a response the CLI could not parse.",
684
+ fallbackDetail: "Publish failed",
685
+ });
686
+ // ---------------------------------------------------------------------------
687
+ // discoverPackages
688
+ // ---------------------------------------------------------------------------
689
+ const discoverPackages = (args) => {
690
+ const payload = {
691
+ client: { axmVersion: "0.0.0" },
692
+ packages: args.packages.map((pkg) => ({
693
+ purl: encodePackageUrl(packageIdentity(pkg.purl)),
694
+ version: pkg.version,
695
+ declaredExtensions: pkg.declaredExtensions.flatMap((entry) => {
696
+ const ref = extensionDeclarationToDiscoveryRef(entry);
697
+ return ref === undefined ? [] : [ref];
698
+ }),
699
+ })),
700
+ };
701
+ return executeRemoteRequest(client
702
+ .DiscoveryPostDiscovery({ payload, config: undefined })
703
+ .pipe(Effect.flatMap(Schema.decodeUnknownEffect(DiscoverPackagesResponseSchema))), {
704
+ operation: "discover packages",
705
+ method: "POST",
706
+ path: "/v1/discovery",
707
+ replaySafety: safe,
708
+ mapError: (error) => mapDiscoveryError(error, "REGISTRY_REMOTE_DISCOVERY"),
709
+ });
710
+ };
711
+ return {
712
+ getExtensionIndex,
713
+ getExactExtensionVersion,
714
+ getExtensionsByScope,
715
+ ownerExists,
716
+ getExtensionPackage,
717
+ publishExtension,
718
+ previewExtensionPublishes,
719
+ getExtensionVisibility,
720
+ updateExtensionVisibility,
721
+ extensionExists,
722
+ discoverPackages,
723
+ };
724
+ };
725
+ //# sourceMappingURL=remote-client.js.map