@openfn/cli 0.0.30 → 0.0.32

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.
@@ -0,0 +1,150 @@
1
+ // src/util/expand-adaptors.ts
2
+ var expand_adaptors_default = (names) => names?.map((name) => {
3
+ if (typeof name === "string") {
4
+ const [left] = name.split("=");
5
+ if (left.match("/") || left.endsWith(".js")) {
6
+ return name;
7
+ }
8
+ return `@openfn/language-${name}`;
9
+ }
10
+ return name;
11
+ });
12
+
13
+ // src/util/logger.ts
14
+ import actualCreateLogger, { printDuration } from "@openfn/logger";
15
+ import { isValidLogLevel, defaultLogger } from "@openfn/logger";
16
+ var CLI = "cli";
17
+ var COMPILER = "compiler";
18
+ var RUNTIME = "runtime";
19
+ var JOB = "job";
20
+ var namespaces = {
21
+ [CLI]: "CLI",
22
+ [RUNTIME]: "R/T",
23
+ [COMPILER]: "CMP",
24
+ [JOB]: "JOB"
25
+ };
26
+ var createLogger = (name = "", options) => {
27
+ const logOptions = options.log;
28
+ let level = logOptions[name] || logOptions.default || "default";
29
+ if (options.logJson) {
30
+ logOptions.json = true;
31
+ }
32
+ return actualCreateLogger(namespaces[name] || name, {
33
+ level,
34
+ ...logOptions
35
+ });
36
+ };
37
+ var logger_default = createLogger;
38
+ var createNullLogger = () => createLogger(void 0, { log: { default: "none" } });
39
+
40
+ // src/util/ensure-opts.ts
41
+ import path from "node:path";
42
+ var defaultLoggerOptions = {
43
+ default: "default",
44
+ job: "debug"
45
+ };
46
+ var ERROR_MESSAGE_LOG_LEVEL = "Unknown log level. Valid levels are none, debug, info and default.";
47
+ var ERROR_MESSAGE_LOG_COMPONENT = "Unknown log component. Valid components are cli, compiler, runtime and job.";
48
+ var DEFAULT_REPO_DIR = "/tmp/openfn/repo";
49
+ var componentShorthands = {
50
+ cmp: "compiler",
51
+ rt: "runtime",
52
+ "r/t": "runtime"
53
+ };
54
+ var isValidComponent = (v) => /^(cli|runtime|compiler|job|default)$/i.test(v);
55
+ var ensureLogOpts = (opts) => {
56
+ const components = {};
57
+ if (!opts.log && /^(version|test)$/.test(opts.command)) {
58
+ opts.log = { default: "info" };
59
+ return opts;
60
+ } else if (opts.log) {
61
+ opts.log.forEach((l) => {
62
+ let component = "";
63
+ let level = "";
64
+ if (l.match(/=/)) {
65
+ const parts = l.split("=");
66
+ component = parts[0].toLowerCase();
67
+ if (componentShorthands[component]) {
68
+ component = componentShorthands[component];
69
+ }
70
+ level = parts[1].toLowerCase();
71
+ } else {
72
+ component = "default";
73
+ level = l.toLowerCase();
74
+ }
75
+ if (!isValidComponent(component)) {
76
+ throw new Error(ERROR_MESSAGE_LOG_COMPONENT);
77
+ }
78
+ level = level.toLowerCase();
79
+ if (!isValidLogLevel(level)) {
80
+ throw new Error(ERROR_MESSAGE_LOG_LEVEL);
81
+ }
82
+ components[component] = level;
83
+ });
84
+ }
85
+ opts.log = {
86
+ ...defaultLoggerOptions,
87
+ ...components
88
+ };
89
+ return opts;
90
+ };
91
+ function ensureOpts(basePath = ".", opts) {
92
+ const newOpts = {
93
+ adaptor: opts.adaptor,
94
+ adaptors: opts.adaptors || [],
95
+ autoinstall: opts.autoinstall,
96
+ command: opts.command,
97
+ expandAdaptors: opts.expandAdaptors !== false,
98
+ force: opts.force || false,
99
+ immutable: opts.immutable || false,
100
+ log: opts.log,
101
+ logJson: typeof opts.logJson == "boolean" ? opts.logJson : Boolean(process.env.OPENFN_LOG_JSON),
102
+ compile: Boolean(opts.compile),
103
+ operation: opts.operation,
104
+ outputStdout: Boolean(opts.outputStdout),
105
+ packages: opts.packages,
106
+ repoDir: opts.repoDir || process.env.OPENFN_REPO_DIR || DEFAULT_REPO_DIR,
107
+ skipAdaptorValidation: opts.skipAdaptorValidation ?? false,
108
+ specifier: opts.specifier,
109
+ stateStdin: opts.stateStdin,
110
+ strictOutput: opts.strictOutput ?? true,
111
+ timeout: opts.timeout
112
+ };
113
+ const set = (key, value) => {
114
+ newOpts[key] = opts.hasOwnProperty(key) ? opts[key] : value;
115
+ };
116
+ if (opts.useAdaptorsMonorepo) {
117
+ newOpts.monorepoPath = process.env.OPENFN_ADAPTORS_REPO || "ERR";
118
+ }
119
+ let baseDir = basePath;
120
+ if (basePath.endsWith(".js")) {
121
+ baseDir = path.dirname(basePath);
122
+ set("jobPath", basePath);
123
+ } else {
124
+ set("jobPath", `${baseDir}/job.js`);
125
+ }
126
+ set("statePath", `${baseDir}/state.json`);
127
+ if (!opts.outputStdout) {
128
+ set(
129
+ "outputPath",
130
+ newOpts.command === "compile" ? `${baseDir}/output.js` : `${baseDir}/output.json`
131
+ );
132
+ }
133
+ ensureLogOpts(newOpts);
134
+ return newOpts;
135
+ }
136
+
137
+ export {
138
+ expand_adaptors_default,
139
+ printDuration,
140
+ CLI,
141
+ COMPILER,
142
+ RUNTIME,
143
+ JOB,
144
+ logger_default,
145
+ createNullLogger,
146
+ defaultLogger,
147
+ DEFAULT_REPO_DIR,
148
+ ensureLogOpts,
149
+ ensureOpts
150
+ };
package/dist/index.js CHANGED
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_REPO_DIR,
4
+ expand_adaptors_default
5
+ } from "./chunk-XYZNU5CH.js";
2
6
 
3
7
  // src/process/spawn.ts
4
8
  import path from "node:path";
@@ -83,92 +87,291 @@ var list = {
83
87
  }
84
88
  };
85
89
 
90
+ // src/util/command-builders.ts
91
+ var build = (opts2, yargs2) => opts2.reduce((_y, o) => yargs2.option(o.name, o.yargs), yargs2);
92
+ var ensure = (command, opts2) => (yargs2) => {
93
+ yargs2.command = command;
94
+ opts2.filter((opt) => opt.ensure).forEach((opt) => {
95
+ opt.ensure(yargs2);
96
+ });
97
+ };
98
+ var override = (command, yargs2) => {
99
+ return {
100
+ ...command,
101
+ yargs: {
102
+ ...command.yargs || {},
103
+ ...yargs2
104
+ }
105
+ };
106
+ };
107
+
108
+ // src/options.ts
109
+ import path2 from "node:path";
110
+ var setDefaultValue = (opts2, key, value) => {
111
+ const v = opts2[key];
112
+ if (isNaN(v) && !v) {
113
+ opts2[key] = value;
114
+ }
115
+ };
116
+ var adaptors = {
117
+ name: "adaptors",
118
+ yargs: {
119
+ alias: ["a", "adaptor"],
120
+ description: "A language adaptor to use for the job. Short-form names are allowed. Can include an explicit path to a local adaptor build"
121
+ },
122
+ ensure: (opts2) => {
123
+ if (opts2.adaptors) {
124
+ if (!Array.isArray(opts2.adaptors)) {
125
+ opts2.adaptors = [opts2.adaptors];
126
+ }
127
+ } else {
128
+ opts2.adaptors = [];
129
+ }
130
+ if (opts2.expandAdaptors) {
131
+ opts2.adaptors = expand_adaptors_default(opts2.adaptors);
132
+ }
133
+ delete opts2.adaptor;
134
+ delete opts2.a;
135
+ }
136
+ };
137
+ var autoinstall = {
138
+ name: "autoinstall",
139
+ yargs: {
140
+ alias: ["i"],
141
+ boolean: true,
142
+ description: "Auto-install the language adaptor",
143
+ default: false
144
+ }
145
+ };
146
+ var compile = {
147
+ name: "no-compile",
148
+ yargs: {
149
+ boolean: true,
150
+ description: "Disable compilation of the incoming source"
151
+ },
152
+ ensure: (opts2) => {
153
+ setDefaultValue(opts2, "compile", true);
154
+ }
155
+ };
156
+ var expandAdaptors = {
157
+ name: "no-expand-adaptors",
158
+ yargs: {
159
+ boolean: true,
160
+ description: "Don't attempt to auto-expand adaptor shorthand names"
161
+ },
162
+ ensure: (opts2) => {
163
+ setDefaultValue(opts2, "expandAdaptors", true);
164
+ }
165
+ };
166
+ var force = {
167
+ name: "force",
168
+ yargs: {
169
+ alias: ["f"],
170
+ boolean: true,
171
+ description: "Force metadata to be regenerated",
172
+ default: false
173
+ }
174
+ };
175
+ var immutable = {
176
+ name: "immutable",
177
+ yargs: {
178
+ description: "Enforce immutabilty on state object",
179
+ boolean: true,
180
+ default: false
181
+ }
182
+ };
183
+ var getBaseDir = (opts2) => {
184
+ const basePath = opts2.path ?? ".";
185
+ if (basePath.endsWith(".js")) {
186
+ return path2.dirname(basePath);
187
+ }
188
+ return basePath;
189
+ };
190
+ var jobPath = {
191
+ name: "job-path",
192
+ yargs: {
193
+ hidden: true
194
+ },
195
+ ensure: (opts2) => {
196
+ const { path: basePath } = opts2;
197
+ if (basePath?.endsWith(".js")) {
198
+ opts2.jobPath = basePath;
199
+ } else {
200
+ const base = getBaseDir(opts2);
201
+ setDefaultValue(opts2, "jobPath", path2.join(base, "job.js"));
202
+ }
203
+ }
204
+ };
205
+ var logJson = {
206
+ name: "log-json",
207
+ yargs: {
208
+ description: "Output all logs as JSON objects",
209
+ boolean: true
210
+ },
211
+ ensure: () => {
212
+ }
213
+ };
214
+ var outputStdout = {
215
+ name: "output-stdout",
216
+ yargs: {
217
+ alias: "O",
218
+ boolean: true,
219
+ description: "Print output to stdout (instead of a file)"
220
+ },
221
+ ensure: (opts2) => {
222
+ setDefaultValue(opts2, "outputStdout", false);
223
+ }
224
+ };
225
+ var outputPath = {
226
+ name: "output-path",
227
+ yargs: {
228
+ alias: "o",
229
+ description: "Path to the output file"
230
+ },
231
+ ensure: (opts2) => {
232
+ if (opts2.command == "compile") {
233
+ if (opts2.outputPath) {
234
+ delete opts2.outputStdout;
235
+ }
236
+ } else {
237
+ if (opts2.outputStdout) {
238
+ delete opts2.outputPath;
239
+ } else {
240
+ const base = getBaseDir(opts2);
241
+ setDefaultValue(opts2, "outputPath", path2.join(base, "output.json"));
242
+ }
243
+ }
244
+ delete opts2.o;
245
+ }
246
+ };
247
+ var repoDir = {
248
+ name: "repo-dir",
249
+ yargs: {
250
+ description: "Provide a path to the repo root dir",
251
+ default: process.env.OPENFN_REPO_DIR || DEFAULT_REPO_DIR
252
+ }
253
+ };
254
+ var strictOutput = {
255
+ name: "no-strict-output",
256
+ yargs: {
257
+ boolean: true,
258
+ description: "Allow properties other than data to be returned in the output"
259
+ },
260
+ ensure: (opts2) => {
261
+ setDefaultValue(opts2, "strictOutput", true);
262
+ }
263
+ };
264
+ var skipAdaptorValidation = {
265
+ name: "skip-adaptor-validation",
266
+ yargs: {
267
+ boolean: true,
268
+ description: "Suppress warning message for jobs which don't use an adaptor",
269
+ default: false
270
+ }
271
+ };
272
+ var statePath = {
273
+ name: "state-path",
274
+ yargs: {
275
+ alias: ["s"],
276
+ description: "Path to the state file"
277
+ }
278
+ };
279
+ var stateStdin = {
280
+ name: "state-stdin",
281
+ yargs: {
282
+ alias: ["S"],
283
+ description: "Read state from stdin (instead of a file)"
284
+ }
285
+ };
286
+ var timeout = {
287
+ name: "timeout",
288
+ yargs: {
289
+ alias: ["t"],
290
+ number: true,
291
+ description: "Set the timeout duration (ms). Defaults to 5 minutes.",
292
+ default: 5 * 60 * 1e3
293
+ }
294
+ };
295
+ var useAdaptorsMonorepo = {
296
+ name: "use-adaptors-monorepo",
297
+ yargs: {
298
+ alias: ["m"],
299
+ boolean: true,
300
+ description: "Load adaptors from the monorepo. The OPENFN_ADAPTORS_REPO env var must be set to a valid path"
301
+ },
302
+ ensure: (opts2) => {
303
+ if (opts2.useAdaptorsMonorepo) {
304
+ opts2.monorepoPath = process.env.OPENFN_ADAPTORS_REPO || "ERR";
305
+ }
306
+ }
307
+ };
308
+
86
309
  // src/execute/command.ts
310
+ var options = [
311
+ expandAdaptors,
312
+ adaptors,
313
+ autoinstall,
314
+ compile,
315
+ immutable,
316
+ jobPath,
317
+ logJson,
318
+ outputPath,
319
+ outputStdout,
320
+ repoDir,
321
+ skipAdaptorValidation,
322
+ statePath,
323
+ stateStdin,
324
+ strictOutput,
325
+ timeout,
326
+ useAdaptorsMonorepo
327
+ ];
87
328
  var executeCommand = {
88
329
  command: "execute [path]",
89
330
  desc: `Run an openfn job. Get more help by running openfn <command> help`,
90
331
  aliases: ["$0"],
91
- handler: (argv) => {
92
- argv.command = "execute";
93
- },
94
- builder: (yargs2) => {
95
- return applyExecuteOptions(yargs2).option("immutable", {
96
- boolean: true,
97
- description: "Treat state as immutable"
98
- }).option("use-adaptors-monorepo", {
99
- alias: "m",
100
- boolean: true,
101
- description: "Load adaptors from the monorepo. The OPENFN_ADAPTORS_REPO env var must be set to a valid path"
102
- }).option("autoinstall", {
103
- alias: "i",
104
- boolean: true,
105
- description: "Auto-install the language adaptor"
106
- }).option("state-path", {
107
- alias: "s",
108
- description: "Path to the state file"
109
- }).option("state-stdin", {
110
- alias: "S",
111
- description: "Read state from stdin (instead of a file)"
112
- }).option("skip-adaptor-validation", {
113
- boolean: true,
114
- description: "Skip adaptor validation warnings"
115
- }).option("timeout", {
116
- alias: "-t",
117
- description: "Set the timeout duration in MS"
118
- }).option("no-compile", {
119
- boolean: true,
120
- description: "Skip compilation"
121
- }).option("no-strict-output", {
122
- boolean: true,
123
- description: "Allow properties other than data to be returned in the output"
124
- }).example(
125
- "openfn foo/job.js",
126
- "Reads foo/job.js, looks for state and output in foo"
127
- ).example(
128
- "openfn job.js -a common",
129
- "Run job.js using @openfn/language-common"
130
- ).example(
131
- "openfn install -a common",
132
- "Install the latest version of language-common to the repo"
133
- );
134
- }
332
+ handler: ensure("execute", options),
333
+ builder: (yargs2) => build(options, yargs2).positional("path", {
334
+ describe: "The path to load the job from (a .js file or a dir containing a job.js file)",
335
+ demandOption: true
336
+ }).example(
337
+ "openfn foo/job.js",
338
+ "Reads foo/job.js, looks for state and output in foo"
339
+ ).example(
340
+ "openfn job.js -a common",
341
+ "Run job.js using @openfn/language-common"
342
+ ).example(
343
+ "openfn install -a common",
344
+ "Install the latest version of language-common to the repo"
345
+ )
135
346
  };
136
- var applyExecuteOptions = (yargs2) => yargs2.positional("path", {
137
- describe: "The path to load the job from (a .js file or a dir containing a job.js file)",
138
- demandOption: true
139
- }).option("output-path", {
140
- alias: "o",
141
- description: "Path to the output file"
142
- }).option("output-stdout", {
143
- alias: "O",
144
- boolean: true,
145
- description: "Print output to stdout (instead of a file)"
146
- }).option("adaptors", {
147
- alias: ["a", "adaptor"],
148
- description: "A language adaptor to use for the job. Short-form names are allowed. Can include an explicit path to a local adaptor build",
149
- array: true
150
- }).option("no-expand", {
151
- description: "Don attempt to auto-expand adaptor shorthand names",
152
- boolean: true
153
- });
154
347
  var command_default = executeCommand;
155
348
 
156
349
  // src/compile/command.ts
350
+ var options2 = [
351
+ expandAdaptors,
352
+ adaptors,
353
+ jobPath,
354
+ logJson,
355
+ override(outputStdout, {
356
+ default: true
357
+ }),
358
+ outputPath,
359
+ useAdaptorsMonorepo
360
+ ];
157
361
  var compileCommand = {
158
362
  command: "compile [path]",
159
- desc: "compile a openfn job and print or save the resulting js",
160
- handler: (argv) => {
161
- argv.command = "compile";
162
- },
163
- builder: (yargs2) => {
164
- return applyExecuteOptions(yargs2).example(
165
- "compile foo/job.js -O",
166
- "Compiles foo/job.js and prints the result to stdout"
167
- ).example(
168
- "compile foo/job.js -o foo/job-compiled.js",
169
- "Compiles foo/job.js and saves the result to foo/job-compiled.js"
170
- );
171
- }
363
+ desc: "Compile an openfn job and print or save the resulting JavaScript.",
364
+ handler: ensure("compile", options2),
365
+ builder: (yargs2) => build(options2, yargs2).positional("path", {
366
+ describe: "The path to load the job from (a .js file or a dir containing a job.js file)",
367
+ demandOption: true
368
+ }).example(
369
+ "compile foo/job.js -O",
370
+ "Compiles foo/job.js and prints the result to stdout"
371
+ ).example(
372
+ "compile foo/job.js -o foo/job-compiled.js",
373
+ "Compiles foo/job.js and saves the result to foo/job-compiled.js"
374
+ )
172
375
  };
173
376
  var command_default2 = compileCommand;
174
377
 
@@ -208,8 +411,29 @@ var command_default5 = {
208
411
  builder: (yargs2) => yargs2.example("docs common fn", "Print help for the common fn operation")
209
412
  };
210
413
 
414
+ // src/metadata/command.ts
415
+ var options3 = [
416
+ expandAdaptors,
417
+ adaptors,
418
+ force,
419
+ logJson,
420
+ repoDir,
421
+ statePath,
422
+ stateStdin,
423
+ useAdaptorsMonorepo
424
+ ];
425
+ var command_default6 = {
426
+ command: "metadata",
427
+ desc: "Generate metadata for an adaptor config",
428
+ handler: ensure("metadata", options3),
429
+ builder: (yargs2) => build(options3, yargs2).example(
430
+ "metadata -a salesforce -s tmp/state.json",
431
+ "Generate salesforce metadata from config in state.json"
432
+ )
433
+ };
434
+
211
435
  // src/cli.ts
212
- var cmd = yargs(hideBin(process.argv)).command(command_default).command(command_default2).command(install).command(repo).command(command_default3).command(command_default5).command(command_default4).option("log", {
436
+ var cmd = yargs(hideBin(process.argv)).command(command_default).command(command_default2).command(install).command(repo).command(command_default3).command(command_default5).command(command_default6).command(command_default4).option("log", {
213
437
  alias: ["l"],
214
438
  description: "Set the default log level to none, default, info or debug",
215
439
  array: true
@@ -1,124 +1,19 @@
1
- // src/util/logger.ts
2
- import actualCreateLogger, { printDuration } from "@openfn/logger";
3
- import { isValidLogLevel, defaultLogger } from "@openfn/logger";
4
- var CLI = "cli";
5
- var COMPILER = "compiler";
6
- var RUNTIME = "runtime";
7
- var JOB = "job";
8
- var namespaces = {
9
- [CLI]: "CLI",
10
- [RUNTIME]: "R/T",
11
- [COMPILER]: "CMP",
12
- [JOB]: "JOB"
13
- };
14
- var createLogger = (name = "", options) => {
15
- const logOptions = options.log || { json: true };
16
- let level = logOptions[name] || logOptions.default || "default";
17
- if (options.logJson) {
18
- logOptions.json = true;
19
- }
20
- return actualCreateLogger(namespaces[name] || name, {
21
- level,
22
- ...logOptions
23
- });
24
- };
25
- var logger_default = createLogger;
26
- var createNullLogger = () => createLogger(void 0, { log: { default: "none" } });
1
+ import {
2
+ CLI,
3
+ COMPILER,
4
+ JOB,
5
+ RUNTIME,
6
+ createNullLogger,
7
+ defaultLogger,
8
+ ensureLogOpts,
9
+ ensureOpts,
10
+ expand_adaptors_default,
11
+ logger_default,
12
+ printDuration
13
+ } from "../chunk-XYZNU5CH.js";
27
14
 
28
- // src/util/ensure-opts.ts
29
- import path from "node:path";
30
- var defaultLoggerOptions = {
31
- default: "default",
32
- job: "debug"
33
- };
34
- var ERROR_MESSAGE_LOG_LEVEL = "Unknown log level. Valid levels are none, debug, info and default.";
35
- var ERROR_MESSAGE_LOG_COMPONENT = "Unknown log component. Valid components are cli, compiler, runtime and job.";
36
- var DEFAULT_REPO_DIR = "/tmp/openfn/repo";
37
- var componentShorthands = {
38
- cmp: "compiler",
39
- rt: "runtime",
40
- "r/t": "runtime"
41
- };
42
- var isValidComponent = (v) => /^(cli|runtime|compiler|job|default)$/i.test(v);
43
- var ensureLogOpts = (opts) => {
44
- const components = {};
45
- if (opts.command === "version" || opts.command === "test" && !opts.log) {
46
- return { default: "info" };
47
- }
48
- if (opts.log) {
49
- opts.log.forEach((l) => {
50
- let component = "";
51
- let level = "";
52
- if (l.match(/=/)) {
53
- const parts = l.split("=");
54
- component = parts[0].toLowerCase();
55
- if (componentShorthands[component]) {
56
- component = componentShorthands[component];
57
- }
58
- level = parts[1].toLowerCase();
59
- } else {
60
- component = "default";
61
- level = l.toLowerCase();
62
- }
63
- if (!isValidComponent(component)) {
64
- throw new Error(ERROR_MESSAGE_LOG_COMPONENT);
65
- }
66
- level = level.toLowerCase();
67
- if (!isValidLogLevel(level)) {
68
- throw new Error(ERROR_MESSAGE_LOG_LEVEL);
69
- }
70
- components[component] = level;
71
- });
72
- }
73
- return {
74
- ...defaultLoggerOptions,
75
- ...components
76
- };
77
- };
78
- function ensureOpts(basePath = ".", opts) {
79
- const newOpts = {
80
- adaptor: opts.adaptor,
81
- adaptors: opts.adaptors || [],
82
- autoinstall: opts.autoinstall,
83
- command: opts.command,
84
- expand: opts.expand !== false,
85
- force: opts.force || false,
86
- immutable: opts.immutable || false,
87
- logJson: typeof opts.logJson == "boolean" ? opts.logJson : Boolean(process.env.OPENFN_LOG_JSON),
88
- noCompile: Boolean(opts.noCompile),
89
- operation: opts.operation,
90
- outputStdout: Boolean(opts.outputStdout),
91
- packages: opts.packages,
92
- repoDir: opts.repoDir || process.env.OPENFN_REPO_DIR || DEFAULT_REPO_DIR,
93
- skipAdaptorValidation: opts.skipAdaptorValidation ?? false,
94
- specifier: opts.specifier,
95
- stateStdin: opts.stateStdin,
96
- strictOutput: opts.strictOutput ?? true,
97
- statePath: opts.statePath,
98
- timeout: opts.timeout
99
- };
100
- const set = (key, value) => {
101
- newOpts[key] = opts.hasOwnProperty(key) ? opts[key] : value;
102
- };
103
- if (opts.useAdaptorsMonorepo) {
104
- newOpts.monorepoPath = process.env.OPENFN_ADAPTORS_REPO || "ERR";
105
- }
106
- let baseDir = basePath;
107
- if (basePath.endsWith(".js")) {
108
- baseDir = path.dirname(basePath);
109
- set("jobPath", basePath);
110
- } else {
111
- set("jobPath", `${baseDir}/job.js`);
112
- }
113
- if (!opts.outputStdout) {
114
- set(
115
- "outputPath",
116
- newOpts.command === "compile" ? `${baseDir}/output.js` : `${baseDir}/output.json`
117
- );
118
- }
119
- newOpts.log = ensureLogOpts(opts);
120
- return newOpts;
121
- }
15
+ // src/execute/handler.ts
16
+ import { readFile } from "node:fs/promises";
122
17
 
123
18
  // src/execute/load-state.ts
124
19
  import fs from "node:fs/promises";
@@ -150,7 +45,9 @@ var load_state_default = async (opts, log) => {
150
45
  log.warn(e);
151
46
  }
152
47
  }
153
- log.info("No state provided - using default state { data: {}, configuration: {}");
48
+ log.info(
49
+ "No state provided - using default state { data: {}, configuration: {}"
50
+ );
154
51
  return {
155
52
  data: {},
156
53
  configuration: {}
@@ -190,25 +87,17 @@ function parseAdaptors(opts) {
190
87
  }
191
88
 
192
89
  // src/compile/compile.ts
193
- import fs2 from "node:fs/promises";
194
90
  import compile, { preloadAdaptorExports } from "@openfn/compiler";
195
91
  import { getModulePath } from "@openfn/runtime";
196
92
  var compile_default = async (opts, log) => {
197
93
  log.debug("Loading job...");
198
- let job;
199
- if (opts.noCompile) {
200
- log.info("Skipping compilation as noCompile is set");
201
- job = fs2.readFile(opts.jobPath, "utf8");
202
- log.success(`Loaded job from ${opts.jobPath} (no compilation)`);
94
+ const compilerOptions = await loadTransformOptions(opts, log);
95
+ compilerOptions.logger = logger_default(COMPILER, opts);
96
+ const job = compile(opts.jobSource || opts.jobPath, compilerOptions);
97
+ if (opts.jobPath) {
98
+ log.success(`Compiled job from ${opts.jobPath}`);
203
99
  } else {
204
- const complilerOptions = await loadTransformOptions(opts, log);
205
- complilerOptions.logger = logger_default(COMPILER, opts);
206
- job = compile(opts.jobSource || opts.jobPath, complilerOptions);
207
- if (opts.jobPath) {
208
- log.success(`Compiled job from ${opts.jobPath}`);
209
- } else {
210
- log.success("Compiled job");
211
- }
100
+ log.success("Compiled job");
212
101
  }
213
102
  return job;
214
103
  };
@@ -302,19 +191,6 @@ var serialize_output_default = serializeOutput;
302
191
  import { exec } from "node:child_process";
303
192
  import treeify from "treeify";
304
193
  import { install as rtInstall, loadRepoPkg } from "@openfn/runtime";
305
-
306
- // src/util/expand-adaptors.ts
307
- var nullLogger = createNullLogger();
308
- var expand_adaptors_default = (names, log = nullLogger) => names?.map((name) => {
309
- if (name.startsWith("@openfn/language-")) {
310
- return name;
311
- }
312
- const expanded = `@openfn/language-${name}`;
313
- log.debug(`Expanded adaptor ${name} to ${expanded}`);
314
- return expanded;
315
- });
316
-
317
- // src/repo/handler.ts
318
194
  var install = async (opts, log = defaultLogger) => {
319
195
  let { packages, adaptor, repoDir } = opts;
320
196
  if (packages) {
@@ -322,7 +198,7 @@ var install = async (opts, log = defaultLogger) => {
322
198
  log.success("Installing packages...");
323
199
  log.debug("repoDir is set to:", repoDir);
324
200
  if (adaptor) {
325
- packages = expand_adaptors_default(packages, log);
201
+ packages = expand_adaptors_default(packages);
326
202
  }
327
203
  await rtInstall(packages, repoDir, log);
328
204
  const duration = log.timer("install");
@@ -421,7 +297,16 @@ var executeHandler = async (options, logger) => {
421
297
  }
422
298
  }
423
299
  const state = await load_state_default(options, logger);
424
- const code = await compile_default(options, logger);
300
+ let code = "";
301
+ if (options.compile) {
302
+ code = await compile_default(options, logger);
303
+ } else {
304
+ logger.info("Skipping compilation as noCompile is set");
305
+ if (options.jobPath) {
306
+ code = await readFile(options.jobPath, "utf8");
307
+ logger.success(`Loaded job from ${options.jobPath} (no compilation)`);
308
+ }
309
+ }
425
310
  try {
426
311
  const result = await execute_default(code, state, options);
427
312
  await serialize_output_default(options, result, logger);
@@ -454,6 +339,7 @@ var handler_default2 = compileHandler;
454
339
  var sillyMessage = "Calculating the answer to life, the universe, and everything...";
455
340
  var testHandler = async (options, logger) => {
456
341
  logger.log("Running test job...");
342
+ options.compile = true;
457
343
  options.jobSource = `const fn = () => state => { console.log('${sillyMessage}'); return state * 2; } ; fn()`;
458
344
  delete options.jobPath;
459
345
  if (!options.stateStdin) {
@@ -472,20 +358,20 @@ var handler_default3 = testHandler;
472
358
  // src/docgen/handler.ts
473
359
  import { writeFile as writeFile3 } from "node:fs/promises";
474
360
  import { readFileSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
475
- import path2 from "node:path";
361
+ import path from "node:path";
476
362
  import { describePackage } from "@openfn/describe-package";
477
363
  import { getNameAndVersion as getNameAndVersion2 } from "@openfn/runtime";
478
364
  var RETRY_DURATION = 500;
479
365
  var RETRY_COUNT = 20;
480
366
  var TIMEOUT_MS = 1e3 * 60;
481
367
  var actualDocGen = (specifier) => describePackage(specifier, {});
482
- var ensurePath = (filePath) => mkdirSync(path2.dirname(filePath), { recursive: true });
368
+ var ensurePath = (filePath) => mkdirSync(path.dirname(filePath), { recursive: true });
483
369
  var generatePlaceholder = (path5) => {
484
370
  writeFileSync(path5, `{ "loading": true, "timestamp": ${Date.now()}}`);
485
371
  };
486
372
  var finish = (logger, resultPath) => {
487
373
  logger.success("Done! Docs can be found at:\n");
488
- logger.print(` ${path2.resolve(resultPath)}`);
374
+ logger.print(` ${path.resolve(resultPath)}`);
489
375
  };
490
376
  var generateDocs = async (specifier, path5, docgen, logger) => {
491
377
  const result = await docgen(specifier);
@@ -565,7 +451,7 @@ var docgenHandler = (options, logger, docgen = actualDocGen, retryDuration = RET
565
451
  var handler_default4 = docgenHandler;
566
452
 
567
453
  // src/docs/handler.ts
568
- import { readFile } from "node:fs/promises";
454
+ import { readFile as readFile2 } from "node:fs/promises";
569
455
  import { getNameAndVersion as getNameAndVersion3, getLatestVersion } from "@openfn/runtime";
570
456
  var describeFn = (adaptorName, fn) => `## ${fn.name}(${fn.parameters.map(({ name }) => name).join(",")})
571
457
 
@@ -611,7 +497,7 @@ var docsHandler = async (options, logger) => {
611
497
  createNullLogger()
612
498
  );
613
499
  if (path5) {
614
- const source = await readFile(path5, "utf8");
500
+ const source = await readFile2(path5, "utf8");
615
501
  const data = JSON.parse(source);
616
502
  let desc;
617
503
  if (operation) {
@@ -632,14 +518,115 @@ var docsHandler = async (options, logger) => {
632
518
  };
633
519
  var handler_default5 = docsHandler;
634
520
 
521
+ // src/metadata/cache.ts
522
+ import { createHash } from "node:crypto";
523
+ import { readFileSync as readFileSync2 } from "node:fs";
524
+ import path2 from "node:path";
525
+ import { writeFile as writeFile4, mkdir } from "node:fs/promises";
526
+ var getPath = (repoDir, key) => `${repoDir}/meta/${key}.json`;
527
+ var generateKey = (config) => createHash("sha256").update(JSON.stringify(config)).digest("hex");
528
+ var get = (repoPath, key) => {
529
+ try {
530
+ const data = readFileSync2(getPath(repoPath, key));
531
+ const json = JSON.parse(data);
532
+ return json;
533
+ } catch (e) {
534
+ return null;
535
+ }
536
+ };
537
+ var set = async (repoPath, key, data) => {
538
+ const fullPath = getPath(repoPath, key);
539
+ await mkdir(path2.dirname(fullPath), { recursive: true });
540
+ await writeFile4(fullPath, JSON.stringify(data));
541
+ };
542
+ var cache_default = { get, set, generateKey, getPath };
543
+
544
+ // src/metadata/handler.ts
545
+ import { getModuleEntryPoint } from "@openfn/runtime";
546
+ var decorateMetadata = (metadata) => {
547
+ metadata.created = new Date().toISOString();
548
+ };
549
+ var getAdaptorPath = async (adaptor, logger, repoDir) => {
550
+ let adaptorPath;
551
+ let adaptorSpecifier;
552
+ if (adaptor.match("=")) {
553
+ const parts = adaptor.split("=");
554
+ adaptorSpecifier = parts[0];
555
+ adaptorPath = parts[1];
556
+ } else {
557
+ if (adaptor.endsWith(".js")) {
558
+ return adaptor;
559
+ }
560
+ adaptorSpecifier = adaptor;
561
+ if (adaptor.startsWith("/")) {
562
+ adaptorPath = adaptor;
563
+ }
564
+ }
565
+ if (!adaptorPath || !adaptorPath.endsWith("js")) {
566
+ const entry = await getModuleEntryPoint(
567
+ adaptorSpecifier,
568
+ adaptorPath,
569
+ repoDir,
570
+ logger
571
+ );
572
+ adaptorPath = entry?.path;
573
+ }
574
+ logger.debug("loading adaptor from", adaptorPath);
575
+ return adaptorPath;
576
+ };
577
+ var metadataHandler = async (options, logger) => {
578
+ const { repoDir, adaptors } = options;
579
+ const adaptor = adaptors[0];
580
+ const state = await load_state_default(options, logger);
581
+ logger.success(`Generating metadata`);
582
+ const config = state.configuration;
583
+ logger.info("config:", config);
584
+ if (!config || Object.keys(config).length === 0) {
585
+ logger.error("ERROR: Invalid configuration passed");
586
+ process.exit(1);
587
+ }
588
+ const finish2 = () => {
589
+ logger.success("Done!");
590
+ logger.print(cache_default.getPath(repoDir, id));
591
+ };
592
+ const id = cache_default.generateKey(config);
593
+ if (!options.force) {
594
+ logger.debug("config hash: ", id);
595
+ const cached = await cache_default.get(repoDir, id);
596
+ if (cached) {
597
+ logger.success("Returning metadata from cache");
598
+ return finish2();
599
+ }
600
+ }
601
+ try {
602
+ const adaptorPath = await getAdaptorPath(adaptor, logger, options.repoDir);
603
+ const mod = await import(adaptorPath);
604
+ if (mod.metadata) {
605
+ logger.info("Metadata function found. Generating metadata...");
606
+ const result = await mod.metadata(config);
607
+ decorateMetadata(result);
608
+ await cache_default.set(repoDir, id, result);
609
+ finish2();
610
+ } else {
611
+ logger.error("No metadata helper found");
612
+ process.exit(1);
613
+ }
614
+ } catch (e) {
615
+ logger.error("Exception while generating metadata");
616
+ logger.error(e);
617
+ process.exit(1);
618
+ }
619
+ };
620
+ var handler_default6 = metadataHandler;
621
+
635
622
  // src/util/use-adaptors-repo.ts
636
- import { readFile as readFile2 } from "node:fs/promises";
623
+ import { readFile as readFile3 } from "node:fs/promises";
637
624
  import path3 from "node:path";
638
625
  import assert from "node:assert";
639
626
  import { getNameAndVersion as getNameAndVersion4 } from "@openfn/runtime";
640
627
  var validateMonoRepo = async (repoPath, log) => {
641
628
  try {
642
- const raw = await readFile2(`${repoPath}/package.json`, "utf8");
629
+ const raw = await readFile3(`${repoPath}/package.json`, "utf8");
643
630
  const pkg = JSON.parse(raw);
644
631
  assert(pkg.name === "adaptors");
645
632
  } catch (e) {
@@ -674,7 +661,7 @@ var useAdaptorsRepo = async (adaptors, repoPath, log) => {
674
661
  var use_adaptors_repo_default = useAdaptorsRepo;
675
662
 
676
663
  // src/util/print-versions.ts
677
- import { readFileSync as readFileSync2 } from "node:fs";
664
+ import { readFileSync as readFileSync3 } from "node:fs";
678
665
  import path4 from "node:path";
679
666
  import { getNameAndVersion as getNameAndVersion5 } from "@openfn/runtime";
680
667
  import { mainSymbols } from "figures";
@@ -685,7 +672,7 @@ var COMPILER2 = "compiler";
685
672
  var { triangleRightSmall: t } = mainSymbols;
686
673
  var loadVersionFromPath = (adaptorPath) => {
687
674
  try {
688
- const pkg = JSON.parse(readFileSync2(path4.resolve(adaptorPath, "package.json"), "utf8"));
675
+ const pkg = JSON.parse(readFileSync3(path4.resolve(adaptorPath, "package.json"), "utf8"));
689
676
  return pkg.version;
690
677
  } catch (e) {
691
678
  return "unknown";
@@ -755,14 +742,16 @@ var handlers = {
755
742
  test: handler_default3,
756
743
  docgen: handler_default4,
757
744
  docs: handler_default5,
745
+ metadata: handler_default6,
758
746
  ["repo-clean"]: clean,
759
747
  ["repo-install"]: install,
760
748
  ["repo-pwd"]: pwd,
761
749
  ["repo-list"]: list,
762
750
  version: async (opts, logger) => print_versions_default(logger, opts)
763
751
  };
752
+ var maybeEnsureOpts = (basePath, options) => /^(execute|compile)$/.test(options.command) ? ensureLogOpts(options) : ensureOpts(basePath, options);
764
753
  var parse = async (basePath, options, log) => {
765
- const opts = ensureOpts(basePath, options);
754
+ const opts = maybeEnsureOpts(basePath, options);
766
755
  const logger = log || logger_default(CLI, opts);
767
756
  if (opts.command === "execute" || opts.command === "test") {
768
757
  await print_versions_default(logger, opts);
@@ -780,8 +769,8 @@ var parse = async (basePath, options, log) => {
780
769
  opts.monorepoPath,
781
770
  logger
782
771
  );
783
- } else if (opts.adaptors && opts.expand) {
784
- opts.adaptors = expand_adaptors_default(opts.adaptors, logger);
772
+ } else if (opts.adaptors && opts.expandAdaptors) {
773
+ opts.adaptors = expand_adaptors_default(opts.adaptors);
785
774
  }
786
775
  if (/^(test|version)$/.test(opts.command) && !opts.repoDir) {
787
776
  logger.warn(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/cli",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
4
4
  "description": "CLI devtools for the openfn toolchain.",
5
5
  "engines": {
6
6
  "node": ">=18",
@@ -41,10 +41,10 @@
41
41
  "rimraf": "^3.0.2",
42
42
  "treeify": "^1.1.0",
43
43
  "yargs": "^17.5.1",
44
- "@openfn/compiler": "0.0.25",
44
+ "@openfn/compiler": "0.0.26",
45
45
  "@openfn/describe-package": "0.0.14",
46
- "@openfn/runtime": "0.0.19",
47
- "@openfn/logger": "0.0.10"
46
+ "@openfn/logger": "0.0.11",
47
+ "@openfn/runtime": "0.0.20"
48
48
  },
49
49
  "files": [
50
50
  "dist",