arazzo-runner 0.0.11 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -66,6 +66,24 @@ jq --arg password "$secret_password" '.workflowId1.password = $password' input.j
66
66
 
67
67
  Obviously, if you have a lot of secret variables that need adding as inputs, then you might need to write a script that can alter the `input.json` file for you within your CI/CD runner.
68
68
 
69
+ ### Config file
70
+
71
+ Arazzo Runner allows for a config file to keep hold of secrets to get OpenAPI/Arazzo documents held on paths behind apikeys:
72
+
73
+ ```js
74
+ "use strict";
75
+
76
+ module.exports = {
77
+ documentKey: {
78
+ key: process.env.APIKey,
79
+ in: "header|query", // either in the header or the query params
80
+ name: "apiKey",
81
+ },
82
+ };
83
+ ```
84
+
85
+ When downloading OpenAPI/Arazzo documents, it will use the documentKey to access those files. This file should be stored in `./options/config.js`
86
+
69
87
  ## OpenAPI Servers
70
88
 
71
89
  OpenAPI Documents allow you to specify servers at the root, [path](https://spec.openapis.org/oas/latest.html#path-item-object) and [operation](https://spec.openapis.org/oas/latest.html#operation-object) level. They allow you to specify multiple servers, however the OpenAPI specification is opinionated that all servers specified in a Document should return the same thing and this Arazzo Runner will follow this opinion and only attempt one of the specified servers.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arazzo-runner",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "A runner to run through Arazzo Document workflows",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -40,6 +40,7 @@
40
40
  "@swaggerexpert/arazzo-runtime-expression": "^1.0.1",
41
41
  "@swaggerexpert/json-pointer": "^2.10.2",
42
42
  "ajv": "^8.17.1",
43
+ "fast-xml-parser": "^5.3.3",
43
44
  "jsonpath": "^1.1.1",
44
45
  "openapi-params": "^0.0.5",
45
46
  "openapi-server-url-templating": "^1.3.0",
package/src/Arazzo.js CHANGED
@@ -348,9 +348,9 @@ class Arazzo extends Document {
348
348
  } else {
349
349
  this.logger.verbose("Using fetch call");
350
350
 
351
- this.logger.verbose(`url: ${url}`);
352
- this.logger.verbose(`method: ${options.method}`);
353
- this.logger.verbose("headers:");
351
+ this.logger.verbose(`request url: ${url}`);
352
+ this.logger.verbose(`request method: ${options.method}`);
353
+ this.logger.verbose("request headers:");
354
354
  for (const [key, value] of options.headers.entries()) {
355
355
  this.logger.verbose(`${key}: ${value}`);
356
356
  }
@@ -360,6 +360,12 @@ class Arazzo extends Document {
360
360
  response = await fetch(url, options);
361
361
  }
362
362
 
363
+ this.logger.verbose(`received StatusCode: ${response.status}`);
364
+ this.logger.verbose(`received headers:`);
365
+ for (const [key, value] of response.headers.entries()) {
366
+ this.logger.verbose(`${key}: ${value}`);
367
+ }
368
+
363
369
  if (response.headers.has("retry-after")) {
364
370
  const retryAfter = parseRetryAfter(response.headers.get("retry-after"));
365
371
  if (retryAfter !== null) {
@@ -504,32 +510,48 @@ class Arazzo extends Document {
504
510
  * @param {*} response
505
511
  */
506
512
  async dealWithResponse(response) {
513
+ if (
514
+ response.headers.has("Content-Type") &&
515
+ response.headers.get("Content-Type") === "application/json"
516
+ ) {
517
+ const json = await response?.json().catch((err) => {
518
+ this.logger.error(
519
+ `Error trying to resolve ${this.step.stepId} outputs`,
520
+ );
521
+ throw new Error(err);
522
+ });
523
+
524
+ this.expression.addToContext("response.body", json);
525
+ } else {
526
+ const body = await response.body;
527
+
528
+ this.expression.addToContext("response.body", body);
529
+ }
530
+
507
531
  this.doNotProcessStep = false;
508
532
  this.alreadyProcessingOnFailure = false;
509
533
 
510
534
  if (this.step.successCriteria) {
511
- if (this.step.successCriteria) {
512
- const passedSuccessCriteria = this.hasPassedSuccessCriteria();
513
-
514
- if (passedSuccessCriteria) {
515
- this.logger.success("All criteria checks passed");
516
- if (this.currentRetryRule) {
517
- if (this.retryContext.doNotDeleteRetryLimits) {
518
- this.retryLimits[this.currentRetryRule] = 0;
519
- this.logger.notice("Retries stopped");
520
- }
535
+ const passedSuccessCriteria = this.hasPassedSuccessCriteria();
536
+
537
+ if (passedSuccessCriteria) {
538
+ this.logger.success("All criteria checks passed");
539
+ if (this.currentRetryRule) {
540
+ if (this.retryContext.doNotDeleteRetryLimits) {
541
+ this.retryLimits[this.currentRetryRule] = 0;
542
+ this.logger.notice("Retries stopped");
521
543
  }
544
+ }
522
545
 
523
- await this.dealWithPassedRule(response);
546
+ await this.dealWithPassedRule(response);
547
+ } else {
548
+ this.logger.error("Not all criteria checks passed");
549
+ if (this.step.onFailure) {
550
+ await this.dealWithFailedRule();
524
551
  } else {
525
- this.logger.error("Not all criteria checks passed");
526
- if (this.step.onFailure) {
527
- await this.dealWithFailedRule();
528
- } else {
529
- throw new Error(
530
- `${this.step.stepId} step of the ${this.workflow.workflowId} workflow failed the successCriteria`,
531
- );
532
- }
552
+ throw new Error(
553
+ `${this.step.stepId} step of the ${this.workflow.workflowId} workflow failed the successCriteria`,
554
+ );
533
555
  }
534
556
  }
535
557
  } else {
@@ -843,14 +865,7 @@ class Arazzo extends Document {
843
865
  * @private
844
866
  * @param {*} response
845
867
  */
846
- async dealWithStepOutputs(response) {
847
- const json = await response?.json().catch((err) => {
848
- this.logger.error(`Error trying to resolve ${this.step.stepId} outputs`);
849
- throw new Error(err);
850
- });
851
-
852
- this.expression.addToContext("response.body", json);
853
-
868
+ async dealWithStepOutputs() {
854
869
  const outputs = {};
855
870
  for (const key in this.step.outputs) {
856
871
  const value = this.expression.resolveExpression(this.step.outputs[key]);
@@ -1067,7 +1082,7 @@ class Arazzo extends Document {
1067
1082
  this.sourceDescription.type,
1068
1083
  this.sourceDescription.url,
1069
1084
  this.sourceDescription.name,
1070
- { logger: this.logger },
1085
+ { logger: this.logger, config: this.config },
1071
1086
  );
1072
1087
 
1073
1088
  Object.assign(this.loadedSourceDescriptions, {
package/src/Document.js CHANGED
@@ -15,14 +15,40 @@ const fsp = require("node:fs/promises");
15
15
  const path = require("node:path");
16
16
 
17
17
  class Document {
18
- constructor(url, name, { logger, reporter }) {
18
+ constructor(url, name, { logger, config }) {
19
19
  this.url = url;
20
20
  this.name = name;
21
21
  this.logger = logger;
22
+ this.config = config;
22
23
  }
23
24
 
24
25
  async loadDocument() {
25
- const response = await fetch(this.url);
26
+ let headers = new Headers();
27
+ let fetchURL = new URL(this.url);
28
+
29
+ if (this.config) {
30
+ if (this.config?.documentKey) {
31
+ if (this.config.documentKey.in === "header") {
32
+ headers.append(
33
+ this.config.documentKey.name,
34
+ this.config.documentKey.key,
35
+ );
36
+ } else {
37
+ fetchURL.searchParams.append(
38
+ this.config.documentKey.name,
39
+ this.config.documentKey.key,
40
+ );
41
+ }
42
+ }
43
+ }
44
+
45
+ this.logger.verbose(`fetching ${this.type} document from: ${fetchURL}`);
46
+ this.logger.verbose("fetch headers:");
47
+ for (const [key, value] of headers.entries()) {
48
+ this.logger.verbose(`${key}: ${value}`);
49
+ }
50
+
51
+ const response = await fetch(fetchURL, { headers: headers });
26
52
 
27
53
  if (!response.ok) {
28
54
  throw new Error(`Error fetching document from ${this.url}`);
package/src/Expression.js CHANGED
@@ -242,6 +242,18 @@ class Expression {
242
242
  // return expression;
243
243
  // }
244
244
 
245
+ /**
246
+ * @private
247
+ * @param {*} value
248
+ * @returns {boolean}
249
+ */
250
+ isXML(value) {
251
+ return (
252
+ typeof value === "string" &&
253
+ (value.trim().startsWith("<?xml") || value.trim().startsWith("<"))
254
+ );
255
+ }
256
+
245
257
  /**
246
258
  * Resolves a runtime expression to its value in the context
247
259
  * @public
@@ -470,6 +482,18 @@ class Expression {
470
482
  throw new Error(`Context path '${normalised}' not found`);
471
483
  }
472
484
 
485
+ // NEW: Check if contextData is XML
486
+ if (this.isXML(contextData)) {
487
+ const { XMLParser } = require("fast-xml-parser");
488
+ const parser = new XMLParser({
489
+ ignoreAttributes: false,
490
+ attributeNamePrefix: "@_",
491
+ });
492
+ const jsonData = parser.parse(contextData);
493
+ return evaluate(jsonData, pointer);
494
+ }
495
+
496
+ // Regular JSON pointer evaluation
473
497
  try {
474
498
  return evaluate(contextData, pointer);
475
499
  } catch (err) {
package/src/OpenAPI.js CHANGED
@@ -65,7 +65,6 @@ class OpenAPI extends Document {
65
65
 
66
66
  for await (const { value } of componentPipeline) {
67
67
  if (value.securitySchemes) {
68
- console.log(value.securitySchemes);
69
68
  this.securitySchemes = value.securitySchemes;
70
69
  }
71
70
  }
package/src/Runner.js CHANGED
@@ -5,10 +5,23 @@ const Input = require("./Input");
5
5
 
6
6
  const Logger = require("./Logger");
7
7
 
8
+ const path = require("node:path");
9
+
8
10
  class Runner {
9
11
  constructor(options, logger) {
10
12
  const verboseLogging = options?.verbose || false;
11
13
  this.logger = logger || new Logger(verboseLogging);
14
+
15
+ try {
16
+ this.logger.verbose(
17
+ `Loading config from ${path.resolve("./options", "config")}`,
18
+ );
19
+
20
+ this.config = require(path.resolve("./options", "config.js"));
21
+ } catch (err) {
22
+ this.logger.verbose("No config found");
23
+ this.config = {};
24
+ }
12
25
  }
13
26
 
14
27
  /**
@@ -23,7 +36,7 @@ class Runner {
23
36
  "arazzo",
24
37
  arazzoUrl,
25
38
  "arazzo",
26
- { logger: this.logger },
39
+ { logger: this.logger, config: this.config },
27
40
  );
28
41
 
29
42
  if (!this.isUrl(arazzoUrl)) {