@wirebench/engine 2.2.0 → 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
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine keys for team secrets (team-secrets spec §2, §4): one X25519 pair to decrypt and one Ed25519
|
|
3
|
+
* pair to sign, per machine per workspace. Keys travel as base64url of their raw 32 bytes, which is what
|
|
4
|
+
* a JWK's `x` and `d` already are, so `node:crypto` imports them without any DER handling.
|
|
5
|
+
*
|
|
6
|
+
* Pure: no I/O. The desktop keeps the private halves in its keychain-backed store; nothing else does.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash, createPrivateKey, createPublicKey, generateKeyPairSync } from 'node:crypto';
|
|
9
|
+
import { teamSecretsError } from './errors.js';
|
|
10
|
+
/** A key id: the first 26 base32 characters of SHA-256 over both public keys. */
|
|
11
|
+
export const KEY_ID_PATTERN = /^[A-Z2-7]{26}$/;
|
|
12
|
+
export function base64url(bytes) {
|
|
13
|
+
return Buffer.from(bytes).toString('base64url');
|
|
14
|
+
}
|
|
15
|
+
const BASE64URL_PATTERN = /^[A-Za-z0-9_-]*$/;
|
|
16
|
+
/**
|
|
17
|
+
* Strict base64url decoding: Node's own decoder tolerates padding, standard `+`/`/`, and embedded
|
|
18
|
+
* whitespace, silently turning any of those into *some* bytes. A team-secrets field is either exactly
|
|
19
|
+
* base64url or it is corrupt, so this instead requires the alphabet `[A-Za-z0-9_-]` with no padding, and
|
|
20
|
+
* that re-encoding the decoded bytes reproduces the input exactly (catching a truncated last group, which
|
|
21
|
+
* the pattern alone would not).
|
|
22
|
+
*
|
|
23
|
+
* @throws WirebenchError `team-secrets-bad-key` if `text` is not strictly base64url.
|
|
24
|
+
*/
|
|
25
|
+
export function fromBase64url(text) {
|
|
26
|
+
if (!BASE64URL_PATTERN.test(text)) {
|
|
27
|
+
throw teamSecretsError('team-secrets-bad-key');
|
|
28
|
+
}
|
|
29
|
+
const bytes = Buffer.from(text, 'base64url');
|
|
30
|
+
if (base64url(bytes) !== text) {
|
|
31
|
+
throw teamSecretsError('team-secrets-bad-key');
|
|
32
|
+
}
|
|
33
|
+
return bytes;
|
|
34
|
+
}
|
|
35
|
+
const BASE32_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
36
|
+
/** RFC 4648 base32 without padding. */
|
|
37
|
+
export function base32(bytes) {
|
|
38
|
+
let bits = 0;
|
|
39
|
+
let value = 0;
|
|
40
|
+
let out = '';
|
|
41
|
+
for (const byte of bytes) {
|
|
42
|
+
// Only the bits not yet written are kept (fewer than 13), so the number never overflows.
|
|
43
|
+
value = ((value << 8) | byte) & 0x1fff;
|
|
44
|
+
bits += 8;
|
|
45
|
+
while (bits >= 5) {
|
|
46
|
+
out += BASE32_ALPHABET[(value >>> (bits - 5)) & 31];
|
|
47
|
+
bits -= 5;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (bits > 0) {
|
|
51
|
+
out += BASE32_ALPHABET[(value << (5 - bits)) & 31];
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
const PUBLIC_KEY_LENGTH = 32;
|
|
56
|
+
/** @throws WirebenchError `team-secrets-bad-key` unless `bytes` is exactly `length` long. */
|
|
57
|
+
function assertKeyLength(bytes, length) {
|
|
58
|
+
if (bytes.length !== length) {
|
|
59
|
+
throw teamSecretsError('team-secrets-bad-key');
|
|
60
|
+
}
|
|
61
|
+
return bytes;
|
|
62
|
+
}
|
|
63
|
+
function publicDigest(keys) {
|
|
64
|
+
return createHash('sha256')
|
|
65
|
+
.update(assertKeyLength(fromBase64url(keys.encryptionKey), PUBLIC_KEY_LENGTH))
|
|
66
|
+
.update(assertKeyLength(fromBase64url(keys.signingKey), PUBLIC_KEY_LENGTH))
|
|
67
|
+
.digest();
|
|
68
|
+
}
|
|
69
|
+
export function keyIdOf(keys) {
|
|
70
|
+
return base32(publicDigest(keys)).slice(0, 26);
|
|
71
|
+
}
|
|
72
|
+
/** What an admin reads out to the person (§3.2): the first 16 hex of the same digest, in groups of four. */
|
|
73
|
+
export function fingerprintOf(keys) {
|
|
74
|
+
return publicDigest(keys).toString('hex').slice(0, 16).match(/.{4}/g)?.join(' ') ?? '';
|
|
75
|
+
}
|
|
76
|
+
export function generateMachineKeys() {
|
|
77
|
+
const encryption = generateKeyPairSync('x25519').privateKey.export({ format: 'jwk' });
|
|
78
|
+
const signing = generateKeyPairSync('ed25519').privateKey.export({ format: 'jwk' });
|
|
79
|
+
const publicKeys = { encryptionKey: String(encryption.x), signingKey: String(signing.x) };
|
|
80
|
+
return {
|
|
81
|
+
...publicKeys,
|
|
82
|
+
keyId: keyIdOf(publicKeys),
|
|
83
|
+
encryptionPrivate: String(encryption.d),
|
|
84
|
+
signingPrivate: String(signing.d),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export function encryptionPublicKey(raw) {
|
|
88
|
+
assertKeyLength(fromBase64url(raw), PUBLIC_KEY_LENGTH);
|
|
89
|
+
return createPublicKey({ key: { kty: 'OKP', crv: 'X25519', x: raw }, format: 'jwk' });
|
|
90
|
+
}
|
|
91
|
+
export function encryptionPrivateKey(keys) {
|
|
92
|
+
return createPrivateKey({
|
|
93
|
+
key: { kty: 'OKP', crv: 'X25519', x: keys.encryptionKey, d: keys.encryptionPrivate },
|
|
94
|
+
format: 'jwk',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export function signingPublicKey(raw) {
|
|
98
|
+
assertKeyLength(fromBase64url(raw), PUBLIC_KEY_LENGTH);
|
|
99
|
+
return createPublicKey({ key: { kty: 'OKP', crv: 'Ed25519', x: raw }, format: 'jwk' });
|
|
100
|
+
}
|
|
101
|
+
export function signingPrivateKey(keys) {
|
|
102
|
+
return createPrivateKey({
|
|
103
|
+
key: { kty: 'OKP', crv: 'Ed25519', x: keys.signingKey, d: keys.signingPrivate },
|
|
104
|
+
format: 'jwk',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/** The stored form, kept in the keychain-backed store only. */
|
|
108
|
+
export function serializeMachineKeys(keys) {
|
|
109
|
+
return JSON.stringify({
|
|
110
|
+
keyId: keys.keyId,
|
|
111
|
+
encryptionKey: keys.encryptionKey,
|
|
112
|
+
encryptionPrivate: keys.encryptionPrivate,
|
|
113
|
+
signingKey: keys.signingKey,
|
|
114
|
+
signingPrivate: keys.signingPrivate,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/** The public half (base64url `x`) a JWK private key exports, i.e. what its private half actually is a key for. */
|
|
118
|
+
function publicHalfOf(privateKey) {
|
|
119
|
+
return String(createPublicKey(privateKey).export({ format: 'jwk' }).x);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Reads the stored form back; `undefined` for anything malformed, whose key id does not match its public
|
|
123
|
+
* keys, or whose public keys are not the ones its private halves actually derive (a stored file could
|
|
124
|
+
* otherwise carry a public key from one machine paired with a private key from another).
|
|
125
|
+
*/
|
|
126
|
+
export function parseMachineKeys(text) {
|
|
127
|
+
let parsed;
|
|
128
|
+
try {
|
|
129
|
+
parsed = JSON.parse(text);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
const fields = parsed;
|
|
138
|
+
const names = ['keyId', 'encryptionKey', 'encryptionPrivate', 'signingKey', 'signingPrivate'];
|
|
139
|
+
if (names.some((name) => typeof fields[name] !== 'string')) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
const keys = Object.fromEntries(names.map((name) => [name, fields[name]]));
|
|
143
|
+
try {
|
|
144
|
+
if (keyIdOf(keys) !== keys.keyId) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
if (publicHalfOf(encryptionPrivateKey(keys)) !== keys.encryptionKey) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
if (publicHalfOf(signingPrivateKey(keys)) !== keys.signingKey) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
return keys;
|
|
158
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AccessEntryFile, KeyRequestFile } from './schema.js';
|
|
2
|
+
/** A key request that proved possession of its keys. */
|
|
3
|
+
export interface KeyInfo {
|
|
4
|
+
readonly keyId: string;
|
|
5
|
+
readonly encryptionKey: string;
|
|
6
|
+
readonly signingKey: string;
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly email: string;
|
|
9
|
+
readonly machine: string;
|
|
10
|
+
readonly requestedAt: string;
|
|
11
|
+
readonly fingerprint: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Removal {
|
|
14
|
+
readonly keyId: string;
|
|
15
|
+
readonly at: string;
|
|
16
|
+
readonly by: string;
|
|
17
|
+
readonly entryId: string;
|
|
18
|
+
}
|
|
19
|
+
export type LogProblem = 'unknown-signer' | 'bad-signature' | 'second-genesis' | 'no-genesis' | 'not-allowed' | 'unknown-key' | 'already-approved' | 'removed-key' | 'not-approved' | 'not-admin' | 'already-admin' | 'last-admin' | 'last-approved' | 'wrong-authority';
|
|
20
|
+
export interface AccessState {
|
|
21
|
+
/** A valid genesis was replayed. */
|
|
22
|
+
readonly on: boolean;
|
|
23
|
+
readonly authority?: 'signed' | 'server';
|
|
24
|
+
readonly genesisId?: string;
|
|
25
|
+
readonly keys: ReadonlyMap<string, KeyInfo>;
|
|
26
|
+
readonly approved: ReadonlySet<string>;
|
|
27
|
+
/** Always empty with `authority: server`. */
|
|
28
|
+
readonly admins: ReadonlySet<string>;
|
|
29
|
+
readonly removed: readonly Removal[];
|
|
30
|
+
readonly problems: readonly {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly problem: LogProblem;
|
|
33
|
+
}[];
|
|
34
|
+
}
|
|
35
|
+
/** The key requests whose id matches their keys and whose self-signature verifies, by key id. */
|
|
36
|
+
export declare function verifiedKeys(files: readonly KeyRequestFile[]): Map<string, KeyInfo>;
|
|
37
|
+
/**
|
|
38
|
+
* The id for a new access entry: a ULID for `now`, or just after the newest existing one when this
|
|
39
|
+
* machine's clock is behind it, so the entry always replays after what its writer saw (§15 clock skew).
|
|
40
|
+
*/
|
|
41
|
+
export declare function nextAccessEntryId(existing: readonly string[], now: number): string;
|
|
42
|
+
/**
|
|
43
|
+
* Replays `entries` in ULID order. `genesisId`, when given, is the only entry allowed to be the genesis
|
|
44
|
+
* (plan decision 4); without it the first valid genesis wins.
|
|
45
|
+
*/
|
|
46
|
+
export declare function replayAccessLog(keys: ReadonlyMap<string, KeyInfo>, entries: readonly AccessEntryFile[], options?: {
|
|
47
|
+
readonly genesisId?: string;
|
|
48
|
+
}): AccessState;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The access log (§2, §3.7): `access/<ulid>.yaml` entries replayed in ULID order give the approved keys
|
|
3
|
+
* and the admins. With `authority: signed` (git and folder shares) an entry counts only when an admin at
|
|
4
|
+
* that point of the replay signed it; with `authority: server` any approved key's signature counts, and
|
|
5
|
+
* the server refuses a non-admin's push to `access/` (§5.1). Invalid entries are skipped and listed.
|
|
6
|
+
*/
|
|
7
|
+
import { decodeTime, ulid } from 'ulidx';
|
|
8
|
+
import { fingerprintOf, keyIdOf } from './keys.js';
|
|
9
|
+
import { verifyDocument } from './sign.js';
|
|
10
|
+
/** The key requests whose id matches their keys and whose self-signature verifies, by key id. */
|
|
11
|
+
export function verifiedKeys(files) {
|
|
12
|
+
const keys = new Map();
|
|
13
|
+
for (const file of files) {
|
|
14
|
+
if (keyIdOf(file) !== file.keyId || !verifyDocument(file, file.signingKey)) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
keys.set(file.keyId, {
|
|
18
|
+
keyId: file.keyId,
|
|
19
|
+
encryptionKey: file.encryptionKey,
|
|
20
|
+
signingKey: file.signingKey,
|
|
21
|
+
name: file.name,
|
|
22
|
+
email: file.email,
|
|
23
|
+
machine: file.machine,
|
|
24
|
+
requestedAt: file.requestedAt,
|
|
25
|
+
fingerprint: fingerprintOf(file),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return keys;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The id for a new access entry: a ULID for `now`, or just after the newest existing one when this
|
|
32
|
+
* machine's clock is behind it, so the entry always replays after what its writer saw (§15 clock skew).
|
|
33
|
+
*/
|
|
34
|
+
export function nextAccessEntryId(existing, now) {
|
|
35
|
+
const last = existing.reduce((max, id) => (max === undefined || id > max ? id : max), undefined);
|
|
36
|
+
if (last === undefined) {
|
|
37
|
+
return ulid(now);
|
|
38
|
+
}
|
|
39
|
+
// A corrupted or out-of-range id (outside what `ULID_PATTERN` accepts) must never crash entry
|
|
40
|
+
// creation — decodeTime throws on those, so fall back to `now` rather than propagate.
|
|
41
|
+
let lastTime;
|
|
42
|
+
try {
|
|
43
|
+
lastTime = decodeTime(last);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return ulid(now);
|
|
47
|
+
}
|
|
48
|
+
return ulid(Math.max(now, lastTime + 1));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Replays `entries` in ULID order. `genesisId`, when given, is the only entry allowed to be the genesis
|
|
52
|
+
* (plan decision 4); without it the first valid genesis wins.
|
|
53
|
+
*/
|
|
54
|
+
export function replayAccessLog(keys, entries, options = {}) {
|
|
55
|
+
const sorted = [...entries].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
56
|
+
let authority;
|
|
57
|
+
let genesisId;
|
|
58
|
+
const approved = new Set();
|
|
59
|
+
const admins = new Set();
|
|
60
|
+
const removedKeys = new Set();
|
|
61
|
+
const removed = [];
|
|
62
|
+
const problems = [];
|
|
63
|
+
for (const entry of sorted) {
|
|
64
|
+
const reject = (problem) => {
|
|
65
|
+
problems.push({ id: entry.id, problem });
|
|
66
|
+
};
|
|
67
|
+
const signer = keys.get(entry.by);
|
|
68
|
+
if (signer === undefined) {
|
|
69
|
+
reject('unknown-signer');
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (!verifyDocument(entry, signer.signingKey)) {
|
|
73
|
+
reject('bad-signature');
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (entry.action === 'genesis') {
|
|
77
|
+
if (authority !== undefined || (options.genesisId !== undefined && options.genesisId !== entry.id)) {
|
|
78
|
+
reject('second-genesis');
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (entry.key !== entry.by || entry.authority === undefined) {
|
|
82
|
+
reject('not-allowed');
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
authority = entry.authority;
|
|
86
|
+
genesisId = entry.id;
|
|
87
|
+
approved.add(entry.key);
|
|
88
|
+
if (authority === 'signed') {
|
|
89
|
+
admins.add(entry.key);
|
|
90
|
+
}
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (authority === undefined) {
|
|
94
|
+
reject('no-genesis');
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const mayManage = authority === 'signed' ? admins.has(entry.by) : approved.has(entry.by);
|
|
98
|
+
if (!mayManage) {
|
|
99
|
+
reject('not-allowed');
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (!keys.has(entry.key)) {
|
|
103
|
+
reject('unknown-key');
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
switch (entry.action) {
|
|
107
|
+
case 'approve':
|
|
108
|
+
if (removedKeys.has(entry.key)) {
|
|
109
|
+
reject('removed-key');
|
|
110
|
+
}
|
|
111
|
+
else if (approved.has(entry.key)) {
|
|
112
|
+
reject('already-approved');
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
approved.add(entry.key);
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
case 'remove':
|
|
119
|
+
if (!approved.has(entry.key)) {
|
|
120
|
+
reject('not-approved');
|
|
121
|
+
}
|
|
122
|
+
else if (authority === 'signed' && admins.has(entry.key) && admins.size === 1) {
|
|
123
|
+
reject('last-admin');
|
|
124
|
+
}
|
|
125
|
+
else if (authority === 'server' && approved.size === 1) {
|
|
126
|
+
reject('last-approved');
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
approved.delete(entry.key);
|
|
130
|
+
admins.delete(entry.key);
|
|
131
|
+
removedKeys.add(entry.key);
|
|
132
|
+
removed.push({ keyId: entry.key, at: entry.at, by: entry.by, entryId: entry.id });
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
case 'grant-admin':
|
|
136
|
+
if (authority !== 'signed') {
|
|
137
|
+
reject('wrong-authority');
|
|
138
|
+
}
|
|
139
|
+
else if (!approved.has(entry.key)) {
|
|
140
|
+
reject('not-approved');
|
|
141
|
+
}
|
|
142
|
+
else if (admins.has(entry.key)) {
|
|
143
|
+
reject('already-admin');
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
admins.add(entry.key);
|
|
147
|
+
}
|
|
148
|
+
break;
|
|
149
|
+
case 'revoke-admin':
|
|
150
|
+
if (authority !== 'signed') {
|
|
151
|
+
reject('wrong-authority');
|
|
152
|
+
}
|
|
153
|
+
else if (!admins.has(entry.key)) {
|
|
154
|
+
reject('not-admin');
|
|
155
|
+
}
|
|
156
|
+
else if (admins.size === 1) {
|
|
157
|
+
reject('last-admin');
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
admins.delete(entry.key);
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
on: authority !== undefined,
|
|
167
|
+
...(authority !== undefined ? { authority } : {}),
|
|
168
|
+
...(genesisId !== undefined ? { genesisId } : {}),
|
|
169
|
+
keys,
|
|
170
|
+
approved,
|
|
171
|
+
admins,
|
|
172
|
+
removed,
|
|
173
|
+
problems,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §3.5: a vault entry is a whole-file value. Of two concurrent versions the later `updatedAt` wins, then
|
|
3
|
+
* the lower `updatedBy`; a side without the file (deleted, or unreadable) loses to one that has it (plan
|
|
4
|
+
* decision 8). Both missing: theirs.
|
|
5
|
+
*/
|
|
6
|
+
import type { VaultEntryFile } from './schema.js';
|
|
7
|
+
export declare function vaultConflictWinner(mine: VaultEntryFile | undefined, theirs: VaultEntryFile | undefined): 'mine' | 'theirs';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function vaultConflictWinner(mine, theirs) {
|
|
2
|
+
if (mine === undefined) {
|
|
3
|
+
return 'theirs';
|
|
4
|
+
}
|
|
5
|
+
if (theirs === undefined) {
|
|
6
|
+
return 'mine';
|
|
7
|
+
}
|
|
8
|
+
const mineAt = Date.parse(mine.updatedAt);
|
|
9
|
+
const theirsAt = Date.parse(theirs.updatedAt);
|
|
10
|
+
if (mineAt !== theirsAt) {
|
|
11
|
+
return mineAt > theirsAt ? 'mine' : 'theirs';
|
|
12
|
+
}
|
|
13
|
+
return mine.updatedBy < theirs.updatedBy ? 'mine' : 'theirs';
|
|
14
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const TEAM_SECRETS_FORMAT_VERSION = 1;
|
|
3
|
+
/**
|
|
4
|
+
* A Crockford-base32 ULID, as `ulidx` writes it. The first character is restricted to `0`-`7`: a ULID's
|
|
5
|
+
* 48-bit timestamp fills at most that much of the first base32 group, so a wider first character (a
|
|
6
|
+
* corrupted or adversarial id) would decode to a timestamp `ulidx`'s `decodeTime` rejects outright — this
|
|
7
|
+
* pattern keeps that failure at parse time instead of wherever `decodeTime` is next called.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ULID_PATTERN: RegExp;
|
|
10
|
+
export declare const keyIdSchema: z.ZodString;
|
|
11
|
+
export declare const keyRequestFileSchema: z.ZodObject<{
|
|
12
|
+
version: z.ZodLiteral<1>;
|
|
13
|
+
keyId: z.ZodString;
|
|
14
|
+
encryptionKey: z.ZodString;
|
|
15
|
+
signingKey: z.ZodString;
|
|
16
|
+
name: z.ZodString;
|
|
17
|
+
email: z.ZodString;
|
|
18
|
+
machine: z.ZodString;
|
|
19
|
+
requestedAt: z.ZodISODateTime;
|
|
20
|
+
signature: z.ZodString;
|
|
21
|
+
}, z.core.$strict>;
|
|
22
|
+
export type KeyRequestFile = z.infer<typeof keyRequestFileSchema>;
|
|
23
|
+
export declare const ACCESS_ACTIONS: readonly ["genesis", "approve", "remove", "grant-admin", "revoke-admin"];
|
|
24
|
+
export type AccessAction = (typeof ACCESS_ACTIONS)[number];
|
|
25
|
+
/** `authority` is the genesis entry's own field: present exactly when `action === 'genesis'`. */
|
|
26
|
+
export declare const accessEntryFileSchema: z.ZodObject<{
|
|
27
|
+
version: z.ZodLiteral<1>;
|
|
28
|
+
id: z.ZodString;
|
|
29
|
+
action: z.ZodEnum<{
|
|
30
|
+
remove: "remove";
|
|
31
|
+
genesis: "genesis";
|
|
32
|
+
approve: "approve";
|
|
33
|
+
"grant-admin": "grant-admin";
|
|
34
|
+
"revoke-admin": "revoke-admin";
|
|
35
|
+
}>;
|
|
36
|
+
authority: z.ZodOptional<z.ZodEnum<{
|
|
37
|
+
server: "server";
|
|
38
|
+
signed: "signed";
|
|
39
|
+
}>>;
|
|
40
|
+
key: z.ZodString;
|
|
41
|
+
by: z.ZodString;
|
|
42
|
+
at: z.ZodISODateTime;
|
|
43
|
+
signature: z.ZodString;
|
|
44
|
+
}, z.core.$strict>;
|
|
45
|
+
export type AccessEntryFile = z.infer<typeof accessEntryFileSchema>;
|
|
46
|
+
/** Which secret an entry holds: a keychain ref as the tree names it, or a `${secret:name}` token of one project. */
|
|
47
|
+
export declare const secretKeySchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
48
|
+
ref: z.ZodString;
|
|
49
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
50
|
+
token: z.ZodObject<{
|
|
51
|
+
projectId: z.ZodString;
|
|
52
|
+
name: z.ZodString;
|
|
53
|
+
}, z.core.$strict>;
|
|
54
|
+
}, z.core.$strict>]>;
|
|
55
|
+
export type SecretKey = z.infer<typeof secretKeySchema>;
|
|
56
|
+
export declare const vaultEntryFileSchema: z.ZodObject<{
|
|
57
|
+
version: z.ZodLiteral<1>;
|
|
58
|
+
secret: z.ZodUnion<readonly [z.ZodObject<{
|
|
59
|
+
ref: z.ZodString;
|
|
60
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
61
|
+
token: z.ZodObject<{
|
|
62
|
+
projectId: z.ZodString;
|
|
63
|
+
name: z.ZodString;
|
|
64
|
+
}, z.core.$strict>;
|
|
65
|
+
}, z.core.$strict>]>;
|
|
66
|
+
label: z.ZodString;
|
|
67
|
+
cipher: z.ZodString;
|
|
68
|
+
wraps: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
69
|
+
updatedAt: z.ZodISODateTime;
|
|
70
|
+
updatedBy: z.ZodString;
|
|
71
|
+
signature: z.ZodString;
|
|
72
|
+
}, z.core.$strict>;
|
|
73
|
+
export type VaultEntryFile = z.infer<typeof vaultEntryFileSchema>;
|
|
74
|
+
export declare const TEAM_SECRETS_KEYS_DIR = "team-secrets/keys";
|
|
75
|
+
export declare const TEAM_SECRETS_ACCESS_DIR = "team-secrets/access";
|
|
76
|
+
export declare const TEAM_SECRETS_VALUES_DIR = "team-secrets/values";
|
|
77
|
+
export declare function keyRequestPath(keyId: string): string;
|
|
78
|
+
export declare function accessEntryPath(id: string): string;
|
|
79
|
+
export declare function vaultEntryPath(id: string): string;
|
|
80
|
+
export declare function isTeamSecretsPath(path: string): boolean;
|
|
81
|
+
export declare function isVaultEntryPath(path: string): boolean;
|
|
82
|
+
export declare function vaultEntryIdOfPath(path: string): string | undefined;
|
|
83
|
+
/** Plan decision 3: base32 of SHA-256 over `ref:<ref>` or `token:<projectId>\n<name>`, first 26 characters. */
|
|
84
|
+
export declare function vaultEntryId(secret: SecretKey): string;
|
|
85
|
+
export declare function sameSecret(a: SecretKey, b: SecretKey): boolean;
|
|
86
|
+
export declare function teamSecretsFileText(doc: object): string;
|
|
87
|
+
export declare function parseTeamSecretsFile<S extends z.ZodType>(schema: S, text: string): z.infer<S> | undefined;
|
|
88
|
+
/** Everything under `team-secrets/`, parsed. `values` is keyed by the file's id. */
|
|
89
|
+
export interface TeamSecretsFiles {
|
|
90
|
+
readonly keys: KeyRequestFile[];
|
|
91
|
+
readonly access: AccessEntryFile[];
|
|
92
|
+
readonly values: Map<string, VaultEntryFile>;
|
|
93
|
+
/** Tree paths that are malformed, or whose name is not their id. */
|
|
94
|
+
readonly invalid: string[];
|
|
95
|
+
}
|
|
96
|
+
/** Parses the tree's team-secrets files, given as tree path → text. Other paths are ignored. */
|
|
97
|
+
export declare function readTeamSecretsFiles(files: ReadonlyMap<string, string>): TeamSecretsFiles;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three kinds of file under `team-secrets/` (§4): key requests, access-log entries and vault entries,
|
|
3
|
+
* one YAML document each, written by the engine's serializer. Binary fields are base64url without padding.
|
|
4
|
+
* Parsing never throws: a malformed or misnamed file is listed in `invalid` and otherwise ignored.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { parseYaml, stringifyYaml } from '../project/yaml.js';
|
|
9
|
+
import { SECRET_NAME_PATTERN } from '../secrets/secret-token.js';
|
|
10
|
+
import { TEAM_SECRETS_DIR } from '../workspace/paths.js';
|
|
11
|
+
import { base32, KEY_ID_PATTERN } from './keys.js';
|
|
12
|
+
export const TEAM_SECRETS_FORMAT_VERSION = 1;
|
|
13
|
+
/**
|
|
14
|
+
* A Crockford-base32 ULID, as `ulidx` writes it. The first character is restricted to `0`-`7`: a ULID's
|
|
15
|
+
* 48-bit timestamp fills at most that much of the first base32 group, so a wider first character (a
|
|
16
|
+
* corrupted or adversarial id) would decode to a timestamp `ulidx`'s `decodeTime` rejects outright — this
|
|
17
|
+
* pattern keeps that failure at parse time instead of wherever `decodeTime` is next called.
|
|
18
|
+
*/
|
|
19
|
+
export const ULID_PATTERN = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
20
|
+
const base64urlSchema = z.string().regex(/^[A-Za-z0-9_-]+$/);
|
|
21
|
+
/** 32 bytes as base64url without padding. */
|
|
22
|
+
const publicKeySchema = z.string().regex(/^[A-Za-z0-9_-]{43}$/);
|
|
23
|
+
/** An Ed25519 signature: 64 bytes as base64url without padding, always exactly 86 characters. */
|
|
24
|
+
const signatureSchema = z.string().regex(/^[A-Za-z0-9_-]{86}$/);
|
|
25
|
+
const isoSchema = z.iso.datetime({ offset: true });
|
|
26
|
+
export const keyIdSchema = z.string().regex(KEY_ID_PATTERN);
|
|
27
|
+
export const keyRequestFileSchema = z.strictObject({
|
|
28
|
+
version: z.literal(TEAM_SECRETS_FORMAT_VERSION),
|
|
29
|
+
keyId: keyIdSchema,
|
|
30
|
+
encryptionKey: publicKeySchema,
|
|
31
|
+
signingKey: publicKeySchema,
|
|
32
|
+
name: z.string().min(1).max(200),
|
|
33
|
+
email: z.string().max(320),
|
|
34
|
+
machine: z.string().min(1).max(200),
|
|
35
|
+
requestedAt: isoSchema,
|
|
36
|
+
signature: signatureSchema,
|
|
37
|
+
});
|
|
38
|
+
export const ACCESS_ACTIONS = ['genesis', 'approve', 'remove', 'grant-admin', 'revoke-admin'];
|
|
39
|
+
/** `authority` is the genesis entry's own field: present exactly when `action === 'genesis'`. */
|
|
40
|
+
export const accessEntryFileSchema = z
|
|
41
|
+
.strictObject({
|
|
42
|
+
version: z.literal(TEAM_SECRETS_FORMAT_VERSION),
|
|
43
|
+
id: z.string().regex(ULID_PATTERN),
|
|
44
|
+
action: z.enum(ACCESS_ACTIONS),
|
|
45
|
+
authority: z.enum(['signed', 'server']).optional(),
|
|
46
|
+
key: keyIdSchema,
|
|
47
|
+
by: keyIdSchema,
|
|
48
|
+
at: isoSchema,
|
|
49
|
+
signature: signatureSchema,
|
|
50
|
+
})
|
|
51
|
+
.refine((entry) => (entry.action === 'genesis') === (entry.authority !== undefined), {
|
|
52
|
+
message: 'authority is required on a genesis entry and forbidden on any other action',
|
|
53
|
+
});
|
|
54
|
+
/** Which secret an entry holds: a keychain ref as the tree names it, or a `${secret:name}` token of one project. */
|
|
55
|
+
export const secretKeySchema = z.union([
|
|
56
|
+
z.strictObject({ ref: z.string().min(1).max(200) }),
|
|
57
|
+
z.strictObject({
|
|
58
|
+
token: z.strictObject({ projectId: z.string().min(1).max(200), name: z.string().regex(SECRET_NAME_PATTERN) }),
|
|
59
|
+
}),
|
|
60
|
+
]);
|
|
61
|
+
export const vaultEntryFileSchema = z.strictObject({
|
|
62
|
+
version: z.literal(TEAM_SECRETS_FORMAT_VERSION),
|
|
63
|
+
secret: secretKeySchema,
|
|
64
|
+
/** The display label, never the value. */
|
|
65
|
+
label: z.string().max(200),
|
|
66
|
+
cipher: base64urlSchema,
|
|
67
|
+
wraps: z.record(keyIdSchema, base64urlSchema),
|
|
68
|
+
/** When the value was last set; rewraps keep it (plan decision 5). */
|
|
69
|
+
updatedAt: isoSchema,
|
|
70
|
+
/** The key that signed this version. */
|
|
71
|
+
updatedBy: keyIdSchema,
|
|
72
|
+
signature: signatureSchema,
|
|
73
|
+
});
|
|
74
|
+
export const TEAM_SECRETS_KEYS_DIR = `${TEAM_SECRETS_DIR}/keys`;
|
|
75
|
+
export const TEAM_SECRETS_ACCESS_DIR = `${TEAM_SECRETS_DIR}/access`;
|
|
76
|
+
export const TEAM_SECRETS_VALUES_DIR = `${TEAM_SECRETS_DIR}/values`;
|
|
77
|
+
export function keyRequestPath(keyId) {
|
|
78
|
+
return `${TEAM_SECRETS_KEYS_DIR}/${keyId}.yaml`;
|
|
79
|
+
}
|
|
80
|
+
export function accessEntryPath(id) {
|
|
81
|
+
return `${TEAM_SECRETS_ACCESS_DIR}/${id}.yaml`;
|
|
82
|
+
}
|
|
83
|
+
export function vaultEntryPath(id) {
|
|
84
|
+
return `${TEAM_SECRETS_VALUES_DIR}/${id}.yaml`;
|
|
85
|
+
}
|
|
86
|
+
const TEAM_SECRETS_FILE = new RegExp(`^${TEAM_SECRETS_DIR}/(keys|access|values)/([0-9A-Z]{26})\\.yaml$`);
|
|
87
|
+
export function isTeamSecretsPath(path) {
|
|
88
|
+
return TEAM_SECRETS_FILE.test(path);
|
|
89
|
+
}
|
|
90
|
+
export function isVaultEntryPath(path) {
|
|
91
|
+
return TEAM_SECRETS_FILE.exec(path)?.[1] === 'values';
|
|
92
|
+
}
|
|
93
|
+
export function vaultEntryIdOfPath(path) {
|
|
94
|
+
const match = TEAM_SECRETS_FILE.exec(path);
|
|
95
|
+
return match?.[1] === 'values' ? match[2] : undefined;
|
|
96
|
+
}
|
|
97
|
+
/** Plan decision 3: base32 of SHA-256 over `ref:<ref>` or `token:<projectId>\n<name>`, first 26 characters. */
|
|
98
|
+
export function vaultEntryId(secret) {
|
|
99
|
+
const text = 'ref' in secret ? `ref:${secret.ref}` : `token:${secret.token.projectId}\n${secret.token.name}`;
|
|
100
|
+
return base32(createHash('sha256').update(text, 'utf8').digest()).slice(0, 26);
|
|
101
|
+
}
|
|
102
|
+
export function sameSecret(a, b) {
|
|
103
|
+
return vaultEntryId(a) === vaultEntryId(b);
|
|
104
|
+
}
|
|
105
|
+
export function teamSecretsFileText(doc) {
|
|
106
|
+
return stringifyYaml(doc);
|
|
107
|
+
}
|
|
108
|
+
export function parseTeamSecretsFile(schema, text) {
|
|
109
|
+
let parsed;
|
|
110
|
+
try {
|
|
111
|
+
parsed = parseYaml(text, 'team-secrets');
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const result = schema.safeParse(parsed);
|
|
117
|
+
return result.success ? result.data : undefined;
|
|
118
|
+
}
|
|
119
|
+
/** Parses the tree's team-secrets files, given as tree path → text. Other paths are ignored. */
|
|
120
|
+
export function readTeamSecretsFiles(files) {
|
|
121
|
+
const out = { keys: [], access: [], values: new Map(), invalid: [] };
|
|
122
|
+
for (const [path, text] of files) {
|
|
123
|
+
const match = TEAM_SECRETS_FILE.exec(path);
|
|
124
|
+
if (match === null) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const [, kind, name] = match;
|
|
128
|
+
if (kind === 'keys') {
|
|
129
|
+
const doc = parseTeamSecretsFile(keyRequestFileSchema, text);
|
|
130
|
+
if (doc !== undefined && doc.keyId === name) {
|
|
131
|
+
out.keys.push(doc);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
out.invalid.push(path);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (kind === 'access') {
|
|
138
|
+
const doc = parseTeamSecretsFile(accessEntryFileSchema, text);
|
|
139
|
+
if (doc !== undefined && doc.id === name) {
|
|
140
|
+
out.access.push(doc);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
out.invalid.push(path);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
const doc = parseTeamSecretsFile(vaultEntryFileSchema, text);
|
|
148
|
+
if (doc !== undefined && name !== undefined && vaultEntryId(doc.secret) === name) {
|
|
149
|
+
out.values.set(name, doc);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
out.invalid.push(path);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type MachineKeys } from './keys.js';
|
|
2
|
+
export type Signed<T> = T & {
|
|
3
|
+
readonly signature: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Canonical JSON of `value`: object keys sorted at every depth, no whitespace, `undefined` values (object
|
|
7
|
+
* fields only, never array elements) dropped. Only JSON's own shapes are accepted — `null`, booleans,
|
|
8
|
+
* strings, finite numbers, arrays, and plain objects (prototype `Object.prototype` or `null`) — so a
|
|
9
|
+
* `Date`, `Map`, `Set`, class instance, function, symbol, `NaN` or `±Infinity` throws rather than silently
|
|
10
|
+
* signing something that would not round-trip through YAML the same way twice. `-0` is written as `0`
|
|
11
|
+
* (`JSON.stringify` already does this, and YAML has no distinct negative zero), which is deliberate, not
|
|
12
|
+
* an oversight.
|
|
13
|
+
*
|
|
14
|
+
* @throws WirebenchError `team-secrets-not-canonical`
|
|
15
|
+
*/
|
|
16
|
+
export declare function canonicalJson(value: unknown): string;
|
|
17
|
+
/** A shallow copy of `doc` without its `signature` field. */
|
|
18
|
+
export declare function withoutSignature(doc: object): Record<string, unknown>;
|
|
19
|
+
/** `doc` with a fresh `signature` by `keys`; an existing signature is replaced. */
|
|
20
|
+
export declare function signDocument<T extends object>(doc: T, keys: MachineKeys): Signed<T>;
|
|
21
|
+
/** Whether `doc.signature` is `signingKey`'s signature over the rest of `doc`. Never throws. */
|
|
22
|
+
export declare function verifyDocument<T extends {
|
|
23
|
+
readonly signature: string;
|
|
24
|
+
}>(doc: T, signingKey: string): boolean;
|