@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,187 @@
1
+ /**
2
+ * Registry utility functions extracted from sources/providers/registry.ts.
3
+ *
4
+ * Shared helpers for registry operations: version selection, integrity
5
+ * computation, zip extraction, type pluralization, and path building.
6
+ *
7
+ * @experimental This API is unstable and may change without notice.
8
+ * @packageDocumentation
9
+ */
10
+ import { unzipSync } from "fflate";
11
+ import * as FileSystem from "effect/FileSystem";
12
+ import * as Path from "effect/Path";
13
+ import * as Duration from "effect/Duration";
14
+ import * as Effect from "effect/Effect";
15
+ import * as Option from "effect/Option";
16
+ import * as semver from "semver";
17
+ import { RegistryOperationFailed } from "./errors.js";
18
+ import { safeChildPath } from "./path-safety.js";
19
+ import { makeAbsolutePath } from "@agentxm/extension-model/unstable/path-types";
20
+ import { resolveVersionInRange } from "@agentxm/extension-model/unstable/version-constraints";
21
+ import { toExtensionTypePlural, } from "@agentxm/extension-model/unstable/extensions";
22
+ import { filterMatureVersions, isVersionEntryEligibleAt, releaseAgeEvidence, } from "@agentxm/registry-protocol/unstable/registry/release-age-policy";
23
+ import {} from "@agentxm/extension-model/unstable/extensions/release-age";
24
+ // -----------------------------------------------------------------------------
25
+ // Version Selection
26
+ // -----------------------------------------------------------------------------
27
+ /**
28
+ * Select the best matching version from a list of versions.
29
+ *
30
+ * Returns the maximum non-yanked version, independent of input order.
31
+ */
32
+ export const selectVersion = (versions) => {
33
+ const availableVersions = versions.filter((entry) => entry.yankedAt === undefined);
34
+ return resolveVersionInRange(availableVersions, Option.none());
35
+ };
36
+ export const resolveVersionEntry = (versions, versionRange) => {
37
+ if (Option.isNone(versionRange)) {
38
+ return selectVersion(versions);
39
+ }
40
+ if (semver.valid(versionRange.value) === versionRange.value) {
41
+ return Option.fromUndefinedOr(versions.find((candidate) => candidate.version === versionRange.value));
42
+ }
43
+ const availableVersions = versions.filter((entry) => entry.yankedAt === undefined);
44
+ const resolved = resolveVersionInRange(availableVersions, versionRange);
45
+ if (Option.isNone(resolved)) {
46
+ return Option.none();
47
+ }
48
+ return Option.fromUndefinedOr(availableVersions.find((candidate) => candidate.version === resolved.value.version));
49
+ };
50
+ export const extensionLifecycleWarnings = (index, version) => {
51
+ const warnings = [];
52
+ const extensionRef = `${index.owner}/${toExtensionTypePlural(index.type)}/${index.name}`;
53
+ if (version.yankedAt !== undefined) {
54
+ const context = [version.yankCategory, version.yankNotice].filter((value) => value !== undefined);
55
+ warnings.push(context.length === 0
56
+ ? `${extensionRef}@${version.version} is yanked`
57
+ : `${extensionRef}@${version.version} is yanked: ${context.join(": ")}`);
58
+ }
59
+ return warnings;
60
+ };
61
+ export const resolveVersionEntryWithReleaseAge = (versions, versionRange, minimumReleaseAge) => {
62
+ if (Option.isNone(minimumReleaseAge)) {
63
+ return Effect.succeed(resolveVersionEntry(versions, versionRange));
64
+ }
65
+ return filterMatureVersions(versions, minimumReleaseAge.value).pipe(Effect.map((mature) => resolveVersionEntry(mature, versionRange)));
66
+ };
67
+ /**
68
+ * Resolve one visible Registry index under one caller-supplied release-age
69
+ * evaluation. The supplied timestamp makes a complete operation deterministic.
70
+ * An accepted version that satisfies the requested range is a lower bound for
71
+ * unattended selection, even while that version is itself under age.
72
+ */
73
+ export const resolveVersionEntryForReleaseAge = (versions, versionRange, evaluation, exemption, acceptedVersion) => {
74
+ const otherwiseSelected = resolveVersionEntry(versions, versionRange);
75
+ if (Option.isNone(otherwiseSelected)) {
76
+ return { kind: "version_unsatisfied" };
77
+ }
78
+ const candidate = otherwiseSelected.value;
79
+ const candidateEligible = isVersionEntryEligibleAt(candidate, evaluation);
80
+ if (!candidateEligible && exemption !== undefined) {
81
+ return {
82
+ kind: "exempted",
83
+ version: candidate,
84
+ bypassed: releaseAgeEvidence(candidate, evaluation),
85
+ exemption,
86
+ };
87
+ }
88
+ const eligible = versions.filter((entry) => isVersionEntryEligibleAt(entry, evaluation));
89
+ const eligibleSelection = resolveVersionEntry(eligible, versionRange);
90
+ const accepted = versions.find((entry) => {
91
+ if (entry.version !== acceptedVersion)
92
+ return false;
93
+ if (Option.isNone(versionRange))
94
+ return true;
95
+ return semver.valid(versionRange.value) === versionRange.value
96
+ ? entry.version === versionRange.value
97
+ : semver.satisfies(entry.version, versionRange.value);
98
+ });
99
+ const selected = accepted !== undefined &&
100
+ (Option.isNone(eligibleSelection) ||
101
+ semver.compareBuild(accepted.version, eligibleSelection.value.version) > 0)
102
+ ? Option.some(accepted)
103
+ : eligibleSelection;
104
+ if (Option.isNone(selected)) {
105
+ return {
106
+ kind: "policy_held",
107
+ candidate: releaseAgeEvidence(candidate, evaluation),
108
+ };
109
+ }
110
+ const selectedAcceptedFloor = accepted?.version === selected.value.version && !candidateEligible;
111
+ return {
112
+ kind: "selected",
113
+ version: selected.value,
114
+ ...(candidateEligible ||
115
+ (candidate.version === selected.value.version && !selectedAcceptedFloor)
116
+ ? {}
117
+ : { newerHeld: releaseAgeEvidence(candidate, evaluation) }),
118
+ };
119
+ };
120
+ // -----------------------------------------------------------------------------
121
+ // Type Pluralization
122
+ // -----------------------------------------------------------------------------
123
+ /** Pluralize extension type for directory segments. */
124
+ export const pluralizeType = (type) => toExtensionTypePlural(type);
125
+ // -----------------------------------------------------------------------------
126
+ // Extension Directory
127
+ // -----------------------------------------------------------------------------
128
+ /** Build the path to an extension's directory within a registry. */
129
+ export const extensionDir = (registryRoot, owner, type, name, join) => join(registryRoot, "extensions", owner, pluralizeType(type), name);
130
+ // -----------------------------------------------------------------------------
131
+ // Zip Extraction
132
+ // -----------------------------------------------------------------------------
133
+ /**
134
+ * Extract a zip archive to a target directory.
135
+ * Uses fflate for in-memory decompression (portable across platforms).
136
+ */
137
+ export const extractZip = (archive, targetDir) => Effect.gen(function* () {
138
+ const fs = yield* FileSystem.FileSystem;
139
+ const path = yield* Path.Path;
140
+ // Decompress zip archive in memory
141
+ const entries = yield* Effect.try({
142
+ try: () => unzipSync(archive),
143
+ catch: (e) => new RegistryOperationFailed({
144
+ category: "validation",
145
+ detail: "Failed to decompress zip archive",
146
+ cause: e,
147
+ }),
148
+ });
149
+ // Resolve the target directory once for containment checks.
150
+ const baseDir = makeAbsolutePath(path, targetDir);
151
+ // Write each entry to the target directory
152
+ yield* Effect.forEach(Object.entries(entries), ([name, data]) => Effect.gen(function* () {
153
+ // Reject any entry whose resolved path escapes the target directory
154
+ // (zip slip): `..` traversal or an absolute path.
155
+ const safePath = yield* safeChildPath(baseDir, name);
156
+ if (Option.isNone(safePath)) {
157
+ return yield* new RegistryOperationFailed({
158
+ category: "validation",
159
+ detail: `Refusing to extract entry outside the target directory: ${name}`,
160
+ });
161
+ }
162
+ const fullPath = safePath.value;
163
+ // Directory entries end with '/'
164
+ if (name.endsWith("/")) {
165
+ yield* fs.makeDirectory(fullPath, { recursive: true }).pipe(Effect.mapError((e) => new RegistryOperationFailed({
166
+ category: "network",
167
+ detail: `Failed to create directory: ${name}`,
168
+ cause: e,
169
+ })));
170
+ }
171
+ else {
172
+ // Ensure parent directory exists
173
+ const parentDir = path.dirname(fullPath);
174
+ yield* fs.makeDirectory(parentDir, { recursive: true }).pipe(Effect.mapError((e) => new RegistryOperationFailed({
175
+ category: "network",
176
+ detail: `Failed to create parent directory for: ${name}`,
177
+ cause: e,
178
+ })));
179
+ yield* fs.writeFile(fullPath, data).pipe(Effect.mapError((e) => new RegistryOperationFailed({
180
+ category: "network",
181
+ detail: `Failed to write file: ${name}`,
182
+ cause: e,
183
+ })));
184
+ }
185
+ }), { concurrency: 1 });
186
+ });
187
+ //# sourceMappingURL=utils.js.map
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@agentxm/registry-client",
3
+ "version": "0.28.4-bootstrap.0",
4
+ "description": "AXM registry integration: local and remote registry clients over the generated OpenAPI transport, request policy and retries, typed registry failures, archive cache, and lifecycle administration for the axm CLI. Unstable and unsupported — use the axm.sh CLI.",
5
+ "type": "module",
6
+ "license": "FSL-1.1-MIT",
7
+ "homepage": "https://axm.sh",
8
+ "bugs": {
9
+ "url": "https://github.com/agentxm/axm/issues"
10
+ },
11
+ "author": "AgentXM <hello@agentxm.ai> (https://agentxm.ai)",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/agentxm/axm.git",
15
+ "directory": "packages/registry-client"
16
+ },
17
+ "sideEffects": false,
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/src/index.d.ts",
21
+ "default": "./dist/src/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist/src/",
26
+ "!**/*.map"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "engines": {
32
+ "node": ">=22.19.0"
33
+ },
34
+ "nx": {
35
+ "includedScripts": []
36
+ },
37
+ "dependencies": {
38
+ "effect": "4.0.0-rc.112",
39
+ "fflate": "^0.8.3",
40
+ "semver": "^7.8.5",
41
+ "@agentxm/extension-model": "^0.28.4-bootstrap.0",
42
+ "@agentxm/registry-protocol": "^0.28.4-bootstrap.0"
43
+ },
44
+ "devDependencies": {
45
+ "@effect/openapi-generator": "4.0.0-rc.112",
46
+ "@effect/platform-node": "4.0.0-rc.112",
47
+ "@effect/vitest": "4.0.0-rc.112",
48
+ "@types/bun": "^1.3.14",
49
+ "@types/semver": "^7.5.8",
50
+ "@typescript/native": "npm:typescript@^7.0.2",
51
+ "swagger2openapi": "^7.0.8",
52
+ "typescript": "npm:@typescript/typescript6@^6.0.2",
53
+ "vitest": "^4.1.10"
54
+ }
55
+ }