@opys/core 0.1.2
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/README.md +121 -0
- package/dist/index.cjs +413 -0
- package/dist/index.d.cts +256 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +256 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +351 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# @opys/core
|
|
2
|
+
|
|
3
|
+
Data model for Opys manifests. Types, factory functions, Zod parsers, and encode/decode utilities. No I/O.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @opys/core @opys/rules zod
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Types
|
|
12
|
+
|
|
13
|
+
### `Source` — artifact origin
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
type Source =
|
|
17
|
+
| { kind: 'url'; url: string }
|
|
18
|
+
| { kind: 'file'; file: string }
|
|
19
|
+
| { kind: 'string'; string: string }
|
|
20
|
+
| { kind: 'empty' };
|
|
21
|
+
|
|
22
|
+
// Factory functions
|
|
23
|
+
sourceUrl('https://example.com/file.jar');
|
|
24
|
+
sourceFile('./local/file.jar');
|
|
25
|
+
sourceString('inline content');
|
|
26
|
+
sourceEmpty();
|
|
27
|
+
|
|
28
|
+
// Parse / encode
|
|
29
|
+
SourceSchema.parse(raw);
|
|
30
|
+
encodeSource(source);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### `ExtractRule` — zip extraction instructions
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
type ExtractRule =
|
|
37
|
+
| { kind: 'pick'; file: string; into: string } // single file
|
|
38
|
+
| { kind: 'scan'; matches: string; into: string; ... } // glob match
|
|
39
|
+
| { kind: 'dump'; into: string; clean?: boolean; ... } // full extract
|
|
40
|
+
|
|
41
|
+
// Factory functions
|
|
42
|
+
extractPick('lwjgl.dll', '${natives_directory}')
|
|
43
|
+
extractScan('*.so', '${natives_directory}', { excludes: ['META-INF/'] })
|
|
44
|
+
extractDump('${natives_directory}', { clean: true, excludes: ['META-INF/'] })
|
|
45
|
+
|
|
46
|
+
// Parse / encode
|
|
47
|
+
ExtractSchema.parse(raw) // always returns ExtractRule[]
|
|
48
|
+
encodeExtract(rules)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### `Artifact` — a single installable artifact
|
|
52
|
+
|
|
53
|
+
An artifact has a source, optional integrity/size checks, optional extract rules, and optional rulesets that gate it per platform or feature.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { ArtifactSchema, encodeArtifact } from '@opys/core';
|
|
57
|
+
|
|
58
|
+
const artifact = ArtifactSchema.parse(raw);
|
|
59
|
+
encodeArtifact(artifact);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### `Manifest` — the manifest
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
interface Manifest {
|
|
66
|
+
vars: ValDefs;
|
|
67
|
+
launch?: Launch;
|
|
68
|
+
artifacts: ReadonlyArray<Artifact>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Parse JSON string
|
|
72
|
+
const manifest = await parseManifest(jsonString);
|
|
73
|
+
|
|
74
|
+
// Filter to current platform
|
|
75
|
+
const filtered = filterManifest(manifest, { name: 'linux', arch: 'x64' });
|
|
76
|
+
|
|
77
|
+
// Encode back to JSON-serializable object
|
|
78
|
+
encodeManifest(manifest);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### `ValDefs` — interpolation variables
|
|
82
|
+
|
|
83
|
+
Variables support OS-conditional values and `${ref}` interpolation.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import {
|
|
87
|
+
parseValDefs,
|
|
88
|
+
encodeValDefs,
|
|
89
|
+
resolveValDefs,
|
|
90
|
+
resolveVars,
|
|
91
|
+
} from '@opys/core';
|
|
92
|
+
|
|
93
|
+
const defs = parseValDefs(raw);
|
|
94
|
+
const flat = resolveValDefs(defs, platform); // pick OS-appropriate values
|
|
95
|
+
const vars = resolveVars(flat); // resolve ${ref} chains
|
|
96
|
+
const result = interpolate('${root}/assets', vars);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### `defineConfig` — config file helper
|
|
100
|
+
|
|
101
|
+
Used as the default export in `opys.config.mjs`:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { defineConfig } from '@opys/core';
|
|
105
|
+
|
|
106
|
+
export default defineConfig({
|
|
107
|
+
output: 'opys.json',
|
|
108
|
+
manifest: {
|
|
109
|
+
artifacts: [...],
|
|
110
|
+
vars: [...],
|
|
111
|
+
launch: { ... },
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Or as a function for context-aware configs
|
|
116
|
+
export default defineConfig((ctx) => ({
|
|
117
|
+
manifest: {
|
|
118
|
+
artifacts: ctx.mode === 'build' ? [...] : [],
|
|
119
|
+
},
|
|
120
|
+
}));
|
|
121
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
let zod = require("zod");
|
|
30
|
+
let _opys_core_binding = require("@opys/core-binding");
|
|
31
|
+
_opys_core_binding = __toESM(_opys_core_binding);
|
|
32
|
+
|
|
33
|
+
//#region lib/fetch.ts
|
|
34
|
+
/**
|
|
35
|
+
* Wrap `fetch()` with bounded retry on transient network failures and
|
|
36
|
+
* 5xx-class responses. Errors that won't recover from a retry (4xx,
|
|
37
|
+
* `AbortError`, JSON parse failures downstream of the response) are
|
|
38
|
+
* surfaced unchanged so callers handle them with their own logic.
|
|
39
|
+
*
|
|
40
|
+
* Network-level retries cover the AggregateError ETIMEDOUT / ECONNRESET
|
|
41
|
+
* / ENOTFOUND / EAI_AGAIN / ECONNREFUSED cases that node:undici reports
|
|
42
|
+
* as `TypeError: fetch failed` with a populated `cause`. Without this
|
|
43
|
+
* one DNS hiccup mid-`opys launch` aborts the whole config evaluation.
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* Default `User-Agent` for every opys HTTP request. The bare `undici`
|
|
47
|
+
* agent gets rejected or rate-limited by some CDNs and by the CurseForge
|
|
48
|
+
* API, so we identify ourselves. The patch component is omitted so the
|
|
49
|
+
* string doesn't churn against `package.json` on every release.
|
|
50
|
+
*/
|
|
51
|
+
const OPYS_USER_AGENT = "opys/1.0";
|
|
52
|
+
const DEFAULT_RETRY_STATUSES = new Set([
|
|
53
|
+
408,
|
|
54
|
+
425,
|
|
55
|
+
429,
|
|
56
|
+
500,
|
|
57
|
+
502,
|
|
58
|
+
503,
|
|
59
|
+
504
|
|
60
|
+
]);
|
|
61
|
+
const TRANSIENT_CODES = new Set([
|
|
62
|
+
"ETIMEDOUT",
|
|
63
|
+
"ECONNRESET",
|
|
64
|
+
"ECONNREFUSED",
|
|
65
|
+
"ENOTFOUND",
|
|
66
|
+
"EAI_AGAIN",
|
|
67
|
+
"EPIPE",
|
|
68
|
+
"UND_ERR_SOCKET",
|
|
69
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
70
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
71
|
+
"UND_ERR_BODY_TIMEOUT"
|
|
72
|
+
]);
|
|
73
|
+
function isTransientFetchError(err) {
|
|
74
|
+
if (!err || typeof err !== "object") return false;
|
|
75
|
+
const cause = err.cause;
|
|
76
|
+
if (cause) {
|
|
77
|
+
const code = cause.code;
|
|
78
|
+
if (code && TRANSIENT_CODES.has(code)) return true;
|
|
79
|
+
const inner = cause.errors;
|
|
80
|
+
if (Array.isArray(inner) && inner.length > 0) return inner.every((e) => {
|
|
81
|
+
const c = e?.code;
|
|
82
|
+
return c !== void 0 && TRANSIENT_CODES.has(c);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const code = err.code;
|
|
86
|
+
if (code && TRANSIENT_CODES.has(code)) return true;
|
|
87
|
+
return err instanceof TypeError && typeof err.message === "string" && err.message.toLowerCase().includes("fetch failed");
|
|
88
|
+
}
|
|
89
|
+
function backoffMs(attempt, base, max) {
|
|
90
|
+
const exp = base * 2 ** (attempt - 1);
|
|
91
|
+
const capped = Math.min(exp, max);
|
|
92
|
+
return Math.floor(capped * (.5 + Math.random() * .5));
|
|
93
|
+
}
|
|
94
|
+
function sleep(ms, signal) {
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
if (signal?.aborted) {
|
|
97
|
+
reject(signal.reason ?? /* @__PURE__ */ new Error("aborted"));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const t = setTimeout(() => {
|
|
101
|
+
signal?.removeEventListener("abort", onAbort);
|
|
102
|
+
resolve();
|
|
103
|
+
}, ms);
|
|
104
|
+
const onAbort = () => {
|
|
105
|
+
clearTimeout(t);
|
|
106
|
+
reject(signal?.reason ?? /* @__PURE__ */ new Error("aborted"));
|
|
107
|
+
};
|
|
108
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async function fetchWithRetry(input, init = {}, retry = {}) {
|
|
112
|
+
const attempts = Math.max(1, retry.attempts ?? 4);
|
|
113
|
+
const base = retry.baseDelayMs ?? 250;
|
|
114
|
+
const max = retry.maxDelayMs ?? 5e3;
|
|
115
|
+
const retryStatuses = retry.retryStatuses instanceof Set ? retry.retryStatuses : retry.retryStatuses ? new Set(retry.retryStatuses) : DEFAULT_RETRY_STATUSES;
|
|
116
|
+
const signal = retry.signal ?? init.signal ?? void 0;
|
|
117
|
+
const headers = new Headers(init.headers);
|
|
118
|
+
if (!headers.has("user-agent")) headers.set("user-agent", OPYS_USER_AGENT);
|
|
119
|
+
let lastErr;
|
|
120
|
+
for (let attempt = 1; attempt <= attempts; attempt++) try {
|
|
121
|
+
const res = await fetch(input, {
|
|
122
|
+
...init,
|
|
123
|
+
headers,
|
|
124
|
+
signal
|
|
125
|
+
});
|
|
126
|
+
if (res.ok || attempt === attempts || !retryStatuses.has(res.status)) return res;
|
|
127
|
+
try {
|
|
128
|
+
await res.body?.cancel();
|
|
129
|
+
} catch {}
|
|
130
|
+
const delay = backoffMs(attempt, base, max);
|
|
131
|
+
retry.onRetry?.({
|
|
132
|
+
attempt,
|
|
133
|
+
delayMs: delay,
|
|
134
|
+
status: res.status
|
|
135
|
+
});
|
|
136
|
+
await sleep(delay, signal);
|
|
137
|
+
} catch (err) {
|
|
138
|
+
lastErr = err;
|
|
139
|
+
if (signal?.aborted) throw err;
|
|
140
|
+
if (!isTransientFetchError(err) || attempt === attempts) throw err;
|
|
141
|
+
const delay = backoffMs(attempt, base, max);
|
|
142
|
+
retry.onRetry?.({
|
|
143
|
+
attempt,
|
|
144
|
+
delayMs: delay,
|
|
145
|
+
error: err
|
|
146
|
+
});
|
|
147
|
+
await sleep(delay, signal);
|
|
148
|
+
}
|
|
149
|
+
throw lastErr;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region lib/index.ts
|
|
154
|
+
/**
|
|
155
|
+
* `@opys/core` — the frozen-manifest contract. Behaviors are backed by the
|
|
156
|
+
* Rust `opys-core` crate (via napi-rs); domain types, factories and small
|
|
157
|
+
* sugar helpers are hand-written TS.
|
|
158
|
+
*
|
|
159
|
+
* Strategy:
|
|
160
|
+
* - Algorithms that touch the manifest contract (decode, encode, resolve,
|
|
161
|
+
* filter, interpolate, glob) → typed wrappers around the Rust binding.
|
|
162
|
+
* - Domain types → hand-typed here, matching the frozen wire shape. These
|
|
163
|
+
* are pure data shapes; consumers construct them as plain JS objects.
|
|
164
|
+
* - Factories / type guards / small dedup helpers → pure TS, no boundary
|
|
165
|
+
* crossing. They are sugar over the typed shapes.
|
|
166
|
+
* - `parseShortRuleset` is implemented in TS as the shorthand sugar — the
|
|
167
|
+
* Rust binding accepts shorthand directly via `satisfiesRuleset` so the
|
|
168
|
+
* TS impl exists for consumers that need expanded `Rule` objects.
|
|
169
|
+
*/
|
|
170
|
+
const OsNameSchema = zod.z.enum([
|
|
171
|
+
"linux",
|
|
172
|
+
"windows",
|
|
173
|
+
"osx"
|
|
174
|
+
]);
|
|
175
|
+
const OsArchSchema = zod.z.enum([
|
|
176
|
+
"x86",
|
|
177
|
+
"x86_64",
|
|
178
|
+
"arm",
|
|
179
|
+
"aarch64",
|
|
180
|
+
"any"
|
|
181
|
+
]);
|
|
182
|
+
const OsConstraintSchema = zod.z.object({
|
|
183
|
+
name: OsNameSchema.optional(),
|
|
184
|
+
version: zod.z.string().optional(),
|
|
185
|
+
arch: OsArchSchema.optional()
|
|
186
|
+
});
|
|
187
|
+
const RuleActionSchema = zod.z.enum(["allow", "disallow"]);
|
|
188
|
+
const RuleSchema = zod.z.union([
|
|
189
|
+
zod.z.object({
|
|
190
|
+
action: RuleActionSchema,
|
|
191
|
+
os: OsConstraintSchema
|
|
192
|
+
}),
|
|
193
|
+
zod.z.object({
|
|
194
|
+
action: RuleActionSchema,
|
|
195
|
+
features: zod.z.record(zod.z.string(), zod.z.boolean())
|
|
196
|
+
}),
|
|
197
|
+
zod.z.object({ action: RuleActionSchema })
|
|
198
|
+
]);
|
|
199
|
+
function decodeManifest(wire) {
|
|
200
|
+
return _opys_core_binding.decodeManifest(wire);
|
|
201
|
+
}
|
|
202
|
+
function encodeManifest(domain) {
|
|
203
|
+
return _opys_core_binding.encodeManifest(domain);
|
|
204
|
+
}
|
|
205
|
+
function parseManifest(input) {
|
|
206
|
+
return _opys_core_binding.parseManifest(input);
|
|
207
|
+
}
|
|
208
|
+
function filterManifest(manifest, platform, features = []) {
|
|
209
|
+
return _opys_core_binding.filterManifest(manifest, platform, features);
|
|
210
|
+
}
|
|
211
|
+
function resolveVars(vars) {
|
|
212
|
+
return _opys_core_binding.resolveVars(vars);
|
|
213
|
+
}
|
|
214
|
+
function interpolate(template, vars) {
|
|
215
|
+
return _opys_core_binding.interpolate(template, vars);
|
|
216
|
+
}
|
|
217
|
+
function resolvedArgs(launch, platform, features = []) {
|
|
218
|
+
return _opys_core_binding.resolvedArgs(launch, platform, features);
|
|
219
|
+
}
|
|
220
|
+
function resolvedEnvs(launch, platform, features = []) {
|
|
221
|
+
return _opys_core_binding.resolvedEnvs(launch, platform, features);
|
|
222
|
+
}
|
|
223
|
+
function satisfiesRuleset(rules, platform, features = []) {
|
|
224
|
+
return _opys_core_binding.satisfiesRuleset(rules, platform, features);
|
|
225
|
+
}
|
|
226
|
+
function globBase(glob) {
|
|
227
|
+
return _opys_core_binding.globBase(glob);
|
|
228
|
+
}
|
|
229
|
+
function globToRegexSource(glob) {
|
|
230
|
+
return _opys_core_binding.globToRegexSource(glob);
|
|
231
|
+
}
|
|
232
|
+
/** Compile a glob to a real `RegExp` (the binding returns the source string). */
|
|
233
|
+
function globToRegex(glob) {
|
|
234
|
+
return new RegExp(_opys_core_binding.globToRegexSource(glob));
|
|
235
|
+
}
|
|
236
|
+
const sourceUrl = (url) => ({
|
|
237
|
+
kind: "url",
|
|
238
|
+
url
|
|
239
|
+
});
|
|
240
|
+
const sourceFile = (file) => ({
|
|
241
|
+
kind: "file",
|
|
242
|
+
file
|
|
243
|
+
});
|
|
244
|
+
const sourceString = (string) => ({
|
|
245
|
+
kind: "string",
|
|
246
|
+
string
|
|
247
|
+
});
|
|
248
|
+
const sourcePointer = (pointer) => ({
|
|
249
|
+
kind: "pointer",
|
|
250
|
+
pointer
|
|
251
|
+
});
|
|
252
|
+
const sourceBytes = (bytes) => ({
|
|
253
|
+
kind: "bytes",
|
|
254
|
+
bytes: Buffer.from(bytes).toString("base64")
|
|
255
|
+
});
|
|
256
|
+
const isSourceUrl = (s) => s.kind === "url";
|
|
257
|
+
const isSourceFile = (s) => s.kind === "file";
|
|
258
|
+
const isSourceString = (s) => s.kind === "string";
|
|
259
|
+
const isSourceBytes = (s) => s.kind === "bytes";
|
|
260
|
+
const isSourcePointer = (s) => s.kind === "pointer";
|
|
261
|
+
const extractPick = (file, into) => ({
|
|
262
|
+
kind: "pick",
|
|
263
|
+
file,
|
|
264
|
+
into
|
|
265
|
+
});
|
|
266
|
+
const extractScan = (matches, into, opts) => ({
|
|
267
|
+
kind: "scan",
|
|
268
|
+
matches,
|
|
269
|
+
into,
|
|
270
|
+
...opts
|
|
271
|
+
});
|
|
272
|
+
const extractDump = (into, opts) => ({
|
|
273
|
+
kind: "dump",
|
|
274
|
+
into,
|
|
275
|
+
...opts
|
|
276
|
+
});
|
|
277
|
+
const emptyRuleset = () => [];
|
|
278
|
+
const allowOsRuleset = (name) => [{
|
|
279
|
+
action: "allow",
|
|
280
|
+
os: { name }
|
|
281
|
+
}];
|
|
282
|
+
/** Deduplicate by normalized (posix) path; later entries win. */
|
|
283
|
+
function deduplicateArtifacts(artifacts) {
|
|
284
|
+
const norm = (p) => {
|
|
285
|
+
const parts = p.split("/");
|
|
286
|
+
const stack = [];
|
|
287
|
+
const lead = p.startsWith("/");
|
|
288
|
+
for (const seg of parts) {
|
|
289
|
+
if (seg === "" || seg === ".") continue;
|
|
290
|
+
if (seg === "..") {
|
|
291
|
+
if (stack.length > 0 && stack[stack.length - 1] !== "..") stack.pop();
|
|
292
|
+
else if (!lead) stack.push("..");
|
|
293
|
+
} else stack.push(seg);
|
|
294
|
+
}
|
|
295
|
+
const joined = stack.join("/");
|
|
296
|
+
if (lead) return "/" + joined;
|
|
297
|
+
return joined === "" ? "." : joined;
|
|
298
|
+
};
|
|
299
|
+
const map = /* @__PURE__ */ new Map();
|
|
300
|
+
for (const u of artifacts) map.set(norm(u.path), u);
|
|
301
|
+
return [...map.values()];
|
|
302
|
+
}
|
|
303
|
+
function parseShortRule(raw) {
|
|
304
|
+
if (typeof raw !== "string") return raw;
|
|
305
|
+
const parts = raw.split(".");
|
|
306
|
+
const action = parts[0];
|
|
307
|
+
if (action !== "allow" && action !== "disallow") throw new Error(`Unknown action '${action}'`);
|
|
308
|
+
const type = parts[1];
|
|
309
|
+
if (!type) return { action };
|
|
310
|
+
const rest = parts.slice(2).join(".");
|
|
311
|
+
switch (type) {
|
|
312
|
+
case "os": {
|
|
313
|
+
if (!rest) throw new Error("missing OS name");
|
|
314
|
+
const atIdx = rest.indexOf("@");
|
|
315
|
+
const name = atIdx === -1 ? rest : rest.slice(0, atIdx);
|
|
316
|
+
if (![
|
|
317
|
+
"linux",
|
|
318
|
+
"windows",
|
|
319
|
+
"osx"
|
|
320
|
+
].includes(name)) throw new Error(`invalid os name '${name}'`);
|
|
321
|
+
const version = atIdx === -1 ? void 0 : rest.slice(atIdx + 1);
|
|
322
|
+
return version ? {
|
|
323
|
+
action,
|
|
324
|
+
os: {
|
|
325
|
+
name,
|
|
326
|
+
version
|
|
327
|
+
}
|
|
328
|
+
} : {
|
|
329
|
+
action,
|
|
330
|
+
os: { name }
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
case "features":
|
|
334
|
+
if (!rest) throw new Error("missing feature name");
|
|
335
|
+
return {
|
|
336
|
+
action,
|
|
337
|
+
features: { [rest]: true }
|
|
338
|
+
};
|
|
339
|
+
case "arch": {
|
|
340
|
+
if (!rest) throw new Error("missing arch");
|
|
341
|
+
const arch = rest;
|
|
342
|
+
if (![
|
|
343
|
+
"x86",
|
|
344
|
+
"x86_64",
|
|
345
|
+
"arm",
|
|
346
|
+
"aarch64",
|
|
347
|
+
"any"
|
|
348
|
+
].includes(arch)) throw new Error(`invalid arch '${arch}'`);
|
|
349
|
+
return {
|
|
350
|
+
action,
|
|
351
|
+
os: { arch }
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
default: throw new Error(`unknown rule type '${type}'`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function parseShortRuleset(raw) {
|
|
358
|
+
return (Array.isArray(raw) ? raw : [raw]).map(parseShortRule);
|
|
359
|
+
}
|
|
360
|
+
function parseValset(raw) {
|
|
361
|
+
if (!Array.isArray(raw)) throw new Error("parseValset: expected an array");
|
|
362
|
+
return raw.map((entry) => {
|
|
363
|
+
if (typeof entry === "string") return {
|
|
364
|
+
rules: [],
|
|
365
|
+
value: [entry]
|
|
366
|
+
};
|
|
367
|
+
if (entry && typeof entry === "object") {
|
|
368
|
+
const obj = entry;
|
|
369
|
+
return {
|
|
370
|
+
rules: obj.rules ? parseShortRuleset(obj.rules) : [],
|
|
371
|
+
value: Array.isArray(obj.value) ? obj.value : [obj.value]
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
throw new Error("parseValset: invalid entry");
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
//#endregion
|
|
379
|
+
exports.OPYS_USER_AGENT = OPYS_USER_AGENT;
|
|
380
|
+
exports.OsArchSchema = OsArchSchema;
|
|
381
|
+
exports.OsNameSchema = OsNameSchema;
|
|
382
|
+
exports.RuleSchema = RuleSchema;
|
|
383
|
+
exports.allowOsRuleset = allowOsRuleset;
|
|
384
|
+
exports.decodeManifest = decodeManifest;
|
|
385
|
+
exports.deduplicateArtifacts = deduplicateArtifacts;
|
|
386
|
+
exports.emptyRuleset = emptyRuleset;
|
|
387
|
+
exports.encodeManifest = encodeManifest;
|
|
388
|
+
exports.extractDump = extractDump;
|
|
389
|
+
exports.extractPick = extractPick;
|
|
390
|
+
exports.extractScan = extractScan;
|
|
391
|
+
exports.fetchWithRetry = fetchWithRetry;
|
|
392
|
+
exports.filterManifest = filterManifest;
|
|
393
|
+
exports.globBase = globBase;
|
|
394
|
+
exports.globToRegex = globToRegex;
|
|
395
|
+
exports.globToRegexSource = globToRegexSource;
|
|
396
|
+
exports.interpolate = interpolate;
|
|
397
|
+
exports.isSourceBytes = isSourceBytes;
|
|
398
|
+
exports.isSourceFile = isSourceFile;
|
|
399
|
+
exports.isSourcePointer = isSourcePointer;
|
|
400
|
+
exports.isSourceString = isSourceString;
|
|
401
|
+
exports.isSourceUrl = isSourceUrl;
|
|
402
|
+
exports.parseManifest = parseManifest;
|
|
403
|
+
exports.parseShortRuleset = parseShortRuleset;
|
|
404
|
+
exports.parseValset = parseValset;
|
|
405
|
+
exports.resolveVars = resolveVars;
|
|
406
|
+
exports.resolvedArgs = resolvedArgs;
|
|
407
|
+
exports.resolvedEnvs = resolvedEnvs;
|
|
408
|
+
exports.satisfiesRuleset = satisfiesRuleset;
|
|
409
|
+
exports.sourceBytes = sourceBytes;
|
|
410
|
+
exports.sourceFile = sourceFile;
|
|
411
|
+
exports.sourcePointer = sourcePointer;
|
|
412
|
+
exports.sourceString = sourceString;
|
|
413
|
+
exports.sourceUrl = sourceUrl;
|