@opys/java 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 ADDED
@@ -0,0 +1,63 @@
1
+ # @opys/java
2
+
3
+ OpenJDK runtime support for opys — auto-installs an [Eclipse Temurin](https://adoptium.net) JDK and exposes `${java_home}` and `${java_bin}` as standardized vars so loader templates can reference a portable Java binary.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm install @opys/java
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { resolveJava } from '@opys/java';
15
+ import { resolveLwjgl3ify } from '@opys/lwjgl3ify';
16
+
17
+ const lw = await resolveLwjgl3ify({ version: '3.0.16' });
18
+ const jav = await resolveJava({ version: '21' });
19
+
20
+ return {
21
+ manifest: {
22
+ artifacts: [lw.artifacts, jav.artifacts],
23
+ vars: { ...lw.vars, ...jav.vars },
24
+ launch: lw.launch, // launch.command is `${java_bin}` already
25
+ },
26
+ };
27
+ ```
28
+
29
+ ### Version input
30
+
31
+ - **Major** — `'21'`, `'17'` — resolves to the latest GA release for that major.
32
+ - **Full version** — `'21.0.11+10'` — exact Adoptium release name (`jdk-` prefix and `-LTS` suffix are tolerated).
33
+
34
+ ### Options
35
+
36
+ ```ts
37
+ resolveJava({
38
+ version: string,
39
+ vendor?: 'openjdk', // only OpenJDK (Temurin) is supported today
40
+ platforms?: JavaPlatform[], // override the default OS/arch matrix
41
+ apiBase?: string, // override the Adoptium API base URL
42
+ });
43
+ ```
44
+
45
+ ## How it works
46
+
47
+ 1. Resolves the requested `version` against `https://api.adoptium.net/v3/`. Major versions hit `/feature_releases/<n>/ga` (latest GA); full versions hit `/release_name/eclipse/jdk-<v>` (exact).
48
+ 2. Queries each platform (linux/osx/windows × x86_64+aarch64) in parallel; soft-skips combinations that don't ship a binary.
49
+ 3. Emits one `Artifact` per platform pointing at the GitHub-hosted release asset, with sha256 from the API and OS+arch rules so only the matching binary downloads at install time.
50
+ 4. Each artifact has an `extract: dump` rule pointing at `${root}/runtimes/jdk-<major>/`, so the JDK lands at `${root}/runtimes/jdk-<major>/jdk-<full>/`.
51
+ 5. Sets `java_home` (per OS — macOS gets the `/Contents/Home` suffix) and `java_bin` (`${java_home}/bin/java` on POSIX, `${java_home}/bin/java.exe` on Windows).
52
+
53
+ `@opys/installer` extracts both `.zip` (Windows) and `.tar.gz` / `.tgz` (Linux/macOS) archives, preserving the executable bit on tar entries so `bin/java` stays runnable without a chmod step.
54
+
55
+ ## Standard `${java_home}` and `${java_bin}` vars
56
+
57
+ Every opys template returned by `@opys/minecraft` (and by any loader built on it) now sets `launch.command = '${java_bin}'`, with `java_bin` defaulting to the literal `'java'` (PATH lookup). When you spread `@opys/java`'s vars over the loader's, the var resolves to the auto-installed JDK instead — without any change to the launch command.
58
+
59
+ ## Notes
60
+
61
+ - **Vendor**: only `openjdk` (Eclipse Temurin) is supported. Adding Liberica, Zulu, GraalVM is a matter of plugging in another resolver.
62
+ - **macOS app bundles**: macOS Temurin tarballs ship as `.app` bundles with `Contents/MacOS/_CodeSignature/...`. `${java_home}` includes the `/Contents/Home` suffix automatically.
63
+ - **Disk usage**: each JDK is ~200 MB compressed, ~500 MB extracted. The archive is downloaded into `${root}/runtimes/` as a sibling of the `jdk-<major>/` extract target — delete the leftover `.tar.gz`/`.zip` archive there to reclaim space.
package/dist/index.cjs ADDED
@@ -0,0 +1,257 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let _opys_dev = require("@opys/dev");
3
+ let _opys_core = require("@opys/core");
4
+
5
+ //#region lib/resolver.ts
6
+ /**
7
+ * Resolver for OpenJDK builds from the Eclipse Adoptium (Temurin) distribution.
8
+ *
9
+ * Adoptium publishes a public asset API at `https://api.adoptium.net/v3/`.
10
+ * We use two endpoints depending on the version input shape:
11
+ *
12
+ * - Major-only (`'21'`, `'17'`) → `/feature_releases/<major>/ga` (latest GA)
13
+ * - Full version → `/release_name/<vendor>/<release-name>`
14
+ * (exact, pinned build). Adoptium release names differ by line — Java 8
15
+ * is `jdk8u<update>-b<build>` (no hyphen), Java 9+ is `jdk-<version>`.
16
+ * A full input is accepted bare (`'8u492-b09'`, `'21.0.13+11'`) or as a
17
+ * complete release name (`'jdk8u492-b09'`, `'jdk-21.0.13+11'`).
18
+ *
19
+ * Each platform (os × arch) is queried separately with `image_type=jdk` and
20
+ * `jvm_impl=hotspot`. Releases that don't ship a binary for a given platform
21
+ * are soft-skipped — the resulting `JavaRelease` only contains the platforms
22
+ * with a real binary.
23
+ */
24
+ const ADOPTIUM_BASE = "https://api.adoptium.net/v3";
25
+ const VENDOR = "eclipse";
26
+ const DEFAULT_PLATFORMS = [
27
+ {
28
+ os: "linux",
29
+ arch: "x86_64",
30
+ adoptiumOs: "linux",
31
+ adoptiumArch: "x64",
32
+ homeSuffix: ""
33
+ },
34
+ {
35
+ os: "linux",
36
+ arch: "aarch64",
37
+ adoptiumOs: "linux",
38
+ adoptiumArch: "aarch64",
39
+ homeSuffix: ""
40
+ },
41
+ {
42
+ os: "osx",
43
+ arch: "x86_64",
44
+ adoptiumOs: "mac",
45
+ adoptiumArch: "x64",
46
+ homeSuffix: "/Contents/Home"
47
+ },
48
+ {
49
+ os: "osx",
50
+ arch: "aarch64",
51
+ adoptiumOs: "mac",
52
+ adoptiumArch: "aarch64",
53
+ homeSuffix: "/Contents/Home"
54
+ },
55
+ {
56
+ os: "windows",
57
+ arch: "x86_64",
58
+ adoptiumOs: "windows",
59
+ adoptiumArch: "x64",
60
+ homeSuffix: ""
61
+ },
62
+ {
63
+ os: "windows",
64
+ arch: "aarch64",
65
+ adoptiumOs: "windows",
66
+ adoptiumArch: "aarch64",
67
+ homeSuffix: ""
68
+ }
69
+ ];
70
+ function normalizeInput(input) {
71
+ const v = input.trim().replace(/-LTS$/, "");
72
+ if (/^\d+$/.test(v)) return {
73
+ kind: "major",
74
+ raw: v
75
+ };
76
+ if (v.startsWith("jdk")) return {
77
+ kind: "full",
78
+ raw: v
79
+ };
80
+ return {
81
+ kind: "full",
82
+ raw: /^\d+u/.test(v) ? `jdk${v}` : `jdk-${v}`
83
+ };
84
+ }
85
+ function adoptiumQuery(platform) {
86
+ return new URLSearchParams({
87
+ image_type: "jdk",
88
+ architecture: platform.adoptiumArch,
89
+ os: platform.adoptiumOs,
90
+ jvm_impl: "hotspot",
91
+ heap_size: "normal",
92
+ vendor: VENDOR
93
+ }).toString();
94
+ }
95
+ async function fetchPlatform(apiBase, platform, version) {
96
+ const res = await (0, _opys_core.fetchWithRetry)(`${apiBase}${version.kind === "major" ? `/assets/feature_releases/${version.raw}/ga?${adoptiumQuery(platform)}&page_size=1&sort_order=DESC` : `/assets/release_name/${VENDOR}/${encodeURIComponent(version.raw)}?${adoptiumQuery(platform)}`}`, { headers: { Accept: "application/json" } });
97
+ if (res.status === 404) return null;
98
+ if (!res.ok) throw new Error(`Adoptium API ${res.status} ${res.statusText} for ${platform.adoptiumOs}/${platform.adoptiumArch}`);
99
+ const body = await res.json();
100
+ const release = Array.isArray(body) ? body[0] : body;
101
+ if (!release || !release.binaries || release.binaries.length === 0) return null;
102
+ const binary = release.binaries.find((b) => b.architecture === platform.adoptiumArch && b.os === platform.adoptiumOs && b.image_type === "jdk");
103
+ if (!binary) return null;
104
+ return {
105
+ release,
106
+ binary
107
+ };
108
+ }
109
+ /**
110
+ * Resolve an OpenJDK release across all requested platforms. Returns a
111
+ * single `JavaRelease` with one entry per platform that has a binary
112
+ * available — platforms that don't ship a build for this release are
113
+ * silently dropped from `binaries`, so callers don't have to handle the
114
+ * "linux x64 exists, windows aarch64 doesn't" case explicitly.
115
+ */
116
+ async function resolveOpenjdk(version, options = {}) {
117
+ const apiBase = options.apiBase ?? ADOPTIUM_BASE;
118
+ const platforms = options.platforms ?? DEFAULT_PLATFORMS;
119
+ const parsed = normalizeInput(version);
120
+ const matched = (await Promise.all(platforms.map(async (p) => {
121
+ const found = await fetchPlatform(apiBase, p, parsed);
122
+ return found ? {
123
+ platform: p,
124
+ ...found
125
+ } : null;
126
+ }))).filter((x) => x !== null);
127
+ if (matched.length === 0) throw new Error(`No OpenJDK binaries found for version '${version}' across requested platforms.`);
128
+ const nameCounts = /* @__PURE__ */ new Map();
129
+ for (const m of matched) nameCounts.set(m.release.release_name, (nameCounts.get(m.release.release_name) ?? 0) + 1);
130
+ const releaseName = [...nameCounts.entries()].sort((a, b) => b[1] - a[1] || b[0].localeCompare(a[0]))[0][0];
131
+ const consistent = matched.filter((m) => m.release.release_name === releaseName);
132
+ const binaries = consistent.map((m) => ({
133
+ platform: m.platform,
134
+ filename: m.binary.package.name,
135
+ url: m.binary.package.link,
136
+ size: m.binary.package.size,
137
+ sha256: m.binary.package.checksum
138
+ }));
139
+ return {
140
+ releaseName,
141
+ extractDir: releaseName,
142
+ major: consistent[0].release.version_data.major,
143
+ binaries
144
+ };
145
+ }
146
+
147
+ //#endregion
148
+ //#region lib/template.ts
149
+ function osArchRuleset(os, arch) {
150
+ return [{
151
+ action: "allow",
152
+ os: { name: os }
153
+ }, {
154
+ action: "allow",
155
+ os: { arch }
156
+ }];
157
+ }
158
+ function osRuleset(os) {
159
+ return [{
160
+ action: "allow",
161
+ os: { name: os }
162
+ }];
163
+ }
164
+ /**
165
+ * Build a opys template fragment that auto-installs an OpenJDK runtime
166
+ * (Eclipse Temurin) and exposes `${java_home}` + `${java_bin}` vars.
167
+ *
168
+ * Each platform's archive is emitted as its own `Artifact` with an
169
+ * OS+arch rule, so only the matching binary downloads at install time.
170
+ * The archive is extracted into `${root}/runtimes/jdk-<major>/`, with
171
+ * the Adoptium release directory as the immediate child (e.g.
172
+ * `jdk-21.0.11+10/`). On macOS, `${java_home}` includes the
173
+ * `/Contents/Home` suffix that Mac JDK bundles use.
174
+ *
175
+ * Spread the result into your loader's vars + artifacts:
176
+ *
177
+ * ```ts
178
+ * const jav = await resolveJava({ version: '21' });
179
+ * return {
180
+ * artifacts: [lw.artifacts, jav.artifacts],
181
+ * vars: { ...lw.vars, ...jav.vars },
182
+ * command: lw.command, // command.command is `${java_bin}` already
183
+ * };
184
+ * ```
185
+ */
186
+ async function resolveJava(options) {
187
+ if (options.vendor && options.vendor !== "openjdk") throw new Error(`@opys/java: vendor '${options.vendor}' is not yet supported (only 'openjdk').`);
188
+ const release = await resolveOpenjdk(options.version, {
189
+ platforms: options.platforms,
190
+ apiBase: options.apiBase
191
+ });
192
+ const javaRoot = `\${java_runtime_dir}/jdk-${release.major}`;
193
+ const artifacts = release.binaries.map((b) => ({
194
+ path: `\${java_runtime_dir}/${b.filename}`,
195
+ source: (0, _opys_core.sourceUrl)(b.url),
196
+ size: b.size,
197
+ rules: osArchRuleset(b.platform.os, b.platform.arch),
198
+ integrity: { sha256: b.sha256 },
199
+ extract: [(0, _opys_core.extractDump)(javaRoot)]
200
+ }));
201
+ const seenOses = new Set(release.binaries.map((b) => b.platform.os));
202
+ const javaHomeArms = [];
203
+ const javaBinArms = [];
204
+ for (const os of seenOses) {
205
+ const platform = release.binaries.find((b) => b.platform.os === os).platform;
206
+ const home = `${javaRoot}/${release.extractDir}${platform.homeSuffix}`;
207
+ javaHomeArms.push({
208
+ value: home,
209
+ rules: osRuleset(os)
210
+ });
211
+ const exe = os === "windows" ? "java.exe" : "java";
212
+ javaBinArms.push({
213
+ value: `\${java_home}/bin/${exe}`,
214
+ rules: osRuleset(os)
215
+ });
216
+ }
217
+ return {
218
+ artifacts,
219
+ vars: {
220
+ java_runtime_dir: "${root}/runtimes",
221
+ java_home: javaHomeArms,
222
+ java_bin: javaBinArms
223
+ },
224
+ release
225
+ };
226
+ }
227
+
228
+ //#endregion
229
+ //#region lib/plugin.ts
230
+ /**
231
+ * Provision an OpenJDK runtime (Eclipse Temurin). Solely owns the
232
+ * `java_home` / `java_bin` vars and exposes `bin` as a launch group, so a
233
+ * config wires the launch command with `command: ({ java }) => java.bin`.
234
+ */
235
+ function java(version, opts = {}) {
236
+ return (0, _opys_dev.definePlugin)({
237
+ name: "java",
238
+ async build(ctx) {
239
+ const t = await resolveJava({
240
+ version,
241
+ ...opts
242
+ });
243
+ ctx.log("java", `OpenJDK ${t.release.releaseName.replace(/^jdk-?/, "")}`);
244
+ return {
245
+ artifacts: t.artifacts,
246
+ vars: t.vars,
247
+ launch: { bin: "${java_bin}" }
248
+ };
249
+ }
250
+ });
251
+ }
252
+
253
+ //#endregion
254
+ exports.DEFAULT_PLATFORMS = DEFAULT_PLATFORMS;
255
+ exports.java = java;
256
+ exports.resolveJava = resolveJava;
257
+ exports.resolveOpenjdk = resolveOpenjdk;
@@ -0,0 +1,115 @@
1
+ import { OpysPlugin } from "@opys/dev";
2
+ import { Artifact, OsArch, OsName, ValDefs } from "@opys/core";
3
+
4
+ //#region lib/resolver.d.ts
5
+ /** Adoptium-side platform descriptor + how it maps onto opys's OS/arch enums. */
6
+ interface JavaPlatform {
7
+ /** opys OS name. */
8
+ readonly os: OsName;
9
+ /** opys arch. `x86_64` is Adoptium's `x64`. */
10
+ readonly arch: OsArch;
11
+ /** Adoptium API `os` value (`linux`, `mac`, `windows`). */
12
+ readonly adoptiumOs: 'linux' | 'mac' | 'windows';
13
+ /** Adoptium API `architecture` value. */
14
+ readonly adoptiumArch: 'x64' | 'aarch64';
15
+ /**
16
+ * Path appended to the extracted top-level directory to reach JAVA_HOME.
17
+ * Empty on Linux/Windows; `/Contents/Home` on macOS bundles.
18
+ */
19
+ readonly homeSuffix: string;
20
+ }
21
+ declare const DEFAULT_PLATFORMS: readonly JavaPlatform[];
22
+ /** A resolved binary for one (os, arch) platform. */
23
+ interface JavaBinary {
24
+ readonly platform: JavaPlatform;
25
+ /** Asset filename, e.g. `OpenJDK21U-jdk_x64_linux_hotspot_21.0.11_10.tar.gz`. */
26
+ readonly filename: string;
27
+ /** Direct download URL (GitHub release asset). */
28
+ readonly url: string;
29
+ /** Asset size in bytes. */
30
+ readonly size: number;
31
+ /** sha256 of the asset (hex). */
32
+ readonly sha256: string;
33
+ }
34
+ interface JavaRelease {
35
+ /** Adoptium release name, e.g. `jdk-21.0.11+10`. */
36
+ readonly releaseName: string;
37
+ /** Top-level directory after extraction (matches `releaseName`). */
38
+ readonly extractDir: string;
39
+ /** Major version, e.g. `21`. */
40
+ readonly major: number;
41
+ /** Per-platform binaries that exist for this release. */
42
+ readonly binaries: JavaBinary[];
43
+ }
44
+ interface ResolveOpenjdkOptions {
45
+ /** Override the platform set. Default: linux/mac/windows × x64+aarch64. */
46
+ platforms?: readonly JavaPlatform[];
47
+ /** Optional override for the Adoptium API base URL. */
48
+ apiBase?: string;
49
+ }
50
+ /**
51
+ * Resolve an OpenJDK release across all requested platforms. Returns a
52
+ * single `JavaRelease` with one entry per platform that has a binary
53
+ * available — platforms that don't ship a build for this release are
54
+ * silently dropped from `binaries`, so callers don't have to handle the
55
+ * "linux x64 exists, windows aarch64 doesn't" case explicitly.
56
+ */
57
+ declare function resolveOpenjdk(version: string, options?: ResolveOpenjdkOptions): Promise<JavaRelease>;
58
+ //#endregion
59
+ //#region lib/template.d.ts
60
+ interface JavaOptions {
61
+ /**
62
+ * OpenJDK version. Accepts:
63
+ * - Major: `'21'` — resolves to the latest GA for that major.
64
+ * - Full version: `'21.0.11+10'` — exact Adoptium release name (`jdk-…` prefix and `-LTS` suffix are tolerated).
65
+ */
66
+ version: string;
67
+ /** Distribution to fetch from. Only `'openjdk'` (Eclipse Temurin) is supported today. */
68
+ vendor?: 'openjdk';
69
+ /** Override the platform set. Default covers linux/osx/windows × x86_64+aarch64. */
70
+ platforms?: readonly JavaPlatform[];
71
+ /** Optional override for the Adoptium API base URL. */
72
+ apiBase?: string;
73
+ }
74
+ interface JavaTemplate {
75
+ /** Per-platform JDK archives, scoped by OS+arch rules and extracted on first install. */
76
+ artifacts: Artifact[];
77
+ /** `java_home` and `java_bin` per OS — spread into your loader's vars. */
78
+ vars: ValDefs;
79
+ /** Resolved release metadata. */
80
+ release: JavaRelease;
81
+ }
82
+ /**
83
+ * Build a opys template fragment that auto-installs an OpenJDK runtime
84
+ * (Eclipse Temurin) and exposes `${java_home}` + `${java_bin}` vars.
85
+ *
86
+ * Each platform's archive is emitted as its own `Artifact` with an
87
+ * OS+arch rule, so only the matching binary downloads at install time.
88
+ * The archive is extracted into `${root}/runtimes/jdk-<major>/`, with
89
+ * the Adoptium release directory as the immediate child (e.g.
90
+ * `jdk-21.0.11+10/`). On macOS, `${java_home}` includes the
91
+ * `/Contents/Home` suffix that Mac JDK bundles use.
92
+ *
93
+ * Spread the result into your loader's vars + artifacts:
94
+ *
95
+ * ```ts
96
+ * const jav = await resolveJava({ version: '21' });
97
+ * return {
98
+ * artifacts: [lw.artifacts, jav.artifacts],
99
+ * vars: { ...lw.vars, ...jav.vars },
100
+ * command: lw.command, // command.command is `${java_bin}` already
101
+ * };
102
+ * ```
103
+ */
104
+ declare function resolveJava(options: JavaOptions): Promise<JavaTemplate>;
105
+ //#endregion
106
+ //#region lib/plugin.d.ts
107
+ /**
108
+ * Provision an OpenJDK runtime (Eclipse Temurin). Solely owns the
109
+ * `java_home` / `java_bin` vars and exposes `bin` as a launch group, so a
110
+ * config wires the launch command with `command: ({ java }) => java.bin`.
111
+ */
112
+ declare function java(version: string, opts?: Omit<JavaOptions, 'version'>): OpysPlugin;
113
+ //#endregion
114
+ export { DEFAULT_PLATFORMS, type JavaBinary, type JavaOptions, type JavaPlatform, type JavaRelease, type JavaTemplate, type ResolveOpenjdkOptions, java, resolveJava, resolveOpenjdk };
115
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../lib/resolver.ts","../lib/template.ts","../lib/plugin.ts"],"mappings":";;;;;UAyBiB,YAAA;;WAEN,EAAA,EAAI,MAAA;EAFc;EAAA,SAIlB,IAAA,EAAM,MAAA;EAAM;EAAA,SAEZ,UAAA;EAJI;EAAA,SAMJ,YAAA;EAJM;;;;EAAA,SASN,UAAA;AAAA;AAAA,cAGE,iBAAA,WAA4B,YAAA;;UA8CxB,UAAA;EAAA,SACN,QAAA,EAAU,YAAA;EA/CgC;EAAA,SAiD1C,QAAA;EAHgB;EAAA,SAKhB,GAAA;EAJsB;EAAA,SAMtB,IAAA;EANU;EAAA,SAQV,MAAA;AAAA;AAAA,UAGM,WAAA;EAHN;EAAA,SAKA,WAAA;EALM;EAAA,SAON,UAAA;EAJiB;EAAA,SAMjB,KAAA;EAEoB;EAAA,SAApB,QAAA,EAAU,UAAA;AAAA;AAAA,UAGJ,qBAAA;EAHN;EAKT,SAAA,YAAqB,YAAA;EALQ;EAO7B,OAAA;AAAA;;;;;;;;iBA6FoB,cAAA,CACpB,OAAA,UACA,OAAA,GAAS,qBAAA,GACR,OAAA,CAAQ,WAAA;;;UCnMM,WAAA;;ADUjB;;;;ECJE,OAAA;EDMa;ECJb,MAAA;EDMe;ECJf,SAAA,YAAqB,YAAA;EDQZ;ECNT,OAAA;AAAA;AAAA,UAGe,YAAA;EDWJ;ECTX,SAAA,EAAW,QAAA;;EAEX,IAAA,EAAM,OAAA;EDO6C;ECLnD,OAAA,EAAS,WAAA;AAAA;;;;;;;;;;;AD+DX;;;;;;;;;;;AAWA;iBCtCsB,WAAA,CAAY,OAAA,EAAS,WAAA,GAAc,OAAA,CAAQ,YAAA;;;;;AD/CjE;;;iBEjBgB,IAAA,CACd,OAAA,UACA,IAAA,GAAM,IAAA,CAAK,WAAA,eACV,UAAA"}
@@ -0,0 +1,115 @@
1
+ import { OpysPlugin } from "@opys/dev";
2
+ import { Artifact, OsArch, OsName, ValDefs } from "@opys/core";
3
+
4
+ //#region lib/resolver.d.ts
5
+ /** Adoptium-side platform descriptor + how it maps onto opys's OS/arch enums. */
6
+ interface JavaPlatform {
7
+ /** opys OS name. */
8
+ readonly os: OsName;
9
+ /** opys arch. `x86_64` is Adoptium's `x64`. */
10
+ readonly arch: OsArch;
11
+ /** Adoptium API `os` value (`linux`, `mac`, `windows`). */
12
+ readonly adoptiumOs: 'linux' | 'mac' | 'windows';
13
+ /** Adoptium API `architecture` value. */
14
+ readonly adoptiumArch: 'x64' | 'aarch64';
15
+ /**
16
+ * Path appended to the extracted top-level directory to reach JAVA_HOME.
17
+ * Empty on Linux/Windows; `/Contents/Home` on macOS bundles.
18
+ */
19
+ readonly homeSuffix: string;
20
+ }
21
+ declare const DEFAULT_PLATFORMS: readonly JavaPlatform[];
22
+ /** A resolved binary for one (os, arch) platform. */
23
+ interface JavaBinary {
24
+ readonly platform: JavaPlatform;
25
+ /** Asset filename, e.g. `OpenJDK21U-jdk_x64_linux_hotspot_21.0.11_10.tar.gz`. */
26
+ readonly filename: string;
27
+ /** Direct download URL (GitHub release asset). */
28
+ readonly url: string;
29
+ /** Asset size in bytes. */
30
+ readonly size: number;
31
+ /** sha256 of the asset (hex). */
32
+ readonly sha256: string;
33
+ }
34
+ interface JavaRelease {
35
+ /** Adoptium release name, e.g. `jdk-21.0.11+10`. */
36
+ readonly releaseName: string;
37
+ /** Top-level directory after extraction (matches `releaseName`). */
38
+ readonly extractDir: string;
39
+ /** Major version, e.g. `21`. */
40
+ readonly major: number;
41
+ /** Per-platform binaries that exist for this release. */
42
+ readonly binaries: JavaBinary[];
43
+ }
44
+ interface ResolveOpenjdkOptions {
45
+ /** Override the platform set. Default: linux/mac/windows × x64+aarch64. */
46
+ platforms?: readonly JavaPlatform[];
47
+ /** Optional override for the Adoptium API base URL. */
48
+ apiBase?: string;
49
+ }
50
+ /**
51
+ * Resolve an OpenJDK release across all requested platforms. Returns a
52
+ * single `JavaRelease` with one entry per platform that has a binary
53
+ * available — platforms that don't ship a build for this release are
54
+ * silently dropped from `binaries`, so callers don't have to handle the
55
+ * "linux x64 exists, windows aarch64 doesn't" case explicitly.
56
+ */
57
+ declare function resolveOpenjdk(version: string, options?: ResolveOpenjdkOptions): Promise<JavaRelease>;
58
+ //#endregion
59
+ //#region lib/template.d.ts
60
+ interface JavaOptions {
61
+ /**
62
+ * OpenJDK version. Accepts:
63
+ * - Major: `'21'` — resolves to the latest GA for that major.
64
+ * - Full version: `'21.0.11+10'` — exact Adoptium release name (`jdk-…` prefix and `-LTS` suffix are tolerated).
65
+ */
66
+ version: string;
67
+ /** Distribution to fetch from. Only `'openjdk'` (Eclipse Temurin) is supported today. */
68
+ vendor?: 'openjdk';
69
+ /** Override the platform set. Default covers linux/osx/windows × x86_64+aarch64. */
70
+ platforms?: readonly JavaPlatform[];
71
+ /** Optional override for the Adoptium API base URL. */
72
+ apiBase?: string;
73
+ }
74
+ interface JavaTemplate {
75
+ /** Per-platform JDK archives, scoped by OS+arch rules and extracted on first install. */
76
+ artifacts: Artifact[];
77
+ /** `java_home` and `java_bin` per OS — spread into your loader's vars. */
78
+ vars: ValDefs;
79
+ /** Resolved release metadata. */
80
+ release: JavaRelease;
81
+ }
82
+ /**
83
+ * Build a opys template fragment that auto-installs an OpenJDK runtime
84
+ * (Eclipse Temurin) and exposes `${java_home}` + `${java_bin}` vars.
85
+ *
86
+ * Each platform's archive is emitted as its own `Artifact` with an
87
+ * OS+arch rule, so only the matching binary downloads at install time.
88
+ * The archive is extracted into `${root}/runtimes/jdk-<major>/`, with
89
+ * the Adoptium release directory as the immediate child (e.g.
90
+ * `jdk-21.0.11+10/`). On macOS, `${java_home}` includes the
91
+ * `/Contents/Home` suffix that Mac JDK bundles use.
92
+ *
93
+ * Spread the result into your loader's vars + artifacts:
94
+ *
95
+ * ```ts
96
+ * const jav = await resolveJava({ version: '21' });
97
+ * return {
98
+ * artifacts: [lw.artifacts, jav.artifacts],
99
+ * vars: { ...lw.vars, ...jav.vars },
100
+ * command: lw.command, // command.command is `${java_bin}` already
101
+ * };
102
+ * ```
103
+ */
104
+ declare function resolveJava(options: JavaOptions): Promise<JavaTemplate>;
105
+ //#endregion
106
+ //#region lib/plugin.d.ts
107
+ /**
108
+ * Provision an OpenJDK runtime (Eclipse Temurin). Solely owns the
109
+ * `java_home` / `java_bin` vars and exposes `bin` as a launch group, so a
110
+ * config wires the launch command with `command: ({ java }) => java.bin`.
111
+ */
112
+ declare function java(version: string, opts?: Omit<JavaOptions, 'version'>): OpysPlugin;
113
+ //#endregion
114
+ export { DEFAULT_PLATFORMS, type JavaBinary, type JavaOptions, type JavaPlatform, type JavaRelease, type JavaTemplate, type ResolveOpenjdkOptions, java, resolveJava, resolveOpenjdk };
115
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../lib/resolver.ts","../lib/template.ts","../lib/plugin.ts"],"mappings":";;;;;UAyBiB,YAAA;;WAEN,EAAA,EAAI,MAAA;EAFc;EAAA,SAIlB,IAAA,EAAM,MAAA;EAAM;EAAA,SAEZ,UAAA;EAJI;EAAA,SAMJ,YAAA;EAJM;;;;EAAA,SASN,UAAA;AAAA;AAAA,cAGE,iBAAA,WAA4B,YAAA;;UA8CxB,UAAA;EAAA,SACN,QAAA,EAAU,YAAA;EA/CgC;EAAA,SAiD1C,QAAA;EAHgB;EAAA,SAKhB,GAAA;EAJsB;EAAA,SAMtB,IAAA;EANU;EAAA,SAQV,MAAA;AAAA;AAAA,UAGM,WAAA;EAHN;EAAA,SAKA,WAAA;EALM;EAAA,SAON,UAAA;EAJiB;EAAA,SAMjB,KAAA;EAEoB;EAAA,SAApB,QAAA,EAAU,UAAA;AAAA;AAAA,UAGJ,qBAAA;EAHN;EAKT,SAAA,YAAqB,YAAA;EALQ;EAO7B,OAAA;AAAA;;;;;;;;iBA6FoB,cAAA,CACpB,OAAA,UACA,OAAA,GAAS,qBAAA,GACR,OAAA,CAAQ,WAAA;;;UCnMM,WAAA;;ADUjB;;;;ECJE,OAAA;EDMa;ECJb,MAAA;EDMe;ECJf,SAAA,YAAqB,YAAA;EDQZ;ECNT,OAAA;AAAA;AAAA,UAGe,YAAA;EDWJ;ECTX,SAAA,EAAW,QAAA;;EAEX,IAAA,EAAM,OAAA;EDO6C;ECLnD,OAAA,EAAS,WAAA;AAAA;;;;;;;;;;;AD+DX;;;;;;;;;;;AAWA;iBCtCsB,WAAA,CAAY,OAAA,EAAS,WAAA,GAAc,OAAA,CAAQ,YAAA;;;;;AD/CjE;;;iBEjBgB,IAAA,CACd,OAAA,UACA,IAAA,GAAM,IAAA,CAAK,WAAA,eACV,UAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,254 @@
1
+ import { definePlugin } from "@opys/dev";
2
+ import { extractDump, fetchWithRetry, sourceUrl } from "@opys/core";
3
+
4
+ //#region lib/resolver.ts
5
+ /**
6
+ * Resolver for OpenJDK builds from the Eclipse Adoptium (Temurin) distribution.
7
+ *
8
+ * Adoptium publishes a public asset API at `https://api.adoptium.net/v3/`.
9
+ * We use two endpoints depending on the version input shape:
10
+ *
11
+ * - Major-only (`'21'`, `'17'`) → `/feature_releases/<major>/ga` (latest GA)
12
+ * - Full version → `/release_name/<vendor>/<release-name>`
13
+ * (exact, pinned build). Adoptium release names differ by line — Java 8
14
+ * is `jdk8u<update>-b<build>` (no hyphen), Java 9+ is `jdk-<version>`.
15
+ * A full input is accepted bare (`'8u492-b09'`, `'21.0.13+11'`) or as a
16
+ * complete release name (`'jdk8u492-b09'`, `'jdk-21.0.13+11'`).
17
+ *
18
+ * Each platform (os × arch) is queried separately with `image_type=jdk` and
19
+ * `jvm_impl=hotspot`. Releases that don't ship a binary for a given platform
20
+ * are soft-skipped — the resulting `JavaRelease` only contains the platforms
21
+ * with a real binary.
22
+ */
23
+ const ADOPTIUM_BASE = "https://api.adoptium.net/v3";
24
+ const VENDOR = "eclipse";
25
+ const DEFAULT_PLATFORMS = [
26
+ {
27
+ os: "linux",
28
+ arch: "x86_64",
29
+ adoptiumOs: "linux",
30
+ adoptiumArch: "x64",
31
+ homeSuffix: ""
32
+ },
33
+ {
34
+ os: "linux",
35
+ arch: "aarch64",
36
+ adoptiumOs: "linux",
37
+ adoptiumArch: "aarch64",
38
+ homeSuffix: ""
39
+ },
40
+ {
41
+ os: "osx",
42
+ arch: "x86_64",
43
+ adoptiumOs: "mac",
44
+ adoptiumArch: "x64",
45
+ homeSuffix: "/Contents/Home"
46
+ },
47
+ {
48
+ os: "osx",
49
+ arch: "aarch64",
50
+ adoptiumOs: "mac",
51
+ adoptiumArch: "aarch64",
52
+ homeSuffix: "/Contents/Home"
53
+ },
54
+ {
55
+ os: "windows",
56
+ arch: "x86_64",
57
+ adoptiumOs: "windows",
58
+ adoptiumArch: "x64",
59
+ homeSuffix: ""
60
+ },
61
+ {
62
+ os: "windows",
63
+ arch: "aarch64",
64
+ adoptiumOs: "windows",
65
+ adoptiumArch: "aarch64",
66
+ homeSuffix: ""
67
+ }
68
+ ];
69
+ function normalizeInput(input) {
70
+ const v = input.trim().replace(/-LTS$/, "");
71
+ if (/^\d+$/.test(v)) return {
72
+ kind: "major",
73
+ raw: v
74
+ };
75
+ if (v.startsWith("jdk")) return {
76
+ kind: "full",
77
+ raw: v
78
+ };
79
+ return {
80
+ kind: "full",
81
+ raw: /^\d+u/.test(v) ? `jdk${v}` : `jdk-${v}`
82
+ };
83
+ }
84
+ function adoptiumQuery(platform) {
85
+ return new URLSearchParams({
86
+ image_type: "jdk",
87
+ architecture: platform.adoptiumArch,
88
+ os: platform.adoptiumOs,
89
+ jvm_impl: "hotspot",
90
+ heap_size: "normal",
91
+ vendor: VENDOR
92
+ }).toString();
93
+ }
94
+ async function fetchPlatform(apiBase, platform, version) {
95
+ const res = await fetchWithRetry(`${apiBase}${version.kind === "major" ? `/assets/feature_releases/${version.raw}/ga?${adoptiumQuery(platform)}&page_size=1&sort_order=DESC` : `/assets/release_name/${VENDOR}/${encodeURIComponent(version.raw)}?${adoptiumQuery(platform)}`}`, { headers: { Accept: "application/json" } });
96
+ if (res.status === 404) return null;
97
+ if (!res.ok) throw new Error(`Adoptium API ${res.status} ${res.statusText} for ${platform.adoptiumOs}/${platform.adoptiumArch}`);
98
+ const body = await res.json();
99
+ const release = Array.isArray(body) ? body[0] : body;
100
+ if (!release || !release.binaries || release.binaries.length === 0) return null;
101
+ const binary = release.binaries.find((b) => b.architecture === platform.adoptiumArch && b.os === platform.adoptiumOs && b.image_type === "jdk");
102
+ if (!binary) return null;
103
+ return {
104
+ release,
105
+ binary
106
+ };
107
+ }
108
+ /**
109
+ * Resolve an OpenJDK release across all requested platforms. Returns a
110
+ * single `JavaRelease` with one entry per platform that has a binary
111
+ * available — platforms that don't ship a build for this release are
112
+ * silently dropped from `binaries`, so callers don't have to handle the
113
+ * "linux x64 exists, windows aarch64 doesn't" case explicitly.
114
+ */
115
+ async function resolveOpenjdk(version, options = {}) {
116
+ const apiBase = options.apiBase ?? ADOPTIUM_BASE;
117
+ const platforms = options.platforms ?? DEFAULT_PLATFORMS;
118
+ const parsed = normalizeInput(version);
119
+ const matched = (await Promise.all(platforms.map(async (p) => {
120
+ const found = await fetchPlatform(apiBase, p, parsed);
121
+ return found ? {
122
+ platform: p,
123
+ ...found
124
+ } : null;
125
+ }))).filter((x) => x !== null);
126
+ if (matched.length === 0) throw new Error(`No OpenJDK binaries found for version '${version}' across requested platforms.`);
127
+ const nameCounts = /* @__PURE__ */ new Map();
128
+ for (const m of matched) nameCounts.set(m.release.release_name, (nameCounts.get(m.release.release_name) ?? 0) + 1);
129
+ const releaseName = [...nameCounts.entries()].sort((a, b) => b[1] - a[1] || b[0].localeCompare(a[0]))[0][0];
130
+ const consistent = matched.filter((m) => m.release.release_name === releaseName);
131
+ const binaries = consistent.map((m) => ({
132
+ platform: m.platform,
133
+ filename: m.binary.package.name,
134
+ url: m.binary.package.link,
135
+ size: m.binary.package.size,
136
+ sha256: m.binary.package.checksum
137
+ }));
138
+ return {
139
+ releaseName,
140
+ extractDir: releaseName,
141
+ major: consistent[0].release.version_data.major,
142
+ binaries
143
+ };
144
+ }
145
+
146
+ //#endregion
147
+ //#region lib/template.ts
148
+ function osArchRuleset(os, arch) {
149
+ return [{
150
+ action: "allow",
151
+ os: { name: os }
152
+ }, {
153
+ action: "allow",
154
+ os: { arch }
155
+ }];
156
+ }
157
+ function osRuleset(os) {
158
+ return [{
159
+ action: "allow",
160
+ os: { name: os }
161
+ }];
162
+ }
163
+ /**
164
+ * Build a opys template fragment that auto-installs an OpenJDK runtime
165
+ * (Eclipse Temurin) and exposes `${java_home}` + `${java_bin}` vars.
166
+ *
167
+ * Each platform's archive is emitted as its own `Artifact` with an
168
+ * OS+arch rule, so only the matching binary downloads at install time.
169
+ * The archive is extracted into `${root}/runtimes/jdk-<major>/`, with
170
+ * the Adoptium release directory as the immediate child (e.g.
171
+ * `jdk-21.0.11+10/`). On macOS, `${java_home}` includes the
172
+ * `/Contents/Home` suffix that Mac JDK bundles use.
173
+ *
174
+ * Spread the result into your loader's vars + artifacts:
175
+ *
176
+ * ```ts
177
+ * const jav = await resolveJava({ version: '21' });
178
+ * return {
179
+ * artifacts: [lw.artifacts, jav.artifacts],
180
+ * vars: { ...lw.vars, ...jav.vars },
181
+ * command: lw.command, // command.command is `${java_bin}` already
182
+ * };
183
+ * ```
184
+ */
185
+ async function resolveJava(options) {
186
+ if (options.vendor && options.vendor !== "openjdk") throw new Error(`@opys/java: vendor '${options.vendor}' is not yet supported (only 'openjdk').`);
187
+ const release = await resolveOpenjdk(options.version, {
188
+ platforms: options.platforms,
189
+ apiBase: options.apiBase
190
+ });
191
+ const javaRoot = `\${java_runtime_dir}/jdk-${release.major}`;
192
+ const artifacts = release.binaries.map((b) => ({
193
+ path: `\${java_runtime_dir}/${b.filename}`,
194
+ source: sourceUrl(b.url),
195
+ size: b.size,
196
+ rules: osArchRuleset(b.platform.os, b.platform.arch),
197
+ integrity: { sha256: b.sha256 },
198
+ extract: [extractDump(javaRoot)]
199
+ }));
200
+ const seenOses = new Set(release.binaries.map((b) => b.platform.os));
201
+ const javaHomeArms = [];
202
+ const javaBinArms = [];
203
+ for (const os of seenOses) {
204
+ const platform = release.binaries.find((b) => b.platform.os === os).platform;
205
+ const home = `${javaRoot}/${release.extractDir}${platform.homeSuffix}`;
206
+ javaHomeArms.push({
207
+ value: home,
208
+ rules: osRuleset(os)
209
+ });
210
+ const exe = os === "windows" ? "java.exe" : "java";
211
+ javaBinArms.push({
212
+ value: `\${java_home}/bin/${exe}`,
213
+ rules: osRuleset(os)
214
+ });
215
+ }
216
+ return {
217
+ artifacts,
218
+ vars: {
219
+ java_runtime_dir: "${root}/runtimes",
220
+ java_home: javaHomeArms,
221
+ java_bin: javaBinArms
222
+ },
223
+ release
224
+ };
225
+ }
226
+
227
+ //#endregion
228
+ //#region lib/plugin.ts
229
+ /**
230
+ * Provision an OpenJDK runtime (Eclipse Temurin). Solely owns the
231
+ * `java_home` / `java_bin` vars and exposes `bin` as a launch group, so a
232
+ * config wires the launch command with `command: ({ java }) => java.bin`.
233
+ */
234
+ function java(version, opts = {}) {
235
+ return definePlugin({
236
+ name: "java",
237
+ async build(ctx) {
238
+ const t = await resolveJava({
239
+ version,
240
+ ...opts
241
+ });
242
+ ctx.log("java", `OpenJDK ${t.release.releaseName.replace(/^jdk-?/, "")}`);
243
+ return {
244
+ artifacts: t.artifacts,
245
+ vars: t.vars,
246
+ launch: { bin: "${java_bin}" }
247
+ };
248
+ }
249
+ });
250
+ }
251
+
252
+ //#endregion
253
+ export { DEFAULT_PLATFORMS, java, resolveJava, resolveOpenjdk };
254
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../lib/resolver.ts","../lib/template.ts","../lib/plugin.ts"],"sourcesContent":["/**\n * Resolver for OpenJDK builds from the Eclipse Adoptium (Temurin) distribution.\n *\n * Adoptium publishes a public asset API at `https://api.adoptium.net/v3/`.\n * We use two endpoints depending on the version input shape:\n *\n * - Major-only (`'21'`, `'17'`) → `/feature_releases/<major>/ga` (latest GA)\n * - Full version → `/release_name/<vendor>/<release-name>`\n * (exact, pinned build). Adoptium release names differ by line — Java 8\n * is `jdk8u<update>-b<build>` (no hyphen), Java 9+ is `jdk-<version>`.\n * A full input is accepted bare (`'8u492-b09'`, `'21.0.13+11'`) or as a\n * complete release name (`'jdk8u492-b09'`, `'jdk-21.0.13+11'`).\n *\n * Each platform (os × arch) is queried separately with `image_type=jdk` and\n * `jvm_impl=hotspot`. Releases that don't ship a binary for a given platform\n * are soft-skipped — the resulting `JavaRelease` only contains the platforms\n * with a real binary.\n */\nimport { fetchWithRetry } from '@opys/core';\nimport type { OsName, OsArch } from '@opys/core';\n\nconst ADOPTIUM_BASE = 'https://api.adoptium.net/v3';\nconst VENDOR = 'eclipse';\n\n/** Adoptium-side platform descriptor + how it maps onto opys's OS/arch enums. */\nexport interface JavaPlatform {\n /** opys OS name. */\n readonly os: OsName;\n /** opys arch. `x86_64` is Adoptium's `x64`. */\n readonly arch: OsArch;\n /** Adoptium API `os` value (`linux`, `mac`, `windows`). */\n readonly adoptiumOs: 'linux' | 'mac' | 'windows';\n /** Adoptium API `architecture` value. */\n readonly adoptiumArch: 'x64' | 'aarch64';\n /**\n * Path appended to the extracted top-level directory to reach JAVA_HOME.\n * Empty on Linux/Windows; `/Contents/Home` on macOS bundles.\n */\n readonly homeSuffix: string;\n}\n\nexport const DEFAULT_PLATFORMS: readonly JavaPlatform[] = [\n {\n os: 'linux',\n arch: 'x86_64',\n adoptiumOs: 'linux',\n adoptiumArch: 'x64',\n homeSuffix: '',\n },\n {\n os: 'linux',\n arch: 'aarch64',\n adoptiumOs: 'linux',\n adoptiumArch: 'aarch64',\n homeSuffix: '',\n },\n {\n os: 'osx',\n arch: 'x86_64',\n adoptiumOs: 'mac',\n adoptiumArch: 'x64',\n homeSuffix: '/Contents/Home',\n },\n {\n os: 'osx',\n arch: 'aarch64',\n adoptiumOs: 'mac',\n adoptiumArch: 'aarch64',\n homeSuffix: '/Contents/Home',\n },\n {\n os: 'windows',\n arch: 'x86_64',\n adoptiumOs: 'windows',\n adoptiumArch: 'x64',\n homeSuffix: '',\n },\n {\n os: 'windows',\n arch: 'aarch64',\n adoptiumOs: 'windows',\n adoptiumArch: 'aarch64',\n homeSuffix: '',\n },\n];\n\n/** A resolved binary for one (os, arch) platform. */\nexport interface JavaBinary {\n readonly platform: JavaPlatform;\n /** Asset filename, e.g. `OpenJDK21U-jdk_x64_linux_hotspot_21.0.11_10.tar.gz`. */\n readonly filename: string;\n /** Direct download URL (GitHub release asset). */\n readonly url: string;\n /** Asset size in bytes. */\n readonly size: number;\n /** sha256 of the asset (hex). */\n readonly sha256: string;\n}\n\nexport interface JavaRelease {\n /** Adoptium release name, e.g. `jdk-21.0.11+10`. */\n readonly releaseName: string;\n /** Top-level directory after extraction (matches `releaseName`). */\n readonly extractDir: string;\n /** Major version, e.g. `21`. */\n readonly major: number;\n /** Per-platform binaries that exist for this release. */\n readonly binaries: JavaBinary[];\n}\n\nexport interface ResolveOpenjdkOptions {\n /** Override the platform set. Default: linux/mac/windows × x64+aarch64. */\n platforms?: readonly JavaPlatform[];\n /** Optional override for the Adoptium API base URL. */\n apiBase?: string;\n}\n\ninterface AdoptiumPackage {\n checksum: string;\n link: string;\n name: string;\n size: number;\n}\n\ninterface AdoptiumBinary {\n architecture: string;\n os: string;\n image_type: string;\n jvm_impl: string;\n package: AdoptiumPackage;\n}\n\ninterface AdoptiumRelease {\n release_name: string;\n binaries: AdoptiumBinary[];\n version_data: { major: number };\n}\n\n/** Normalized version input: a bare major, or a full Adoptium version. */\ntype VersionInput = { kind: 'major' | 'full'; raw: string };\n\nfunction normalizeInput(input: string): VersionInput {\n const v = input.trim().replace(/-LTS$/, '');\n if (/^\\d+$/.test(v)) return { kind: 'major', raw: v };\n // A `full` input resolves to an exact Adoptium release name. A value that\n // already carries the `jdk` prefix is a complete release name; a bare\n // version is prefixed to match — `jdk` (no hyphen) for the Java 8\n // `8u…-b…` form, `jdk-` for the Java 9+ `<major>.<minor>.<patch>+<build>`.\n if (v.startsWith('jdk')) return { kind: 'full', raw: v };\n return { kind: 'full', raw: /^\\d+u/.test(v) ? `jdk${v}` : `jdk-${v}` };\n}\n\nfunction adoptiumQuery(platform: JavaPlatform): string {\n const params = new URLSearchParams({\n image_type: 'jdk',\n architecture: platform.adoptiumArch,\n os: platform.adoptiumOs,\n jvm_impl: 'hotspot',\n // `heap_size=normal` excludes the `large` (huge-pages) variant;\n // `vendor=eclipse` pins the distribution to Temurin.\n heap_size: 'normal',\n vendor: VENDOR,\n });\n return params.toString();\n}\n\nasync function fetchPlatform(\n apiBase: string,\n platform: JavaPlatform,\n version: VersionInput,\n): Promise<{ release: AdoptiumRelease; binary: AdoptiumBinary } | null> {\n const path =\n version.kind === 'major'\n ? `/assets/feature_releases/${version.raw}/ga?${adoptiumQuery(platform)}&page_size=1&sort_order=DESC`\n : `/assets/release_name/${VENDOR}/${encodeURIComponent(version.raw)}?${adoptiumQuery(platform)}`;\n\n const url = `${apiBase}${path}`;\n const res = await fetchWithRetry(url, {\n headers: { Accept: 'application/json' },\n });\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(\n `Adoptium API ${res.status} ${res.statusText} for ${platform.adoptiumOs}/${platform.adoptiumArch}`,\n );\n }\n const body = (await res.json()) as AdoptiumRelease | AdoptiumRelease[];\n const release = Array.isArray(body) ? body[0] : body;\n if (!release || !release.binaries || release.binaries.length === 0)\n return null;\n const binary = release.binaries.find(\n (b) =>\n b.architecture === platform.adoptiumArch &&\n b.os === platform.adoptiumOs &&\n b.image_type === 'jdk',\n );\n if (!binary) return null;\n return { release, binary };\n}\n\n/**\n * Resolve an OpenJDK release across all requested platforms. Returns a\n * single `JavaRelease` with one entry per platform that has a binary\n * available — platforms that don't ship a build for this release are\n * silently dropped from `binaries`, so callers don't have to handle the\n * \"linux x64 exists, windows aarch64 doesn't\" case explicitly.\n */\nexport async function resolveOpenjdk(\n version: string,\n options: ResolveOpenjdkOptions = {},\n): Promise<JavaRelease> {\n const apiBase = options.apiBase ?? ADOPTIUM_BASE;\n const platforms = options.platforms ?? DEFAULT_PLATFORMS;\n const parsed = normalizeInput(version);\n\n const fetched = await Promise.all(\n platforms.map(async (p) => {\n const found = await fetchPlatform(apiBase, p, parsed);\n return found ? { platform: p, ...found } : null;\n }),\n );\n\n const matched = fetched.filter((x): x is NonNullable<typeof x> => x !== null);\n if (matched.length === 0) {\n throw new Error(\n `No OpenJDK binaries found for version '${version}' across requested platforms.`,\n );\n }\n\n // All platforms should agree on release_name when querying a specific\n // release_name; for major queries each platform may resolve to a\n // different latest GA — we anchor to the most-common release_name to\n // keep the bundle coherent (and skip mismatched binaries).\n const nameCounts = new Map<string, number>();\n for (const m of matched) {\n nameCounts.set(\n m.release.release_name,\n (nameCounts.get(m.release.release_name) ?? 0) + 1,\n );\n }\n // count desc, then newest/lexicographically-largest release name wins on a tie\n const releaseName = [...nameCounts.entries()].sort(\n (a, b) => b[1] - a[1] || b[0].localeCompare(a[0]),\n )[0]![0];\n\n const consistent = matched.filter(\n (m) => m.release.release_name === releaseName,\n );\n\n const binaries: JavaBinary[] = consistent.map((m) => ({\n platform: m.platform,\n filename: m.binary.package.name,\n url: m.binary.package.link,\n size: m.binary.package.size,\n sha256: m.binary.package.checksum,\n }));\n\n return {\n releaseName,\n extractDir: releaseName,\n major: consistent[0]!.release.version_data.major,\n binaries,\n };\n}\n","import {\n type Artifact,\n type ValDefs,\n type ConditionalVal,\n sourceUrl,\n extractDump,\n} from '@opys/core';\nimport type { OsName, OsArch, Ruleset } from '@opys/core';\nimport {\n resolveOpenjdk,\n type JavaPlatform,\n type JavaRelease,\n type ResolveOpenjdkOptions,\n} from './resolver';\n\nexport interface JavaOptions {\n /**\n * OpenJDK version. Accepts:\n * - Major: `'21'` — resolves to the latest GA for that major.\n * - Full version: `'21.0.11+10'` — exact Adoptium release name (`jdk-…` prefix and `-LTS` suffix are tolerated).\n */\n version: string;\n /** Distribution to fetch from. Only `'openjdk'` (Eclipse Temurin) is supported today. */\n vendor?: 'openjdk';\n /** Override the platform set. Default covers linux/osx/windows × x86_64+aarch64. */\n platforms?: readonly JavaPlatform[];\n /** Optional override for the Adoptium API base URL. */\n apiBase?: string;\n}\n\nexport interface JavaTemplate {\n /** Per-platform JDK archives, scoped by OS+arch rules and extracted on first install. */\n artifacts: Artifact[];\n /** `java_home` and `java_bin` per OS — spread into your loader's vars. */\n vars: ValDefs;\n /** Resolved release metadata. */\n release: JavaRelease;\n}\n\nfunction osArchRuleset(os: OsName, arch: OsArch): Ruleset {\n return [\n { action: 'allow', os: { name: os } },\n { action: 'allow', os: { arch } },\n ];\n}\n\nfunction osRuleset(os: OsName): Ruleset {\n return [{ action: 'allow', os: { name: os } }];\n}\n\n/**\n * Build a opys template fragment that auto-installs an OpenJDK runtime\n * (Eclipse Temurin) and exposes `${java_home}` + `${java_bin}` vars.\n *\n * Each platform's archive is emitted as its own `Artifact` with an\n * OS+arch rule, so only the matching binary downloads at install time.\n * The archive is extracted into `${root}/runtimes/jdk-<major>/`, with\n * the Adoptium release directory as the immediate child (e.g.\n * `jdk-21.0.11+10/`). On macOS, `${java_home}` includes the\n * `/Contents/Home` suffix that Mac JDK bundles use.\n *\n * Spread the result into your loader's vars + artifacts:\n *\n * ```ts\n * const jav = await resolveJava({ version: '21' });\n * return {\n * artifacts: [lw.artifacts, jav.artifacts],\n * vars: { ...lw.vars, ...jav.vars },\n * command: lw.command, // command.command is `${java_bin}` already\n * };\n * ```\n */\nexport async function resolveJava(options: JavaOptions): Promise<JavaTemplate> {\n if (options.vendor && options.vendor !== 'openjdk') {\n throw new Error(\n `@opys/java: vendor '${options.vendor}' is not yet supported (only 'openjdk').`,\n );\n }\n const release = await resolveOpenjdk(options.version, {\n platforms: options.platforms,\n apiBase: options.apiBase,\n } satisfies ResolveOpenjdkOptions);\n\n // JDK runtimes install under the `java_runtime_dir` var (default\n // `${root}/runtimes`) — override it in the config's `vars` to relocate.\n // Archives download directly into it: a sibling of, never nested inside,\n // the extract target, so no `.cache` special-casing is needed.\n const javaRoot = `\\${java_runtime_dir}/jdk-${release.major}`;\n\n const artifacts: Artifact[] = release.binaries.map((b) => ({\n path: `\\${java_runtime_dir}/${b.filename}`,\n source: sourceUrl(b.url),\n size: b.size,\n rules: osArchRuleset(b.platform.os, b.platform.arch),\n integrity: { sha256: b.sha256 },\n extract: [extractDump(javaRoot)],\n }));\n\n // `java_home` only varies by OS (Linux/Windows have no suffix; macOS\n // bundles add `/Contents/Home`). Both x86_64 and aarch64 archives\n // extract to the same top-level directory, so we don't need to split\n // by arch here.\n const seenOses = new Set(release.binaries.map((b) => b.platform.os));\n const javaHomeArms: ConditionalVal[] = [];\n const javaBinArms: ConditionalVal[] = [];\n for (const os of seenOses) {\n const platform = release.binaries.find(\n (b) => b.platform.os === os,\n )!.platform;\n const home = `${javaRoot}/${release.extractDir}${platform.homeSuffix}`;\n javaHomeArms.push({ value: home, rules: osRuleset(os) });\n const exe = os === 'windows' ? 'java.exe' : 'java';\n javaBinArms.push({\n value: `\\${java_home}/bin/${exe}`,\n rules: osRuleset(os),\n });\n }\n\n const vars: ValDefs = {\n java_runtime_dir: '${root}/runtimes',\n java_home: javaHomeArms,\n java_bin: javaBinArms,\n };\n\n return { artifacts, vars, release };\n}\n","import { definePlugin, type OpysPlugin } from '@opys/dev';\nimport { resolveJava, type JavaOptions } from './template';\n\n/**\n * Provision an OpenJDK runtime (Eclipse Temurin). Solely owns the\n * `java_home` / `java_bin` vars and exposes `bin` as a launch group, so a\n * config wires the launch command with `command: ({ java }) => java.bin`.\n */\nexport function java(\n version: string,\n opts: Omit<JavaOptions, 'version'> = {},\n): OpysPlugin {\n return definePlugin({\n name: 'java',\n async build(ctx) {\n const t = await resolveJava({ version, ...opts });\n // The resolved build, e.g. `OpenJDK 21.0.13+11` / `OpenJDK 8u492-b09`.\n ctx.log('java', `OpenJDK ${t.release.releaseName.replace(/^jdk-?/, '')}`);\n return {\n artifacts: t.artifacts,\n vars: t.vars,\n launch: { bin: '${java_bin}' },\n };\n },\n });\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@opys/java",
3
+ "version": "0.1.2",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/index.mjs",
9
+ "require": "./dist/index.cjs"
10
+ }
11
+ },
12
+ "scripts": {
13
+ "build": "tsdown lib/index.ts --format esm,cjs --dts --clean",
14
+ "typecheck": "tsc --noEmit -p tsconfig.json",
15
+ "test": "vitest run tests/unit --passWithNoTests",
16
+ "test:int": "vitest run tests/integration --testTimeout=120000"
17
+ },
18
+ "dependencies": {
19
+ "@opys/core": "^0.1.2",
20
+ "@opys/dev": "^0.1.2"
21
+ },
22
+ "peerDependencies": {
23
+ "zod": "^4.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "tsdown": "*",
27
+ "vitest": "*"
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "engines": {
33
+ "node": ">=20"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/harmoniya-net/opys.git",
38
+ "directory": "packages/java"
39
+ }
40
+ }