@opentf/web-compiler 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,10 +12,9 @@ const bin = otfwcPath(); // absolute path to the otfwc executable for this platf
12
12
 
13
13
  This single package ships the `otfwc` binary for every supported platform,
14
14
  **brotli-compressed**, under `bin/<platform>-<arch>/otfwc[.exe].br` (~0.65 MB each
15
- vs ~2.3 MB raw). On install a `postinstall` script decompresses **only the host's**
16
- binary; `otfwcPath()` also decompresses lazily as a fallback (e.g. under
17
- `--ignore-scripts`) and returns the path matching the host
18
- (`process.platform-process.arch`).
15
+ vs ~2.3 MB raw). `otfwcPath()` decompresses **only the host's** binary lazily on
16
+ first use, so installation has no Node lifecycle hook, and returns the path
17
+ matching the host.
19
18
 
20
19
  Shipping all platforms in one package is cheaper to maintain than the per-platform
21
20
  optionalDependencies fan-out that rolldown/swc/esbuild use (their binaries are far
Binary file
Binary file
Binary file
Binary file
package/extract.js CHANGED
@@ -1,70 +1,77 @@
1
1
  //! Decompress the host's otfwc binary from its shipped brotli archive.
2
2
  //
3
3
  // The package ships one brotli-compressed binary per platform under
4
- // `bin/<platform>-<arch>/otfwc[.exe].br` (~0.65MB each vs ~2.3MB raw). On install
5
- // the postinstall script decompresses only the host's; `otfwcPath()` also does it
6
- // lazily as a fallback (e.g. when scripts are skipped with --ignore-scripts).
4
+ // `bin/<platform>-<arch>/otfwc[.exe].br` (~0.65MB each vs ~2.3MB raw).
5
+ // `otfwcPath()` decompresses the host's archive lazily on first use.
6
+ //
7
+ // It runs under the ES-Runtime alongside the rest of the toolchain, so package
8
+ // installation needs no Node lifecycle hook.
9
+
10
+ import { chmod, exists, file, write } from "runtime:fs";
11
+ import { dirname, fromFileURL, join } from "runtime:path";
12
+ import { arch, env, platform } from "runtime:process";
7
13
 
8
- import { existsSync, readFileSync, writeFileSync, chmodSync } from "node:fs";
9
- import { brotliDecompressSync } from "node:zlib";
10
- import { dirname, join } from "node:path";
11
- import { fileURLToPath } from "node:url";
14
+ const here = dirname(fromFileURL(import.meta.url));
12
15
 
13
- const here = dirname(fileURLToPath(import.meta.url));
16
+ // The shipped `bin/` subdirectories are named the way node reports a host, which is
17
+ // not how the runtime does; map onto them rather than renaming what we publish.
18
+ const OS_NAMES = { linux: "linux", macos: "darwin", windows: "win32" };
19
+ const ARCH_NAMES = { x86_64: "x64", aarch64: "arm64" };
14
20
 
15
- // `process.platform-process.arch` maps directly onto our bin/ subdirectory names.
16
- const SUPPORTED = new Set([
17
- "linux-x64",
18
- "darwin-x64",
19
- "darwin-arm64",
20
- "win32-x64",
21
- ]);
21
+ const SUPPORTED = new Set(["linux-x64", "darwin-x64", "darwin-arm64", "win32-x64"]);
22
22
 
23
- function hostBinPath() {
24
- const key = `${process.platform}-${process.arch}`;
23
+ function hostKey(platformName = platform, architecture = arch) {
24
+ const os = OS_NAMES[platformName];
25
+ const cpu = ARCH_NAMES[architecture];
26
+ return os && cpu ? `${os}-${cpu}` : `${platformName}-${architecture}`;
27
+ }
28
+
29
+ function hostBinPath({ binaryDir = here, os = platform, cpuArch = arch } = {}) {
30
+ const key = hostKey(os, cpuArch);
25
31
  if (!SUPPORTED.has(key)) return null;
26
- const bin = process.platform === "win32" ? "otfwc.exe" : "otfwc";
27
- return join(here, "bin", key, bin);
32
+ return join(binaryDir, "bin", key, os === "windows" ? "otfwc.exe" : "otfwc");
28
33
  }
29
34
 
30
35
  /** Decompress the host's `.br` archive to a runnable binary; returns its path. */
31
- function decompress(out) {
32
- const archive = `${out}.br`;
33
- writeFileSync(out, brotliDecompressSync(readFileSync(archive)));
34
- if (process.platform !== "win32") chmodSync(out, 0o755);
36
+ async function decompress(out, os = platform) {
37
+ const compressed = await file(`${out}.br`).stream();
38
+ const plain = compressed.pipeThrough(new DecompressionStream("brotli"));
39
+ await write(out, new Uint8Array(await new Response(plain).arrayBuffer()));
40
+ if (os !== "windows") await chmod(out, 0o755);
35
41
  return out;
36
42
  }
37
43
 
38
44
  /**
39
45
  * Best-effort: decompress the host binary if the archive is present. No-op (returns
40
- * null) on an unsupported platform or a source checkout without the `.br`. Used by
41
- * the postinstall script — never throws, so it can't break `npm install`.
46
+ * null) on an unsupported platform or a source checkout without the `.br`. Never
47
+ * throws — the caller falls back to reporting the missing binary itself.
42
48
  */
43
- export function extractIfPackaged() {
49
+ export async function extractIfPackaged() {
44
50
  const out = hostBinPath();
45
- if (!out || existsSync(out) || !existsSync(`${out}.br`)) return null;
51
+ if (!out) return null;
46
52
  try {
47
- return decompress(out);
53
+ if ((await exists(out)) || !(await exists(`${out}.br`))) return null;
54
+ return await decompress(out);
48
55
  } catch {
49
- return null; // lazy fallback in otfwcPath() will retry / surface the error
56
+ return null;
50
57
  }
51
58
  }
52
59
 
53
60
  /** Absolute path to the otfwc executable, or throw with a clear message. */
54
- export function otfwcPath() {
55
- if (process.env.OTFWC_BIN) {
56
- if (existsSync(process.env.OTFWC_BIN)) return process.env.OTFWC_BIN;
57
- throw new Error(`otfwc: OTFWC_BIN is set but ${process.env.OTFWC_BIN} does not exist`);
61
+ export async function otfwcPath({ binaryDir = here, environment = env, os = platform, cpuArch = arch } = {}) {
62
+ if (environment.OTFWC_BIN) {
63
+ if (await exists(environment.OTFWC_BIN)) return environment.OTFWC_BIN;
64
+ throw new Error(`otfwc: OTFWC_BIN is set but ${environment.OTFWC_BIN} does not exist`);
58
65
  }
59
- const out = hostBinPath();
66
+ const out = hostBinPath({ binaryDir, os, cpuArch });
60
67
  if (!out) {
61
68
  throw new Error(
62
- `otfwc: no prebuilt binary for ${process.platform}-${process.arch}. ` +
69
+ `otfwc: no prebuilt binary for ${hostKey(os, cpuArch)}. ` +
63
70
  `Supported: ${[...SUPPORTED].join(", ")}. Build from source and set OTFWC_BIN.`,
64
71
  );
65
72
  }
66
- if (existsSync(out)) return out;
67
- if (existsSync(`${out}.br`)) return decompress(out);
73
+ if (await exists(out)) return out;
74
+ if (await exists(`${out}.br`)) return decompress(out, os);
68
75
  throw new Error(
69
76
  `otfwc: prebuilt binary missing at ${out}. ` +
70
77
  `Reinstall @opentf/web-compiler, or set OTFWC_BIN.`,
package/package.json CHANGED
@@ -1,19 +1,15 @@
1
1
  {
2
2
  "name": "@opentf/web-compiler",
3
- "version": "0.17.0",
4
- "description": "OTF Web IR compiler (otfwc) — prebuilt platform binaries + host resolver (ARCHITECTURE.md §8).",
3
+ "version": "0.18.0",
4
+ "description": "OTF Web native toolchain (otfwc) — component compilation and documentation indexing in one platform binary.",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "exports": {
8
8
  ".": "./index.js"
9
9
  },
10
- "scripts": {
11
- "postinstall": "node scripts/postinstall.js"
12
- },
13
10
  "files": [
14
11
  "index.js",
15
12
  "extract.js",
16
- "scripts",
17
13
  "bin"
18
14
  ],
19
15
  "keywords": [
@@ -1,7 +0,0 @@
1
- //! Decompress the host's otfwc binary after install. Best-effort: a no-op on a
2
- //! source checkout (no `.br` present) and never throws, so it can't break install.
3
- //! `otfwcPath()` decompresses lazily anyway if this is skipped (--ignore-scripts).
4
-
5
- import { extractIfPackaged } from "../extract.js";
6
-
7
- extractIfPackaged();