@openfn/cli 0.0.31 → 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.
@@ -1,7 +1,8 @@
1
1
  // src/util/expand-adaptors.ts
2
2
  var expand_adaptors_default = (names) => names?.map((name) => {
3
3
  if (typeof name === "string") {
4
- if (name.startsWith("@openfn/language-")) {
4
+ const [left] = name.split("=");
5
+ if (left.match("/") || left.endsWith(".js")) {
5
6
  return name;
6
7
  }
7
8
  return `@openfn/language-${name}`;
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  DEFAULT_REPO_DIR,
4
4
  expand_adaptors_default
5
- } from "./chunk-Q2H7WYJB.js";
5
+ } from "./chunk-XYZNU5CH.js";
6
6
 
7
7
  // src/process/spawn.ts
8
8
  import path from "node:path";
@@ -163,6 +163,15 @@ var expandAdaptors = {
163
163
  setDefaultValue(opts2, "expandAdaptors", true);
164
164
  }
165
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
+ };
166
175
  var immutable = {
167
176
  name: "immutable",
168
177
  yargs: {
@@ -402,8 +411,29 @@ var command_default5 = {
402
411
  builder: (yargs2) => yargs2.example("docs common fn", "Print help for the common fn operation")
403
412
  };
404
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
+
405
435
  // src/cli.ts
406
- 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", {
407
437
  alias: ["l"],
408
438
  description: "Set the default log level to none, default, info or debug",
409
439
  array: true
@@ -10,7 +10,7 @@ import {
10
10
  expand_adaptors_default,
11
11
  logger_default,
12
12
  printDuration
13
- } from "../chunk-Q2H7WYJB.js";
13
+ } from "../chunk-XYZNU5CH.js";
14
14
 
15
15
  // src/execute/handler.ts
16
16
  import { readFile } from "node:fs/promises";
@@ -71,11 +71,11 @@ var execute_default = (code, state, opts) => {
71
71
  function parseAdaptors(opts) {
72
72
  const adaptors = {};
73
73
  opts.adaptors.reduce((obj, exp) => {
74
- const [module, path4] = exp.split("=");
74
+ const [module, path5] = exp.split("=");
75
75
  const { name, version } = getNameAndVersion(module);
76
76
  const info = {};
77
- if (path4) {
78
- info.path = path4;
77
+ if (path5) {
78
+ info.path = path5;
79
79
  }
80
80
  if (version) {
81
81
  info.version = version;
@@ -109,10 +109,10 @@ var stripVersionSpecifier = (specifier) => {
109
109
  return specifier;
110
110
  };
111
111
  var resolveSpecifierPath = async (pattern, repoDir, log) => {
112
- const [specifier, path4] = pattern.split("=");
113
- if (path4) {
114
- log.debug(`Resolved ${specifier} to path: ${path4}`);
115
- return path4;
112
+ const [specifier, path5] = pattern.split("=");
113
+ if (path5) {
114
+ log.debug(`Resolved ${specifier} to path: ${path5}`);
115
+ return path5;
116
116
  }
117
117
  const repoPath = await getModulePath(specifier, repoDir, log);
118
118
  if (repoPath) {
@@ -129,15 +129,15 @@ var loadTransformOptions = async (opts, log) => {
129
129
  const [pattern] = opts.adaptors;
130
130
  const [specifier] = pattern.split("=");
131
131
  log.debug(`Attempting to preload typedefs for ${specifier}`);
132
- const path4 = await resolveSpecifierPath(pattern, opts.repoDir, log);
133
- if (path4) {
132
+ const path5 = await resolveSpecifierPath(pattern, opts.repoDir, log);
133
+ if (path5) {
134
134
  try {
135
- exports = await preloadAdaptorExports(path4);
135
+ exports = await preloadAdaptorExports(path5);
136
136
  if (exports) {
137
137
  log.info(`Loaded typedefs for ${specifier}`);
138
138
  }
139
139
  } catch (e) {
140
- log.error(`Failed to load adaptor typedefs from path ${path4}`);
140
+ log.error(`Failed to load adaptor typedefs from path ${path5}`);
141
141
  log.error(e);
142
142
  }
143
143
  }
@@ -366,20 +366,20 @@ var RETRY_COUNT = 20;
366
366
  var TIMEOUT_MS = 1e3 * 60;
367
367
  var actualDocGen = (specifier) => describePackage(specifier, {});
368
368
  var ensurePath = (filePath) => mkdirSync(path.dirname(filePath), { recursive: true });
369
- var generatePlaceholder = (path4) => {
370
- writeFileSync(path4, `{ "loading": true, "timestamp": ${Date.now()}}`);
369
+ var generatePlaceholder = (path5) => {
370
+ writeFileSync(path5, `{ "loading": true, "timestamp": ${Date.now()}}`);
371
371
  };
372
372
  var finish = (logger, resultPath) => {
373
373
  logger.success("Done! Docs can be found at:\n");
374
374
  logger.print(` ${path.resolve(resultPath)}`);
375
375
  };
376
- var generateDocs = async (specifier, path4, docgen, logger) => {
376
+ var generateDocs = async (specifier, path5, docgen, logger) => {
377
377
  const result = await docgen(specifier);
378
- await writeFile3(path4, JSON.stringify(result, null, 2));
379
- finish(logger, path4);
380
- return path4;
378
+ await writeFile3(path5, JSON.stringify(result, null, 2));
379
+ finish(logger, path5);
380
+ return path5;
381
381
  };
382
- var waitForDocs = async (docs, path4, logger, retryDuration = RETRY_DURATION) => {
382
+ var waitForDocs = async (docs, path5, logger, retryDuration = RETRY_DURATION) => {
383
383
  try {
384
384
  if (docs.hasOwnProperty("loading")) {
385
385
  logger.info("Docs are being loaded by another process. Waiting.");
@@ -391,19 +391,19 @@ var waitForDocs = async (docs, path4, logger, retryDuration = RETRY_DURATION) =>
391
391
  clearInterval(i);
392
392
  reject(new Error("Timed out waiting for docs to load"));
393
393
  }
394
- const updated = JSON.parse(readFileSync(path4, "utf8"));
394
+ const updated = JSON.parse(readFileSync(path5, "utf8"));
395
395
  if (!updated.hasOwnProperty("loading")) {
396
396
  logger.info("Docs found!");
397
397
  clearInterval(i);
398
- resolve(path4);
398
+ resolve(path5);
399
399
  }
400
400
  count++;
401
401
  }, retryDuration);
402
402
  });
403
403
  } else {
404
- logger.info(`Docs already written to cache at ${path4}`);
405
- finish(logger, path4);
406
- return path4;
404
+ logger.info(`Docs already written to cache at ${path5}`);
405
+ finish(logger, path5);
406
+ return path5;
407
407
  }
408
408
  } catch (e) {
409
409
  logger.error("Existing doc JSON corrupt. Aborting");
@@ -420,28 +420,28 @@ var docgenHandler = (options, logger, docgen = actualDocGen, retryDuration = RET
420
420
  process.exit(9);
421
421
  }
422
422
  logger.success(`Generating docs for ${specifier}`);
423
- const path4 = `${repoDir}/docs/${specifier}.json`;
424
- ensurePath(path4);
423
+ const path5 = `${repoDir}/docs/${specifier}.json`;
424
+ ensurePath(path5);
425
425
  const handleError = () => {
426
426
  logger.info("Removing placeholder");
427
- rmSync(path4);
427
+ rmSync(path5);
428
428
  };
429
429
  try {
430
- const existing = readFileSync(path4, "utf8");
430
+ const existing = readFileSync(path5, "utf8");
431
431
  const json = JSON.parse(existing);
432
432
  if (json && json.timeout && Date.now() - json.timeout >= TIMEOUT_MS) {
433
433
  logger.info(`Expired placeholder found. Removing.`);
434
- rmSync(path4);
434
+ rmSync(path5);
435
435
  throw new Error("TIMEOUT");
436
436
  }
437
- return waitForDocs(json, path4, logger, retryDuration);
437
+ return waitForDocs(json, path5, logger, retryDuration);
438
438
  } catch (e) {
439
439
  if (e.message !== "TIMEOUT") {
440
- logger.info(`Docs JSON not found at ${path4}`);
440
+ logger.info(`Docs JSON not found at ${path5}`);
441
441
  }
442
442
  logger.debug("Generating placeholder");
443
- generatePlaceholder(path4);
444
- return generateDocs(specifier, path4, docgen, logger).catch((e2) => {
443
+ generatePlaceholder(path5);
444
+ return generateDocs(specifier, path5, docgen, logger).catch((e2) => {
445
445
  logger.error("Error generating documentation");
446
446
  logger.error(e2);
447
447
  handleError();
@@ -489,15 +489,15 @@ var docsHandler = async (options, logger) => {
489
489
  logger.success(`Showing docs for ${adaptorName} v${version}`);
490
490
  }
491
491
  logger.info("Generating/loading documentation...");
492
- const path4 = await handler_default4(
492
+ const path5 = await handler_default4(
493
493
  {
494
494
  specifier: `${name}@${version}`,
495
495
  repoDir
496
496
  },
497
497
  createNullLogger()
498
498
  );
499
- if (path4) {
500
- const source = await readFile2(path4, "utf8");
499
+ if (path5) {
500
+ const source = await readFile2(path5, "utf8");
501
501
  const data = JSON.parse(source);
502
502
  let desc;
503
503
  if (operation) {
@@ -518,9 +518,110 @@ var docsHandler = async (options, logger) => {
518
518
  };
519
519
  var handler_default5 = docsHandler;
520
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
+
521
622
  // src/util/use-adaptors-repo.ts
522
623
  import { readFile as readFile3 } from "node:fs/promises";
523
- import path2 from "node:path";
624
+ import path3 from "node:path";
524
625
  import assert from "node:assert";
525
626
  import { getNameAndVersion as getNameAndVersion4 } from "@openfn/runtime";
526
627
  var validateMonoRepo = async (repoPath, log) => {
@@ -544,7 +645,7 @@ var updatePath = (adaptor, repoPath, log) => {
544
645
  );
545
646
  }
546
647
  const shortName = name.replace("@openfn/language-", "");
547
- const abspath = path2.resolve(repoPath, "packages", shortName);
648
+ const abspath = path3.resolve(repoPath, "packages", shortName);
548
649
  return `${name}=${abspath}`;
549
650
  };
550
651
  var useAdaptorsRepo = async (adaptors, repoPath, log) => {
@@ -560,8 +661,8 @@ var useAdaptorsRepo = async (adaptors, repoPath, log) => {
560
661
  var use_adaptors_repo_default = useAdaptorsRepo;
561
662
 
562
663
  // src/util/print-versions.ts
563
- import { readFileSync as readFileSync2 } from "node:fs";
564
- import path3 from "node:path";
664
+ import { readFileSync as readFileSync3 } from "node:fs";
665
+ import path4 from "node:path";
565
666
  import { getNameAndVersion as getNameAndVersion5 } from "@openfn/runtime";
566
667
  import { mainSymbols } from "figures";
567
668
  var NODE = "node.js";
@@ -571,7 +672,7 @@ var COMPILER2 = "compiler";
571
672
  var { triangleRightSmall: t } = mainSymbols;
572
673
  var loadVersionFromPath = (adaptorPath) => {
573
674
  try {
574
- const pkg = JSON.parse(readFileSync2(path3.resolve(adaptorPath, "package.json"), "utf8"));
675
+ const pkg = JSON.parse(readFileSync3(path4.resolve(adaptorPath, "package.json"), "utf8"));
575
676
  return pkg.version;
576
677
  } catch (e) {
577
678
  return "unknown";
@@ -641,6 +742,7 @@ var handlers = {
641
742
  test: handler_default3,
642
743
  docgen: handler_default4,
643
744
  docs: handler_default5,
745
+ metadata: handler_default6,
644
746
  ["repo-clean"]: clean,
645
747
  ["repo-install"]: install,
646
748
  ["repo-pwd"]: pwd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/cli",
3
- "version": "0.0.31",
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/logger": "0.0.10",
47
- "@openfn/runtime": "0.0.19"
46
+ "@openfn/logger": "0.0.11",
47
+ "@openfn/runtime": "0.0.20"
48
48
  },
49
49
  "files": [
50
50
  "dist",