@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.
- package/LICENSE +110 -0
- package/README.md +9 -0
- package/dist/src/__generated__/registry-client.d.ts +6501 -0
- package/dist/src/__generated__/registry-client.js +2270 -0
- package/dist/src/admin-client.d.ts +181 -0
- package/dist/src/admin-client.js +165 -0
- package/dist/src/archive-cache.d.ts +46 -0
- package/dist/src/archive-cache.js +179 -0
- package/dist/src/atomic-write.d.ts +49 -0
- package/dist/src/atomic-write.js +60 -0
- package/dist/src/axm-package-meta.d.ts +31 -0
- package/dist/src/axm-package-meta.js +31 -0
- package/dist/src/cache-root.d.ts +11 -0
- package/dist/src/cache-root.js +43 -0
- package/dist/src/client.d.ts +270 -0
- package/dist/src/client.js +43 -0
- package/dist/src/deprecation-warning.d.ts +3 -0
- package/dist/src/deprecation-warning.js +16 -0
- package/dist/src/error-mapping.d.ts +82 -0
- package/dist/src/error-mapping.js +186 -0
- package/dist/src/errors.d.ts +107 -0
- package/dist/src/errors.js +98 -0
- package/dist/src/failure-mapping.d.ts +14 -0
- package/dist/src/failure-mapping.js +100 -0
- package/dist/src/fs-helpers.d.ts +12 -0
- package/dist/src/fs-helpers.js +13 -0
- package/dist/src/index.d.ts +33 -0
- package/dist/src/index.js +37 -0
- package/dist/src/integrity.d.ts +13 -0
- package/dist/src/integrity.js +17 -0
- package/dist/src/local-client.d.ts +24 -0
- package/dist/src/local-client.js +815 -0
- package/dist/src/network.d.ts +6 -0
- package/dist/src/network.js +6 -0
- package/dist/src/path-safety.d.ts +18 -0
- package/dist/src/path-safety.js +26 -0
- package/dist/src/purl-match.d.ts +28 -0
- package/dist/src/purl-match.js +35 -0
- package/dist/src/registry-url.d.ts +14 -0
- package/dist/src/registry-url.js +12 -0
- package/dist/src/remote-client.d.ts +27 -0
- package/dist/src/remote-client.js +725 -0
- package/dist/src/request-policy.d.ts +29 -0
- package/dist/src/request-policy.js +190 -0
- package/dist/src/response-body.d.ts +11 -0
- package/dist/src/response-body.js +32 -0
- package/dist/src/retry-after.d.ts +9 -0
- package/dist/src/retry-after.js +28 -0
- package/dist/src/translate.d.ts +20 -0
- package/dist/src/translate.js +170 -0
- package/dist/src/utils.d.ts +60 -0
- package/dist/src/utils.js +187 -0
- 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
|
+
}
|