@blamejs/blamejs-shop 0.5.12 → 0.5.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/lib/asset-manifest.json +1 -1
- package/lib/vendor/MANIFEST.json +632 -416
- package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
- package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
- package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
- package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
- package/lib/vendor/blamejs/.gitignore +2 -0
- package/lib/vendor/blamejs/CHANGELOG.md +122 -0
- package/lib/vendor/blamejs/NOTICE +26 -1
- package/lib/vendor/blamejs/SECURITY.md +1 -1
- package/lib/vendor/blamejs/api-snapshot.json +207 -5
- package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
- package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
- package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
- package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
- package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
- package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
- package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
- package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
- package/lib/vendor/blamejs/index.js +6 -0
- package/lib/vendor/blamejs/lib/a2a.js +4 -4
- package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
- package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
- package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
- package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
- package/lib/vendor/blamejs/lib/archive-read.js +8 -0
- package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
- package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
- package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
- package/lib/vendor/blamejs/lib/audit.js +71 -8
- package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
- package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
- package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
- package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
- package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
- package/lib/vendor/blamejs/lib/backup/index.js +16 -5
- package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
- package/lib/vendor/blamejs/lib/base32.js +21 -0
- package/lib/vendor/blamejs/lib/break-glass.js +19 -10
- package/lib/vendor/blamejs/lib/bundler.js +5 -1
- package/lib/vendor/blamejs/lib/cache-status.js +3 -7
- package/lib/vendor/blamejs/lib/calendar.js +21 -1
- package/lib/vendor/blamejs/lib/cbor.js +12 -1
- package/lib/vendor/blamejs/lib/cert.js +29 -11
- package/lib/vendor/blamejs/lib/cli.js +94 -24
- package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
- package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
- package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
- package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
- package/lib/vendor/blamejs/lib/content-digest.js +2 -1
- package/lib/vendor/blamejs/lib/cookies.js +13 -3
- package/lib/vendor/blamejs/lib/cose.js +31 -16
- package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
- package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
- package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
- package/lib/vendor/blamejs/lib/crypto.js +314 -19
- package/lib/vendor/blamejs/lib/csp.js +11 -3
- package/lib/vendor/blamejs/lib/daemon.js +270 -24
- package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
- package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
- package/lib/vendor/blamejs/lib/db-query.js +34 -7
- package/lib/vendor/blamejs/lib/db.js +18 -6
- package/lib/vendor/blamejs/lib/dbsc.js +17 -0
- package/lib/vendor/blamejs/lib/dev.js +21 -2
- package/lib/vendor/blamejs/lib/dsr.js +157 -102
- package/lib/vendor/blamejs/lib/external-db.js +41 -2
- package/lib/vendor/blamejs/lib/file-upload.js +25 -7
- package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
- package/lib/vendor/blamejs/lib/forms.js +113 -27
- package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
- package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
- package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
- package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
- package/lib/vendor/blamejs/lib/guard-html.js +26 -53
- package/lib/vendor/blamejs/lib/guard-image.js +24 -5
- package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
- package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
- package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
- package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
- package/lib/vendor/blamejs/lib/guard-time.js +1 -1
- package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
- package/lib/vendor/blamejs/lib/html-balance.js +3 -3
- package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
- package/lib/vendor/blamejs/lib/http-client.js +39 -7
- package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
- package/lib/vendor/blamejs/lib/i18n.js +35 -21
- package/lib/vendor/blamejs/lib/incident-report.js +8 -1
- package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
- package/lib/vendor/blamejs/lib/json-path.js +23 -1
- package/lib/vendor/blamejs/lib/jwk.js +20 -3
- package/lib/vendor/blamejs/lib/link-header.js +2 -1
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
- package/lib/vendor/blamejs/lib/log-stream.js +8 -3
- package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
- package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
- package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
- package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
- package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
- package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
- package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
- package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
- package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
- package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
- package/lib/vendor/blamejs/lib/mail.js +15 -5
- package/lib/vendor/blamejs/lib/metrics.js +268 -63
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
- package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
- package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
- package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
- package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
- package/lib/vendor/blamejs/lib/network-dns.js +21 -2
- package/lib/vendor/blamejs/lib/network-tls.js +69 -7
- package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
- package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
- package/lib/vendor/blamejs/lib/outbox.js +1 -1
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
- package/lib/vendor/blamejs/lib/permissions.js +6 -3
- package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
- package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
- package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
- package/lib/vendor/blamejs/lib/pubsub.js +20 -9
- package/lib/vendor/blamejs/lib/queue-local.js +8 -1
- package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
- package/lib/vendor/blamejs/lib/redact.js +54 -0
- package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
- package/lib/vendor/blamejs/lib/restore.js +19 -0
- package/lib/vendor/blamejs/lib/retention.js +12 -4
- package/lib/vendor/blamejs/lib/router.js +60 -6
- package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
- package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
- package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
- package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
- package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
- package/lib/vendor/blamejs/lib/safe-object.js +80 -0
- package/lib/vendor/blamejs/lib/safe-path.js +52 -4
- package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
- package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
- package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
- package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
- package/lib/vendor/blamejs/lib/scheduler.js +8 -1
- package/lib/vendor/blamejs/lib/security-assert.js +6 -6
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
- package/lib/vendor/blamejs/lib/self-update.js +517 -87
- package/lib/vendor/blamejs/lib/server-timing.js +2 -4
- package/lib/vendor/blamejs/lib/session.js +34 -12
- package/lib/vendor/blamejs/lib/sql.js +15 -1
- package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
- package/lib/vendor/blamejs/lib/static.js +55 -13
- package/lib/vendor/blamejs/lib/storage.js +8 -2
- package/lib/vendor/blamejs/lib/subject.js +6 -1
- package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
- package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
- package/lib/vendor/blamejs/lib/tsa.js +34 -13
- package/lib/vendor/blamejs/lib/uri-template.js +8 -1
- package/lib/vendor/blamejs/lib/vault/index.js +13 -0
- package/lib/vendor/blamejs/lib/vc.js +44 -5
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
- package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
- package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
- package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
- package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
- package/lib/vendor/blamejs/lib/watcher.js +89 -17
- package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
- package/lib/vendor/blamejs/lib/webhook.js +12 -2
- package/lib/vendor/blamejs/lib/ws-client.js +32 -1
- package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
- package/lib/vendor/blamejs/package-lock.json +2 -2
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
- package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
- package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
- package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
- package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
- package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
- package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
- package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
- package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
- package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
- package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
- package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
- package/lib/vendor/blamejs/socket.yml +94 -0
- package/lib/vendor/blamejs/test/00-primitives.js +605 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
- package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
- package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
- package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
- package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
- package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
- package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
- package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
- package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
- package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
- package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
- 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 +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
- package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
- package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
- package/lib/vendor/blamejs/test/smoke.js +2 -0
- package/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
- package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
- package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
- package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
- package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
- package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
- package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
- package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
- package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
|
@@ -9,14 +9,47 @@
|
|
|
9
9
|
var helpers = require("../helpers");
|
|
10
10
|
var b = helpers.b;
|
|
11
11
|
var check = helpers.check;
|
|
12
|
+
var fs = helpers.fs;
|
|
13
|
+
var os = helpers.os;
|
|
14
|
+
var path = helpers.path;
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
// A b.db-shaped stub that satisfies create()'s duck-type check
|
|
17
|
+
// (from + prepare + getTableMetadata functions) without booting a real DB —
|
|
18
|
+
// used only by the config-validation cases, which throw before any query runs.
|
|
19
|
+
function _stubDb() {
|
|
20
|
+
return {
|
|
21
|
+
from: function () { return { where: function () { return this; }, select: function () { return this; }, all: function () { return []; } }; },
|
|
22
|
+
prepare: function () { return { all: function () { return []; }, get: function () { return null; } }; },
|
|
23
|
+
getTableMetadata: function () { return {}; },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function _mkTmp(prefix) {
|
|
28
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function _catch(fn) {
|
|
32
|
+
try { fn(); return null; } catch (e) { return e; }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Surface
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
function testSurface() {
|
|
14
40
|
check("tenantQuota.create is fn", typeof b.tenantQuota.create === "function");
|
|
15
41
|
check("tenantQuota.budget is fn", typeof b.tenantQuota.budget === "function");
|
|
16
42
|
check("tenantQuota.instrumentQuery is fn", typeof b.tenantQuota.instrumentQuery === "function");
|
|
17
43
|
check("TenantQuotaError is fn", typeof b.tenantQuota.TenantQuotaError === "function");
|
|
44
|
+
var e = new b.tenantQuota.TenantQuotaError("tenant-quota/test", "t");
|
|
45
|
+
check("TenantQuotaError carries code", e.code === "tenant-quota/test");
|
|
46
|
+
}
|
|
18
47
|
|
|
19
|
-
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// budget() — sliding-window sentry (happy path + boundary)
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
function testBudgetSlidingWindow() {
|
|
20
53
|
var budget = b.tenantQuota.budget({
|
|
21
54
|
tenantField: "tenantId",
|
|
22
55
|
perTenantQpsCap: 2,
|
|
@@ -43,22 +76,135 @@ async function run() {
|
|
|
43
76
|
var snapReset = budget.snapshot("tenant-acme");
|
|
44
77
|
check("reset clears counters", snapReset.calls === 0);
|
|
45
78
|
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
79
|
+
// TRUE sliding window (no fixed-window boundary doubling). maxCalls =
|
|
80
|
+
// floor(qpsCap * window/1s) = 5. Fill 5 near the window's tail, then 1 more
|
|
81
|
+
// just past the nominal reset: a fixed window admits it (~2x burst), a
|
|
82
|
+
// sliding window refuses (trailing window still covers them).
|
|
50
83
|
var sw = b.tenantQuota.budget({ tenantField: "tenantId", perTenantQpsCap: 5, window: 1000, audit: false });
|
|
51
84
|
for (var i = 0; i < 5; i++) sw.observe("t-burst", { now: 900 });
|
|
52
85
|
var threwBoundary = null;
|
|
53
86
|
try { sw.observe("t-burst", { now: 1001 }); } catch (e) { threwBoundary = e; }
|
|
54
87
|
check("sliding window refuses the boundary-straddling burst (not a fixed window)",
|
|
55
88
|
threwBoundary && threwBoundary.code === "tenant-quota/budget-exceeded");
|
|
56
|
-
// After a full window has elapsed, the old calls scroll out → admitted again
|
|
89
|
+
// After a full window has elapsed, the old calls scroll out → admitted again
|
|
90
|
+
// (advance >= BINS full-clear path in _slide).
|
|
57
91
|
var allowedAfterGap = true;
|
|
58
92
|
try { sw.observe("t-burst", { now: 2600 }); } catch (_e) { allowedAfterGap = false; }
|
|
59
93
|
check("sliding window admits again once the prior calls age out", allowedAfterGap === true);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// budget() — observe defaults, calls-arm breach, in-counters snapshot,
|
|
98
|
+
// sub-window (small-advance) ring slide
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
function testBudgetObserveDefaults() {
|
|
102
|
+
var budget = b.tenantQuota.budget({ tenantField: "tenantId", audit: false });
|
|
103
|
+
|
|
104
|
+
// No info at all → rowsRead defaults to 0, now defaults to wall-clock.
|
|
105
|
+
var d0 = budget.observe("t-default");
|
|
106
|
+
check("observe with no info defaults rowsRead to 0", d0.rowsRead === 0 && d0.calls === 1);
|
|
107
|
+
|
|
108
|
+
// Negative rowsRead is clamped to 0 (the `info.rowsRead >= 0` guard's false arm).
|
|
109
|
+
var d1 = budget.observe("t-default", { rowsRead: -50 });
|
|
110
|
+
check("observe clamps negative rowsRead to 0", d1.rowsRead === 0 && d1.calls === 2);
|
|
111
|
+
|
|
112
|
+
// In-counters snapshot path (distinct from the empty-tenant zero return).
|
|
113
|
+
var snapLive = budget.snapshot("t-default");
|
|
114
|
+
check("snapshot of an observed tenant reports live calls", snapLive.calls === 2);
|
|
115
|
+
|
|
116
|
+
// Calls-arm breach, isolated from the rows arm: maxCalls = floor(1 * 1) = 1,
|
|
117
|
+
// rows cap huge, so the second call trips purely on the call count.
|
|
118
|
+
var callBudget = b.tenantQuota.budget({
|
|
119
|
+
tenantField: "tenantId",
|
|
120
|
+
perTenantQpsCap: 1,
|
|
121
|
+
perTenantTotalRowsRead: 1000000,
|
|
122
|
+
window: 1000,
|
|
123
|
+
audit: false,
|
|
124
|
+
});
|
|
125
|
+
callBudget.observe("t-calls", { now: 500, rowsRead: 0 });
|
|
126
|
+
var threwCalls = null;
|
|
127
|
+
try { callBudget.observe("t-calls", { now: 500, rowsRead: 0 }); }
|
|
128
|
+
catch (e) { threwCalls = e; }
|
|
129
|
+
check("observe throws on the calls arm of the budget (rowsRead well under cap)",
|
|
130
|
+
threwCalls && threwCalls.code === "tenant-quota/budget-exceeded" &&
|
|
131
|
+
/rowsRead=0\//.test(threwCalls.message));
|
|
132
|
+
|
|
133
|
+
// Sub-window ring advance (0 < advance < BINS): observe at bin 0, then a
|
|
134
|
+
// second observe a few bins later shifts the ring without a full clear.
|
|
135
|
+
var slideBudget = b.tenantQuota.budget({ tenantField: "tenantId", window: 1200, audit: false });
|
|
136
|
+
slideBudget.observe("t-slide", { now: 0 });
|
|
137
|
+
var sSlide = slideBudget.observe("t-slide", { now: 300 });
|
|
138
|
+
check("ring slides a few bins without dropping the earlier call",
|
|
139
|
+
sSlide.calls === 2);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// budget() — config validation (every throw branch)
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
|
|
146
|
+
function testBudgetConfigValidation() {
|
|
147
|
+
var nonObj = _catch(function () { return b.tenantQuota.budget(null); });
|
|
148
|
+
check("budget rejects non-object opts",
|
|
149
|
+
nonObj instanceof b.tenantQuota.TenantQuotaError);
|
|
150
|
+
|
|
151
|
+
var unknownKey = _catch(function () {
|
|
152
|
+
return b.tenantQuota.budget({ tenantField: "tenantId", bogus: 1, audit: false });
|
|
153
|
+
});
|
|
154
|
+
check("budget rejects an unknown opt key",
|
|
155
|
+
unknownKey && /unknown option/.test(unknownKey.message));
|
|
156
|
+
|
|
157
|
+
var badField = _catch(function () {
|
|
158
|
+
return b.tenantQuota.budget({ tenantField: "", audit: false });
|
|
159
|
+
});
|
|
160
|
+
check("budget rejects empty tenantField",
|
|
161
|
+
badField && badField.code === "tenant-quota/bad-field");
|
|
162
|
+
|
|
163
|
+
var badQps = _catch(function () {
|
|
164
|
+
return b.tenantQuota.budget({ tenantField: "tenantId", perTenantQpsCap: 0, audit: false });
|
|
165
|
+
});
|
|
166
|
+
check("budget rejects non-positive perTenantQpsCap",
|
|
167
|
+
badQps && badQps.code === "tenant-quota/bad-qps");
|
|
168
|
+
|
|
169
|
+
var infQps = _catch(function () {
|
|
170
|
+
return b.tenantQuota.budget({ tenantField: "tenantId", perTenantQpsCap: Infinity, audit: false });
|
|
171
|
+
});
|
|
172
|
+
check("budget rejects Infinity perTenantQpsCap",
|
|
173
|
+
infQps && infQps.code === "tenant-quota/bad-qps");
|
|
174
|
+
|
|
175
|
+
var badRows = _catch(function () {
|
|
176
|
+
return b.tenantQuota.budget({ tenantField: "tenantId", perTenantTotalRowsRead: -1, audit: false });
|
|
177
|
+
});
|
|
178
|
+
check("budget rejects non-positive perTenantTotalRowsRead",
|
|
179
|
+
badRows && badRows.code === "tenant-quota/bad-rows");
|
|
180
|
+
|
|
181
|
+
var badWindow = _catch(function () {
|
|
182
|
+
return b.tenantQuota.budget({ tenantField: "tenantId", window: 0, audit: false });
|
|
183
|
+
});
|
|
184
|
+
check("budget rejects non-positive window",
|
|
185
|
+
badWindow && badWindow.code === "tenant-quota/bad-window");
|
|
60
186
|
|
|
61
|
-
//
|
|
187
|
+
// observe() input validation — empty tenantId is refused.
|
|
188
|
+
var okBudget = b.tenantQuota.budget({ tenantField: "tenantId", audit: false });
|
|
189
|
+
var badObserve = _catch(function () { return okBudget.observe(""); });
|
|
190
|
+
check("observe rejects empty tenantId",
|
|
191
|
+
badObserve && badObserve.code === "tenant-quota/bad-tenant");
|
|
192
|
+
|
|
193
|
+
// reset() with an explicit tenantId (the delete-one branch) and no-arg
|
|
194
|
+
// (clear-all branch) both no-op cleanly.
|
|
195
|
+
okBudget.observe("t-x");
|
|
196
|
+
okBudget.reset("t-x");
|
|
197
|
+
check("reset(tenantId) clears just that tenant", okBudget.snapshot("t-x").calls === 0);
|
|
198
|
+
okBudget.observe("t-y");
|
|
199
|
+
okBudget.reset();
|
|
200
|
+
check("reset() with no arg clears every tenant", okBudget.snapshot("t-y").calls === 0);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
// instrumentQuery() — isolation breach detection
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
|
|
207
|
+
function testInstrumentQueryBasic() {
|
|
62
208
|
var goodCheck = b.tenantQuota.instrumentQuery({
|
|
63
209
|
rows: [
|
|
64
210
|
{ tenantId: "tenant-a", value: 1 },
|
|
@@ -68,8 +214,8 @@ async function run() {
|
|
|
68
214
|
tenantId: "tenant-a",
|
|
69
215
|
audit: false,
|
|
70
216
|
});
|
|
71
|
-
check("instrumentQuery clean rows → ok",
|
|
72
|
-
check("instrumentQuery clean rows → empty cross",
|
|
217
|
+
check("instrumentQuery clean rows → ok", goodCheck.ok === true);
|
|
218
|
+
check("instrumentQuery clean rows → empty cross", goodCheck.crossover.length === 0);
|
|
73
219
|
|
|
74
220
|
var badCheck = b.tenantQuota.instrumentQuery({
|
|
75
221
|
rows: [
|
|
@@ -80,27 +226,443 @@ async function run() {
|
|
|
80
226
|
tenantId: "tenant-a",
|
|
81
227
|
audit: false,
|
|
82
228
|
});
|
|
83
|
-
check("instrumentQuery crossover detected",
|
|
84
|
-
check("instrumentQuery crossover index recorded",
|
|
229
|
+
check("instrumentQuery crossover detected", badCheck.ok === false);
|
|
230
|
+
check("instrumentQuery crossover index recorded", badCheck.crossover[0].index === 1);
|
|
85
231
|
check("instrumentQuery crossover actual recorded",
|
|
86
232
|
badCheck.crossover[0].actualTenantId === "tenant-b");
|
|
233
|
+
}
|
|
87
234
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
// instrumentQuery() — adversarial / defensive input
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
|
|
239
|
+
function testInstrumentQueryAdversarial() {
|
|
240
|
+
var nullOpts = _catch(function () { return b.tenantQuota.instrumentQuery(null); });
|
|
241
|
+
check("instrumentQuery rejects null opts",
|
|
242
|
+
nullOpts && nullOpts.code === "tenant-quota/bad-instr");
|
|
243
|
+
|
|
244
|
+
var scalarOpts = _catch(function () { return b.tenantQuota.instrumentQuery("nope"); });
|
|
245
|
+
check("instrumentQuery rejects non-object opts",
|
|
246
|
+
scalarOpts && scalarOpts.code === "tenant-quota/bad-instr");
|
|
247
|
+
|
|
248
|
+
var unknownKey = _catch(function () {
|
|
249
|
+
return b.tenantQuota.instrumentQuery({
|
|
250
|
+
rows: [], tenantField: "tenantId", tenantId: "t", surprise: 1, audit: false,
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
check("instrumentQuery rejects an unknown opt key",
|
|
254
|
+
unknownKey && /unknown option/.test(unknownKey.message));
|
|
255
|
+
|
|
256
|
+
var badRows = _catch(function () {
|
|
257
|
+
return b.tenantQuota.instrumentQuery({
|
|
258
|
+
rows: "not-an-array", tenantField: "tenantId", tenantId: "t", audit: false,
|
|
93
259
|
});
|
|
94
|
-
}
|
|
95
|
-
check("
|
|
96
|
-
|
|
260
|
+
});
|
|
261
|
+
check("instrumentQuery rejects non-array rows",
|
|
262
|
+
badRows && badRows.code === "tenant-quota/bad-rows");
|
|
97
263
|
|
|
98
|
-
var
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
264
|
+
var badField = _catch(function () {
|
|
265
|
+
return b.tenantQuota.instrumentQuery({
|
|
266
|
+
rows: [], tenantField: "", tenantId: "t", audit: false,
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
check("instrumentQuery rejects empty tenantField",
|
|
270
|
+
badField && badField.code === "tenant-quota/bad-field");
|
|
271
|
+
|
|
272
|
+
var badTenant = _catch(function () {
|
|
273
|
+
return b.tenantQuota.instrumentQuery({
|
|
274
|
+
rows: [], tenantField: "tenantId", tenantId: "", audit: false,
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
check("instrumentQuery rejects empty tenantId",
|
|
278
|
+
badTenant && badTenant.code === "tenant-quota/bad-tenant");
|
|
279
|
+
|
|
280
|
+
// Defensive row walk: non-object rows (null, scalar) are skipped, and rows
|
|
281
|
+
// whose tenantField is null/undefined are NOT flagged as a crossover.
|
|
282
|
+
var mixed = b.tenantQuota.instrumentQuery({
|
|
283
|
+
rows: [
|
|
284
|
+
null, // skipped (not an object)
|
|
285
|
+
42, // skipped (not an object)
|
|
286
|
+
{ tenantId: null, value: 1 }, // null field → not a crossover
|
|
287
|
+
{ value: 2 }, // missing field → not a crossover
|
|
288
|
+
{ tenantId: "tenant-a", value: 3 }, // matches claim → ok
|
|
289
|
+
],
|
|
290
|
+
tenantField: "tenantId",
|
|
291
|
+
tenantId: "tenant-a",
|
|
292
|
+
audit: false,
|
|
293
|
+
});
|
|
294
|
+
check("instrumentQuery skips non-object rows and null-field rows",
|
|
295
|
+
mixed.ok === true && mixed.crossover.length === 0);
|
|
296
|
+
|
|
297
|
+
// audit-on crossover: exercises the audit().safeEmit + observability branch
|
|
298
|
+
// (default audit:true). The emission is best-effort so it never throws.
|
|
299
|
+
var audited = b.tenantQuota.instrumentQuery({
|
|
300
|
+
rows: [
|
|
301
|
+
{ tenantId: "tenant-a", value: 1 },
|
|
302
|
+
{ tenantId: "tenant-b", value: 2 },
|
|
303
|
+
],
|
|
304
|
+
tenantField: "tenantId",
|
|
305
|
+
tenantId: "tenant-a",
|
|
306
|
+
table: "orders",
|
|
307
|
+
});
|
|
308
|
+
check("instrumentQuery audit-on path still returns the crossover result",
|
|
309
|
+
audited.ok === false && audited.crossover.length === 1);
|
|
310
|
+
|
|
311
|
+
// audit-on crossover WITHOUT a table → exercises the `opts.table || null`
|
|
312
|
+
// fallback in the emitted audit metadata.
|
|
313
|
+
var auditedNoTable = b.tenantQuota.instrumentQuery({
|
|
314
|
+
rows: [
|
|
315
|
+
{ tenantId: "tenant-a", value: 1 },
|
|
316
|
+
{ tenantId: "tenant-b", value: 2 },
|
|
317
|
+
],
|
|
318
|
+
tenantField: "tenantId",
|
|
319
|
+
tenantId: "tenant-a",
|
|
320
|
+
});
|
|
321
|
+
check("instrumentQuery audit-on crossover without a table still reports the breach",
|
|
322
|
+
auditedNoTable.ok === false && auditedNoTable.crossover.length === 1);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ---------------------------------------------------------------------------
|
|
326
|
+
// create() — defensive: db.getTableMetadata() returning null
|
|
327
|
+
// ---------------------------------------------------------------------------
|
|
328
|
+
|
|
329
|
+
async function testEmptyMetadataResolvesNoTables() {
|
|
330
|
+
// getTableMetadata() may legitimately return null (no tables declared yet);
|
|
331
|
+
// the byte walk must fall back to an empty table set, not crash.
|
|
332
|
+
var nullMetaDb = {
|
|
333
|
+
from: function () {
|
|
334
|
+
return { where: function () { return this; }, select: function () { return this; }, all: function () { return []; } };
|
|
335
|
+
},
|
|
336
|
+
prepare: function () { return { all: function () { return []; }, get: function () { return null; } }; },
|
|
337
|
+
getTableMetadata: function () { return null; },
|
|
338
|
+
};
|
|
339
|
+
var quota = b.tenantQuota.create({ db: nullMetaDb, tenantField: "tenantId", audit: false });
|
|
340
|
+
var snap = await quota.snapshot("t-none");
|
|
341
|
+
check("snapshot on a db with null metadata yields zero bytes",
|
|
342
|
+
snap.tenantId === "t-none" && snap.bytesUsed === 0);
|
|
343
|
+
var listed = await quota.list();
|
|
344
|
+
check("list on a db with null metadata is empty",
|
|
345
|
+
Array.isArray(listed) && listed.length === 0);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ---------------------------------------------------------------------------
|
|
349
|
+
// create() — config validation (every throw branch, no DB required)
|
|
350
|
+
// ---------------------------------------------------------------------------
|
|
351
|
+
|
|
352
|
+
function testCreateConfigValidation() {
|
|
353
|
+
var stub = _stubDb();
|
|
354
|
+
|
|
355
|
+
var nonObj = _catch(function () { return b.tenantQuota.create(null); });
|
|
356
|
+
check("create rejects non-object opts",
|
|
357
|
+
nonObj instanceof b.tenantQuota.TenantQuotaError);
|
|
358
|
+
|
|
359
|
+
var unknownKey = _catch(function () {
|
|
360
|
+
return b.tenantQuota.create({ db: stub, tenantField: "tenantId", bogus: 1, audit: false });
|
|
361
|
+
});
|
|
362
|
+
check("create rejects an unknown opt key",
|
|
363
|
+
unknownKey && /unknown option/.test(unknownKey.message));
|
|
364
|
+
|
|
365
|
+
var missingDb = _catch(function () {
|
|
366
|
+
return b.tenantQuota.create({ tenantField: "tenantId", audit: false });
|
|
367
|
+
});
|
|
368
|
+
check("create rejects a missing db handle",
|
|
369
|
+
missingDb && missingDb.code === "tenant-quota/bad-db");
|
|
370
|
+
|
|
371
|
+
var badDb = _catch(function () {
|
|
372
|
+
return b.tenantQuota.create({ db: { foo: 1 }, tenantField: "tenantId", audit: false });
|
|
373
|
+
});
|
|
374
|
+
check("create rejects a non-b.db handle",
|
|
375
|
+
badDb && badDb.code === "tenant-quota/bad-db");
|
|
376
|
+
|
|
377
|
+
var badField = _catch(function () {
|
|
378
|
+
return b.tenantQuota.create({ db: stub, tenantField: "", audit: false });
|
|
379
|
+
});
|
|
102
380
|
check("create rejects empty tenantField",
|
|
103
|
-
|
|
381
|
+
badField && badField.code === "tenant-quota/bad-field");
|
|
382
|
+
|
|
383
|
+
var badCap = _catch(function () {
|
|
384
|
+
return b.tenantQuota.create({ db: stub, tenantField: "tenantId", defaultBytesCap: 0, audit: false });
|
|
385
|
+
});
|
|
386
|
+
check("create rejects non-positive defaultBytesCap",
|
|
387
|
+
badCap && badCap.code === "tenant-quota/bad-cap");
|
|
388
|
+
|
|
389
|
+
var nanCap = _catch(function () {
|
|
390
|
+
return b.tenantQuota.create({ db: stub, tenantField: "tenantId", defaultBytesCap: Number.NaN, audit: false });
|
|
391
|
+
});
|
|
392
|
+
check("create rejects NaN defaultBytesCap",
|
|
393
|
+
nanCap && nanCap.code === "tenant-quota/bad-cap");
|
|
394
|
+
|
|
395
|
+
var arrayPer = _catch(function () {
|
|
396
|
+
return b.tenantQuota.create({ db: stub, tenantField: "tenantId", perTenantBytesCap: [], audit: false });
|
|
397
|
+
});
|
|
398
|
+
check("create rejects an array perTenantBytesCap",
|
|
399
|
+
arrayPer && arrayPer.code === "tenant-quota/bad-per-tenant");
|
|
400
|
+
|
|
401
|
+
var badPerVal = _catch(function () {
|
|
402
|
+
return b.tenantQuota.create({
|
|
403
|
+
db: stub, tenantField: "tenantId",
|
|
404
|
+
perTenantBytesCap: { "t-vip": -5 }, audit: false,
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
check("create rejects a negative per-tenant override",
|
|
408
|
+
badPerVal && badPerVal.code === "tenant-quota/bad-per-tenant");
|
|
409
|
+
|
|
410
|
+
var badTtl = _catch(function () {
|
|
411
|
+
return b.tenantQuota.create({ db: stub, tenantField: "tenantId", cacheTtlMs: -1, audit: false });
|
|
412
|
+
});
|
|
413
|
+
check("create rejects a negative cacheTtlMs",
|
|
414
|
+
badTtl && badTtl.code === "tenant-quota/bad-ttl");
|
|
415
|
+
|
|
416
|
+
// A fully-valid create with a stub db returns the enforcer object; the
|
|
417
|
+
// default-cap / default-ttl / auditOn assignment branches all run here.
|
|
418
|
+
var ok = b.tenantQuota.create({ db: stub, tenantField: "tenantId", audit: false });
|
|
419
|
+
check("create with valid opts returns an enforcer object",
|
|
420
|
+
ok && typeof ok.assert === "function" && typeof ok.snapshot === "function" &&
|
|
421
|
+
typeof ok.list === "function" && typeof ok.invalidate === "function");
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// ---------------------------------------------------------------------------
|
|
425
|
+
// create() — storage-cap lifecycle against a real encrypted DB
|
|
426
|
+
// ---------------------------------------------------------------------------
|
|
427
|
+
|
|
428
|
+
async function testStorageCapLifecycle() {
|
|
429
|
+
var tmpDir = _mkTmp("tenant-quota-");
|
|
430
|
+
try {
|
|
431
|
+
await helpers.setupTestDb(tmpDir, [
|
|
432
|
+
{
|
|
433
|
+
name: "docs",
|
|
434
|
+
columns: {
|
|
435
|
+
_id: "TEXT PRIMARY KEY",
|
|
436
|
+
tenantId: "TEXT",
|
|
437
|
+
body: "TEXT",
|
|
438
|
+
blob: "BLOB",
|
|
439
|
+
},
|
|
440
|
+
indexes: ["tenantId"],
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
// A table WITHOUT the tenantField — auto-detection must skip it.
|
|
444
|
+
name: "sansTenant",
|
|
445
|
+
columns: { _id: "TEXT PRIMARY KEY", label: "TEXT" },
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
// A table with a SEALED column — its on-disk value is a vault
|
|
449
|
+
// envelope far larger than the plaintext it unseals to. The byte
|
|
450
|
+
// count must measure the stored envelope, not the auto-unsealed cell.
|
|
451
|
+
name: "sealed_docs",
|
|
452
|
+
columns: { _id: "TEXT PRIMARY KEY", tenantId: "TEXT", secret: "TEXT" },
|
|
453
|
+
sealedFields: ["secret"],
|
|
454
|
+
indexes: ["tenantId"],
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
// A table whose NAME is a SQL reserved word ("from"). db.from()
|
|
458
|
+
// supports it (quoting neutralizes the keyword), so the storage-byte
|
|
459
|
+
// sum — which builds its own SQL — must quote it with allowReserved
|
|
460
|
+
// too, or snapshot throws sql/reserved-word for a schema-valid table.
|
|
461
|
+
name: "from",
|
|
462
|
+
columns: { _id: "TEXT PRIMARY KEY", tenantId: "TEXT", note: "TEXT" },
|
|
463
|
+
indexes: ["tenantId"],
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
// A table whose tenantField ("tid") is itself a SEALED column with a
|
|
467
|
+
// derived hash. On disk "tid" holds a vault envelope, so a plaintext
|
|
468
|
+
// `WHERE tid = ?` matches nothing; the byte sum must filter by the
|
|
469
|
+
// derived-hash blind index (as db.from().where() does) or the cap
|
|
470
|
+
// silently counts zero for these tenants.
|
|
471
|
+
name: "sealed_tenant",
|
|
472
|
+
columns: { _id: "TEXT PRIMARY KEY", tid: "TEXT", tidHash: "TEXT", note: "TEXT" },
|
|
473
|
+
sealedFields: ["tid"],
|
|
474
|
+
derivedHashes: { tidHash: { from: "tid" } },
|
|
475
|
+
indexes: ["tidHash"],
|
|
476
|
+
},
|
|
477
|
+
]);
|
|
478
|
+
|
|
479
|
+
b.db.from("docs").insertOne({ _id: "d1", tenantId: "t-acme", body: "hello", blob: Buffer.from("ABCD") });
|
|
480
|
+
b.db.from("docs").insertOne({ _id: "d2", tenantId: "t-acme", body: null }); // null col → skipped in the byte walk
|
|
481
|
+
b.db.from("docs").insertOne({ _id: "d3", tenantId: "t-small", body: "x" });
|
|
482
|
+
b.db.from("docs").insertOne({ _id: "d4", tenantId: null, body: "orphan" }); // null tenant → skipped by list()
|
|
483
|
+
b.db.from("sansTenant").insertOne({ _id: "s1", label: "ignore-me" });
|
|
484
|
+
|
|
485
|
+
// Auto-detected tables (walks getTableMetadata for the tenantField).
|
|
486
|
+
var quota = b.tenantQuota.create({
|
|
487
|
+
db: b.db,
|
|
488
|
+
tenantField: "tenantId",
|
|
489
|
+
defaultBytesCap: b.constants.BYTES.gib(1),
|
|
490
|
+
perTenantBytesCap: { "t-acme": b.constants.BYTES.gib(10) },
|
|
491
|
+
audit: false,
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
var snap = await quota.snapshot("t-acme");
|
|
495
|
+
check("snapshot returns the standard shape",
|
|
496
|
+
snap.tenantId === "t-acme" && typeof snap.bytesUsed === "number" &&
|
|
497
|
+
typeof snap.bytesCap === "number" && typeof snap.percent === "number");
|
|
498
|
+
check("snapshot counts textual + buffer bytes across the tenant's rows",
|
|
499
|
+
snap.bytesUsed > 0);
|
|
500
|
+
check("per-tenant override wins over the default cap",
|
|
501
|
+
snap.bytesCap === b.constants.BYTES.gib(10));
|
|
502
|
+
|
|
503
|
+
// Cache-aside: a second snapshot within the TTL returns the cached total
|
|
504
|
+
// even after new rows land; invalidate() forces the recompute.
|
|
505
|
+
var before = snap.bytesUsed;
|
|
506
|
+
b.db.from("docs").insertOne({ _id: "d5", tenantId: "t-acme", body: "more-bytes-here" });
|
|
507
|
+
var cached = await quota.snapshot("t-acme");
|
|
508
|
+
check("snapshot serves the cached byte total inside the TTL",
|
|
509
|
+
cached.bytesUsed === before);
|
|
510
|
+
quota.invalidate("t-acme");
|
|
511
|
+
var recomputed = await quota.snapshot("t-acme");
|
|
512
|
+
check("invalidate(tenantId) forces a recompute that sees the new row",
|
|
513
|
+
recomputed.bytesUsed > before);
|
|
514
|
+
// No-arg invalidate clears the whole cache; the next snapshot recomputes.
|
|
515
|
+
quota.invalidate();
|
|
516
|
+
var afterClear = await quota.snapshot("t-small");
|
|
517
|
+
check("invalidate() with no arg still yields a fresh snapshot",
|
|
518
|
+
afterClear.tenantId === "t-small" && afterClear.bytesUsed > 0);
|
|
519
|
+
|
|
520
|
+
// Default cap applies to a tenant with no override.
|
|
521
|
+
check("tenant without an override uses the default cap",
|
|
522
|
+
afterClear.bytesCap === b.constants.BYTES.gib(1));
|
|
523
|
+
|
|
524
|
+
// assert() under the cap returns the snapshot.
|
|
525
|
+
var okAssert = await quota.assert("t-small");
|
|
526
|
+
check("assert under the cap returns the snapshot", okAssert.tenantId === "t-small");
|
|
527
|
+
|
|
528
|
+
// list() enumerates distinct tenants (skipping the null-tenant orphan row).
|
|
529
|
+
var listed = await quota.list();
|
|
530
|
+
var ids = listed.map(function (s) { return s.tenantId; }).sort();
|
|
531
|
+
check("list() returns a snapshot per distinct tenant",
|
|
532
|
+
ids.length === 2 && ids[0] === "t-acme" && ids[1] === "t-small");
|
|
533
|
+
|
|
534
|
+
// Over-cap refusal: a tiny cap forces assert() to refuse the insert.
|
|
535
|
+
var tightQuota = b.tenantQuota.create({
|
|
536
|
+
db: b.db,
|
|
537
|
+
tenantField: "tenantId",
|
|
538
|
+
defaultBytesCap: 1, // 1 byte — any real row breaches
|
|
539
|
+
cacheTtlMs: 0, // always recompute (miss-branch every call)
|
|
540
|
+
tables: ["docs"], // explicit tables override (skips auto-detect)
|
|
541
|
+
audit: false,
|
|
542
|
+
});
|
|
543
|
+
var threwOver = null;
|
|
544
|
+
try { await tightQuota.assert("t-small"); }
|
|
545
|
+
catch (e) { threwOver = e; }
|
|
546
|
+
check("assert refuses (throws) when the tenant is over its byte cap",
|
|
547
|
+
threwOver && threwOver.code === "tenant-quota/exceeded");
|
|
548
|
+
check("over-cap refusal is a TenantQuotaError",
|
|
549
|
+
threwOver instanceof b.tenantQuota.TenantQuotaError);
|
|
550
|
+
|
|
551
|
+
// snapshot() input validation: empty tenantId is refused.
|
|
552
|
+
var badTenant = null;
|
|
553
|
+
try { await quota.snapshot(""); }
|
|
554
|
+
catch (e) { badTenant = e; }
|
|
555
|
+
check("snapshot rejects empty tenantId",
|
|
556
|
+
badTenant && badTenant.code === "tenant-quota/bad-tenant");
|
|
557
|
+
|
|
558
|
+
// Blob byte-accounting: a BLOB column round-trips as a Uint8Array (not a
|
|
559
|
+
// Node Buffer). Its contribution must be the true byte length, not the
|
|
560
|
+
// decimal-joined String() form. Isolate a tenant whose only non-null cells
|
|
561
|
+
// are _id + tenantId + an 8-byte blob so the total is exact.
|
|
562
|
+
// _id "bd1" (3) + tenantId "t-blob" (6) + blob.byteLength (8) = 17.
|
|
563
|
+
b.db.from("docs").insertOne({ _id: "bd1", tenantId: "t-blob", body: null, blob: Buffer.from("ABCDEFGH") });
|
|
564
|
+
var blobSnap = await quota.snapshot("t-blob");
|
|
565
|
+
check("blob bytes counted by byteLength (not the stringified array)",
|
|
566
|
+
blobSnap.bytesUsed === 3 + 6 + 8);
|
|
567
|
+
|
|
568
|
+
// Sealed-column storage: a sealed cell is stored as a (much larger) vault
|
|
569
|
+
// envelope. The byte count must read the raw stored value, not the ORM's
|
|
570
|
+
// auto-unsealed facade — otherwise a tenant with sealed columns slips far
|
|
571
|
+
// under a storage cap. Insert a tiny plaintext ("x"), then verify the
|
|
572
|
+
// count reflects the full on-disk envelope for that isolated tenant.
|
|
573
|
+
b.db.from("sealed_docs").insertOne({ _id: "sd1", tenantId: "t-sealed", secret: "x" });
|
|
574
|
+
var rawSecret = b.db.prepare('SELECT secret FROM sealed_docs WHERE _id = ?').get("sd1").secret;
|
|
575
|
+
check("sealed column is stored as a vault envelope, not plaintext (precondition)",
|
|
576
|
+
typeof rawSecret === "string" && rawSecret !== "x" && Buffer.byteLength(rawSecret, "utf8") > 20);
|
|
577
|
+
var sealedSnap = await quota.snapshot("t-sealed");
|
|
578
|
+
// _id "sd1" (3) + tenantId "t-sealed" (8) + the raw envelope bytes. The
|
|
579
|
+
// unsealed-plaintext path would count "x" as 1 byte → 12 total, far below.
|
|
580
|
+
check("sealed column counted at its on-disk envelope size, not the unsealed plaintext",
|
|
581
|
+
sealedSnap.bytesUsed === 3 + 8 + Buffer.byteLength(rawSecret, "utf8"));
|
|
582
|
+
|
|
583
|
+
// A reserved-word table name ("from") is schema-valid and queryable via
|
|
584
|
+
// db.from(); snapshot's own SQL must quote it with allowReserved so it
|
|
585
|
+
// does not throw sql/reserved-word. _id "rw1" (3) + tenantId "t-rw" (4)
|
|
586
|
+
// + note "hi" (2) = 9 bytes for this isolated tenant.
|
|
587
|
+
b.db.from("from").insertOne({ _id: "rw1", tenantId: "t-rw", note: "hi" });
|
|
588
|
+
var rwThrew = null, rwSnap = null;
|
|
589
|
+
try { rwSnap = await quota.snapshot("t-rw"); } catch (e) { rwThrew = e; }
|
|
590
|
+
check("snapshot does not throw on a reserved-word table name", rwThrew === null);
|
|
591
|
+
check("reserved-word table rows counted correctly",
|
|
592
|
+
rwSnap && rwSnap.bytesUsed === 3 + 4 + 2);
|
|
593
|
+
|
|
594
|
+
// A schema-qualified table name ("archive.docs") must pass identifier
|
|
595
|
+
// quoting the same way db.from() / b.sql do (they quote "schema"."table").
|
|
596
|
+
// The previous hand-rolled quoteIdentifier treated the dot as part of one
|
|
597
|
+
// name and rejected it with sql/bad-shape before the query ran. The
|
|
598
|
+
// attached "archive" db is absent here, so the query fails with a
|
|
599
|
+
// no-such-table error — the point is that it is NOT rejected at quoting.
|
|
600
|
+
var qualQuota = b.tenantQuota.create({
|
|
601
|
+
db: b.db,
|
|
602
|
+
tenantField: "tenantId",
|
|
603
|
+
tables: ["archive.docs"],
|
|
604
|
+
defaultBytesCap: b.constants.BYTES.gib(1),
|
|
605
|
+
audit: false,
|
|
606
|
+
});
|
|
607
|
+
var qualErr = null;
|
|
608
|
+
try { await qualQuota.snapshot("t-any"); } catch (e) { qualErr = e; }
|
|
609
|
+
check("schema-qualified table name passes identifier quoting (not sql/bad-shape)",
|
|
610
|
+
qualErr === null || qualErr.code !== "sql/bad-shape");
|
|
611
|
+
|
|
612
|
+
// A sealed tenantField: "tid" is sealed on disk, so a plaintext WHERE
|
|
613
|
+
// never matches. snapshot must filter by the derived-hash blind index
|
|
614
|
+
// (as db.from().where() does) — otherwise the cap silently counts zero.
|
|
615
|
+
b.db.from("sealed_tenant").insertOne({ _id: "st1", tid: "tenant-x", note: "data" });
|
|
616
|
+
var sealedTenantQuota = b.tenantQuota.create({
|
|
617
|
+
db: b.db,
|
|
618
|
+
tenantField: "tid",
|
|
619
|
+
tables: ["sealed_tenant"],
|
|
620
|
+
defaultBytesCap: b.constants.BYTES.gib(1),
|
|
621
|
+
audit: false,
|
|
622
|
+
});
|
|
623
|
+
var stSnap = await sealedTenantQuota.snapshot("tenant-x");
|
|
624
|
+
check("sealed tenantField resolves via derived hash (rows are found, not zero)",
|
|
625
|
+
stSnap.bytesUsed > 0);
|
|
626
|
+
// The row's raw cells: _id "st1" + the sealed "tid" envelope + the tidHash
|
|
627
|
+
// digest + note "data" — comfortably over 40 bytes; the buggy plaintext
|
|
628
|
+
// filter would match nothing and report 0.
|
|
629
|
+
check("sealed-tenantField storage counted (envelope + hash + plaintext cells)",
|
|
630
|
+
stSnap.bytesUsed > 40);
|
|
631
|
+
|
|
632
|
+
// instrumentQuery audit-on path with a live audit chain (real safeEmit).
|
|
633
|
+
var audited = b.tenantQuota.instrumentQuery({
|
|
634
|
+
rows: [
|
|
635
|
+
{ tenantId: "t-acme", v: 1 },
|
|
636
|
+
{ tenantId: "t-evil", v: 2 },
|
|
637
|
+
],
|
|
638
|
+
tenantField: "tenantId",
|
|
639
|
+
tenantId: "t-acme",
|
|
640
|
+
table: "docs",
|
|
641
|
+
});
|
|
642
|
+
check("instrumentQuery emits on a live audit chain and reports the breach",
|
|
643
|
+
audited.ok === false && audited.crossover[0].actualTenantId === "t-evil");
|
|
644
|
+
} finally {
|
|
645
|
+
await helpers.teardownTestDb(tmpDir);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
async function run() {
|
|
650
|
+
testSurface();
|
|
651
|
+
testBudgetSlidingWindow();
|
|
652
|
+
testBudgetObserveDefaults();
|
|
653
|
+
testBudgetConfigValidation();
|
|
654
|
+
testInstrumentQueryBasic();
|
|
655
|
+
testInstrumentQueryAdversarial();
|
|
656
|
+
testCreateConfigValidation();
|
|
657
|
+
await testEmptyMetadataResolvesNoTables();
|
|
658
|
+
await testStorageCapLifecycle();
|
|
104
659
|
}
|
|
105
660
|
|
|
106
661
|
module.exports = { run: run };
|
|
662
|
+
|
|
663
|
+
if (require.main === module) {
|
|
664
|
+
run().then(
|
|
665
|
+
function () { console.log("[tenant-quota] OK — " + helpers.getChecks() + " checks passed"); },
|
|
666
|
+
function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }
|
|
667
|
+
);
|
|
668
|
+
}
|