@wirebench/engine 2.2.1 → 3.1.0-rc.1
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 +134 -1
- package/dist/account/schema.d.ts +34 -0
- package/dist/account/schema.js +29 -0
- package/dist/assert/callback.d.ts +76 -0
- package/dist/assert/callback.js +320 -0
- package/dist/assert/capture-source.d.ts +50 -0
- package/dist/assert/capture-source.js +89 -0
- package/dist/assert/check.d.ts +8 -0
- package/dist/assert/check.js +18 -0
- package/dist/assert/header.d.ts +5 -0
- package/dist/assert/header.js +48 -0
- package/dist/assert/index.d.ts +2 -2
- package/dist/assert/index.js +12 -0
- package/dist/assert/match.d.ts +6 -0
- package/dist/assert/match.js +13 -4
- package/dist/assert/model.d.ts +110 -3
- package/dist/assert/model.js +16 -1
- package/dist/assert/schema.d.ts +194 -1
- package/dist/assert/schema.js +154 -12
- package/dist/assert/status-names.d.ts +9 -0
- package/dist/assert/status-names.js +27 -0
- package/dist/assert/status.d.ts +4 -1
- package/dist/assert/status.js +27 -3
- package/dist/asyncapi/browser.d.ts +7 -0
- package/dist/asyncapi/browser.js +6 -0
- package/dist/asyncapi/frame-check-worker-host.d.ts +44 -0
- package/dist/asyncapi/frame-check-worker-host.js +175 -0
- package/dist/asyncapi/frame-check-worker.d.ts +12 -0
- package/dist/asyncapi/frame-check-worker.js +25 -0
- package/dist/asyncapi/frame-check.d.ts +25 -0
- package/dist/asyncapi/frame-check.js +78 -0
- package/dist/asyncapi/import.d.ts +25 -0
- package/dist/asyncapi/import.js +34 -0
- package/dist/asyncapi/map.d.ts +40 -0
- package/dist/asyncapi/map.js +230 -0
- package/dist/asyncapi/model.d.ts +84 -0
- package/dist/asyncapi/model.js +7 -0
- package/dist/asyncapi/normalise-2.d.ts +13 -0
- package/dist/asyncapi/normalise-2.js +113 -0
- package/dist/asyncapi/normalise-3.d.ts +14 -0
- package/dist/asyncapi/normalise-3.js +133 -0
- package/dist/asyncapi/parse.d.ts +31 -0
- package/dist/asyncapi/parse.js +85 -0
- package/dist/asyncapi/read.d.ts +35 -0
- package/dist/asyncapi/read.js +186 -0
- package/dist/asyncapi/security.d.ts +14 -0
- package/dist/asyncapi/security.js +55 -0
- package/dist/asyncapi/update.d.ts +53 -0
- package/dist/asyncapi/update.js +220 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +22 -0
- package/dist/grpc/events.d.ts +22 -0
- package/dist/grpc/events.js +1 -0
- package/dist/grpc/expand.d.ts +1 -1
- package/dist/grpc/expand.js +15 -5
- package/dist/grpc/files.d.ts +271 -0
- package/dist/grpc/files.js +62 -0
- package/dist/grpc/model.d.ts +11 -1
- package/dist/grpc/module.d.ts +2 -0
- package/dist/grpc/module.js +13 -0
- package/dist/grpc/run.d.ts +73 -0
- package/dist/grpc/run.js +407 -0
- package/dist/grpc/script-types.d.ts +8 -0
- package/dist/grpc/script-types.js +149 -0
- package/dist/grpc/scripting.d.ts +34 -0
- package/dist/grpc/scripting.js +147 -0
- package/dist/grpc/send-input.d.ts +46 -0
- package/dist/grpc/send-input.js +42 -0
- package/dist/grpc/send.d.ts +2 -2
- package/dist/grpc/status.d.ts +9 -2
- package/dist/grpc/status.js +11 -24
- package/dist/grpc/storage.d.ts +9 -0
- package/dist/grpc/storage.js +167 -0
- package/dist/{rest/auth.d.ts → http/auth/apply-auth.d.ts} +4 -4
- package/dist/{rest/auth.js → http/auth/apply-auth.js} +1 -1
- package/dist/http/auth/apply.d.ts +1 -1
- package/dist/{rest → http/auth}/oauth2.d.ts +2 -2
- package/dist/{rest → http/auth}/oauth2.js +1 -1
- package/dist/http/auth/send-auth.d.ts +57 -0
- package/dist/http/auth/send-auth.js +7 -0
- package/dist/http/client.js +150 -8
- package/dist/http/cookies.d.ts +79 -0
- package/dist/http/cookies.js +81 -0
- package/dist/http/curl.d.ts +4 -14
- package/dist/http/curl.js +4 -154
- package/dist/http/decompress.d.ts +7 -0
- package/dist/http/decompress.js +23 -1
- package/dist/http/document-fetch.d.ts +42 -0
- package/dist/http/document-fetch.js +207 -0
- package/dist/http/entries.d.ts +27 -0
- package/dist/http/entries.js +16 -0
- package/dist/http/escape.d.ts +18 -0
- package/dist/http/escape.js +30 -0
- package/dist/http/fetch-document.d.ts +28 -0
- package/dist/{wsdl/fetch.js → http/fetch-document.js} +8 -16
- package/dist/http/media-type.d.ts +9 -0
- package/dist/http/media-type.js +12 -0
- package/dist/http/transcript-cap.d.ts +26 -0
- package/dist/http/transcript-cap.js +36 -0
- package/dist/http/types.d.ts +59 -0
- package/dist/http/webhook-signature.d.ts +81 -0
- package/dist/http/webhook-signature.js +227 -0
- package/dist/import-detect.d.ts +2 -2
- package/dist/import-detect.js +10 -1
- package/dist/index.d.ts +207 -55
- package/dist/index.js +129 -32
- package/dist/json/cursor.d.ts +2 -0
- package/dist/json/cursor.js +1 -0
- package/dist/json/pointer-range.d.ts +18 -0
- package/dist/json/pointer-range.js +157 -0
- package/dist/json/schema/model.d.ts +59 -0
- package/dist/json/schema/model.js +8 -0
- package/dist/json/schema/parse-text.d.ts +16 -0
- package/dist/json/schema/parse-text.js +37 -0
- package/dist/{rest/openapi → json/schema}/refs.d.ts +2 -2
- package/dist/{rest/openapi → json/schema}/refs.js +3 -3
- package/dist/{rest/openapi → json/schema}/sample.d.ts +4 -0
- package/dist/{rest/openapi → json/schema}/sample.js +2 -2
- package/dist/json/schema/source.d.ts +21 -0
- package/dist/json/schema/source.js +8 -0
- package/dist/json/schema-validate.d.ts +49 -0
- package/dist/json/schema-validate.js +557 -0
- package/dist/{wss/keystore → keystore}/index.js +1 -1
- package/dist/{wss/keystore → keystore}/pem.js +1 -1
- package/dist/{wss/keystore → keystore}/pkcs12.js +1 -1
- package/dist/project/attachments-cache.d.ts +3 -1
- package/dist/{wsdl → project}/cache-naming.js +1 -1
- package/dist/project/endpoints.d.ts +18 -8
- package/dist/project/endpoints.js +21 -6
- package/dist/project/environments.d.ts +7 -5
- package/dist/project/history.d.ts +105 -9
- package/dist/project/history.js +195 -23
- package/dist/project/inherit.d.ts +7 -0
- package/dist/project/inherit.js +9 -0
- package/dist/project/keystores.d.ts +1 -1
- package/dist/project/load-helpers.d.ts +89 -0
- package/dist/project/load-helpers.js +177 -0
- package/dist/project/load.d.ts +30 -4
- package/dist/project/load.js +168 -545
- package/dist/project/managed-files.d.ts +36 -0
- package/dist/project/managed-files.js +97 -0
- package/dist/project/migrate.d.ts +2 -2
- package/dist/project/migrate.js +2 -2
- package/dist/project/model.d.ts +92 -14
- package/dist/project/model.js +50 -4
- package/dist/project/paths.d.ts +10 -1
- package/dist/project/paths.js +10 -1
- package/dist/project/preferences.d.ts +11 -2
- package/dist/project/preferences.js +5 -1
- package/dist/project/properties.d.ts +31 -17
- package/dist/project/properties.js +89 -70
- package/dist/project/request-location.d.ts +20 -0
- package/dist/project/request-location.js +62 -0
- package/dist/project/save.d.ts +12 -2
- package/dist/project/save.js +186 -141
- package/dist/project/schema-parts.d.ts +337 -0
- package/dist/project/schema-parts.js +248 -0
- package/dist/project/schema.d.ts +72 -928
- package/dist/project/schema.js +17 -466
- package/dist/project/sequence-guards.d.ts +43 -0
- package/dist/project/sequence-guards.js +109 -0
- package/dist/project/serialize-helpers.d.ts +60 -0
- package/dist/project/serialize-helpers.js +108 -0
- package/dist/project/serialize.d.ts +7 -8
- package/dist/project/serialize.js +34 -293
- package/dist/protocol/features.d.ts +51 -0
- package/dist/protocol/features.js +64 -0
- package/dist/protocol/index.d.ts +7 -0
- package/dist/protocol/index.js +4 -0
- package/dist/protocol/module.d.ts +247 -0
- package/dist/protocol/module.js +48 -0
- package/dist/protocol/registry.d.ts +42 -0
- package/dist/protocol/registry.js +47 -0
- package/dist/protocols.d.ts +77 -0
- package/dist/protocols.js +40 -0
- package/dist/redact/index.d.ts +12 -1
- package/dist/redact/index.js +55 -7
- package/dist/redact/literal.d.ts +10 -0
- package/dist/redact/literal.js +110 -12
- package/dist/rest/body.d.ts +2 -10
- package/dist/rest/body.js +3 -25
- package/dist/rest/browser.d.ts +4 -0
- package/dist/rest/browser.js +5 -0
- package/dist/rest/contract-check-worker-host.d.ts +36 -0
- package/dist/rest/contract-check-worker-host.js +158 -0
- package/dist/rest/contract-check-worker.d.ts +7 -0
- package/dist/rest/contract-check-worker.js +28 -0
- package/dist/rest/contract-check.d.ts +43 -0
- package/dist/rest/contract-check.js +217 -0
- package/dist/rest/cookie-jar.d.ts +62 -0
- package/dist/rest/cookie-jar.js +262 -0
- package/dist/rest/cookies.d.ts +6 -22
- package/dist/rest/cookies.js +6 -42
- package/dist/rest/curl.js +5 -1
- package/dist/rest/events.d.ts +12 -0
- package/dist/rest/events.js +1 -0
- package/dist/rest/expand.d.ts +6 -1
- package/dist/rest/expand.js +29 -11
- package/dist/rest/files.d.ts +439 -0
- package/dist/rest/files.js +107 -0
- package/dist/rest/json-form.d.ts +97 -0
- package/dist/rest/json-form.js +396 -0
- package/dist/rest/model.d.ts +35 -24
- package/dist/rest/model.js +6 -9
- package/dist/rest/module.d.ts +2 -0
- package/dist/rest/module.js +13 -0
- package/dist/rest/openapi/cache.d.ts +7 -2
- package/dist/rest/openapi/cache.js +2 -2
- package/dist/rest/openapi/import.d.ts +11 -16
- package/dist/rest/openapi/import.js +6 -2
- package/dist/rest/openapi/map.d.ts +38 -1
- package/dist/rest/openapi/map.js +151 -41
- package/dist/rest/openapi/match.d.ts +20 -0
- package/dist/rest/openapi/match.js +117 -0
- package/dist/rest/openapi/model.d.ts +33 -45
- package/dist/rest/openapi/parse.d.ts +3 -12
- package/dist/rest/openapi/parse.js +138 -67
- package/dist/rest/openapi/responses.d.ts +23 -0
- package/dist/rest/openapi/responses.js +59 -0
- package/dist/rest/openapi/runtime-expression.d.ts +69 -0
- package/dist/rest/openapi/runtime-expression.js +213 -0
- package/dist/rest/openapi/update.d.ts +116 -0
- package/dist/rest/openapi/update.js +456 -0
- package/dist/rest/postman/map.d.ts +1 -0
- package/dist/rest/postman/map.js +66 -4
- package/dist/rest/postman/model.d.ts +9 -0
- package/dist/rest/postman/parse.js +33 -10
- package/dist/rest/response.d.ts +2 -23
- package/dist/rest/response.js +3 -75
- package/dist/rest/run.d.ts +56 -0
- package/dist/rest/run.js +395 -0
- package/dist/rest/script-types.d.ts +7 -0
- package/dist/rest/script-types.js +83 -0
- package/dist/rest/scripting.d.ts +38 -0
- package/dist/rest/scripting.js +282 -0
- package/dist/rest/send-input.d.ts +54 -0
- package/dist/rest/send-input.js +73 -0
- package/dist/rest/send.d.ts +77 -4
- package/dist/rest/send.js +128 -7
- package/dist/rest/sse-transcript.d.ts +25 -0
- package/dist/rest/sse-transcript.js +95 -0
- package/dist/rest/sse.d.ts +43 -0
- package/dist/rest/sse.js +195 -0
- package/dist/rest/storage.d.ts +26 -0
- package/dist/rest/storage.js +262 -0
- package/dist/rest/url.d.ts +10 -4
- package/dist/rest/url.js +38 -5
- package/dist/run/baseline-update.d.ts +35 -0
- package/dist/run/baseline-update.js +97 -0
- package/dist/run/baseline.d.ts +42 -0
- package/dist/run/baseline.js +93 -0
- package/dist/run/context.d.ts +86 -0
- package/dist/run/context.js +31 -0
- package/dist/run/current-values.d.ts +32 -0
- package/dist/run/current-values.js +43 -0
- package/dist/run/event-queue.d.ts +14 -0
- package/dist/run/event-queue.js +46 -0
- package/dist/run/exchange.d.ts +62 -0
- package/dist/run/exchange.js +65 -0
- package/dist/run/host.d.ts +89 -0
- package/dist/run/host.js +1 -0
- package/dist/run/index.d.ts +20 -7
- package/dist/run/index.js +12 -4
- package/dist/run/oauth2-token.d.ts +42 -0
- package/dist/run/oauth2-token.js +92 -0
- package/dist/run/open.d.ts +12 -0
- package/dist/run/open.js +16 -0
- package/dist/run/run.d.ts +124 -4
- package/dist/run/run.js +293 -134
- package/dist/run/scope.d.ts +11 -0
- package/dist/run/scope.js +26 -0
- package/dist/run/script-support.d.ts +53 -0
- package/dist/run/script-support.js +68 -0
- package/dist/run/secret-needs.d.ts +11 -4
- package/dist/run/secret-needs.js +48 -96
- package/dist/run/select.d.ts +34 -25
- package/dist/run/select.js +45 -54
- package/dist/run/send-helpers.d.ts +93 -0
- package/dist/run/send-helpers.js +255 -0
- package/dist/run/tree.d.ts +50 -0
- package/dist/run/tree.js +54 -0
- package/dist/script/api/postman.d.ts +10 -0
- package/dist/script/api/postman.js +264 -0
- package/dist/script/api/prelude.d.ts +20 -0
- package/dist/script/api/prelude.js +215 -0
- package/dist/script/apply.d.ts +44 -0
- package/dist/script/apply.js +120 -0
- package/dist/script/check/host.d.ts +41 -0
- package/dist/script/check/host.js +143 -0
- package/dist/script/check/service.d.ts +52 -0
- package/dist/script/check/service.js +195 -0
- package/dist/script/check/worker.d.ts +1 -0
- package/dist/script/check/worker.js +40 -0
- package/dist/script/index.d.ts +16 -0
- package/dist/script/index.js +10 -0
- package/dist/script/lookup.d.ts +10 -0
- package/dist/script/lookup.js +23 -0
- package/dist/script/model.d.ts +82 -0
- package/dist/script/model.js +18 -0
- package/dist/script/props.d.ts +8 -0
- package/dist/script/props.js +28 -0
- package/dist/script/request-scripts.d.ts +83 -0
- package/dist/script/request-scripts.js +160 -0
- package/dist/script/run.d.ts +47 -0
- package/dist/script/run.js +146 -0
- package/dist/script/sandbox/execute.d.ts +26 -0
- package/dist/script/sandbox/execute.js +212 -0
- package/dist/script/sandbox/host-api.d.ts +27 -0
- package/dist/script/sandbox/host-api.js +101 -0
- package/dist/script/sandbox/host.d.ts +18 -0
- package/dist/script/sandbox/host.js +172 -0
- package/dist/script/sandbox/model.d.ts +69 -0
- package/dist/script/sandbox/model.js +24 -0
- package/dist/script/sandbox/worker.d.ts +1 -0
- package/dist/script/sandbox/worker.js +20 -0
- package/dist/script/send.d.ts +27 -0
- package/dist/script/send.js +76 -0
- package/dist/script/strip.d.ts +5 -0
- package/dist/script/strip.js +43 -0
- package/dist/script/types/api.d.ts +38 -0
- package/dist/script/types/api.js +113 -0
- package/dist/script/types/json-schema.d.ts +26 -0
- package/dist/script/types/json-schema.js +206 -0
- package/dist/secrets/env-names.d.ts +9 -1
- package/dist/secrets/env-names.js +17 -1
- package/dist/secrets/resolve.d.ts +44 -4
- package/dist/secrets/resolve.js +58 -1
- package/dist/secrets/scan/apply.d.ts +36 -0
- package/dist/secrets/scan/apply.js +194 -0
- package/dist/secrets/scan/rules.d.ts +32 -0
- package/dist/secrets/scan/rules.js +346 -0
- package/dist/secrets/scan/scan.d.ts +6 -0
- package/dist/secrets/scan/scan.js +57 -0
- package/dist/secrets/scan/walk.d.ts +70 -0
- package/dist/secrets/scan/walk.js +156 -0
- package/dist/secrets/secret-refs.d.ts +8 -0
- package/dist/secrets/secret-refs.js +25 -0
- package/dist/secrets/secret-token.d.ts +17 -0
- package/dist/secrets/secret-token.js +25 -0
- package/dist/sequence/file.d.ts +169 -0
- package/dist/sequence/file.js +237 -0
- package/dist/sequence/index.d.ts +7 -0
- package/dist/sequence/index.js +5 -0
- package/dist/sequence/load.d.ts +32 -0
- package/dist/sequence/load.js +56 -0
- package/dist/sequence/model.d.ts +115 -0
- package/dist/sequence/model.js +53 -0
- package/dist/sequence/run.d.ts +131 -0
- package/dist/sequence/run.js +191 -0
- package/dist/sequence/transfer.d.ts +24 -0
- package/dist/sequence/transfer.js +75 -0
- package/dist/server-api/audit.d.ts +455 -0
- package/dist/server-api/audit.js +186 -0
- package/dist/server-api/ci-tokens.d.ts +50 -0
- package/dist/server-api/ci-tokens.js +35 -0
- package/dist/server-api/hooks.d.ts +337 -0
- package/dist/server-api/hooks.js +152 -0
- package/dist/server-api/identity.d.ts +210 -0
- package/dist/server-api/identity.js +115 -0
- package/dist/server-api/licensing.d.ts +80 -0
- package/dist/server-api/licensing.js +53 -0
- package/dist/server-api/live.d.ts +132 -0
- package/dist/server-api/live.js +102 -0
- package/dist/server-api/meta.d.ts +31 -0
- package/dist/server-api/meta.js +21 -0
- package/dist/server-api/sync.d.ts +179 -0
- package/dist/server-api/sync.js +124 -0
- package/dist/server-api/teams.d.ts +306 -0
- package/dist/server-api/teams.js +113 -0
- package/dist/snapshot/diff.d.ts +30 -0
- package/dist/snapshot/diff.js +75 -0
- package/dist/snapshot/format.d.ts +17 -0
- package/dist/snapshot/format.js +40 -0
- package/dist/snapshot/golden-file.d.ts +45 -0
- package/dist/snapshot/golden-file.js +173 -0
- package/dist/snapshot/ignore.d.ts +14 -0
- package/dist/snapshot/ignore.js +79 -0
- package/dist/snapshot/index.d.ts +9 -0
- package/dist/snapshot/index.js +9 -0
- package/dist/snapshot/json-diff.d.ts +3 -0
- package/dist/snapshot/json-diff.js +93 -0
- package/dist/snapshot/xml-diff.d.ts +10 -0
- package/dist/snapshot/xml-diff.js +194 -0
- package/dist/soap/auth.d.ts +26 -0
- package/dist/soap/auth.js +54 -0
- package/dist/soap/curl.d.ts +20 -0
- package/dist/soap/curl.js +161 -0
- package/dist/soap/expand.d.ts +24 -0
- package/dist/soap/expand.js +95 -0
- package/dist/soap/files.d.ts +384 -0
- package/dist/soap/files.js +114 -0
- package/dist/soap/form-request.d.ts +13 -0
- package/dist/soap/form-request.js +2 -2
- package/dist/soap/generate.d.ts +12 -0
- package/dist/{generate.js → soap/generate.js} +4 -4
- package/dist/{import.d.ts → soap/import.d.ts} +4 -4
- package/dist/{import.js → soap/import.js} +13 -13
- package/dist/soap/json-operation.d.ts +35 -0
- package/dist/soap/json-operation.js +225 -0
- package/dist/soap/legacy-project/env-refs.d.ts +19 -0
- package/dist/soap/legacy-project/env-refs.js +105 -0
- package/dist/soap/legacy-project/map.d.ts +2 -2
- package/dist/soap/legacy-project/map.js +6 -0
- package/dist/soap/mime/multipart.d.ts +2 -2
- package/dist/soap/mime/multipart.js +2 -5
- package/dist/soap/mime/send-pipeline.d.ts +1 -1
- package/dist/soap/mime/send-pipeline.js +1 -1
- package/dist/soap/mime/types.d.ts +1 -3
- package/dist/soap/module.d.ts +2 -0
- package/dist/soap/module.js +13 -0
- package/dist/soap/namespace-scope.js +1 -1
- package/dist/soap/operations.d.ts +12 -0
- package/dist/{operations.js → soap/operations.js} +4 -4
- package/dist/soap/run.d.ts +70 -0
- package/dist/soap/run.js +549 -0
- package/dist/soap/script-types.d.ts +65 -0
- package/dist/soap/script-types.js +379 -0
- package/dist/soap/scripting.d.ts +45 -0
- package/dist/soap/scripting.js +221 -0
- package/dist/soap/send-input.d.ts +61 -0
- package/dist/{send-options.js → soap/send-input.js} +5 -109
- package/dist/{send.d.ts → soap/send.d.ts} +1 -1
- package/dist/{send.js → soap/send.js} +28 -12
- package/dist/soap/storage.d.ts +9 -0
- package/dist/soap/storage.js +237 -0
- package/dist/soap/transforms.d.ts +3 -12
- package/dist/soap/transforms.js +3 -14
- package/dist/{types.d.ts → soap/types.d.ts} +34 -84
- package/dist/sync/git-cli.d.ts +202 -0
- package/dist/sync/git-cli.js +684 -0
- package/dist/sync/three-way-merge.d.ts +41 -0
- package/dist/sync/three-way-merge.js +85 -0
- package/dist/sync/tree-paths.d.ts +34 -0
- package/dist/sync/tree-paths.js +131 -0
- package/dist/team-secrets/envelope.d.ts +10 -0
- package/dist/team-secrets/envelope.js +121 -0
- package/dist/team-secrets/errors.d.ts +26 -0
- package/dist/team-secrets/errors.js +27 -0
- package/dist/team-secrets/index.d.ts +14 -0
- package/dist/team-secrets/index.js +8 -0
- package/dist/team-secrets/keys.d.ts +52 -0
- package/dist/team-secrets/keys.js +158 -0
- package/dist/team-secrets/log.d.ts +48 -0
- package/dist/team-secrets/log.js +175 -0
- package/dist/team-secrets/resolve-conflict.d.ts +7 -0
- package/dist/team-secrets/resolve-conflict.js +14 -0
- package/dist/team-secrets/schema.d.ts +97 -0
- package/dist/team-secrets/schema.js +157 -0
- package/dist/team-secrets/sign.d.ts +24 -0
- package/dist/team-secrets/sign.js +71 -0
- package/dist/team-secrets/vault.d.ts +49 -0
- package/dist/team-secrets/vault.js +148 -0
- package/dist/validate/wsi/run-message.d.ts +2 -2
- package/dist/validate/wsi/run-message.js +1 -1
- package/dist/validate/wsi/run-wsdl.d.ts +2 -2
- package/dist/validate/wsi/run-wsdl.js +1 -1
- package/dist/validate/wsi/types.d.ts +1 -1
- package/dist/webhooks/model.d.ts +138 -0
- package/dist/webhooks/model.js +150 -0
- package/dist/workspace/commit-message.d.ts +1 -1
- package/dist/workspace/commit-message.js +6 -1
- package/dist/workspace/environments.d.ts +11 -4
- package/dist/workspace/environments.js +12 -0
- package/dist/workspace/index.d.ts +3 -3
- package/dist/workspace/index.js +2 -2
- package/dist/workspace/paths.d.ts +5 -2
- package/dist/workspace/paths.js +5 -2
- package/dist/workspace/schema.d.ts +7 -3
- package/dist/workspace/schema.js +24 -3
- package/dist/workspace/share.d.ts +30 -11
- package/dist/workspace/share.js +32 -6
- package/dist/ws/call.d.ts +1 -1
- package/dist/ws/call.js +2 -2
- package/dist/ws/connect.d.ts +60 -0
- package/dist/ws/connect.js +131 -0
- package/dist/ws/events.d.ts +17 -0
- package/dist/ws/events.js +1 -0
- package/dist/ws/expand.d.ts +1 -1
- package/dist/ws/expand.js +1 -1
- package/dist/ws/files.d.ts +284 -0
- package/dist/ws/files.js +71 -0
- package/dist/ws/history-entry.d.ts +44 -0
- package/dist/ws/history-entry.js +93 -0
- package/dist/ws/model.d.ts +44 -3
- package/dist/ws/model.js +3 -0
- package/dist/ws/module.d.ts +2 -0
- package/dist/ws/module.js +11 -0
- package/dist/ws/run.d.ts +63 -0
- package/dist/ws/run.js +470 -0
- package/dist/ws/session.d.ts +18 -0
- package/dist/ws/session.js +52 -25
- package/dist/ws/storage.d.ts +9 -0
- package/dist/ws/storage.js +176 -0
- package/dist/ws/transcript.d.ts +3 -4
- package/dist/ws/transcript.js +26 -17
- package/dist/ws/url.d.ts +1 -1
- package/dist/wsdl/cache.js +1 -1
- package/dist/wsdl/docs-generator.d.ts +3 -3
- package/dist/wsdl/docs-generator.js +1 -1
- package/dist/wsdl/export-definition.js +1 -1
- package/dist/wsdl/qname.d.ts +2 -5
- package/dist/wsdl/resolver.d.ts +4 -11
- package/dist/wsdl/resolver.js +3 -3
- package/dist/wsdl/update-definition.d.ts +5 -5
- package/dist/wsdl/update-definition.js +6 -6
- package/dist/wss/apply.js +1 -1
- package/dist/{project/wss-configs.d.ts → wss/configs.d.ts} +2 -2
- package/dist/{project/wss-configs.js → wss/configs.js} +2 -2
- package/dist/wss/incoming/decrypt.d.ts +1 -1
- package/dist/wss/incoming/index.js +1 -1
- package/dist/wss/incoming/verify.d.ts +1 -1
- package/dist/wss/incoming/verify.js +1 -1
- package/dist/wss/key-identifiers.js +1 -1
- package/dist/wss/model.d.ts +1 -1
- package/dist/wss/outgoing/encryption.d.ts +1 -1
- package/dist/wss/outgoing/signature.d.ts +1 -1
- package/dist/xml/decode.d.ts +15 -0
- package/dist/xml/decode.js +22 -0
- package/dist/xml/entitize.d.ts +17 -0
- package/dist/xml/entitize.js +19 -0
- package/dist/xml/index.d.ts +1 -1
- package/dist/xml/index.js +1 -1
- package/dist/xml/locate.d.ts +39 -0
- package/dist/xml/locate.js +117 -0
- package/dist/xml/qname.d.ts +12 -0
- package/dist/xml/qname.js +8 -0
- package/dist/xpath/evaluate-async.d.ts +19 -0
- package/dist/xpath/evaluate-async.js +31 -11
- package/dist/xpath/evaluate.d.ts +1 -1
- package/dist/xpath/namespaces.js +1 -1
- package/dist/xpath/worker.d.ts +11 -5
- package/dist/xpath/worker.js +24 -7
- package/dist/xsd/form-model.d.ts +19 -2
- package/dist/xsd/form-model.js +14 -2
- package/dist/xsd/json-bridge.d.ts +152 -0
- package/dist/xsd/json-bridge.js +1213 -0
- package/dist/xsd/locate.d.ts +2 -30
- package/dist/xsd/locate.js +1 -109
- package/dist/xsd/xml-scan.d.ts +2 -0
- package/dist/xsd/xml-scan.js +1 -1
- package/dist/xsd/xml-writer.d.ts +2 -0
- package/dist/xsd/xml-writer.js +4 -0
- package/package.json +12 -1
- package/dist/generate.d.ts +0 -12
- package/dist/operations.d.ts +0 -12
- package/dist/run/effective-auth.d.ts +0 -10
- package/dist/run/effective-auth.js +0 -19
- package/dist/run/prepare.d.ts +0 -43
- package/dist/run/prepare.js +0 -280
- package/dist/send-options.d.ts +0 -141
- package/dist/wsdl/fetch.d.ts +0 -13
- /package/dist/{soap → http}/charset.d.ts +0 -0
- /package/dist/{soap → http}/charset.js +0 -0
- /package/dist/{wsdl → http}/ref-policy.d.ts +0 -0
- /package/dist/{wsdl → http}/ref-policy.js +0 -0
- /package/dist/{wss/keystore → keystore}/certificate.d.ts +0 -0
- /package/dist/{wss/keystore → keystore}/certificate.js +0 -0
- /package/dist/{wss/keystore → keystore}/index.d.ts +0 -0
- /package/dist/{wss/keystore → keystore}/model.d.ts +0 -0
- /package/dist/{wss/keystore → keystore}/model.js +0 -0
- /package/dist/{wss/keystore → keystore}/pem.d.ts +0 -0
- /package/dist/{wss/keystore → keystore}/pkcs12.d.ts +0 -0
- /package/dist/{wsdl → project}/cache-naming.d.ts +0 -0
- /package/dist/{types.js → soap/types.js} +0 -0
- /package/dist/{soap → xml}/prefixes.d.ts +0 -0
- /package/dist/{soap → xml}/prefixes.js +0 -0
package/dist/rest/response.d.ts
CHANGED
|
@@ -47,26 +47,5 @@ export interface PrettyBody {
|
|
|
47
47
|
* broken body *is* the interesting thing when an API misbehaves, and hiding it would hide the bug.
|
|
48
48
|
*/
|
|
49
49
|
export declare function prettyBody(text: string, language: BodyLanguage, indent?: number): PrettyBody;
|
|
50
|
-
|
|
51
|
-
export
|
|
52
|
-
readonly name: string;
|
|
53
|
-
readonly value: string;
|
|
54
|
-
readonly domain?: string;
|
|
55
|
-
readonly path?: string;
|
|
56
|
-
/** As declared, in ISO form when it could be parsed; absent for a session cookie. */
|
|
57
|
-
readonly expires?: string;
|
|
58
|
-
readonly maxAge?: number;
|
|
59
|
-
readonly secure?: boolean;
|
|
60
|
-
readonly httpOnly?: boolean;
|
|
61
|
-
readonly sameSite?: 'Strict' | 'Lax' | 'None';
|
|
62
|
-
/** Set when the header could not be parsed as a cookie; `name` then holds the whole line. */
|
|
63
|
-
readonly malformed?: boolean;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Parses every `Set-Cookie` header of a response (RFC 6265 §5.2).
|
|
67
|
-
*
|
|
68
|
-
* `rawHeaders` rather than the merged map, because several cookies arrive as several headers and
|
|
69
|
-
* joining them with `, ` — which is what merging does — makes them unparseable. A line that is not
|
|
70
|
-
* a cookie at all is kept as `malformed` instead of dropped: it is evidence about the server.
|
|
71
|
-
*/
|
|
72
|
-
export declare function parseSetCookie(rawHeaders: readonly (readonly [string, string])[]): Cookie[];
|
|
50
|
+
export { parseSetCookie } from '../http/cookies.js';
|
|
51
|
+
export type { Cookie } from '../http/cookies.js';
|
package/dist/rest/response.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* promised, a `Set-Cookie` with an attribute in the wrong order — and none of that may throw,
|
|
8
8
|
* because the user still has to be able to look at it.
|
|
9
9
|
*/
|
|
10
|
-
import { decodeBody } from '../
|
|
11
|
-
import { mediaTypeOf } from '../
|
|
10
|
+
import { decodeBody } from '../http/charset.js';
|
|
11
|
+
import { mediaTypeOf } from '../http/media-type.js';
|
|
12
12
|
import { formatXml } from '../xml/pretty.js';
|
|
13
13
|
/**
|
|
14
14
|
* The language of a response body.
|
|
@@ -146,76 +146,4 @@ function formatHtml(text, indent) {
|
|
|
146
146
|
}
|
|
147
147
|
return lines.join('\n');
|
|
148
148
|
}
|
|
149
|
-
|
|
150
|
-
* Parses every `Set-Cookie` header of a response (RFC 6265 §5.2).
|
|
151
|
-
*
|
|
152
|
-
* `rawHeaders` rather than the merged map, because several cookies arrive as several headers and
|
|
153
|
-
* joining them with `, ` — which is what merging does — makes them unparseable. A line that is not
|
|
154
|
-
* a cookie at all is kept as `malformed` instead of dropped: it is evidence about the server.
|
|
155
|
-
*/
|
|
156
|
-
export function parseSetCookie(rawHeaders) {
|
|
157
|
-
const cookies = [];
|
|
158
|
-
for (const [name, value] of rawHeaders) {
|
|
159
|
-
if (name.toLowerCase() !== 'set-cookie') {
|
|
160
|
-
continue;
|
|
161
|
-
}
|
|
162
|
-
cookies.push(parseOne(value));
|
|
163
|
-
}
|
|
164
|
-
return cookies;
|
|
165
|
-
}
|
|
166
|
-
function parseOne(header) {
|
|
167
|
-
const parts = header.split(';');
|
|
168
|
-
const pair = parts[0] ?? '';
|
|
169
|
-
const equals = pair.indexOf('=');
|
|
170
|
-
if (equals <= 0) {
|
|
171
|
-
return { name: header.trim(), value: '', malformed: true };
|
|
172
|
-
}
|
|
173
|
-
const cookie = {
|
|
174
|
-
name: pair.slice(0, equals).trim(),
|
|
175
|
-
value: unquote(pair.slice(equals + 1).trim()),
|
|
176
|
-
};
|
|
177
|
-
for (const attribute of parts.slice(1)) {
|
|
178
|
-
const split = attribute.indexOf('=');
|
|
179
|
-
const key = (split === -1 ? attribute : attribute.slice(0, split)).trim().toLowerCase();
|
|
180
|
-
const attributeValue = split === -1 ? '' : attribute.slice(split + 1).trim();
|
|
181
|
-
switch (key) {
|
|
182
|
-
case 'domain':
|
|
183
|
-
// A leading dot is legal and means the same as its absence (RFC 6265 §5.2.3).
|
|
184
|
-
cookie.domain = attributeValue.replace(/^\./, '').toLowerCase();
|
|
185
|
-
break;
|
|
186
|
-
case 'path':
|
|
187
|
-
cookie.path = attributeValue;
|
|
188
|
-
break;
|
|
189
|
-
case 'expires': {
|
|
190
|
-
const date = new Date(attributeValue);
|
|
191
|
-
cookie.expires = Number.isNaN(date.getTime()) ? attributeValue : date.toISOString();
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
case 'max-age': {
|
|
195
|
-
const seconds = Number.parseInt(attributeValue, 10);
|
|
196
|
-
if (!Number.isNaN(seconds)) {
|
|
197
|
-
cookie.maxAge = seconds;
|
|
198
|
-
}
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
201
|
-
case 'secure':
|
|
202
|
-
cookie.secure = true;
|
|
203
|
-
break;
|
|
204
|
-
case 'httponly':
|
|
205
|
-
cookie.httpOnly = true;
|
|
206
|
-
break;
|
|
207
|
-
case 'samesite': {
|
|
208
|
-
const normalized = attributeValue.toLowerCase();
|
|
209
|
-
cookie.sameSite = normalized === 'strict' ? 'Strict' : normalized === 'none' ? 'None' : 'Lax';
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
default:
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return cookie;
|
|
217
|
-
}
|
|
218
|
-
/** Strips one layer of double quotes from a cookie value, which some servers add. */
|
|
219
|
-
function unquote(value) {
|
|
220
|
-
return value.length > 1 && value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
|
221
|
-
}
|
|
149
|
+
export { parseSetCookie } from '../http/cookies.js';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { AssertionSubject } from '../assert/model.js';
|
|
2
|
+
import type { AuthConfig, Project } from '../project/model.js';
|
|
3
|
+
import type { ProtocolRun } from '../protocol/module.js';
|
|
4
|
+
import type { RunContext } from '../run/context.js';
|
|
5
|
+
import type { Resolved } from '../run/send-helpers.js';
|
|
6
|
+
import type { EffectiveSigning } from '../webhooks/model.js';
|
|
7
|
+
import type { RestApi, RestFolder, RestRequestDef } from './model.js';
|
|
8
|
+
import type { RestExchange, RestSendInput } from './send.js';
|
|
9
|
+
/** One saved REST request, or one webhook item, selected for a run. */
|
|
10
|
+
export interface RestSelected {
|
|
11
|
+
readonly kind: 'rest';
|
|
12
|
+
readonly path: string;
|
|
13
|
+
readonly group: string;
|
|
14
|
+
readonly api: RestApi;
|
|
15
|
+
readonly chain: readonly RestFolder[];
|
|
16
|
+
readonly request: RestRequestDef;
|
|
17
|
+
/** A webhook item's effective signing (webhook-signatures §5.2); absent for an API request. */
|
|
18
|
+
readonly signing?: EffectiveSigning;
|
|
19
|
+
}
|
|
20
|
+
/** Innermost first, as the app's `authChainFor` builds it: request, its folders inside-out, the API. */
|
|
21
|
+
export declare function restEffectiveAuth(selected: RestSelected): AuthConfig;
|
|
22
|
+
/**
|
|
23
|
+
* One REST request resolved (spec §3.4): its properties and secret tokens expanded (the secrets
|
|
24
|
+
* behind `context.secretPlaceholders` when given), nothing connected and the credentials still as
|
|
25
|
+
* configured, so the input holds no `auth`. A reference nothing resolves is reported in
|
|
26
|
+
* `unresolved`, not thrown: the send refuses it, a preview shows it.
|
|
27
|
+
*
|
|
28
|
+
* A webhook item goes to its callback URL when the host names one: that URL is the whole
|
|
29
|
+
* destination, taken literally (ADR-0015), with no base. Otherwise it goes to its target, which
|
|
30
|
+
* must expand to an `http(s)` URL.
|
|
31
|
+
*
|
|
32
|
+
* @throws WirebenchError `secret-missing` | `rest-file-outside-project` | `webhook-target-missing` |
|
|
33
|
+
* `webhook-target-invalid`
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveRest(selected: RestSelected, context: RunContext): Promise<Resolved<RestSendInput>>;
|
|
36
|
+
/**
|
|
37
|
+
* TLS, signing, credentials (an OAuth2 token included) and the proxy, over a resolved input: what
|
|
38
|
+
* a send does after its pre-request script, so the script never sees a credential (spec §7).
|
|
39
|
+
*
|
|
40
|
+
* @throws WirebenchError `secret-missing` | `auth-grant-unsupported` | `keystore-missing` |
|
|
41
|
+
* `webhook-signing-secret`
|
|
42
|
+
*/
|
|
43
|
+
export declare function connectRest(selected: RestSelected, context: RunContext, input: RestSendInput): Promise<RestSendInput>;
|
|
44
|
+
/**
|
|
45
|
+
* A REST response as assertions and sequence transfers see it. A buffered event stream is the data
|
|
46
|
+
* of its events, in order, as a JSON array (spec §5.2).
|
|
47
|
+
*/
|
|
48
|
+
export declare function restSubject(exchange: RestExchange): AssertionSubject;
|
|
49
|
+
/**
|
|
50
|
+
* The REST item for `requestId`, an API request or a webhook item, built as a run builds it — and
|
|
51
|
+
* found even when its contract no longer has it (`orphaned`), which a run skips and a person may
|
|
52
|
+
* still send. Undefined when no REST request has that id.
|
|
53
|
+
*/
|
|
54
|
+
export declare function restItemFor(project: Project, requestId: string): RestSelected | undefined;
|
|
55
|
+
/** REST's run facet. */
|
|
56
|
+
export declare const restRun: ProtocolRun<RestSelected>;
|
package/dist/rest/run.js
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST's run facet (spec §3.3): the requests of every API, and the project's webhook items as a
|
|
3
|
+
* group a run sends only when a selector names it. A send resolves the request (its properties and
|
|
4
|
+
* secret tokens), runs its pre-request script, connects (its TLS identity, a webhook item's signing
|
|
5
|
+
* secret, its credentials with an OAuth2 token, the proxy), then goes on the wire (spec §3.4). A
|
|
6
|
+
* send that is not live reads an event stream to its end or the timeout (spec §5.2).
|
|
7
|
+
*/
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import { readAttachment } from '../project/attachments-cache.js';
|
|
10
|
+
import { REQUESTS_DIR, WEBHOOKS_DIR } from '../project/paths.js';
|
|
11
|
+
import { scopesFor } from '../run/context.js';
|
|
12
|
+
import { exchangeController } from '../run/exchange.js';
|
|
13
|
+
import { authFor, baseUrlFor, dropRefusedToken, insideProject, keystoreNeeds, originOf, tlsFor, unresolvedError, withSecrets, } from '../run/send-helpers.js';
|
|
14
|
+
import { ORPHANED_STEP_REASON, byOrder, findInTree, walkTree } from '../run/tree.js';
|
|
15
|
+
import { applyRestSnapshot, restRequestSnapshot, restResponseSnapshot } from './scripting.js';
|
|
16
|
+
import { createSseParser, isEventStream } from './sse.js';
|
|
17
|
+
import { loadOpenApiDocument, restOperationFor, restScriptTypes } from './script-types.js';
|
|
18
|
+
import { secretNeedsOfAuth } from '../secrets/env-names.js';
|
|
19
|
+
import { toRestSendInput } from './send-input.js';
|
|
20
|
+
import { assertWebhookTarget, effectiveSigning, effectiveTarget, signingSecretMissing, signingSecretRef, signingSourceLabel, } from '../webhooks/model.js';
|
|
21
|
+
import { resolveAuthChain } from '../http/auth/apply-auth.js';
|
|
22
|
+
import { expandRestSendInput } from './expand.js';
|
|
23
|
+
import { createApi } from './model.js';
|
|
24
|
+
import { sendRest } from './send.js';
|
|
25
|
+
import { joinBase } from './url.js';
|
|
26
|
+
/** Innermost first, as the app's `authChainFor` builds it: request, its folders inside-out, the API. */
|
|
27
|
+
export function restEffectiveAuth(selected) {
|
|
28
|
+
const { api, chain, request } = selected;
|
|
29
|
+
return resolveAuthChain([request.auth, ...[...chain].reverse().map((folder) => folder.auth), api.auth]);
|
|
30
|
+
}
|
|
31
|
+
/** A REST multipart file part or binary body, read from inside the project folder. */
|
|
32
|
+
function restFileResolver(context) {
|
|
33
|
+
return async (source) => source.kind === 'cache'
|
|
34
|
+
? readAttachment(context.projectDir, source.sha256)
|
|
35
|
+
: new Uint8Array(await readFile(await insideProject(context, source.path, 'rest-file-outside-project', source.path)));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A webhook item's signing with its secret, or `undefined` when it signs nothing. The secret is
|
|
39
|
+
* read through the run's `GetSecret` (the CLI: `WIREBENCH_SECRET_<secretEnv>`), so it is masked
|
|
40
|
+
* like every other secret the run hands out.
|
|
41
|
+
*
|
|
42
|
+
* @throws WirebenchError `webhook-signing-secret` when signing is set and the secret is not given
|
|
43
|
+
*/
|
|
44
|
+
async function signFor(selected, context) {
|
|
45
|
+
const effective = selected.signing;
|
|
46
|
+
if (effective === undefined || effective.signing.mode !== 'sign')
|
|
47
|
+
return undefined;
|
|
48
|
+
const ref = signingSecretRef(effective.signing);
|
|
49
|
+
const secret = ref === undefined ? undefined : await context.host.getSecret(ref);
|
|
50
|
+
if (secret === undefined || secret === '')
|
|
51
|
+
throw signingSecretMissing(effective, ref);
|
|
52
|
+
return { scheme: effective.signing.scheme, secret };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* One REST request resolved (spec §3.4): its properties and secret tokens expanded (the secrets
|
|
56
|
+
* behind `context.secretPlaceholders` when given), nothing connected and the credentials still as
|
|
57
|
+
* configured, so the input holds no `auth`. A reference nothing resolves is reported in
|
|
58
|
+
* `unresolved`, not thrown: the send refuses it, a preview shows it.
|
|
59
|
+
*
|
|
60
|
+
* A webhook item goes to its callback URL when the host names one: that URL is the whole
|
|
61
|
+
* destination, taken literally (ADR-0015), with no base. Otherwise it goes to its target, which
|
|
62
|
+
* must expand to an `http(s)` URL.
|
|
63
|
+
*
|
|
64
|
+
* @throws WirebenchError `secret-missing` | `rest-file-outside-project` | `webhook-target-missing` |
|
|
65
|
+
* `webhook-target-invalid`
|
|
66
|
+
*/
|
|
67
|
+
export async function resolveRest(selected, context) {
|
|
68
|
+
const { api, request } = selected;
|
|
69
|
+
const scopes = scopesFor(context);
|
|
70
|
+
const callbackUrl = isWebhookItem(selected) ? await context.host.callbackUrlFor?.(selected) : undefined;
|
|
71
|
+
const unexpanded = toRestSendInput({
|
|
72
|
+
request: {
|
|
73
|
+
method: request.method,
|
|
74
|
+
url: callbackUrl ?? request.url,
|
|
75
|
+
pathParams: request.pathParams,
|
|
76
|
+
query: request.query,
|
|
77
|
+
headers: request.headers,
|
|
78
|
+
body: request.body,
|
|
79
|
+
settings: request.settings,
|
|
80
|
+
},
|
|
81
|
+
baseUrl: callbackUrl !== undefined ? '' : baseUrlFor(context, api),
|
|
82
|
+
projectSettings: context.project.settings,
|
|
83
|
+
...(context.host.preferences !== undefined ? { preferences: context.host.preferences } : {}),
|
|
84
|
+
resolveFile: restFileResolver(context),
|
|
85
|
+
...(context.signal !== undefined ? { signal: context.signal } : {}),
|
|
86
|
+
});
|
|
87
|
+
const withTokens = await withSecrets(unexpanded, scopes, context.host.getSecret, context.secretPlaceholders);
|
|
88
|
+
const { input, unresolved } = expandRestSendInput(unexpanded, withTokens, {
|
|
89
|
+
escape: request.settings.escapeProperties === true,
|
|
90
|
+
...(callbackUrl !== undefined ? { literalUrl: true } : {}),
|
|
91
|
+
});
|
|
92
|
+
// A target holding a secret still behind its placeholder is checked by nothing: its value is not in.
|
|
93
|
+
if (isWebhookItem(selected) &&
|
|
94
|
+
callbackUrl === undefined &&
|
|
95
|
+
context.secretPlaceholders?.holds(input.baseUrl) !== true) {
|
|
96
|
+
assertWebhookTarget(input.baseUrl, input.request.url, unresolved.length > 0);
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
input: {
|
|
100
|
+
...input,
|
|
101
|
+
...(context.timeoutMs !== undefined ? { settings: { ...input.settings, timeoutMs: context.timeoutMs } } : {}),
|
|
102
|
+
},
|
|
103
|
+
unresolved,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* TLS, signing, credentials (an OAuth2 token included) and the proxy, over a resolved input: what
|
|
108
|
+
* a send does after its pre-request script, so the script never sees a credential (spec §7).
|
|
109
|
+
*
|
|
110
|
+
* @throws WirebenchError `secret-missing` | `auth-grant-unsupported` | `keystore-missing` |
|
|
111
|
+
* `webhook-signing-secret`
|
|
112
|
+
*/
|
|
113
|
+
export async function connectRest(selected, context, input) {
|
|
114
|
+
const { request } = selected;
|
|
115
|
+
const tls = await tlsFor(context, request.settings.sslKeystoreRef, request.settings.trustInvalid === true);
|
|
116
|
+
// As the app does: a webhook item's signing secret is read before any OAuth2 token is fetched.
|
|
117
|
+
const sign = await signFor(selected, context);
|
|
118
|
+
const auth = await authFor(restEffectiveAuth(selected), selected.path, context, tls);
|
|
119
|
+
// As the app does: the proxy is chosen for the base URL, or the request's own URL when there is none.
|
|
120
|
+
const proxy = await context.host.proxyFor?.(input.baseUrl === '' ? input.request.url : input.baseUrl);
|
|
121
|
+
return {
|
|
122
|
+
...input,
|
|
123
|
+
...(auth !== undefined ? { auth } : {}),
|
|
124
|
+
...(tls !== undefined ? { tls: { ...input.tls, ...tls } } : {}),
|
|
125
|
+
...(proxy !== undefined ? { proxy } : {}),
|
|
126
|
+
...(sign !== undefined ? { sign } : {}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The data of every event in a buffered event stream, in order: what a run read of the stream, to
|
|
131
|
+
* its end or the timeout. Undefined for any other response, and for one a live send streamed.
|
|
132
|
+
*/
|
|
133
|
+
function bufferedEvents(exchange) {
|
|
134
|
+
if (exchange.stream !== undefined || !isEventStream(exchange.headers['content-type']))
|
|
135
|
+
return undefined;
|
|
136
|
+
const events = [];
|
|
137
|
+
const parser = createSseParser((row) => {
|
|
138
|
+
if (row.kind === 'event')
|
|
139
|
+
events.push(row.data);
|
|
140
|
+
});
|
|
141
|
+
parser.push(exchange.body, 0);
|
|
142
|
+
parser.end();
|
|
143
|
+
return events;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* A REST response as assertions and sequence transfers see it. A buffered event stream is the data
|
|
147
|
+
* of its events, in order, as a JSON array (spec §5.2).
|
|
148
|
+
*/
|
|
149
|
+
export function restSubject(exchange) {
|
|
150
|
+
const events = bufferedEvents(exchange);
|
|
151
|
+
return {
|
|
152
|
+
protocol: 'rest',
|
|
153
|
+
status: exchange.status,
|
|
154
|
+
durationMs: exchange.durationMs,
|
|
155
|
+
bodyText: events !== undefined ? JSON.stringify(events) : exchange.text,
|
|
156
|
+
bodyKind: events !== undefined || exchange.language === 'json' ? 'json' : exchange.language === 'xml' ? 'xml' : 'other',
|
|
157
|
+
headers: exchange.rawHeaders,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/** A webhook item's signing secret, read from `WIREBENCH_SECRET_<secretEnv>` (§5.2). */
|
|
161
|
+
function signingNeeds(selected) {
|
|
162
|
+
const effective = selected.signing;
|
|
163
|
+
if (effective === undefined || effective.signing.mode !== 'sign')
|
|
164
|
+
return [];
|
|
165
|
+
const ref = signingSecretRef(effective.signing);
|
|
166
|
+
if (ref === undefined)
|
|
167
|
+
return [];
|
|
168
|
+
return [
|
|
169
|
+
{
|
|
170
|
+
ref,
|
|
171
|
+
...(effective.signing.secretEnv !== undefined ? { envName: effective.signing.secretEnv } : {}),
|
|
172
|
+
purpose: `webhook signing secret (${signingSourceLabel(effective)})`,
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* An API's requests in explorer order, without the ones its contract no longer has unless
|
|
178
|
+
* `orphaned` asks for them too.
|
|
179
|
+
*/
|
|
180
|
+
function apiCandidates(api, orphaned = false) {
|
|
181
|
+
const out = [];
|
|
182
|
+
walkTree(api, [], api.name, `apis/${api.slug}/requests`, (request, chain, group) => request.orphaned === true && !orphaned
|
|
183
|
+
? undefined
|
|
184
|
+
: { kind: 'rest', path: `${group}/${request.name}`, group, api, chain, request }, out);
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
/** True for a webhook item, which `webhookCandidates` builds against the synthetic `webhooks` API. */
|
|
188
|
+
function isWebhookItem(selected) {
|
|
189
|
+
return selected.api.id === 'webhooks';
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The project's webhook items, as REST items against a synthetic API whose base URL is each item's
|
|
193
|
+
* effective target. A run has no history, so a callback uses the target.
|
|
194
|
+
*/
|
|
195
|
+
function webhookCandidates(collection, orphaned = false) {
|
|
196
|
+
const out = [];
|
|
197
|
+
const visit = (folders, requests, chain) => {
|
|
198
|
+
const group = ['Webhooks', ...chain.map((folder) => folder.name)].join('/');
|
|
199
|
+
const dir = [WEBHOOKS_DIR, REQUESTS_DIR, ...chain.map((folder) => folder.slug)].join('/');
|
|
200
|
+
const api = createApi('Webhooks', {
|
|
201
|
+
id: 'webhooks',
|
|
202
|
+
slug: 'webhooks',
|
|
203
|
+
baseUrl: effectiveTarget(collection, chain),
|
|
204
|
+
...(collection.auth !== undefined ? { auth: collection.auth } : {}),
|
|
205
|
+
});
|
|
206
|
+
for (const request of [...requests].sort(byOrder)) {
|
|
207
|
+
if (request.orphaned === true && !orphaned)
|
|
208
|
+
continue;
|
|
209
|
+
out.push({
|
|
210
|
+
item: {
|
|
211
|
+
kind: 'rest',
|
|
212
|
+
path: `${group}/${request.name}`,
|
|
213
|
+
group,
|
|
214
|
+
api,
|
|
215
|
+
chain,
|
|
216
|
+
request,
|
|
217
|
+
signing: effectiveSigning(collection, request.id),
|
|
218
|
+
},
|
|
219
|
+
diskPath: `${dir}/${request.slug}`,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
for (const folder of [...folders].sort(byOrder))
|
|
223
|
+
visit(folder.folders, folder.requests, [...chain, folder]);
|
|
224
|
+
};
|
|
225
|
+
visit(collection.folders, collection.requests, []);
|
|
226
|
+
return out;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* The REST item for `requestId`, an API request or a webhook item, built as a run builds it — and
|
|
230
|
+
* found even when its contract no longer has it (`orphaned`), which a run skips and a person may
|
|
231
|
+
* still send. Undefined when no REST request has that id.
|
|
232
|
+
*/
|
|
233
|
+
export function restItemFor(project, requestId) {
|
|
234
|
+
const candidates = [
|
|
235
|
+
...project.apis.flatMap((api) => apiCandidates(api, true)),
|
|
236
|
+
...(project.webhooks !== undefined ? webhookCandidates(project.webhooks, true) : []),
|
|
237
|
+
];
|
|
238
|
+
return candidates.find((candidate) => candidate.item.request.id === requestId)?.item;
|
|
239
|
+
}
|
|
240
|
+
/** What a failed send was about to put on the wire: the resolved URL, the method, the enabled headers. */
|
|
241
|
+
function attemptedOf(input) {
|
|
242
|
+
return {
|
|
243
|
+
url: joinBase(input.baseUrl, input.request.url),
|
|
244
|
+
method: input.request.method,
|
|
245
|
+
headers: Object.fromEntries(input.request.headers.filter((header) => header.enabled).map((header) => [header.name, header.value])),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Resolves, connects and sends one request, telling the host when either stage fails, then hands
|
|
250
|
+
* the response's cookies and its contract result to the host. A reference nothing resolves is
|
|
251
|
+
* refused in the prepare stage, with what would have been sent; a failure before resolve has an
|
|
252
|
+
* input is reported with nothing attempted.
|
|
253
|
+
*/
|
|
254
|
+
async function connectAndSend(selected, context, resolve, controller, live,
|
|
255
|
+
/** The pre-request script's step, inside the prepare stage so its failure is reported with it. */
|
|
256
|
+
script) {
|
|
257
|
+
let startedAt = Date.now();
|
|
258
|
+
// Never masks the send's own error: a row that cannot be built, or a host that throws, is dropped.
|
|
259
|
+
const failed = (stage, error, attempted) => {
|
|
260
|
+
try {
|
|
261
|
+
context.host.events?.onFailed?.(selected, {
|
|
262
|
+
stage,
|
|
263
|
+
error,
|
|
264
|
+
startedAt,
|
|
265
|
+
durationMs: Date.now() - startedAt,
|
|
266
|
+
...(attempted !== undefined ? { attempted: attemptedOf(attempted), input: attempted } : {}),
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
// Deliberately ignored — see above.
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
let input;
|
|
274
|
+
let connected;
|
|
275
|
+
try {
|
|
276
|
+
const resolved = await resolve();
|
|
277
|
+
input = resolved.input;
|
|
278
|
+
if (resolved.unresolved.length > 0) {
|
|
279
|
+
throw unresolvedError('rest-unresolved-properties', selected.path, resolved.unresolved);
|
|
280
|
+
}
|
|
281
|
+
connected = await connectRest(selected, context, script !== undefined ? await script(input) : input);
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
failed('prepare', error, input);
|
|
285
|
+
throw error;
|
|
286
|
+
}
|
|
287
|
+
// The send stage's own clock: a send-stage failure never counts resolve, the script, the token or the proxy.
|
|
288
|
+
startedAt = Date.now();
|
|
289
|
+
let exchange;
|
|
290
|
+
try {
|
|
291
|
+
exchange = await sendRest({
|
|
292
|
+
...connected,
|
|
293
|
+
signal: controller.signal,
|
|
294
|
+
// Not part of `connected`, which History and the log keep: the jar is the host's, per send.
|
|
295
|
+
...(context.host.cookies !== undefined
|
|
296
|
+
? { jar: { host: context.host.cookies, send: selected.request.settings.sendCookies === true } }
|
|
297
|
+
: {}),
|
|
298
|
+
// Only a live send parses an event stream; any other keeps the buffered body.
|
|
299
|
+
...(live
|
|
300
|
+
? {
|
|
301
|
+
onStream: {
|
|
302
|
+
onOpen: (status, headers) => controller.queue.push({ protocol: 'rest', kind: 'open', status, headers }),
|
|
303
|
+
onRow: (row) => controller.queue.push({ protocol: 'rest', kind: 'row', row }),
|
|
304
|
+
},
|
|
305
|
+
}
|
|
306
|
+
: {}),
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
failed('send', error, connected);
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
dropRefusedToken(context, connected.auth, exchange.status === 401);
|
|
314
|
+
// The request has gone out: a contract check that rejects checked nothing, and fails nothing.
|
|
315
|
+
const contract = await context.host.contractFor?.(selected, exchange, connected).catch(() => undefined);
|
|
316
|
+
return {
|
|
317
|
+
connected,
|
|
318
|
+
sent: {
|
|
319
|
+
subject: restSubject(exchange),
|
|
320
|
+
raw: exchange,
|
|
321
|
+
exchange: { kind: 'rest', rest: exchange, input: connected, ...(contract !== undefined ? { contract } : {}) },
|
|
322
|
+
...originOf(exchange.request.url),
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* One REST request as a run sends it (spec §3.4): resolve, run its pre-request script when
|
|
328
|
+
* `scripts` is given, connect, send, then its post-response script.
|
|
329
|
+
*/
|
|
330
|
+
async function sendRestItem(selected, context, scripts, controller, live) {
|
|
331
|
+
if (scripts === undefined) {
|
|
332
|
+
return (await connectAndSend(selected, context, () => resolveRest(selected, context), controller, live)).sent;
|
|
333
|
+
}
|
|
334
|
+
// Resolved with its secrets behind placeholders; the URL is rebuilt only when the script changed it.
|
|
335
|
+
const resolve = () => resolveRest(selected, { ...context, secretPlaceholders: scripts.placeholders });
|
|
336
|
+
let sent;
|
|
337
|
+
const result = await connectAndSend(selected, context, resolve, controller, live, async (input) => {
|
|
338
|
+
const before = restRequestSnapshot(input);
|
|
339
|
+
sent = await scripts.session.pre(before);
|
|
340
|
+
const changed = applyRestSnapshot(input, before, sent);
|
|
341
|
+
const restored = await scripts.placeholders.restore({ baseUrl: changed.baseUrl, request: changed.request }, context.host.getSecret);
|
|
342
|
+
return { ...changed, ...restored };
|
|
343
|
+
});
|
|
344
|
+
const exchange = result.sent.raw;
|
|
345
|
+
return {
|
|
346
|
+
...result.sent,
|
|
347
|
+
script: await scripts.session.post(sent, restResponseSnapshot(exchange)),
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
/** REST's run facet. */
|
|
351
|
+
export const restRun = {
|
|
352
|
+
groups(project) {
|
|
353
|
+
const apis = project.apis.map((api) => ({
|
|
354
|
+
order: api.order,
|
|
355
|
+
name: api.name,
|
|
356
|
+
candidates: apiCandidates(api),
|
|
357
|
+
}));
|
|
358
|
+
// Webhook items deliver to a receiver rather than test an API: sent only when a selector names one.
|
|
359
|
+
return project.webhooks === undefined
|
|
360
|
+
? apis
|
|
361
|
+
: [...apis, { order: 0, name: 'Webhooks', candidates: webhookCandidates(project.webhooks), explicitOnly: true }];
|
|
362
|
+
},
|
|
363
|
+
whyNotRunnable(project, requestId) {
|
|
364
|
+
if (project.webhooks !== undefined && findInTree(project.webhooks, requestId) !== undefined) {
|
|
365
|
+
return 'A webhook cannot be a sequence step';
|
|
366
|
+
}
|
|
367
|
+
for (const api of project.apis) {
|
|
368
|
+
const request = findInTree(api, requestId);
|
|
369
|
+
if (request !== undefined) {
|
|
370
|
+
return request.orphaned === true ? ORPHANED_STEP_REASON : undefined;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return undefined;
|
|
374
|
+
},
|
|
375
|
+
open(selected, scope, host, options) {
|
|
376
|
+
const controller = exchangeController('rest', options);
|
|
377
|
+
const context = { ...scope.context, host, signal: controller.signal };
|
|
378
|
+
return controller.handle(() => sendRestItem(selected, context, options.scripts, controller, options.live === true));
|
|
379
|
+
},
|
|
380
|
+
resolve(selected, scope, host) {
|
|
381
|
+
return resolveRest(selected, { ...scope.context, host });
|
|
382
|
+
},
|
|
383
|
+
async scriptTypes(selected, scope) {
|
|
384
|
+
const { api } = selected;
|
|
385
|
+
const openApi = await scope.memo(`rest:${api.id}:openapi`, () => loadOpenApiDocument(scope.context.projectDir, api.slug));
|
|
386
|
+
return { generated: restScriptTypes(restOperationFor(openApi, selected.request.contract)) };
|
|
387
|
+
},
|
|
388
|
+
secretNeeds(selected, project) {
|
|
389
|
+
return [
|
|
390
|
+
...secretNeedsOfAuth(restEffectiveAuth(selected)),
|
|
391
|
+
...keystoreNeeds(project, selected.request.settings.sslKeystoreRef),
|
|
392
|
+
...signingNeeds(selected),
|
|
393
|
+
];
|
|
394
|
+
},
|
|
395
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RestContractLink } from './model.js';
|
|
2
|
+
import type { OpenApiDocument, OpenApiOperation } from './openapi/model.js';
|
|
3
|
+
export declare function restScriptTypes(operation: OpenApiOperation | undefined): string;
|
|
4
|
+
/** The operation a REST request is linked to, by its method and templated path. */
|
|
5
|
+
export declare function restOperationFor(document: OpenApiDocument | undefined, contract: RestContractLink | undefined): OpenApiOperation | undefined;
|
|
6
|
+
/** An API's cached OpenAPI document, read offline; `undefined` when it has none or it cannot be read. */
|
|
7
|
+
export declare function loadOpenApiDocument(projectDir: string, apiSlug: string): Promise<OpenApiDocument | undefined>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A REST request's script types, from the OpenAPI operation it is linked to (spec §Types, REST).
|
|
3
|
+
*
|
|
4
|
+
* `WbRequestBody` is the JSON request body's type. `WbResponse` is a union with one arm per declared
|
|
5
|
+
* status. Each arm's `status` is a set of literals — one code, a range less the codes declared on
|
|
6
|
+
* their own, or everything left for `default` — so `response.status === 200` narrows `json()` exactly,
|
|
7
|
+
* and a status the contract does not declare falls into a last arm whose body is `unknown`.
|
|
8
|
+
*/
|
|
9
|
+
import { ProjectError } from '../errors.js';
|
|
10
|
+
import { apiDefinitionDir } from '../project/paths.js';
|
|
11
|
+
import { JsonSchemaTypes } from '../script/types/json-schema.js';
|
|
12
|
+
import { createCachedApiFetch, readApiDefinitionCache } from './openapi/cache.js';
|
|
13
|
+
import { parseOpenApi } from './openapi/import.js';
|
|
14
|
+
/** The JSON media type among a content map's keys, if any. */
|
|
15
|
+
function jsonMedia(content) {
|
|
16
|
+
if (content === undefined) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const key = Object.keys(content).find((k) => /^application\/json\b/i.test(k)) ??
|
|
20
|
+
Object.keys(content).find((k) => /\+json\b/i.test(k));
|
|
21
|
+
return key === undefined ? undefined : content[key];
|
|
22
|
+
}
|
|
23
|
+
export function restScriptTypes(operation) {
|
|
24
|
+
if (operation === undefined) {
|
|
25
|
+
return [
|
|
26
|
+
'// This request is not linked to an operation of its API, so its bodies are untyped.',
|
|
27
|
+
'type WbRequestBody = unknown;',
|
|
28
|
+
'type WbResponse = WbResponseArm<WbStatus, unknown>;',
|
|
29
|
+
'',
|
|
30
|
+
].join('\n');
|
|
31
|
+
}
|
|
32
|
+
const types = new JsonSchemaTypes();
|
|
33
|
+
const requestMedia = jsonMedia(operation.requestBody?.content);
|
|
34
|
+
const requestBody = requestMedia?.schema !== undefined ? types.typeOf(requestMedia.schema) : 'unknown';
|
|
35
|
+
const responses = operation.responses ?? {};
|
|
36
|
+
const exact = Object.keys(responses).filter((key) => /^[1-5]\d\d$/.test(key));
|
|
37
|
+
const ranges = Object.keys(responses).filter((key) => /^[1-5]XX$/i.test(key));
|
|
38
|
+
const exactUnion = exact.length > 0 ? exact.join(' | ') : 'never';
|
|
39
|
+
const rangeTypes = ranges.map((key) => `WbRange${key[0]}`);
|
|
40
|
+
const arms = [];
|
|
41
|
+
const bodyOf = (key) => {
|
|
42
|
+
const media = jsonMedia(responses[key]?.content);
|
|
43
|
+
return media?.schema !== undefined ? types.typeOf(media.schema) : 'unknown';
|
|
44
|
+
};
|
|
45
|
+
for (const key of exact) {
|
|
46
|
+
arms.push(`WbResponseArm<${key}, ${bodyOf(key)}>`);
|
|
47
|
+
}
|
|
48
|
+
for (const key of ranges) {
|
|
49
|
+
arms.push(`WbResponseArm<Exclude<WbRange${key[0]}, ${exactUnion}>, ${bodyOf(key)}>`);
|
|
50
|
+
}
|
|
51
|
+
const covered = [exactUnion, ...rangeTypes].filter((t) => t !== 'never').join(' | ') || 'never';
|
|
52
|
+
const rest = `Exclude<WbStatus, ${covered}>`;
|
|
53
|
+
arms.push(`WbResponseArm<${rest}, ${responses['default'] !== undefined ? bodyOf('default') : 'unknown'}>`);
|
|
54
|
+
const where = `${operation.method.toUpperCase()} ${operation.path}`.replace(/\*\//g, '*\\/');
|
|
55
|
+
return [
|
|
56
|
+
`// Types from the contract's ${where}.`,
|
|
57
|
+
types.declarations(),
|
|
58
|
+
`type WbRequestBody = ${requestBody};`,
|
|
59
|
+
`type WbResponse =\n | ${arms.join('\n | ')};`,
|
|
60
|
+
'',
|
|
61
|
+
].join('\n');
|
|
62
|
+
}
|
|
63
|
+
/** The operation a REST request is linked to, by its method and templated path. */
|
|
64
|
+
export function restOperationFor(document, contract) {
|
|
65
|
+
if (document === undefined || contract === undefined)
|
|
66
|
+
return undefined;
|
|
67
|
+
return document.operations.find((op) => op.method.toLowerCase() === contract.method.toLowerCase() && op.path === contract.path);
|
|
68
|
+
}
|
|
69
|
+
/** An API's cached OpenAPI document, read offline; `undefined` when it has none or it cannot be read. */
|
|
70
|
+
export async function loadOpenApiDocument(projectDir, apiSlug) {
|
|
71
|
+
const dir = apiDefinitionDir(projectDir, apiSlug);
|
|
72
|
+
try {
|
|
73
|
+
const cached = await readApiDefinitionCache(dir);
|
|
74
|
+
const offline = createCachedApiFetch(cached.manifest, dir, (location) => Promise.reject(new ProjectError('definition-cache-missing', `"${location}" is not in this API's definition cache`, {
|
|
75
|
+
details: { location },
|
|
76
|
+
})));
|
|
77
|
+
const parsed = await parseOpenApi({ kind: 'url', url: cached.manifest.rootLocation }, { fetchDocument: offline });
|
|
78
|
+
return parsed.document;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|