@appthreat/caxa 1.0.12 → 2.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appthreat/caxa",
3
- "version": "1.0.12",
3
+ "version": "2.0.0",
4
4
  "description": "Package Node.js applications into executable binaries",
5
5
  "author": "Team AppThreat <cloud@appthreat.com>",
6
6
  "homepage": "https://github.com/appthreat/caxa",
@@ -21,9 +21,17 @@
21
21
  "caxa": "build/index.mjs"
22
22
  },
23
23
  "scripts": {
24
- "prepare": "cd ./source/ && tsc",
25
- "prepare:stubs": "shx rm -f stubs/stub--win32--x64 && cross-env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags \"-s -w -extldflags=-Wl,-z,now,-z,relro\" -o stubs/stub--win32--x64 stubs/stub.go && shx echo >> stubs/stub--win32--x64 && shx echo CAXACAXACAXA >> stubs/stub--win32--x64 && shx rm -f stubs/stub--win32--arm64 && cross-env CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -ldflags \"-s -w -extldflags=-Wl,-z,now,-z,relro\" -o stubs/stub--win32--arm64 stubs/stub.go && shx echo >> stubs/stub--win32--arm64 && shx echo CAXACAXACAXA >> stubs/stub--win32--arm64 && shx rm -f stubs/stub--darwin--x64 && cross-env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags \"-s -w -extldflags=-Wl,-z,now,-z,relro\" -o stubs/stub--darwin--x64 stubs/stub.go && shx echo >> stubs/stub--darwin--x64 && shx echo CAXACAXACAXA >> stubs/stub--darwin--x64 && shx rm -f stubs/stub--darwin--arm64 && cross-env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags \"-s -w -extldflags=-Wl,-z,now,-z,relro\" -o stubs/stub--darwin--arm64 stubs/stub.go && shx echo >> stubs/stub--darwin--arm64 && shx echo CAXACAXACAXA >> stubs/stub--darwin--arm64 && shx rm -f stubs/stub--linux--x64 && cross-env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags \"-s -w -extldflags=-Wl,-z,now,-z,relro\" -o stubs/stub--linux--x64 stubs/stub.go && shx echo >> stubs/stub--linux--x64 && shx echo CAXACAXACAXA >> stubs/stub--linux--x64 && shx rm -f stubs/stub--linux--arm64 && cross-env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags \"-s -w -extldflags=-Wl,-z,now,-z,relro\" -o stubs/stub--linux--arm64 stubs/stub.go && shx echo >> stubs/stub--linux--arm64 && shx echo CAXACAXACAXA >> stubs/stub--linux--arm64 && shx rm -f stubs/stub--linux--riscv64 && cross-env CGO_ENABLED=0 GOOS=linux GOARCH=riscv64 go build -ldflags \"-s -w -extldflags=-Wl,-z,now,-z,relro\" -o stubs/stub--linux--riscv64 stubs/stub.go && shx echo >> stubs/stub--linux--riscv64 && shx echo CAXACAXACAXA >> stubs/stub--linux--riscv64 && shx rm -f stubs/stub--linux--arm && cross-env CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags \"-s -w -extldflags=-Wl,-z,now,-z,relro\" -o stubs/stub--linux--arm stubs/stub.go && shx echo >> stubs/stub--linux--arm && shx echo CAXACAXACAXA >> stubs/stub--linux--arm",
26
- "test": "prettier --check \"source/**/*.mts\" --end-of-line auto"
24
+ "prepare": "npm run prepare:stubs && tsc",
25
+ "prepare:stubs": "shx rm -f stubs/stub--* && npm run build:stub:win && npm run build:stub:mac && npm run build:stub:linux",
26
+ "build:stub:win": "cross-env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -C stubs -ldflags \"-s -w\" -o stub--win32--x64 stub.go && npm run append:sig -- stubs/stub--win32--x64 && cross-env CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -C stubs -ldflags \"-s -w\" -o stub--win32--arm64 stub.go && npm run append:sig -- stubs/stub--win32--arm64",
27
+ "build:stub:mac": "cross-env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -C stubs -ldflags \"-s -w\" -o stub--darwin--x64 stub.go && npm run append:sig -- stubs/stub--darwin--x64 && cross-env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -C stubs -ldflags \"-s -w\" -o stub--darwin--arm64 stub.go && npm run append:sig -- stubs/stub--darwin--arm64",
28
+ "build:stub:linux": "cross-env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -C stubs -ldflags \"-s -w\" -o stub--linux--x64 stub.go && npm run append:sig -- stubs/stub--linux--x64 && cross-env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -C stubs -ldflags \"-s -w\" -o stub--linux--arm64 stub.go && npm run append:sig -- stubs/stub--linux--arm64 && cross-env CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -C stubs -ldflags \"-s -w\" -o stub--linux--arm stub.go && npm run append:sig -- stubs/stub--linux--arm",
29
+ "append:sig": "node -e \"const fs=require('fs'); fs.appendFileSync(process.argv[1], '\\nCAXACAXACAXA\\n')\"",
30
+ "pretest": "npm run prepare:stubs",
31
+ "test": "npm run test:lint && npm run test:go && npm run test:e2e",
32
+ "test:lint": "prettier --check \"source/**/*.mts\" --end-of-line auto",
33
+ "test:go": "cd stubs && go test -v",
34
+ "test:e2e": "node test/e2e.test.mjs"
27
35
  },
28
36
  "dependencies": {
29
37
  "archiver": "^7.0.1",
@@ -31,16 +39,16 @@
31
39
  "crypto-random-string": "^5.0.0",
32
40
  "dedent": "^1.6.0",
33
41
  "fs-extra": "^11.3.0",
34
- "globby": "^14.1.0"
42
+ "globby": "^16.0.0"
35
43
  },
36
44
  "devDependencies": {
37
- "@types/archiver": "^6.0.3",
45
+ "@types/archiver": "^7.0.0",
38
46
  "@types/dedent": "^0.7.2",
39
47
  "@types/fs-extra": "^11.0.4",
40
48
  "@types/node": "^24.0.10",
41
- "cross-env": "^7.0.3",
49
+ "cross-env": "^10.1.0",
42
50
  "prettier": "^3.6.2",
43
51
  "shx": "^0.4.0",
44
52
  "typescript": "^5.8.3"
45
53
  }
46
- }
54
+ }
package/source/index.mts CHANGED
@@ -2,18 +2,15 @@
2
2
 
3
3
  import path from "node:path";
4
4
  import url from "node:url";
5
- import os from "node:os";
6
5
  import stream from "node:stream/promises";
7
6
  import fs from "fs-extra";
8
- import { globbySync } from "globby";
7
+ import { globby } from "globby";
9
8
  import cryptoRandomString from "crypto-random-string";
10
9
  import bash from "dedent";
11
- import dedent from "dedent";
12
10
  import archiver from "archiver";
13
11
  import * as commander from "commander";
14
12
  import process from "node:process";
15
13
 
16
- // Some default excludes
17
14
  const defaultExcludes = [
18
15
  ".*",
19
16
  "*.exe",
@@ -53,17 +50,6 @@ export default async function caxa({
53
50
  command,
54
51
  force = true,
55
52
  exclude = defaultExcludes,
56
- filter = (() => {
57
- if (!exclude.length) {
58
- exclude = defaultExcludes;
59
- }
60
- const pathsToExclude = globbySync(exclude, {
61
- expandDirectories: false,
62
- onlyFiles: false,
63
- }).map((pathToExclude: string) => path.normalize(pathToExclude));
64
- return (pathToCopy: string) =>
65
- !pathsToExclude.includes(path.normalize(pathToCopy));
66
- })(),
67
53
  includeNode = true,
68
54
  stub = url.fileURLToPath(
69
55
  new URL(
@@ -75,7 +61,6 @@ export default async function caxa({
75
61
  path.basename(path.basename(path.basename(output, ".exe"), ".app"), ".sh"),
76
62
  cryptoRandomString({ length: 10, type: "alphanumeric" }).toLowerCase(),
77
63
  ),
78
- removeBuildDirectory = true,
79
64
  uncompressionMessage,
80
65
  }: {
81
66
  input: string;
@@ -97,39 +82,145 @@ export default async function caxa({
97
82
  if (process.platform === "win32" && !output.endsWith(".exe"))
98
83
  throw new Error("Windows executable must end in ‘.exe’.");
99
84
 
100
- const buildDirectory = path.join(
101
- os.tmpdir(),
102
- "caxa",
103
- "builds",
104
- cryptoRandomString({ length: 10, type: "alphanumeric" }).toLowerCase(),
105
- );
106
- await fs.copy(input, buildDirectory, { filter });
107
- if (includeNode) {
108
- const node = path.join(
109
- buildDirectory,
110
- "node_modules",
111
- ".bin",
112
- path.basename(process.execPath),
113
- );
114
- await fs.ensureDir(path.dirname(node));
115
- await fs.copyFile(process.execPath, node);
116
- }
117
-
118
85
  await fs.ensureDir(path.dirname(output));
119
86
  await fs.remove(output);
120
87
 
88
+ if (!exclude) exclude = defaultExcludes;
89
+ const files = await globby(["**/*", ...exclude.map((e) => `!${e}`)], {
90
+ cwd: input,
91
+ onlyFiles: true,
92
+ dot: true,
93
+ followSymbolicLinks: false,
94
+ });
95
+
96
+ interface Component {
97
+ group: string;
98
+ name: string;
99
+ version: string;
100
+ purl: string;
101
+ _rawDeps?: Record<string, string>;
102
+ }
103
+
104
+ interface DependencyGraphEntry {
105
+ ref: string;
106
+ dependsOn: string[];
107
+ }
108
+
109
+ const components: Component[] = [];
110
+ const purlLookup = new Map<string, string>();
111
+
112
+ for (const file of files) {
113
+ if (path.basename(file) === "package.json") {
114
+ try {
115
+ const pkg = await fs.readJson(path.join(input, file));
116
+ if (pkg.name && pkg.version) {
117
+ let name = pkg.name;
118
+ let namespace = "";
119
+ if (name.startsWith("@")) {
120
+ const parts = name.split("/");
121
+ namespace = parts[0];
122
+ name = parts[1];
123
+ }
124
+
125
+ let purl = "pkg:npm/";
126
+ if (namespace) {
127
+ purl += `${encodeURIComponent(namespace)}/`;
128
+ }
129
+ purl += `${name}@${pkg.version}`;
130
+
131
+ purlLookup.set(pkg.name, purl);
132
+
133
+ components.push({
134
+ group: namespace,
135
+ name: name,
136
+ version: pkg.version,
137
+ purl: purl,
138
+ _rawDeps: pkg.dependencies,
139
+ });
140
+ }
141
+ } catch (e) {
142
+ // Ignore
143
+ }
144
+ }
145
+ }
146
+
147
+ const dependencies: DependencyGraphEntry[] = [];
148
+
149
+ for (const comp of components) {
150
+ const childPurls: string[] = [];
151
+ if (comp._rawDeps) {
152
+ for (const depName of Object.keys(comp._rawDeps)) {
153
+ const resolvedPurl = purlLookup.get(depName);
154
+ if (resolvedPurl) {
155
+ childPurls.push(resolvedPurl);
156
+ }
157
+ }
158
+ delete comp._rawDeps;
159
+ }
160
+
161
+ if (childPurls.length > 0) {
162
+ dependencies.push({
163
+ ref: comp.purl,
164
+ dependsOn: childPurls,
165
+ });
166
+ }
167
+ }
168
+
169
+ await fs.writeJson(
170
+ path.join(path.dirname(output), "binary-metadata.json"),
171
+ {
172
+ components,
173
+ dependencies,
174
+ },
175
+ { spaces: 0 },
176
+ );
177
+
178
+ const appendApplicationPayload = async (destination: string, prefix = "") => {
179
+ const archive = archiver("tar", {
180
+ gzip: true,
181
+ gzipOptions: { level: 6 },
182
+ });
183
+ const outputStream = fs.createWriteStream(destination, { flags: "a" });
184
+ archive.pipe(outputStream);
185
+
186
+ for (const file of files) {
187
+ const absPath = path.join(input, file);
188
+ let name = path.join(prefix, file);
189
+ if (process.platform === "win32") {
190
+ name = name.replace(/\\/g, "/");
191
+ }
192
+ archive.file(absPath, { name });
193
+ }
194
+
195
+ if (includeNode) {
196
+ const nodePath = process.execPath;
197
+ let nodeDest = path.join(
198
+ prefix,
199
+ "node_modules",
200
+ ".bin",
201
+ path.basename(nodePath),
202
+ );
203
+ if (process.platform === "win32") {
204
+ nodeDest = nodeDest.replace(/\\/g, "/");
205
+ }
206
+ archive.file(nodePath, { name: nodeDest });
207
+ }
208
+
209
+ await archive.finalize();
210
+ await stream.finished(outputStream);
211
+ };
212
+
121
213
  if (output.endsWith(".app")) {
122
214
  if (process.platform !== "darwin")
123
215
  throw new Error(
124
216
  "macOS Application Bundles (.app) are supported in macOS only.",
125
217
  );
126
- await fs.ensureDir(path.join(output, "Contents", "Resources"));
127
- await fs.move(
128
- buildDirectory,
129
- path.join(output, "Contents", "Resources", "application"),
130
- );
218
+
131
219
  await fs.ensureDir(path.join(output, "Contents", "MacOS"));
220
+ await fs.ensureDir(path.join(output, "Contents", "Resources"));
221
+
132
222
  const name = path.basename(output, ".app");
223
+
133
224
  await fs.writeFile(
134
225
  path.join(output, "Contents", "MacOS", name),
135
226
  bash`
@@ -138,202 +229,130 @@ export default async function caxa({
138
229
  ` + "\n",
139
230
  { mode: 0o755 },
140
231
  );
232
+
141
233
  await fs.writeFile(
142
234
  path.join(output, "Contents", "Resources", name),
143
235
  bash`
144
236
  #!/usr/bin/env sh
145
237
  ${command
146
238
  .map(
147
- (part) =>
148
- `"${part.replace(
149
- /\{\{\s*caxa\s*\}\}/g,
150
- `$(dirname "$0")/application`,
151
- )}"`,
239
+ (p) =>
240
+ `"${p.replace(/\{\{\s*caxa\s*}}/g, `$(dirname "$0")/application`)}"`,
152
241
  )
153
242
  .join(" ")}
154
243
  ` + "\n",
155
244
  { mode: 0o755 },
156
245
  );
246
+
247
+ const appDest = path.join(output, "Contents", "Resources", "application");
248
+ await fs.ensureDir(appDest);
249
+
250
+ for (const file of files) {
251
+ const src = path.join(input, file);
252
+ const dest = path.join(appDest, file);
253
+ await fs.copy(src, dest);
254
+ }
255
+
256
+ if (includeNode) {
257
+ const nodeDest = path.join(
258
+ appDest,
259
+ "node_modules",
260
+ ".bin",
261
+ path.basename(process.execPath),
262
+ );
263
+ await fs.ensureDir(path.dirname(nodeDest));
264
+ await fs.copyFile(process.execPath, nodeDest);
265
+ }
157
266
  } else if (output.endsWith(".sh")) {
158
267
  if (process.platform === "win32")
159
268
  throw new Error("The Shell Stub (.sh) isn’t supported in Windows.");
160
- let stub =
269
+
270
+ let shellStub =
161
271
  bash`
162
272
  #!/usr/bin/env sh
163
- export CAXA_TEMPORARY_DIRECTORY="$(dirname $(mktemp))/caxa"
164
- export CAXA_EXTRACTION_ATTEMPT=-1
273
+ export CAXA_TMP="$(dirname $(mktemp))/caxa"
274
+ export CAXA_ID="${identifier}"
165
275
  while true
166
276
  do
167
- export CAXA_EXTRACTION_ATTEMPT=$(( CAXA_EXTRACTION_ATTEMPT + 1 ))
168
- export CAXA_LOCK="$CAXA_TEMPORARY_DIRECTORY/locks/${identifier}/$CAXA_EXTRACTION_ATTEMPT"
169
- export CAXA_APPLICATION_DIRECTORY="$CAXA_TEMPORARY_DIRECTORY/applications/${identifier}/$CAXA_EXTRACTION_ATTEMPT"
170
- if [ -d "$CAXA_APPLICATION_DIRECTORY" ]
171
- then
172
- if [ -d "$CAXA_LOCK" ]
173
- then
174
- continue
175
- else
176
- break
177
- fi
178
- else
179
- ${
180
- uncompressionMessage === undefined
181
- ? bash``
182
- : bash`echo "${uncompressionMessage}" >&2`
183
- }
184
- mkdir -p "$CAXA_LOCK"
185
- mkdir -p "$CAXA_APPLICATION_DIRECTORY"
186
- tail -n+{{caxa-number-of-lines}} "$0" | tar -xz -C "$CAXA_APPLICATION_DIRECTORY"
187
- rmdir "$CAXA_LOCK"
188
- break
277
+ export CAXA_LOCK="$CAXA_TMP/locks/$CAXA_ID"
278
+ export CAXA_APP="$CAXA_TMP/apps/$CAXA_ID"
279
+ if [ -d "$CAXA_APP" ] && [ ! -d "$CAXA_LOCK" ]; then
280
+ break
189
281
  fi
282
+
283
+ ${uncompressionMessage ? bash`echo "${uncompressionMessage}" >&2` : ""}
284
+ mkdir -p "$CAXA_LOCK" "$CAXA_APP"
285
+
286
+ # Use atomic extraction pattern
287
+ tail -n+{{lines}} "$0" | tar -xz -C "$CAXA_APP"
288
+
289
+ rmdir "$CAXA_LOCK"
290
+ break
190
291
  done
191
292
  exec ${command
192
- .map(
193
- (commandPart) =>
194
- `"${commandPart.replace(
195
- /\{\{\s*caxa\s*\}\}/g,
196
- `"$CAXA_APPLICATION_DIRECTORY"`,
197
- )}"`,
198
- )
293
+ .map((p) => `"${p.replace(/\{\{\s*caxa\s*}}/g, `"$CAXA_APP"`)}"`)
199
294
  .join(" ")} "$@"
200
295
  ` + "\n";
201
- stub = stub.replace(
202
- "{{caxa-number-of-lines}}",
203
- String(stub.split("\n").length),
296
+
297
+ shellStub = shellStub.replace(
298
+ "{{lines}}",
299
+ String(shellStub.split("\n").length),
204
300
  );
205
- await fs.writeFile(output, stub, { mode: 0o755 });
206
- await appendTarballOfBuildDirectoryToOutput();
301
+ await fs.writeFile(output, shellStub, { mode: 0o755 });
302
+ await appendApplicationPayload(output);
207
303
  } else {
208
304
  if (!(await fs.pathExists(stub)))
209
305
  throw new Error(
210
306
  `Stub not found (your operating system / architecture may be unsupported): ‘${stub}’`,
211
307
  );
308
+
212
309
  await fs.copyFile(stub, output);
213
310
  await fs.chmod(output, 0o755);
214
- await appendTarballOfBuildDirectoryToOutput();
311
+
312
+ await appendApplicationPayload(output);
313
+
215
314
  await fs.appendFile(
216
315
  output,
217
316
  "\n" + JSON.stringify({ identifier, command, uncompressionMessage }),
218
317
  );
219
318
  }
220
-
221
- if (removeBuildDirectory) await fs.remove(buildDirectory);
222
-
223
- async function appendTarballOfBuildDirectoryToOutput(): Promise<void> {
224
- const archive = archiver("tar", { gzip: true });
225
- const archiveStream = fs.createWriteStream(output, { flags: "a" });
226
- archive.pipe(archiveStream);
227
- archive.directory(buildDirectory, false);
228
- await archive.finalize();
229
- await stream.finished(archiveStream);
230
- }
231
319
  }
232
320
 
233
321
  if (url.fileURLToPath(import.meta.url) === (await fs.realpath(process.argv[1])))
234
322
  await commander.program
235
323
  .name("caxa")
236
324
  .description("Package Node.js applications into executable binaries")
237
- .requiredOption(
238
- "-i, --input <input>",
239
- "[Required] The input directory to package.",
240
- )
325
+ .requiredOption("-i, --input <input>", "Input directory to package.")
241
326
  .requiredOption(
242
327
  "-o, --output <output>",
243
- "[Required] The path where the executable will be produced. On Windows, must end in ‘.exe’. In macOS and Linux, may have no extension to produce regular binary. In macOS and Linux, may end in ‘.sh’ to use the Shell Stub, which is a bit smaller, but depends on some tools being installed on the end-user machine, for example, ‘tar’, ‘tail’, and so forth. In macOS, may end in ‘.app’ to generate a macOS Application Bundle.",
244
- )
245
- .option("-F, --no-force", "[Advanced] Don’t overwrite output if it exists.")
246
- .option(
247
- "-e, --exclude <path...>",
248
- `[Advanced] Paths to exclude from the build. The paths are passed to https://github.com/sindresorhus/globby and paths that match will be excluded. [Super-Advanced, Please don’t use] If you wish to emulate ‘--include’, you may use ‘--exclude "*" ".*" "!path-to-include" ...’. The problem with ‘--include’ is that if you change your project structure but forget to change the caxa invocation, then things will subtly fail only in the packaged version.`,
249
- )
250
- .option(
251
- "-N, --no-include-node",
252
- "[Advanced] Don’t copy the Node.js executable to ‘{{caxa}}/node_modules/.bin/node’.",
253
- )
254
- .option("-s, --stub <path>", "[Advanced] Path to the stub.")
255
- .option(
256
- "--identifier <identifier>",
257
- "[Advanced] Build identifier, which is part of the path in which the application will be unpacked.",
328
+ "Path where the executable will be produced.",
258
329
  )
330
+ .option("-F, --no-force", "Don’t overwrite output if it exists.")
331
+ .option("-e, --exclude <path...>", "Paths to exclude from the build.")
332
+ .option("-N, --no-include-node", "Don’t copy the Node.js executable.")
333
+ .option("-s, --stub <path>", "Path to the stub.")
334
+ .option("--identifier <id>", "Build identifier.")
259
335
  .option(
260
336
  "-B, --no-remove-build-directory",
261
- "[Advanced] Remove the build directory after the build.",
337
+ "Ignored in v2 (streaming build).",
262
338
  )
263
339
  .option(
264
- "-m, --uncompression-message <message>",
265
- "[Advanced] A message to show when uncompressing, for example, ‘This may take a while to run the first time, please wait...’.",
266
- )
267
- .argument(
268
- "<command...>",
269
- "The command to run and optional arguments to pass to the command every time the executable is called. Paths must be absolute. The ‘{{caxa}}’ placeholder is substituted for the folder from which the package runs. The ‘node’ executable is available at ‘{{caxa}}/node_modules/.bin/node’. Use double quotes to delimit the command and each argument.",
340
+ "-m, --uncompression-message <msg>",
341
+ "Message to show during extraction.",
270
342
  )
343
+ .argument("<command...>", "Command to run.")
271
344
  .version(
272
345
  JSON.parse(
273
346
  await fs.readFile(new URL("../package.json", import.meta.url), "utf8"),
274
347
  ).version,
275
348
  )
276
- .addHelpText(
277
- "after",
278
- "\n" +
279
- dedent`
280
- Examples:
281
- Windows:
282
- > caxa --input "examples/echo-command-line-parameters" --output "echo-command-line-parameters.exe" -- "{{caxa}}/node_modules/.bin/node" "{{caxa}}/index.mjs" "some" "embedded arguments" "--an-option-thats-part-of-the-command"
283
-
284
- macOS/Linux:
285
- $ caxa --input "examples/echo-command-line-parameters" --output "echo-command-line-parameters" -- "{{caxa}}/node_modules/.bin/node" "{{caxa}}/index.mjs" "some" "embedded arguments" "--an-option-thats-part-of-the-command"
286
-
287
- macOS/Linux (Shell Stub):
288
- $ caxa --input "examples/echo-command-line-parameters" --output "echo-command-line-parameters.sh" -- "{{caxa}}/node_modules/.bin/node" "{{caxa}}/index.mjs" "some" "embedded arguments" "--an-option-thats-part-of-the-command"
289
-
290
- macOS (Application Bundle):
291
- $ caxa --input "examples/echo-command-line-parameters" --output "Echo Command Line Parameters.app" -- "{{caxa}}/node_modules/.bin/node" "{{caxa}}/index.mjs" "some" "embedded arguments" "--an-option-thats-part-of-the-command"
292
- `,
293
- )
294
- .action(
295
- async (
296
- command: string[],
297
- {
298
- input,
299
- output,
300
- force,
301
- exclude,
302
- includeNode,
303
- stub,
304
- identifier,
305
- removeBuildDirectory,
306
- uncompressionMessage,
307
- }: {
308
- input: string;
309
- output: string;
310
- force?: boolean;
311
- exclude?: string[];
312
- includeNode?: boolean;
313
- stub?: string;
314
- identifier?: string;
315
- removeBuildDirectory?: boolean;
316
- uncompressionMessage?: string;
317
- },
318
- ) => {
319
- try {
320
- await caxa({
321
- input,
322
- output,
323
- command,
324
- force,
325
- exclude,
326
- includeNode,
327
- stub,
328
- identifier,
329
- removeBuildDirectory,
330
- uncompressionMessage,
331
- });
332
- } catch (error: any) {
333
- console.error(error.message);
334
- process.exit(1);
335
- }
336
- },
337
- )
349
+ .action(async (command, opts) => {
350
+ try {
351
+ await caxa({ command, ...opts });
352
+ } catch (error: any) {
353
+ console.error(error.message);
354
+ process.exit(1);
355
+ }
356
+ })
338
357
  .showHelpAfterError()
339
358
  .parseAsync();
package/stubs/go.mod ADDED
@@ -0,0 +1,5 @@
1
+ module caxa-stubs
2
+
3
+ go 1.25.6
4
+
5
+ require github.com/klauspost/compress v1.18.3
package/stubs/go.sum ADDED
@@ -0,0 +1,2 @@
1
+ github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
2
+ github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file