@blamejs/blamejs-shop 0.0.44
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/CHANGELOG.md +87 -0
- package/LICENSE +17 -0
- package/README.md +117 -0
- package/SECURITY.md +139 -0
- package/lib/admin.js +952 -0
- package/lib/analytics.js +267 -0
- package/lib/cart.js +279 -0
- package/lib/catalog-import.js +344 -0
- package/lib/catalog.js +769 -0
- package/lib/checkout.js +320 -0
- package/lib/config.js +151 -0
- package/lib/customers.js +322 -0
- package/lib/email.js +242 -0
- package/lib/externaldb-d1.js +283 -0
- package/lib/index.js +57 -0
- package/lib/inventory-alerts.js +198 -0
- package/lib/newsletter.js +142 -0
- package/lib/order.js +380 -0
- package/lib/payment.js +318 -0
- package/lib/pricing.js +185 -0
- package/lib/r2-bridge.js +169 -0
- package/lib/shipping.js +185 -0
- package/lib/storefront.js +2160 -0
- package/lib/subscriptions.js +410 -0
- package/lib/tax.js +161 -0
- package/lib/theme.js +194 -0
- package/lib/vendor/MANIFEST.json +19 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +23 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +34 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/project.yaml +16 -0
- package/lib/vendor/blamejs/.dockerignore +45 -0
- package/lib/vendor/blamejs/.gitattributes +42 -0
- package/lib/vendor/blamejs/.github/CODEOWNERS +4 -0
- package/lib/vendor/blamejs/.github/FUNDING.yml +2 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/bug_report.md +58 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/feature_request.md +99 -0
- package/lib/vendor/blamejs/.github/PULL_REQUEST_TEMPLATE.md +77 -0
- package/lib/vendor/blamejs/.github/dependabot.yml +37 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +148 -0
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +107 -0
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +122 -0
- package/lib/vendor/blamejs/.github/workflows/ci.yml +511 -0
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +50 -0
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +655 -0
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +406 -0
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +101 -0
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +134 -0
- package/lib/vendor/blamejs/.gitignore +102 -0
- package/lib/vendor/blamejs/.gitleaks.toml +166 -0
- package/lib/vendor/blamejs/.hadolint.yaml +18 -0
- package/lib/vendor/blamejs/.npmrc +5 -0
- package/lib/vendor/blamejs/.pinact.yaml +17 -0
- package/lib/vendor/blamejs/ARCHITECTURE.md +158 -0
- package/lib/vendor/blamejs/CHANGELOG.md +1351 -0
- package/lib/vendor/blamejs/CODE_OF_CONDUCT.md +86 -0
- package/lib/vendor/blamejs/CONTRIBUTING.md +156 -0
- package/lib/vendor/blamejs/GOVERNANCE.md +201 -0
- package/lib/vendor/blamejs/LICENSE +201 -0
- package/lib/vendor/blamejs/LTS-CALENDAR.md +29 -0
- package/lib/vendor/blamejs/MIGRATING.md +29 -0
- package/lib/vendor/blamejs/NOTICE +81 -0
- package/lib/vendor/blamejs/README.md +304 -0
- package/lib/vendor/blamejs/SECURITY.md +432 -0
- package/lib/vendor/blamejs/api-snapshot.json +48709 -0
- package/lib/vendor/blamejs/assets/BlameJS_Logo.png +0 -0
- package/lib/vendor/blamejs/assets/BlameJS_Logo.svg +129 -0
- package/lib/vendor/blamejs/bench/README.md +77 -0
- package/lib/vendor/blamejs/bench/_helpers.js +70 -0
- package/lib/vendor/blamejs/bench/baseline.json +183 -0
- package/lib/vendor/blamejs/bench/crypto-hash.bench.js +19 -0
- package/lib/vendor/blamejs/bench/crypto-symmetric.bench.js +28 -0
- package/lib/vendor/blamejs/bench/run.js +140 -0
- package/lib/vendor/blamejs/bench/safe-json.bench.js +31 -0
- package/lib/vendor/blamejs/bin/blamejs.js +13 -0
- package/lib/vendor/blamejs/docker/caddy/Caddyfile +46 -0
- package/lib/vendor/blamejs/docker/coredns/Corefile +37 -0
- package/lib/vendor/blamejs/docker/haproxy/haproxy.cfg +52 -0
- package/lib/vendor/blamejs/docker/init/generate-certs.sh +118 -0
- package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +87 -0
- package/lib/vendor/blamejs/docker/mitmproxy/config.yaml +16 -0
- package/lib/vendor/blamejs/docker/mongo/init-tls.sh +17 -0
- package/lib/vendor/blamejs/docker/mysql/my.cnf +12 -0
- package/lib/vendor/blamejs/docker/nats/nats.conf +33 -0
- package/lib/vendor/blamejs/docker/postgres/init-tls.sh +17 -0
- package/lib/vendor/blamejs/docker/postgres/postgresql.conf +18 -0
- package/lib/vendor/blamejs/docker/rabbitmq/rabbitmq.conf +18 -0
- package/lib/vendor/blamejs/docker/redis/redis.conf +15 -0
- package/lib/vendor/blamejs/docker/squid/squid.conf +24 -0
- package/lib/vendor/blamejs/docker/syslog/syslog-ng.conf +34 -0
- package/lib/vendor/blamejs/docker-compose.test.yml +545 -0
- package/lib/vendor/blamejs/docs/cis-postgres-crosswalk.md +102 -0
- package/lib/vendor/blamejs/docs/cis-sqlite-equivalent.md +92 -0
- package/lib/vendor/blamejs/eslint.config.mjs +204 -0
- package/lib/vendor/blamejs/examples/wiki/Caddyfile +40 -0
- package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +218 -0
- package/lib/vendor/blamejs/examples/wiki/Dockerfile +120 -0
- package/lib/vendor/blamejs/examples/wiki/README.md +157 -0
- package/lib/vendor/blamejs/examples/wiki/cli-snapshot.json +250 -0
- package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +231 -0
- package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +166 -0
- package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +217 -0
- package/lib/vendor/blamejs/examples/wiki/lib/auto-site-entries.js +139 -0
- package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +555 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-cli.js +507 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-env-vars.js +435 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-errors.js +282 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-vendored-deps.js +321 -0
- package/lib/vendor/blamejs/examples/wiki/lib/nav.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/lib/opts-resolver.js +75 -0
- package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +508 -0
- package/lib/vendor/blamejs/examples/wiki/lib/section.js +276 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +587 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +318 -0
- package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +122 -0
- package/lib/vendor/blamejs/examples/wiki/migrations/0001-pages-schema.js +74 -0
- package/lib/vendor/blamejs/examples/wiki/package.json +18 -0
- package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.png +0 -0
- package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.svg +129 -0
- package/lib/vendor/blamejs/examples/wiki/public/robots.txt +5 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/MANIFEST.json +30 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.css +1 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/public/wiki.css +1250 -0
- package/lib/vendor/blamejs/examples/wiki/routes/admin.js +366 -0
- package/lib/vendor/blamejs/examples/wiki/routes/integration.js +230 -0
- package/lib/vendor/blamejs/examples/wiki/routes/pages.js +266 -0
- package/lib/vendor/blamejs/examples/wiki/scripts/backfill-module-metadata.js +214 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/0001-default-pages.js +35 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/_index.js +34 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/api.js +76 -0
- package/lib/vendor/blamejs/examples/wiki/server.js +129 -0
- package/lib/vendor/blamejs/examples/wiki/site.config.js +197 -0
- package/lib/vendor/blamejs/examples/wiki/snippets/README.md +38 -0
- package/lib/vendor/blamejs/examples/wiki/snippets/auth/password-hash.example.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/src/editor.js +103 -0
- package/lib/vendor/blamejs/examples/wiki/src/wiki.js +349 -0
- package/lib/vendor/blamejs/examples/wiki/test/AUDIT.md +155 -0
- package/lib/vendor/blamejs/examples/wiki/test/codebase-patterns.test.js +594 -0
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +741 -0
- package/lib/vendor/blamejs/examples/wiki/test/find-missing-pages.js +254 -0
- package/lib/vendor/blamejs/examples/wiki/test/integration.js +391 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-cli-snapshot.js +379 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-env-snapshot.js +346 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-nav-coverage.js +212 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-site-coverage.js +252 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-source-comment-blocks.js +107 -0
- package/lib/vendor/blamejs/examples/wiki/views/_layout.html +115 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/api-keys.html +51 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/dashboard.html +22 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/edit.html +17 -0
- package/lib/vendor/blamejs/examples/wiki/views/home.html +85 -0
- package/lib/vendor/blamejs/examples/wiki/views/login.html +18 -0
- package/lib/vendor/blamejs/examples/wiki/views/page.html +5 -0
- package/lib/vendor/blamejs/examples/wiki/views/partials/nav.html +13 -0
- package/lib/vendor/blamejs/examples/wiki/views/search.html +19 -0
- package/lib/vendor/blamejs/examples/wiki/wiki.config.js +15 -0
- package/lib/vendor/blamejs/fuzz/README.md +137 -0
- package/lib/vendor/blamejs/fuzz/_expected.js +35 -0
- package/lib/vendor/blamejs/fuzz/guard-agent-registry.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-csv.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/01-basic.csv +3 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/02-formula.csv +1 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/03-hyperlink.csv +1 -0
- package/lib/vendor/blamejs/fuzz/guard-dsn.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-email.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-email_seed_corpus/01-basic.eml +5 -0
- package/lib/vendor/blamejs/fuzz/guard-envelope.fuzz.js +24 -0
- package/lib/vendor/blamejs/fuzz/guard-event-bus-payload.fuzz.js +24 -0
- package/lib/vendor/blamejs/fuzz/guard-event-bus-topic.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-html.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/01-basic.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/02-script.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/03-event.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/04-jsurl.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-idempotency-key.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-imap-command.fuzz.js +35 -0
- package/lib/vendor/blamejs/fuzz/guard-jmap.fuzz.js +41 -0
- package/lib/vendor/blamejs/fuzz/guard-json.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/01-basic.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/02-proto.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/03-dupkey.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/04-nan.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/05-bom.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-list-id.fuzz.js +21 -0
- package/lib/vendor/blamejs/fuzz/guard-list-unsubscribe.fuzz.js +25 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-compose.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-move.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-query.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-reply.fuzz.js +23 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-sieve.fuzz.js +36 -0
- package/lib/vendor/blamejs/fuzz/guard-managesieve-command.fuzz.js +26 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/01-basic.md +2 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/02-jsurl.md +1 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/03-jsimg.md +1 -0
- package/lib/vendor/blamejs/fuzz/guard-message-id.fuzz.js +26 -0
- package/lib/vendor/blamejs/fuzz/guard-pop3-command.fuzz.js +23 -0
- package/lib/vendor/blamejs/fuzz/guard-posture-chain.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-saga-config.fuzz.js +32 -0
- package/lib/vendor/blamejs/fuzz/guard-smtp-command.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/guard-snapshot-envelope.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-stream-args.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-svg.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/01-basic.svg +1 -0
- package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/02-script.svg +1 -0
- package/lib/vendor/blamejs/fuzz/guard-tenant-id.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-trace-context.fuzz.js +30 -0
- package/lib/vendor/blamejs/fuzz/guard-xml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/01-basic.xml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/02-xxe.xml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/01-basic.yaml +2 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/02-anchor.yaml +2 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/03-norway.yaml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/04-multidoc.yaml +4 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-ini.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-ini_seed_corpus/01-basic.ini +2 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-toml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-toml_seed_corpus/01-basic.toml +4 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-xml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-xml_seed_corpus/01-basic.xml +1 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-yaml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-yaml_seed_corpus/01-basic.yaml +4 -0
- package/lib/vendor/blamejs/fuzz/safe-decompress.fuzz.js +49 -0
- package/lib/vendor/blamejs/fuzz/safe-dns.fuzz.js +29 -0
- package/lib/vendor/blamejs/fuzz/safe-ical.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-icap.fuzz.js +42 -0
- package/lib/vendor/blamejs/fuzz/safe-json.fuzz.js +25 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/01-object.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/02-array.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/03-string.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/04-proto.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/05-deep.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/01-basic.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/02-filter.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/03-deepscan.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/04-slice.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-mime.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/safe-mount-info.fuzz.js +33 -0
- package/lib/vendor/blamejs/fuzz/safe-sieve.fuzz.js +28 -0
- package/lib/vendor/blamejs/fuzz/safe-smtp.fuzz.js +64 -0
- package/lib/vendor/blamejs/fuzz/safe-url.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/01-basic.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/02-userinfo.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/03-dangerous.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/04-data.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/05-ipv6.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/06-idn.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-vcard.fuzz.js +16 -0
- package/lib/vendor/blamejs/index.js +678 -0
- package/lib/vendor/blamejs/keys/release-pqc-pub.json +7 -0
- package/lib/vendor/blamejs/lib/_test/crypto-fixtures.js +67 -0
- package/lib/vendor/blamejs/lib/a2a-tasks.js +598 -0
- package/lib/vendor/blamejs/lib/a2a.js +407 -0
- package/lib/vendor/blamejs/lib/acme.js +1448 -0
- package/lib/vendor/blamejs/lib/agent-audit.js +45 -0
- package/lib/vendor/blamejs/lib/agent-event-bus.js +382 -0
- package/lib/vendor/blamejs/lib/agent-idempotency.js +497 -0
- package/lib/vendor/blamejs/lib/agent-orchestrator.js +717 -0
- package/lib/vendor/blamejs/lib/agent-posture-chain.js +366 -0
- package/lib/vendor/blamejs/lib/agent-saga.js +321 -0
- package/lib/vendor/blamejs/lib/agent-snapshot.js +676 -0
- package/lib/vendor/blamejs/lib/agent-stream.js +269 -0
- package/lib/vendor/blamejs/lib/agent-tenant.js +632 -0
- package/lib/vendor/blamejs/lib/agent-trace.js +281 -0
- package/lib/vendor/blamejs/lib/ai-adverse-decision.js +184 -0
- package/lib/vendor/blamejs/lib/ai-content-detect.js +268 -0
- package/lib/vendor/blamejs/lib/ai-input.js +201 -0
- package/lib/vendor/blamejs/lib/ai-model-manifest.js +363 -0
- package/lib/vendor/blamejs/lib/ai-pref.js +340 -0
- package/lib/vendor/blamejs/lib/api-key.js +721 -0
- package/lib/vendor/blamejs/lib/api-snapshot.js +458 -0
- package/lib/vendor/blamejs/lib/app-shutdown.js +557 -0
- package/lib/vendor/blamejs/lib/app.js +365 -0
- package/lib/vendor/blamejs/lib/archive.js +547 -0
- package/lib/vendor/blamejs/lib/arg-parser.js +697 -0
- package/lib/vendor/blamejs/lib/argon2-builtin.js +173 -0
- package/lib/vendor/blamejs/lib/asn1-der.js +424 -0
- package/lib/vendor/blamejs/lib/asyncapi-bindings.js +160 -0
- package/lib/vendor/blamejs/lib/asyncapi-traits.js +143 -0
- package/lib/vendor/blamejs/lib/asyncapi.js +575 -0
- package/lib/vendor/blamejs/lib/atomic-file.js +1023 -0
- package/lib/vendor/blamejs/lib/audit-chain.js +266 -0
- package/lib/vendor/blamejs/lib/audit-daily-review.js +389 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +751 -0
- package/lib/vendor/blamejs/lib/audit-tools.js +1113 -0
- package/lib/vendor/blamejs/lib/audit.js +1671 -0
- package/lib/vendor/blamejs/lib/auth/aal.js +169 -0
- package/lib/vendor/blamejs/lib/auth/access-lock.js +220 -0
- package/lib/vendor/blamejs/lib/auth/acr-vocabulary.js +265 -0
- package/lib/vendor/blamejs/lib/auth/ato-kill-switch.js +112 -0
- package/lib/vendor/blamejs/lib/auth/auth-time-tracker.js +111 -0
- package/lib/vendor/blamejs/lib/auth/bot-challenge.js +573 -0
- package/lib/vendor/blamejs/lib/auth/ciba.js +637 -0
- package/lib/vendor/blamejs/lib/auth/dpop.js +516 -0
- package/lib/vendor/blamejs/lib/auth/elevation-grant.js +306 -0
- package/lib/vendor/blamejs/lib/auth/fal.js +229 -0
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +681 -0
- package/lib/vendor/blamejs/lib/auth/jwt-external.js +519 -0
- package/lib/vendor/blamejs/lib/auth/jwt.js +430 -0
- package/lib/vendor/blamejs/lib/auth/lockout.js +449 -0
- package/lib/vendor/blamejs/lib/auth/oauth.js +2141 -0
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +657 -0
- package/lib/vendor/blamejs/lib/auth/oid4vp.js +531 -0
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +600 -0
- package/lib/vendor/blamejs/lib/auth/passkey.js +676 -0
- package/lib/vendor/blamejs/lib/auth/password.js +693 -0
- package/lib/vendor/blamejs/lib/auth/saml.js +2109 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-disclosure.js +95 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +225 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +197 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +728 -0
- package/lib/vendor/blamejs/lib/auth/status-list.js +272 -0
- package/lib/vendor/blamejs/lib/auth/step-up-policy.js +335 -0
- package/lib/vendor/blamejs/lib/auth/step-up.js +454 -0
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +505 -0
- package/lib/vendor/blamejs/lib/auth-header.js +148 -0
- package/lib/vendor/blamejs/lib/backup/bundle.js +265 -0
- package/lib/vendor/blamejs/lib/backup/crypto.js +176 -0
- package/lib/vendor/blamejs/lib/backup/index.js +1001 -0
- package/lib/vendor/blamejs/lib/backup/manifest.js +443 -0
- package/lib/vendor/blamejs/lib/boot-gates.js +174 -0
- package/lib/vendor/blamejs/lib/breach-deadline.js +272 -0
- package/lib/vendor/blamejs/lib/break-glass.js +1753 -0
- package/lib/vendor/blamejs/lib/budr.js +205 -0
- package/lib/vendor/blamejs/lib/bundler.js +461 -0
- package/lib/vendor/blamejs/lib/cache-redis.js +256 -0
- package/lib/vendor/blamejs/lib/cache-status.js +288 -0
- package/lib/vendor/blamejs/lib/cache.js +1331 -0
- package/lib/vendor/blamejs/lib/calendar.js +1240 -0
- package/lib/vendor/blamejs/lib/canonical-json.js +143 -0
- package/lib/vendor/blamejs/lib/cdn-cache-control.js +473 -0
- package/lib/vendor/blamejs/lib/cert.js +763 -0
- package/lib/vendor/blamejs/lib/chain-writer.js +259 -0
- package/lib/vendor/blamejs/lib/circuit-breaker.js +101 -0
- package/lib/vendor/blamejs/lib/cli-helpers.js +237 -0
- package/lib/vendor/blamejs/lib/cli.js +2328 -0
- package/lib/vendor/blamejs/lib/client-hints.js +318 -0
- package/lib/vendor/blamejs/lib/cloud-events.js +277 -0
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +317 -0
- package/lib/vendor/blamejs/lib/cluster-storage.js +351 -0
- package/lib/vendor/blamejs/lib/cluster.js +1017 -0
- package/lib/vendor/blamejs/lib/cms-codec.js +826 -0
- package/lib/vendor/blamejs/lib/codepoint-class.js +262 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +190 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +205 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-risk.js +189 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +200 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act.js +821 -0
- package/lib/vendor/blamejs/lib/compliance-eaa.js +204 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-aliases.js +167 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +206 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-fuzzy.js +297 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions.js +569 -0
- package/lib/vendor/blamejs/lib/compliance.js +1558 -0
- package/lib/vendor/blamejs/lib/config-drift.js +426 -0
- package/lib/vendor/blamejs/lib/config.js +446 -0
- package/lib/vendor/blamejs/lib/consent.js +369 -0
- package/lib/vendor/blamejs/lib/constants.js +209 -0
- package/lib/vendor/blamejs/lib/content-credentials.js +704 -0
- package/lib/vendor/blamejs/lib/cookies.js +560 -0
- package/lib/vendor/blamejs/lib/cra-report.js +299 -0
- package/lib/vendor/blamejs/lib/credential-hash.js +394 -0
- package/lib/vendor/blamejs/lib/crypto-field.js +1017 -0
- package/lib/vendor/blamejs/lib/crypto-hpke-pq.js +187 -0
- package/lib/vendor/blamejs/lib/crypto-hpke.js +256 -0
- package/lib/vendor/blamejs/lib/crypto.js +1908 -0
- package/lib/vendor/blamejs/lib/csp.js +271 -0
- package/lib/vendor/blamejs/lib/csv.js +418 -0
- package/lib/vendor/blamejs/lib/daemon.js +481 -0
- package/lib/vendor/blamejs/lib/dark-patterns.js +488 -0
- package/lib/vendor/blamejs/lib/data-act.js +328 -0
- package/lib/vendor/blamejs/lib/db-collection.js +587 -0
- package/lib/vendor/blamejs/lib/db-declare-row-policy.js +267 -0
- package/lib/vendor/blamejs/lib/db-declare-view.js +420 -0
- package/lib/vendor/blamejs/lib/db-file-lifecycle.js +333 -0
- package/lib/vendor/blamejs/lib/db-query.js +802 -0
- package/lib/vendor/blamejs/lib/db-role-context.js +50 -0
- package/lib/vendor/blamejs/lib/db-schema.js +322 -0
- package/lib/vendor/blamejs/lib/db.js +3111 -0
- package/lib/vendor/blamejs/lib/dbsc.js +299 -0
- package/lib/vendor/blamejs/lib/ddl-change-control.js +523 -0
- package/lib/vendor/blamejs/lib/deprecate.js +377 -0
- package/lib/vendor/blamejs/lib/dev.js +405 -0
- package/lib/vendor/blamejs/lib/dora.js +402 -0
- package/lib/vendor/blamejs/lib/dr-runbook.js +368 -0
- package/lib/vendor/blamejs/lib/dsr.js +1188 -0
- package/lib/vendor/blamejs/lib/dual-control.js +526 -0
- package/lib/vendor/blamejs/lib/early-hints.js +212 -0
- package/lib/vendor/blamejs/lib/error-page.js +420 -0
- package/lib/vendor/blamejs/lib/events.js +214 -0
- package/lib/vendor/blamejs/lib/external-db-migrate.js +659 -0
- package/lib/vendor/blamejs/lib/external-db.js +1877 -0
- package/lib/vendor/blamejs/lib/fapi2.js +394 -0
- package/lib/vendor/blamejs/lib/fda-21cfr11.js +395 -0
- package/lib/vendor/blamejs/lib/fdx.js +370 -0
- package/lib/vendor/blamejs/lib/fedcm.js +264 -0
- package/lib/vendor/blamejs/lib/file-type.js +360 -0
- package/lib/vendor/blamejs/lib/file-upload.js +1256 -0
- package/lib/vendor/blamejs/lib/flag-cache.js +136 -0
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +135 -0
- package/lib/vendor/blamejs/lib/flag-providers.js +279 -0
- package/lib/vendor/blamejs/lib/flag-targeting.js +210 -0
- package/lib/vendor/blamejs/lib/flag.js +346 -0
- package/lib/vendor/blamejs/lib/forms.js +525 -0
- package/lib/vendor/blamejs/lib/framework-error.js +724 -0
- package/lib/vendor/blamejs/lib/framework-schema.js +845 -0
- package/lib/vendor/blamejs/lib/framework-sha1-hibp.js +34 -0
- package/lib/vendor/blamejs/lib/fsm.js +469 -0
- package/lib/vendor/blamejs/lib/gate-contract.js +1661 -0
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +261 -0
- package/lib/vendor/blamejs/lib/graphql-federation.js +234 -0
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +179 -0
- package/lib/vendor/blamejs/lib/guard-all.js +555 -0
- package/lib/vendor/blamejs/lib/guard-archive.js +901 -0
- package/lib/vendor/blamejs/lib/guard-auth.js +451 -0
- package/lib/vendor/blamejs/lib/guard-cidr.js +676 -0
- package/lib/vendor/blamejs/lib/guard-csv.js +1176 -0
- package/lib/vendor/blamejs/lib/guard-domain.js +814 -0
- package/lib/vendor/blamejs/lib/guard-dsn.js +382 -0
- package/lib/vendor/blamejs/lib/guard-email.js +951 -0
- package/lib/vendor/blamejs/lib/guard-envelope.js +294 -0
- package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +217 -0
- package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +150 -0
- package/lib/vendor/blamejs/lib/guard-filename.js +956 -0
- package/lib/vendor/blamejs/lib/guard-graphql.js +731 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-aria.js +164 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-forms.js +144 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-tables.js +154 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-tagwalk.js +44 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag.js +470 -0
- package/lib/vendor/blamejs/lib/guard-html.js +1209 -0
- package/lib/vendor/blamejs/lib/guard-idempotency-key.js +151 -0
- package/lib/vendor/blamejs/lib/guard-image.js +584 -0
- package/lib/vendor/blamejs/lib/guard-imap-command.js +337 -0
- package/lib/vendor/blamejs/lib/guard-jmap.js +321 -0
- package/lib/vendor/blamejs/lib/guard-json.js +935 -0
- package/lib/vendor/blamejs/lib/guard-jsonpath.js +512 -0
- package/lib/vendor/blamejs/lib/guard-jwt.js +772 -0
- package/lib/vendor/blamejs/lib/guard-list-id.js +318 -0
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +412 -0
- package/lib/vendor/blamejs/lib/guard-mail-compose.js +282 -0
- package/lib/vendor/blamejs/lib/guard-mail-move.js +202 -0
- package/lib/vendor/blamejs/lib/guard-mail-query.js +310 -0
- package/lib/vendor/blamejs/lib/guard-mail-reply.js +172 -0
- package/lib/vendor/blamejs/lib/guard-mail-sieve.js +207 -0
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +566 -0
- package/lib/vendor/blamejs/lib/guard-markdown.js +768 -0
- package/lib/vendor/blamejs/lib/guard-message-id.js +267 -0
- package/lib/vendor/blamejs/lib/guard-mime.js +609 -0
- package/lib/vendor/blamejs/lib/guard-oauth.js +650 -0
- package/lib/vendor/blamejs/lib/guard-pdf.js +569 -0
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +317 -0
- package/lib/vendor/blamejs/lib/guard-posture-chain.js +201 -0
- package/lib/vendor/blamejs/lib/guard-regex.js +632 -0
- package/lib/vendor/blamejs/lib/guard-saga-config.js +157 -0
- package/lib/vendor/blamejs/lib/guard-shell.js +522 -0
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +594 -0
- package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +168 -0
- package/lib/vendor/blamejs/lib/guard-stream-args.js +166 -0
- package/lib/vendor/blamejs/lib/guard-svg.js +1163 -0
- package/lib/vendor/blamejs/lib/guard-template.js +490 -0
- package/lib/vendor/blamejs/lib/guard-tenant-id.js +138 -0
- package/lib/vendor/blamejs/lib/guard-time.js +586 -0
- package/lib/vendor/blamejs/lib/guard-trace-context.js +172 -0
- package/lib/vendor/blamejs/lib/guard-uuid.js +548 -0
- package/lib/vendor/blamejs/lib/guard-xml.js +666 -0
- package/lib/vendor/blamejs/lib/guard-yaml.js +726 -0
- package/lib/vendor/blamejs/lib/hal.js +125 -0
- package/lib/vendor/blamejs/lib/handlers.js +350 -0
- package/lib/vendor/blamejs/lib/honeytoken.js +168 -0
- package/lib/vendor/blamejs/lib/html-balance.js +347 -0
- package/lib/vendor/blamejs/lib/http-client-cache.js +923 -0
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +519 -0
- package/lib/vendor/blamejs/lib/http-client.js +2152 -0
- package/lib/vendor/blamejs/lib/http-message-signature.js +589 -0
- package/lib/vendor/blamejs/lib/http2-teardown.js +34 -0
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +398 -0
- package/lib/vendor/blamejs/lib/i18n.js +931 -0
- package/lib/vendor/blamejs/lib/iab-mspa.js +257 -0
- package/lib/vendor/blamejs/lib/iab-tcf.js +461 -0
- package/lib/vendor/blamejs/lib/importmap-integrity.js +90 -0
- package/lib/vendor/blamejs/lib/inbox.js +435 -0
- package/lib/vendor/blamejs/lib/incident-report.js +314 -0
- package/lib/vendor/blamejs/lib/ip-utils.js +102 -0
- package/lib/vendor/blamejs/lib/jobs.js +185 -0
- package/lib/vendor/blamejs/lib/jose-jwe-experimental.js +228 -0
- package/lib/vendor/blamejs/lib/jsonapi.js +230 -0
- package/lib/vendor/blamejs/lib/keychain.js +865 -0
- package/lib/vendor/blamejs/lib/lazy-require.js +48 -0
- package/lib/vendor/blamejs/lib/legal-hold.js +374 -0
- package/lib/vendor/blamejs/lib/local-db-thin.js +321 -0
- package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +369 -0
- package/lib/vendor/blamejs/lib/log-stream-local.js +146 -0
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +410 -0
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +286 -0
- package/lib/vendor/blamejs/lib/log-stream-syslog.js +310 -0
- package/lib/vendor/blamejs/lib/log-stream-webhook.js +199 -0
- package/lib/vendor/blamejs/lib/log-stream.js +584 -0
- package/lib/vendor/blamejs/lib/log.js +625 -0
- package/lib/vendor/blamejs/lib/lro.js +200 -0
- package/lib/vendor/blamejs/lib/mail-agent.js +786 -0
- package/lib/vendor/blamejs/lib/mail-arc-sign.js +417 -0
- package/lib/vendor/blamejs/lib/mail-arf.js +343 -0
- package/lib/vendor/blamejs/lib/mail-auth.js +2144 -0
- package/lib/vendor/blamejs/lib/mail-bimi.js +1047 -0
- package/lib/vendor/blamejs/lib/mail-bounce.js +955 -0
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +1286 -0
- package/lib/vendor/blamejs/lib/mail-crypto-smime.js +789 -0
- package/lib/vendor/blamejs/lib/mail-crypto.js +108 -0
- package/lib/vendor/blamejs/lib/mail-dav.js +1224 -0
- package/lib/vendor/blamejs/lib/mail-deploy.js +1119 -0
- package/lib/vendor/blamejs/lib/mail-dkim.js +1250 -0
- package/lib/vendor/blamejs/lib/mail-greylist.js +448 -0
- package/lib/vendor/blamejs/lib/mail-helo.js +473 -0
- package/lib/vendor/blamejs/lib/mail-journal.js +435 -0
- package/lib/vendor/blamejs/lib/mail-mdn.js +424 -0
- package/lib/vendor/blamejs/lib/mail-rbl.js +392 -0
- package/lib/vendor/blamejs/lib/mail-require-tls.js +198 -0
- package/lib/vendor/blamejs/lib/mail-scan.js +502 -0
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +629 -0
- package/lib/vendor/blamejs/lib/mail-server-imap.js +1858 -0
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +1565 -0
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +908 -0
- package/lib/vendor/blamejs/lib/mail-server-mx.js +969 -0
- package/lib/vendor/blamejs/lib/mail-server-pop3.js +915 -0
- package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +315 -0
- package/lib/vendor/blamejs/lib/mail-server-registry.js +378 -0
- package/lib/vendor/blamejs/lib/mail-server-submission.js +1396 -0
- package/lib/vendor/blamejs/lib/mail-server-tls.js +445 -0
- package/lib/vendor/blamejs/lib/mail-sieve.js +557 -0
- package/lib/vendor/blamejs/lib/mail-spam-score.js +284 -0
- package/lib/vendor/blamejs/lib/mail-srs.js +248 -0
- package/lib/vendor/blamejs/lib/mail-store-fts.js +394 -0
- package/lib/vendor/blamejs/lib/mail-store.js +929 -0
- package/lib/vendor/blamejs/lib/mail-unsubscribe.js +400 -0
- package/lib/vendor/blamejs/lib/mail.js +1971 -0
- package/lib/vendor/blamejs/lib/mcp-tool-registry.js +473 -0
- package/lib/vendor/blamejs/lib/mcp.js +950 -0
- package/lib/vendor/blamejs/lib/metrics.js +1503 -0
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +177 -0
- package/lib/vendor/blamejs/lib/middleware/ai-act-disclosure.js +203 -0
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +981 -0
- package/lib/vendor/blamejs/lib/middleware/assetlinks.js +137 -0
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +171 -0
- package/lib/vendor/blamejs/lib/middleware/attach-user.js +220 -0
- package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +293 -0
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +1519 -0
- package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +183 -0
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +217 -0
- package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +122 -0
- package/lib/vendor/blamejs/lib/middleware/compose-pipeline.js +355 -0
- package/lib/vendor/blamejs/lib/middleware/compression.js +489 -0
- package/lib/vendor/blamejs/lib/middleware/cookies.js +130 -0
- package/lib/vendor/blamejs/lib/middleware/cors.js +386 -0
- package/lib/vendor/blamejs/lib/middleware/csp-nonce.js +388 -0
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +167 -0
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +499 -0
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +243 -0
- package/lib/vendor/blamejs/lib/middleware/db-role-for.js +304 -0
- package/lib/vendor/blamejs/lib/middleware/dpop.js +402 -0
- package/lib/vendor/blamejs/lib/middleware/error-handler.js +69 -0
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +168 -0
- package/lib/vendor/blamejs/lib/middleware/flag-context.js +110 -0
- package/lib/vendor/blamejs/lib/middleware/gpc.js +153 -0
- package/lib/vendor/blamejs/lib/middleware/headers.js +242 -0
- package/lib/vendor/blamejs/lib/middleware/health.js +438 -0
- package/lib/vendor/blamejs/lib/middleware/host-allowlist.js +189 -0
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +964 -0
- package/lib/vendor/blamejs/lib/middleware/index.js +183 -0
- package/lib/vendor/blamejs/lib/middleware/nel.js +214 -0
- package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +237 -0
- package/lib/vendor/blamejs/lib/middleware/no-cache.js +106 -0
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +177 -0
- package/lib/vendor/blamejs/lib/middleware/protected-resource-metadata.js +277 -0
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +556 -0
- package/lib/vendor/blamejs/lib/middleware/request-id.js +79 -0
- package/lib/vendor/blamejs/lib/middleware/request-log.js +205 -0
- package/lib/vendor/blamejs/lib/middleware/require-aal.js +138 -0
- package/lib/vendor/blamejs/lib/middleware/require-auth.js +144 -0
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +290 -0
- package/lib/vendor/blamejs/lib/middleware/require-content-type.js +113 -0
- package/lib/vendor/blamejs/lib/middleware/require-methods.js +97 -0
- package/lib/vendor/blamejs/lib/middleware/require-mtls.js +212 -0
- package/lib/vendor/blamejs/lib/middleware/require-step-up.js +226 -0
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +375 -0
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +285 -0
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +170 -0
- package/lib/vendor/blamejs/lib/middleware/span-http-server.js +280 -0
- package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +323 -0
- package/lib/vendor/blamejs/lib/middleware/sse.js +200 -0
- package/lib/vendor/blamejs/lib/middleware/trace-log-correlation.js +167 -0
- package/lib/vendor/blamejs/lib/middleware/trace-propagate.js +148 -0
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +749 -0
- package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +164 -0
- package/lib/vendor/blamejs/lib/migration-files.js +37 -0
- package/lib/vendor/blamejs/lib/migrations.js +385 -0
- package/lib/vendor/blamejs/lib/mime-parse.js +198 -0
- package/lib/vendor/blamejs/lib/money.js +699 -0
- package/lib/vendor/blamejs/lib/mtls-ca.js +572 -0
- package/lib/vendor/blamejs/lib/mtls-engine-default.js +501 -0
- package/lib/vendor/blamejs/lib/network-byte-quota.js +308 -0
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +533 -0
- package/lib/vendor/blamejs/lib/network-dns.js +1930 -0
- package/lib/vendor/blamejs/lib/network-heartbeat.js +425 -0
- package/lib/vendor/blamejs/lib/network-nts.js +574 -0
- package/lib/vendor/blamejs/lib/network-proxy.js +265 -0
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +836 -0
- package/lib/vendor/blamejs/lib/network-tls.js +3126 -0
- package/lib/vendor/blamejs/lib/network.js +346 -0
- package/lib/vendor/blamejs/lib/nis2-report.js +181 -0
- package/lib/vendor/blamejs/lib/nist-crosswalk.js +293 -0
- package/lib/vendor/blamejs/lib/nonce-store.js +177 -0
- package/lib/vendor/blamejs/lib/notify.js +683 -0
- package/lib/vendor/blamejs/lib/ntp-check.js +458 -0
- package/lib/vendor/blamejs/lib/numeric-bounds.js +111 -0
- package/lib/vendor/blamejs/lib/numeric-checks.js +40 -0
- package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +349 -0
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +488 -0
- package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +351 -0
- package/lib/vendor/blamejs/lib/object-store/gcs.js +515 -0
- package/lib/vendor/blamejs/lib/object-store/http-put.js +153 -0
- package/lib/vendor/blamejs/lib/object-store/http-request.js +38 -0
- package/lib/vendor/blamejs/lib/object-store/index.js +197 -0
- package/lib/vendor/blamejs/lib/object-store/local.js +163 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +1133 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +957 -0
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +420 -0
- package/lib/vendor/blamejs/lib/observability-tracer.js +395 -0
- package/lib/vendor/blamejs/lib/observability.js +720 -0
- package/lib/vendor/blamejs/lib/openapi-paths-builder.js +248 -0
- package/lib/vendor/blamejs/lib/openapi-schema-walk.js +192 -0
- package/lib/vendor/blamejs/lib/openapi-security.js +169 -0
- package/lib/vendor/blamejs/lib/openapi-yaml.js +154 -0
- package/lib/vendor/blamejs/lib/openapi.js +489 -0
- package/lib/vendor/blamejs/lib/otel-export.js +278 -0
- package/lib/vendor/blamejs/lib/outbox.js +547 -0
- package/lib/vendor/blamejs/lib/pagination.js +542 -0
- package/lib/vendor/blamejs/lib/parsers/index.js +91 -0
- package/lib/vendor/blamejs/lib/parsers/safe-env.js +642 -0
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +293 -0
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +784 -0
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +390 -0
- package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +1015 -0
- package/lib/vendor/blamejs/lib/permissions.js +793 -0
- package/lib/vendor/blamejs/lib/pick.js +105 -0
- package/lib/vendor/blamejs/lib/pqc-agent.js +351 -0
- package/lib/vendor/blamejs/lib/pqc-gate.js +279 -0
- package/lib/vendor/blamejs/lib/pqc-software.js +271 -0
- package/lib/vendor/blamejs/lib/problem-details.js +482 -0
- package/lib/vendor/blamejs/lib/process-spawn.js +196 -0
- package/lib/vendor/blamejs/lib/promise-pool.js +162 -0
- package/lib/vendor/blamejs/lib/protobuf-encoder.js +190 -0
- package/lib/vendor/blamejs/lib/protocol-dispatcher.js +161 -0
- package/lib/vendor/blamejs/lib/public-suffix.js +403 -0
- package/lib/vendor/blamejs/lib/pubsub-cluster.js +154 -0
- package/lib/vendor/blamejs/lib/pubsub-redis.js +167 -0
- package/lib/vendor/blamejs/lib/pubsub.js +463 -0
- package/lib/vendor/blamejs/lib/queue-local.js +476 -0
- package/lib/vendor/blamejs/lib/queue-redis.js +745 -0
- package/lib/vendor/blamejs/lib/queue-sqs.js +319 -0
- package/lib/vendor/blamejs/lib/queue.js +1016 -0
- package/lib/vendor/blamejs/lib/redact.js +1007 -0
- package/lib/vendor/blamejs/lib/redis-client.js +520 -0
- package/lib/vendor/blamejs/lib/render.js +285 -0
- package/lib/vendor/blamejs/lib/request-helpers.js +767 -0
- package/lib/vendor/blamejs/lib/resource-access-lock.js +116 -0
- package/lib/vendor/blamejs/lib/restore-bundle.js +340 -0
- package/lib/vendor/blamejs/lib/restore-rollback.js +365 -0
- package/lib/vendor/blamejs/lib/restore.js +409 -0
- package/lib/vendor/blamejs/lib/retention.js +640 -0
- package/lib/vendor/blamejs/lib/retry.js +523 -0
- package/lib/vendor/blamejs/lib/router.js +1289 -0
- package/lib/vendor/blamejs/lib/safe-async.js +1184 -0
- package/lib/vendor/blamejs/lib/safe-buffer.js +562 -0
- package/lib/vendor/blamejs/lib/safe-decompress.js +297 -0
- package/lib/vendor/blamejs/lib/safe-dns.js +665 -0
- package/lib/vendor/blamejs/lib/safe-ical.js +634 -0
- package/lib/vendor/blamejs/lib/safe-icap.js +502 -0
- package/lib/vendor/blamejs/lib/safe-json.js +946 -0
- package/lib/vendor/blamejs/lib/safe-jsonpath.js +285 -0
- package/lib/vendor/blamejs/lib/safe-mime.js +831 -0
- package/lib/vendor/blamejs/lib/safe-mount-info.js +306 -0
- package/lib/vendor/blamejs/lib/safe-path.js +254 -0
- package/lib/vendor/blamejs/lib/safe-redirect.js +106 -0
- package/lib/vendor/blamejs/lib/safe-schema.js +1810 -0
- package/lib/vendor/blamejs/lib/safe-sieve.js +684 -0
- package/lib/vendor/blamejs/lib/safe-smtp.js +185 -0
- package/lib/vendor/blamejs/lib/safe-sql.js +363 -0
- package/lib/vendor/blamejs/lib/safe-url.js +428 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +473 -0
- package/lib/vendor/blamejs/lib/sandbox-worker.js +135 -0
- package/lib/vendor/blamejs/lib/sandbox.js +358 -0
- package/lib/vendor/blamejs/lib/scheduler.js +827 -0
- package/lib/vendor/blamejs/lib/sd-notify.js +269 -0
- package/lib/vendor/blamejs/lib/sec-cyber.js +214 -0
- package/lib/vendor/blamejs/lib/security-assert.js +395 -0
- package/lib/vendor/blamejs/lib/seeders.js +620 -0
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +309 -0
- package/lib/vendor/blamejs/lib/self-update.js +804 -0
- package/lib/vendor/blamejs/lib/server-timing.js +174 -0
- package/lib/vendor/blamejs/lib/session-device-binding.js +431 -0
- package/lib/vendor/blamejs/lib/session-stores.js +138 -0
- package/lib/vendor/blamejs/lib/session.js +1162 -0
- package/lib/vendor/blamejs/lib/slug.js +381 -0
- package/lib/vendor/blamejs/lib/sse.js +349 -0
- package/lib/vendor/blamejs/lib/ssrf-guard.js +792 -0
- package/lib/vendor/blamejs/lib/standard-webhooks.js +183 -0
- package/lib/vendor/blamejs/lib/static.js +1249 -0
- package/lib/vendor/blamejs/lib/storage.js +1272 -0
- package/lib/vendor/blamejs/lib/stream-throttle.js +235 -0
- package/lib/vendor/blamejs/lib/structured-fields.js +244 -0
- package/lib/vendor/blamejs/lib/subject.js +667 -0
- package/lib/vendor/blamejs/lib/tcpa-10dlc.js +175 -0
- package/lib/vendor/blamejs/lib/template.js +931 -0
- package/lib/vendor/blamejs/lib/tenant-quota.js +545 -0
- package/lib/vendor/blamejs/lib/test-harness.js +275 -0
- package/lib/vendor/blamejs/lib/testing.js +1185 -0
- package/lib/vendor/blamejs/lib/time.js +578 -0
- package/lib/vendor/blamejs/lib/tls-exporter.js +239 -0
- package/lib/vendor/blamejs/lib/totp.js +318 -0
- package/lib/vendor/blamejs/lib/tracing.js +546 -0
- package/lib/vendor/blamejs/lib/uuid.js +207 -0
- package/lib/vendor/blamejs/lib/validate-opts.js +381 -0
- package/lib/vendor/blamejs/lib/vault/index.js +638 -0
- package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +311 -0
- package/lib/vendor/blamejs/lib/vault/passphrase-source.js +198 -0
- package/lib/vendor/blamejs/lib/vault/rotate.js +803 -0
- package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +471 -0
- package/lib/vendor/blamejs/lib/vault/wrap.js +296 -0
- package/lib/vendor/blamejs/lib/vault-aad.js +259 -0
- package/lib/vendor/blamejs/lib/vendor/.vendor-data-pubkey +4 -0
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +161 -0
- package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.data.js +68 -0
- package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.pem +33 -0
- package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.data.js +1325 -0
- package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.txt +10002 -0
- package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +9 -0
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +18 -0
- package/lib/vendor/blamejs/lib/vendor/pki.cjs +181 -0
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +16382 -0
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5881 -0
- package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +328 -0
- package/lib/vendor/blamejs/lib/vendor/vendor-data-pubkey.js +16 -0
- package/lib/vendor/blamejs/lib/vendor-data.js +520 -0
- package/lib/vendor/blamejs/lib/vex.js +630 -0
- package/lib/vendor/blamejs/lib/watcher.js +608 -0
- package/lib/vendor/blamejs/lib/web-push-vapid.js +322 -0
- package/lib/vendor/blamejs/lib/webhook.js +977 -0
- package/lib/vendor/blamejs/lib/websocket-channels.js +327 -0
- package/lib/vendor/blamejs/lib/websocket.js +1561 -0
- package/lib/vendor/blamejs/lib/wiki-concepts.js +338 -0
- package/lib/vendor/blamejs/lib/worker-pool.js +464 -0
- package/lib/vendor/blamejs/lib/ws-client.js +978 -0
- package/lib/vendor/blamejs/lib/xml-c14n.js +506 -0
- package/lib/vendor/blamejs/memory/specs/node-26-map-getorinsert-migration.md +164 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +19 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/README.md +88 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/build.sh +26 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/project.yaml +28 -0
- package/lib/vendor/blamejs/package.json +81 -0
- package/lib/vendor/blamejs/release-notes/v0.0.x.json +310 -0
- package/lib/vendor/blamejs/release-notes/v0.1.x.json +1798 -0
- package/lib/vendor/blamejs/release-notes/v0.10.x.json +1288 -0
- package/lib/vendor/blamejs/release-notes/v0.11.x.json +2551 -0
- package/lib/vendor/blamejs/release-notes/v0.12.0.json +64 -0
- package/lib/vendor/blamejs/release-notes/v0.12.1.json +32 -0
- package/lib/vendor/blamejs/release-notes/v0.12.2.json +45 -0
- package/lib/vendor/blamejs/release-notes/v0.2.x.json +706 -0
- package/lib/vendor/blamejs/release-notes/v0.3.x.json +786 -0
- package/lib/vendor/blamejs/release-notes/v0.4.x.json +588 -0
- package/lib/vendor/blamejs/release-notes/v0.5.x.json +390 -0
- package/lib/vendor/blamejs/release-notes/v0.6.x.json +1947 -0
- package/lib/vendor/blamejs/release-notes/v0.7.x.json +3811 -0
- package/lib/vendor/blamejs/release-notes/v0.8.x.json +3318 -0
- package/lib/vendor/blamejs/release-notes/v0.9.x.json +2257 -0
- package/lib/vendor/blamejs/scripts/build-vendored-sbom.js +325 -0
- package/lib/vendor/blamejs/scripts/check-api-snapshot.js +62 -0
- package/lib/vendor/blamejs/scripts/check-changelog-extract.js +108 -0
- package/lib/vendor/blamejs/scripts/check-pack-against-gitignore.js +83 -0
- package/lib/vendor/blamejs/scripts/check-services.js +483 -0
- package/lib/vendor/blamejs/scripts/check-vendor-currency.js +349 -0
- package/lib/vendor/blamejs/scripts/consolidate-release-notes.js +216 -0
- package/lib/vendor/blamejs/scripts/gen-migrating.js +275 -0
- package/lib/vendor/blamejs/scripts/generate-changelog-entry.js +577 -0
- package/lib/vendor/blamejs/scripts/generate-release-signing-key.js +79 -0
- package/lib/vendor/blamejs/scripts/publish-dep-confusion-placeholder.sh +101 -0
- package/lib/vendor/blamejs/scripts/refresh-api-snapshot.js +31 -0
- package/lib/vendor/blamejs/scripts/refresh-vendor-manifest.js +132 -0
- package/lib/vendor/blamejs/scripts/release.js +652 -0
- package/lib/vendor/blamejs/scripts/sha3-digest.js +62 -0
- package/lib/vendor/blamejs/scripts/sign-release-artifact.js +92 -0
- package/lib/vendor/blamejs/scripts/test-integration.js +181 -0
- package/lib/vendor/blamejs/scripts/test-wiki-integration.js +126 -0
- package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +77 -0
- package/lib/vendor/blamejs/scripts/vendor-data-gen.js +186 -0
- package/lib/vendor/blamejs/scripts/vendor-data-keygen.js +101 -0
- package/lib/vendor/blamejs/scripts/vendor-update.sh +278 -0
- package/lib/vendor/blamejs/test/00-primitives.js +19075 -0
- package/lib/vendor/blamejs/test/10-state.js +622 -0
- package/lib/vendor/blamejs/test/20-db.js +561 -0
- package/lib/vendor/blamejs/test/30-chain.js +2110 -0
- package/lib/vendor/blamejs/test/40-consumers.js +2453 -0
- package/lib/vendor/blamejs/test/50-integration.js +486 -0
- package/lib/vendor/blamejs/test/_helpers.js +10 -0
- package/lib/vendor/blamejs/test/_smoke-worker.js +69 -0
- package/lib/vendor/blamejs/test/fixtures/exploit-corpus/corpus.json +368 -0
- package/lib/vendor/blamejs/test/fixtures/http-client-stream-payload.txt +2 -0
- package/lib/vendor/blamejs/test/fixtures/worker-pool/echo.js +52 -0
- package/lib/vendor/blamejs/test/helpers/_codebase-shingle-worker.js +24 -0
- package/lib/vendor/blamejs/test/helpers/_codebase-shingle.js +203 -0
- package/lib/vendor/blamejs/test/helpers/_shape-match.js +513 -0
- package/lib/vendor/blamejs/test/helpers/check.js +36 -0
- package/lib/vendor/blamejs/test/helpers/cluster.js +70 -0
- package/lib/vendor/blamejs/test/helpers/db.js +143 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +207 -0
- package/lib/vendor/blamejs/test/helpers/fs-watch.js +101 -0
- package/lib/vendor/blamejs/test/helpers/http.js +14 -0
- package/lib/vendor/blamejs/test/helpers/index.js +93 -0
- package/lib/vendor/blamejs/test/helpers/json-round-trip.js +120 -0
- package/lib/vendor/blamejs/test/helpers/mocks.js +20 -0
- package/lib/vendor/blamejs/test/helpers/otel.js +13 -0
- package/lib/vendor/blamejs/test/helpers/services.js +380 -0
- package/lib/vendor/blamejs/test/helpers/wait.js +206 -0
- package/lib/vendor/blamejs/test/integration/cache.test.js +235 -0
- package/lib/vendor/blamejs/test/integration/cluster-provider-mysql.test.js +174 -0
- package/lib/vendor/blamejs/test/integration/federation-auth.test.js +611 -0
- package/lib/vendor/blamejs/test/integration/http-client.test.js +129 -0
- package/lib/vendor/blamejs/test/integration/log-stream.test.js +219 -0
- package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +181 -0
- package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +152 -0
- package/lib/vendor/blamejs/test/integration/mail-smtp.test.js +161 -0
- package/lib/vendor/blamejs/test/integration/mtls-ca.test.js +289 -0
- package/lib/vendor/blamejs/test/integration/network-dns.test.js +123 -0
- package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +101 -0
- package/lib/vendor/blamejs/test/integration/ntp-check.test.js +89 -0
- package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +403 -0
- package/lib/vendor/blamejs/test/integration/pqc-pkcs8-forward-compat.test.js +271 -0
- package/lib/vendor/blamejs/test/integration/pubsub.test.js +137 -0
- package/lib/vendor/blamejs/test/integration/queue-redis.test.js +352 -0
- package/lib/vendor/blamejs/test/integration/redis-client-tls.test.js +96 -0
- package/lib/vendor/blamejs/test/integration/ssrf-guard.test.js +98 -0
- package/lib/vendor/blamejs/test/integration/websocket-permessage-deflate.test.js +261 -0
- package/lib/vendor/blamejs/test/integration/ws-client-roundtrip.test.js +230 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +211 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/access-lock.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +219 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +262 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-orchestrator.test.js +390 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-posture-chain.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +279 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +322 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-stream.test.js +227 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-tenant.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-trace.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-adverse-decision.test.js +44 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-content-detect.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-input.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-model-manifest.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-pref.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +1080 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +311 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-zip-stream.test.js +291 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +267 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +108 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asyncapi.test.js +929 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-conflict-path.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-cve-defensive.test.js +176 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-export-cadf.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +141 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-segregation.test.js +115 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-ml-dsa-65.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +246 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge-verifier.test.js +485 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +331 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +352 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +572 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-password-audit.test.js +61 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-bucket-ops.test.js +258 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-worker.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/bearer-auth.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-chunked-malformed.test.js +131 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-smuggling.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/boot-gates.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/breach-deadline.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +861 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/budr.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/bundler-engine.test.js +209 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache-status.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +871 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +891 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/canonical-json-jcs.test.js +43 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cdn-cache-control.test.js +243 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +550 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-audit-verify-chain.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-backup.test.js +135 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-config-drift.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +75 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-file-type.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-helpers.test.js +145 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-mtls.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-password.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-restore.test.js +160 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-retention.test.js +84 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-security.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-vault.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/client-hints.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +237 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +9600 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-cascade.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-eaa.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +712 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/config-drift.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/config.test.js +424 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +357 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cra-report.test.js +31 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-envelope.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +193 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke-pq.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke.test.js +155 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-mlkem768-x25519.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-namespace-hash.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-random-int.test.js +72 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +210 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daily-byte-quota.test.js +153 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-collection-extensions.test.js +226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-collection.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-init-extensions.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-extensions.test.js +191 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-role-for.test.js +228 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-vacuum.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +184 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/declare-row-policy.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/declare-view.test.js +303 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dns-dnssec-algorithm.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dns-null-mx.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dr-runbook.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr-state-rules.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +786 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/early-hints.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/events.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/exploit-replay.test.js +243 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +181 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-routing.test.js +531 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fapi2.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +156 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fdx.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +434 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +432 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/file-type.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +887 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/forensic-snapshot.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fsm.test.js +375 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gcs-bucket-ops.test.js +321 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +41 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-agent-registry.test.js +87 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-all.test.js +328 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +339 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +694 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-dsn.test.js +296 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +234 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-envelope.test.js +192 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-payload.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-topic.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +386 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html-wcag.test.js +859 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +357 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +317 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-id.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-unsubscribe.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-compose.test.js +111 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-move.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-query.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-reply.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-sieve.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +301 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +265 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-message-id.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +161 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-posture-chain.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-saga-config.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-smtp-command.test.js +269 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-snapshot-envelope.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-stream-args.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +288 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-tenant-id.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-trace-context.test.js +102 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +202 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/hal.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/honeytoken.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +692 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +280 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +225 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +991 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/iab-mspa.test.js +63 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/iab-tcf.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +612 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +56 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +166 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/incident-report.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jose-jwe-experimental.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-api.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-round-trip-helper.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +159 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/local-db-thin.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-cloudwatch.test.js +489 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp-grpc.test.js +207 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/lro.test.js +65 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +417 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +208 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +910 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +502 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +680 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-canspam.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +297 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +514 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy-tlsrpt.test.js +369 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +627 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-feedback-id.test.js +56 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +217 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +217 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-mdn.test.js +334 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-rbl.test.js +271 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-require-tls.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +215 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +336 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +732 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +840 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +285 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +229 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +394 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-spam-score.test.js +204 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-srs.test.js +152 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +279 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-unsubscribe.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +439 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp-tool-registry.test.js +202 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +155 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-shadow-registry.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +224 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-compose-pipeline.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +376 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-paths.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nel.test.js +200 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-byte-quota.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +372 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +635 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-heartbeat-passive.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-build-options.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-ct-inclusion.test.js +179 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +447 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +369 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nis2-report.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nist-crosswalk.test.js +42 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/no-cache.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/notify.test.js +707 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/numeric-bounds.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +72 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +597 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/openapi.test.js +877 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +257 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pagination.test.js +522 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +324 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +546 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +153 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-software.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/problem-details.test.js +195 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/process-spawn.test.js +62 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/promise-pool.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protected-resource-metadata.test.js +68 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protobuf-encoder.test.js +138 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protocol-dispatcher.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/public-suffix.test.js +197 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +232 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-dlq-extend-lease.test.js +178 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +322 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-priority-rate-progress.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-sqs.test.js +300 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-cluster.test.js +338 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-registry.test.js +75 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +246 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +335 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-log.test.js +170 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-auth-cache-control.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-mtls.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/resource-access-lock.test.js +52 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retry.test.js +535 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-cross-origin-redirect.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-parallel.test.js +170 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +248 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +451 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +289 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-icap.test.js +206 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +339 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mount-info.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-sieve.test.js +123 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-smtp.test.js +95 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-idn-homograph.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +257 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/saml-slo.test.js +249 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +228 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-exactly-once.test.js +238 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +700 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-notify.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sec-cyber.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +175 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/seeders.test.js +816 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update-standalone-verifier.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/server-timing.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +247 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +295 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/shape-match.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +952 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-multipart-sse.test.js +441 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/slug.test.js +330 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/smtp-policy.test.js +233 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/source-comment-blocks.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/speculation-rules.test.js +319 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sse.test.js +148 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/standard-webhooks.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +487 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-chunk-scratch.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +773 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/stream-throttle.test.js +173 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tcpa-10dlc.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +571 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/test-harness.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/testing-request.test.js +119 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/testing.test.js +522 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-exporter.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-ct.test.js +275 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-verify.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-pinset-drift.test.js +35 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-preferred-groups.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tracing.test.js +280 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/uuid.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-aad.test.js +277 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-seal-pem-file.test.js +252 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vendor-data.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vendor-manifest.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vex.test.js +661 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +308 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/web-push-vapid.test.js +144 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +674 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket-channels.test.js +360 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +349 -0
- package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +717 -0
- package/lib/vendor/blamejs/test/layer-5-integration/bundler-output.test.js +444 -0
- package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +597 -0
- package/lib/vendor/blamejs/test/layer-5-integration/security-chaos.test.js +308 -0
- package/lib/vendor/blamejs/test/smoke.js +431 -0
- package/lib/webhooks.js +305 -0
- package/package.json +43 -0
|
@@ -0,0 +1,1565 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module b.mail.server.jmap
|
|
4
|
+
* @nav Mail
|
|
5
|
+
* @title Mail JMAP Server
|
|
6
|
+
* @order 548
|
|
7
|
+
*
|
|
8
|
+
* @intro
|
|
9
|
+
* JMAP Core (RFC 8620) + JMAP Mail (RFC 8621) listener. Where IMAP
|
|
10
|
+
* is a TCP text-protocol with a connection state-machine, JMAP is
|
|
11
|
+
* HTTP-mounted JSON-RPC — operators mount the handler under their
|
|
12
|
+
* existing `b.router` / `b.createApp` and the JMAP semantics ride
|
|
13
|
+
* the HTTP request lifecycle (auth → body parse → handler →
|
|
14
|
+
* response).
|
|
15
|
+
*
|
|
16
|
+
* ## Public surface
|
|
17
|
+
*
|
|
18
|
+
* ```js
|
|
19
|
+
* var jmap = b.mail.server.jmap.create({
|
|
20
|
+
* mailStore: b.mailStore.create({ backend: b.db.handle() }),
|
|
21
|
+
* methods: {
|
|
22
|
+
* "Mailbox/get": async function (actor, args) {...},
|
|
23
|
+
* "Email/query": async function (actor, args) {...},
|
|
24
|
+
* "Email/get": async function (actor, args) {...},
|
|
25
|
+
* },
|
|
26
|
+
* serverCapabilities: {
|
|
27
|
+
* "urn:ietf:params:jmap:mail": { maxMailboxesPerEmail: null },
|
|
28
|
+
* "urn:ietf:params:jmap:submission": null,
|
|
29
|
+
* },
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Mount on the framework's router:
|
|
33
|
+
* app.use("/.well-known/jmap", jmap.discoveryHandler);
|
|
34
|
+
* app.use("/jmap/session", b.middleware.bearerAuth(...), jmap.sessionHandler);
|
|
35
|
+
* app.use("/jmap/api", b.middleware.bearerAuth(...), jmap.apiHandler);
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* The listener owns the request envelope (`b.guardJmap.validate`),
|
|
39
|
+
* back-reference resolution (RFC 8620 §3.7), the per-call dispatch,
|
|
40
|
+
* and the standard error mapping (RFC 8620 §3.6.1). Operators wire
|
|
41
|
+
* the actual method implementations — JMAP semantics are too varied
|
|
42
|
+
* (Mailbox / Email / Thread / SearchSnippet / Identity /
|
|
43
|
+
* EmailSubmission) to enshrine in v1.
|
|
44
|
+
*
|
|
45
|
+
* ## Capability discovery (RFC 8620 §2)
|
|
46
|
+
*
|
|
47
|
+
* GET `/.well-known/jmap` redirects to the session resource per
|
|
48
|
+
* §2.2. GET `/jmap/session` returns the session object with the
|
|
49
|
+
* server's capabilities, account list (operator-supplied via
|
|
50
|
+
* `opts.accountsFor(actor)`), and endpoint URLs.
|
|
51
|
+
*
|
|
52
|
+
* ## Request shape (RFC 8620 §3.3)
|
|
53
|
+
*
|
|
54
|
+
* POST `/jmap/api` with body:
|
|
55
|
+
*
|
|
56
|
+
* ```json
|
|
57
|
+
* {
|
|
58
|
+
* "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
|
|
59
|
+
* "methodCalls": [
|
|
60
|
+
* ["Mailbox/get", { "accountId": "A1" }, "c0"],
|
|
61
|
+
* ["Email/query", { "filter": { "inMailbox": "#c0/list/0/id" } }, "c1"]
|
|
62
|
+
* ]
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* Response shape:
|
|
67
|
+
*
|
|
68
|
+
* ```json
|
|
69
|
+
* {
|
|
70
|
+
* "methodResponses": [
|
|
71
|
+
* ["Mailbox/get", { ... }, "c0"],
|
|
72
|
+
* ["Email/query", { ... }, "c1"]
|
|
73
|
+
* ],
|
|
74
|
+
* "sessionState": "<opaque-token>"
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* ## Caps (RFC 8620 §3.6)
|
|
79
|
+
*
|
|
80
|
+
* Enforced via `b.guardJmap.validate` — `maxCallsInRequest`,
|
|
81
|
+
* `maxSizeRequest`, `maxObjectsInGet/Set`, `maxBackRefDepth`. Per-
|
|
82
|
+
* account method-call concurrent cap via `b.mail.server.rateLimit`
|
|
83
|
+
* when wired.
|
|
84
|
+
*
|
|
85
|
+
* ## Error vocabulary (RFC 8620 §3.6.1)
|
|
86
|
+
*
|
|
87
|
+
* Standard errors emitted as the methodResponse object:
|
|
88
|
+
*
|
|
89
|
+
* - `urn:ietf:params:jmap:error:requestTooLarge`
|
|
90
|
+
* - `urn:ietf:params:jmap:error:invalidArguments`
|
|
91
|
+
* - `urn:ietf:params:jmap:error:invalidResultReference`
|
|
92
|
+
* - `urn:ietf:params:jmap:error:unknownCapability`
|
|
93
|
+
* - `urn:ietf:params:jmap:error:limit/<name>`
|
|
94
|
+
* - `urn:ietf:params:jmap:error:forbidden`
|
|
95
|
+
* - `urn:ietf:params:jmap:error:accountNotFound`
|
|
96
|
+
* - `urn:ietf:params:jmap:error:serverFail` (opaque last-resort)
|
|
97
|
+
*
|
|
98
|
+
* ## What v1 does NOT ship
|
|
99
|
+
*
|
|
100
|
+
* - **Push channel (SSE + WebSocket per RFC 8887)** — operator wires
|
|
101
|
+
* `b.sse` or `b.websocket` to the `pushSubscribe` hook. v1.5
|
|
102
|
+
* bundles a turnkey push handler.
|
|
103
|
+
* - **Blob upload/download endpoints** — operator wires their own
|
|
104
|
+
* `/jmap/upload` / `/jmap/download` handlers; the framework
|
|
105
|
+
* supplies `b.storage` + `b.objectStore` + the guard-* family
|
|
106
|
+
* for the actual upload path.
|
|
107
|
+
* - **EmailSubmission (RFC 8621 §7)** — operator wires the bridge
|
|
108
|
+
* to `b.mail.server.submission`'s outbound agent.
|
|
109
|
+
* - **Calendars / Contacts (RFC 9610)**, **Sieve (RFC 9404)**,
|
|
110
|
+
* **MDN (RFC 9007)** — opt-in capabilities.
|
|
111
|
+
*
|
|
112
|
+
* @card
|
|
113
|
+
* JMAP Core (RFC 8620) + JMAP Mail (RFC 8621) listener. HTTP-mounted
|
|
114
|
+
* JSON-RPC. Composes b.guardJmap (request-envelope validator) +
|
|
115
|
+
* operator-supplied method handlers + b.mailStore. Per-account back-
|
|
116
|
+
* reference resolution (RFC 8620 §3.7) + standard error vocabulary
|
|
117
|
+
* (RFC 8620 §3.6.1) handled at the listener boundary.
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
var lazyRequire = require("./lazy-require");
|
|
121
|
+
var C = require("./constants");
|
|
122
|
+
var bCrypto = require("./crypto");
|
|
123
|
+
var safeJson = require("./safe-json");
|
|
124
|
+
var safeBuffer = require("./safe-buffer");
|
|
125
|
+
var websocket = require("./websocket");
|
|
126
|
+
var validateOpts = require("./validate-opts");
|
|
127
|
+
var guardJmap = require("./guard-jmap");
|
|
128
|
+
var mailServerRegistry = require("./mail-server-registry");
|
|
129
|
+
var { defineClass } = require("./framework-error");
|
|
130
|
+
|
|
131
|
+
var audit = lazyRequire(function () { return require("./audit"); });
|
|
132
|
+
|
|
133
|
+
var MailServerJmapError = defineClass("MailServerJmapError", { alwaysPermanent: true });
|
|
134
|
+
|
|
135
|
+
var DEFAULT_PROFILE = "strict";
|
|
136
|
+
var WELL_KNOWN_PATH = "/.well-known/jmap";
|
|
137
|
+
void C; // reserved for future cap constants
|
|
138
|
+
void WELL_KNOWN_PATH;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @primitive b.mail.server.jmap.create
|
|
142
|
+
* @signature b.mail.server.jmap.create(opts)
|
|
143
|
+
* @since 0.9.50
|
|
144
|
+
* @status stable
|
|
145
|
+
* @related b.mail.server.imap.create, b.guardJmap.validate, b.mailStore.create
|
|
146
|
+
*
|
|
147
|
+
* Build a JMAP Core + JMAP Mail listener. Returns a handle exposing
|
|
148
|
+
* `apiHandler` / `sessionHandler` / `discoveryHandler` (Express-style
|
|
149
|
+
* `(req, res, next)` functions) and `dispatch(actor, body)` for
|
|
150
|
+
* operators with a non-Express transport.
|
|
151
|
+
*
|
|
152
|
+
* @opts
|
|
153
|
+
* mailStore: b.mailStore handle (operator-supplied backend),
|
|
154
|
+
* methods: { "<Type>/<verb>": async fn(actor, args, ctx) },
|
|
155
|
+
* // operator-supplied JMAP method handlers
|
|
156
|
+
* serverCapabilities: { "<URI>": <capability-record> },
|
|
157
|
+
* // capabilities the server advertises beyond core
|
|
158
|
+
* accountsFor: async function (actor) → { primaryAccounts, accounts },
|
|
159
|
+
* // operator-supplied accountId enumeration
|
|
160
|
+
* profile: "strict" | "balanced" | "permissive",
|
|
161
|
+
* posture: "hipaa" | "pci-dss" | "gdpr" | "soc2",
|
|
162
|
+
* audit: b.audit // optional
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* var jmap = b.mail.server.jmap.create({
|
|
166
|
+
* mailStore: b.mailStore.create({ backend: b.db.handle() }),
|
|
167
|
+
* methods: {
|
|
168
|
+
* "Mailbox/get": async function (actor, args) {
|
|
169
|
+
* return { accountId: args.accountId, list: [], notFound: [] };
|
|
170
|
+
* },
|
|
171
|
+
* },
|
|
172
|
+
* serverCapabilities: { "urn:ietf:params:jmap:mail": {} },
|
|
173
|
+
* accountsFor: async function (actor) {
|
|
174
|
+
* return {
|
|
175
|
+
* primaryAccounts: { "urn:ietf:params:jmap:mail": "A1" },
|
|
176
|
+
* accounts: { A1: { name: actor.username } },
|
|
177
|
+
* };
|
|
178
|
+
* },
|
|
179
|
+
* });
|
|
180
|
+
*
|
|
181
|
+
* app.post("/jmap/api", b.middleware.bearerAuth({ verify: verify }), jmap.apiHandler);
|
|
182
|
+
*/
|
|
183
|
+
function create(opts) {
|
|
184
|
+
validateOpts.requireObject(opts, "mail.server.jmap.create",
|
|
185
|
+
MailServerJmapError, "mail-server-jmap/bad-opts");
|
|
186
|
+
if (!opts.mailStore) {
|
|
187
|
+
throw new MailServerJmapError("mail-server-jmap/no-mail-store",
|
|
188
|
+
"mail.server.jmap.create: mailStore is required (compose b.mailStore.create({ backend: ... }))");
|
|
189
|
+
}
|
|
190
|
+
if (typeof opts.methods !== "object" || opts.methods === null || Array.isArray(opts.methods)) {
|
|
191
|
+
throw new MailServerJmapError("mail-server-jmap/no-methods",
|
|
192
|
+
"mail.server.jmap.create: opts.methods must be an object mapping method-name → async fn(actor, args, ctx)");
|
|
193
|
+
}
|
|
194
|
+
if (typeof opts.accountsFor !== "function") {
|
|
195
|
+
throw new MailServerJmapError("mail-server-jmap/no-accounts-for",
|
|
196
|
+
"mail.server.jmap.create: opts.accountsFor(actor) async function is required for the session resource");
|
|
197
|
+
}
|
|
198
|
+
var profile = opts.profile || DEFAULT_PROFILE;
|
|
199
|
+
var posture = opts.posture || null;
|
|
200
|
+
var serverCapabilities = opts.serverCapabilities || {};
|
|
201
|
+
|
|
202
|
+
// JMAP method registry. Wrap operator-supplied `opts.methods` map
|
|
203
|
+
// through `b.mail.serverRegistry` so per-handler resource budgets
|
|
204
|
+
// (maxHandlerBytes / maxHandlerMs) apply uniformly across the IMAP
|
|
205
|
+
// / JMAP / ManageSieve listeners. Legacy `opts.methods` callers get
|
|
206
|
+
// an auto-default budget (10 MiB / 30s) with a one-time deprecation
|
|
207
|
+
// audit event per process; new callers use `opts.overrides` with
|
|
208
|
+
// explicit budgets per the stricter-mode register contract.
|
|
209
|
+
var LEGACY_JMAP_BYTES = 10 * 1024 * 1024; // allow:raw-byte-literal — 10 MiB legacy auto-budget for JMAP methods
|
|
210
|
+
var LEGACY_JMAP_MS = 30 * 1000; // allow:raw-time-literal — 30s legacy auto-budget
|
|
211
|
+
var _legacyDeprecationEmitted = false;
|
|
212
|
+
var defaults = {};
|
|
213
|
+
var methodNames = Object.keys(opts.methods);
|
|
214
|
+
for (var mi = 0; mi < methodNames.length; mi += 1) {
|
|
215
|
+
var mname = methodNames[mi];
|
|
216
|
+
if (typeof opts.methods[mname] !== "function") continue;
|
|
217
|
+
defaults[mname] = {
|
|
218
|
+
fn: opts.methods[mname],
|
|
219
|
+
maxHandlerBytes: LEGACY_JMAP_BYTES,
|
|
220
|
+
maxHandlerMs: LEGACY_JMAP_MS,
|
|
221
|
+
allowExperimental: true, // legacy callers wired anything; preserve the openness
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
var registry = mailServerRegistry.create({
|
|
225
|
+
protocol: "jmap",
|
|
226
|
+
defaults: defaults,
|
|
227
|
+
overrides: opts.overrides || {},
|
|
228
|
+
// b.agent.tenant adoption (v0.10.12). When `opts.tenantScope` is
|
|
229
|
+
// supplied, every method dispatch first gates on
|
|
230
|
+
// `tenantScope.check(state.actor, agentTenantId)` — JMAP's
|
|
231
|
+
// accountId scoping continues to apply inside operator handlers.
|
|
232
|
+
tenantScope: opts.tenantScope || null,
|
|
233
|
+
agentTenantId: opts.agentTenantId || null,
|
|
234
|
+
});
|
|
235
|
+
var sessionState = bCrypto.generateToken(16); // allow:raw-byte-literal — opaque session-state token length
|
|
236
|
+
|
|
237
|
+
function _emit(action, metadata, outcome) {
|
|
238
|
+
try {
|
|
239
|
+
audit().safeEmit({
|
|
240
|
+
action: action,
|
|
241
|
+
outcome: outcome || "success",
|
|
242
|
+
metadata: metadata || {},
|
|
243
|
+
});
|
|
244
|
+
} catch (_e) { /* drop-silent — audit best-effort */ }
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ---- Back-reference resolution (RFC 8620 §3.7) -------------------------
|
|
248
|
+
//
|
|
249
|
+
// Walks the args tree replacing `#<refClientId>/<jsonPointer>` shapes
|
|
250
|
+
// with the resolved value from the prior method-response. Returns the
|
|
251
|
+
// resolved args object on success or throws an
|
|
252
|
+
// `urn:ietf:params:jmap:error:invalidResultReference`.
|
|
253
|
+
function _resolveBackRefs(args, priorResponses) {
|
|
254
|
+
if (args === null || typeof args !== "object") return args;
|
|
255
|
+
if (Array.isArray(args)) {
|
|
256
|
+
var out = [];
|
|
257
|
+
for (var i = 0; i < args.length; i += 1) out.push(_resolveBackRefs(args[i], priorResponses));
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
var obj = {};
|
|
261
|
+
var keys = Object.keys(args);
|
|
262
|
+
for (var k = 0; k < keys.length; k += 1) {
|
|
263
|
+
var key = keys[k];
|
|
264
|
+
var val = args[key];
|
|
265
|
+
if (key.charCodeAt(0) === 0x23) { // allow:raw-byte-literal — `#` (0x23) is the JMAP back-ref-key prefix
|
|
266
|
+
// `#<srcClientId>` → key strips the `#`; value is { resultOf, name, path }
|
|
267
|
+
var targetKey = key.slice(1);
|
|
268
|
+
if (!val || typeof val !== "object" || Array.isArray(val) ||
|
|
269
|
+
typeof val.resultOf !== "string" || typeof val.name !== "string" ||
|
|
270
|
+
typeof val.path !== "string") {
|
|
271
|
+
throw new MailServerJmapError("urn:ietf:params:jmap:error:invalidResultReference",
|
|
272
|
+
"back-ref `#" + targetKey + "` malformed (expected { resultOf, name, path })");
|
|
273
|
+
}
|
|
274
|
+
var src = priorResponses[val.resultOf];
|
|
275
|
+
if (!src || src.name !== val.name) {
|
|
276
|
+
throw new MailServerJmapError("urn:ietf:params:jmap:error:invalidResultReference",
|
|
277
|
+
"back-ref `#" + targetKey + "` → no prior response with clientId='" + val.resultOf +
|
|
278
|
+
"' and name='" + val.name + "'");
|
|
279
|
+
}
|
|
280
|
+
var resolved = _pointerLookup(src.result, val.path);
|
|
281
|
+
if (resolved === undefined) {
|
|
282
|
+
throw new MailServerJmapError("urn:ietf:params:jmap:error:invalidResultReference",
|
|
283
|
+
"back-ref `#" + targetKey + "` → path '" + val.path + "' resolved to undefined");
|
|
284
|
+
}
|
|
285
|
+
obj[targetKey] = resolved;
|
|
286
|
+
} else {
|
|
287
|
+
obj[key] = _resolveBackRefs(val, priorResponses);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return obj;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Minimal JSON Pointer (RFC 6901 §3) — `/foo/bar/0` traversal. JMAP
|
|
294
|
+
// back-references constrain the shape (single object → single array
|
|
295
|
+
// → single field) so we don't need the full RFC 6901 escape grammar
|
|
296
|
+
// here. Bounded recursion via the back-ref-depth cap upstream.
|
|
297
|
+
function _pointerLookup(node, path) {
|
|
298
|
+
if (typeof path !== "string") return undefined;
|
|
299
|
+
if (path === "" || path === "/") return node;
|
|
300
|
+
var parts = path.split("/");
|
|
301
|
+
var cur = node;
|
|
302
|
+
for (var i = 0; i < parts.length; i += 1) {
|
|
303
|
+
var seg = parts[i];
|
|
304
|
+
if (seg === "" && i === 0) continue;
|
|
305
|
+
if (cur === null || typeof cur !== "object") return undefined;
|
|
306
|
+
// RFC 6901 ~1 / ~0 escapes — minimal grammar.
|
|
307
|
+
seg = seg.replace(/~1/g, "/").replace(/~0/g, "~"); // allow:regex-no-length-cap — seg length bounded by path which is bounded by maxLineBytes upstream
|
|
308
|
+
if (Array.isArray(cur)) {
|
|
309
|
+
if (seg === "*") return cur;
|
|
310
|
+
var idx = parseInt(seg, 10);
|
|
311
|
+
if (!isFinite(idx) || idx < 0 || idx >= cur.length) return undefined;
|
|
312
|
+
cur = cur[idx];
|
|
313
|
+
} else {
|
|
314
|
+
if (!Object.prototype.hasOwnProperty.call(cur, seg)) return undefined;
|
|
315
|
+
cur = cur[seg];
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return cur;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// ---- Dispatch ------------------------------------------------------------
|
|
322
|
+
//
|
|
323
|
+
// `dispatch(actor, body)` is the operator-callable form — accepts a
|
|
324
|
+
// pre-parsed request body + an authenticated actor, returns a
|
|
325
|
+
// response object suitable for JSON-serialization to the client.
|
|
326
|
+
async function dispatch(actor, body) {
|
|
327
|
+
if (!actor) {
|
|
328
|
+
return _refusalResponse("urn:ietf:params:jmap:error:forbidden",
|
|
329
|
+
"actor is required (operator must wire b.middleware.bearerAuth before this handler)");
|
|
330
|
+
}
|
|
331
|
+
var parsed;
|
|
332
|
+
try {
|
|
333
|
+
parsed = guardJmap.validate(body, {
|
|
334
|
+
profile: profile,
|
|
335
|
+
posture: posture,
|
|
336
|
+
serverCapabilities: serverCapabilities,
|
|
337
|
+
});
|
|
338
|
+
} catch (e) {
|
|
339
|
+
var errType = (e && e.code) || "urn:ietf:params:jmap:error:invalidArguments";
|
|
340
|
+
_emit("mail.server.jmap.request_refused",
|
|
341
|
+
{ type: errType, reason: (e && e.message) || "" }, "denied");
|
|
342
|
+
return _refusalResponse(errType, (e && e.message) || "request refused");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
var methodResponses = [];
|
|
346
|
+
var byClientId = Object.create(null);
|
|
347
|
+
for (var i = 0; i < parsed.methodCalls.length; i += 1) {
|
|
348
|
+
var call = parsed.methodCalls[i];
|
|
349
|
+
var methodName = call[0];
|
|
350
|
+
var rawArgs = call[1];
|
|
351
|
+
var clientId = call[2];
|
|
352
|
+
var resolvedArgs;
|
|
353
|
+
try {
|
|
354
|
+
resolvedArgs = _resolveBackRefs(rawArgs, byClientId);
|
|
355
|
+
} catch (e) {
|
|
356
|
+
var refType = (e && e.code) || "urn:ietf:params:jmap:error:invalidResultReference";
|
|
357
|
+
methodResponses.push(["error", { type: refType, description: (e && e.message) || "" }, clientId]);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (!registry.has(methodName)) {
|
|
361
|
+
methodResponses.push(["error",
|
|
362
|
+
{ type: "urn:ietf:params:jmap:error:unknownMethod",
|
|
363
|
+
description: "Method '" + methodName + "' not implemented on this server" }, clientId]);
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (!_legacyDeprecationEmitted && registry.source(methodName) === "builtin") {
|
|
367
|
+
_legacyDeprecationEmitted = true;
|
|
368
|
+
_emit("mail.server.jmap.methods_opt_deprecated",
|
|
369
|
+
{ note: "opts.methods is shimmed through b.mail.serverRegistry with auto-budget; " +
|
|
370
|
+
"future minor will require opts.overrides with explicit budgets" },
|
|
371
|
+
"warning");
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
// JMAP methodCalls execute sequentially by spec (RFC 8620 §3.7 —
|
|
375
|
+
// back-references require strict ordering). The await-in-loop
|
|
376
|
+
// pattern is intentional here.
|
|
377
|
+
var result = await registry.dispatch(methodName, actor, resolvedArgs, {
|
|
378
|
+
using: parsed.using,
|
|
379
|
+
createdIds: parsed.createdIds,
|
|
380
|
+
methodName: methodName,
|
|
381
|
+
clientId: clientId,
|
|
382
|
+
});
|
|
383
|
+
if (result && typeof result === "object" && result.type &&
|
|
384
|
+
typeof result.type === "string" && result.type.indexOf("urn:ietf:params:jmap:error:") === 0) {
|
|
385
|
+
// Operator-emitted error shape — preserve as-is.
|
|
386
|
+
methodResponses.push(["error", result, clientId]);
|
|
387
|
+
byClientId[clientId] = { name: "error", result: result };
|
|
388
|
+
} else {
|
|
389
|
+
methodResponses.push([methodName, result || {}, clientId]);
|
|
390
|
+
byClientId[clientId] = { name: methodName, result: result || {} };
|
|
391
|
+
}
|
|
392
|
+
} catch (e) {
|
|
393
|
+
_emit("mail.server.jmap.method_threw",
|
|
394
|
+
{ method: methodName, clientId: clientId,
|
|
395
|
+
error: (e && e.message) || String(e) }, "failure");
|
|
396
|
+
methodResponses.push(["error",
|
|
397
|
+
{ type: "urn:ietf:params:jmap:error:serverFail",
|
|
398
|
+
description: "Method threw" }, clientId]);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
_emit("mail.server.jmap.request",
|
|
403
|
+
{ methodCallCount: parsed.methodCalls.length, using: parsed.using });
|
|
404
|
+
|
|
405
|
+
return {
|
|
406
|
+
methodResponses: methodResponses,
|
|
407
|
+
sessionState: sessionState,
|
|
408
|
+
createdIds: parsed.createdIds,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function _refusalResponse(type, description) {
|
|
413
|
+
return {
|
|
414
|
+
type: type,
|
|
415
|
+
description: description,
|
|
416
|
+
methodResponses: [],
|
|
417
|
+
sessionState: sessionState,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// ---- HTTP handlers -----------------------------------------------------
|
|
422
|
+
|
|
423
|
+
function apiHandler(req, res) {
|
|
424
|
+
// Operator wires b.middleware.bearerAuth before this handler, so
|
|
425
|
+
// `req.user` is the authenticated actor. If req.user is missing,
|
|
426
|
+
// refuse with 401 + Problem Details body.
|
|
427
|
+
var actor = req.user || (req.actor || null);
|
|
428
|
+
var rawBody = req.body;
|
|
429
|
+
if (rawBody === undefined) {
|
|
430
|
+
// b.middleware.bodyParser may not have run. Refuse cleanly.
|
|
431
|
+
res.statusCode = 400;
|
|
432
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
433
|
+
res.end(JSON.stringify({
|
|
434
|
+
type: "urn:ietf:params:jmap:error:invalidArguments",
|
|
435
|
+
description: "request body missing (wire b.middleware.bodyParser before this handler)",
|
|
436
|
+
}));
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
dispatch(actor, rawBody).then(function (response) {
|
|
440
|
+
// Map typed JMAP refusals to the right HTTP status. `forbidden`
|
|
441
|
+
// means the dispatcher refused because actor was missing /
|
|
442
|
+
// wrong-tenant — clients + proxies need 401 to trigger their
|
|
443
|
+
// re-auth flow (a 400 looks like a malformed request, which it
|
|
444
|
+
// isn't). Everything else stays 400 per RFC 8620 §3.6.1.
|
|
445
|
+
if (response && response.type === "urn:ietf:params:jmap:error:forbidden") {
|
|
446
|
+
res.statusCode = 401; // allow:raw-byte-literal — HTTP status codes
|
|
447
|
+
} else if (response && response.type) {
|
|
448
|
+
res.statusCode = 400; // allow:raw-byte-literal — HTTP status codes
|
|
449
|
+
} else {
|
|
450
|
+
res.statusCode = 200; // allow:raw-byte-literal — HTTP status codes
|
|
451
|
+
}
|
|
452
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
453
|
+
res.end(JSON.stringify(response));
|
|
454
|
+
}, function (err) {
|
|
455
|
+
_emit("mail.server.jmap.handler_threw",
|
|
456
|
+
{ error: (err && err.message) || String(err) }, "failure");
|
|
457
|
+
res.statusCode = 500;
|
|
458
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
459
|
+
res.end(JSON.stringify({
|
|
460
|
+
type: "urn:ietf:params:jmap:error:serverFail",
|
|
461
|
+
description: "Server error",
|
|
462
|
+
}));
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function sessionHandler(req, res) {
|
|
467
|
+
var actor = req.user || (req.actor || null);
|
|
468
|
+
if (!actor) {
|
|
469
|
+
res.statusCode = 401;
|
|
470
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
471
|
+
res.end(JSON.stringify({
|
|
472
|
+
type: "urn:ietf:params:jmap:error:forbidden",
|
|
473
|
+
description: "Authentication required",
|
|
474
|
+
}));
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
Promise.resolve().then(function () { return opts.accountsFor(actor); })
|
|
478
|
+
.then(function (accountInfo) {
|
|
479
|
+
var info = accountInfo || { primaryAccounts: {}, accounts: {} };
|
|
480
|
+
// RFC 8887 §3 — advertise the WebSocket transport in the
|
|
481
|
+
// capabilities object so RFC-compliant clients discover the
|
|
482
|
+
// endpoint via the canonical session-discovery flow rather
|
|
483
|
+
// than depending on the top-level `webSocketUrl` alias.
|
|
484
|
+
var defaultCaps = { "urn:ietf:params:jmap:core": {} };
|
|
485
|
+
var hasOperatorWsCap = Object.prototype.hasOwnProperty.call(
|
|
486
|
+
serverCapabilities, "urn:ietf:params:jmap:websocket");
|
|
487
|
+
if (!hasOperatorWsCap) {
|
|
488
|
+
defaultCaps["urn:ietf:params:jmap:websocket"] = {
|
|
489
|
+
url: opts.webSocketUrl || "/jmap/ws",
|
|
490
|
+
supportsPush: true,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
var session = {
|
|
494
|
+
capabilities: Object.assign({}, defaultCaps, serverCapabilities),
|
|
495
|
+
accounts: info.accounts || {},
|
|
496
|
+
primaryAccounts: info.primaryAccounts || {},
|
|
497
|
+
username: actor.username || actor.id || "unknown",
|
|
498
|
+
apiUrl: opts.apiUrl || "/jmap/api",
|
|
499
|
+
downloadUrl: opts.downloadUrl || "/jmap/download/{accountId}/{blobId}/{name}?accept={type}",
|
|
500
|
+
uploadUrl: opts.uploadUrl || "/jmap/upload/{accountId}",
|
|
501
|
+
eventSourceUrl: opts.eventSourceUrl || "/jmap/eventsource?types={types}&closeafter={closeafter}&ping={ping}",
|
|
502
|
+
// RFC 8887 §3 — `webSocketUrl` advertises the JMAP WS
|
|
503
|
+
// endpoint. Operator overrides via opts.webSocketUrl; default
|
|
504
|
+
// mounts at `/jmap/ws`.
|
|
505
|
+
urlEndpointResolution: serverCapabilities["urn:ietf:params:jmap:websocket"]
|
|
506
|
+
? { useEndpoint: opts.webSocketUrl || "/jmap/ws", urlPrefix: "" }
|
|
507
|
+
: undefined,
|
|
508
|
+
webSocketUrl: opts.webSocketUrl || "/jmap/ws",
|
|
509
|
+
state: sessionState,
|
|
510
|
+
};
|
|
511
|
+
res.statusCode = 200;
|
|
512
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
513
|
+
res.end(safeJson.stringify ? safeJson.stringify(session) : JSON.stringify(session)); // allow:bare-canonicalize-walk — JSON response, not signed payload
|
|
514
|
+
})
|
|
515
|
+
.catch(function (err) {
|
|
516
|
+
_emit("mail.server.jmap.session_threw",
|
|
517
|
+
{ error: (err && err.message) || String(err) }, "failure");
|
|
518
|
+
res.statusCode = 500;
|
|
519
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
520
|
+
res.end(JSON.stringify({
|
|
521
|
+
type: "urn:ietf:params:jmap:error:serverFail",
|
|
522
|
+
description: "Session resource failed",
|
|
523
|
+
}));
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// RFC 8620 §7.3 — EventSource (Server-Sent Events) push channel.
|
|
528
|
+
// Clients connect to `/jmap/eventsource?types=...&closeafter=...&ping=N`.
|
|
529
|
+
// Server holds the connection open and writes `event: state` + JSON
|
|
530
|
+
// payloads when the operator backend reports a state change.
|
|
531
|
+
// Periodic `event: ping` keeps intermediate proxies / load-balancers
|
|
532
|
+
// from closing the idle connection.
|
|
533
|
+
//
|
|
534
|
+
// closeafter=state — close after first state event (poll-like).
|
|
535
|
+
// closeafter=no (default) — keep open until disconnect.
|
|
536
|
+
// ping=<seconds> — keepalive interval (default 30s, min 5s, max 900s).
|
|
537
|
+
function eventSourceHandler(req, res) {
|
|
538
|
+
var actor = req.user || (req.actor || null);
|
|
539
|
+
if (!actor) {
|
|
540
|
+
res.statusCode = 401;
|
|
541
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
542
|
+
res.end(JSON.stringify({
|
|
543
|
+
type: "urn:ietf:params:jmap:error:forbidden",
|
|
544
|
+
description: "Authentication required",
|
|
545
|
+
}));
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
if (typeof opts.mailStore.subscribePush !== "function") {
|
|
549
|
+
res.statusCode = 503;
|
|
550
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
551
|
+
res.end(JSON.stringify({
|
|
552
|
+
type: "urn:ietf:params:jmap:error:serverUnavailable",
|
|
553
|
+
description: "Push subscribe backend not configured (mailStore.subscribePush)",
|
|
554
|
+
}));
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
// Parse query params from the URL. The HTTP server hands `req.url`
|
|
558
|
+
// with the query intact; we don't depend on Node's URL constructor
|
|
559
|
+
// for the query-string parse — small inline scan is enough.
|
|
560
|
+
var url = String(req.url || "");
|
|
561
|
+
var qIdx = url.indexOf("?");
|
|
562
|
+
var query = qIdx === -1 ? "" : url.slice(qIdx + 1);
|
|
563
|
+
var params = Object.create(null);
|
|
564
|
+
query.split("&").forEach(function (pair) {
|
|
565
|
+
if (!pair) return;
|
|
566
|
+
var eq = pair.indexOf("=");
|
|
567
|
+
var k = eq === -1 ? pair : pair.slice(0, eq);
|
|
568
|
+
var v = eq === -1 ? "" : pair.slice(eq + 1);
|
|
569
|
+
try { params[decodeURIComponent(k)] = decodeURIComponent(v); }
|
|
570
|
+
catch (_e) { /* drop-silent — malformed % encoding */ }
|
|
571
|
+
});
|
|
572
|
+
var typesStr = params.types || "*";
|
|
573
|
+
var types = typesStr === "*"
|
|
574
|
+
? null
|
|
575
|
+
: typesStr.split(",").map(function (s) { return s.trim(); }).filter(Boolean);
|
|
576
|
+
var closeAfter = (params.closeafter || "no").toLowerCase();
|
|
577
|
+
if (closeAfter !== "no" && closeAfter !== "state") {
|
|
578
|
+
res.statusCode = 400;
|
|
579
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
580
|
+
res.end(JSON.stringify({
|
|
581
|
+
type: "urn:ietf:params:jmap:error:invalidArguments",
|
|
582
|
+
description: "closeafter must be 'no' or 'state' (RFC 8620 §7.3)",
|
|
583
|
+
}));
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
// RFC 8620 §7.3 — `ping=0` is the EXPLICIT opt-out for the
|
|
587
|
+
// keepalive event channel. Treat it as "no ping" rather than
|
|
588
|
+
// clamping to the default. Any other non-finite / out-of-band
|
|
589
|
+
// value falls back to the 30 s default; in-band values
|
|
590
|
+
// (5..900 s) pass through unchanged so clients see the same
|
|
591
|
+
// negotiated interval they requested.
|
|
592
|
+
var pingN;
|
|
593
|
+
var pingDisabled = false;
|
|
594
|
+
if (params.ping === "0") {
|
|
595
|
+
pingDisabled = true;
|
|
596
|
+
pingN = 0;
|
|
597
|
+
} else {
|
|
598
|
+
pingN = parseInt(params.ping, 10);
|
|
599
|
+
if (!isFinite(pingN) || pingN < 5) pingN = 30; // allow:raw-byte-literal — RFC 8620 §7.3 default ping seconds
|
|
600
|
+
if (pingN > 900) pingN = 900; // allow:raw-byte-literal — operator-supplied ping seconds, not bytes // allow:raw-time-literal — explicit max-ping cap (15 minutes)
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// SSE wire headers per the HTML5 spec § "Server-sent events"
|
|
604
|
+
// and RFC 8620 §7.3 — Content-Type MUST be `text/event-stream`,
|
|
605
|
+
// intermediates MUST NOT cache (`Cache-Control: no-cache`),
|
|
606
|
+
// `Connection: keep-alive` instructs proxies to leave it open.
|
|
607
|
+
res.statusCode = 200;
|
|
608
|
+
res.setHeader("Content-Type", "text/event-stream; charset=utf-8");
|
|
609
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
610
|
+
res.setHeader("Connection", "keep-alive");
|
|
611
|
+
res.setHeader("X-Accel-Buffering", "no"); // disables nginx response buffering on the EventSource stream
|
|
612
|
+
// Initial event tells the client the stream is alive + carries
|
|
613
|
+
// the current session state so a fresh subscriber can compare
|
|
614
|
+
// against its cached `state` to know whether a missed update
|
|
615
|
+
// happened during the (re)connect.
|
|
616
|
+
res.write("retry: 5000\n\n"); // allow:raw-byte-literal — SSE reconnect-after hint (5s)
|
|
617
|
+
res.write(": connected\n\n");
|
|
618
|
+
|
|
619
|
+
var closed = false;
|
|
620
|
+
var pingTimer = null;
|
|
621
|
+
var unsubscribe = null;
|
|
622
|
+
|
|
623
|
+
function _send(eventName, data) {
|
|
624
|
+
if (closed) return;
|
|
625
|
+
try {
|
|
626
|
+
res.write("event: " + eventName + "\n");
|
|
627
|
+
res.write("data: " + (typeof data === "string" ? data : JSON.stringify(data)) + "\n\n");
|
|
628
|
+
} catch (_e) {
|
|
629
|
+
// Socket already torn down — clean up.
|
|
630
|
+
_cleanup();
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function _cleanup() {
|
|
635
|
+
if (closed) return;
|
|
636
|
+
closed = true;
|
|
637
|
+
if (pingTimer) { clearInterval(pingTimer); pingTimer = null; }
|
|
638
|
+
if (typeof unsubscribe === "function") {
|
|
639
|
+
try { unsubscribe(); } catch (_e) { /* silent-catch: drop-silent — unsubscribe is best-effort cleanup */ }
|
|
640
|
+
}
|
|
641
|
+
try { res.end(); } catch (_e) { /* silent-catch: drop-silent — socket already torn down */ }
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function _pingTick() {
|
|
645
|
+
if (closed) return;
|
|
646
|
+
// RFC 8620 §7.3 — ping payload carries `{ "interval": <N> }` so
|
|
647
|
+
// clients can detect stale connections via interval drift and
|
|
648
|
+
// tell whether the server clamped their requested value.
|
|
649
|
+
var pingPayload = JSON.stringify({ interval: pingN });
|
|
650
|
+
try { res.write("event: ping\ndata: " + pingPayload + "\n\n"); }
|
|
651
|
+
catch (_e) { _cleanup(); }
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Operator-supplied emit-fn — the backend pushes
|
|
655
|
+
// { kind: "StateChange", changed: { <accountId>: { <type>: <state> } } }
|
|
656
|
+
// events into the SSE stream. The listener formats per RFC 8620
|
|
657
|
+
// §7.4 — `event: state` carries the StateChange object body.
|
|
658
|
+
var emitFn = function (event) {
|
|
659
|
+
if (!event || closed) return;
|
|
660
|
+
if (event.kind === "StateChange") {
|
|
661
|
+
_send("state", {
|
|
662
|
+
"@type": "StateChange",
|
|
663
|
+
changed: event.changed || {},
|
|
664
|
+
pushed: event.pushed || undefined,
|
|
665
|
+
});
|
|
666
|
+
if (closeAfter === "state") {
|
|
667
|
+
_cleanup();
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
Promise.resolve()
|
|
673
|
+
.then(function () { return opts.mailStore.subscribePush(actor, types, emitFn); })
|
|
674
|
+
.then(function (unsub) {
|
|
675
|
+
if (closed) {
|
|
676
|
+
if (typeof unsub === "function") { try { unsub(); } catch (_e) { /* silent-catch: drop-silent — unsubscribe is best-effort cleanup */ } }
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
unsubscribe = typeof unsub === "function" ? unsub : null;
|
|
680
|
+
if (!pingDisabled) {
|
|
681
|
+
pingTimer = setInterval(_pingTick, pingN * 1000); // allow:raw-time-literal — seconds → ms conversion // allow:raw-byte-literal — not bytes, time conversion
|
|
682
|
+
if (pingTimer && typeof pingTimer.unref === "function") pingTimer.unref();
|
|
683
|
+
}
|
|
684
|
+
})
|
|
685
|
+
.catch(function (err) {
|
|
686
|
+
_emit("mail.server.jmap.push_subscribe_threw",
|
|
687
|
+
{ error: (err && err.message) || String(err) }, "failure");
|
|
688
|
+
_cleanup();
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
req.on("close", _cleanup);
|
|
692
|
+
req.on("error", _cleanup);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// RFC 8620 §6.1 — blob upload. Operators POST raw bytes to
|
|
696
|
+
// `/jmap/upload/{accountId}` with `Content-Type` set to the
|
|
697
|
+
// blob MIME type. The handler streams the request body into a
|
|
698
|
+
// bounded buffer, calls `mailStore.uploadBlob(actor, accountId,
|
|
699
|
+
// contentType, bytes)`, and returns the JSON descriptor
|
|
700
|
+
// `{ accountId, blobId, type, size }` the client uses in
|
|
701
|
+
// subsequent Email/set / Email/import calls.
|
|
702
|
+
//
|
|
703
|
+
// Path parameters are extracted from the URL; the operator-side
|
|
704
|
+
// HTTP router MUST mount this handler at a prefix that exposes
|
|
705
|
+
// the accountId segment (e.g. `/jmap/upload/:accountId`). The
|
|
706
|
+
// handler defensively re-parses the URL in case the router didn't
|
|
707
|
+
// populate `req.params`.
|
|
708
|
+
var DEFAULT_MAX_BLOB_BYTES = opts.maxBlobBytes || (50 * 1024 * 1024); // allow:raw-byte-literal — 50 MiB default blob upload cap
|
|
709
|
+
// RFC 8620 §1.2 — JMAP `Id` is a non-empty string of < 256 octets in
|
|
710
|
+
// `[A-Za-z0-9_-]`. The earlier shape capped at 64 chars which refused
|
|
711
|
+
// legitimate-shape accounts; widen to the full spec maximum.
|
|
712
|
+
var MAX_JMAP_ID_LEN = 255; // allow:raw-byte-literal — RFC 8620 §1.2 Id max length
|
|
713
|
+
var JMAP_ID_RE = /^[A-Za-z0-9_-]{1,255}$/;
|
|
714
|
+
// Anti-polynomial: bound the URL length BEFORE any regex / split runs
|
|
715
|
+
// (CodeQL flags `\/+` on uncontrolled input). Headers + URL paths in
|
|
716
|
+
// practice stay well under 8 KiB; over-long URLs refuse outright.
|
|
717
|
+
var MAX_URL_LEN = 8192; // allow:raw-byte-literal — 8 KiB URL cap
|
|
718
|
+
|
|
719
|
+
// Strip a query string + walk the path producing non-empty segments,
|
|
720
|
+
// WITHOUT any unbounded regex. Returns an empty array when the URL
|
|
721
|
+
// is over the cap so the caller can refuse with 400.
|
|
722
|
+
function _splitPathSegments(rawUrl) {
|
|
723
|
+
if (typeof rawUrl !== "string" || rawUrl.length === 0 || rawUrl.length > MAX_URL_LEN) {
|
|
724
|
+
return [];
|
|
725
|
+
}
|
|
726
|
+
var qIdx = rawUrl.indexOf("?");
|
|
727
|
+
var pathOnly = qIdx === -1 ? rawUrl : rawUrl.slice(0, qIdx);
|
|
728
|
+
var out = [];
|
|
729
|
+
var cur = "";
|
|
730
|
+
for (var i = 0; i < pathOnly.length; i += 1) {
|
|
731
|
+
var ch = pathOnly.charCodeAt(i);
|
|
732
|
+
if (ch === 0x2f) { // allow:raw-byte-literal — '/' (0x2f)
|
|
733
|
+
if (cur.length > 0) { out.push(cur); cur = ""; }
|
|
734
|
+
} else {
|
|
735
|
+
cur += pathOnly[i];
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
if (cur.length > 0) out.push(cur);
|
|
739
|
+
return out;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function uploadHandler(req, res) {
|
|
743
|
+
var actor = req.user || (req.actor || null);
|
|
744
|
+
if (!actor) {
|
|
745
|
+
res.statusCode = 401;
|
|
746
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
747
|
+
res.end(JSON.stringify({
|
|
748
|
+
type: "urn:ietf:params:jmap:error:forbidden",
|
|
749
|
+
description: "Authentication required",
|
|
750
|
+
}));
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
if (typeof opts.mailStore.uploadBlob !== "function") {
|
|
754
|
+
res.statusCode = 503;
|
|
755
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
756
|
+
res.end(JSON.stringify({
|
|
757
|
+
type: "urn:ietf:params:jmap:error:serverUnavailable",
|
|
758
|
+
description: "Upload backend not configured (mailStore.uploadBlob)",
|
|
759
|
+
}));
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
// Extract accountId from URL path. The mount path is
|
|
763
|
+
// `/jmap/upload/{accountId}`; the operator's router may strip
|
|
764
|
+
// the `/jmap/upload/` prefix (so segments == [accountId]) OR
|
|
765
|
+
// pass through the full path. Either shape gives the trailing
|
|
766
|
+
// segment as accountId — but the WHOLE URL must split cleanly
|
|
767
|
+
// (`_splitPathSegments` refuses over-long input).
|
|
768
|
+
var segments = _splitPathSegments(req.url);
|
|
769
|
+
if (segments.length === 0) {
|
|
770
|
+
res.statusCode = 400;
|
|
771
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
772
|
+
res.end(JSON.stringify({
|
|
773
|
+
type: "urn:ietf:params:jmap:error:invalidArguments",
|
|
774
|
+
description: "Upload URL is empty or exceeds the " + MAX_URL_LEN + "-byte cap",
|
|
775
|
+
}));
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
var accountId = (req.params && req.params.accountId) || segments[segments.length - 1] || "";
|
|
779
|
+
if (!accountId || accountId.length > MAX_JMAP_ID_LEN || !JMAP_ID_RE.test(accountId)) {
|
|
780
|
+
res.statusCode = 400;
|
|
781
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
782
|
+
res.end(JSON.stringify({
|
|
783
|
+
type: "urn:ietf:params:jmap:error:invalidArguments",
|
|
784
|
+
description: "Upload URL missing or malformed accountId path segment (JMAP Id: [A-Za-z0-9_-]{1," + MAX_JMAP_ID_LEN + "})",
|
|
785
|
+
}));
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
var contentType = req.headers && req.headers["content-type"]
|
|
789
|
+
? String(req.headers["content-type"]).split(";")[0].trim()
|
|
790
|
+
: "application/octet-stream";
|
|
791
|
+
var collector = safeBuffer.boundedChunkCollector({
|
|
792
|
+
maxBytes: DEFAULT_MAX_BLOB_BYTES,
|
|
793
|
+
errorClass: MailServerJmapError,
|
|
794
|
+
sizeCode: "mail-server-jmap/blob-too-large",
|
|
795
|
+
sizeMessage: "Blob exceeds maxSizeUpload (" + DEFAULT_MAX_BLOB_BYTES + " bytes)",
|
|
796
|
+
});
|
|
797
|
+
var refused = false;
|
|
798
|
+
|
|
799
|
+
req.on("data", function (chunk) {
|
|
800
|
+
if (refused) return;
|
|
801
|
+
try { collector.push(chunk); }
|
|
802
|
+
catch (_e) {
|
|
803
|
+
refused = true;
|
|
804
|
+
res.statusCode = 413;
|
|
805
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
806
|
+
res.end(JSON.stringify({
|
|
807
|
+
type: "urn:ietf:params:jmap:error:limit",
|
|
808
|
+
limit: "maxSizeUpload",
|
|
809
|
+
description: "Blob exceeds maxSizeUpload (" + DEFAULT_MAX_BLOB_BYTES + " bytes)",
|
|
810
|
+
}));
|
|
811
|
+
try { req.destroy(); } catch (_e2) { /* silent-catch: socket already torn down */ }
|
|
812
|
+
}
|
|
813
|
+
});
|
|
814
|
+
req.on("end", function () {
|
|
815
|
+
if (refused) return;
|
|
816
|
+
var bytes = collector.result();
|
|
817
|
+
Promise.resolve()
|
|
818
|
+
.then(function () { return opts.mailStore.uploadBlob(actor, accountId, contentType, bytes); })
|
|
819
|
+
.then(function (meta) {
|
|
820
|
+
if (!meta || typeof meta !== "object" || typeof meta.blobId !== "string") {
|
|
821
|
+
throw new MailServerJmapError("mail-server-jmap/bad-upload-result",
|
|
822
|
+
"uploadBlob backend MUST return { blobId, type?, size? }");
|
|
823
|
+
}
|
|
824
|
+
res.statusCode = 201; // allow:raw-byte-literal — HTTP 201 Created
|
|
825
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
826
|
+
res.end(JSON.stringify({
|
|
827
|
+
accountId: accountId,
|
|
828
|
+
blobId: meta.blobId,
|
|
829
|
+
type: meta.type || contentType,
|
|
830
|
+
size: typeof meta.size === "number" ? meta.size : bytes.length,
|
|
831
|
+
}));
|
|
832
|
+
})
|
|
833
|
+
.catch(function (err) {
|
|
834
|
+
_emit("mail.server.jmap.upload_threw",
|
|
835
|
+
{ accountId: accountId, error: (err && err.message) || String(err) }, "failure");
|
|
836
|
+
res.statusCode = 500;
|
|
837
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
838
|
+
res.end(JSON.stringify({
|
|
839
|
+
type: "urn:ietf:params:jmap:error:serverFail",
|
|
840
|
+
description: "Upload failed",
|
|
841
|
+
}));
|
|
842
|
+
});
|
|
843
|
+
});
|
|
844
|
+
req.on("error", function () {
|
|
845
|
+
if (!refused) {
|
|
846
|
+
refused = true;
|
|
847
|
+
try { res.statusCode = 400; res.end(); } // allow:raw-byte-literal — HTTP 400
|
|
848
|
+
catch (_e) { /* silent-catch: socket already torn down */ }
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// RFC 8620 §6.2 — blob download. GET `/jmap/download/{accountId}/
|
|
854
|
+
// {blobId}/{name}?accept={type}`. Backend hook returns a stream-
|
|
855
|
+
// shaped buffer (Buffer or async-iterable) + the canonical MIME
|
|
856
|
+
// type; the handler pipes it to the response.
|
|
857
|
+
function downloadHandler(req, res) {
|
|
858
|
+
var actor = req.user || (req.actor || null);
|
|
859
|
+
if (!actor) {
|
|
860
|
+
res.statusCode = 401;
|
|
861
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
862
|
+
res.end(JSON.stringify({
|
|
863
|
+
type: "urn:ietf:params:jmap:error:forbidden",
|
|
864
|
+
description: "Authentication required",
|
|
865
|
+
}));
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
if (typeof opts.mailStore.downloadBlob !== "function") {
|
|
869
|
+
res.statusCode = 503;
|
|
870
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
871
|
+
res.end(JSON.stringify({
|
|
872
|
+
type: "urn:ietf:params:jmap:error:serverUnavailable",
|
|
873
|
+
description: "Download backend not configured (mailStore.downloadBlob)",
|
|
874
|
+
}));
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
var rawUrl = String(req.url || "");
|
|
878
|
+
if (rawUrl.length > MAX_URL_LEN) {
|
|
879
|
+
res.statusCode = 400;
|
|
880
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
881
|
+
res.end(JSON.stringify({
|
|
882
|
+
type: "urn:ietf:params:jmap:error:invalidArguments",
|
|
883
|
+
description: "Download URL exceeds the " + MAX_URL_LEN + "-byte cap",
|
|
884
|
+
}));
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
var qIdx2 = rawUrl.indexOf("?");
|
|
888
|
+
var query = qIdx2 === -1 ? "" : rawUrl.slice(qIdx2 + 1);
|
|
889
|
+
var acceptType = "";
|
|
890
|
+
query.split("&").forEach(function (pair) {
|
|
891
|
+
if (!pair) return;
|
|
892
|
+
var eq = pair.indexOf("=");
|
|
893
|
+
var k = eq === -1 ? pair : pair.slice(0, eq);
|
|
894
|
+
var v = eq === -1 ? "" : pair.slice(eq + 1);
|
|
895
|
+
if (k === "accept") {
|
|
896
|
+
try { acceptType = decodeURIComponent(v); } catch (_e) { /* silent-catch: malformed % encoding */ }
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
// Path parsing — `/jmap/download/{accountId}/{blobId}/{name}`. The
|
|
900
|
+
// operator's router may strip the `/jmap/download/` prefix, so
|
|
901
|
+
// valid segment counts are EXACTLY 3 (router-stripped) OR 5+ AND
|
|
902
|
+
// starting with `jmap` + `download`. Anything else refuses BEFORE
|
|
903
|
+
// a tail-segment remap could land path tokens in the wrong
|
|
904
|
+
// accountId / blobId / name slots.
|
|
905
|
+
var pathSegs = _splitPathSegments(rawUrl);
|
|
906
|
+
var routerSupplied = req.params && req.params.accountId && req.params.blobId && req.params.name;
|
|
907
|
+
var accountId, blobId, fileName;
|
|
908
|
+
if (routerSupplied) {
|
|
909
|
+
accountId = req.params.accountId;
|
|
910
|
+
blobId = req.params.blobId;
|
|
911
|
+
fileName = req.params.name;
|
|
912
|
+
} else if (pathSegs.length === 3) {
|
|
913
|
+
accountId = pathSegs[0];
|
|
914
|
+
blobId = pathSegs[1];
|
|
915
|
+
fileName = pathSegs[2];
|
|
916
|
+
} else if (pathSegs.length >= 5 &&
|
|
917
|
+
pathSegs[pathSegs.length - 5].toLowerCase() === "jmap" &&
|
|
918
|
+
pathSegs[pathSegs.length - 4].toLowerCase() === "download") {
|
|
919
|
+
accountId = pathSegs[pathSegs.length - 3];
|
|
920
|
+
blobId = pathSegs[pathSegs.length - 2];
|
|
921
|
+
fileName = pathSegs[pathSegs.length - 1];
|
|
922
|
+
} else {
|
|
923
|
+
res.statusCode = 400;
|
|
924
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
925
|
+
res.end(JSON.stringify({
|
|
926
|
+
type: "urn:ietf:params:jmap:error:invalidArguments",
|
|
927
|
+
description: "Download URL must be /jmap/download/{accountId}/{blobId}/{name} (or router-stripped {accountId}/{blobId}/{name})",
|
|
928
|
+
}));
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
if (!accountId || accountId.length > MAX_JMAP_ID_LEN || !JMAP_ID_RE.test(accountId)) {
|
|
932
|
+
res.statusCode = 400;
|
|
933
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
934
|
+
res.end(JSON.stringify({
|
|
935
|
+
type: "urn:ietf:params:jmap:error:invalidArguments",
|
|
936
|
+
description: "Download URL has malformed accountId segment (JMAP Id: [A-Za-z0-9_-]{1," + MAX_JMAP_ID_LEN + "})",
|
|
937
|
+
}));
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
if (!blobId || blobId.length > MAX_JMAP_ID_LEN || !JMAP_ID_RE.test(blobId)) {
|
|
941
|
+
res.statusCode = 400;
|
|
942
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
943
|
+
res.end(JSON.stringify({
|
|
944
|
+
type: "urn:ietf:params:jmap:error:invalidArguments",
|
|
945
|
+
description: "Download URL has malformed blobId segment (JMAP Id: [A-Za-z0-9_-]{1," + MAX_JMAP_ID_LEN + "})",
|
|
946
|
+
}));
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
Promise.resolve()
|
|
950
|
+
.then(function () { return opts.mailStore.downloadBlob(actor, accountId, blobId); })
|
|
951
|
+
.then(function (result) {
|
|
952
|
+
if (!result || (typeof result !== "object" && !Buffer.isBuffer(result))) {
|
|
953
|
+
res.statusCode = 404;
|
|
954
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
955
|
+
res.end(JSON.stringify({
|
|
956
|
+
type: "urn:ietf:params:jmap:error:invalidArguments",
|
|
957
|
+
description: "Blob not found",
|
|
958
|
+
}));
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
var bytes = Buffer.isBuffer(result) ? result : result.bytes;
|
|
962
|
+
var bType = result.type || acceptType || "application/octet-stream";
|
|
963
|
+
if (!Buffer.isBuffer(bytes)) {
|
|
964
|
+
res.statusCode = 500;
|
|
965
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
966
|
+
res.end(JSON.stringify({
|
|
967
|
+
type: "urn:ietf:params:jmap:error:serverFail",
|
|
968
|
+
description: "downloadBlob backend returned a non-Buffer body",
|
|
969
|
+
}));
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
res.statusCode = 200;
|
|
973
|
+
res.setHeader("Content-Type", bType);
|
|
974
|
+
res.setHeader("Content-Length", bytes.length);
|
|
975
|
+
// RFC 5987 — operator may want to surface fileName via
|
|
976
|
+
// Content-Disposition. Default to attachment when the
|
|
977
|
+
// download is a non-text type.
|
|
978
|
+
if (fileName && /^[A-Za-z0-9._-]{1,200}$/.test(fileName)) {
|
|
979
|
+
res.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
|
980
|
+
}
|
|
981
|
+
res.end(bytes);
|
|
982
|
+
})
|
|
983
|
+
.catch(function (err) {
|
|
984
|
+
_emit("mail.server.jmap.download_threw",
|
|
985
|
+
{ accountId: accountId, blobId: blobId, error: (err && err.message) || String(err) }, "failure");
|
|
986
|
+
res.statusCode = 500;
|
|
987
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
988
|
+
res.end(JSON.stringify({
|
|
989
|
+
type: "urn:ietf:params:jmap:error:serverFail",
|
|
990
|
+
description: "Download failed",
|
|
991
|
+
}));
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// RFC 8887 — JMAP over WebSocket. The session-resource's `webSocketUrl`
|
|
996
|
+
// points at this handler. Client opens a WS connection with the `jmap`
|
|
997
|
+
// subprotocol; bidirectional JSON frames carry `{ "@type": "Request" }`
|
|
998
|
+
// / `{ "@type": "WebSocketPushEnable" }` / `{ "@type":
|
|
999
|
+
// "WebSocketPushDisable" }` from the client, and `{ "@type":
|
|
1000
|
+
// "Response" }` / `{ "@type": "StateChange" }` / `{ "@type":
|
|
1001
|
+
// "RequestError" }` from the server.
|
|
1002
|
+
function webSocketHandler(req, socket, head) {
|
|
1003
|
+
var actor = req.user || (req.actor || null);
|
|
1004
|
+
if (!actor) {
|
|
1005
|
+
try { socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n"); socket.destroy(); }
|
|
1006
|
+
catch (_e) { /* silent-catch: socket already torn down */ }
|
|
1007
|
+
return null;
|
|
1008
|
+
}
|
|
1009
|
+
var conn = websocket.handleUpgrade(req, socket, head, {
|
|
1010
|
+
subprotocols: ["jmap"],
|
|
1011
|
+
origins: opts.webSocketOrigins || null,
|
|
1012
|
+
maxMessageBytes: opts.webSocketMaxMessageBytes || (10 * 1024 * 1024), // allow:raw-byte-literal — 10 MiB JMAP WS message cap
|
|
1013
|
+
// permessage-deflate is off by default — same CRIME-class threat
|
|
1014
|
+
// model as the IMAP COMPRESS=DEFLATE intentional skip in v0.11.28.
|
|
1015
|
+
// Operators opt in via opts.webSocketPermessageDeflate.
|
|
1016
|
+
permessageDeflate: opts.webSocketPermessageDeflate === true,
|
|
1017
|
+
});
|
|
1018
|
+
if (!conn) return null;
|
|
1019
|
+
// RFC 8887 §3.1 — server MUST select `jmap` if offered. Refuse the
|
|
1020
|
+
// connection cleanly if subprotocol negotiation came back null.
|
|
1021
|
+
if (conn.subprotocol !== "jmap") {
|
|
1022
|
+
try { conn.close(1002, "RFC 8887 requires Sec-WebSocket-Protocol: jmap"); } // allow:raw-byte-literal — RFC 6455 protocol-error close code
|
|
1023
|
+
catch (_e) { /* silent-catch: closed */ }
|
|
1024
|
+
return null;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
var pushUnsubscribe = null;
|
|
1028
|
+
var pushEnabled = false;
|
|
1029
|
+
var pushSetupPromise = null;
|
|
1030
|
+
var connClosed = false;
|
|
1031
|
+
|
|
1032
|
+
function _sendJson(obj) {
|
|
1033
|
+
try { conn.send(JSON.stringify(obj)); }
|
|
1034
|
+
catch (_e) { /* silent-catch: socket already torn down */ }
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function _sendRequestError(requestId, type, description) {
|
|
1038
|
+
_sendJson({
|
|
1039
|
+
"@type": "RequestError",
|
|
1040
|
+
requestId: requestId || null,
|
|
1041
|
+
type: type,
|
|
1042
|
+
description: description,
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
conn.on("message", function (data, isBinary) {
|
|
1047
|
+
if (isBinary) {
|
|
1048
|
+
_sendRequestError(null,
|
|
1049
|
+
"urn:ietf:params:jmap:error:notJSON",
|
|
1050
|
+
"WebSocket frame must be a JSON text frame (RFC 8887 §4)");
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
var text = data.toString("utf8");
|
|
1054
|
+
if (text.length > (opts.webSocketMaxMessageBytes || (10 * 1024 * 1024))) { // allow:raw-byte-literal — mirrors handleUpgrade cap
|
|
1055
|
+
_sendRequestError(null,
|
|
1056
|
+
"urn:ietf:params:jmap:error:limit",
|
|
1057
|
+
"WebSocket message exceeds maxSizeRequest");
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
var parsed;
|
|
1061
|
+
try { parsed = safeJson.parse(text, { maxBytes: opts.webSocketMaxMessageBytes || (10 * 1024 * 1024) }); } // allow:raw-byte-literal — mirrors handleUpgrade cap
|
|
1062
|
+
catch (_e) {
|
|
1063
|
+
_sendRequestError(null,
|
|
1064
|
+
"urn:ietf:params:jmap:error:notJSON",
|
|
1065
|
+
"WebSocket frame is not valid JSON");
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
var type = parsed && parsed["@type"];
|
|
1069
|
+
var requestId = parsed && parsed.id;
|
|
1070
|
+
|
|
1071
|
+
if (type === "Request") {
|
|
1072
|
+
// RFC 8887 §4 — `Request` carries the same body as the HTTP
|
|
1073
|
+
// POST: `{ using, methodCalls, createdIds? }`. Dispatch
|
|
1074
|
+
// through the existing dispatch path; response is wrapped in
|
|
1075
|
+
// `{ "@type": "Response", requestId, methodResponses, createdIds? }`.
|
|
1076
|
+
// EXCEPT when dispatch returns a refusal shape — request-
|
|
1077
|
+
// level validation failure (`{ type, description,
|
|
1078
|
+
// methodResponses: [] }`) — those MUST surface as
|
|
1079
|
+
// `{ "@type": "RequestError" }` so the client can distinguish
|
|
1080
|
+
// an invalid request from a valid empty-result Response.
|
|
1081
|
+
Promise.resolve()
|
|
1082
|
+
.then(function () { return dispatch(actor, parsed); })
|
|
1083
|
+
.then(function (rv) {
|
|
1084
|
+
if (rv && typeof rv.type === "string" && typeof rv.description === "string") {
|
|
1085
|
+
_sendRequestError(requestId, rv.type, rv.description);
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
_sendJson({
|
|
1089
|
+
"@type": "Response",
|
|
1090
|
+
requestId: requestId,
|
|
1091
|
+
methodResponses: rv.methodResponses,
|
|
1092
|
+
sessionState: rv.sessionState,
|
|
1093
|
+
createdIds: rv.createdIds,
|
|
1094
|
+
});
|
|
1095
|
+
})
|
|
1096
|
+
.catch(function (err) {
|
|
1097
|
+
_sendRequestError(requestId,
|
|
1098
|
+
(err && err.code) || "urn:ietf:params:jmap:error:serverFail",
|
|
1099
|
+
(err && err.message) || "Dispatch failed");
|
|
1100
|
+
});
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
if (type === "WebSocketPushEnable") {
|
|
1105
|
+
if (typeof opts.mailStore.subscribePush !== "function") {
|
|
1106
|
+
_sendRequestError(null,
|
|
1107
|
+
"urn:ietf:params:jmap:error:serverUnavailable",
|
|
1108
|
+
"Push subscribe backend not configured (mailStore.subscribePush)");
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
// RFC 8887 §5 — duplicate enable is a no-op. Also refuse
|
|
1112
|
+
// mid-subscription concurrency: if a previous PushEnable hasn't
|
|
1113
|
+
// resolved yet, the second is treated as no-op. Without this
|
|
1114
|
+
// gate a fast-firing enable/disable/enable sequence could
|
|
1115
|
+
// leak duplicate backend subscriptions OR end up with an
|
|
1116
|
+
// un-unsubscribed handle when connection closes.
|
|
1117
|
+
if (pushEnabled) return;
|
|
1118
|
+
// SYNC flip: gate concurrent PushEnable calls before the
|
|
1119
|
+
// async subscribePush resolves. PushDisable / close that
|
|
1120
|
+
// arrive in the gap see pushEnabled=true + a pending
|
|
1121
|
+
// pushSetupPromise; the setup promise's `then` handles the
|
|
1122
|
+
// late-cleanup case via the connClosed flag.
|
|
1123
|
+
pushEnabled = true;
|
|
1124
|
+
var dataTypes = Array.isArray(parsed.dataTypes) && parsed.dataTypes.length > 0
|
|
1125
|
+
? parsed.dataTypes : null;
|
|
1126
|
+
pushSetupPromise = Promise.resolve()
|
|
1127
|
+
.then(function () {
|
|
1128
|
+
return opts.mailStore.subscribePush(actor, dataTypes, function (event) {
|
|
1129
|
+
if (!event || connClosed) return;
|
|
1130
|
+
if (event.kind === "StateChange") {
|
|
1131
|
+
_sendJson({
|
|
1132
|
+
"@type": "StateChange",
|
|
1133
|
+
changed: event.changed || {},
|
|
1134
|
+
pushed: event.pushed,
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1138
|
+
})
|
|
1139
|
+
.then(function (unsub) {
|
|
1140
|
+
pushUnsubscribe = typeof unsub === "function" ? unsub : null;
|
|
1141
|
+
// Late cleanup: if Disable / close arrived in the setup
|
|
1142
|
+
// gap, run the unsubscribe immediately.
|
|
1143
|
+
if ((connClosed || !pushEnabled) && typeof pushUnsubscribe === "function") {
|
|
1144
|
+
try { pushUnsubscribe(); }
|
|
1145
|
+
catch (_e) { /* silent-catch: drop-silent — unsubscribe is best-effort */ }
|
|
1146
|
+
pushUnsubscribe = null;
|
|
1147
|
+
}
|
|
1148
|
+
})
|
|
1149
|
+
.catch(function (err) {
|
|
1150
|
+
// Setup failed — roll back the sync flip so a retry can
|
|
1151
|
+
// succeed, and surface the error to the operator client.
|
|
1152
|
+
pushEnabled = false;
|
|
1153
|
+
_sendRequestError(null,
|
|
1154
|
+
"urn:ietf:params:jmap:error:serverFail",
|
|
1155
|
+
(err && err.message) || "subscribePush threw");
|
|
1156
|
+
});
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
if (type === "WebSocketPushDisable") {
|
|
1161
|
+
// Mark disabled first so an in-flight subscribePush sees
|
|
1162
|
+
// pushEnabled=false in its late-cleanup branch.
|
|
1163
|
+
pushEnabled = false;
|
|
1164
|
+
if (typeof pushUnsubscribe === "function") {
|
|
1165
|
+
try { pushUnsubscribe(); }
|
|
1166
|
+
catch (_e) { /* silent-catch: drop-silent — unsubscribe is best-effort */ }
|
|
1167
|
+
}
|
|
1168
|
+
pushUnsubscribe = null;
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
_sendRequestError(requestId,
|
|
1173
|
+
"urn:ietf:params:jmap:error:unknownDataType",
|
|
1174
|
+
"Unknown WebSocket frame @type '" + type + "' (RFC 8887 §4)");
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
conn.on("close", function () {
|
|
1178
|
+
// SYNC flip — an in-flight subscribePush.then() observes
|
|
1179
|
+
// connClosed=true and runs the late-cleanup unsubscribe path.
|
|
1180
|
+
connClosed = true;
|
|
1181
|
+
pushEnabled = false;
|
|
1182
|
+
if (typeof pushUnsubscribe === "function") {
|
|
1183
|
+
try { pushUnsubscribe(); }
|
|
1184
|
+
catch (_e) { /* silent-catch: drop-silent */ }
|
|
1185
|
+
}
|
|
1186
|
+
pushUnsubscribe = null;
|
|
1187
|
+
});
|
|
1188
|
+
void pushSetupPromise;
|
|
1189
|
+
|
|
1190
|
+
return conn;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
function discoveryHandler(req, res) {
|
|
1194
|
+
// RFC 8620 §2.2 — well-known endpoint redirects (or directly returns)
|
|
1195
|
+
// the session URL. We redirect to /jmap/session per the most common
|
|
1196
|
+
// pattern; operators with a non-root mount path override via
|
|
1197
|
+
// opts.sessionUrl.
|
|
1198
|
+
res.statusCode = 302;
|
|
1199
|
+
res.setHeader("Location", opts.sessionUrl || "/jmap/session");
|
|
1200
|
+
res.end();
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
return {
|
|
1204
|
+
create: create,
|
|
1205
|
+
dispatch: dispatch,
|
|
1206
|
+
apiHandler: apiHandler,
|
|
1207
|
+
sessionHandler: sessionHandler,
|
|
1208
|
+
discoveryHandler: discoveryHandler,
|
|
1209
|
+
eventSourceHandler: eventSourceHandler,
|
|
1210
|
+
uploadHandler: uploadHandler,
|
|
1211
|
+
downloadHandler: downloadHandler,
|
|
1212
|
+
webSocketHandler: webSocketHandler,
|
|
1213
|
+
MailServerJmapError: MailServerJmapError,
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
/**
|
|
1218
|
+
* @primitive b.mail.server.jmap.emailSubmissionSetHandler
|
|
1219
|
+
* @signature b.mail.server.jmap.emailSubmissionSetHandler(opts)
|
|
1220
|
+
* @since 0.11.38
|
|
1221
|
+
* @status stable
|
|
1222
|
+
* @related b.mail.server.jmap.create
|
|
1223
|
+
* @compliance gdpr, soc2
|
|
1224
|
+
*
|
|
1225
|
+
* Reference implementation of JMAP `EmailSubmission/set` (RFC 8621 §7.5)
|
|
1226
|
+
* that composes `b.mail.send.deliver`. Returns an async method-handler
|
|
1227
|
+
* suitable for plumbing into `b.mail.server.jmap.create({ methods: ... })`.
|
|
1228
|
+
*
|
|
1229
|
+
* The handler:
|
|
1230
|
+
*
|
|
1231
|
+
* 1. Walks `args.create` per RFC 8621 §7.5. For each EmailSubmission:
|
|
1232
|
+
* - Refuses `identityId` not registered in `opts.identities(accountId)`.
|
|
1233
|
+
* - Refuses `emailId` absent — calls `opts.lookupEmail(emailId,
|
|
1234
|
+
* accountId, actor)` to fetch the RFC 822 blob (refuses
|
|
1235
|
+
* `emailNotFound` when null).
|
|
1236
|
+
* - Refuses missing or oversize `envelope.rcptTo` (max 1000 per
|
|
1237
|
+
* the same recipient cap `b.mail.send.deliver` enforces).
|
|
1238
|
+
* - Validates `envelope.mailFrom.email` matches the identity's
|
|
1239
|
+
* authorized addresses (`forbiddenMailFrom` per RFC 8621
|
|
1240
|
+
* §7.5.1.2 when not).
|
|
1241
|
+
* 2. Hands the RFC 822 blob to the supplied `opts.deliver(envelope)`
|
|
1242
|
+
* (a `b.mail.send.deliver.create()` instance).
|
|
1243
|
+
* 3. Maps `deliver`'s `{ delivered, deferred, failed }` result into
|
|
1244
|
+
* JMAP `deliveryStatus` (`recipient → { smtpReply, delivered,
|
|
1245
|
+
* displayed }` per RFC 8621 §7.4).
|
|
1246
|
+
* 4. Calls `opts.onCreated(subId, submission, accountId)` so the
|
|
1247
|
+
* operator can persist the EmailSubmission record (state survives
|
|
1248
|
+
* across JMAP requests via `EmailSubmission/get`).
|
|
1249
|
+
*
|
|
1250
|
+
* `args.destroy` removes EmailSubmission records via
|
|
1251
|
+
* `opts.onDestroyed(subId, accountId)` — the delivery itself cannot
|
|
1252
|
+
* be unsent at this point; `destroy` only removes the JMAP-visible
|
|
1253
|
+
* record.
|
|
1254
|
+
*
|
|
1255
|
+
* `args.update` is honored only for the `undoStatus: "canceled"`
|
|
1256
|
+
* transition per RFC 8621 §7.5.2 (operators with a queue-based
|
|
1257
|
+
* deferred-send model wire `opts.onCancel(subId, accountId)`; the
|
|
1258
|
+
* reference handler refuses with `cannotUnsend` when no `onCancel`
|
|
1259
|
+
* is configured).
|
|
1260
|
+
*
|
|
1261
|
+
* @opts
|
|
1262
|
+
* deliver: async function (envelope), // b.mail.send.deliver instance (REQUIRED)
|
|
1263
|
+
* lookupEmail: async function (emailId, accountId, actor) → Buffer|null, (REQUIRED)
|
|
1264
|
+
* identities: function (accountId) → [ { id, email, mayDelegate } ], (REQUIRED)
|
|
1265
|
+
* onCreated: async function (subId, submission, accountId), (optional)
|
|
1266
|
+
* onDestroyed: async function (subId, accountId), (optional)
|
|
1267
|
+
* onCancel: async function (subId, accountId) → boolean, (optional — undo support)
|
|
1268
|
+
* maxRecipients: number, // default 1000
|
|
1269
|
+
*
|
|
1270
|
+
* @example
|
|
1271
|
+
* var deliver = b.mail.send.deliver({ hostname: "mta.example.com" });
|
|
1272
|
+
* var emailSubSet = b.mail.server.jmap.emailSubmissionSetHandler({
|
|
1273
|
+
* deliver: deliver,
|
|
1274
|
+
* lookupEmail: async function (emailId, accountId) {
|
|
1275
|
+
* return mailStore.fetchBlob(accountId, emailId);
|
|
1276
|
+
* },
|
|
1277
|
+
* identities: function (accountId) {
|
|
1278
|
+
* return [{ id: "I1", email: "ops@example.com" }];
|
|
1279
|
+
* },
|
|
1280
|
+
* onCreated: async function (id, sub, accountId) { return; },
|
|
1281
|
+
* });
|
|
1282
|
+
*
|
|
1283
|
+
* var jmap = b.mail.server.jmap.create({
|
|
1284
|
+
* mailStore: store,
|
|
1285
|
+
* accountsFor: async function () { return { primaryAccounts: {}, accounts: {} }; },
|
|
1286
|
+
* methods: { "EmailSubmission/set": emailSubSet },
|
|
1287
|
+
* });
|
|
1288
|
+
*/
|
|
1289
|
+
function emailSubmissionSetHandler(opts) {
|
|
1290
|
+
validateOpts.requireObject(opts, "mail.server.jmap.emailSubmissionSetHandler",
|
|
1291
|
+
MailServerJmapError, "mail-server-jmap/bad-opts");
|
|
1292
|
+
if (typeof opts.deliver !== "function") {
|
|
1293
|
+
throw new MailServerJmapError("mail-server-jmap/no-deliver",
|
|
1294
|
+
"emailSubmissionSetHandler: opts.deliver async function is required " +
|
|
1295
|
+
"(compose b.mail.send.deliver.create({ ... }))");
|
|
1296
|
+
}
|
|
1297
|
+
if (typeof opts.lookupEmail !== "function") {
|
|
1298
|
+
throw new MailServerJmapError("mail-server-jmap/no-lookup-email",
|
|
1299
|
+
"emailSubmissionSetHandler: opts.lookupEmail(emailId, accountId, actor) async function is required");
|
|
1300
|
+
}
|
|
1301
|
+
if (typeof opts.identities !== "function") {
|
|
1302
|
+
throw new MailServerJmapError("mail-server-jmap/no-identities",
|
|
1303
|
+
"emailSubmissionSetHandler: opts.identities(accountId) function is required (returns Array<{id,email}>)");
|
|
1304
|
+
}
|
|
1305
|
+
var maxRecipients = opts.maxRecipients || 1000; // allow:raw-byte-literal — recipient cap mirrors b.mail.send.deliver
|
|
1306
|
+
if (typeof maxRecipients !== "number" || !isFinite(maxRecipients) || maxRecipients < 1) {
|
|
1307
|
+
throw new MailServerJmapError("mail-server-jmap/bad-max-recipients",
|
|
1308
|
+
"emailSubmissionSetHandler: opts.maxRecipients MUST be a positive integer");
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
return async function emailSubmissionSet(actor, args, _ctx) {
|
|
1312
|
+
if (!args || typeof args !== "object" || typeof args.accountId !== "string") {
|
|
1313
|
+
throw new MailServerJmapError("urn:ietf:params:jmap:error:invalidArguments",
|
|
1314
|
+
"EmailSubmission/set: accountId is required");
|
|
1315
|
+
}
|
|
1316
|
+
var accountId = args.accountId;
|
|
1317
|
+
var created = {};
|
|
1318
|
+
var notCreated = {};
|
|
1319
|
+
var updated = {};
|
|
1320
|
+
var notUpdated = {};
|
|
1321
|
+
var destroyed = [];
|
|
1322
|
+
var notDestroyed = {};
|
|
1323
|
+
|
|
1324
|
+
// ---- create branch (RFC 8621 §7.5.1) ----------------------------------
|
|
1325
|
+
if (args.create && typeof args.create === "object" && !Array.isArray(args.create)) {
|
|
1326
|
+
var createKeys = Object.keys(args.create);
|
|
1327
|
+
for (var ci = 0; ci < createKeys.length; ci += 1) {
|
|
1328
|
+
var clientId = createKeys[ci];
|
|
1329
|
+
var sub = args.create[clientId];
|
|
1330
|
+
try {
|
|
1331
|
+
var result = await _processCreate(actor, accountId, sub);
|
|
1332
|
+
created[clientId] = result;
|
|
1333
|
+
if (typeof opts.onCreated === "function") {
|
|
1334
|
+
try { await opts.onCreated(result.id, result, accountId); }
|
|
1335
|
+
catch (_e) { /* drop-silent — persistence is operator side-effect */ }
|
|
1336
|
+
}
|
|
1337
|
+
} catch (err) {
|
|
1338
|
+
notCreated[clientId] = _jmapErrorShape(err);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
// ---- update branch (RFC 8621 §7.5.2 — undoStatus="canceled" only) -----
|
|
1344
|
+
if (args.update && typeof args.update === "object" && !Array.isArray(args.update)) {
|
|
1345
|
+
var updateKeys = Object.keys(args.update);
|
|
1346
|
+
for (var ui = 0; ui < updateKeys.length; ui += 1) {
|
|
1347
|
+
var subId = updateKeys[ui];
|
|
1348
|
+
var patch = args.update[subId];
|
|
1349
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
|
|
1350
|
+
notUpdated[subId] = { type: "invalidPatch", description: "patch must be an object" };
|
|
1351
|
+
continue;
|
|
1352
|
+
}
|
|
1353
|
+
var patchKeys = Object.keys(patch);
|
|
1354
|
+
// RFC 8621 §7.5.2 — only `undoStatus` is mutable post-create.
|
|
1355
|
+
var nonUndo = patchKeys.filter(function (k) { return k !== "undoStatus"; });
|
|
1356
|
+
if (nonUndo.length > 0) {
|
|
1357
|
+
notUpdated[subId] = {
|
|
1358
|
+
type: "invalidProperties",
|
|
1359
|
+
properties: nonUndo,
|
|
1360
|
+
description: "only undoStatus may be updated on an EmailSubmission",
|
|
1361
|
+
};
|
|
1362
|
+
continue;
|
|
1363
|
+
}
|
|
1364
|
+
if (patch.undoStatus !== "canceled") {
|
|
1365
|
+
notUpdated[subId] = {
|
|
1366
|
+
type: "invalidProperties",
|
|
1367
|
+
properties: ["undoStatus"],
|
|
1368
|
+
description: "only undoStatus='canceled' is honored",
|
|
1369
|
+
};
|
|
1370
|
+
continue;
|
|
1371
|
+
}
|
|
1372
|
+
if (typeof opts.onCancel !== "function") {
|
|
1373
|
+
notUpdated[subId] = {
|
|
1374
|
+
type: "cannotUnsend",
|
|
1375
|
+
description: "undo not supported (opts.onCancel was not configured)",
|
|
1376
|
+
};
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1379
|
+
try {
|
|
1380
|
+
var ok = await opts.onCancel(subId, accountId);
|
|
1381
|
+
if (ok) updated[subId] = null;
|
|
1382
|
+
else notUpdated[subId] = { type: "cannotUnsend" };
|
|
1383
|
+
} catch (err) {
|
|
1384
|
+
notUpdated[subId] = _jmapErrorShape(err);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// ---- destroy branch (RFC 8621 §7.5.3) ---------------------------------
|
|
1390
|
+
if (Array.isArray(args.destroy)) {
|
|
1391
|
+
for (var di = 0; di < args.destroy.length; di += 1) {
|
|
1392
|
+
var destroyId = args.destroy[di];
|
|
1393
|
+
if (typeof destroyId !== "string" || destroyId.length === 0) {
|
|
1394
|
+
notDestroyed[String(destroyId)] = { type: "invalidArguments" };
|
|
1395
|
+
continue;
|
|
1396
|
+
}
|
|
1397
|
+
if (typeof opts.onDestroyed === "function") {
|
|
1398
|
+
try {
|
|
1399
|
+
await opts.onDestroyed(destroyId, accountId);
|
|
1400
|
+
destroyed.push(destroyId);
|
|
1401
|
+
} catch (err) {
|
|
1402
|
+
notDestroyed[destroyId] = _jmapErrorShape(err);
|
|
1403
|
+
}
|
|
1404
|
+
} else {
|
|
1405
|
+
// No persistence wired — accept the destroy as a noop so the
|
|
1406
|
+
// operator's clients can clean up client-side state.
|
|
1407
|
+
destroyed.push(destroyId);
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
_emit("mail.jmap.emailsubmission.set", {
|
|
1413
|
+
accountId: accountId,
|
|
1414
|
+
created: Object.keys(created).length,
|
|
1415
|
+
notCreated: Object.keys(notCreated).length,
|
|
1416
|
+
updated: Object.keys(updated).length,
|
|
1417
|
+
notUpdated: Object.keys(notUpdated).length,
|
|
1418
|
+
destroyed: destroyed.length,
|
|
1419
|
+
notDestroyed: Object.keys(notDestroyed).length,
|
|
1420
|
+
});
|
|
1421
|
+
|
|
1422
|
+
return {
|
|
1423
|
+
accountId: accountId,
|
|
1424
|
+
oldState: args.ifInState || null,
|
|
1425
|
+
newState: bCrypto.generateToken(16), // allow:raw-byte-literal — opaque state token length
|
|
1426
|
+
created: Object.keys(created).length > 0 ? created : null,
|
|
1427
|
+
notCreated: Object.keys(notCreated).length > 0 ? notCreated : null,
|
|
1428
|
+
updated: Object.keys(updated).length > 0 ? updated : null,
|
|
1429
|
+
notUpdated: Object.keys(notUpdated).length > 0 ? notUpdated : null,
|
|
1430
|
+
destroyed: destroyed.length > 0 ? destroyed : null,
|
|
1431
|
+
notDestroyed: Object.keys(notDestroyed).length > 0 ? notDestroyed : null,
|
|
1432
|
+
};
|
|
1433
|
+
};
|
|
1434
|
+
|
|
1435
|
+
// -------- per-create processing -------------------------------------------
|
|
1436
|
+
async function _processCreate(actor, accountId, sub) {
|
|
1437
|
+
if (!sub || typeof sub !== "object" || Array.isArray(sub)) {
|
|
1438
|
+
throw _err("invalidArguments", "EmailSubmission must be an object");
|
|
1439
|
+
}
|
|
1440
|
+
if (typeof sub.identityId !== "string" || sub.identityId.length === 0) {
|
|
1441
|
+
throw _err("invalidProperties", "identityId is required", ["identityId"]);
|
|
1442
|
+
}
|
|
1443
|
+
if (typeof sub.emailId !== "string" || sub.emailId.length === 0) {
|
|
1444
|
+
throw _err("invalidProperties", "emailId is required", ["emailId"]);
|
|
1445
|
+
}
|
|
1446
|
+
if (!sub.envelope || typeof sub.envelope !== "object" || Array.isArray(sub.envelope)) {
|
|
1447
|
+
throw _err("invalidProperties", "envelope is required", ["envelope"]);
|
|
1448
|
+
}
|
|
1449
|
+
var mailFrom = sub.envelope.mailFrom;
|
|
1450
|
+
if (!mailFrom || typeof mailFrom !== "object" || typeof mailFrom.email !== "string") {
|
|
1451
|
+
throw _err("invalidProperties", "envelope.mailFrom.email is required", ["envelope/mailFrom"]);
|
|
1452
|
+
}
|
|
1453
|
+
if (!Array.isArray(sub.envelope.rcptTo) || sub.envelope.rcptTo.length === 0) {
|
|
1454
|
+
throw _err("noRecipients", "envelope.rcptTo must contain at least one Address");
|
|
1455
|
+
}
|
|
1456
|
+
if (sub.envelope.rcptTo.length > maxRecipients) {
|
|
1457
|
+
throw _err("tooManyRecipients", "rcptTo exceeds " + maxRecipients);
|
|
1458
|
+
}
|
|
1459
|
+
var rcptEmails = [];
|
|
1460
|
+
for (var ri = 0; ri < sub.envelope.rcptTo.length; ri += 1) {
|
|
1461
|
+
var r = sub.envelope.rcptTo[ri];
|
|
1462
|
+
if (!r || typeof r.email !== "string" || r.email.indexOf("@") <= 0) {
|
|
1463
|
+
throw _err("invalidRecipients", "envelope.rcptTo[" + ri + "].email malformed");
|
|
1464
|
+
}
|
|
1465
|
+
rcptEmails.push(r.email);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
// Identity gate (RFC 8621 §7.5.1.2 forbiddenMailFrom / §7.5.1.3 identityNotFound).
|
|
1469
|
+
var identList = opts.identities(accountId) || [];
|
|
1470
|
+
var identity = null;
|
|
1471
|
+
for (var ii = 0; ii < identList.length; ii += 1) {
|
|
1472
|
+
if (identList[ii].id === sub.identityId) { identity = identList[ii]; break; }
|
|
1473
|
+
}
|
|
1474
|
+
if (!identity) {
|
|
1475
|
+
throw _err("identityNotFound", "no identity " + sub.identityId + " for account " + accountId);
|
|
1476
|
+
}
|
|
1477
|
+
if (identity.email && identity.email !== mailFrom.email) {
|
|
1478
|
+
throw _err("forbiddenMailFrom",
|
|
1479
|
+
"envelope.mailFrom.email does not match identity " + identity.id);
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
// Blob lookup (RFC 8621 §7.5.1.4 emailNotFound).
|
|
1483
|
+
var rfc822 = await opts.lookupEmail(sub.emailId, accountId, actor);
|
|
1484
|
+
if (rfc822 == null) {
|
|
1485
|
+
throw _err("emailNotFound", "emailId " + sub.emailId + " not found");
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
// Hand to b.mail.send.deliver.
|
|
1489
|
+
var deliverResult = await opts.deliver({
|
|
1490
|
+
from: mailFrom.email,
|
|
1491
|
+
to: rcptEmails,
|
|
1492
|
+
rfc822: rfc822,
|
|
1493
|
+
});
|
|
1494
|
+
|
|
1495
|
+
// Map deliver result → JMAP deliveryStatus (RFC 8621 §7.4).
|
|
1496
|
+
var deliveryStatus = Object.create(null);
|
|
1497
|
+
var delivered = deliverResult && deliverResult.delivered ? deliverResult.delivered : [];
|
|
1498
|
+
var deferred = deliverResult && deliverResult.deferred ? deliverResult.deferred : [];
|
|
1499
|
+
var failed = deliverResult && deliverResult.failed ? deliverResult.failed : [];
|
|
1500
|
+
for (var ddi = 0; ddi < delivered.length; ddi += 1) {
|
|
1501
|
+
deliveryStatus[delivered[ddi].recipient] = {
|
|
1502
|
+
smtpReply: delivered[ddi].smtpReply || "250 Accepted",
|
|
1503
|
+
delivered: "yes",
|
|
1504
|
+
displayed: "unknown",
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
for (var dfi = 0; dfi < deferred.length; dfi += 1) {
|
|
1508
|
+
deliveryStatus[deferred[dfi].recipient] = {
|
|
1509
|
+
smtpReply: deferred[dfi].smtpReply || "451 Temporary failure",
|
|
1510
|
+
delivered: "queued",
|
|
1511
|
+
displayed: "unknown",
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
for (var ffi = 0; ffi < failed.length; ffi += 1) {
|
|
1515
|
+
deliveryStatus[failed[ffi].recipient] = {
|
|
1516
|
+
smtpReply: failed[ffi].smtpReply || "550 Permanent failure",
|
|
1517
|
+
delivered: "no",
|
|
1518
|
+
displayed: "unknown",
|
|
1519
|
+
};
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
var newId = bCrypto.generateToken(12); // allow:raw-byte-literal — JMAP-server-assigned id
|
|
1523
|
+
return {
|
|
1524
|
+
id: newId,
|
|
1525
|
+
identityId: sub.identityId,
|
|
1526
|
+
emailId: sub.emailId,
|
|
1527
|
+
threadId: sub.threadId || null,
|
|
1528
|
+
envelope: sub.envelope,
|
|
1529
|
+
sendAt: new Date().toISOString(),
|
|
1530
|
+
undoStatus: "final",
|
|
1531
|
+
deliveryStatus: deliveryStatus,
|
|
1532
|
+
dsnBlobIds: [],
|
|
1533
|
+
mdnBlobIds: [],
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
function _err(type, description, properties) {
|
|
1538
|
+
var e = new MailServerJmapError("urn:ietf:params:jmap:error:" + type, description);
|
|
1539
|
+
e._jmapType = type;
|
|
1540
|
+
if (properties) e._jmapProperties = properties;
|
|
1541
|
+
return e;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
function _jmapErrorShape(err) {
|
|
1545
|
+
if (err && err._jmapType) {
|
|
1546
|
+
var shape = { type: err._jmapType };
|
|
1547
|
+
if (err.message) shape.description = err.message;
|
|
1548
|
+
if (err._jmapProperties) shape.properties = err._jmapProperties;
|
|
1549
|
+
return shape;
|
|
1550
|
+
}
|
|
1551
|
+
return { type: "serverFail", description: (err && err.message) || String(err) };
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
function _emit(action, metadata) {
|
|
1555
|
+
try {
|
|
1556
|
+
audit().safeEmit({ action: action, outcome: "success", metadata: metadata || {} });
|
|
1557
|
+
} catch (_e) { /* drop-silent */ }
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
module.exports = {
|
|
1562
|
+
create: create,
|
|
1563
|
+
emailSubmissionSetHandler: emailSubmissionSetHandler,
|
|
1564
|
+
MailServerJmapError: MailServerJmapError,
|
|
1565
|
+
};
|