@dhruv2mars/offdex 0.0.1

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,31 @@
1
+ # @dhruv2mars/offdex
2
+
3
+ Install the Offdex bridge CLI globally:
4
+
5
+ ```bash
6
+ npm install -g @dhruv2mars/offdex
7
+ ```
8
+
9
+ Then run:
10
+
11
+ ```bash
12
+ offdex
13
+ ```
14
+
15
+ The package downloads the matching native runtime for your platform from GitHub Releases.
16
+
17
+ Supported targets:
18
+
19
+ - macOS `arm64`
20
+ - macOS `x64`
21
+ - Linux `arm64`
22
+ - Linux `x64`
23
+ - Windows `x64`
24
+
25
+ Common usage:
26
+
27
+ ```bash
28
+ offdex bridge --host 0.0.0.0 --port 42420
29
+ offdex bridge --control-plane-url https://control.offdex.app
30
+ offdex --help
31
+ ```
@@ -0,0 +1,326 @@
1
+ import { createHash } from "node:crypto";
2
+ import { createWriteStream, existsSync, readFileSync } from "node:fs";
3
+ import { chmod, mkdir, rename, rm, writeFile } from "node:fs/promises";
4
+ import http from "node:http";
5
+ import https from "node:https";
6
+ import { homedir } from "node:os";
7
+ import { join } from "node:path";
8
+
9
+ const REPO = "Dhruv2mars/offdex";
10
+ const SUPPORTED_TARGETS = new Map([
11
+ ["darwin:arm64", "bun-darwin-arm64"],
12
+ ["darwin:x64", "bun-darwin-x64"],
13
+ ["linux:arm64", "bun-linux-arm64"],
14
+ ["linux:x64", "bun-linux-x64-baseline"],
15
+ ["win32:x64", "bun-windows-x64-baseline"]
16
+ ]);
17
+
18
+ export function supportedPlatformMatrix() {
19
+ return [...SUPPORTED_TARGETS.keys()].map((key) => {
20
+ const [platform, arch] = key.split(":");
21
+ return { platform, arch, target: SUPPORTED_TARGETS.get(key) };
22
+ });
23
+ }
24
+
25
+ export function isSupportedPlatform(platform = process.platform, arch = process.arch) {
26
+ return SUPPORTED_TARGETS.has(`${platform}:${arch}`);
27
+ }
28
+
29
+ export function supportedPlatformList() {
30
+ return supportedPlatformMatrix().map(({ platform, arch }) => `${platform}/${arch}`);
31
+ }
32
+
33
+ export function targetForPlatform(platform = process.platform, arch = process.arch) {
34
+ const target = SUPPORTED_TARGETS.get(`${platform}:${arch}`);
35
+ if (!target) {
36
+ throw new Error(`unsupported_platform:${platform}-${arch}`);
37
+ }
38
+ return target;
39
+ }
40
+
41
+ export function assertSupportedPlatform(platform = process.platform, arch = process.arch) {
42
+ if (isSupportedPlatform(platform, arch)) {
43
+ return;
44
+ }
45
+ throw new Error(`unsupported_platform:${platform}-${arch}`);
46
+ }
47
+
48
+ export function binNameForPlatform(platform = process.platform) {
49
+ return platform === "win32" ? "offdex.exe" : "offdex";
50
+ }
51
+
52
+ export function assetNameFor(platform = process.platform, arch = process.arch) {
53
+ const ext = platform === "win32" ? ".exe" : "";
54
+ return `offdex-${platform}-${arch}${ext}`;
55
+ }
56
+
57
+ export function checksumsAssetNameFor(platform = process.platform, arch = process.arch) {
58
+ return `checksums-${platform}-${arch}.txt`;
59
+ }
60
+
61
+ export function resolveInstallRoot(env = process.env, home = homedir()) {
62
+ return env.OFFDEX_INSTALL_ROOT || join(home, ".offdex");
63
+ }
64
+
65
+ export function resolveInstallMetaPath(env = process.env, home = homedir()) {
66
+ return join(resolveInstallRoot(env, home), "install-meta.json");
67
+ }
68
+
69
+ export function resolveInstalledBin(env = process.env, platform = process.platform, home = homedir()) {
70
+ return join(resolveInstallRoot(env, home), "bin", binNameForPlatform(platform));
71
+ }
72
+
73
+ export function packageManagerHintFromEnv(env = process.env) {
74
+ const execPath = String(env.npm_execpath || "").toLowerCase();
75
+ if (execPath.includes("bun")) return "bun";
76
+ if (execPath.includes("pnpm")) return "pnpm";
77
+ if (execPath.includes("yarn")) return "yarn";
78
+ if (execPath.includes("npm")) return "npm";
79
+
80
+ const ua = String(env.npm_config_user_agent || "").toLowerCase();
81
+ if (ua.startsWith("bun/")) return "bun";
82
+ if (ua.startsWith("pnpm/")) return "pnpm";
83
+ if (ua.startsWith("yarn/")) return "yarn";
84
+ if (ua.startsWith("npm/")) return "npm";
85
+
86
+ return null;
87
+ }
88
+
89
+ export function shouldInstallBinary({ binExists, installedVersion, packageVersion }) {
90
+ if (!binExists) return true;
91
+ if (!packageVersion) return false;
92
+ return installedVersion !== packageVersion;
93
+ }
94
+
95
+ export function resolvePackageVersion(packageJsonPath, env = process.env) {
96
+ try {
97
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8"));
98
+ return typeof pkg.version === "string" && pkg.version.length > 0
99
+ ? pkg.version
100
+ : (env.npm_package_version || "0.0.0");
101
+ } catch {
102
+ return env.npm_package_version || "0.0.0";
103
+ }
104
+ }
105
+
106
+ export function isWorkspaceCheckout(packageJsonPath) {
107
+ try {
108
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8"));
109
+ return pkg?.name === "offdex" && Array.isArray(pkg?.workspaces);
110
+ } catch {
111
+ return false;
112
+ }
113
+ }
114
+
115
+ export function shouldSkipPackageInstall({
116
+ env = process.env,
117
+ packageRoot
118
+ }) {
119
+ if (env.OFFDEX_SKIP_INSTALL === "1") {
120
+ return true;
121
+ }
122
+
123
+ const workspaceRootPackageJson = join(packageRoot, "..", "..", "package.json");
124
+ return isWorkspaceCheckout(workspaceRootPackageJson);
125
+ }
126
+
127
+ export function parseChecksumForAsset(text, asset) {
128
+ if (typeof text !== "string") return null;
129
+ for (const line of text.split(/\r?\n/)) {
130
+ const match = line.trim().match(/^([a-fA-F0-9]{64})\s+\*?(.+)$/);
131
+ if (!match) continue;
132
+ const candidate = match[2].trim().replace(/^[.][/\\]/, "");
133
+ if (candidate !== asset) continue;
134
+ return match[1].toLowerCase();
135
+ }
136
+ return null;
137
+ }
138
+
139
+ function requestProtocolFor(url) {
140
+ return new URL(url).protocol;
141
+ }
142
+
143
+ export function requestText(url, redirects = 0) {
144
+ if (redirects > 5) {
145
+ throw new Error("too_many_redirects");
146
+ }
147
+ return new Promise((resolve, reject) => {
148
+ const transport = requestProtocolFor(url) === "http:" ? http : https;
149
+ const request = transport.get(
150
+ url,
151
+ {
152
+ agent: false,
153
+ headers: {
154
+ Connection: "close",
155
+ "User-Agent": "offdex-installer"
156
+ }
157
+ },
158
+ (response) => {
159
+ if (
160
+ response.statusCode &&
161
+ response.statusCode >= 300 &&
162
+ response.statusCode < 400 &&
163
+ response.headers.location
164
+ ) {
165
+ response.resume();
166
+ requestText(response.headers.location, redirects + 1).then(resolve, reject);
167
+ return;
168
+ }
169
+ if (response.statusCode !== 200) {
170
+ response.resume();
171
+ reject(new Error(`http ${response.statusCode}`));
172
+ return;
173
+ }
174
+ let data = "";
175
+ response.setEncoding("utf8");
176
+ response.on("data", (chunk) => {
177
+ data += chunk;
178
+ });
179
+ response.on("end", () => resolve(data));
180
+ }
181
+ );
182
+ request.on("error", reject);
183
+ });
184
+ }
185
+
186
+ export function download(url, outputPath, redirects = 0) {
187
+ if (redirects > 5) {
188
+ throw new Error("too_many_redirects");
189
+ }
190
+ const partPath = `${outputPath}.part`;
191
+ return new Promise((resolve, reject) => {
192
+ const transport = requestProtocolFor(url) === "http:" ? http : https;
193
+ const request = transport.get(
194
+ url,
195
+ {
196
+ agent: false,
197
+ headers: {
198
+ Connection: "close",
199
+ "User-Agent": "offdex-installer"
200
+ }
201
+ },
202
+ (response) => {
203
+ if (
204
+ response.statusCode &&
205
+ response.statusCode >= 300 &&
206
+ response.statusCode < 400 &&
207
+ response.headers.location
208
+ ) {
209
+ response.resume();
210
+ download(response.headers.location, outputPath, redirects + 1).then(resolve, reject);
211
+ return;
212
+ }
213
+ if (response.statusCode !== 200) {
214
+ response.resume();
215
+ reject(new Error(`http ${response.statusCode}`));
216
+ return;
217
+ }
218
+ const file = createWriteStream(partPath);
219
+ file.on("error", async (error) => {
220
+ await rm(partPath, { force: true });
221
+ reject(error);
222
+ });
223
+ response.on("error", async (error) => {
224
+ await rm(partPath, { force: true });
225
+ reject(error);
226
+ });
227
+ response.pipe(file);
228
+ file.on("finish", () => {
229
+ file.close(async () => {
230
+ try {
231
+ await rename(partPath, outputPath);
232
+ resolve();
233
+ } catch (error) {
234
+ await rm(partPath, { force: true });
235
+ reject(error);
236
+ }
237
+ });
238
+ });
239
+ }
240
+ );
241
+ request.on("error", async (error) => {
242
+ await rm(partPath, { force: true });
243
+ reject(error);
244
+ });
245
+ });
246
+ }
247
+
248
+ export async function installRuntime({
249
+ version,
250
+ env = process.env,
251
+ platform = process.platform,
252
+ arch = process.arch,
253
+ home = homedir(),
254
+ downloadFn = download,
255
+ requestTextFn = requestText
256
+ }) {
257
+ assertSupportedPlatform(platform, arch);
258
+ const installRoot = resolveInstallRoot(env, home);
259
+ const installBin = resolveInstalledBin(env, platform, home);
260
+ const installMeta = resolveInstallMetaPath(env, home);
261
+ const asset = assetNameFor(platform, arch);
262
+ const checksumsAsset = checksumsAssetNameFor(platform, arch);
263
+ const baseUrl = env.OFFDEX_RELEASE_BASE_URL
264
+ || `https://github.com/${REPO}/releases/download/v${version}`;
265
+
266
+ await mkdir(join(installRoot, "bin"), { recursive: true });
267
+
268
+ let checksumsText;
269
+ try {
270
+ checksumsText = await requestTextFn(`${baseUrl}/${checksumsAsset}`);
271
+ } catch {
272
+ throw new Error(`failed_download:${checksumsAsset}`);
273
+ }
274
+ const expectedChecksum = parseChecksumForAsset(checksumsText, asset);
275
+ if (!expectedChecksum) {
276
+ throw new Error(`missing_checksum:${asset}`);
277
+ }
278
+
279
+ const tempPath = `${installBin}.download`;
280
+ try {
281
+ try {
282
+ await downloadFn(`${baseUrl}/${asset}`, tempPath);
283
+ } catch {
284
+ throw new Error(`failed_download:${asset}`);
285
+ }
286
+ const actualChecksum = createHash("sha256").update(readFileSync(tempPath)).digest("hex");
287
+ if (actualChecksum !== expectedChecksum) {
288
+ throw new Error(`checksum_mismatch:${asset}`);
289
+ }
290
+ if (platform !== "win32") {
291
+ await chmod(tempPath, 0o755);
292
+ }
293
+ await rm(installBin, { force: true });
294
+ await rename(tempPath, installBin);
295
+ } catch (error) {
296
+ await rm(tempPath, { force: true });
297
+ throw error;
298
+ }
299
+ if (platform !== "win32") {
300
+ await chmod(installBin, 0o755);
301
+ }
302
+
303
+ await writeFile(
304
+ installMeta,
305
+ JSON.stringify(
306
+ {
307
+ packageManager: packageManagerHintFromEnv(env),
308
+ version
309
+ },
310
+ null,
311
+ 2
312
+ )
313
+ );
314
+
315
+ return { asset, installBin, installRoot, version };
316
+ }
317
+
318
+ export function readInstalledVersion(env = process.env, home = homedir()) {
319
+ const metaPath = resolveInstallMetaPath(env, home);
320
+ if (!existsSync(metaPath)) return null;
321
+ try {
322
+ return JSON.parse(readFileSync(metaPath, "utf8")).version || null;
323
+ } catch {
324
+ return null;
325
+ }
326
+ }
package/bin/install.js ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath } from "node:url";
3
+ import { dirname, join } from "node:path";
4
+ import {
5
+ installRuntime,
6
+ resolvePackageVersion,
7
+ shouldSkipPackageInstall,
8
+ supportedPlatformList
9
+ } from "./install-lib.js";
10
+
11
+ const here = dirname(fileURLToPath(import.meta.url));
12
+ const packageRoot = join(here, "..");
13
+ const packageVersion = resolvePackageVersion(join(packageRoot, "package.json"), process.env);
14
+
15
+ if (shouldSkipPackageInstall({ env: process.env, packageRoot })) {
16
+ console.log("offdex: skipping native runtime install inside workspace checkout");
17
+ process.exit(0);
18
+ }
19
+
20
+ installRuntime({ version: packageVersion })
21
+ .then(({ installBin }) => {
22
+ console.log(`offdex: installed ${installBin}`);
23
+ })
24
+ .catch((error) => {
25
+ const message = error instanceof Error ? error.message : "unknown";
26
+ console.error(`offdex: install failed (${message})`);
27
+ if (typeof message === "string" && message.startsWith("unsupported_platform:")) {
28
+ console.error(`offdex: supported targets are ${supportedPlatformList().join(", ")}`);
29
+ }
30
+ process.exit(1);
31
+ });
@@ -0,0 +1,21 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ import { dirname, join } from "node:path";
4
+ import { readInstalledVersion, resolveInstalledBin, shouldInstallBinary } from "./install-lib.js";
5
+
6
+ export function resolvePackageBinDir(moduleUrl = import.meta.url) {
7
+ return dirname(fileURLToPath(moduleUrl));
8
+ }
9
+
10
+ export function readPackageVersion(moduleUrl = import.meta.url) {
11
+ const binDir = resolvePackageBinDir(moduleUrl);
12
+ const packageJsonPath = join(binDir, "..", "package.json");
13
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8"));
14
+ return pkg.version;
15
+ }
16
+
17
+ export function installedVersion(env = process.env) {
18
+ return readInstalledVersion(env);
19
+ }
20
+
21
+ export { resolveInstalledBin, shouldInstallBinary };
package/bin/offdex.js ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from "node:fs";
3
+ import { spawnSync } from "node:child_process";
4
+ import { join } from "node:path";
5
+
6
+ import {
7
+ installedVersion,
8
+ readPackageVersion,
9
+ resolveInstalledBin,
10
+ resolvePackageBinDir,
11
+ shouldInstallBinary
12
+ } from "./offdex-lib.js";
13
+
14
+ const args = process.argv.slice(2);
15
+ const installedBin = resolveInstalledBin(process.env, process.platform);
16
+ const packageVersion = readPackageVersion();
17
+ const currentInstalledVersion = installedVersion(process.env);
18
+
19
+ if (
20
+ shouldInstallBinary({
21
+ binExists: existsSync(installedBin),
22
+ installedVersion: currentInstalledVersion,
23
+ packageVersion
24
+ })
25
+ ) {
26
+ console.error("offdex: setting up native runtime...");
27
+ const here = resolvePackageBinDir(import.meta.url);
28
+ const installer = join(here, "install.js");
29
+ const install = spawnSync(process.execPath, [installer], {
30
+ stdio: "inherit",
31
+ env: process.env
32
+ });
33
+ if (install.status !== 0 || !existsSync(installedBin)) {
34
+ console.error("offdex: install missing. try reinstall: npm i -g @dhruv2mars/offdex");
35
+ process.exit(1);
36
+ }
37
+ }
38
+
39
+ const result = spawnSync(installedBin, args, {
40
+ stdio: "inherit",
41
+ env: process.env
42
+ });
43
+ process.exit(result.status ?? 1);
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@dhruv2mars/offdex",
3
+ "version": "0.0.1",
4
+ "description": "Codex mobile bridge CLI for Offdex",
5
+ "type": "module",
6
+ "bin": {
7
+ "offdex": "bin/offdex.js"
8
+ },
9
+ "files": [
10
+ "bin"
11
+ ],
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "scripts": {
16
+ "offdex": "node bin/offdex.js",
17
+ "postinstall": "node bin/install.js",
18
+ "build": "node -e \"process.exit(0)\"",
19
+ "check": "node --check bin/offdex.js && node --check bin/offdex-lib.js && node --check bin/install.js && node --check bin/install-lib.js && node --test test/*.test.js",
20
+ "test": "node --test test/*.test.js"
21
+ },
22
+ "homepage": "https://github.com/Dhruv2mars/offdex#readme",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/Dhruv2mars/offdex.git",
26
+ "directory": "packages/npm"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/Dhruv2mars/offdex/issues"
30
+ },
31
+ "keywords": [
32
+ "codex",
33
+ "offdex",
34
+ "cli",
35
+ "bridge"
36
+ ],
37
+ "engines": {
38
+ "node": ">=18"
39
+ },
40
+ "preferGlobal": true,
41
+ "license": "MIT"
42
+ }