@blamejs/blamejs-shop 0.4.56 → 0.4.57
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 +426 -366
- package/lib/vendor/blamejs/.github/codeql/codeql-config.yml +25 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/ci.yml +13 -13
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +8 -7
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +2 -2
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +4 -4
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
- package/lib/vendor/blamejs/CHANGELOG.md +2 -0
- package/lib/vendor/blamejs/api-snapshot.json +1381 -4
- package/lib/vendor/blamejs/eslint.config.mjs +1 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +4 -1
- package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +5 -2
- package/lib/vendor/blamejs/examples/wiki/routes/pages.js +4 -1
- package/lib/vendor/blamejs/fuzz/guard-text.fuzz.js +20 -0
- package/lib/vendor/blamejs/index.js +2 -0
- package/lib/vendor/blamejs/lib/a2a-tasks.js +7 -23
- package/lib/vendor/blamejs/lib/acme.js +6 -5
- package/lib/vendor/blamejs/lib/agent-event-bus.js +5 -4
- package/lib/vendor/blamejs/lib/agent-idempotency.js +2 -5
- package/lib/vendor/blamejs/lib/agent-orchestrator.js +2 -5
- package/lib/vendor/blamejs/lib/agent-saga.js +3 -5
- package/lib/vendor/blamejs/lib/agent-tenant.js +2 -5
- package/lib/vendor/blamejs/lib/ai-adverse-decision.js +2 -15
- package/lib/vendor/blamejs/lib/ai-capability.js +1 -6
- package/lib/vendor/blamejs/lib/ai-dp.js +1 -5
- package/lib/vendor/blamejs/lib/ai-input.js +2 -2
- package/lib/vendor/blamejs/lib/ai-pref.js +3 -8
- package/lib/vendor/blamejs/lib/ai-quota.js +3 -14
- package/lib/vendor/blamejs/lib/api-key.js +37 -28
- package/lib/vendor/blamejs/lib/archive-adapters.js +2 -4
- package/lib/vendor/blamejs/lib/archive-entry-policy.js +32 -0
- package/lib/vendor/blamejs/lib/archive-read.js +5 -17
- package/lib/vendor/blamejs/lib/archive-tar-read.js +5 -16
- package/lib/vendor/blamejs/lib/archive.js +2 -10
- package/lib/vendor/blamejs/lib/arg-parser.js +7 -6
- package/lib/vendor/blamejs/lib/asyncapi-traits.js +2 -6
- package/lib/vendor/blamejs/lib/atomic-file.js +108 -31
- package/lib/vendor/blamejs/lib/audit-chain.js +133 -53
- package/lib/vendor/blamejs/lib/audit-daily-review.js +24 -14
- package/lib/vendor/blamejs/lib/audit-emit.js +82 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +257 -0
- package/lib/vendor/blamejs/lib/audit.js +84 -0
- package/lib/vendor/blamejs/lib/auth/access-lock.js +5 -27
- package/lib/vendor/blamejs/lib/auth/dpop.js +23 -35
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +9 -15
- package/lib/vendor/blamejs/lib/auth/jwt-external.js +26 -8
- package/lib/vendor/blamejs/lib/auth/jwt.js +13 -15
- package/lib/vendor/blamejs/lib/auth/lockout.js +6 -25
- package/lib/vendor/blamejs/lib/auth/oauth.js +67 -45
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +55 -32
- package/lib/vendor/blamejs/lib/auth/oid4vp.js +3 -2
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +6 -6
- package/lib/vendor/blamejs/lib/auth/passkey.js +3 -3
- package/lib/vendor/blamejs/lib/auth/password.js +7 -1
- package/lib/vendor/blamejs/lib/auth/saml.js +37 -27
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +2 -14
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +2 -14
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +1 -1
- package/lib/vendor/blamejs/lib/auth/status-list.js +7 -7
- package/lib/vendor/blamejs/lib/auth/step-up.js +6 -12
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +6 -37
- package/lib/vendor/blamejs/lib/backup/bundle.js +11 -18
- package/lib/vendor/blamejs/lib/backup/index.js +14 -47
- package/lib/vendor/blamejs/lib/bounded-map.js +112 -1
- package/lib/vendor/blamejs/lib/breach-deadline.js +1 -11
- package/lib/vendor/blamejs/lib/cache.js +7 -18
- package/lib/vendor/blamejs/lib/cbor.js +2 -1
- package/lib/vendor/blamejs/lib/cdn-cache-control.js +8 -9
- package/lib/vendor/blamejs/lib/cert.js +3 -10
- package/lib/vendor/blamejs/lib/chain-writer.js +162 -47
- package/lib/vendor/blamejs/lib/cli.js +5 -1
- package/lib/vendor/blamejs/lib/client-hints.js +7 -9
- package/lib/vendor/blamejs/lib/cloud-events.js +40 -31
- package/lib/vendor/blamejs/lib/cluster-storage.js +2 -38
- package/lib/vendor/blamejs/lib/cms-codec.js +2 -1
- package/lib/vendor/blamejs/lib/codepoint-class.js +67 -1
- package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +1 -6
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +2 -4
- package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -11
- package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +21 -28
- package/lib/vendor/blamejs/lib/compliance-sanctions.js +2 -14
- package/lib/vendor/blamejs/lib/compliance.js +2 -9
- package/lib/vendor/blamejs/lib/config-drift.js +2 -12
- package/lib/vendor/blamejs/lib/content-digest.js +10 -8
- package/lib/vendor/blamejs/lib/cookies.js +5 -11
- package/lib/vendor/blamejs/lib/cose.js +19 -11
- package/lib/vendor/blamejs/lib/cra-report.js +1 -11
- package/lib/vendor/blamejs/lib/crypto-field.js +5 -10
- package/lib/vendor/blamejs/lib/crypto.js +120 -3
- package/lib/vendor/blamejs/lib/csp.js +235 -3
- package/lib/vendor/blamejs/lib/daemon.js +42 -41
- package/lib/vendor/blamejs/lib/data-act.js +19 -9
- package/lib/vendor/blamejs/lib/db-query.js +6 -40
- package/lib/vendor/blamejs/lib/db.js +34 -12
- package/lib/vendor/blamejs/lib/dbsc.js +5 -6
- package/lib/vendor/blamejs/lib/ddl-change-control.js +18 -14
- package/lib/vendor/blamejs/lib/deprecate.js +4 -5
- package/lib/vendor/blamejs/lib/did.js +6 -2
- package/lib/vendor/blamejs/lib/dsr.js +8 -12
- package/lib/vendor/blamejs/lib/external-db-migrate.js +21 -22
- package/lib/vendor/blamejs/lib/external-db.js +14 -26
- package/lib/vendor/blamejs/lib/fda-21cfr11.js +12 -8
- package/lib/vendor/blamejs/lib/fdx.js +22 -18
- package/lib/vendor/blamejs/lib/file-upload.js +80 -66
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +5 -8
- package/lib/vendor/blamejs/lib/framework-error.js +12 -0
- package/lib/vendor/blamejs/lib/framework-schema.js +19 -0
- package/lib/vendor/blamejs/lib/fsm.js +7 -12
- package/lib/vendor/blamejs/lib/gate-contract.js +869 -38
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +4 -13
- package/lib/vendor/blamejs/lib/graphql-federation.js +1 -1
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +2 -1
- package/lib/vendor/blamejs/lib/guard-all.js +1 -0
- package/lib/vendor/blamejs/lib/guard-archive.js +9 -30
- package/lib/vendor/blamejs/lib/guard-auth.js +23 -80
- package/lib/vendor/blamejs/lib/guard-cidr.js +20 -96
- package/lib/vendor/blamejs/lib/guard-csv.js +135 -196
- package/lib/vendor/blamejs/lib/guard-domain.js +23 -106
- package/lib/vendor/blamejs/lib/guard-dsn.js +16 -13
- package/lib/vendor/blamejs/lib/guard-email.js +46 -53
- package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
- package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +2 -1
- package/lib/vendor/blamejs/lib/guard-filename.js +12 -60
- package/lib/vendor/blamejs/lib/guard-graphql.js +28 -75
- package/lib/vendor/blamejs/lib/guard-html-wcag.js +15 -2
- package/lib/vendor/blamejs/lib/guard-html.js +65 -117
- package/lib/vendor/blamejs/lib/guard-idempotency-key.js +2 -1
- package/lib/vendor/blamejs/lib/guard-image.js +280 -77
- package/lib/vendor/blamejs/lib/guard-imap-command.js +8 -9
- package/lib/vendor/blamejs/lib/guard-json.js +87 -103
- package/lib/vendor/blamejs/lib/guard-jsonpath.js +20 -88
- package/lib/vendor/blamejs/lib/guard-jwt.js +32 -114
- package/lib/vendor/blamejs/lib/guard-list-id.js +2 -7
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -7
- package/lib/vendor/blamejs/lib/guard-mail-compose.js +5 -6
- package/lib/vendor/blamejs/lib/guard-mail-move.js +2 -1
- package/lib/vendor/blamejs/lib/guard-mail-query.js +5 -3
- package/lib/vendor/blamejs/lib/guard-mail-sieve.js +6 -7
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +5 -4
- package/lib/vendor/blamejs/lib/guard-markdown.js +76 -110
- package/lib/vendor/blamejs/lib/guard-message-id.js +5 -6
- package/lib/vendor/blamejs/lib/guard-mime.js +20 -99
- package/lib/vendor/blamejs/lib/guard-oauth.js +19 -73
- package/lib/vendor/blamejs/lib/guard-pdf.js +65 -72
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +12 -13
- package/lib/vendor/blamejs/lib/guard-posture-chain.js +2 -1
- package/lib/vendor/blamejs/lib/guard-regex.js +24 -99
- package/lib/vendor/blamejs/lib/guard-saga-config.js +2 -1
- package/lib/vendor/blamejs/lib/guard-shell.js +22 -87
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +8 -11
- package/lib/vendor/blamejs/lib/guard-sql.js +15 -13
- package/lib/vendor/blamejs/lib/guard-stream-args.js +2 -1
- package/lib/vendor/blamejs/lib/guard-svg.js +95 -140
- package/lib/vendor/blamejs/lib/guard-template.js +23 -80
- package/lib/vendor/blamejs/lib/guard-tenant-id.js +2 -1
- package/lib/vendor/blamejs/lib/guard-text.js +592 -0
- package/lib/vendor/blamejs/lib/guard-time.js +27 -95
- package/lib/vendor/blamejs/lib/guard-uuid.js +21 -93
- package/lib/vendor/blamejs/lib/guard-xml.js +76 -106
- package/lib/vendor/blamejs/lib/guard-yaml.js +24 -60
- package/lib/vendor/blamejs/lib/http-client-cache.js +5 -12
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +2 -4
- package/lib/vendor/blamejs/lib/http-client.js +8 -21
- package/lib/vendor/blamejs/lib/http-message-signature.js +3 -2
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +5 -7
- package/lib/vendor/blamejs/lib/i18n.js +83 -26
- package/lib/vendor/blamejs/lib/inbox.js +8 -8
- package/lib/vendor/blamejs/lib/incident-report.js +3 -21
- package/lib/vendor/blamejs/lib/ip-utils.js +49 -6
- package/lib/vendor/blamejs/lib/jobs.js +3 -2
- package/lib/vendor/blamejs/lib/keychain.js +6 -18
- package/lib/vendor/blamejs/lib/legal-hold.js +6 -15
- package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +44 -112
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +17 -14
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +16 -80
- package/lib/vendor/blamejs/lib/log-stream-webhook.js +20 -92
- package/lib/vendor/blamejs/lib/mail-arc-sign.js +8 -3
- package/lib/vendor/blamejs/lib/mail-arf.js +3 -2
- package/lib/vendor/blamejs/lib/mail-auth.js +40 -66
- package/lib/vendor/blamejs/lib/mail-bimi.js +19 -39
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +3 -2
- package/lib/vendor/blamejs/lib/mail-dav.js +8 -35
- package/lib/vendor/blamejs/lib/mail-deploy.js +6 -9
- package/lib/vendor/blamejs/lib/mail-dkim.js +19 -38
- package/lib/vendor/blamejs/lib/mail-greylist.js +15 -26
- package/lib/vendor/blamejs/lib/mail-helo.js +2 -3
- package/lib/vendor/blamejs/lib/mail-journal.js +2 -1
- package/lib/vendor/blamejs/lib/mail-mdn.js +4 -3
- package/lib/vendor/blamejs/lib/mail-rbl.js +5 -8
- package/lib/vendor/blamejs/lib/mail-scan.js +2 -2
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +33 -20
- package/lib/vendor/blamejs/lib/mail-server-imap.js +32 -87
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +35 -51
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +29 -83
- package/lib/vendor/blamejs/lib/mail-server-mx.js +33 -74
- package/lib/vendor/blamejs/lib/mail-server-net.js +177 -0
- package/lib/vendor/blamejs/lib/mail-server-pop3.js +30 -83
- package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +30 -6
- package/lib/vendor/blamejs/lib/mail-server-submission.js +34 -73
- package/lib/vendor/blamejs/lib/mail-server-tls.js +89 -0
- package/lib/vendor/blamejs/lib/mail-spam-score.js +7 -8
- package/lib/vendor/blamejs/lib/mail-store.js +3 -2
- package/lib/vendor/blamejs/lib/mail.js +6 -11
- package/lib/vendor/blamejs/lib/markup-escape.js +31 -0
- package/lib/vendor/blamejs/lib/markup-tokenizer.js +54 -0
- package/lib/vendor/blamejs/lib/mcp-tool-registry.js +26 -23
- package/lib/vendor/blamejs/lib/mcp.js +1 -1
- package/lib/vendor/blamejs/lib/mdoc.js +11 -12
- package/lib/vendor/blamejs/lib/metrics.js +32 -30
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +3 -23
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +11 -22
- package/lib/vendor/blamejs/lib/middleware/assetlinks.js +2 -7
- package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +31 -48
- package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +7 -10
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +2 -10
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +13 -2
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -26
- package/lib/vendor/blamejs/lib/middleware/deny-response.js +19 -1
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +7 -0
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +4 -20
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +20 -28
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +9 -1
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +2 -6
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +12 -27
- package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +2 -7
- package/lib/vendor/blamejs/lib/migrations.js +4 -13
- package/lib/vendor/blamejs/lib/mime-parse.js +34 -17
- package/lib/vendor/blamejs/lib/module-loader.js +44 -0
- package/lib/vendor/blamejs/lib/money.js +105 -0
- package/lib/vendor/blamejs/lib/mtls-ca.js +116 -36
- package/lib/vendor/blamejs/lib/network-byte-quota.js +4 -18
- package/lib/vendor/blamejs/lib/network-dane.js +8 -6
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +97 -6
- package/lib/vendor/blamejs/lib/network-dnssec.js +16 -16
- package/lib/vendor/blamejs/lib/network-heartbeat.js +3 -2
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +29 -41
- package/lib/vendor/blamejs/lib/network-tls.js +40 -42
- package/lib/vendor/blamejs/lib/nis2-report.js +1 -11
- package/lib/vendor/blamejs/lib/nonce-store.js +81 -3
- package/lib/vendor/blamejs/lib/numeric-bounds.js +22 -8
- package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +2 -6
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +5 -45
- package/lib/vendor/blamejs/lib/object-store/gcs.js +8 -71
- package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -5
- package/lib/vendor/blamejs/lib/object-store/http-request.js +128 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +2 -1
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +9 -77
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -25
- package/lib/vendor/blamejs/lib/observability.js +95 -0
- package/lib/vendor/blamejs/lib/openapi-paths-builder.js +7 -3
- package/lib/vendor/blamejs/lib/otel-export.js +7 -10
- package/lib/vendor/blamejs/lib/outbox.js +43 -37
- package/lib/vendor/blamejs/lib/pagination.js +11 -15
- package/lib/vendor/blamejs/lib/parsers/safe-env.js +5 -4
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +10 -4
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +11 -9
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +2 -2
- package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +7 -6
- package/lib/vendor/blamejs/lib/pick.js +63 -5
- package/lib/vendor/blamejs/lib/pipl-cn.js +69 -59
- package/lib/vendor/blamejs/lib/privacy-pass.js +8 -6
- package/lib/vendor/blamejs/lib/problem-details.js +2 -5
- package/lib/vendor/blamejs/lib/pubsub.js +4 -8
- package/lib/vendor/blamejs/lib/redact.js +2 -1
- package/lib/vendor/blamejs/lib/render.js +4 -2
- package/lib/vendor/blamejs/lib/request-helpers.js +133 -6
- package/lib/vendor/blamejs/lib/restore.js +5 -22
- package/lib/vendor/blamejs/lib/retention.js +3 -5
- package/lib/vendor/blamejs/lib/safe-async.js +457 -0
- package/lib/vendor/blamejs/lib/safe-buffer.js +137 -6
- package/lib/vendor/blamejs/lib/safe-decompress.js +2 -1
- package/lib/vendor/blamejs/lib/safe-dns.js +2 -1
- package/lib/vendor/blamejs/lib/safe-ical.js +12 -26
- package/lib/vendor/blamejs/lib/safe-json.js +7 -8
- package/lib/vendor/blamejs/lib/safe-jsonpath.js +6 -5
- package/lib/vendor/blamejs/lib/safe-mime.js +25 -29
- package/lib/vendor/blamejs/lib/safe-redirect.js +2 -5
- package/lib/vendor/blamejs/lib/safe-schema.js +7 -6
- package/lib/vendor/blamejs/lib/safe-sql.js +126 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +12 -26
- package/lib/vendor/blamejs/lib/sandbox-worker.js +9 -2
- package/lib/vendor/blamejs/lib/sandbox.js +3 -2
- package/lib/vendor/blamejs/lib/scheduler.js +5 -12
- package/lib/vendor/blamejs/lib/sec-cyber.js +82 -37
- package/lib/vendor/blamejs/lib/seeders.js +4 -11
- package/lib/vendor/blamejs/lib/self-update.js +92 -69
- package/lib/vendor/blamejs/lib/session-device-binding.js +112 -66
- package/lib/vendor/blamejs/lib/session.js +194 -6
- package/lib/vendor/blamejs/lib/sql.js +225 -78
- package/lib/vendor/blamejs/lib/sse.js +6 -10
- package/lib/vendor/blamejs/lib/static.js +136 -98
- package/lib/vendor/blamejs/lib/storage.js +4 -2
- package/lib/vendor/blamejs/lib/structured-fields.js +275 -16
- package/lib/vendor/blamejs/lib/tenant-quota.js +2 -20
- package/lib/vendor/blamejs/lib/tsa.js +11 -15
- package/lib/vendor/blamejs/lib/validate-opts.js +154 -8
- package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +30 -48
- package/lib/vendor/blamejs/lib/vault-aad.js +3 -2
- package/lib/vendor/blamejs/lib/vc.js +2 -7
- package/lib/vendor/blamejs/lib/vex.js +35 -13
- package/lib/vendor/blamejs/lib/web-push-vapid.js +23 -20
- package/lib/vendor/blamejs/lib/webhook-dispatcher.js +706 -0
- package/lib/vendor/blamejs/lib/webhook.js +43 -18
- package/lib/vendor/blamejs/lib/websocket-channels.js +9 -7
- package/lib/vendor/blamejs/lib/websocket.js +7 -3
- package/lib/vendor/blamejs/lib/worm.js +2 -3
- package/lib/vendor/blamejs/lib/ws-client.js +8 -10
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.15.13.json +81 -0
- package/lib/vendor/blamejs/scripts/check-changelog-extract.js +1 -1
- package/lib/vendor/blamejs/test/00-primitives.js +136 -7
- package/lib/vendor/blamejs/test/10-state.js +9 -3
- package/lib/vendor/blamejs/test/30-chain.js +40 -0
- package/lib/vendor/blamejs/test/helpers/check.js +18 -0
- package/lib/vendor/blamejs/test/helpers/db.js +4 -0
- package/lib/vendor/blamejs/test/helpers/index.js +1 -0
- package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +2 -1
- package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +2 -1
- package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +8 -1
- package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +1 -1
- package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +2 -1
- package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +269 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +88 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +55 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-object-store-adapter.test.js +2 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/bounded-map.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/chain-writer-multichain.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +12 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +2788 -3214
- package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +63 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +2 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +2 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-resolve-opts.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +9 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract-content-gate.test.js +290 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +84 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +23 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-gate-disposition-coverage.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +60 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +184 -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-json.test.js +54 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +101 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-text.test.js +365 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +35 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +20 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mime-parse.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-revocation.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-release.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-memory-getorinsert.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +88 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +14 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +2 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/session-valid-from.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/validate-opts-shape.test.js +235 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +374 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +75 -8
- package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +3 -3
- package/package.json +1 -1
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
*/
|
|
49
49
|
var audit = require("./audit");
|
|
50
50
|
var canonicalJson = require("./canonical-json");
|
|
51
|
+
var validateOpts = require("./validate-opts");
|
|
51
52
|
var cluster = require("./cluster");
|
|
52
53
|
var clusterStorage = require("./cluster-storage");
|
|
53
54
|
var C = require("./constants");
|
|
@@ -149,6 +150,38 @@ function _sessionSqlTable() { return frameworkSchema.tableName(SESSION_TABLE); }
|
|
|
149
150
|
// dispatch; this controls only the builder-side quoting + idiom selection.
|
|
150
151
|
function _sessionSqlOpts() { return { dialect: clusterStorage.dialect() }; }
|
|
151
152
|
|
|
153
|
+
// Per-subject valid-from boundary table. A monotonic epoch (ms) the issuer
|
|
154
|
+
// bumps to invalidate every STATELESS self-validating token (sealed cookie
|
|
155
|
+
// with no DB row, JWT) minted before the bump: log-out-everywhere, a
|
|
156
|
+
// right-to-erasure cutoff, a forced re-auth after a credential change. Token
|
|
157
|
+
// readers compare the token's iat against this boundary via check(). Same
|
|
158
|
+
// dual-storage shape as _blamejs_sessions — registered in both db.js's
|
|
159
|
+
// FRAMEWORK_SCHEMA (single-node SQLite) and framework-schema.js (cluster
|
|
160
|
+
// external-db); clusterStorage.execute routes by cluster mode. The subject id
|
|
161
|
+
// is hashed before it becomes the PRIMARY KEY, so the plaintext id never lands
|
|
162
|
+
// in the table (the same sidHash / userIdHash discipline the sessions table
|
|
163
|
+
// follows).
|
|
164
|
+
var VALID_FROM_TABLE = "_blamejs_session_valid_from"; // allow:hand-rolled-sql — canonical logical table-name + reserved schema name
|
|
165
|
+
var VALID_FROM_SUBJECT_NAMESPACE = "bj-session-valid-from-subject:";
|
|
166
|
+
function _validFromSqlTable() { return frameworkSchema.tableName(VALID_FROM_TABLE); }
|
|
167
|
+
function _hashSubjectId(subjectId) { return sha3Hash(VALID_FROM_SUBJECT_NAMESPACE + subjectId); }
|
|
168
|
+
|
|
169
|
+
// Dialect-aware conflict-row references for the monotonic-max upsert in
|
|
170
|
+
// bump(). Mirrors rate-limit.js's pattern: the proposed row is EXCLUDED
|
|
171
|
+
// (Postgres/SQLite) / VALUES() (MySQL); the existing row is a self-reference.
|
|
172
|
+
function _validFromConflictRefs(dialect, table) {
|
|
173
|
+
if (dialect === "mysql") {
|
|
174
|
+
return {
|
|
175
|
+
proposed: function (col) { return "VALUES(`" + col + "`)"; },
|
|
176
|
+
existing: function (col) { return "`" + table + "`.`" + col + "`"; },
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
proposed: function (col) { return "EXCLUDED.\"" + col + "\""; },
|
|
181
|
+
existing: function (col) { return "\"" + table + "\".\"" + col + "\""; },
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
152
185
|
// Column order used for INSERT — kept as a constant so the placeholders
|
|
153
186
|
// list and the values list stay in sync. Must match the session table's
|
|
154
187
|
// schema in db.js (single-node) and framework-schema.js (cluster mode).
|
|
@@ -825,6 +858,10 @@ async function destroyAllForUser(userId) {
|
|
|
825
858
|
.whereIn("userIdHash", userHashes)
|
|
826
859
|
.toSql();
|
|
827
860
|
var result = await _currentStore().execute(built.sql, built.params);
|
|
861
|
+
// Also raise the stateless valid-from boundary so a "logout everywhere"
|
|
862
|
+
// revokes the operator's stateless tokens (sealed cookies / JWTs checked via
|
|
863
|
+
// b.session.check) too, not only the store-backed rows just deleted.
|
|
864
|
+
await bump(userId);
|
|
828
865
|
return result.rowCount || 0;
|
|
829
866
|
}
|
|
830
867
|
|
|
@@ -1272,12 +1309,8 @@ function useStore(store) {
|
|
|
1272
1309
|
_store = null;
|
|
1273
1310
|
return;
|
|
1274
1311
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
typeof store.executeOne !== "function") {
|
|
1278
|
-
throw _err("INVALID_ARG",
|
|
1279
|
-
"session.useStore: store must expose execute(sql,params) and executeOne(sql,params)", true);
|
|
1280
|
-
}
|
|
1312
|
+
validateOpts.requireMethods(store, ["execute", "executeOne"],
|
|
1313
|
+
"session.useStore: store", SessionError, "INVALID_ARG", true);
|
|
1281
1314
|
_store = store;
|
|
1282
1315
|
}
|
|
1283
1316
|
|
|
@@ -1304,6 +1337,158 @@ function isAnonymous(userId) {
|
|
|
1304
1337
|
return _isAnonymousUserId(userId);
|
|
1305
1338
|
}
|
|
1306
1339
|
|
|
1340
|
+
/**
|
|
1341
|
+
* @primitive b.session.bump
|
|
1342
|
+
* @signature b.session.bump(subjectId, opts?)
|
|
1343
|
+
* @since 0.15.13
|
|
1344
|
+
* @status stable
|
|
1345
|
+
* @related b.session.check, b.session.validFrom, b.session.destroyAllForUser
|
|
1346
|
+
*
|
|
1347
|
+
* Revoke every STATELESS self-validating token (sealed cookie carrying no DB
|
|
1348
|
+
* row, JWT) for a subject by raising a durable per-subject valid-from boundary
|
|
1349
|
+
* to now. Any token whose issued-at (`iat`) predates the boundary fails
|
|
1350
|
+
* `b.session.check`. Unlike `destroyAllForUser` — which deletes server-side
|
|
1351
|
+
* session rows — this revokes tokens the framework never stored a row for:
|
|
1352
|
+
* log-out-everywhere, a right-to-erasure cutoff, a forced re-auth after a
|
|
1353
|
+
* password / key change. `destroyAllForUser` calls this for you, so a single
|
|
1354
|
+
* "logout everywhere" covers both store-backed and stateless tokens.
|
|
1355
|
+
*
|
|
1356
|
+
* The boundary is MONOTONIC: it only ever moves forward. A bump to an
|
|
1357
|
+
* `epochMs` at or below the stored value is a no-op — a replayed or
|
|
1358
|
+
* clock-skewed lower value can never widen a revoked window back open. Returns
|
|
1359
|
+
* the boundary in effect after the call. Leader-only. The subject id is stored
|
|
1360
|
+
* hashed; the plaintext id never lands in the table.
|
|
1361
|
+
*
|
|
1362
|
+
* @opts
|
|
1363
|
+
* epochMs: number, // boundary to set; default Date.now(). Tokens with iat < this are revoked.
|
|
1364
|
+
*
|
|
1365
|
+
* @example
|
|
1366
|
+
* // Force re-auth everywhere for a subject after a password change:
|
|
1367
|
+
* var boundary = await b.session.bump("user-42");
|
|
1368
|
+
* // Cut off at a specific instant (right-to-erasure effective time):
|
|
1369
|
+
* await b.session.bump("user-42", { epochMs: erasureEffectiveMs });
|
|
1370
|
+
*/
|
|
1371
|
+
async function bump(subjectId, opts) {
|
|
1372
|
+
cluster.requireLeader();
|
|
1373
|
+
if (typeof subjectId !== "string" || subjectId.length === 0) {
|
|
1374
|
+
throw _err("INVALID_ARG", "session.bump requires a non-empty subjectId", true);
|
|
1375
|
+
}
|
|
1376
|
+
opts = opts || {};
|
|
1377
|
+
var epochMs = opts.epochMs === undefined ? Date.now() : opts.epochMs;
|
|
1378
|
+
if (typeof epochMs !== "number" || !isFinite(epochMs) || epochMs < 0) {
|
|
1379
|
+
throw _err("INVALID_ARG",
|
|
1380
|
+
"session.bump: epochMs must be a non-negative finite number, got " + JSON.stringify(epochMs), true);
|
|
1381
|
+
}
|
|
1382
|
+
var subjectHash = _hashSubjectId(subjectId);
|
|
1383
|
+
var t = _validFromSqlTable();
|
|
1384
|
+
var dialect = clusterStorage.dialect();
|
|
1385
|
+
var refs = _validFromConflictRefs(dialect, t);
|
|
1386
|
+
|
|
1387
|
+
// Monotonic-max conflict action: keep the LATER of the proposed and the
|
|
1388
|
+
// stored boundary, so a lower (replayed / clock-skewed) epoch can never move
|
|
1389
|
+
// the boundary backwards and re-open a revoked window.
|
|
1390
|
+
var validFromExpr = "CASE WHEN " + refs.proposed("validFromEpoch") + " > " +
|
|
1391
|
+
refs.existing("validFromEpoch") + " THEN " + refs.proposed("validFromEpoch") +
|
|
1392
|
+
" ELSE " + refs.existing("validFromEpoch") + " END";
|
|
1393
|
+
var built = sql.upsert(t, _sessionSqlOpts())
|
|
1394
|
+
.columns(["subjectHash", "validFromEpoch", "updatedAt"])
|
|
1395
|
+
.values({ subjectHash: subjectHash, validFromEpoch: epochMs, updatedAt: Date.now() })
|
|
1396
|
+
.onConflict(["subjectHash"])
|
|
1397
|
+
.doUpdate({ validFromEpoch: validFromExpr, updatedAt: "?" }, [Date.now()])
|
|
1398
|
+
.returning(["validFromEpoch"])
|
|
1399
|
+
.toSql();
|
|
1400
|
+
// The valid-from boundary is a FRAMEWORK table (FRAMEWORK_SCHEMA / cluster
|
|
1401
|
+
// DDL), NOT session data — it must execute against clusterStorage (the
|
|
1402
|
+
// framework db), never _currentStore(): a pluggable session-data store
|
|
1403
|
+
// (b.session.useStore / localDbThin) does not provision this table, so
|
|
1404
|
+
// routing the bump through it throws "no such table".
|
|
1405
|
+
var row;
|
|
1406
|
+
if (built.readbackSql) {
|
|
1407
|
+
// MySQL: ON DUPLICATE KEY UPDATE has no RETURNING — run the upsert, then
|
|
1408
|
+
// the readback SELECT b.sql emits (keyed on subjectHash).
|
|
1409
|
+
await clusterStorage.execute(built.sql, built.params);
|
|
1410
|
+
var readback = await clusterStorage.execute(built.readbackSql.sql, built.readbackSql.params);
|
|
1411
|
+
row = readback.rows && readback.rows[0];
|
|
1412
|
+
} else {
|
|
1413
|
+
var result = await clusterStorage.execute(built.sql, built.params);
|
|
1414
|
+
row = result.rows && result.rows[0];
|
|
1415
|
+
}
|
|
1416
|
+
var effective = row ? Number(row.validFromEpoch) : epochMs;
|
|
1417
|
+
|
|
1418
|
+
// Best-effort audit — matches the file's emit convention (safeEmit is
|
|
1419
|
+
// already drop-silent internally).
|
|
1420
|
+
try {
|
|
1421
|
+
audit.safeEmit({
|
|
1422
|
+
action: "auth.session.valid_from_bump",
|
|
1423
|
+
outcome: "success",
|
|
1424
|
+
metadata: { validFromEpoch: effective },
|
|
1425
|
+
});
|
|
1426
|
+
} catch (_ignored) { /* audit best-effort */ }
|
|
1427
|
+
|
|
1428
|
+
return effective;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
/**
|
|
1432
|
+
* @primitive b.session.validFrom
|
|
1433
|
+
* @signature b.session.validFrom(subjectId)
|
|
1434
|
+
* @since 0.15.13
|
|
1435
|
+
* @status stable
|
|
1436
|
+
* @related b.session.bump, b.session.check
|
|
1437
|
+
*
|
|
1438
|
+
* Read the current valid-from boundary (epoch ms) for a subject. Returns `0`
|
|
1439
|
+
* when the subject has never been bumped — no token is revoked by boundary, so
|
|
1440
|
+
* any non-negative token `iat` passes `b.session.check`. Runs anywhere (leader
|
|
1441
|
+
* or follower) — it only reads. The subject id is hashed before lookup; the
|
|
1442
|
+
* plaintext id never lands in the table.
|
|
1443
|
+
*
|
|
1444
|
+
* @example
|
|
1445
|
+
* var boundary = await b.session.validFrom("user-42");
|
|
1446
|
+
* // → 1735689600000 (last bump) or 0 (never bumped)
|
|
1447
|
+
*/
|
|
1448
|
+
async function validFrom(subjectId) {
|
|
1449
|
+
if (typeof subjectId !== "string" || subjectId.length === 0) return 0;
|
|
1450
|
+
var built = sql.select(_validFromSqlTable(), _sessionSqlOpts())
|
|
1451
|
+
.columns(["validFromEpoch"])
|
|
1452
|
+
.where("subjectHash", _hashSubjectId(subjectId))
|
|
1453
|
+
.toSql();
|
|
1454
|
+
// Framework valid-from table — read from clusterStorage (the framework db),
|
|
1455
|
+
// not _currentStore(), so a pluggable session-data store cannot divert it (it
|
|
1456
|
+
// does not provision this table). See bump() for the full rationale.
|
|
1457
|
+
var row = await clusterStorage.executeOne(built.sql, built.params);
|
|
1458
|
+
return row ? Number(row.validFromEpoch) : 0;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
/**
|
|
1462
|
+
* @primitive b.session.check
|
|
1463
|
+
* @signature b.session.check(subjectId, tokenIatMs)
|
|
1464
|
+
* @since 0.15.13
|
|
1465
|
+
* @status stable
|
|
1466
|
+
* @related b.session.bump, b.session.validFrom
|
|
1467
|
+
*
|
|
1468
|
+
* Decide whether a stateless self-validating token is still valid against the
|
|
1469
|
+
* subject's valid-from boundary. Returns `true` when the token's issued-at
|
|
1470
|
+
* (`tokenIatMs`, epoch ms) is at or after the boundary; `false` when the token
|
|
1471
|
+
* was issued before the last `bump` (revoked). A subject that was never bumped
|
|
1472
|
+
* has boundary `0`, so any non-negative `iat` is valid. Runs anywhere.
|
|
1473
|
+
*
|
|
1474
|
+
* Fails CLOSED: a non-finite / negative / non-number `tokenIatMs` returns
|
|
1475
|
+
* `false` (treat an unparseable token as revoked rather than admit it). Call
|
|
1476
|
+
* this AFTER the token's own signature + expiry checks pass — it is the
|
|
1477
|
+
* server-side revocation layer those stateless checks otherwise lack.
|
|
1478
|
+
*
|
|
1479
|
+
* @example
|
|
1480
|
+
* // jwt already signature- and exp-verified; iat is in seconds → ms:
|
|
1481
|
+
* var ok = await b.session.check(claims.sub, claims.iat * 1000);
|
|
1482
|
+
* if (!ok) { res.statusCode = 401; res.end("session revoked"); return; }
|
|
1483
|
+
*/
|
|
1484
|
+
async function check(subjectId, tokenIatMs) {
|
|
1485
|
+
if (typeof tokenIatMs !== "number" || !isFinite(tokenIatMs) || tokenIatMs < 0) {
|
|
1486
|
+
return false;
|
|
1487
|
+
}
|
|
1488
|
+
var boundary = await validFrom(subjectId);
|
|
1489
|
+
return tokenIatMs >= boundary;
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1307
1492
|
module.exports = {
|
|
1308
1493
|
create: create,
|
|
1309
1494
|
verify: verify,
|
|
@@ -1315,6 +1500,9 @@ module.exports = {
|
|
|
1315
1500
|
updateData: updateData,
|
|
1316
1501
|
purgeExpired: purgeExpired,
|
|
1317
1502
|
count: count,
|
|
1503
|
+
bump: bump,
|
|
1504
|
+
validFrom: validFrom,
|
|
1505
|
+
check: check,
|
|
1318
1506
|
useStore: useStore,
|
|
1319
1507
|
isAnonymous: isAnonymous,
|
|
1320
1508
|
stores: require("./session-stores"), // allow:inline-require — session-stores depends on local-db-thin which requires audit lazily; eager require is fine here
|
|
@@ -1107,39 +1107,11 @@ function _checkRawFragment(sql, params, opts, where) {
|
|
|
1107
1107
|
// comments are skipped. Single linear pass, no backtracking regex. Same
|
|
1108
1108
|
// shape as db-query.js's scanner.
|
|
1109
1109
|
function _assertRawNoStringLiteral(sql, where) {
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
if (ch === '"') {
|
|
1116
|
-
i += 1;
|
|
1117
|
-
while (i < len) {
|
|
1118
|
-
if (sql.charAt(i) === '"') {
|
|
1119
|
-
if (sql.charAt(i + 1) === '"') { i += 2; continue; }
|
|
1120
|
-
i += 1; break;
|
|
1121
|
-
}
|
|
1122
|
-
i += 1;
|
|
1123
|
-
}
|
|
1124
|
-
continue;
|
|
1125
|
-
}
|
|
1126
|
-
if (ch === "-" && next === "-") {
|
|
1127
|
-
while (i < len && sql.charAt(i) !== "\n") i += 1;
|
|
1128
|
-
continue;
|
|
1129
|
-
}
|
|
1130
|
-
if (ch === "/" && next === "*") {
|
|
1131
|
-
i += 2;
|
|
1132
|
-
while (i < len && !(sql.charAt(i) === "*" && sql.charAt(i + 1) === "/")) i += 1;
|
|
1133
|
-
i += 2;
|
|
1134
|
-
continue;
|
|
1135
|
-
}
|
|
1136
|
-
if (ch === "'") {
|
|
1137
|
-
throw _err(where + ": raw SQL must not contain a string literal ('...') - bind " +
|
|
1138
|
-
"every value with a ? placeholder, or pass { allowLiterals: true } when the " +
|
|
1139
|
-
"literal is static and operator-controlled", "sql-builder/raw-literal");
|
|
1140
|
-
}
|
|
1141
|
-
i += 1;
|
|
1142
|
-
}
|
|
1110
|
+
safeSql.assertNoRawStringLiteral(sql, where, function (w) {
|
|
1111
|
+
return _err(w + ": raw SQL must not contain a string literal ('...') - bind " +
|
|
1112
|
+
"every value with a ? placeholder, or pass { allowLiterals: true } when the " +
|
|
1113
|
+
"literal is static and operator-controlled", "sql-builder/raw-literal");
|
|
1114
|
+
});
|
|
1143
1115
|
}
|
|
1144
1116
|
|
|
1145
1117
|
// Refuse the two-char Postgres JSONB key-existence tokens (?| / ?&) in a raw
|
|
@@ -1188,51 +1160,10 @@ function _assertNoRawJsonbKeyOp(sql, where) {
|
|
|
1188
1160
|
var _countPlaceholders = safeSql.countPlaceholders;
|
|
1189
1161
|
|
|
1190
1162
|
// Translate the builder's `?` placeholders to a dialect's positional form
|
|
1191
|
-
// (Postgres `$1..$N`; SQLite / MySQL keep `?`)
|
|
1192
|
-
//
|
|
1193
|
-
//
|
|
1194
|
-
|
|
1195
|
-
// clusterStorage in the path to do the rewrite). The translator lives here -
|
|
1196
|
-
// the builder owns its driver-final output rendering - rather than reaching
|
|
1197
|
-
// into clusterStorage (which transitively requires this module).
|
|
1198
|
-
function _toPositional(sql, dialect) {
|
|
1199
|
-
if (dialect !== "postgres") return sql;
|
|
1200
|
-
var out = "";
|
|
1201
|
-
var n = 0;
|
|
1202
|
-
var i = 0;
|
|
1203
|
-
var len = sql.length;
|
|
1204
|
-
while (i < len) {
|
|
1205
|
-
var c = sql.charAt(i);
|
|
1206
|
-
var nx = i + 1 < len ? sql.charAt(i + 1) : "";
|
|
1207
|
-
if (c === "'" || c === '"' || c === "`") {
|
|
1208
|
-
out += c;
|
|
1209
|
-
i += 1;
|
|
1210
|
-
while (i < len) {
|
|
1211
|
-
var q = sql.charAt(i);
|
|
1212
|
-
if (q === c) {
|
|
1213
|
-
if (sql.charAt(i + 1) === c) { out += c + c; i += 2; continue; }
|
|
1214
|
-
out += c; i += 1; break;
|
|
1215
|
-
}
|
|
1216
|
-
out += q; i += 1;
|
|
1217
|
-
}
|
|
1218
|
-
continue;
|
|
1219
|
-
}
|
|
1220
|
-
if (c === "-" && nx === "-") {
|
|
1221
|
-
while (i < len && sql.charAt(i) !== "\n") { out += sql.charAt(i); i += 1; }
|
|
1222
|
-
continue;
|
|
1223
|
-
}
|
|
1224
|
-
if (c === "/" && nx === "*") {
|
|
1225
|
-
out += "/*"; i += 2;
|
|
1226
|
-
while (i < len && !(sql.charAt(i) === "*" && sql.charAt(i + 1) === "/")) { out += sql.charAt(i); i += 1; }
|
|
1227
|
-
if (i < len) { out += "*/"; i += 2; }
|
|
1228
|
-
continue;
|
|
1229
|
-
}
|
|
1230
|
-
if (c === "?") { n += 1; out += "$" + n; i += 1; continue; }
|
|
1231
|
-
out += c;
|
|
1232
|
-
i += 1;
|
|
1233
|
-
}
|
|
1234
|
-
return out;
|
|
1235
|
-
}
|
|
1163
|
+
// (Postgres `$1..$N`; SQLite / MySQL keep `?`); composed from safe-sql so the
|
|
1164
|
+
// quote / comment / backtick skip rules live in one place. The toExternalSql
|
|
1165
|
+
// terminal for code that hands the SQL to an operator-supplied driver directly.
|
|
1166
|
+
var _toPositional = safeSql.toPositional;
|
|
1236
1167
|
|
|
1237
1168
|
/**
|
|
1238
1169
|
* @primitive b.sql.toExternalSql
|
|
@@ -1922,6 +1853,163 @@ class InsertBuilder extends Builder {
|
|
|
1922
1853
|
}
|
|
1923
1854
|
}
|
|
1924
1855
|
|
|
1856
|
+
// ---- INSERT ... SELECT ... WHERE (conditional / append-only) --------
|
|
1857
|
+
//
|
|
1858
|
+
// A conditional INSERT that materialises its row from a value-less SELECT
|
|
1859
|
+
// guarded by a WHERE - INSERT INTO t (cols) SELECT <cells> WHERE <guard>.
|
|
1860
|
+
// The append-only-ledger debit idiom: the new row is written ONLY when a
|
|
1861
|
+
// guard derived from the table itself holds (a store-credit / gift-card /
|
|
1862
|
+
// points / metered-quota balance that lives on the latest row, with no
|
|
1863
|
+
// mutable counter row to increment()). The SELECT has no FROM - it is a
|
|
1864
|
+
// single computed row that the WHERE either admits (one row inserted) or
|
|
1865
|
+
// rejects (zero rows), evaluated atomically inside the INSERT against the
|
|
1866
|
+
// table the guard's correlated subquery / EXISTS references, so two racing
|
|
1867
|
+
// debits cannot both pass the balance check.
|
|
1868
|
+
//
|
|
1869
|
+
// Standard-SQL across sqlite / Postgres / MySQL - the only dialect-divergent
|
|
1870
|
+
// clause is RETURNING (Postgres / SQLite; refused on MySQL by the shared
|
|
1871
|
+
// _renderReturning, which the MySQL caller replaces with an explicit read).
|
|
1872
|
+
// Every SELECT cell routes through the SAME _renderValueCell choke-point
|
|
1873
|
+
// INSERT VALUES uses (so a cell is a bound ?, a b.sql.cast(...) ?::type, or a
|
|
1874
|
+
// b.sql.fn(...) allowlisted server function - no param), and the guard is a
|
|
1875
|
+
// full Predicate (the whole where-family: whereExists / whereSub / whereOp /
|
|
1876
|
+
// whereRaw / whereGroup compose, which is how a balance fence is expressed).
|
|
1877
|
+
//
|
|
1878
|
+
// Safety default: an INSERT...SELECT with no WHERE is just an INSERT...VALUES
|
|
1879
|
+
// and shipping it un-guarded is almost always a bug, so the verb THROWS
|
|
1880
|
+
// without a where() unless allowNoWhere() opts in - the same discipline
|
|
1881
|
+
// update / delete apply.
|
|
1882
|
+
class InsertSelectWhereBuilder extends Builder {
|
|
1883
|
+
constructor(tableNameOrRef, opts) {
|
|
1884
|
+
super("insert-select-where", tableNameOrRef, opts);
|
|
1885
|
+
this._columns = null;
|
|
1886
|
+
this._values = null; // single row, aligned to _columns
|
|
1887
|
+
this._where = new Predicate(this, "AND");
|
|
1888
|
+
this._returning = null;
|
|
1889
|
+
this._allowNoWhere = false;
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
// Declare the target column list (validated + gated). values() infers it
|
|
1893
|
+
// from a row object's keys when omitted, exactly like INSERT.
|
|
1894
|
+
columns(cols) {
|
|
1895
|
+
if (!Array.isArray(cols) || cols.length === 0) {
|
|
1896
|
+
throw _err("columns() expects a non-empty array", "sql-builder/bad-columns");
|
|
1897
|
+
}
|
|
1898
|
+
var self = this;
|
|
1899
|
+
cols.forEach(function (c) { self._assertColumnMember(c, "insertSelectWhere"); _validateColumn(c); });
|
|
1900
|
+
this._columns = cols.slice();
|
|
1901
|
+
return this;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
// values(obj) - one row from a column->value map (sets _columns from the
|
|
1905
|
+
// keys when not already declared). values(array) - one positional row
|
|
1906
|
+
// aligned to a prior columns() call. A single row only: the SELECT
|
|
1907
|
+
// materialises exactly one candidate row gated by the WHERE.
|
|
1908
|
+
values(rowOrArray) {
|
|
1909
|
+
if (Array.isArray(rowOrArray)) {
|
|
1910
|
+
if (this._columns === null) {
|
|
1911
|
+
throw _err("values(array) requires a prior columns([...]) call", "sql-builder/no-columns");
|
|
1912
|
+
}
|
|
1913
|
+
if (rowOrArray.length !== this._columns.length) {
|
|
1914
|
+
throw _err("values(array): " + rowOrArray.length + " values but " +
|
|
1915
|
+
this._columns.length + " columns", "sql-builder/value-count");
|
|
1916
|
+
}
|
|
1917
|
+
this._values = rowOrArray.slice();
|
|
1918
|
+
return this;
|
|
1919
|
+
}
|
|
1920
|
+
if (rowOrArray && typeof rowOrArray === "object") {
|
|
1921
|
+
var keys = Object.keys(rowOrArray);
|
|
1922
|
+
if (keys.length === 0) throw _err("insertSelectWhere row object is empty", "sql-builder/empty-values");
|
|
1923
|
+
if (this._columns === null) this.columns(keys);
|
|
1924
|
+
var self = this;
|
|
1925
|
+
this._values = this._columns.map(function (c) {
|
|
1926
|
+
if (!Object.prototype.hasOwnProperty.call(rowOrArray, c)) {
|
|
1927
|
+
throw _err("insertSelectWhere row is missing column '" + c + "'", "sql-builder/missing-column");
|
|
1928
|
+
}
|
|
1929
|
+
return rowOrArray[c];
|
|
1930
|
+
});
|
|
1931
|
+
keys.forEach(function (k) {
|
|
1932
|
+
if (self._columns.indexOf(k) === -1) {
|
|
1933
|
+
throw _err("insertSelectWhere row has column '" + k + "' not in the column set",
|
|
1934
|
+
"sql-builder/extra-column");
|
|
1935
|
+
}
|
|
1936
|
+
});
|
|
1937
|
+
return this;
|
|
1938
|
+
}
|
|
1939
|
+
throw _err("insertSelectWhere values() requires a row object or a value array aligned to columns()",
|
|
1940
|
+
"sql-builder/bad-values");
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
// A deliberate un-guarded conditional insert opts in here - same shape as
|
|
1944
|
+
// update / delete. Without it the verb refuses an empty WHERE.
|
|
1945
|
+
allowNoWhere() { this._allowNoWhere = true; return this; }
|
|
1946
|
+
|
|
1947
|
+
where() { this._where.where.apply(this._where, arguments); return this; }
|
|
1948
|
+
andWhere() { this._where.andWhere.apply(this._where, arguments); return this; }
|
|
1949
|
+
orWhere() { this._where.orWhere.apply(this._where, arguments); return this; }
|
|
1950
|
+
whereOp(col, op, value) { this._where.whereOp(col, op, value); return this; }
|
|
1951
|
+
orWhereOp(col, op, value) { this._where.orWhereOp(col, op, value); return this; }
|
|
1952
|
+
whereIn(col, values) { this._where.whereIn(col, values); return this; }
|
|
1953
|
+
whereNotIn(col, values) { this._where.whereNotIn(col, values); return this; }
|
|
1954
|
+
orWhereIn(col, values) { this._where.orWhereIn(col, values); return this; }
|
|
1955
|
+
whereInArray(col, values) { this._where.whereInArray(col, values); return this; }
|
|
1956
|
+
orWhereInArray(col, values) { this._where.orWhereInArray(col, values); return this; }
|
|
1957
|
+
whereInJsonEach(col, jsonArrayString) { this._where.whereInJsonEach(col, jsonArrayString); return this; }
|
|
1958
|
+
whereMatch(target, expr) { this._where.whereMatch(target, expr); return this; }
|
|
1959
|
+
whereNull(col) { this._where.whereNull(col); return this; }
|
|
1960
|
+
whereNotNull(col) { this._where.whereNotNull(col); return this; }
|
|
1961
|
+
orWhereNull(col) { this._where.orWhereNull(col); return this; }
|
|
1962
|
+
whereLike(col, term, mode) { this._where.whereLike(col, term, mode); return this; }
|
|
1963
|
+
orWhereLike(col, term, mode) { this._where.orWhereLike(col, term, mode); return this; }
|
|
1964
|
+
whereBetween(col, low, high) { this._where.whereBetween(col, low, high); return this; }
|
|
1965
|
+
whereSub(col, op, sub) { this._where.whereSub(col, op, sub); return this; }
|
|
1966
|
+
whereExists(sub) { this._where.whereExists(sub); return this; }
|
|
1967
|
+
whereNotExists(sub) { this._where.whereNotExists(sub); return this; }
|
|
1968
|
+
orWhereExists(sub) { this._where.orWhereExists(sub); return this; }
|
|
1969
|
+
whereGroup(closure) { this._where.whereGroup(closure); return this; }
|
|
1970
|
+
orWhereGroup(closure) { this._where.orWhereGroup(closure); return this; }
|
|
1971
|
+
whereRaw(sql, params, opts) { this._where.whereRaw(sql, params, opts); return this; }
|
|
1972
|
+
orWhereRaw(sql, params, opts) { this._where.orWhereRaw(sql, params, opts); return this; }
|
|
1973
|
+
|
|
1974
|
+
returning(cols) { this._returning = _normReturning(cols); return this; }
|
|
1975
|
+
|
|
1976
|
+
_render() {
|
|
1977
|
+
if (this._columns === null || this._values === null) {
|
|
1978
|
+
throw _err("insertSelectWhere requires columns + a values() row", "sql-builder/empty-values");
|
|
1979
|
+
}
|
|
1980
|
+
if (this._where.length === 0 && !this._allowNoWhere) {
|
|
1981
|
+
throw _err("refusing unconditional insertSelectWhere - call where(...) first or " +
|
|
1982
|
+
"allowNoWhere() (an un-guarded INSERT...SELECT is just INSERT...VALUES)",
|
|
1983
|
+
"sql-builder/no-where");
|
|
1984
|
+
}
|
|
1985
|
+
var dialect = this._dialect;
|
|
1986
|
+
var params = [];
|
|
1987
|
+
var quotedCols = this._columns.map(function (c) { return _quoteId(c, dialect); }).join(", ");
|
|
1988
|
+
|
|
1989
|
+
// Each SELECT cell renders through the same choke-point INSERT VALUES
|
|
1990
|
+
// uses: `?` (bound), `?::type` (cast), or an allowlisted server-function
|
|
1991
|
+
// token (NOW() / CURRENT_TIMESTAMP - no param).
|
|
1992
|
+
var cells = [];
|
|
1993
|
+
for (var v = 0; v < this._values.length; v += 1) {
|
|
1994
|
+
var rendered = _renderValueCell(this._values[v], dialect);
|
|
1995
|
+
cells.push(rendered.sql);
|
|
1996
|
+
for (var rp = 0; rp < rendered.params.length; rp += 1) params.push(rendered.params[rp]);
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
var sql = "INSERT INTO " + this._table.ref(dialect) + " (" + quotedCols + ") SELECT " +
|
|
2000
|
+
cells.join(", ");
|
|
2001
|
+
|
|
2002
|
+
var w = this._where.build();
|
|
2003
|
+
if (w.sql) {
|
|
2004
|
+
sql += " WHERE " + w.sql;
|
|
2005
|
+
for (var wi = 0; wi < w.params.length; wi += 1) params.push(w.params[wi]);
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
sql += _renderReturning(this._returning, dialect);
|
|
2009
|
+
return _emit(sql, params);
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
|
|
1925
2013
|
// ---- UPDATE ---------------------------------------------------------
|
|
1926
2014
|
|
|
1927
2015
|
class UpdateBuilder extends Builder {
|
|
@@ -3699,6 +3787,64 @@ function select(tableNameOrRef, opts) { return new SelectBuilder(tableNameOrRef,
|
|
|
3699
3787
|
*/
|
|
3700
3788
|
function insert(tableNameOrRef, opts) { return new InsertBuilder(tableNameOrRef, opts); }
|
|
3701
3789
|
|
|
3790
|
+
/**
|
|
3791
|
+
* @primitive b.sql.insertSelectWhere
|
|
3792
|
+
* @signature b.sql.insertSelectWhere(table, opts?)
|
|
3793
|
+
* @since 0.15.13
|
|
3794
|
+
* @status stable
|
|
3795
|
+
* @related b.sql.insert, b.sql.upsert, b.sql.update
|
|
3796
|
+
*
|
|
3797
|
+
* Start a conditional `INSERT ... SELECT ... WHERE` builder - a row written
|
|
3798
|
+
* ONLY when a guard derived from the table itself holds. Emits
|
|
3799
|
+
* `INSERT INTO t (cols) SELECT <cells> WHERE <guard>`: the value-less SELECT
|
|
3800
|
+
* is a single computed candidate row the WHERE either admits (one row
|
|
3801
|
+
* inserted) or rejects (zero rows). It is the race-free append-only-ledger
|
|
3802
|
+
* debit - a store-credit / gift-card / wallet / points / metered-quota /
|
|
3803
|
+
* seat-counter balance that lives only on the latest row, with no mutable
|
|
3804
|
+
* counter row to `increment()`. The guard's correlated subquery / `EXISTS`
|
|
3805
|
+
* is evaluated atomically inside the INSERT, so two concurrent debits cannot
|
|
3806
|
+
* both pass the same balance check.
|
|
3807
|
+
*
|
|
3808
|
+
* Supply the row via `columns([...])` + `values([...])` (positional),
|
|
3809
|
+
* `values({ ... })` (one row object, inferring the column list from its
|
|
3810
|
+
* keys), then the guard via the full `where` family (`whereExists` /
|
|
3811
|
+
* `whereSub` / `whereOp` / `whereGroup` / `whereRaw` all compose - the
|
|
3812
|
+
* balance fence is typically an `EXISTS` against the same table). Each SELECT
|
|
3813
|
+
* cell routes through the same choke-point INSERT `values()` uses, so a cell
|
|
3814
|
+
* may be a bound `?`, a `b.sql.cast(...)` (`?::type`), or a `b.sql.fn(...)`
|
|
3815
|
+
* allowlisted server function (`NOW()`, no param). Standard SQL across sqlite
|
|
3816
|
+
* / Postgres / MySQL; only `RETURNING` diverges (Postgres / SQLite - refused
|
|
3817
|
+
* on MySQL, run an explicit read).
|
|
3818
|
+
*
|
|
3819
|
+
* Safety default: an INSERT...SELECT with no WHERE is just an
|
|
3820
|
+
* INSERT...VALUES, so the verb THROWS without a `where()` unless
|
|
3821
|
+
* `allowNoWhere()` opts in - the same discipline `update` / `delete` apply.
|
|
3822
|
+
*
|
|
3823
|
+
* @opts
|
|
3824
|
+
* dialect: string, // postgres | sqlite | mysql (default sqlite)
|
|
3825
|
+
* schema: string, // schema qualifier
|
|
3826
|
+
* prefix: string, // operator app-table namespace prefix
|
|
3827
|
+
* allowedColumns: array, // column-membership gate set
|
|
3828
|
+
*
|
|
3829
|
+
* @example
|
|
3830
|
+
* // Append a -25 debit ONLY if the wallet's balance row still covers it -
|
|
3831
|
+
* // a race-free conditional insert with no read-modify-write. The guard is
|
|
3832
|
+
* // an EXISTS over a same-dialect sub-builder (no raw statement verb).
|
|
3833
|
+
* var covered = b.sql.select("wallet", { dialect: "postgres" })
|
|
3834
|
+
* .selectRaw("1")
|
|
3835
|
+
* .whereRaw('"id" = ? AND "balance" >= ?', ["w-1", 25]);
|
|
3836
|
+
* b.sql.insertSelectWhere("wallet_ledger", { dialect: "postgres" })
|
|
3837
|
+
* .values({ wallet_id: "w-1", amount: -25, at: b.sql.fn("NOW") })
|
|
3838
|
+
* .whereExists(covered)
|
|
3839
|
+
* .returning(["id"])
|
|
3840
|
+
* .toSql();
|
|
3841
|
+
* // -> { sql: 'INSERT INTO wallet_ledger ("wallet_id", "amount", "at") ' +
|
|
3842
|
+
* // 'SELECT ?, ?, NOW() WHERE EXISTS (SELECT 1 FROM wallet ' +
|
|
3843
|
+
* // 'WHERE ("id" = ? AND "balance" >= ?)) RETURNING "id"',
|
|
3844
|
+
* // params: ["w-1", -25, "w-1", 25] }
|
|
3845
|
+
*/
|
|
3846
|
+
function insertSelectWhere(tableNameOrRef, opts) { return new InsertSelectWhereBuilder(tableNameOrRef, opts); }
|
|
3847
|
+
|
|
3702
3848
|
/**
|
|
3703
3849
|
* @primitive b.sql.update
|
|
3704
3850
|
* @signature b.sql.update(table, opts?)
|
|
@@ -3806,6 +3952,7 @@ module.exports = {
|
|
|
3806
3952
|
// Verbs
|
|
3807
3953
|
select: select,
|
|
3808
3954
|
insert: insert,
|
|
3955
|
+
insertSelectWhere: insertSelectWhere,
|
|
3809
3956
|
update: update,
|
|
3810
3957
|
delete: del,
|
|
3811
3958
|
upsert: upsert,
|
|
@@ -76,6 +76,8 @@
|
|
|
76
76
|
|
|
77
77
|
var C = require("./constants");
|
|
78
78
|
var audit = require("./audit");
|
|
79
|
+
var validateOpts = require("./validate-opts");
|
|
80
|
+
var numericBounds = require("./numeric-bounds");
|
|
79
81
|
var { SseError } = require("./framework-error");
|
|
80
82
|
|
|
81
83
|
// Per W3C SSE — the wire format uses LF as terminator. A single LF
|
|
@@ -228,10 +230,8 @@ function _readLastEventId(req) {
|
|
|
228
230
|
function create(req, res, opts) {
|
|
229
231
|
opts = opts || {};
|
|
230
232
|
var errorClass = opts.errorClass || SseError;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
"sse.create: res must be a writable response stream");
|
|
234
|
-
}
|
|
233
|
+
validateOpts.requireMethods(res, ["write", "end"],
|
|
234
|
+
"sse.create: res (writable response stream)", errorClass, "sse/bad-res");
|
|
235
235
|
var heartbeatMs = opts.heartbeatMs;
|
|
236
236
|
if (heartbeatMs === undefined) heartbeatMs = C.TIME.seconds(15);
|
|
237
237
|
if (typeof heartbeatMs !== "number" || !isFinite(heartbeatMs) ||
|
|
@@ -255,12 +255,8 @@ function create(req, res, opts) {
|
|
|
255
255
|
// never affected. Config-time input → throw on a bad value.
|
|
256
256
|
var maxBufferedBytes = opts.maxBufferedBytes;
|
|
257
257
|
if (maxBufferedBytes === undefined) maxBufferedBytes = C.BYTES.mib(1);
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
throw errorClass.factory("sse/bad-opts",
|
|
261
|
-
"sse.create: maxBufferedBytes must be a positive integer byte count (got " +
|
|
262
|
-
JSON.stringify(maxBufferedBytes) + ")");
|
|
263
|
-
}
|
|
258
|
+
numericBounds.requirePositiveFiniteInt(maxBufferedBytes,
|
|
259
|
+
"sse.create: maxBufferedBytes", errorClass, "sse/bad-opts");
|
|
264
260
|
|
|
265
261
|
var lastEventId = _readLastEventId(req);
|
|
266
262
|
|