@openapi-flow/n8n 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.md +129 -2
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/dist/legacy/workflow/common/plan-validation.d.ts +1 -0
- package/dist/legacy/workflow/common/plan-validation.js +11 -0
- package/dist/legacy/workflow/common/workflow-id.d.ts +1 -0
- package/dist/legacy/workflow/common/workflow-id.js +8 -0
- package/dist/legacy/workflow/inbound/build-inbound-workflow.d.ts +2 -0
- package/dist/legacy/workflow/inbound/build-inbound-workflow.js +60 -0
- package/dist/legacy/workflow/inbound/compile-inbound-workflow.d.ts +2 -0
- package/dist/legacy/workflow/inbound/compile-inbound-workflow.js +25 -0
- package/dist/legacy/workflow/inbound/inbound-response.d.ts +2 -0
- package/dist/legacy/workflow/inbound/inbound-response.js +51 -0
- package/dist/legacy/workflow/request/base-url.d.ts +1 -0
- package/dist/legacy/workflow/request/base-url.js +14 -0
- package/dist/legacy/workflow/request/build-request-workflow.d.ts +3 -0
- package/dist/legacy/workflow/request/build-request-workflow.js +47 -0
- package/dist/legacy/workflow/request/build-sequence-workflow.d.ts +3 -0
- package/dist/legacy/workflow/request/build-sequence-workflow.js +53 -0
- package/dist/legacy/workflow/request/compile-catalog-sequence.d.ts +2 -0
- package/dist/legacy/workflow/request/compile-catalog-sequence.js +122 -0
- package/dist/legacy/workflow/request/compile-sequence.d.ts +2 -0
- package/dist/legacy/workflow/request/compile-sequence.js +41 -0
- package/dist/legacy/workflow/request/compile-workflow.d.ts +4 -0
- package/dist/legacy/workflow/request/compile-workflow.js +93 -0
- package/dist/legacy/workflow/request/credential-binding.d.ts +5 -0
- package/dist/legacy/workflow/request/credential-binding.js +31 -0
- package/dist/legacy/workflow/request/effect-policy.d.ts +4 -0
- package/dist/legacy/workflow/request/effect-policy.js +16 -0
- package/dist/legacy/workflow/request/http-request-node.d.ts +2 -0
- package/dist/legacy/workflow/request/http-request-node.js +69 -0
- package/dist/legacy/workflow/request/prepare-sequence.d.ts +4 -0
- package/dist/legacy/workflow/request/prepare-sequence.js +103 -0
- package/dist/legacy/workflow/request/request-body.d.ts +4 -0
- package/dist/legacy/workflow/request/request-body.js +64 -0
- package/dist/legacy/workflow/request/request-headers.d.ts +4 -0
- package/dist/legacy/workflow/request/request-headers.js +30 -0
- package/dist/legacy/workflow/request/request-url.d.ts +4 -0
- package/dist/legacy/workflow/request/request-url.js +34 -0
- package/dist/legacy/workflow/request/response-assertion-code.d.ts +3 -0
- package/dist/legacy/workflow/request/response-assertion-code.js +28 -0
- package/dist/legacy/workflow/request/sequence-url.d.ts +4 -0
- package/dist/legacy/workflow/request/sequence-url.js +104 -0
- package/dist/legacy-api.d.ts +25 -0
- package/dist/legacy-api.js +20 -0
- package/dist/nodes/common/validation/compile-standalone-validator.d.ts +3 -0
- package/dist/nodes/common/validation/compile-standalone-validator.js +44 -0
- package/dist/nodes/gap/create-gap-node.d.ts +3 -0
- package/dist/nodes/gap/create-gap-node.js +35 -0
- package/dist/nodes/inputs/compile-template-input-validators.d.ts +3 -0
- package/dist/nodes/inputs/compile-template-input-validators.js +26 -0
- package/dist/nodes/inputs/create-template-input-nodes.d.ts +4 -0
- package/dist/nodes/inputs/create-template-input-nodes.js +61 -0
- package/dist/nodes/native/arrays/create-array-node-fragment.d.ts +4 -0
- package/dist/nodes/native/arrays/create-array-node-fragment.js +42 -0
- package/dist/nodes/native/arrays/create-array-reader-code.d.ts +3 -0
- package/dist/nodes/native/arrays/create-array-reader-code.js +12 -0
- package/dist/nodes/native/arrays/create-bound-native-array-capability.d.ts +4 -0
- package/dist/nodes/native/arrays/create-bound-native-array-capability.js +81 -0
- package/dist/nodes/native/arrays/create-native-array-capability.d.ts +4 -0
- package/dist/nodes/native/arrays/create-native-array-capability.js +12 -0
- package/dist/nodes/native/arrays/native-array-definition.d.ts +2 -0
- package/dist/nodes/native/arrays/native-array-definition.js +27 -0
- package/dist/nodes/native/common/create-material-planning-capability.d.ts +4 -0
- package/dist/nodes/native/common/create-material-planning-capability.js +14 -0
- package/dist/nodes/native/common/create-native-fragment.d.ts +2 -0
- package/dist/nodes/native/common/create-native-fragment.js +10 -0
- package/dist/nodes/native/common/define-material-bound-capability.d.ts +4 -0
- package/dist/nodes/native/common/define-material-bound-capability.js +33 -0
- package/dist/nodes/native/common/resolve-native-runtime-source.d.ts +3 -0
- package/dist/nodes/native/common/resolve-native-runtime-source.js +15 -0
- package/dist/nodes/native/common/response-reference-bindings.d.ts +4 -0
- package/dist/nodes/native/common/response-reference-bindings.js +15 -0
- package/dist/nodes/native/common/response-references.d.ts +3 -0
- package/dist/nodes/native/common/response-references.js +5 -0
- package/dist/nodes/native/create-exclusive-branch-merge-capability.d.ts +3 -0
- package/dist/nodes/native/create-exclusive-branch-merge-capability.js +43 -0
- package/dist/nodes/native/create-json-output-capability.d.ts +3 -0
- package/dist/nodes/native/create-json-output-capability.js +48 -0
- package/dist/nodes/native/create-native-capabilities.d.ts +2 -0
- package/dist/nodes/native/create-native-capabilities.js +15 -0
- package/dist/nodes/native/create-pass-through-capability.d.ts +3 -0
- package/dist/nodes/native/create-pass-through-capability.js +32 -0
- package/dist/nodes/native/create-response-array-capability.d.ts +3 -0
- package/dist/nodes/native/create-response-array-capability.js +78 -0
- package/dist/nodes/native/create-response-collection-capability.d.ts +3 -0
- package/dist/nodes/native/create-response-collection-capability.js +134 -0
- package/dist/nodes/native/if-capability.d.ts +2 -0
- package/dist/nodes/native/if-capability.js +80 -0
- package/dist/nodes/native/inputs/native-input-runtime.bundle.js +24 -0
- package/dist/nodes/native/inputs/prepend-native-parameter-guard.d.ts +4 -0
- package/dist/nodes/native/inputs/prepend-native-parameter-guard.js +52 -0
- package/dist/nodes/native/item-join/create-bound-item-join-capability.d.ts +3 -0
- package/dist/nodes/native/item-join/create-bound-item-join-capability.js +169 -0
- package/dist/nodes/native/item-join/create-item-join-capability.d.ts +4 -0
- package/dist/nodes/native/item-join/create-item-join-capability.js +10 -0
- package/dist/nodes/native/item-join/create-item-join-reader-code.d.ts +2 -0
- package/dist/nodes/native/item-join/create-item-join-reader-code.js +18 -0
- package/dist/nodes/native/item-join/item-join-definition.d.ts +2 -0
- package/dist/nodes/native/item-join/item-join-definition.js +33 -0
- package/dist/nodes/native/item-join/runtime/item-join-runtime.bundle.js +24 -0
- package/dist/nodes/native/item-join/runtime/join-api-items.d.ts +3 -0
- package/dist/nodes/native/item-join/runtime/join-api-items.js +37 -0
- package/dist/nodes/native/merge-append-capability.d.ts +2 -0
- package/dist/nodes/native/merge-append-capability.js +33 -0
- package/dist/nodes/native/registry/native-feature-definitions.d.ts +4 -0
- package/dist/nodes/native/registry/native-feature-definitions.js +93 -0
- package/dist/nodes/native/registry/native-feature-material-requirements.d.ts +3 -0
- package/dist/nodes/native/registry/native-feature-material-requirements.js +10 -0
- package/dist/nodes/native/registry/resolve-n8n-native-features.d.ts +3 -0
- package/dist/nodes/native/registry/resolve-n8n-native-features.js +6 -0
- package/dist/nodes/native/registry/resolve-n8n-native-planning-features.d.ts +3 -0
- package/dist/nodes/native/registry/resolve-n8n-native-planning-features.js +5 -0
- package/dist/nodes/native/registry/resolve-native-feature-registry.d.ts +3 -0
- package/dist/nodes/native/registry/resolve-native-feature-registry.js +99 -0
- package/dist/nodes/native/registry/validate-native-feature-context.d.ts +2 -0
- package/dist/nodes/native/registry/validate-native-feature-context.js +46 -0
- package/dist/nodes/native/response-array-definition.d.ts +2 -0
- package/dist/nodes/native/response-array-definition.js +27 -0
- package/dist/nodes/native/response-assertion-capability.d.ts +2 -0
- package/dist/nodes/native/response-assertion-capability.js +57 -0
- package/dist/nodes/native/response-check-code.d.ts +3 -0
- package/dist/nodes/native/response-check-code.js +65 -0
- package/dist/nodes/native/response-checks/create-response-check-guard.d.ts +4 -0
- package/dist/nodes/native/response-checks/create-response-check-guard.js +22 -0
- package/dist/nodes/native/response-checks/create-response-check-reader.d.ts +3 -0
- package/dist/nodes/native/response-checks/create-response-check-reader.js +23 -0
- package/dist/nodes/native/response-collection-definition.d.ts +2 -0
- package/dist/nodes/native/response-collection-definition.js +27 -0
- package/dist/nodes/native/stop-and-error-capability.d.ts +2 -0
- package/dist/nodes/native/stop-and-error-capability.js +43 -0
- package/dist/nodes/request/authentication/credential-field-name.d.ts +1 -0
- package/dist/nodes/request/authentication/credential-field-name.js +3 -0
- package/dist/nodes/request/authentication/resolve-http-request-authentication.d.ts +2 -0
- package/dist/nodes/request/authentication/resolve-http-request-authentication.js +42 -0
- package/dist/nodes/request/bindings/compile-native-output-validators.d.ts +3 -0
- package/dist/nodes/request/bindings/compile-native-output-validators.js +12 -0
- package/dist/nodes/request/bindings/compile-request-validator.d.ts +3 -0
- package/dist/nodes/request/bindings/compile-request-validator.js +13 -0
- package/dist/nodes/request/bindings/compile-source-response-validators.d.ts +2 -0
- package/dist/nodes/request/bindings/compile-source-response-validators.js +12 -0
- package/dist/nodes/request/bindings/create-bound-request-fragment.d.ts +3 -0
- package/dist/nodes/request/bindings/create-bound-request-fragment.js +82 -0
- package/dist/nodes/request/bindings/create-output-item-reader-code.d.ts +2 -0
- package/dist/nodes/request/bindings/create-output-item-reader-code.js +7 -0
- package/dist/nodes/request/bindings/create-output-reader-code.d.ts +3 -0
- package/dist/nodes/request/bindings/create-output-reader-code.js +26 -0
- package/dist/nodes/request/bindings/resolve-output-binding-sources.d.ts +3 -0
- package/dist/nodes/request/bindings/resolve-output-binding-sources.js +36 -0
- package/dist/nodes/request/create-http-request-node.d.ts +2 -0
- package/dist/nodes/request/create-http-request-node.js +73 -0
- package/dist/nodes/request/deployment/create-request-deployment-notes.d.ts +2 -0
- package/dist/nodes/request/deployment/create-request-deployment-notes.js +3 -0
- package/dist/nodes/request/deployment/resolve-http-request-deployment.d.ts +2 -0
- package/dist/nodes/request/deployment/resolve-http-request-deployment.js +33 -0
- package/dist/nodes/request/finalize-http-request-fragment.d.ts +3 -0
- package/dist/nodes/request/finalize-http-request-fragment.js +22 -0
- package/dist/nodes/request/resolve-http-request-node-configuration.d.ts +4 -0
- package/dist/nodes/request/resolve-http-request-node-configuration.js +41 -0
- package/dist/nodes/request/response/create-http-response-decoder.d.ts +4 -0
- package/dist/nodes/request/response/create-http-response-decoder.js +57 -0
- package/dist/nodes/request/response/decode-http-response.d.ts +3 -0
- package/dist/nodes/request/response/decode-http-response.js +42 -0
- package/dist/nodes/request/response/http-response-media.d.ts +2 -0
- package/dist/nodes/request/response/http-response-media.js +32 -0
- package/dist/nodes/request/response/http-response-node-name.d.ts +2 -0
- package/dist/nodes/request/response/http-response-node-name.js +4 -0
- package/dist/nodes/request/response/response-runtime.bundle.js +24 -0
- package/dist/nodes/request/runtime/materialize-http-request.d.ts +4 -0
- package/dist/nodes/request/runtime/materialize-http-request.js +35 -0
- package/dist/nodes/request/runtime/request-runtime.bundle.js +24 -0
- package/dist/nodes/request/serialization/create-serialized-http-request-node.d.ts +3 -0
- package/dist/nodes/request/serialization/create-serialized-http-request-node.js +17 -0
- package/dist/nodes/request/serialization/serialize-http-request.d.ts +5 -0
- package/dist/nodes/request/serialization/serialize-http-request.js +70 -0
- package/dist/public-api.d.ts +43 -0
- package/dist/public-api.js +26 -0
- package/dist/schemas/batch-execution-schema.d.ts +15 -0
- package/dist/schemas/batch-execution-schema.js +14 -0
- package/dist/schemas/create-native-comparison-planning-schema.d.ts +81 -0
- package/dist/schemas/create-native-comparison-planning-schema.js +36 -0
- package/dist/schemas/exclusive-branch-merge-schema.d.ts +4 -0
- package/dist/schemas/exclusive-branch-merge-schema.js +7 -0
- package/dist/schemas/item-join-schema.d.ts +13 -0
- package/dist/schemas/item-join-schema.js +26 -0
- package/dist/schemas/native-array-schema.d.ts +11 -0
- package/dist/schemas/native-array-schema.js +19 -0
- package/dist/schemas/native-capability-schemas.d.ts +100 -0
- package/dist/schemas/native-capability-schemas.js +62 -0
- package/dist/schemas/native-feature-registry-schema.d.ts +17 -0
- package/dist/schemas/native-feature-registry-schema.js +8 -0
- package/dist/schemas/native-runtime-input-schema.d.ts +5 -0
- package/dist/schemas/native-runtime-input-schema.js +5 -0
- package/dist/schemas/request-deployment-schema.d.ts +9 -0
- package/dist/schemas/request-deployment-schema.js +27 -0
- package/dist/schemas/response-array-schema.d.ts +11 -0
- package/dist/schemas/response-array-schema.js +19 -0
- package/dist/schemas/response-collection-schema.d.ts +11 -0
- package/dist/schemas/response-collection-schema.js +19 -0
- package/dist/schemas/template-deployment-selection-schema.d.ts +3 -0
- package/dist/schemas/template-deployment-selection-schema.js +10 -0
- package/dist/schemas/workflow-input-value-map-schema.d.ts +5 -0
- package/dist/schemas/workflow-input-value-map-schema.js +5 -0
- package/dist/schemas/workflow-template-schema.d.ts +11 -0
- package/dist/schemas/workflow-template-schema.js +10 -0
- package/dist/types/array-iteration.d.ts +8 -0
- package/dist/types/array-iteration.js +1 -0
- package/dist/types/array-split.d.ts +13 -0
- package/dist/types/array-split.js +1 -0
- package/dist/types/authentication.d.ts +14 -0
- package/dist/types/authentication.js +1 -0
- package/dist/types/batch-execution.d.ts +23 -0
- package/dist/types/batch-execution.js +1 -0
- package/dist/types/http-response-decoding.d.ts +16 -0
- package/dist/types/http-response-decoding.js +1 -0
- package/dist/types/item-join.d.ts +40 -0
- package/dist/types/item-join.js +1 -0
- package/dist/types/legacy/catalog-workflow.d.ts +37 -0
- package/dist/types/legacy/catalog-workflow.js +1 -0
- package/dist/types/legacy/inbound-workflow.d.ts +27 -0
- package/dist/types/legacy/inbound-workflow.js +1 -0
- package/dist/types/legacy/request-node.d.ts +23 -0
- package/dist/types/legacy/request-node.js +1 -0
- package/dist/types/legacy/request-workflow.d.ts +43 -0
- package/dist/types/legacy/request-workflow.js +1 -0
- package/dist/types/legacy/sequence-workflow.d.ts +57 -0
- package/dist/types/legacy/sequence-workflow.js +1 -0
- package/dist/types/native-array.d.ts +8 -0
- package/dist/types/native-array.js +1 -0
- package/dist/types/native-capability.d.ts +46 -0
- package/dist/types/native-capability.js +1 -0
- package/dist/types/native-feature-registry.d.ts +70 -0
- package/dist/types/native-feature-registry.js +14 -0
- package/dist/types/native-material-binding.d.ts +56 -0
- package/dist/types/native-material-binding.js +1 -0
- package/dist/types/native-runtime-parameters.d.ts +55 -0
- package/dist/types/native-runtime-parameters.js +1 -0
- package/dist/types/node-fragment.d.ts +51 -0
- package/dist/types/node-fragment.js +1 -0
- package/dist/types/output-binding-source.d.ts +27 -0
- package/dist/types/output-binding-source.js +1 -0
- package/dist/types/request-deployment.d.ts +17 -0
- package/dist/types/request-deployment.js +1 -0
- package/dist/types/request-materialization.d.ts +30 -0
- package/dist/types/request-materialization.js +1 -0
- package/dist/types/request-node-configuration.d.ts +13 -0
- package/dist/types/request-node-configuration.js +1 -0
- package/dist/types/response-check-compilation.d.ts +11 -0
- package/dist/types/response-check-compilation.js +1 -0
- package/dist/types/response-check-guard.d.ts +6 -0
- package/dist/types/response-check-guard.js +1 -0
- package/dist/types/response-collection.d.ts +7 -0
- package/dist/types/response-collection.js +1 -0
- package/dist/types/reviewable-workflow.d.ts +29 -0
- package/dist/types/reviewable-workflow.js +1 -0
- package/dist/types/schema-compilation.d.ts +5 -0
- package/dist/types/schema-compilation.js +1 -0
- package/dist/types/serialized-http-request.d.ts +4 -0
- package/dist/types/serialized-http-request.js +1 -0
- package/dist/types/workflow-compilation.d.ts +39 -0
- package/dist/types/workflow-compilation.js +1 -0
- package/dist/types/workflow-template.d.ts +121 -0
- package/dist/types/workflow-template.js +1 -0
- package/dist/utils/bundled-license-banner.d.ts +3 -0
- package/dist/utils/bundled-license-banner.js +32 -0
- package/dist/utils/javascript-json-literal.d.ts +2 -0
- package/dist/utils/javascript-json-literal.js +10 -0
- package/dist/utils/json-values-equal.cjs +24 -0
- package/dist/utils/json-values-equal.d.cts +1 -0
- package/dist/workflow/assemble-n8n-workflow.d.ts +2 -0
- package/dist/workflow/assemble-n8n-workflow.js +11 -0
- package/dist/workflow/batch/compile-batched-n8n-workflow.d.ts +3 -0
- package/dist/workflow/batch/compile-batched-n8n-workflow.js +36 -0
- package/dist/workflow/batch/create-batch-execution-scopes.d.ts +3 -0
- package/dist/workflow/batch/create-batch-execution-scopes.js +59 -0
- package/dist/workflow/batch/validate-batch-exclusive-rejoin.d.ts +3 -0
- package/dist/workflow/batch/validate-batch-exclusive-rejoin.js +49 -0
- package/dist/workflow/batch/validate-batch-item-flow.d.ts +3 -0
- package/dist/workflow/batch/validate-batch-item-flow.js +98 -0
- package/dist/workflow/build-n8n-workflow.d.ts +2 -0
- package/dist/workflow/build-n8n-workflow.js +140 -0
- package/dist/workflow/compile-native-material-fragments.d.ts +3 -0
- package/dist/workflow/compile-native-material-fragments.js +76 -0
- package/dist/workflow/compile-native-workflow-nodes.d.ts +3 -0
- package/dist/workflow/compile-native-workflow-nodes.js +25 -0
- package/dist/workflow/compile-planned-n8n-workflow.d.ts +3 -0
- package/dist/workflow/compile-planned-n8n-workflow.js +42 -0
- package/dist/workflow/compile-reviewable-n8n-workflow.d.ts +3 -0
- package/dist/workflow/compile-reviewable-n8n-workflow.js +92 -0
- package/dist/workflow/compile-validated-workflow-fragments.d.ts +3 -0
- package/dist/workflow/compile-validated-workflow-fragments.js +20 -0
- package/dist/workflow/compile-workflow-material-fragments.d.ts +4 -0
- package/dist/workflow/compile-workflow-material-fragments.js +18 -0
- package/dist/workflow/create-n8n-native-output-sources.d.ts +3 -0
- package/dist/workflow/create-n8n-native-output-sources.js +58 -0
- package/dist/workflow/entrypoint/manual-trigger.d.ts +4 -0
- package/dist/workflow/entrypoint/manual-trigger.js +16 -0
- package/dist/workflow/find-singleton-api-responses.d.ts +3 -0
- package/dist/workflow/find-singleton-api-responses.js +22 -0
- package/dist/workflow/inputs/compile-native-runtime-inputs.d.ts +5 -0
- package/dist/workflow/inputs/compile-native-runtime-inputs.js +129 -0
- package/dist/workflow/inputs/create-runtime-input-native-capabilities.d.ts +4 -0
- package/dist/workflow/inputs/create-runtime-input-native-capabilities.js +36 -0
- package/dist/workflow/resolve-n8n-native-materials.d.ts +2 -0
- package/dist/workflow/resolve-n8n-native-materials.js +16 -0
- package/dist/workflow/review/create-gap-review-content.d.ts +2 -0
- package/dist/workflow/review/create-gap-review-content.js +28 -0
- package/dist/workflow/review/create-gap-review-region.d.ts +2 -0
- package/dist/workflow/review/create-gap-review-region.js +23 -0
- package/dist/workflow/review/escape-review-markdown.d.ts +1 -0
- package/dist/workflow/review/escape-review-markdown.js +7 -0
- package/dist/workflow/review/gap-review-region-layout.d.ts +4 -0
- package/dist/workflow/review/gap-review-region-layout.js +21 -0
- package/dist/workflow/templates/compile-n8n-workflow-template.d.ts +3 -0
- package/dist/workflow/templates/compile-n8n-workflow-template.js +211 -0
- package/dist/workflow/templates/create-template-artifact-mapping.d.ts +2 -0
- package/dist/workflow/templates/create-template-artifact-mapping.js +58 -0
- package/dist/workflow/templates/create-template-gap-regions.d.ts +5 -0
- package/dist/workflow/templates/create-template-gap-regions.js +22 -0
- package/dist/workflow/templates/create-workflow-template-guide.d.ts +3 -0
- package/dist/workflow/templates/create-workflow-template-guide.js +44 -0
- package/dist/workflow/templates/prepare-template-api-fragments.d.ts +3 -0
- package/dist/workflow/templates/prepare-template-api-fragments.js +74 -0
- package/dist/workflow/templates/select-n8n-template-deployments.d.ts +3 -0
- package/dist/workflow/templates/select-n8n-template-deployments.js +12 -0
- package/dist/workflow/templates/workflow-template-identities.d.ts +5 -0
- package/dist/workflow/templates/workflow-template-identities.js +5 -0
- package/dist/workflow/validate-compiled-binding-sources.d.ts +4 -0
- package/dist/workflow/validate-compiled-binding-sources.js +40 -0
- package/dist/workflow/validate-node-fragments.d.ts +3 -0
- package/dist/workflow/validate-node-fragments.js +58 -0
- package/package.json +59 -4
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { node } from '@n8n/workflow-sdk';
|
|
3
|
+
import { javascriptJsonLiteral } from '../../../utils/javascript-json-literal.js';
|
|
4
|
+
import { createSerializedHttpRequestNode } from '../serialization/create-serialized-http-request-node.js';
|
|
5
|
+
import { resolveCredentialBinding } from '../../../legacy/workflow/request/credential-binding.js';
|
|
6
|
+
import { compileRequestValidator } from './compile-request-validator.js';
|
|
7
|
+
import { resolveOutputBindingSources } from './resolve-output-binding-sources.js';
|
|
8
|
+
import { createOutputReaderCode } from './create-output-reader-code.js';
|
|
9
|
+
export function createBoundRequestFragment(input, config) {
|
|
10
|
+
const sources = resolveOutputBindingSources(input);
|
|
11
|
+
const runtime = readFileSync(new URL('../runtime/request-runtime.bundle.js', import.meta.url), 'utf8');
|
|
12
|
+
const validator = compileRequestValidator(config);
|
|
13
|
+
const linked = input.itemMode === 'linked';
|
|
14
|
+
const materialize = `OpenApiFlowRequestRuntime.materializeHttpRequest(config,responses,OpenApiFlowRequestValidator${config.deferredInputs ? ',inputValues' : ''})`;
|
|
15
|
+
const inputReader = config.deferredInputs
|
|
16
|
+
? `const inputItems=$(${javascriptJsonLiteral(config.deferredInputs.inputNodeName)}).all(0,0);if(inputItems.length!==1||inputItems[0].json.revision!==${config.deferredInputs.revision})throw new Error('Missing or stale validated workflow inputs: expected revision ${config.deferredInputs.revision}');const inputValues=inputItems[0].json.values;`
|
|
17
|
+
: '';
|
|
18
|
+
const code = `${runtime}\n${validator}\nconst config=${javascriptJsonLiteral(config)};\n${inputReader}\n${linked ? `return $input.all().map((_,inputIndex)=>{${createOutputReaderCode(sources, true)}\nreturn {json:${materialize},pairedItem:{item:inputIndex}};});` : `${createOutputReaderCode(sources)}\nreturn [{json:${materialize}}];`}`;
|
|
19
|
+
const materializer = node({
|
|
20
|
+
type: 'n8n-nodes-base.code',
|
|
21
|
+
version: 2,
|
|
22
|
+
config: {
|
|
23
|
+
id: `${config.arguments.callId}-materialize`,
|
|
24
|
+
name: `Materialize ${config.arguments.callId}`,
|
|
25
|
+
position: input.position,
|
|
26
|
+
parameters: { mode: 'runOnceForAllItems', jsCode: code },
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
const bodyPresent = Object.hasOwn(config.arguments.values, 'body') ||
|
|
30
|
+
config.arguments.bindings.some((binding) => binding.targetPointer === '/body' ||
|
|
31
|
+
binding.targetPointer.startsWith('/body/')) ||
|
|
32
|
+
config.deferredInputs?.slots.some((slot) => slot.targetPointer === '/body' ||
|
|
33
|
+
slot.targetPointer.startsWith('/body/')) === true;
|
|
34
|
+
const mediaTypes = config.operation.body
|
|
35
|
+
? Object.keys(config.operation.body.mediaTypes)
|
|
36
|
+
: [];
|
|
37
|
+
const mediaType = config.arguments.requestMediaType ??
|
|
38
|
+
(mediaTypes.length === 1 ? mediaTypes[0] : undefined);
|
|
39
|
+
if (bodyPresent && mediaType === undefined)
|
|
40
|
+
throw new Error('requestMediaType must select the bound body media type');
|
|
41
|
+
if (bodyPresent &&
|
|
42
|
+
mediaType !== 'application/json' &&
|
|
43
|
+
mediaType !== 'application/x-www-form-urlencoded')
|
|
44
|
+
throw new Error(`${config.operation.operationRef}: requestBody media type ${mediaType} has no n8n mapping`);
|
|
45
|
+
const request = createSerializedHttpRequestNode({
|
|
46
|
+
bodySource: 'materialized',
|
|
47
|
+
operation: config.operation,
|
|
48
|
+
id: `${config.arguments.callId}-transport`,
|
|
49
|
+
name: 'Receive ' + config.arguments.callId,
|
|
50
|
+
position: [input.position[0] + 220, input.position[1]],
|
|
51
|
+
url: '={{ $json.url }}',
|
|
52
|
+
headers: [],
|
|
53
|
+
body: bodyPresent
|
|
54
|
+
? {
|
|
55
|
+
contentType: mediaType === 'application/json' ? 'json' : 'form-urlencoded',
|
|
56
|
+
value: '={{ $json.body.value }}',
|
|
57
|
+
}
|
|
58
|
+
: undefined,
|
|
59
|
+
authentication: resolveCredentialBinding(input, input.credentialBindings),
|
|
60
|
+
shouldAssert: false,
|
|
61
|
+
});
|
|
62
|
+
// Headers may include bound values; HTTP Request supports a JSON expression.
|
|
63
|
+
request.config.parameters = {
|
|
64
|
+
...request.config.parameters,
|
|
65
|
+
sendHeaders: true,
|
|
66
|
+
specifyHeaders: 'json',
|
|
67
|
+
jsonHeaders: '={{ $json.headersJson }}',
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
nodeId: config.arguments.callId,
|
|
71
|
+
preservesInputItems: linked,
|
|
72
|
+
bindingSources: sources,
|
|
73
|
+
nodes: [materializer, request],
|
|
74
|
+
entry: materializer,
|
|
75
|
+
exit: request,
|
|
76
|
+
internalEdges: [
|
|
77
|
+
{ from: materializer.id, output: 0, to: request.id, input: 0 },
|
|
78
|
+
],
|
|
79
|
+
inputPorts: { main: 0 },
|
|
80
|
+
outputPorts: { main: 0 },
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** A graph-proven singleton is read as exactly one item, never as an ancestry fallback. */
|
|
2
|
+
export function createOutputItemReaderCode(linked) {
|
|
3
|
+
const single = "const items=$(source.nodeName).all();if(items.length!==1)throw new Error('Response '+source.nodeId+' requires an unambiguous single JSON item; got '+items.length+' items');return items[0];";
|
|
4
|
+
return linked
|
|
5
|
+
? `const item=source.singleton===true?(()=>{${single}})():$(source.nodeName).itemMatching(inputIndex);`
|
|
6
|
+
: `const item=(()=>{${single}})();`;
|
|
7
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { N8nOutputBindingSource } from '../../../types/output-binding-source.js';
|
|
2
|
+
/** Read declared JSON roots without coercion or ambiguous item selection. */
|
|
3
|
+
export declare function createOutputReaderCode(sources: N8nOutputBindingSource[], linked?: boolean, singletonNodeIds?: string[]): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { javascriptJsonLiteral } from '../../../utils/javascript-json-literal.js';
|
|
2
|
+
import { compileNativeOutputValidators } from './compile-native-output-validators.js';
|
|
3
|
+
import { compileSourceResponseValidators } from './compile-source-response-validators.js';
|
|
4
|
+
import { createOutputItemReaderCode } from './create-output-item-reader-code.js';
|
|
5
|
+
/** Read declared JSON roots without coercion or ambiguous item selection. */
|
|
6
|
+
export function createOutputReaderCode(sources, linked = false, singletonNodeIds = []) {
|
|
7
|
+
const declarations = sources.map((source, index) => ({
|
|
8
|
+
nodeId: source.nodeId,
|
|
9
|
+
nodeName: source.nodeName,
|
|
10
|
+
kind: source.kind,
|
|
11
|
+
singleton: singletonNodeIds.includes(source.nodeId),
|
|
12
|
+
validator: source.kind === 'native-json' || source.operation ? index : null,
|
|
13
|
+
}));
|
|
14
|
+
const responseValidators = sources
|
|
15
|
+
.map((source, index) => source.kind === 'api-response' && source.operation
|
|
16
|
+
? `OpenApiFlowResponseValidator${index}`
|
|
17
|
+
: 'null')
|
|
18
|
+
.join(',');
|
|
19
|
+
const nativeValidators = sources
|
|
20
|
+
.map((source, index) => source.kind === 'native-json'
|
|
21
|
+
? `OpenApiFlowNativeOutputValidator${index}`
|
|
22
|
+
: 'null')
|
|
23
|
+
.join(',');
|
|
24
|
+
const reader = createOutputItemReaderCode(linked);
|
|
25
|
+
return `${compileNativeOutputValidators(sources)}\n${compileSourceResponseValidators(sources)}\nconst sources=${javascriptJsonLiteral(declarations)};\nconst validators=[${responseValidators}];\nconst nativeValidators=[${nativeValidators}];\nconst responses=Object.create(null);\nfor(const source of sources){${reader}if(!item||!item.json||typeof item.json!=='object')throw new Error('Missing JSON output '+source.nodeId);if(source.kind==='api-response'){if(source.validator!==null){const validate=validators[source.validator];if(!validate(OpenApiFlowRequestRuntime.apiResponseValidationValue(item.json)))throw new Error('Response '+source.nodeId+' does not match its OAS contract: '+JSON.stringify(validate.errors));}if(!Object.hasOwn(item.json,'body'))throw new Error('Missing response body '+source.nodeId);responses[source.nodeId]=item.json.body;}else{const validate=nativeValidators[source.validator];if(!validate(item.json))throw new Error('Native output does not match declared schema: '+JSON.stringify(validate.errors)+' (source '+source.nodeId+')');responses[source.nodeId]=item.json;}}`;
|
|
26
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CreateHttpRequestNodeInput } from '../../../types/node-fragment.js';
|
|
2
|
+
import type { N8nOutputBindingSource } from '../../../types/output-binding-source.js';
|
|
3
|
+
export declare function resolveOutputBindingSources(input: CreateHttpRequestNodeInput): N8nOutputBindingSource[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { validateNativeOutputContracts } from '@openapi-flow/core';
|
|
2
|
+
export function resolveOutputBindingSources(input) {
|
|
3
|
+
validateNativeOutputContracts(input.nativeOutputSources ?? []);
|
|
4
|
+
const native = new Map((input.nativeOutputSources ?? []).map((item) => [item.nodeId, item]));
|
|
5
|
+
for (const item of native.values()) {
|
|
6
|
+
if (typeof item.nodeName !== 'string' || !item.nodeName.trim())
|
|
7
|
+
throw new Error(`nativeOutputSources[${item.nodeId}].nodeName must be a non-empty string`);
|
|
8
|
+
if (input.apiNodeNames && Object.hasOwn(input.apiNodeNames, item.nodeId))
|
|
9
|
+
throw new Error(`binding source ${item.nodeId} is declared as both API and native`);
|
|
10
|
+
}
|
|
11
|
+
return [
|
|
12
|
+
...new Set(input.arguments.bindings.map((binding) => binding.sourceNodeId)),
|
|
13
|
+
].map((nodeId) => {
|
|
14
|
+
const source = native.get(nodeId);
|
|
15
|
+
if (source)
|
|
16
|
+
return { ...source, kind: 'native-json' };
|
|
17
|
+
if (!input.apiNodeNames)
|
|
18
|
+
throw new Error(`arguments[${input.arguments.callId}] requires apiNodeNames for API response bindings`);
|
|
19
|
+
if (!Object.hasOwn(input.apiNodeNames, nodeId) ||
|
|
20
|
+
!input.apiNodeNames[nodeId].trim())
|
|
21
|
+
throw new Error(`apiNodeNames is missing ${nodeId}`);
|
|
22
|
+
if ((input.apiResponseContracts || input.itemMode === 'linked') &&
|
|
23
|
+
(!input.apiResponseContracts ||
|
|
24
|
+
!Object.hasOwn(input.apiResponseContracts, nodeId) ||
|
|
25
|
+
!input.apiResponseContracts[nodeId]))
|
|
26
|
+
throw new Error(`apiResponseContracts is missing ${nodeId}`);
|
|
27
|
+
return {
|
|
28
|
+
kind: 'api-response',
|
|
29
|
+
nodeId,
|
|
30
|
+
nodeName: input.apiNodeNames[nodeId],
|
|
31
|
+
...(input.apiResponseContracts
|
|
32
|
+
? { operation: input.apiResponseContracts[nodeId] }
|
|
33
|
+
: {}),
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { validateApiArguments, inspectApiArgumentRequirements, } from '@openapi-flow/core';
|
|
2
|
+
import { resolveCredentialBinding } from '../../legacy/workflow/request/credential-binding.js';
|
|
3
|
+
import { createBoundRequestFragment } from './bindings/create-bound-request-fragment.js';
|
|
4
|
+
import { serializeHttpRequest } from './serialization/serialize-http-request.js';
|
|
5
|
+
import { createSerializedHttpRequestNode } from './serialization/create-serialized-http-request-node.js';
|
|
6
|
+
import { resolveHttpRequestNodeConfiguration } from './resolve-http-request-node-configuration.js';
|
|
7
|
+
import { finalizeHttpRequestFragment } from './finalize-http-request-fragment.js';
|
|
8
|
+
export function createHttpRequestNode(input) {
|
|
9
|
+
const { operation: contract, arguments: args } = input;
|
|
10
|
+
if (input.itemMode !== undefined && input.itemMode !== 'linked')
|
|
11
|
+
throw new Error('itemMode must be linked or omitted');
|
|
12
|
+
if (!args || typeof args.callId !== 'string' || !args.callId.trim())
|
|
13
|
+
throw new Error('arguments.callId must be non-empty');
|
|
14
|
+
if (!Array.isArray(args.unresolvedInputs))
|
|
15
|
+
throw new Error(`arguments[${args.callId}].unresolvedInputs must be an array`);
|
|
16
|
+
if (args.unresolvedInputs.length)
|
|
17
|
+
throw new Error(`arguments[${args.callId}] has unresolved inputs: ${args.unresolvedInputs.join(', ')}`);
|
|
18
|
+
const validation = validateApiArguments({
|
|
19
|
+
operation: contract,
|
|
20
|
+
values: args.values,
|
|
21
|
+
bindings: args.bindings,
|
|
22
|
+
requestMediaType: args.requestMediaType,
|
|
23
|
+
});
|
|
24
|
+
if (!validation.valid)
|
|
25
|
+
throw new Error(`arguments[${args.callId}] is missing ${validation.missingInputs.join(', ')}`);
|
|
26
|
+
const inspected = inspectApiArgumentRequirements({
|
|
27
|
+
operation: contract,
|
|
28
|
+
callId: args.callId,
|
|
29
|
+
values: args.values,
|
|
30
|
+
bindings: args.bindings,
|
|
31
|
+
requestMediaType: args.requestMediaType,
|
|
32
|
+
requestedInputs: args.requestedInputs,
|
|
33
|
+
});
|
|
34
|
+
if (inspected.status === 'needs-input')
|
|
35
|
+
throw new Error(`arguments[${args.callId}] is missing scenario-requested inputs: ${inspected.requirements.map((requirement) => requirement.targetPointer).join(', ')}`);
|
|
36
|
+
const prepared = resolveHttpRequestNodeConfiguration(input);
|
|
37
|
+
const resolvedInput = prepared.input;
|
|
38
|
+
const operation = prepared.config.operation;
|
|
39
|
+
let fragment;
|
|
40
|
+
if (args.bindings.length) {
|
|
41
|
+
fragment = createBoundRequestFragment(resolvedInput, prepared.config);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const { url, body, headers } = serializeHttpRequest(operation, prepared.config.templateUrl, args.values, args.requestMediaType);
|
|
45
|
+
const request = createSerializedHttpRequestNode({
|
|
46
|
+
bodySource: 'literal',
|
|
47
|
+
operation,
|
|
48
|
+
id: `${args.callId}-transport`,
|
|
49
|
+
name: 'Receive ' + args.callId,
|
|
50
|
+
position: input.position,
|
|
51
|
+
url,
|
|
52
|
+
body,
|
|
53
|
+
headers,
|
|
54
|
+
authentication: resolveCredentialBinding(resolvedInput, resolvedInput.credentialBindings),
|
|
55
|
+
shouldAssert: false,
|
|
56
|
+
});
|
|
57
|
+
fragment = {
|
|
58
|
+
nodeId: args.callId,
|
|
59
|
+
preservesInputItems: true,
|
|
60
|
+
nodes: [request],
|
|
61
|
+
entry: request,
|
|
62
|
+
exit: request,
|
|
63
|
+
inputPorts: { main: 0 },
|
|
64
|
+
outputPorts: { main: 0 },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return finalizeHttpRequestFragment({
|
|
68
|
+
fragment,
|
|
69
|
+
method: contract.method,
|
|
70
|
+
documentId: contract.key.documentId,
|
|
71
|
+
deployment: resolvedInput,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export function createRequestDeploymentNotes(documentId, deployment) {
|
|
2
|
+
return `REPLACE_ME: OAS ${documentId} requires ${deployment.pendingFields.join(', ')} before execution. Supply deployment options and regenerate, or replace the placeholders in the exported JSON and select the real n8n credential. Bound request URLs are configured in their Materialize node. No credential secret is stored in this workflow.`;
|
|
3
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { httpRequestDeploymentOptionsSchema } from '../../../schemas/request-deployment-schema.js';
|
|
2
|
+
export function resolveHttpRequestDeployment(input) {
|
|
3
|
+
const options = httpRequestDeploymentOptionsSchema.parse({
|
|
4
|
+
baseUrl: input.baseUrl,
|
|
5
|
+
credentialBindings: input.credentialBindings,
|
|
6
|
+
securityRequirementIndex: input.securityRequirementIndex,
|
|
7
|
+
});
|
|
8
|
+
const pendingFields = [];
|
|
9
|
+
let baseUrl;
|
|
10
|
+
if (options.baseUrl === undefined) {
|
|
11
|
+
baseUrl = 'https://REPLACE_ME.invalid';
|
|
12
|
+
pendingFields.push('baseUrl');
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
baseUrl = options.baseUrl;
|
|
16
|
+
}
|
|
17
|
+
const credentialBindings = options.credentialBindings === undefined ? {} : options.credentialBindings;
|
|
18
|
+
const schemeName = input.authentication?.schemeName;
|
|
19
|
+
if (schemeName !== undefined &&
|
|
20
|
+
!Object.hasOwn(credentialBindings, schemeName)) {
|
|
21
|
+
credentialBindings[schemeName] = {
|
|
22
|
+
id: `REPLACE_ME:${encodeURIComponent(input.documentId)}:${encodeURIComponent(schemeName)}`,
|
|
23
|
+
name: `REPLACE_ME (${input.documentId}: ${schemeName})`,
|
|
24
|
+
};
|
|
25
|
+
pendingFields.push(`credentialBindings.${schemeName}`);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
baseUrl,
|
|
29
|
+
credentialBindings,
|
|
30
|
+
pendingFields,
|
|
31
|
+
authentication: input.authentication,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { FinalizeHttpRequestFragmentInput } from '../../types/request-node-configuration.js';
|
|
2
|
+
import type { N8nNodeFragment } from '../../types/node-fragment.js';
|
|
3
|
+
export declare function finalizeHttpRequestFragment(input: FinalizeHttpRequestFragmentInput): N8nNodeFragment;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createHttpResponseDecoder } from './response/create-http-response-decoder.js';
|
|
2
|
+
import { createRequestDeploymentNotes } from './deployment/create-request-deployment-notes.js';
|
|
3
|
+
export function finalizeHttpRequestFragment(input) {
|
|
4
|
+
const fragment = createHttpResponseDecoder(input);
|
|
5
|
+
const { deployment } = input;
|
|
6
|
+
if (deployment.pendingFields.length ||
|
|
7
|
+
deployment.authentication?.credentialRequirements) {
|
|
8
|
+
const notes = [
|
|
9
|
+
...(deployment.pendingFields.length
|
|
10
|
+
? [createRequestDeploymentNotes(input.documentId, deployment)]
|
|
11
|
+
: []),
|
|
12
|
+
...(deployment.authentication?.credentialRequirements
|
|
13
|
+
? [deployment.authentication.credentialRequirements]
|
|
14
|
+
: []),
|
|
15
|
+
].join('\n');
|
|
16
|
+
for (const node of fragment.nodes) {
|
|
17
|
+
node.config.notes = notes;
|
|
18
|
+
node.config.notesInFlow = true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return fragment;
|
|
22
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CreateHttpRequestNodeInput } from '../../types/node-fragment.js';
|
|
2
|
+
import type { ResolveHttpRequestNodeConfigurationResult } from '../../types/request-node-configuration.js';
|
|
3
|
+
/** Shared configuration ownership, after the strict or template boundary checks. */
|
|
4
|
+
export declare function resolveHttpRequestNodeConfiguration(input: CreateHttpRequestNodeInput): ResolveHttpRequestNodeConfigurationResult;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { mapHttpOperationContract } from '@openapi-flow/core/internal';
|
|
2
|
+
import { originFrom } from '../../legacy/workflow/request/base-url.js';
|
|
3
|
+
import { absoluteOperationPath } from '../../legacy/workflow/request/request-url.js';
|
|
4
|
+
import { resolveHttpRequestAuthentication } from './authentication/resolve-http-request-authentication.js';
|
|
5
|
+
import { resolveHttpRequestDeployment } from './deployment/resolve-http-request-deployment.js';
|
|
6
|
+
/** Shared configuration ownership, after the strict or template boundary checks. */
|
|
7
|
+
export function resolveHttpRequestNodeConfiguration(input) {
|
|
8
|
+
const contract = input.operation;
|
|
9
|
+
const operation = mapHttpOperationContract(contract.path, contract.method, contract.key.operationRef, contract.pathItem, contract.operation);
|
|
10
|
+
const authentication = resolveHttpRequestAuthentication({
|
|
11
|
+
operation: contract,
|
|
12
|
+
securityRequirementIndex: input.securityRequirementIndex,
|
|
13
|
+
});
|
|
14
|
+
const deployment = resolveHttpRequestDeployment({
|
|
15
|
+
documentId: contract.key.documentId,
|
|
16
|
+
authentication,
|
|
17
|
+
baseUrl: input.baseUrl,
|
|
18
|
+
credentialBindings: input.credentialBindings,
|
|
19
|
+
securityRequirementIndex: input.securityRequirementIndex,
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
input: { ...input, ...deployment },
|
|
23
|
+
config: {
|
|
24
|
+
contract,
|
|
25
|
+
operation,
|
|
26
|
+
arguments: {
|
|
27
|
+
callId: input.arguments.callId,
|
|
28
|
+
values: structuredClone(input.arguments.values),
|
|
29
|
+
bindings: structuredClone(input.arguments.bindings),
|
|
30
|
+
...(input.arguments.requestedInputs === undefined
|
|
31
|
+
? {}
|
|
32
|
+
: { requestedInputs: [...input.arguments.requestedInputs] }),
|
|
33
|
+
unresolvedInputs: [...input.arguments.unresolvedInputs],
|
|
34
|
+
...(input.arguments.requestMediaType === undefined
|
|
35
|
+
? {}
|
|
36
|
+
: { requestMediaType: input.arguments.requestMediaType }),
|
|
37
|
+
},
|
|
38
|
+
templateUrl: new URL(absoluteOperationPath(originFrom(deployment.baseUrl), operation.path)).href,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { N8nNodeFragment } from '../../../types/node-fragment.js';
|
|
2
|
+
import type { CreateHttpResponseDecoderInput } from '../../../types/http-response-decoding.js';
|
|
3
|
+
/** Keep transport metadata and item ancestry while exposing the decoded API exit. */
|
|
4
|
+
export declare function createHttpResponseDecoder({ fragment, method, }: CreateHttpResponseDecoderInput): N8nNodeFragment;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { node } from '@n8n/workflow-sdk';
|
|
3
|
+
import { isObject } from '@openapi-flow/core/internal';
|
|
4
|
+
import { javascriptJsonLiteral } from '../../../utils/javascript-json-literal.js';
|
|
5
|
+
import { httpResponseNodeName } from './http-response-node-name.js';
|
|
6
|
+
/** Keep transport metadata and item ancestry while exposing the decoded API exit. */
|
|
7
|
+
export function createHttpResponseDecoder({ fragment, method, }) {
|
|
8
|
+
const transport = fragment.exit;
|
|
9
|
+
const position = transport.config.position;
|
|
10
|
+
if (!position || position.length !== 2)
|
|
11
|
+
throw new Error(`API ${fragment.nodeId} response decoder requires transport position`);
|
|
12
|
+
const parameters = transport.config.parameters;
|
|
13
|
+
if (!parameters ||
|
|
14
|
+
!isObject(parameters.options) ||
|
|
15
|
+
!isObject(parameters.options.response) ||
|
|
16
|
+
!isObject(parameters.options.response.response))
|
|
17
|
+
throw new Error(`API ${fragment.nodeId} transport requires options.response.response`);
|
|
18
|
+
transport.config.parameters = {
|
|
19
|
+
...parameters,
|
|
20
|
+
options: {
|
|
21
|
+
...parameters.options,
|
|
22
|
+
response: {
|
|
23
|
+
...parameters.options.response,
|
|
24
|
+
response: {
|
|
25
|
+
...parameters.options.response.response,
|
|
26
|
+
fullResponse: true,
|
|
27
|
+
responseFormat: 'file',
|
|
28
|
+
outputPropertyName: 'openApiFlowRawResponse',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const runtime = readFileSync(new URL('./response-runtime.bundle.js', import.meta.url), 'utf8');
|
|
34
|
+
const decoder = node({
|
|
35
|
+
type: 'n8n-nodes-base.code',
|
|
36
|
+
version: 2,
|
|
37
|
+
config: {
|
|
38
|
+
id: fragment.nodeId,
|
|
39
|
+
name: httpResponseNodeName(fragment.nodeId),
|
|
40
|
+
position: [position[0] + 220, position[1]],
|
|
41
|
+
notes: 'Decode the raw HTTP response once. Preserve status, headers, body types and item ancestry. Invalid JSON fails without repair.',
|
|
42
|
+
parameters: {
|
|
43
|
+
mode: 'runOnceForAllItems',
|
|
44
|
+
jsCode: `${runtime}\nconst sourceNodeId=${javascriptJsonLiteral(fragment.nodeId)};\nconst method=${javascriptJsonLiteral(method)};\nconst result=[];\nfor(const [inputIndex,item] of $input.all().entries()){\nconst bytes=await this.helpers.getBinaryDataBuffer(inputIndex,'openApiFlowRawResponse');\nconst decoded=OpenApiFlowResponseRuntime.decodeHttpResponse({response:item.json,bytes,method,sourceNodeId});\nconst binary={...item.binary};\nconst raw=binary.openApiFlowRawResponse;\ndelete binary.openApiFlowRawResponse;\nif(decoded.kind==='binary')binary.data=raw;\nresult.push({json:decoded.response,...(Object.keys(binary).length?{binary}:{}),pairedItem:{item:inputIndex}});\n}\nreturn result;`,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
...fragment,
|
|
50
|
+
nodes: [...fragment.nodes, decoder],
|
|
51
|
+
exit: decoder,
|
|
52
|
+
internalEdges: [
|
|
53
|
+
...(fragment.internalEdges ?? []),
|
|
54
|
+
{ from: transport.id, output: 0, to: decoder.id, input: 0 },
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DecodedHttpResponse, HttpResponseDecodeInput } from '../../../types/http-response-decoding.js';
|
|
2
|
+
/** Decode raw transport bytes once; never guess or repair an already parsed value. */
|
|
3
|
+
export declare function decodeHttpResponse({ response, bytes, method, sourceNodeId, }: HttpResponseDecodeInput): DecodedHttpResponse;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { apiResponseValidationValue } from '@openapi-flow/core/runtime';
|
|
2
|
+
import { isBinaryResponseMedia, isJsonResponseMedia, } from './http-response-media.js';
|
|
3
|
+
/** Decode raw transport bytes once; never guess or repair an already parsed value. */
|
|
4
|
+
export function decodeHttpResponse({ response, bytes, method, sourceNodeId, }) {
|
|
5
|
+
const observed = apiResponseValidationValue(response);
|
|
6
|
+
if (Object.hasOwn(response, 'body'))
|
|
7
|
+
throw new Error(`API ${sourceNodeId} raw File transport must not contain body`);
|
|
8
|
+
if (bytes.byteLength === 0 &&
|
|
9
|
+
(method === 'HEAD' ||
|
|
10
|
+
observed.statusCode === 204 ||
|
|
11
|
+
observed.statusCode === 304))
|
|
12
|
+
return { response: { ...response }, kind: 'empty' };
|
|
13
|
+
if (isBinaryResponseMedia(observed.mediaType))
|
|
14
|
+
return { response: { ...response }, kind: 'binary' };
|
|
15
|
+
const json = isJsonResponseMedia(observed.mediaType);
|
|
16
|
+
const contentType = Object.entries(response.headers).find(([name]) => name.toLowerCase() === 'content-type')?.[1];
|
|
17
|
+
const charset = typeof contentType === 'string'
|
|
18
|
+
? /;\s*charset\s*=\s*(?:"([^"]*)"|([^;\s]*))/i.exec(contentType)
|
|
19
|
+
: null;
|
|
20
|
+
// JSON uses UTF-8 (RFC 8259 §8.1). Text retains the native UTF-8 codec default
|
|
21
|
+
// unless the actual HTTP header explicitly declares another charset.
|
|
22
|
+
const encoding = json || charset === null ? 'utf-8' : (charset[1] ?? charset[2]);
|
|
23
|
+
let text;
|
|
24
|
+
try {
|
|
25
|
+
text = new TextDecoder(encoding, { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
26
|
+
}
|
|
27
|
+
catch (cause) {
|
|
28
|
+
throw new Error(`API ${sourceNodeId} has invalid HTTP response encoding`, {
|
|
29
|
+
cause,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (!json)
|
|
33
|
+
return { response: { ...response, body: text }, kind: 'text' };
|
|
34
|
+
try {
|
|
35
|
+
return { response: { ...response, body: JSON.parse(text) }, kind: 'json' };
|
|
36
|
+
}
|
|
37
|
+
catch (cause) {
|
|
38
|
+
throw new Error(`API ${sourceNodeId} has an invalid JSON HTTP response`, {
|
|
39
|
+
cause,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Preserve the HTTP Request v4.3 binary routing policy (n8n 2.37.10).
|
|
2
|
+
// https://github.com/n8n-io/n8n/blob/n8n%402.37.10/packages/nodes-base/nodes/HttpRequest/GenericFunctions.ts
|
|
3
|
+
const binaryMediaTypes = new Set([
|
|
4
|
+
'application/octet-stream',
|
|
5
|
+
'application/gzip',
|
|
6
|
+
'application/zip',
|
|
7
|
+
'application/vnd.rar',
|
|
8
|
+
'application/epub+zip',
|
|
9
|
+
'application/x-bzip',
|
|
10
|
+
'application/x-bzip2',
|
|
11
|
+
'application/x-cdf',
|
|
12
|
+
'application/vnd.amazon.ebook',
|
|
13
|
+
'application/msword',
|
|
14
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
15
|
+
'application/vnd.ms-fontobject',
|
|
16
|
+
'application/vnd.oasis.opendocument.presentation',
|
|
17
|
+
'application/pdf',
|
|
18
|
+
'application/x-tar',
|
|
19
|
+
'application/vnd.visio',
|
|
20
|
+
'application/vnd.ms-excel',
|
|
21
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
22
|
+
'application/x-7z-compressed',
|
|
23
|
+
]);
|
|
24
|
+
export function isJsonResponseMedia(mediaType) {
|
|
25
|
+
return (mediaType === 'application/json' ||
|
|
26
|
+
(mediaType !== undefined && /^[^/]+\/[^/]+\+json$/.test(mediaType)));
|
|
27
|
+
}
|
|
28
|
+
export function isBinaryResponseMedia(mediaType) {
|
|
29
|
+
return (mediaType !== undefined &&
|
|
30
|
+
(/^(image|audio|video)\//.test(mediaType) ||
|
|
31
|
+
binaryMediaTypes.has(mediaType)));
|
|
32
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*! MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 carefreelife98
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
var OpenApiFlowResponseRuntime;
|
|
24
|
+
(()=>{function l(e){if(!e||!Number.isInteger(e.statusCode))throw new Error("API response.statusCode is required");if(!e.headers||typeof e.headers!="object"||Array.isArray(e.headers))throw new Error("API response.headers is required");let t=Object.entries(e.headers).filter(([r])=>r.toLowerCase()==="content-type");if(t.length>1)throw new Error("API response.headers has ambiguous Content-Type");let o={statusCode:e.statusCode};if(t.length){if(typeof t[0][1]!="string")throw new Error("API response Content-Type must be a string");o.mediaType=t[0][1].split(";")[0].trim().toLowerCase()}return Object.hasOwn(e,"body")&&(o.body=e.body),o}var x=new Set(["application/octet-stream","application/gzip","application/zip","application/vnd.rar","application/epub+zip","application/x-bzip","application/x-bzip2","application/x-cdf","application/vnd.amazon.ebook","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.ms-fontobject","application/vnd.oasis.opendocument.presentation","application/pdf","application/x-tar","application/vnd.visio","application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","application/x-7z-compressed"]);function h(e){return e==="application/json"||e!==void 0&&/^[^/]+\/[^/]+\+json$/.test(e)}function m(e){return e!==void 0&&(/^(image|audio|video)\//.test(e)||x.has(e))}function g({response:e,bytes:t,method:o,sourceNodeId:r}){let s=l(e);if(Object.hasOwn(e,"body"))throw new Error(`API ${r} raw File transport must not contain body`);if(t.byteLength===0&&(o==="HEAD"||s.statusCode===204||s.statusCode===304))return{response:{...e},kind:"empty"};if(m(s.mediaType))return{response:{...e},kind:"binary"};let d=h(s.mediaType),u=Object.entries(e.headers).find(([i])=>i.toLowerCase()==="content-type")?.[1],c=typeof u=="string"?/;\s*charset\s*=\s*(?:"([^"]*)"|([^;\s]*))/i.exec(u):null,w=d||c===null?"utf-8":c[1]??c[2],a;try{a=new TextDecoder(w,{fatal:!0,ignoreBOM:!0}).decode(t)}catch(i){throw new Error(`API ${r} has invalid HTTP response encoding`,{cause:i})}if(!d)return{response:{...e,body:a},kind:"text"};try{return{response:{...e,body:JSON.parse(a)},kind:"json"}}catch(i){throw new Error(`API ${r} has an invalid JSON HTTP response`,{cause:i})}}OpenApiFlowResponseRuntime={decodeHttpResponse:g};})();
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DeferredApiInputValues } from '@openapi-flow/core';
|
|
2
|
+
import type { RequestMaterializationConfig, ResponseBodies, RuntimeHttpRequest, RuntimeRequestValidator } from '../../../types/request-materialization.js';
|
|
3
|
+
/** Shared OAS validators/serializers run on the final values before HTTP sends. */
|
|
4
|
+
export declare function materializeHttpRequest(config: RequestMaterializationConfig, responses: ResponseBodies, validate: RuntimeRequestValidator, inputValues?: DeferredApiInputValues): RuntimeHttpRequest;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { materializeApiArguments, assignRequestInputValue, listMissingRequestedApiInputs, } from '@openapi-flow/core/runtime';
|
|
2
|
+
import { serializeHttpRequest } from '../serialization/serialize-http-request.js';
|
|
3
|
+
/** Shared OAS validators/serializers run on the final values before HTTP sends. */
|
|
4
|
+
export function materializeHttpRequest(config, responses, validate, inputValues) {
|
|
5
|
+
let literals = JSON.parse(JSON.stringify(config.arguments.values));
|
|
6
|
+
for (const slot of config.deferredInputs?.slots ?? []) {
|
|
7
|
+
if (!inputValues || !Object.hasOwn(inputValues, slot.id))
|
|
8
|
+
throw new Error(`Missing runtime input ${slot.id} for ${slot.callId}${slot.targetPointer}`);
|
|
9
|
+
literals = assignRequestInputValue(literals, slot.targetPointer, inputValues[slot.id], {
|
|
10
|
+
callId: config.arguments.callId,
|
|
11
|
+
operation: config.contract,
|
|
12
|
+
requestMediaType: config.arguments.requestMediaType,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const values = materializeApiArguments(literals, config.arguments.bindings, responses, {
|
|
16
|
+
callId: config.arguments.callId,
|
|
17
|
+
operation: config.contract,
|
|
18
|
+
requestMediaType: config.arguments.requestMediaType,
|
|
19
|
+
});
|
|
20
|
+
if (!validate(values))
|
|
21
|
+
throw new Error(`Runtime request ${config.arguments.callId} does not match the OAS schema: ${JSON.stringify(validate.errors)}`);
|
|
22
|
+
const missing = listMissingRequestedApiInputs({
|
|
23
|
+
source: `Runtime request ${config.arguments.callId}`,
|
|
24
|
+
rootPointer: '',
|
|
25
|
+
value: values,
|
|
26
|
+
requestedInputs: config.arguments.requestedInputs,
|
|
27
|
+
});
|
|
28
|
+
if (missing.length)
|
|
29
|
+
throw new Error(`Runtime request ${config.arguments.callId} omits scenario-requested inputs: ${missing.join(', ')}`);
|
|
30
|
+
const request = serializeHttpRequest(config.operation, config.templateUrl, values, config.arguments.requestMediaType);
|
|
31
|
+
return {
|
|
32
|
+
...request,
|
|
33
|
+
headersJson: JSON.stringify(Object.fromEntries(request.headers.map((header) => [header.name, header.value]))),
|
|
34
|
+
};
|
|
35
|
+
}
|