@openfn/cli 1.2.4 → 1.3.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/dist/index.js CHANGED
@@ -171,6 +171,29 @@ var autoinstall = {
171
171
  default: true
172
172
  }
173
173
  };
174
+ var apolloUrl = {
175
+ name: "apollo-url",
176
+ yargs: {
177
+ alias: ["url"],
178
+ description: "Auto-install the language adaptor(s)"
179
+ },
180
+ // map local, staging, prod to apollo-url
181
+ ensure: (opts2) => {
182
+ let didLoadShortcut = false;
183
+ ["local", "staging", "prod", "production"].forEach((shortcut) => {
184
+ if (shortcut in opts2) {
185
+ if (didLoadShortcut) {
186
+ throw new Error(
187
+ "Invalid apollo URL - please only enter one of local, staging or prod"
188
+ );
189
+ }
190
+ opts2.apolloUrl = shortcut;
191
+ delete opts2[shortcut];
192
+ didLoadShortcut = true;
193
+ }
194
+ });
195
+ }
196
+ };
174
197
  var cacheSteps = {
175
198
  name: "cache-steps",
176
199
  yargs: {
@@ -319,7 +342,7 @@ var outputPath = {
319
342
  description: "Path to the output file"
320
343
  },
321
344
  ensure: (opts2) => {
322
- if (opts2.command == "compile") {
345
+ if (/^(compile|apollo)$/.test(opts2.command)) {
323
346
  if (opts2.outputPath) {
324
347
  delete opts2.outputStdout;
325
348
  }
@@ -476,8 +499,36 @@ var override = (command, yargs2) => {
476
499
  };
477
500
  };
478
501
 
479
- // src/compile/command.ts
502
+ // src/apollo/util.ts
503
+ var STAGING_URL = "http://34.95.82.109";
504
+
505
+ // src/apollo/command.ts
480
506
  var options = [
507
+ apolloUrl,
508
+ stateStdin,
509
+ log,
510
+ logJson,
511
+ outputPath,
512
+ override(outputStdout, {
513
+ default: true
514
+ })
515
+ ];
516
+ var desc = `Call services on the openfn apollo server. Set the local server location with OPENFN_APOLLO_SERVER. The staging server is set to ${STAGING_URL}`;
517
+ var command_default = {
518
+ command: "apollo <service> [payload]",
519
+ desc,
520
+ handler: ensure("apollo", options),
521
+ builder: (yargs2) => build(options, yargs2).example(
522
+ "apollo echo path/to/json",
523
+ "Call the echo service, which returns json back"
524
+ ).example(
525
+ "apollo adaptor_gen cat-facts.example.json --local",
526
+ "Generate an adaptor template against a local server"
527
+ )
528
+ };
529
+
530
+ // src/compile/command.ts
531
+ var options2 = [
481
532
  expandAdaptors,
482
533
  adaptors,
483
534
  ignoreImports,
@@ -494,8 +545,8 @@ var options = [
494
545
  var compileCommand = {
495
546
  command: "compile [path]",
496
547
  describe: "Compile an openfn job or workflow and print or save the resulting JavaScript.",
497
- handler: ensure("compile", options),
498
- builder: (yargs2) => build(options, yargs2).positional("path", {
548
+ handler: ensure("compile", options2),
549
+ builder: (yargs2) => build(options2, yargs2).positional("path", {
499
550
  describe: "The path to load the job or workflow from (a .js or .json file or a dir containing a job.js file)",
500
551
  demandOption: true
501
552
  }).example(
@@ -506,10 +557,10 @@ var compileCommand = {
506
557
  "Compiles the workflow at foo/work.json and prints the result to -o foo/workflow-compiled.json"
507
558
  )
508
559
  };
509
- var command_default = compileCommand;
560
+ var command_default2 = compileCommand;
510
561
 
511
562
  // src/deploy/command.ts
512
- var options2 = [
563
+ var options3 = [
513
564
  configPath,
514
565
  confirm,
515
566
  describe,
@@ -521,10 +572,10 @@ var options2 = [
521
572
  var deployCommand = {
522
573
  command: "deploy",
523
574
  describe: "Deploy a project's config to a remote Lightning instance",
524
- handler: ensure("deploy", options2),
525
- builder: (yargs2) => build(options2, yargs2)
575
+ handler: ensure("deploy", options3),
576
+ builder: (yargs2) => build(options3, yargs2)
526
577
  };
527
- var command_default2 = deployCommand;
578
+ var command_default3 = deployCommand;
528
579
 
529
580
  // src/docgen/command.ts
530
581
  var docgenCommand = {
@@ -537,23 +588,23 @@ var docgenCommand = {
537
588
  },
538
589
  builder: (yargs2) => yargs2.example("docgen @openfn/language-common@1.7.5", "")
539
590
  };
540
- var command_default3 = docgenCommand;
591
+ var command_default4 = docgenCommand;
541
592
 
542
593
  // src/docs/command.ts
543
- var options3 = [log, logJson, repoDir];
594
+ var options4 = [log, logJson, repoDir];
544
595
  var docsCommand = {
545
596
  command: "docs <adaptor> [operation]",
546
597
  describe: "Print help for an adaptor function. You can use short-hand for adaptor names (ie, common instead of @openfn/language-common)",
547
- handler: ensure("docs", options3),
548
- builder: (yargs2) => build(options3, yargs2).example(
598
+ handler: ensure("docs", options4),
599
+ builder: (yargs2) => build(options4, yargs2).example(
549
600
  "docs common fn",
550
601
  "Print help for the common fn operation"
551
602
  )
552
603
  };
553
- var command_default4 = docsCommand;
604
+ var command_default5 = docsCommand;
554
605
 
555
606
  // src/execute/command.ts
556
- var options4 = [
607
+ var options5 = [
557
608
  expandAdaptors,
558
609
  adaptors,
559
610
  autoinstall,
@@ -585,8 +636,8 @@ Execute will run a expression/workflow at the path and write the output state to
585
636
 
586
637
  Remember to include the adaptor name with -a. Auto install adaptors with the -i flag.`,
587
638
  aliases: ["$0"],
588
- handler: ensure("execute", options4),
589
- builder: (yargs2) => build(options4, yargs2).positional("path", {
639
+ handler: ensure("execute", options5),
640
+ builder: (yargs2) => build(options5, yargs2).positional("path", {
590
641
  describe: "The path to load the job or workflow from (a .js or .json file or a dir containing a job.js file)",
591
642
  demandOption: true
592
643
  }).example(
@@ -603,10 +654,10 @@ Remember to include the adaptor name with -a. Auto install adaptors with the -i
603
654
  "Compile the expression at job.js with the http adaptor and print the code to stdout"
604
655
  )
605
656
  };
606
- var command_default5 = executeCommand;
657
+ var command_default6 = executeCommand;
607
658
 
608
659
  // src/metadata/command.ts
609
- var options5 = [
660
+ var options6 = [
610
661
  expandAdaptors,
611
662
  adaptors,
612
663
  force,
@@ -617,31 +668,31 @@ var options5 = [
617
668
  stateStdin,
618
669
  useAdaptorsMonorepo
619
670
  ];
620
- var command_default6 = {
671
+ var command_default7 = {
621
672
  command: "metadata",
622
673
  describe: "Generate metadata for an adaptor config",
623
- handler: ensure("metadata", options5),
624
- builder: (yargs2) => build(options5, yargs2).example(
674
+ handler: ensure("metadata", options6),
675
+ builder: (yargs2) => build(options6, yargs2).example(
625
676
  "metadata -a salesforce -s tmp/state.json",
626
677
  "Generate salesforce metadata from config in state.json"
627
678
  )
628
679
  };
629
680
 
630
681
  // src/pull/command.ts
631
- var options6 = [statePath, projectPath, configPath, log, logJson];
682
+ var options7 = [statePath, projectPath, configPath, log, logJson];
632
683
  var pullCommand = {
633
684
  command: "pull [projectId]",
634
685
  describe: "Pull a project's state and spec from a Lightning Instance to the local directory",
635
- builder: (yargs2) => build(options6, yargs2).positional("projectId", {
686
+ builder: (yargs2) => build(options7, yargs2).positional("projectId", {
636
687
  describe: "The id of the project that should be pulled shouled be a UUID",
637
688
  demandOption: true
638
689
  }).example(
639
690
  "pull 57862287-23e6-4650-8d79-e1dd88b24b1c",
640
691
  "Pull an updated copy of a the above spec and state from a Lightning Instance"
641
692
  ),
642
- handler: ensure("pull", options6)
693
+ handler: ensure("pull", options7)
643
694
  };
644
- var command_default7 = pullCommand;
695
+ var command_default8 = pullCommand;
645
696
 
646
697
  // src/repo/command.ts
647
698
  var repo = {
@@ -702,17 +753,17 @@ var list = {
702
753
  };
703
754
 
704
755
  // src/test/command.ts
705
- var options7 = [stateStdin, log, logJson];
706
- var command_default8 = {
756
+ var options8 = [stateStdin, log, logJson];
757
+ var command_default9 = {
707
758
  command: "test",
708
759
  desc: "Compiles and runs a test job, printing the result to stdout",
709
- handler: ensure("test", options7),
710
- builder: (yargs2) => build(options7, yargs2).example("test", "Run the test script")
760
+ handler: ensure("test", options8),
761
+ builder: (yargs2) => build(options8, yargs2).example("test", "Run the test script")
711
762
  };
712
763
 
713
764
  // src/cli.ts
714
765
  var y = yargs(hideBin(process.argv));
715
- var cmd = y.command(command_default5).command(command_default).command(command_default2).command(install).command(repo).command(command_default8).command(command_default4).command(command_default6).command(command_default3).command(command_default7).command({
766
+ var cmd = y.command(command_default6).command(command_default2).command(command_default3).command(install).command(repo).command(command_default9).command(command_default5).command(command_default).command(command_default7).command(command_default4).command(command_default8).command({
716
767
  command: "version",
717
768
  describe: "Show the currently installed version of the CLI, compiler and runtime.",
718
769
  handler: (argv) => {
@@ -1,3 +1,144 @@
1
+ // src/apollo/handler.ts
2
+ import { WebSocket } from "ws";
3
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import createLogger from "@openfn/logger";
6
+
7
+ // src/apollo/util.ts
8
+ var PRODUCTION_URL = "https://apollo.openfn.org";
9
+ var STAGING_URL = "http://34.95.82.109";
10
+ var LOCAL_URL = "http://localhost:3000";
11
+ var urlMap = {
12
+ ["prod"]: PRODUCTION_URL,
13
+ ["production"]: PRODUCTION_URL,
14
+ ["staging"]: STAGING_URL,
15
+ ["local"]: LOCAL_URL
16
+ };
17
+ var DEFAULT_ENV = "staging";
18
+ var getURL = (options) => {
19
+ if (options.apolloUrl) {
20
+ if (options.apolloUrl in urlMap) {
21
+ return urlMap[options.apolloUrl];
22
+ }
23
+ if (options.apolloUrl.startsWith("http")) {
24
+ return options.apolloUrl;
25
+ }
26
+ throw new Error(`Unrecognised apollo URL`);
27
+ }
28
+ const userDefault = process.env.OPENFN_APOLLO_DEFAULT_ENV || DEFAULT_ENV;
29
+ if (!/^(staging|prod|production|local|http*)$/.test(userDefault)) {
30
+ throw new Error(`Unrecognised apollo URL loaded from env: ${userDefault}`);
31
+ }
32
+ return urlMap[userDefault || "staging"];
33
+ };
34
+ var outputFiles = (files, logger) => {
35
+ logger.print();
36
+ for (const k in files) {
37
+ const line = new Array(k.length + 1).fill("-").join("");
38
+ logger.print(line);
39
+ logger.print(`${k}`);
40
+ logger.print(line);
41
+ logger.print();
42
+ logger.print(files[k]);
43
+ logger.print();
44
+ logger.print();
45
+ }
46
+ };
47
+
48
+ // src/apollo/handler.ts
49
+ var apolloHandler = async (options, logger) => {
50
+ logger.always(`Calling Apollo service: ${options.service}`);
51
+ const json = await loadPayload(logger, options.payload);
52
+ const url2 = getURL(options);
53
+ logger.success(`Using apollo server at`, url2);
54
+ const result = await callApollo(url2, options.service, json, logger);
55
+ if (result) {
56
+ await serializeOutput(options, result, logger);
57
+ } else {
58
+ logger.warn("No output returned from Apollo");
59
+ }
60
+ logger.success("Done!");
61
+ };
62
+ var write = async (basePath, filePath, content, logger) => {
63
+ const ext = path.extname(basePath);
64
+ let dir;
65
+ if (ext) {
66
+ dir = path.dirname(path.resolve(basePath));
67
+ } else {
68
+ dir = basePath;
69
+ }
70
+ await mkdir(dir, { recursive: true });
71
+ console.log(content);
72
+ const dest = path.resolve(basePath, filePath);
73
+ await writeFile(dest, content);
74
+ logger.success(`Wrote content to ${dest}`);
75
+ };
76
+ var serializeOutput = async (options, result, logger) => {
77
+ if (options.outputPath) {
78
+ if (result.files && !options.outputPath.endsWith(".json")) {
79
+ for (const p in result.files) {
80
+ await write(options.outputPath, p, result.files[p], logger);
81
+ }
82
+ } else {
83
+ await write(
84
+ options.outputPath,
85
+ "",
86
+ JSON.stringify(result, null, 2),
87
+ logger
88
+ );
89
+ }
90
+ return;
91
+ }
92
+ logger.success("Result:");
93
+ if (result.files) {
94
+ outputFiles(result.files, logger);
95
+ } else {
96
+ logger.always(JSON.stringify(result, void 0, 2));
97
+ }
98
+ };
99
+ var callApollo = async (apolloBaseUrl, serviceName, payload, logger) => {
100
+ return new Promise((resolve) => {
101
+ const apolloLogger = createLogger("APO", { level: "debug" });
102
+ const url2 = `${apolloBaseUrl.replace(
103
+ /^http/,
104
+ "ws"
105
+ )}/services/${serviceName}`;
106
+ logger.always("Calling apollo: ", url2);
107
+ const socket = new WebSocket(url2);
108
+ socket.addEventListener("message", ({ data }) => {
109
+ const evt = JSON.parse(data);
110
+ if (evt.event === "complete") {
111
+ logger.debug("Apollo responded with: ", evt.data);
112
+ resolve(evt.data);
113
+ } else if (evt.event === "log") {
114
+ apolloLogger.info(evt.data);
115
+ }
116
+ });
117
+ socket.addEventListener("open", () => {
118
+ socket.send(
119
+ JSON.stringify({
120
+ event: "start",
121
+ data: payload
122
+ })
123
+ );
124
+ });
125
+ });
126
+ };
127
+ var loadPayload = async (logger, path9) => {
128
+ if (!path9) {
129
+ logger.warn("No JSON payload provided");
130
+ logger.warn("Most apollo services require JSON to be uploaded");
131
+ return {};
132
+ }
133
+ if (path9.endsWith(".json")) {
134
+ const str = await readFile(path9, "utf8");
135
+ const json = JSON.parse(str);
136
+ logger.debug("Loaded JSON payload");
137
+ return json;
138
+ }
139
+ };
140
+ var handler_default = apolloHandler;
141
+
1
142
  // src/execute/execute.ts
2
143
  import run, { NOTIFY_JOB_COMPLETE, getNameAndVersion } from "@openfn/runtime";
3
144
 
@@ -14,7 +155,7 @@ var namespaces = {
14
155
  [COMPILER]: "CMP",
15
156
  [JOB]: "JOB"
16
157
  };
17
- var createLogger = (name = "", options) => {
158
+ var createLogger2 = (name = "", options) => {
18
159
  const logOptions = options.log || {};
19
160
  let json = false;
20
161
  let level = logOptions[name] || logOptions.default || "default";
@@ -28,25 +169,25 @@ var createLogger = (name = "", options) => {
28
169
  ...logOptions
29
170
  });
30
171
  };
31
- var logger_default = createLogger;
32
- var createNullLogger = () => createLogger(void 0, { log: { default: "none" } });
172
+ var logger_default = createLogger2;
173
+ var createNullLogger = () => createLogger2(void 0, { log: { default: "none" } });
33
174
 
34
175
  // src/util/cache.ts
35
176
  import fs from "node:fs";
36
- import path from "node:path";
177
+ import path2 from "node:path";
37
178
  import { rmdir } from "node:fs/promises";
38
179
  var getCachePath = async (plan, options, stepId) => {
39
180
  const { baseDir } = options;
40
181
  const { name } = plan.workflow;
41
182
  const basePath = `${baseDir}/.cli-cache/${name}`;
42
183
  if (stepId) {
43
- return path.resolve(`${basePath}/${stepId.replace(/ /, "-")}.json`);
184
+ return path2.resolve(`${basePath}/${stepId.replace(/ /, "-")}.json`);
44
185
  }
45
- return path.resolve(basePath);
186
+ return path2.resolve(basePath);
46
187
  };
47
188
  var ensureGitIgnore = (options) => {
48
189
  if (!options._hasGitIgnore) {
49
- const ignorePath = path.resolve(
190
+ const ignorePath = path2.resolve(
50
191
  options.baseDir,
51
192
  ".cli-cache",
52
193
  ".gitignore"
@@ -62,7 +203,7 @@ var ensureGitIgnore = (options) => {
62
203
  var saveToCache = async (plan, stepId, output, options, logger) => {
63
204
  if (options.cacheSteps) {
64
205
  const cachePath = await getCachePath(plan, options, stepId);
65
- fs.mkdirSync(path.dirname(cachePath), { recursive: true });
206
+ fs.mkdirSync(path2.dirname(cachePath), { recursive: true });
66
207
  ensureGitIgnore(options);
67
208
  logger.info(`Writing ${stepId} output to ${cachePath}`);
68
209
  fs.writeFileSync(cachePath, JSON.stringify(output));
@@ -100,7 +241,9 @@ var execute_default = async (plan, input, opts, logger) => {
100
241
  await saveToCache(plan, jobId, state, opts, logger);
101
242
  }
102
243
  }
103
- }
244
+ },
245
+ defaultRunTimeoutMs: 5 * 60 * 1e3
246
+ // 5 minutes
104
247
  });
105
248
  return result;
106
249
  } catch (e) {
@@ -110,13 +253,13 @@ var execute_default = async (plan, input, opts, logger) => {
110
253
  };
111
254
  function parseAdaptors(plan) {
112
255
  const extractInfo = (specifier) => {
113
- const [module, path8] = specifier.split("=");
256
+ const [module, path9] = specifier.split("=");
114
257
  const { name, version } = getNameAndVersion(module);
115
258
  const info = {
116
259
  name
117
260
  };
118
- if (path8) {
119
- info.path = path8;
261
+ if (path9) {
262
+ info.path = path9;
120
263
  }
121
264
  if (version) {
122
265
  info.version = version;
@@ -135,8 +278,8 @@ function parseAdaptors(plan) {
135
278
  }
136
279
 
137
280
  // src/execute/serialize-output.ts
138
- import { writeFile } from "node:fs/promises";
139
- var serializeOutput = async (options, result, logger) => {
281
+ import { writeFile as writeFile2 } from "node:fs/promises";
282
+ var serializeOutput2 = async (options, result, logger) => {
140
283
  let output = result;
141
284
  if (output && (output.configuration || output.data)) {
142
285
  const { configuration, ...rest } = result;
@@ -152,12 +295,12 @@ var serializeOutput = async (options, result, logger) => {
152
295
  logger.always(output);
153
296
  } else if (options.outputPath) {
154
297
  logger.debug(`Writing output to ${options.outputPath}`);
155
- await writeFile(options.outputPath, output);
298
+ await writeFile2(options.outputPath, output);
156
299
  logger.success(`State written to ${options.outputPath}`);
157
300
  }
158
301
  return output;
159
302
  };
160
- var serialize_output_default = serializeOutput;
303
+ var serialize_output_default = serializeOutput2;
161
304
 
162
305
  // src/execute/get-autoinstall-targets.ts
163
306
  var getAutoinstallTargets = (plan) => {
@@ -322,10 +465,10 @@ var stripVersionSpecifier = (specifier) => {
322
465
  return specifier;
323
466
  };
324
467
  var resolveSpecifierPath = async (pattern, repoDir, log) => {
325
- const [specifier, path8] = pattern.split("=");
326
- if (path8) {
327
- log.debug(`Resolved ${specifier} to path: ${path8}`);
328
- return path8;
468
+ const [specifier, path9] = pattern.split("=");
469
+ if (path9) {
470
+ log.debug(`Resolved ${specifier} to path: ${path9}`);
471
+ return path9;
329
472
  }
330
473
  const repoPath = await getModulePath(specifier, repoDir, log);
331
474
  if (repoPath) {
@@ -342,16 +485,16 @@ var loadTransformOptions = async (opts, log) => {
342
485
  const [pattern] = opts.adaptors;
343
486
  const [specifier] = pattern.split("=");
344
487
  log.debug(`Trying to preload types for ${specifier}`);
345
- const path8 = await resolveSpecifierPath(pattern, opts.repoDir, log);
346
- if (path8) {
488
+ const path9 = await resolveSpecifierPath(pattern, opts.repoDir, log);
489
+ if (path9) {
347
490
  try {
348
491
  exports = await preloadAdaptorExports(
349
- path8,
492
+ path9,
350
493
  opts.useAdaptorsMonorepo,
351
494
  log
352
495
  );
353
496
  } catch (e) {
354
- log.error(`Failed to load adaptor typedefs from path ${path8}`);
497
+ log.error(`Failed to load adaptor typedefs from path ${path9}`);
355
498
  log.error(e);
356
499
  }
357
500
  }
@@ -487,7 +630,7 @@ var validate_adaptors_default = validateAdaptors;
487
630
 
488
631
  // src/util/load-plan.ts
489
632
  import fs3 from "node:fs/promises";
490
- import path3 from "node:path";
633
+ import path4 from "node:path";
491
634
  import { isPath } from "@openfn/compiler";
492
635
 
493
636
  // src/util/expand-adaptors.ts
@@ -516,13 +659,13 @@ var expand_adaptors_default = (input) => {
516
659
  };
517
660
 
518
661
  // src/util/map-adaptors-to-monorepo.ts
519
- import { readFile } from "node:fs/promises";
520
- import path2 from "node:path";
662
+ import { readFile as readFile2 } from "node:fs/promises";
663
+ import path3 from "node:path";
521
664
  import assert from "node:assert";
522
665
  import { getNameAndVersion as getNameAndVersion2 } from "@openfn/runtime";
523
666
  var validateMonoRepo = async (repoPath, log) => {
524
667
  try {
525
- const raw = await readFile(`${repoPath}/package.json`, "utf8");
668
+ const raw = await readFile2(`${repoPath}/package.json`, "utf8");
526
669
  const pkg = JSON.parse(raw);
527
670
  assert(pkg.name === "adaptors");
528
671
  } catch (e) {
@@ -541,7 +684,7 @@ var updatePath = (adaptor, repoPath, log) => {
541
684
  );
542
685
  }
543
686
  const shortName = name.replace("@openfn/language-", "");
544
- const abspath = path2.resolve(repoPath, "packages", shortName);
687
+ const abspath = path3.resolve(repoPath, "packages", shortName);
545
688
  log.info(`Mapped adaptor ${name} to monorepo: ${abspath}`);
546
689
  return `${name}=${abspath}`;
547
690
  };
@@ -572,10 +715,10 @@ var loadPlan = async (options, logger) => {
572
715
  }
573
716
  const jsonPath = planPath || workflowPath;
574
717
  if (!options.baseDir) {
575
- options.baseDir = path3.dirname(jsonPath);
718
+ options.baseDir = path4.dirname(jsonPath);
576
719
  }
577
720
  const json = await loadJson(jsonPath, logger);
578
- const defaultName = path3.parse(jsonPath).name;
721
+ const defaultName = path4.parse(jsonPath).name;
579
722
  if (json.workflow) {
580
723
  return loadXPlan(json, options, logger, defaultName);
581
724
  } else {
@@ -621,7 +764,7 @@ var loadExpression = async (options, logger) => {
621
764
  logger.debug(`Loading expression from ${expressionPath}`);
622
765
  try {
623
766
  const expression = await fs3.readFile(expressionPath, "utf8");
624
- const name = path3.parse(expressionPath).name;
767
+ const name = path4.parse(expressionPath).name;
625
768
  const step = { expression };
626
769
  if (options.adaptors) {
627
770
  const [adaptor] = options.adaptors;
@@ -668,7 +811,7 @@ var loadOldWorkflow = async (workflow, options, logger, defaultName = "") => {
668
811
  };
669
812
  var fetchFile = async (jobId, rootDir = "", filePath, log) => {
670
813
  try {
671
- const fullPath = filePath.startsWith("~") ? filePath : path3.resolve(rootDir, filePath);
814
+ const fullPath = filePath.startsWith("~") ? filePath : path4.resolve(rootDir, filePath);
672
815
  const result = await fs3.readFile(fullPath, "utf8");
673
816
  log.debug("Loaded file", fullPath);
674
817
  return result;
@@ -731,8 +874,8 @@ var loadXPlan = async (plan, options, logger, defaultName = "") => {
731
874
  };
732
875
 
733
876
  // src/util/assert-path.ts
734
- var assert_path_default = (path8) => {
735
- if (!path8) {
877
+ var assert_path_default = (path9) => {
878
+ if (!path9) {
736
879
  console.error("ERROR: no path provided!");
737
880
  console.error("\nUsage:");
738
881
  console.error(" open path/to/job");
@@ -874,10 +1017,10 @@ var executeHandler = async (options, logger) => {
874
1017
  process.exitCode = 1;
875
1018
  }
876
1019
  };
877
- var handler_default = executeHandler;
1020
+ var handler_default2 = executeHandler;
878
1021
 
879
1022
  // src/compile/handler.ts
880
- import { writeFile as writeFile2 } from "node:fs/promises";
1023
+ import { writeFile as writeFile3 } from "node:fs/promises";
881
1024
  var compileHandler = async (options, logger) => {
882
1025
  assert_path_default(options.path);
883
1026
  let result;
@@ -891,11 +1034,11 @@ var compileHandler = async (options, logger) => {
891
1034
  if (options.outputStdout) {
892
1035
  logger.success("Result:\n\n" + result);
893
1036
  } else {
894
- await writeFile2(options.outputPath, result);
1037
+ await writeFile3(options.outputPath, result);
895
1038
  logger.success(`Compiled to ${options.outputPath}`);
896
1039
  }
897
1040
  };
898
- var handler_default2 = compileHandler;
1041
+ var handler_default3 = compileHandler;
899
1042
 
900
1043
  // src/test/handler.ts
901
1044
  var testHandler = async (options, logger) => {
@@ -947,7 +1090,7 @@ var testHandler = async (options, logger) => {
947
1090
  logger.success(`Result: ${result.data.answer}`);
948
1091
  return result;
949
1092
  };
950
- var handler_default3 = testHandler;
1093
+ var handler_default4 = testHandler;
951
1094
 
952
1095
  // src/deploy/handler.ts
953
1096
  import {
@@ -1000,33 +1143,33 @@ function mergeOverrides(config, options) {
1000
1143
  function pickFirst(...args) {
1001
1144
  return args.find((arg) => arg !== void 0 && arg !== null);
1002
1145
  }
1003
- var handler_default4 = deployHandler;
1146
+ var handler_default5 = deployHandler;
1004
1147
 
1005
1148
  // src/docgen/handler.ts
1006
- import { writeFile as writeFile3 } from "node:fs/promises";
1149
+ import { writeFile as writeFile4 } from "node:fs/promises";
1007
1150
  import { readFileSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
1008
- import path4 from "node:path";
1151
+ import path5 from "node:path";
1009
1152
  import { describePackage } from "@openfn/describe-package";
1010
1153
  import { getNameAndVersion as getNameAndVersion3 } from "@openfn/runtime";
1011
1154
  var RETRY_DURATION = 500;
1012
1155
  var RETRY_COUNT = 20;
1013
1156
  var TIMEOUT_MS = 1e3 * 60;
1014
1157
  var actualDocGen = (specifier) => describePackage(specifier, {});
1015
- var ensurePath = (filePath) => mkdirSync(path4.dirname(filePath), { recursive: true });
1016
- var generatePlaceholder = (path8) => {
1017
- writeFileSync(path8, `{ "loading": true, "timestamp": ${Date.now()}}`);
1158
+ var ensurePath = (filePath) => mkdirSync(path5.dirname(filePath), { recursive: true });
1159
+ var generatePlaceholder = (path9) => {
1160
+ writeFileSync(path9, `{ "loading": true, "timestamp": ${Date.now()}}`);
1018
1161
  };
1019
1162
  var finish = (logger, resultPath) => {
1020
1163
  logger.success("Done! Docs can be found at:\n");
1021
- logger.print(` ${path4.resolve(resultPath)}`);
1164
+ logger.print(` ${path5.resolve(resultPath)}`);
1022
1165
  };
1023
- var generateDocs = async (specifier, path8, docgen, logger) => {
1166
+ var generateDocs = async (specifier, path9, docgen, logger) => {
1024
1167
  const result = await docgen(specifier);
1025
- await writeFile3(path8, JSON.stringify(result, null, 2));
1026
- finish(logger, path8);
1027
- return path8;
1168
+ await writeFile4(path9, JSON.stringify(result, null, 2));
1169
+ finish(logger, path9);
1170
+ return path9;
1028
1171
  };
1029
- var waitForDocs = async (docs, path8, logger, retryDuration = RETRY_DURATION) => {
1172
+ var waitForDocs = async (docs, path9, logger, retryDuration = RETRY_DURATION) => {
1030
1173
  try {
1031
1174
  if (docs.hasOwnProperty("loading")) {
1032
1175
  logger.info("Docs are being loaded by another process. Waiting.");
@@ -1038,19 +1181,19 @@ var waitForDocs = async (docs, path8, logger, retryDuration = RETRY_DURATION) =>
1038
1181
  clearInterval(i);
1039
1182
  reject(new Error("Timed out waiting for docs to load"));
1040
1183
  }
1041
- const updated = JSON.parse(readFileSync(path8, "utf8"));
1184
+ const updated = JSON.parse(readFileSync(path9, "utf8"));
1042
1185
  if (!updated.hasOwnProperty("loading")) {
1043
1186
  logger.info("Docs found!");
1044
1187
  clearInterval(i);
1045
- resolve(path8);
1188
+ resolve(path9);
1046
1189
  }
1047
1190
  count++;
1048
1191
  }, retryDuration);
1049
1192
  });
1050
1193
  } else {
1051
- logger.info(`Docs already written to cache at ${path8}`);
1052
- finish(logger, path8);
1053
- return path8;
1194
+ logger.info(`Docs already written to cache at ${path9}`);
1195
+ finish(logger, path9);
1196
+ return path9;
1054
1197
  }
1055
1198
  } catch (e) {
1056
1199
  logger.error("Existing doc JSON corrupt. Aborting");
@@ -1067,38 +1210,38 @@ var docgenHandler = (options, logger, docgen = actualDocGen, retryDuration = RET
1067
1210
  process.exit(9);
1068
1211
  }
1069
1212
  logger.success(`Generating docs for ${specifier}`);
1070
- const path8 = `${repoDir}/docs/${specifier}.json`;
1071
- ensurePath(path8);
1213
+ const path9 = `${repoDir}/docs/${specifier}.json`;
1214
+ ensurePath(path9);
1072
1215
  const handleError = () => {
1073
1216
  logger.info("Removing placeholder");
1074
- rmSync(path8);
1217
+ rmSync(path9);
1075
1218
  };
1076
1219
  try {
1077
- const existing = readFileSync(path8, "utf8");
1220
+ const existing = readFileSync(path9, "utf8");
1078
1221
  const json = JSON.parse(existing);
1079
1222
  if (json && json.timeout && Date.now() - json.timeout >= TIMEOUT_MS) {
1080
1223
  logger.info(`Expired placeholder found. Removing.`);
1081
- rmSync(path8);
1224
+ rmSync(path9);
1082
1225
  throw new Error("TIMEOUT");
1083
1226
  }
1084
- return waitForDocs(json, path8, logger, retryDuration);
1227
+ return waitForDocs(json, path9, logger, retryDuration);
1085
1228
  } catch (e) {
1086
1229
  if (e.message !== "TIMEOUT") {
1087
- logger.info(`Docs JSON not found at ${path8}`);
1230
+ logger.info(`Docs JSON not found at ${path9}`);
1088
1231
  }
1089
1232
  logger.debug("Generating placeholder");
1090
- generatePlaceholder(path8);
1091
- return generateDocs(specifier, path8, docgen, logger).catch((e2) => {
1233
+ generatePlaceholder(path9);
1234
+ return generateDocs(specifier, path9, docgen, logger).catch((e2) => {
1092
1235
  logger.error("Error generating documentation");
1093
1236
  logger.error(e2);
1094
1237
  handleError();
1095
1238
  });
1096
1239
  }
1097
1240
  };
1098
- var handler_default5 = docgenHandler;
1241
+ var handler_default6 = docgenHandler;
1099
1242
 
1100
1243
  // src/docs/handler.ts
1101
- import { readFile as readFile2 } from "node:fs/promises";
1244
+ import { readFile as readFile3 } from "node:fs/promises";
1102
1245
  import c from "chalk";
1103
1246
  import { getNameAndVersion as getNameAndVersion4, getLatestVersion } from "@openfn/runtime";
1104
1247
  var describeFn = (adaptorName, fn) => [
@@ -1135,7 +1278,7 @@ var docsHandler = async (options, logger) => {
1135
1278
  logger.success(`Showing docs for ${adaptorName} v${version}`);
1136
1279
  }
1137
1280
  logger.info("Generating/loading documentation...");
1138
- const path8 = await handler_default5(
1281
+ const path9 = await handler_default6(
1139
1282
  {
1140
1283
  specifier: `${name}@${version}`,
1141
1284
  repoDir
@@ -1144,8 +1287,8 @@ var docsHandler = async (options, logger) => {
1144
1287
  createNullLogger()
1145
1288
  );
1146
1289
  let didError = false;
1147
- if (path8) {
1148
- const source = await readFile2(path8, "utf8");
1290
+ if (path9) {
1291
+ const source = await readFile3(path9, "utf8");
1149
1292
  const data = JSON.parse(source);
1150
1293
  let desc;
1151
1294
  if (operation) {
@@ -1178,13 +1321,13 @@ var docsHandler = async (options, logger) => {
1178
1321
  logger.error("Not found");
1179
1322
  }
1180
1323
  };
1181
- var handler_default6 = docsHandler;
1324
+ var handler_default7 = docsHandler;
1182
1325
 
1183
1326
  // src/metadata/cache.ts
1184
1327
  import { createHash } from "node:crypto";
1185
1328
  import { readFileSync as readFileSync2 } from "node:fs";
1186
- import path5 from "node:path";
1187
- import { writeFile as writeFile4, mkdir } from "node:fs/promises";
1329
+ import path6 from "node:path";
1330
+ import { writeFile as writeFile5, mkdir as mkdir2 } from "node:fs/promises";
1188
1331
  var getPath = (repoDir, key) => `${repoDir}/meta/${key}.json`;
1189
1332
  var sortKeys = (obj) => {
1190
1333
  const newObj = {};
@@ -1214,8 +1357,8 @@ var get = (repoPath, key) => {
1214
1357
  };
1215
1358
  var set = async (repoPath, key, data) => {
1216
1359
  const fullPath = getPath(repoPath, key);
1217
- await mkdir(path5.dirname(fullPath), { recursive: true });
1218
- await writeFile4(fullPath, JSON.stringify(data));
1360
+ await mkdir2(path6.dirname(fullPath), { recursive: true });
1361
+ await writeFile5(fullPath, JSON.stringify(data));
1219
1362
  };
1220
1363
  var cache_default = { get, set, generateKey, getPath, sortKeys };
1221
1364
 
@@ -1299,10 +1442,10 @@ var metadataHandler = async (options, logger) => {
1299
1442
  process.exit(1);
1300
1443
  }
1301
1444
  };
1302
- var handler_default7 = metadataHandler;
1445
+ var handler_default8 = metadataHandler;
1303
1446
 
1304
1447
  // src/pull/handler.ts
1305
- import path6 from "path";
1448
+ import path7 from "path";
1306
1449
  import fs4 from "node:fs/promises";
1307
1450
  import {
1308
1451
  getConfig as getConfig2,
@@ -1326,7 +1469,7 @@ async function pullHandler(options, logger) {
1326
1469
  }
1327
1470
  const state = getStateFromProjectPayload(project);
1328
1471
  await fs4.writeFile(
1329
- path6.resolve(config.statePath),
1472
+ path7.resolve(config.statePath),
1330
1473
  JSON.stringify(state, null, 2)
1331
1474
  );
1332
1475
  logger.always(
@@ -1351,7 +1494,7 @@ async function pullHandler(options, logger) {
1351
1494
  process.exitCode = 1;
1352
1495
  process.exit(1);
1353
1496
  }
1354
- const resolvedPath = path6.resolve(config.specPath);
1497
+ const resolvedPath = path7.resolve(config.specPath);
1355
1498
  logger.debug("reading spec from", resolvedPath);
1356
1499
  await fs4.writeFile(resolvedPath, res.body);
1357
1500
  const spec = await getSpec(resolvedPath);
@@ -1380,11 +1523,11 @@ function mergeOverrides2(config, options) {
1380
1523
  function pickFirst2(...args) {
1381
1524
  return args.find((arg) => arg !== void 0 && arg !== null);
1382
1525
  }
1383
- var handler_default8 = pullHandler;
1526
+ var handler_default9 = pullHandler;
1384
1527
 
1385
1528
  // src/util/print-versions.ts
1386
1529
  import { readFileSync as readFileSync3 } from "node:fs";
1387
- import path7 from "node:path";
1530
+ import path8 from "node:path";
1388
1531
  import url from "node:url";
1389
1532
  import { getNameAndVersion as getNameAndVersion5 } from "@openfn/runtime";
1390
1533
  import { mainSymbols } from "figures";
@@ -1396,7 +1539,7 @@ var { triangleRightSmall: t } = mainSymbols;
1396
1539
  var loadVersionFromPath = (adaptorPath) => {
1397
1540
  try {
1398
1541
  const pkg = JSON.parse(
1399
- readFileSync3(path7.resolve(adaptorPath, "package.json"), "utf8")
1542
+ readFileSync3(path8.resolve(adaptorPath, "package.json"), "utf8")
1400
1543
  );
1401
1544
  return pkg.version;
1402
1545
  } catch (e) {
@@ -1429,7 +1572,7 @@ var printVersions = async (logger, options = {}, includeComponents = false) => {
1429
1572
  ...[NODE, CLI2, RUNTIME2, COMPILER2, adaptorName].map((s) => s.length)
1430
1573
  );
1431
1574
  const prefix = (str) => ` ${t} ${str.padEnd(longest + 4, " ")}`;
1432
- const dirname = path7.dirname(url.fileURLToPath(import.meta.url));
1575
+ const dirname = path8.dirname(url.fileURLToPath(import.meta.url));
1433
1576
  const pkg = JSON.parse(readFileSync3(`${dirname}/../../package.json`, "utf8"));
1434
1577
  const { version, dependencies } = pkg;
1435
1578
  const compilerVersion = dependencies["@openfn/compiler"];
@@ -1469,14 +1612,15 @@ var print_versions_default = printVersions;
1469
1612
 
1470
1613
  // src/commands.ts
1471
1614
  var handlers = {
1472
- execute: handler_default,
1473
- compile: handler_default2,
1474
- test: handler_default3,
1475
- deploy: handler_default4,
1476
- docgen: handler_default5,
1477
- docs: handler_default6,
1478
- metadata: handler_default7,
1479
- pull: handler_default8,
1615
+ apollo: handler_default,
1616
+ execute: handler_default2,
1617
+ compile: handler_default3,
1618
+ test: handler_default4,
1619
+ deploy: handler_default5,
1620
+ docgen: handler_default6,
1621
+ docs: handler_default7,
1622
+ metadata: handler_default8,
1623
+ pull: handler_default9,
1480
1624
  ["repo-clean"]: clean,
1481
1625
  ["repo-install"]: install,
1482
1626
  ["repo-pwd"]: pwd,
@@ -1505,7 +1649,7 @@ var parse = async (options, log) => {
1505
1649
  logger
1506
1650
  );
1507
1651
  }
1508
- if (!/^(pull|deploy|test|version)$/.test(options.command) && !options.repoDir) {
1652
+ if (!/^(pull|deploy|test|version|apollo)$/.test(options.command) && !options.repoDir) {
1509
1653
  logger.warn(
1510
1654
  "WARNING: no repo module dir found! Using the default (/tmp/repo)"
1511
1655
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/cli",
3
- "version": "1.2.4",
3
+ "version": "1.3.0",
4
4
  "description": "CLI devtools for the openfn toolchain.",
5
5
  "engines": {
6
6
  "node": ">=18",
@@ -29,6 +29,7 @@
29
29
  "@types/node": "^18.15.13",
30
30
  "@types/rimraf": "^3.0.2",
31
31
  "@types/treeify": "^1.0.0",
32
+ "@types/ws": "^8.5.10",
32
33
  "@types/yargs": "^17.0.24",
33
34
  "ava": "5.3.1",
34
35
  "mock-fs": "^5.1.4",
@@ -44,12 +45,13 @@
44
45
  "figures": "^5.0.0",
45
46
  "rimraf": "^3.0.2",
46
47
  "treeify": "^1.1.0",
48
+ "ws": "^8.14.1",
47
49
  "yargs": "^17.7.2",
48
- "@openfn/compiler": "0.1.2",
49
50
  "@openfn/describe-package": "0.0.19",
51
+ "@openfn/compiler": "0.1.2",
50
52
  "@openfn/logger": "1.0.1",
51
53
  "@openfn/deploy": "0.4.6",
52
- "@openfn/runtime": "1.1.2"
54
+ "@openfn/runtime": "1.1.3"
53
55
  },
54
56
  "files": [
55
57
  "dist",