@opys/dev 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/dist/index.cjs +359 -0
- package/dist/index.d.cts +312 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +312 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +346 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +38 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { Artifact, Discovery, ExtractRule, Launch, Manifest, Ruleset, Val, ValDefs, Valset, parseShortRuleset } from "@opys/core";
|
|
2
|
+
|
|
3
|
+
//#region lib/plugin.d.ts
|
|
4
|
+
/** Build-time context handed to every plugin's `build` hook. */
|
|
5
|
+
interface BuildContext {
|
|
6
|
+
/** Sanctioned build-time logging channel; auto-prefixed by plugin name. */
|
|
7
|
+
log: (scope: string, message: string) => void;
|
|
8
|
+
/** Absolute directory of `opys.config.mjs` — anchor for relative paths. */
|
|
9
|
+
configDir: string;
|
|
10
|
+
/** Value of `opys build --mode <m>`; empty string when unset. */
|
|
11
|
+
mode: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Named launch fragments a plugin exposes for the config's `command`/`args`
|
|
15
|
+
* accessor functions — e.g. `{ jvmArgs, mainClass, gameArgs }` or `{ bin }`.
|
|
16
|
+
*/
|
|
17
|
+
type LaunchGroups = Record<string, Valset | Val | string>;
|
|
18
|
+
/** What a plugin's `build` hook returns. */
|
|
19
|
+
interface Contribution {
|
|
20
|
+
/** Artifacts to download/copy/extract. */
|
|
21
|
+
artifacts?: Artifact[];
|
|
22
|
+
/** Manifest vars this plugin owns. */
|
|
23
|
+
vars?: ValDefs;
|
|
24
|
+
/** Named launch fragments, exposed to the config's accessor functions. */
|
|
25
|
+
launch?: LaunchGroups;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A opys plugin — a pure-to-construct, bundler-style hook object. The
|
|
29
|
+
* constructor (`forge('1.20.1-best')`, …) does zero I/O; all network/fs work
|
|
30
|
+
* happens inside `build`, which the engine drives.
|
|
31
|
+
*/
|
|
32
|
+
interface OpysPlugin {
|
|
33
|
+
name: string;
|
|
34
|
+
build(ctx: BuildContext): Promise<Contribution> | Contribution;
|
|
35
|
+
}
|
|
36
|
+
/** Identity helper for authoring a plugin with inferred types. */
|
|
37
|
+
declare function definePlugin(plugin: OpysPlugin): OpysPlugin;
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region lib/config.d.ts
|
|
40
|
+
/** Map of plugin name → its launch groups, passed to launch accessors. */
|
|
41
|
+
type PluginMap = Record<string, LaunchGroups>;
|
|
42
|
+
/** One entry of a config's assembled `args` — flattened to a `Valset`. */
|
|
43
|
+
type ArgItem = Valset | Val | string;
|
|
44
|
+
interface OpysManifestConfig {
|
|
45
|
+
/** Hand-written literal artifacts, merged with plugin output (last wins). */
|
|
46
|
+
artifacts?: Artifact[];
|
|
47
|
+
/** Override/extra vars layered on top of the merged plugin vars. */
|
|
48
|
+
vars?: ValDefs;
|
|
49
|
+
/** Launch command — typically `({ java }) => java.bin`. */
|
|
50
|
+
command: (plugins: PluginMap) => string;
|
|
51
|
+
/** Launch args — author-ordered named groups, flattened to a `Valset`. */
|
|
52
|
+
args: (plugins: PluginMap) => ArgItem[];
|
|
53
|
+
/** Working directory for the launched process. */
|
|
54
|
+
workdir?: string | ((plugins: PluginMap) => string);
|
|
55
|
+
/** Environment variables for the launched process. */
|
|
56
|
+
envs?: ValDefs | ((plugins: PluginMap) => ValDefs);
|
|
57
|
+
/** `restrict` globs swept clean after install. */
|
|
58
|
+
restrict?: string[];
|
|
59
|
+
}
|
|
60
|
+
interface OpysConfig {
|
|
61
|
+
/** Default manifest output path, relative to the config file. */
|
|
62
|
+
output?: string;
|
|
63
|
+
/** The plugins whose `build` hooks produce the manifest. */
|
|
64
|
+
plugins: OpysPlugin[];
|
|
65
|
+
/** Declarative manifest fields, separate from tooling config. */
|
|
66
|
+
manifest: OpysManifestConfig;
|
|
67
|
+
/**
|
|
68
|
+
* Launch-time manifest patch. Re-run on every `opys launch`; the returned
|
|
69
|
+
* partial is shallow-merged (per field) over the loaded manifest.
|
|
70
|
+
*/
|
|
71
|
+
runClient?: (manifest: Manifest) => Partial<Manifest>;
|
|
72
|
+
}
|
|
73
|
+
interface OpysConfigContext {
|
|
74
|
+
/** Value of `opys build --mode <m>`; empty string when unset. */
|
|
75
|
+
mode: string;
|
|
76
|
+
}
|
|
77
|
+
type OpysConfigInput = OpysConfig | ((ctx: OpysConfigContext) => OpysConfig | Promise<OpysConfig>);
|
|
78
|
+
/** Use as the default export of `opys.config.mjs`. */
|
|
79
|
+
declare function defineConfig(input: OpysConfigInput): OpysConfigInput;
|
|
80
|
+
/** Resolve a config input to a concrete `OpysConfig`. */
|
|
81
|
+
declare function resolveConfig(input: OpysConfigInput, ctx: OpysConfigContext): Promise<OpysConfig>;
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region lib/engine.d.ts
|
|
84
|
+
/**
|
|
85
|
+
* Run every plugin's `build` hook in parallel, merge the contributions, and
|
|
86
|
+
* assemble the final `Manifest`.
|
|
87
|
+
*/
|
|
88
|
+
declare function buildManifest(config: OpysConfig, ctx: BuildContext): Promise<Manifest>;
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region lib/overrides.d.ts
|
|
91
|
+
/**
|
|
92
|
+
* Targets a subset of artifacts:
|
|
93
|
+
*
|
|
94
|
+
* - `string` / `string[]` — glob(s) matched against `artifact.path`
|
|
95
|
+
* (multiple = OR).
|
|
96
|
+
* - predicate — `(a) => boolean`, the escape hatch for matching on source
|
|
97
|
+
* kind, size, metadata, …
|
|
98
|
+
*/
|
|
99
|
+
type Selector = string | string[] | ((artifact: Artifact) => boolean);
|
|
100
|
+
declare function matchesSelector(selector: Selector, artifact: Artifact): boolean;
|
|
101
|
+
/** A ruleset in any form `parseShortRuleset` accepts (shorthand or full). */
|
|
102
|
+
type RulesetInput = Parameters<typeof parseShortRuleset>[0];
|
|
103
|
+
/**
|
|
104
|
+
* A per-selector patch over the artifacts a plugin produces. Each entry
|
|
105
|
+
* names the files it `match`es and the changes to apply — drop them,
|
|
106
|
+
* attach a ruleset, or clear integrity. Overrides run in list order; a
|
|
107
|
+
* later entry sees the effect of an earlier one.
|
|
108
|
+
*/
|
|
109
|
+
interface ArtifactOverride {
|
|
110
|
+
/** Files this override applies to. */
|
|
111
|
+
match: Selector;
|
|
112
|
+
/** Drop matched artifacts entirely. */
|
|
113
|
+
exclude?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Ruleset to attach to matched artifacts — shorthand (`'allow.os.osx'`)
|
|
116
|
+
* or a full `Ruleset`. Appended to each artifact's existing `rules`.
|
|
117
|
+
*/
|
|
118
|
+
rules?: RulesetInput;
|
|
119
|
+
/** `null` clears `integrity` + `discovery` (skip verification). */
|
|
120
|
+
integrity?: null;
|
|
121
|
+
}
|
|
122
|
+
/** Apply an ordered list of {@link ArtifactOverride}s to a list of artifacts. */
|
|
123
|
+
declare function applyOverrides(artifacts: readonly Artifact[], overrides: readonly ArtifactOverride[]): Artifact[];
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region lib/artifact-plugin.d.ts
|
|
126
|
+
/**
|
|
127
|
+
* Wraps a {@link OpysPlugin} so that the artifacts it contributes are passed
|
|
128
|
+
* through an ordered list of {@link ArtifactOverride}s before being returned.
|
|
129
|
+
*
|
|
130
|
+
* Use this to give artifact-producing plugins (`forge`, `curseforge`, …) the
|
|
131
|
+
* same filter/patch support that `artifactScanner` already has natively. The
|
|
132
|
+
* inner plugin's `build` runs unchanged; only `Contribution.artifacts` is
|
|
133
|
+
* rewritten. Non-artifact contribution fields (`vars`, `launch`) pass through
|
|
134
|
+
* untouched.
|
|
135
|
+
*
|
|
136
|
+
* @param plugin The inner plugin to wrap.
|
|
137
|
+
* @param overrides Overrides applied to the inner plugin's artifacts. An empty
|
|
138
|
+
* list is a no-op (artifacts pass through unchanged).
|
|
139
|
+
*/
|
|
140
|
+
declare function defineArtifactPlugin(plugin: OpysPlugin, overrides: readonly ArtifactOverride[]): OpysPlugin;
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region lib/paths.d.ts
|
|
143
|
+
/**
|
|
144
|
+
* Per-user data directory for an application, matching OS conventions:
|
|
145
|
+
*
|
|
146
|
+
* - Windows: `%APPDATA%\<name>` (e.g. `C:\Users\you\AppData\Roaming\<name>`)
|
|
147
|
+
* - macOS: `~/Library/Application Support/<name>`
|
|
148
|
+
* - Linux: `$XDG_DATA_HOME/<name>` or `~/.local/share/<name>`
|
|
149
|
+
*/
|
|
150
|
+
declare function userDataDir(name: string): string;
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region lib/scanner.d.ts
|
|
153
|
+
/** A file discovered by {@link artifactScanner}, passed to `path`/`url` functions. */
|
|
154
|
+
interface ScannedFile {
|
|
155
|
+
/** Path relative to `directory`, POSIX separators. */
|
|
156
|
+
readonly rel: string;
|
|
157
|
+
/** Directory portion of `rel` (`''` at the root). */
|
|
158
|
+
readonly dir: string;
|
|
159
|
+
/** Final path segment. */
|
|
160
|
+
readonly filename: string;
|
|
161
|
+
/** Absolute path on the build machine. */
|
|
162
|
+
readonly abs: string;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* A `path` / `url` value: either a template string — interpolating the
|
|
166
|
+
* per-file placeholders `${rel}` / `${dir}` / `${filename}`, with any other
|
|
167
|
+
* `${var}` left for install — or a `(file) => string` function. Only the
|
|
168
|
+
* function form receives the build-machine `abs` path.
|
|
169
|
+
*/
|
|
170
|
+
type ScanTemplate = string | ((file: ScannedFile) => string);
|
|
171
|
+
interface ArtifactScannerOptions {
|
|
172
|
+
/** Directory to scan. */
|
|
173
|
+
directory: string;
|
|
174
|
+
/** URL for fetching each file — template string or `(file) => string`. */
|
|
175
|
+
url: ScanTemplate;
|
|
176
|
+
/** Destination path — template or function. Defaults to the file's `rel`. */
|
|
177
|
+
path?: ScanTemplate;
|
|
178
|
+
hash?: 'sha1' | 'sha256';
|
|
179
|
+
/**
|
|
180
|
+
* 'url' → emit sourceUrl + computed hash (default)
|
|
181
|
+
* 'file' → emit sourceFile pointing at the local copy; skip hashing entirely
|
|
182
|
+
*/
|
|
183
|
+
source?: 'url' | 'file';
|
|
184
|
+
/**
|
|
185
|
+
* Per-selector patches applied to the scanned artifacts — exclude files,
|
|
186
|
+
* attach rulesets (OS / feature gates), or clear integrity.
|
|
187
|
+
*/
|
|
188
|
+
overrides?: ArtifactOverride[];
|
|
189
|
+
}
|
|
190
|
+
/** Scan a local directory tree into artifacts — a generic build-time plugin. */
|
|
191
|
+
declare function artifactScanner(options: ArtifactScannerOptions): OpysPlugin;
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region lib/github.d.ts
|
|
194
|
+
/** A single asset on a GitHub release, mirroring the `/releases` API shape. */
|
|
195
|
+
interface GitHubAsset {
|
|
196
|
+
name: string;
|
|
197
|
+
size: number;
|
|
198
|
+
browser_download_url: string;
|
|
199
|
+
/** `sha256:<hex>` when present (introduced 2024); older releases lack it. */
|
|
200
|
+
digest?: string;
|
|
201
|
+
}
|
|
202
|
+
/** A single GitHub release entry from the `/releases` API. */
|
|
203
|
+
interface GitHubRelease {
|
|
204
|
+
tag_name: string;
|
|
205
|
+
prerelease: boolean;
|
|
206
|
+
draft: boolean;
|
|
207
|
+
published_at: string;
|
|
208
|
+
assets: GitHubAsset[];
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* List all releases for `repo` (`owner/name`), newest first. Fetches a
|
|
212
|
+
* single page of up to 100 releases. `token` raises the rate limit.
|
|
213
|
+
*/
|
|
214
|
+
declare function listGitHubReleases(repo: string, token?: string): Promise<GitHubRelease[]>;
|
|
215
|
+
/**
|
|
216
|
+
* Extract the hex sha256 from an asset's `digest` field. GitHub's `digest`
|
|
217
|
+
* is `sha256:<hex>` when present (introduced 2024); older releases lack it.
|
|
218
|
+
*/
|
|
219
|
+
declare function gitHubAssetSha256(asset: GitHubAsset): string | undefined;
|
|
220
|
+
/** Selector accepted by {@link pickGitHubRelease}. */
|
|
221
|
+
type GitHubReleaseSelector = /** Newest non-prerelease. */'latest' /** Newest including prereleases. */ | 'prerelease' /** Exact `tag_name` match. */ | (string & {});
|
|
222
|
+
interface PickGitHubReleaseOptions {
|
|
223
|
+
/** Optional GitHub token for higher rate limits. */
|
|
224
|
+
token?: string;
|
|
225
|
+
/**
|
|
226
|
+
* Restrict candidates before the selector runs. Returns true to keep.
|
|
227
|
+
* Use this when the loader needs specific assets present (e.g. a
|
|
228
|
+
* `version.json` next to a mod jar) — `'latest'` then falls through to
|
|
229
|
+
* the newest release that actually qualifies.
|
|
230
|
+
*/
|
|
231
|
+
filter?: (release: GitHubRelease) => boolean;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Fetch `repo`'s releases and pick one matching `selector`. Drafts are
|
|
235
|
+
* always skipped; the optional `filter` further narrows candidates before
|
|
236
|
+
* the selector runs. Throws a descriptive error (with up to 5 available
|
|
237
|
+
* tags) when nothing matches.
|
|
238
|
+
*/
|
|
239
|
+
declare function pickGitHubRelease(repo: string, selector: GitHubReleaseSelector, options?: PickGitHubReleaseOptions): Promise<GitHubRelease>;
|
|
240
|
+
/**
|
|
241
|
+
* One asset → Artifact mapping inside a {@link gitHubReleaseArtifacts}
|
|
242
|
+
* call. The asset's URL, size, and sha256 are auto-derived; the spec
|
|
243
|
+
* supplies the install-time path plus any extra Artifact fields.
|
|
244
|
+
*/
|
|
245
|
+
interface GitHubAssetSpec {
|
|
246
|
+
/** Predicate to pick the asset on the resolved release. */
|
|
247
|
+
match: (asset: GitHubAsset, release: GitHubRelease) => boolean;
|
|
248
|
+
/**
|
|
249
|
+
* Install-time destination path. Manifest template literals (`${var}`)
|
|
250
|
+
* pass through unchanged. Use the function form when the path embeds a
|
|
251
|
+
* build-time value like the release tag.
|
|
252
|
+
*/
|
|
253
|
+
path: string | ((asset: GitHubAsset, release: GitHubRelease) => string);
|
|
254
|
+
/** Human description used in the error if `match` finds nothing. */
|
|
255
|
+
description?: string;
|
|
256
|
+
/** Manifest rules (OS/arch constraints). Default `[]`. */
|
|
257
|
+
rules?: Ruleset;
|
|
258
|
+
/** Extract rules for jars / tarballs. */
|
|
259
|
+
extract?: ExtractRule[];
|
|
260
|
+
/** Optional install-time discovery hints. */
|
|
261
|
+
discovery?: Discovery;
|
|
262
|
+
/** Opaque metadata, forwarded into the manifest unchanged. */
|
|
263
|
+
metadata?: unknown;
|
|
264
|
+
}
|
|
265
|
+
interface GitHubReleaseArtifactsOptions {
|
|
266
|
+
/** GitHub token (raises rate limits). */
|
|
267
|
+
token?: string;
|
|
268
|
+
/**
|
|
269
|
+
* Restrict candidate releases before the selector runs. Use when the
|
|
270
|
+
* loader requires multiple assets present in the same release so that
|
|
271
|
+
* `'latest'` falls through to the newest one that fully qualifies.
|
|
272
|
+
*/
|
|
273
|
+
filter?: (release: GitHubRelease) => boolean;
|
|
274
|
+
/** One spec per asset → Artifact mapping, in output order. */
|
|
275
|
+
assets: GitHubAssetSpec[];
|
|
276
|
+
}
|
|
277
|
+
interface GitHubReleaseArtifactsResult {
|
|
278
|
+
/** The picked release — handy for downstream metadata or side-fetches. */
|
|
279
|
+
release: GitHubRelease;
|
|
280
|
+
/** Mapped artifacts in input order, one per `assets` spec. */
|
|
281
|
+
artifacts: Artifact[];
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Pick a GitHub release and project a list of asset specs into Artifacts
|
|
285
|
+
* in one call. Throws if the release can't be picked or any spec has no
|
|
286
|
+
* matching asset on the picked release.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* const { artifacts } = await gitHubReleaseArtifacts(
|
|
290
|
+
* 'me/myloader', version, {
|
|
291
|
+
* assets: [{
|
|
292
|
+
* match: (a) => a.name.endsWith('.jar'),
|
|
293
|
+
* path: '${mods_directory}/myloader.jar',
|
|
294
|
+
* }],
|
|
295
|
+
* },
|
|
296
|
+
* );
|
|
297
|
+
*/
|
|
298
|
+
declare function gitHubReleaseArtifacts(repo: string, selector: GitHubReleaseSelector, options: GitHubReleaseArtifactsOptions): Promise<GitHubReleaseArtifactsResult>;
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region lib/loader.d.ts
|
|
301
|
+
/** Shared shape of the vanilla / forge-family loader templates. */
|
|
302
|
+
interface LoaderTemplate {
|
|
303
|
+
launch: Launch;
|
|
304
|
+
jvmArgs: Valset;
|
|
305
|
+
mainClass: Val;
|
|
306
|
+
gameArgs: Valset;
|
|
307
|
+
}
|
|
308
|
+
/** Project a loader template's launch surface into named groups. */
|
|
309
|
+
declare function launchGroups(t: LoaderTemplate): LaunchGroups;
|
|
310
|
+
//#endregion
|
|
311
|
+
export { ArgItem, ArtifactOverride, ArtifactScannerOptions, BuildContext, Contribution, GitHubAsset, GitHubAssetSpec, GitHubRelease, GitHubReleaseArtifactsOptions, GitHubReleaseArtifactsResult, GitHubReleaseSelector, LaunchGroups, LoaderTemplate, OpysConfig, OpysConfigContext, OpysConfigInput, OpysManifestConfig, OpysPlugin, PickGitHubReleaseOptions, PluginMap, RulesetInput, ScanTemplate, ScannedFile, Selector, applyOverrides, artifactScanner, buildManifest, defineArtifactPlugin, defineConfig, definePlugin, gitHubAssetSha256, gitHubReleaseArtifacts, launchGroups, listGitHubReleases, matchesSelector, pickGitHubRelease, resolveConfig, userDataDir };
|
|
312
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../lib/plugin.ts","../lib/config.ts","../lib/engine.ts","../lib/overrides.ts","../lib/artifact-plugin.ts","../lib/paths.ts","../lib/scanner.ts","../lib/github.ts","../lib/loader.ts"],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { deduplicateArtifacts, fetchWithRetry, globToRegex, interpolate, parseShortRuleset, sourceFile, sourceUrl } from "@opys/core";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
6
|
+
|
|
7
|
+
//#region lib/plugin.ts
|
|
8
|
+
/** Identity helper for authoring a plugin with inferred types. */
|
|
9
|
+
function definePlugin(plugin) {
|
|
10
|
+
return plugin;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region lib/config.ts
|
|
15
|
+
/** Use as the default export of `opys.config.mjs`. */
|
|
16
|
+
function defineConfig(input) {
|
|
17
|
+
return input;
|
|
18
|
+
}
|
|
19
|
+
/** Resolve a config input to a concrete `OpysConfig`. */
|
|
20
|
+
async function resolveConfig(input, ctx) {
|
|
21
|
+
return typeof input === "function" ? input(ctx) : input;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region lib/engine.ts
|
|
26
|
+
/** Flatten author-ordered launch groups into a single `Valset`. */
|
|
27
|
+
function flattenArgs(items) {
|
|
28
|
+
const out = [];
|
|
29
|
+
for (const item of items) if (typeof item === "string") out.push({
|
|
30
|
+
rules: [],
|
|
31
|
+
value: [item]
|
|
32
|
+
});
|
|
33
|
+
else if (Array.isArray(item)) out.push(...item);
|
|
34
|
+
else out.push(item);
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run every plugin's `build` hook in parallel, merge the contributions, and
|
|
39
|
+
* assemble the final `Manifest`.
|
|
40
|
+
*/
|
|
41
|
+
async function buildManifest(config, ctx) {
|
|
42
|
+
ctx.log("opys", `resolving ${config.plugins.length} plugin(s)`);
|
|
43
|
+
const results = await Promise.all(config.plugins.map(async (p) => ({
|
|
44
|
+
name: p.name,
|
|
45
|
+
contribution: await p.build(ctx)
|
|
46
|
+
})));
|
|
47
|
+
const artifacts = [];
|
|
48
|
+
for (const r of results) if (r.contribution.artifacts) artifacts.push(...r.contribution.artifacts);
|
|
49
|
+
if (config.manifest.artifacts) artifacts.push(...config.manifest.artifacts);
|
|
50
|
+
const deduped = deduplicateArtifacts(artifacts);
|
|
51
|
+
const vars = {};
|
|
52
|
+
const owner = {};
|
|
53
|
+
for (const r of results) {
|
|
54
|
+
if (!r.contribution.vars) continue;
|
|
55
|
+
for (const [key, value] of Object.entries(r.contribution.vars)) {
|
|
56
|
+
const prev = owner[key];
|
|
57
|
+
if (prev !== void 0 && prev !== r.name) ctx.log("opys", `warning: var '${key}' set by both '${prev}' and '${r.name}' — using '${r.name}'`);
|
|
58
|
+
vars[key] = value;
|
|
59
|
+
owner[key] = r.name;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (config.manifest.vars) for (const [key, value] of Object.entries(config.manifest.vars)) vars[key] = value;
|
|
63
|
+
const pluginMap = Object.fromEntries(results.map((r) => [r.name, r.contribution.launch ?? {}]));
|
|
64
|
+
const m = config.manifest;
|
|
65
|
+
const launch = {
|
|
66
|
+
command: m.command(pluginMap),
|
|
67
|
+
workdir: typeof m.workdir === "function" ? m.workdir(pluginMap) : m.workdir ?? ".",
|
|
68
|
+
args: flattenArgs(m.args(pluginMap)),
|
|
69
|
+
envs: typeof m.envs === "function" ? m.envs(pluginMap) : m.envs ?? {}
|
|
70
|
+
};
|
|
71
|
+
ctx.log("opys", `merged ${deduped.length} artifact(s) (${artifacts.length - deduped.length} deduped)`);
|
|
72
|
+
return {
|
|
73
|
+
vars,
|
|
74
|
+
launch,
|
|
75
|
+
artifacts: deduped,
|
|
76
|
+
...m.restrict && m.restrict.length > 0 ? { restrict: m.restrict } : {}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region lib/overrides.ts
|
|
82
|
+
function matchesSelector(selector, artifact) {
|
|
83
|
+
if (typeof selector === "function") return selector(artifact);
|
|
84
|
+
return (Array.isArray(selector) ? selector : [selector]).map(globToRegex).some((re) => re.test(artifact.path));
|
|
85
|
+
}
|
|
86
|
+
/** Apply an ordered list of {@link ArtifactOverride}s to a list of artifacts. */
|
|
87
|
+
function applyOverrides(artifacts, overrides) {
|
|
88
|
+
if (overrides.length === 0) return [...artifacts];
|
|
89
|
+
const out = [];
|
|
90
|
+
for (const artifact of artifacts) {
|
|
91
|
+
let current = artifact;
|
|
92
|
+
for (const override of overrides) {
|
|
93
|
+
if (current === null) break;
|
|
94
|
+
if (!matchesSelector(override.match, current)) continue;
|
|
95
|
+
if (override.exclude) {
|
|
96
|
+
current = null;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
if (override.rules !== void 0) {
|
|
100
|
+
const extra = parseShortRuleset(override.rules);
|
|
101
|
+
current = {
|
|
102
|
+
...current,
|
|
103
|
+
rules: [...current.rules, ...extra]
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (override.integrity === null) current = {
|
|
107
|
+
...current,
|
|
108
|
+
integrity: void 0,
|
|
109
|
+
discovery: void 0
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (current !== null) out.push(current);
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region lib/artifact-plugin.ts
|
|
119
|
+
/**
|
|
120
|
+
* Wraps a {@link OpysPlugin} so that the artifacts it contributes are passed
|
|
121
|
+
* through an ordered list of {@link ArtifactOverride}s before being returned.
|
|
122
|
+
*
|
|
123
|
+
* Use this to give artifact-producing plugins (`forge`, `curseforge`, …) the
|
|
124
|
+
* same filter/patch support that `artifactScanner` already has natively. The
|
|
125
|
+
* inner plugin's `build` runs unchanged; only `Contribution.artifacts` is
|
|
126
|
+
* rewritten. Non-artifact contribution fields (`vars`, `launch`) pass through
|
|
127
|
+
* untouched.
|
|
128
|
+
*
|
|
129
|
+
* @param plugin The inner plugin to wrap.
|
|
130
|
+
* @param overrides Overrides applied to the inner plugin's artifacts. An empty
|
|
131
|
+
* list is a no-op (artifacts pass through unchanged).
|
|
132
|
+
*/
|
|
133
|
+
function defineArtifactPlugin(plugin, overrides) {
|
|
134
|
+
return {
|
|
135
|
+
name: plugin.name,
|
|
136
|
+
async build(ctx) {
|
|
137
|
+
const contribution = await plugin.build(ctx);
|
|
138
|
+
if (contribution.artifacts === void 0) return contribution;
|
|
139
|
+
return {
|
|
140
|
+
...contribution,
|
|
141
|
+
artifacts: applyOverrides(contribution.artifacts, overrides)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region lib/paths.ts
|
|
149
|
+
/**
|
|
150
|
+
* Per-user data directory for an application, matching OS conventions:
|
|
151
|
+
*
|
|
152
|
+
* - Windows: `%APPDATA%\<name>` (e.g. `C:\Users\you\AppData\Roaming\<name>`)
|
|
153
|
+
* - macOS: `~/Library/Application Support/<name>`
|
|
154
|
+
* - Linux: `$XDG_DATA_HOME/<name>` or `~/.local/share/<name>`
|
|
155
|
+
*/
|
|
156
|
+
function userDataDir(name) {
|
|
157
|
+
if (process.platform === "win32") return join(process.env.APPDATA ?? homedir(), name);
|
|
158
|
+
if (process.platform === "darwin") return join(homedir(), "Library", "Application Support", name);
|
|
159
|
+
return join(process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share"), name);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region lib/scanner.ts
|
|
164
|
+
async function walkDir(dir) {
|
|
165
|
+
async function walk(cur) {
|
|
166
|
+
const entries = await readdir(cur, { withFileTypes: true });
|
|
167
|
+
return (await Promise.all(entries.map(async (e) => {
|
|
168
|
+
const abs = join(cur, e.name);
|
|
169
|
+
if (e.isDirectory()) return walk(abs);
|
|
170
|
+
if (e.isFile()) {
|
|
171
|
+
const { size } = await stat(abs);
|
|
172
|
+
const rel = relative(dir, abs).replace(/\\/g, "/");
|
|
173
|
+
const d = dirname(rel);
|
|
174
|
+
return [{
|
|
175
|
+
rel,
|
|
176
|
+
dir: d === "." ? "" : d,
|
|
177
|
+
filename: basename(rel),
|
|
178
|
+
abs,
|
|
179
|
+
size
|
|
180
|
+
}];
|
|
181
|
+
}
|
|
182
|
+
return [];
|
|
183
|
+
}))).flat();
|
|
184
|
+
}
|
|
185
|
+
return walk(dir);
|
|
186
|
+
}
|
|
187
|
+
async function hashFile(path, algo) {
|
|
188
|
+
return createHash(algo).update(await readFile(path)).digest("hex");
|
|
189
|
+
}
|
|
190
|
+
function applyTemplate(tpl, file) {
|
|
191
|
+
if (typeof tpl === "function") return tpl(file);
|
|
192
|
+
return interpolate(tpl, {
|
|
193
|
+
rel: file.rel,
|
|
194
|
+
dir: file.dir,
|
|
195
|
+
filename: file.filename
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
async function* scanDirectory(options, baseDir) {
|
|
199
|
+
const algo = options.hash ?? "sha1";
|
|
200
|
+
const sourceKind = options.source ?? "url";
|
|
201
|
+
const files = await walkDir(baseDir);
|
|
202
|
+
for (const file of files) {
|
|
203
|
+
const artifactPath = options.path ? applyTemplate(options.path, file) : file.rel;
|
|
204
|
+
let integrity;
|
|
205
|
+
let source;
|
|
206
|
+
if (sourceKind === "file") source = sourceFile(file.abs);
|
|
207
|
+
else {
|
|
208
|
+
source = sourceUrl(applyTemplate(options.url, file));
|
|
209
|
+
const digest = await hashFile(file.abs, algo);
|
|
210
|
+
integrity = algo === "sha1" ? { sha1: digest } : { sha256: digest };
|
|
211
|
+
}
|
|
212
|
+
yield {
|
|
213
|
+
path: artifactPath,
|
|
214
|
+
source,
|
|
215
|
+
size: file.size,
|
|
216
|
+
rules: [],
|
|
217
|
+
integrity
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/** Scan a local directory tree into artifacts — a generic build-time plugin. */
|
|
222
|
+
function artifactScanner(options) {
|
|
223
|
+
return definePlugin({
|
|
224
|
+
name: "artifactScanner",
|
|
225
|
+
async build(ctx) {
|
|
226
|
+
const baseDir = isAbsolute(options.directory) ? options.directory : resolve(ctx.configDir, options.directory);
|
|
227
|
+
const scanned = [];
|
|
228
|
+
for await (const a of scanDirectory(options, baseDir)) scanned.push(a);
|
|
229
|
+
const artifacts = applyOverrides(scanned, options.overrides ?? []);
|
|
230
|
+
const dropped = scanned.length - artifacts.length;
|
|
231
|
+
ctx.log("artifactScanner", `scanned ${scanned.length} file(s)` + (dropped > 0 ? `, ${dropped} excluded` : ""));
|
|
232
|
+
return { artifacts };
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
//#endregion
|
|
238
|
+
//#region lib/github.ts
|
|
239
|
+
/**
|
|
240
|
+
* Shared GitHub Releases helpers.
|
|
241
|
+
*
|
|
242
|
+
* The forge-family loaders (cleanroom, lwjgl3ify, unimixins) all resolve
|
|
243
|
+
* their versions straight off GitHub Releases. This module centralises the
|
|
244
|
+
* release-listing request and the `sha256:<hex>` digest parsing so the
|
|
245
|
+
* resolvers don't each carry their own copy.
|
|
246
|
+
*/
|
|
247
|
+
/**
|
|
248
|
+
* List all releases for `repo` (`owner/name`), newest first. Fetches a
|
|
249
|
+
* single page of up to 100 releases. `token` raises the rate limit.
|
|
250
|
+
*/
|
|
251
|
+
async function listGitHubReleases(repo, token) {
|
|
252
|
+
const headers = {
|
|
253
|
+
Accept: "application/vnd.github+json",
|
|
254
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
255
|
+
};
|
|
256
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
257
|
+
const res = await fetchWithRetry(`https://api.github.com/repos/${repo}/releases?per_page=100`, { headers });
|
|
258
|
+
if (!res.ok) throw new Error(`GitHub API ${res.status} ${res.statusText} listing ${repo} releases`);
|
|
259
|
+
return await res.json();
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Extract the hex sha256 from an asset's `digest` field. GitHub's `digest`
|
|
263
|
+
* is `sha256:<hex>` when present (introduced 2024); older releases lack it.
|
|
264
|
+
*/
|
|
265
|
+
function gitHubAssetSha256(asset) {
|
|
266
|
+
return asset.digest?.startsWith("sha256:") ? asset.digest.slice(7) : void 0;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Fetch `repo`'s releases and pick one matching `selector`. Drafts are
|
|
270
|
+
* always skipped; the optional `filter` further narrows candidates before
|
|
271
|
+
* the selector runs. Throws a descriptive error (with up to 5 available
|
|
272
|
+
* tags) when nothing matches.
|
|
273
|
+
*/
|
|
274
|
+
async function pickGitHubRelease(repo, selector, options = {}) {
|
|
275
|
+
const candidates = (await listGitHubReleases(repo, options.token)).filter((r) => !r.draft).filter(options.filter ?? (() => true));
|
|
276
|
+
const picked = selectGitHubRelease(candidates, selector);
|
|
277
|
+
if (picked) return picked;
|
|
278
|
+
if (selector === "latest" || selector === "prerelease") throw new Error(`No ${selector === "latest" ? "stable" : ""} GitHub release in ${repo}${options.filter ? " matching the loader filter" : ""}`.replace(/ +/g, " "));
|
|
279
|
+
const tags = candidates.slice(0, 5).map((r) => r.tag_name);
|
|
280
|
+
throw new Error(`GitHub release '${selector}' not found in ${repo}. Available: ${tags.join(", ")}${candidates.length > 5 ? ", …" : ""}`);
|
|
281
|
+
}
|
|
282
|
+
function selectGitHubRelease(releases, selector) {
|
|
283
|
+
if (selector === "latest") return releases.find((r) => !r.prerelease);
|
|
284
|
+
if (selector === "prerelease") return releases[0];
|
|
285
|
+
return releases.find((r) => r.tag_name === selector);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Pick a GitHub release and project a list of asset specs into Artifacts
|
|
289
|
+
* in one call. Throws if the release can't be picked or any spec has no
|
|
290
|
+
* matching asset on the picked release.
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* const { artifacts } = await gitHubReleaseArtifacts(
|
|
294
|
+
* 'me/myloader', version, {
|
|
295
|
+
* assets: [{
|
|
296
|
+
* match: (a) => a.name.endsWith('.jar'),
|
|
297
|
+
* path: '${mods_directory}/myloader.jar',
|
|
298
|
+
* }],
|
|
299
|
+
* },
|
|
300
|
+
* );
|
|
301
|
+
*/
|
|
302
|
+
async function gitHubReleaseArtifacts(repo, selector, options) {
|
|
303
|
+
const release = await pickGitHubRelease(repo, selector, {
|
|
304
|
+
token: options.token,
|
|
305
|
+
filter: options.filter
|
|
306
|
+
});
|
|
307
|
+
return {
|
|
308
|
+
release,
|
|
309
|
+
artifacts: options.assets.map((spec) => gitHubAssetToArtifact(spec, release))
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function gitHubAssetToArtifact(spec, release) {
|
|
313
|
+
const asset = release.assets.find((a) => spec.match(a, release));
|
|
314
|
+
if (!asset) {
|
|
315
|
+
const what = spec.description ? ` (${spec.description})` : "";
|
|
316
|
+
throw new Error(`No matching asset${what} on GitHub release ${release.tag_name}. Assets: ${release.assets.map((a) => a.name).join(", ") || "(none)"}`);
|
|
317
|
+
}
|
|
318
|
+
const path = typeof spec.path === "function" ? spec.path(asset, release) : spec.path;
|
|
319
|
+
const sha256 = gitHubAssetSha256(asset);
|
|
320
|
+
return {
|
|
321
|
+
path,
|
|
322
|
+
source: sourceUrl(asset.browser_download_url),
|
|
323
|
+
size: asset.size,
|
|
324
|
+
rules: spec.rules ?? [],
|
|
325
|
+
...sha256 ? { integrity: { sha256 } } : {},
|
|
326
|
+
...spec.extract ? { extract: spec.extract } : {},
|
|
327
|
+
...spec.discovery ? { discovery: spec.discovery } : {},
|
|
328
|
+
...spec.metadata !== void 0 ? { metadata: spec.metadata } : {}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
//#endregion
|
|
333
|
+
//#region lib/loader.ts
|
|
334
|
+
/** Project a loader template's launch surface into named groups. */
|
|
335
|
+
function launchGroups(t) {
|
|
336
|
+
return {
|
|
337
|
+
command: t.launch.command,
|
|
338
|
+
jvmArgs: t.jvmArgs,
|
|
339
|
+
mainClass: t.mainClass,
|
|
340
|
+
gameArgs: t.gameArgs
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
//#endregion
|
|
345
|
+
export { applyOverrides, artifactScanner, buildManifest, defineArtifactPlugin, defineConfig, definePlugin, gitHubAssetSha256, gitHubReleaseArtifacts, launchGroups, listGitHubReleases, matchesSelector, pickGitHubRelease, resolveConfig, userDataDir };
|
|
346
|
+
//# sourceMappingURL=index.mjs.map
|