@blamejs/blamejs-shop 0.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -0
- package/LICENSE +17 -0
- package/README.md +117 -0
- package/SECURITY.md +139 -0
- package/lib/admin.js +952 -0
- package/lib/analytics.js +267 -0
- package/lib/cart.js +279 -0
- package/lib/catalog-import.js +344 -0
- package/lib/catalog.js +769 -0
- package/lib/checkout.js +320 -0
- package/lib/config.js +151 -0
- package/lib/customers.js +322 -0
- package/lib/email.js +242 -0
- package/lib/externaldb-d1.js +283 -0
- package/lib/index.js +57 -0
- package/lib/inventory-alerts.js +198 -0
- package/lib/newsletter.js +142 -0
- package/lib/order.js +380 -0
- package/lib/payment.js +318 -0
- package/lib/pricing.js +185 -0
- package/lib/r2-bridge.js +169 -0
- package/lib/shipping.js +185 -0
- package/lib/storefront.js +2160 -0
- package/lib/subscriptions.js +410 -0
- package/lib/tax.js +161 -0
- package/lib/theme.js +194 -0
- package/lib/vendor/MANIFEST.json +19 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +23 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +34 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/project.yaml +16 -0
- package/lib/vendor/blamejs/.dockerignore +45 -0
- package/lib/vendor/blamejs/.gitattributes +42 -0
- package/lib/vendor/blamejs/.github/CODEOWNERS +4 -0
- package/lib/vendor/blamejs/.github/FUNDING.yml +2 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/bug_report.md +58 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/feature_request.md +99 -0
- package/lib/vendor/blamejs/.github/PULL_REQUEST_TEMPLATE.md +77 -0
- package/lib/vendor/blamejs/.github/dependabot.yml +37 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +148 -0
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +107 -0
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +122 -0
- package/lib/vendor/blamejs/.github/workflows/ci.yml +511 -0
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +50 -0
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +655 -0
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +406 -0
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +101 -0
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +134 -0
- package/lib/vendor/blamejs/.gitignore +102 -0
- package/lib/vendor/blamejs/.gitleaks.toml +166 -0
- package/lib/vendor/blamejs/.hadolint.yaml +18 -0
- package/lib/vendor/blamejs/.npmrc +5 -0
- package/lib/vendor/blamejs/.pinact.yaml +17 -0
- package/lib/vendor/blamejs/ARCHITECTURE.md +158 -0
- package/lib/vendor/blamejs/CHANGELOG.md +1351 -0
- package/lib/vendor/blamejs/CODE_OF_CONDUCT.md +86 -0
- package/lib/vendor/blamejs/CONTRIBUTING.md +156 -0
- package/lib/vendor/blamejs/GOVERNANCE.md +201 -0
- package/lib/vendor/blamejs/LICENSE +201 -0
- package/lib/vendor/blamejs/LTS-CALENDAR.md +29 -0
- package/lib/vendor/blamejs/MIGRATING.md +29 -0
- package/lib/vendor/blamejs/NOTICE +81 -0
- package/lib/vendor/blamejs/README.md +304 -0
- package/lib/vendor/blamejs/SECURITY.md +432 -0
- package/lib/vendor/blamejs/api-snapshot.json +48709 -0
- package/lib/vendor/blamejs/assets/BlameJS_Logo.png +0 -0
- package/lib/vendor/blamejs/assets/BlameJS_Logo.svg +129 -0
- package/lib/vendor/blamejs/bench/README.md +77 -0
- package/lib/vendor/blamejs/bench/_helpers.js +70 -0
- package/lib/vendor/blamejs/bench/baseline.json +183 -0
- package/lib/vendor/blamejs/bench/crypto-hash.bench.js +19 -0
- package/lib/vendor/blamejs/bench/crypto-symmetric.bench.js +28 -0
- package/lib/vendor/blamejs/bench/run.js +140 -0
- package/lib/vendor/blamejs/bench/safe-json.bench.js +31 -0
- package/lib/vendor/blamejs/bin/blamejs.js +13 -0
- package/lib/vendor/blamejs/docker/caddy/Caddyfile +46 -0
- package/lib/vendor/blamejs/docker/coredns/Corefile +37 -0
- package/lib/vendor/blamejs/docker/haproxy/haproxy.cfg +52 -0
- package/lib/vendor/blamejs/docker/init/generate-certs.sh +118 -0
- package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +87 -0
- package/lib/vendor/blamejs/docker/mitmproxy/config.yaml +16 -0
- package/lib/vendor/blamejs/docker/mongo/init-tls.sh +17 -0
- package/lib/vendor/blamejs/docker/mysql/my.cnf +12 -0
- package/lib/vendor/blamejs/docker/nats/nats.conf +33 -0
- package/lib/vendor/blamejs/docker/postgres/init-tls.sh +17 -0
- package/lib/vendor/blamejs/docker/postgres/postgresql.conf +18 -0
- package/lib/vendor/blamejs/docker/rabbitmq/rabbitmq.conf +18 -0
- package/lib/vendor/blamejs/docker/redis/redis.conf +15 -0
- package/lib/vendor/blamejs/docker/squid/squid.conf +24 -0
- package/lib/vendor/blamejs/docker/syslog/syslog-ng.conf +34 -0
- package/lib/vendor/blamejs/docker-compose.test.yml +545 -0
- package/lib/vendor/blamejs/docs/cis-postgres-crosswalk.md +102 -0
- package/lib/vendor/blamejs/docs/cis-sqlite-equivalent.md +92 -0
- package/lib/vendor/blamejs/eslint.config.mjs +204 -0
- package/lib/vendor/blamejs/examples/wiki/Caddyfile +40 -0
- package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +218 -0
- package/lib/vendor/blamejs/examples/wiki/Dockerfile +120 -0
- package/lib/vendor/blamejs/examples/wiki/README.md +157 -0
- package/lib/vendor/blamejs/examples/wiki/cli-snapshot.json +250 -0
- package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +231 -0
- package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +166 -0
- package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +217 -0
- package/lib/vendor/blamejs/examples/wiki/lib/auto-site-entries.js +139 -0
- package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +555 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-cli.js +507 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-env-vars.js +435 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-errors.js +282 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-vendored-deps.js +321 -0
- package/lib/vendor/blamejs/examples/wiki/lib/nav.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/lib/opts-resolver.js +75 -0
- package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +508 -0
- package/lib/vendor/blamejs/examples/wiki/lib/section.js +276 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +587 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +318 -0
- package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +122 -0
- package/lib/vendor/blamejs/examples/wiki/migrations/0001-pages-schema.js +74 -0
- package/lib/vendor/blamejs/examples/wiki/package.json +18 -0
- package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.png +0 -0
- package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.svg +129 -0
- package/lib/vendor/blamejs/examples/wiki/public/robots.txt +5 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/MANIFEST.json +30 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.css +1 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/public/wiki.css +1250 -0
- package/lib/vendor/blamejs/examples/wiki/routes/admin.js +366 -0
- package/lib/vendor/blamejs/examples/wiki/routes/integration.js +230 -0
- package/lib/vendor/blamejs/examples/wiki/routes/pages.js +266 -0
- package/lib/vendor/blamejs/examples/wiki/scripts/backfill-module-metadata.js +214 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/0001-default-pages.js +35 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/_index.js +34 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/api.js +76 -0
- package/lib/vendor/blamejs/examples/wiki/server.js +129 -0
- package/lib/vendor/blamejs/examples/wiki/site.config.js +197 -0
- package/lib/vendor/blamejs/examples/wiki/snippets/README.md +38 -0
- package/lib/vendor/blamejs/examples/wiki/snippets/auth/password-hash.example.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/src/editor.js +103 -0
- package/lib/vendor/blamejs/examples/wiki/src/wiki.js +349 -0
- package/lib/vendor/blamejs/examples/wiki/test/AUDIT.md +155 -0
- package/lib/vendor/blamejs/examples/wiki/test/codebase-patterns.test.js +594 -0
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +741 -0
- package/lib/vendor/blamejs/examples/wiki/test/find-missing-pages.js +254 -0
- package/lib/vendor/blamejs/examples/wiki/test/integration.js +391 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-cli-snapshot.js +379 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-env-snapshot.js +346 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-nav-coverage.js +212 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-site-coverage.js +252 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-source-comment-blocks.js +107 -0
- package/lib/vendor/blamejs/examples/wiki/views/_layout.html +115 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/api-keys.html +51 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/dashboard.html +22 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/edit.html +17 -0
- package/lib/vendor/blamejs/examples/wiki/views/home.html +85 -0
- package/lib/vendor/blamejs/examples/wiki/views/login.html +18 -0
- package/lib/vendor/blamejs/examples/wiki/views/page.html +5 -0
- package/lib/vendor/blamejs/examples/wiki/views/partials/nav.html +13 -0
- package/lib/vendor/blamejs/examples/wiki/views/search.html +19 -0
- package/lib/vendor/blamejs/examples/wiki/wiki.config.js +15 -0
- package/lib/vendor/blamejs/fuzz/README.md +137 -0
- package/lib/vendor/blamejs/fuzz/_expected.js +35 -0
- package/lib/vendor/blamejs/fuzz/guard-agent-registry.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-csv.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/01-basic.csv +3 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/02-formula.csv +1 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/03-hyperlink.csv +1 -0
- package/lib/vendor/blamejs/fuzz/guard-dsn.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-email.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-email_seed_corpus/01-basic.eml +5 -0
- package/lib/vendor/blamejs/fuzz/guard-envelope.fuzz.js +24 -0
- package/lib/vendor/blamejs/fuzz/guard-event-bus-payload.fuzz.js +24 -0
- package/lib/vendor/blamejs/fuzz/guard-event-bus-topic.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-html.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/01-basic.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/02-script.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/03-event.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/04-jsurl.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-idempotency-key.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-imap-command.fuzz.js +35 -0
- package/lib/vendor/blamejs/fuzz/guard-jmap.fuzz.js +41 -0
- package/lib/vendor/blamejs/fuzz/guard-json.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/01-basic.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/02-proto.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/03-dupkey.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/04-nan.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/05-bom.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-list-id.fuzz.js +21 -0
- package/lib/vendor/blamejs/fuzz/guard-list-unsubscribe.fuzz.js +25 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-compose.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-move.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-query.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-reply.fuzz.js +23 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-sieve.fuzz.js +36 -0
- package/lib/vendor/blamejs/fuzz/guard-managesieve-command.fuzz.js +26 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/01-basic.md +2 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/02-jsurl.md +1 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/03-jsimg.md +1 -0
- package/lib/vendor/blamejs/fuzz/guard-message-id.fuzz.js +26 -0
- package/lib/vendor/blamejs/fuzz/guard-pop3-command.fuzz.js +23 -0
- package/lib/vendor/blamejs/fuzz/guard-posture-chain.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-saga-config.fuzz.js +32 -0
- package/lib/vendor/blamejs/fuzz/guard-smtp-command.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/guard-snapshot-envelope.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-stream-args.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-svg.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/01-basic.svg +1 -0
- package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/02-script.svg +1 -0
- package/lib/vendor/blamejs/fuzz/guard-tenant-id.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-trace-context.fuzz.js +30 -0
- package/lib/vendor/blamejs/fuzz/guard-xml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/01-basic.xml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/02-xxe.xml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/01-basic.yaml +2 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/02-anchor.yaml +2 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/03-norway.yaml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/04-multidoc.yaml +4 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-ini.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-ini_seed_corpus/01-basic.ini +2 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-toml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-toml_seed_corpus/01-basic.toml +4 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-xml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-xml_seed_corpus/01-basic.xml +1 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-yaml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-yaml_seed_corpus/01-basic.yaml +4 -0
- package/lib/vendor/blamejs/fuzz/safe-decompress.fuzz.js +49 -0
- package/lib/vendor/blamejs/fuzz/safe-dns.fuzz.js +29 -0
- package/lib/vendor/blamejs/fuzz/safe-ical.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-icap.fuzz.js +42 -0
- package/lib/vendor/blamejs/fuzz/safe-json.fuzz.js +25 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/01-object.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/02-array.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/03-string.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/04-proto.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/05-deep.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/01-basic.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/02-filter.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/03-deepscan.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/04-slice.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-mime.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/safe-mount-info.fuzz.js +33 -0
- package/lib/vendor/blamejs/fuzz/safe-sieve.fuzz.js +28 -0
- package/lib/vendor/blamejs/fuzz/safe-smtp.fuzz.js +64 -0
- package/lib/vendor/blamejs/fuzz/safe-url.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/01-basic.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/02-userinfo.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/03-dangerous.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/04-data.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/05-ipv6.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/06-idn.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-vcard.fuzz.js +16 -0
- package/lib/vendor/blamejs/index.js +678 -0
- package/lib/vendor/blamejs/keys/release-pqc-pub.json +7 -0
- package/lib/vendor/blamejs/lib/_test/crypto-fixtures.js +67 -0
- package/lib/vendor/blamejs/lib/a2a-tasks.js +598 -0
- package/lib/vendor/blamejs/lib/a2a.js +407 -0
- package/lib/vendor/blamejs/lib/acme.js +1448 -0
- package/lib/vendor/blamejs/lib/agent-audit.js +45 -0
- package/lib/vendor/blamejs/lib/agent-event-bus.js +382 -0
- package/lib/vendor/blamejs/lib/agent-idempotency.js +497 -0
- package/lib/vendor/blamejs/lib/agent-orchestrator.js +717 -0
- package/lib/vendor/blamejs/lib/agent-posture-chain.js +366 -0
- package/lib/vendor/blamejs/lib/agent-saga.js +321 -0
- package/lib/vendor/blamejs/lib/agent-snapshot.js +676 -0
- package/lib/vendor/blamejs/lib/agent-stream.js +269 -0
- package/lib/vendor/blamejs/lib/agent-tenant.js +632 -0
- package/lib/vendor/blamejs/lib/agent-trace.js +281 -0
- package/lib/vendor/blamejs/lib/ai-adverse-decision.js +184 -0
- package/lib/vendor/blamejs/lib/ai-content-detect.js +268 -0
- package/lib/vendor/blamejs/lib/ai-input.js +201 -0
- package/lib/vendor/blamejs/lib/ai-model-manifest.js +363 -0
- package/lib/vendor/blamejs/lib/ai-pref.js +340 -0
- package/lib/vendor/blamejs/lib/api-key.js +721 -0
- package/lib/vendor/blamejs/lib/api-snapshot.js +458 -0
- package/lib/vendor/blamejs/lib/app-shutdown.js +557 -0
- package/lib/vendor/blamejs/lib/app.js +365 -0
- package/lib/vendor/blamejs/lib/archive.js +547 -0
- package/lib/vendor/blamejs/lib/arg-parser.js +697 -0
- package/lib/vendor/blamejs/lib/argon2-builtin.js +173 -0
- package/lib/vendor/blamejs/lib/asn1-der.js +424 -0
- package/lib/vendor/blamejs/lib/asyncapi-bindings.js +160 -0
- package/lib/vendor/blamejs/lib/asyncapi-traits.js +143 -0
- package/lib/vendor/blamejs/lib/asyncapi.js +575 -0
- package/lib/vendor/blamejs/lib/atomic-file.js +1023 -0
- package/lib/vendor/blamejs/lib/audit-chain.js +266 -0
- package/lib/vendor/blamejs/lib/audit-daily-review.js +389 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +751 -0
- package/lib/vendor/blamejs/lib/audit-tools.js +1113 -0
- package/lib/vendor/blamejs/lib/audit.js +1671 -0
- package/lib/vendor/blamejs/lib/auth/aal.js +169 -0
- package/lib/vendor/blamejs/lib/auth/access-lock.js +220 -0
- package/lib/vendor/blamejs/lib/auth/acr-vocabulary.js +265 -0
- package/lib/vendor/blamejs/lib/auth/ato-kill-switch.js +112 -0
- package/lib/vendor/blamejs/lib/auth/auth-time-tracker.js +111 -0
- package/lib/vendor/blamejs/lib/auth/bot-challenge.js +573 -0
- package/lib/vendor/blamejs/lib/auth/ciba.js +637 -0
- package/lib/vendor/blamejs/lib/auth/dpop.js +516 -0
- package/lib/vendor/blamejs/lib/auth/elevation-grant.js +306 -0
- package/lib/vendor/blamejs/lib/auth/fal.js +229 -0
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +681 -0
- package/lib/vendor/blamejs/lib/auth/jwt-external.js +519 -0
- package/lib/vendor/blamejs/lib/auth/jwt.js +430 -0
- package/lib/vendor/blamejs/lib/auth/lockout.js +449 -0
- package/lib/vendor/blamejs/lib/auth/oauth.js +2141 -0
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +657 -0
- package/lib/vendor/blamejs/lib/auth/oid4vp.js +531 -0
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +600 -0
- package/lib/vendor/blamejs/lib/auth/passkey.js +676 -0
- package/lib/vendor/blamejs/lib/auth/password.js +693 -0
- package/lib/vendor/blamejs/lib/auth/saml.js +2109 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-disclosure.js +95 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +225 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +197 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +728 -0
- package/lib/vendor/blamejs/lib/auth/status-list.js +272 -0
- package/lib/vendor/blamejs/lib/auth/step-up-policy.js +335 -0
- package/lib/vendor/blamejs/lib/auth/step-up.js +454 -0
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +505 -0
- package/lib/vendor/blamejs/lib/auth-header.js +148 -0
- package/lib/vendor/blamejs/lib/backup/bundle.js +265 -0
- package/lib/vendor/blamejs/lib/backup/crypto.js +176 -0
- package/lib/vendor/blamejs/lib/backup/index.js +1001 -0
- package/lib/vendor/blamejs/lib/backup/manifest.js +443 -0
- package/lib/vendor/blamejs/lib/boot-gates.js +174 -0
- package/lib/vendor/blamejs/lib/breach-deadline.js +272 -0
- package/lib/vendor/blamejs/lib/break-glass.js +1753 -0
- package/lib/vendor/blamejs/lib/budr.js +205 -0
- package/lib/vendor/blamejs/lib/bundler.js +461 -0
- package/lib/vendor/blamejs/lib/cache-redis.js +256 -0
- package/lib/vendor/blamejs/lib/cache-status.js +288 -0
- package/lib/vendor/blamejs/lib/cache.js +1331 -0
- package/lib/vendor/blamejs/lib/calendar.js +1240 -0
- package/lib/vendor/blamejs/lib/canonical-json.js +143 -0
- package/lib/vendor/blamejs/lib/cdn-cache-control.js +473 -0
- package/lib/vendor/blamejs/lib/cert.js +763 -0
- package/lib/vendor/blamejs/lib/chain-writer.js +259 -0
- package/lib/vendor/blamejs/lib/circuit-breaker.js +101 -0
- package/lib/vendor/blamejs/lib/cli-helpers.js +237 -0
- package/lib/vendor/blamejs/lib/cli.js +2328 -0
- package/lib/vendor/blamejs/lib/client-hints.js +318 -0
- package/lib/vendor/blamejs/lib/cloud-events.js +277 -0
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +317 -0
- package/lib/vendor/blamejs/lib/cluster-storage.js +351 -0
- package/lib/vendor/blamejs/lib/cluster.js +1017 -0
- package/lib/vendor/blamejs/lib/cms-codec.js +826 -0
- package/lib/vendor/blamejs/lib/codepoint-class.js +262 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +190 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +205 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-risk.js +189 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +200 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act.js +821 -0
- package/lib/vendor/blamejs/lib/compliance-eaa.js +204 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-aliases.js +167 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +206 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-fuzzy.js +297 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions.js +569 -0
- package/lib/vendor/blamejs/lib/compliance.js +1558 -0
- package/lib/vendor/blamejs/lib/config-drift.js +426 -0
- package/lib/vendor/blamejs/lib/config.js +446 -0
- package/lib/vendor/blamejs/lib/consent.js +369 -0
- package/lib/vendor/blamejs/lib/constants.js +209 -0
- package/lib/vendor/blamejs/lib/content-credentials.js +704 -0
- package/lib/vendor/blamejs/lib/cookies.js +560 -0
- package/lib/vendor/blamejs/lib/cra-report.js +299 -0
- package/lib/vendor/blamejs/lib/credential-hash.js +394 -0
- package/lib/vendor/blamejs/lib/crypto-field.js +1017 -0
- package/lib/vendor/blamejs/lib/crypto-hpke-pq.js +187 -0
- package/lib/vendor/blamejs/lib/crypto-hpke.js +256 -0
- package/lib/vendor/blamejs/lib/crypto.js +1908 -0
- package/lib/vendor/blamejs/lib/csp.js +271 -0
- package/lib/vendor/blamejs/lib/csv.js +418 -0
- package/lib/vendor/blamejs/lib/daemon.js +481 -0
- package/lib/vendor/blamejs/lib/dark-patterns.js +488 -0
- package/lib/vendor/blamejs/lib/data-act.js +328 -0
- package/lib/vendor/blamejs/lib/db-collection.js +587 -0
- package/lib/vendor/blamejs/lib/db-declare-row-policy.js +267 -0
- package/lib/vendor/blamejs/lib/db-declare-view.js +420 -0
- package/lib/vendor/blamejs/lib/db-file-lifecycle.js +333 -0
- package/lib/vendor/blamejs/lib/db-query.js +802 -0
- package/lib/vendor/blamejs/lib/db-role-context.js +50 -0
- package/lib/vendor/blamejs/lib/db-schema.js +322 -0
- package/lib/vendor/blamejs/lib/db.js +3111 -0
- package/lib/vendor/blamejs/lib/dbsc.js +299 -0
- package/lib/vendor/blamejs/lib/ddl-change-control.js +523 -0
- package/lib/vendor/blamejs/lib/deprecate.js +377 -0
- package/lib/vendor/blamejs/lib/dev.js +405 -0
- package/lib/vendor/blamejs/lib/dora.js +402 -0
- package/lib/vendor/blamejs/lib/dr-runbook.js +368 -0
- package/lib/vendor/blamejs/lib/dsr.js +1188 -0
- package/lib/vendor/blamejs/lib/dual-control.js +526 -0
- package/lib/vendor/blamejs/lib/early-hints.js +212 -0
- package/lib/vendor/blamejs/lib/error-page.js +420 -0
- package/lib/vendor/blamejs/lib/events.js +214 -0
- package/lib/vendor/blamejs/lib/external-db-migrate.js +659 -0
- package/lib/vendor/blamejs/lib/external-db.js +1877 -0
- package/lib/vendor/blamejs/lib/fapi2.js +394 -0
- package/lib/vendor/blamejs/lib/fda-21cfr11.js +395 -0
- package/lib/vendor/blamejs/lib/fdx.js +370 -0
- package/lib/vendor/blamejs/lib/fedcm.js +264 -0
- package/lib/vendor/blamejs/lib/file-type.js +360 -0
- package/lib/vendor/blamejs/lib/file-upload.js +1256 -0
- package/lib/vendor/blamejs/lib/flag-cache.js +136 -0
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +135 -0
- package/lib/vendor/blamejs/lib/flag-providers.js +279 -0
- package/lib/vendor/blamejs/lib/flag-targeting.js +210 -0
- package/lib/vendor/blamejs/lib/flag.js +346 -0
- package/lib/vendor/blamejs/lib/forms.js +525 -0
- package/lib/vendor/blamejs/lib/framework-error.js +724 -0
- package/lib/vendor/blamejs/lib/framework-schema.js +845 -0
- package/lib/vendor/blamejs/lib/framework-sha1-hibp.js +34 -0
- package/lib/vendor/blamejs/lib/fsm.js +469 -0
- package/lib/vendor/blamejs/lib/gate-contract.js +1661 -0
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +261 -0
- package/lib/vendor/blamejs/lib/graphql-federation.js +234 -0
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +179 -0
- package/lib/vendor/blamejs/lib/guard-all.js +555 -0
- package/lib/vendor/blamejs/lib/guard-archive.js +901 -0
- package/lib/vendor/blamejs/lib/guard-auth.js +451 -0
- package/lib/vendor/blamejs/lib/guard-cidr.js +676 -0
- package/lib/vendor/blamejs/lib/guard-csv.js +1176 -0
- package/lib/vendor/blamejs/lib/guard-domain.js +814 -0
- package/lib/vendor/blamejs/lib/guard-dsn.js +382 -0
- package/lib/vendor/blamejs/lib/guard-email.js +951 -0
- package/lib/vendor/blamejs/lib/guard-envelope.js +294 -0
- package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +217 -0
- package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +150 -0
- package/lib/vendor/blamejs/lib/guard-filename.js +956 -0
- package/lib/vendor/blamejs/lib/guard-graphql.js +731 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-aria.js +164 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-forms.js +144 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-tables.js +154 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-tagwalk.js +44 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag.js +470 -0
- package/lib/vendor/blamejs/lib/guard-html.js +1209 -0
- package/lib/vendor/blamejs/lib/guard-idempotency-key.js +151 -0
- package/lib/vendor/blamejs/lib/guard-image.js +584 -0
- package/lib/vendor/blamejs/lib/guard-imap-command.js +337 -0
- package/lib/vendor/blamejs/lib/guard-jmap.js +321 -0
- package/lib/vendor/blamejs/lib/guard-json.js +935 -0
- package/lib/vendor/blamejs/lib/guard-jsonpath.js +512 -0
- package/lib/vendor/blamejs/lib/guard-jwt.js +772 -0
- package/lib/vendor/blamejs/lib/guard-list-id.js +318 -0
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +412 -0
- package/lib/vendor/blamejs/lib/guard-mail-compose.js +282 -0
- package/lib/vendor/blamejs/lib/guard-mail-move.js +202 -0
- package/lib/vendor/blamejs/lib/guard-mail-query.js +310 -0
- package/lib/vendor/blamejs/lib/guard-mail-reply.js +172 -0
- package/lib/vendor/blamejs/lib/guard-mail-sieve.js +207 -0
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +566 -0
- package/lib/vendor/blamejs/lib/guard-markdown.js +768 -0
- package/lib/vendor/blamejs/lib/guard-message-id.js +267 -0
- package/lib/vendor/blamejs/lib/guard-mime.js +609 -0
- package/lib/vendor/blamejs/lib/guard-oauth.js +650 -0
- package/lib/vendor/blamejs/lib/guard-pdf.js +569 -0
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +317 -0
- package/lib/vendor/blamejs/lib/guard-posture-chain.js +201 -0
- package/lib/vendor/blamejs/lib/guard-regex.js +632 -0
- package/lib/vendor/blamejs/lib/guard-saga-config.js +157 -0
- package/lib/vendor/blamejs/lib/guard-shell.js +522 -0
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +594 -0
- package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +168 -0
- package/lib/vendor/blamejs/lib/guard-stream-args.js +166 -0
- package/lib/vendor/blamejs/lib/guard-svg.js +1163 -0
- package/lib/vendor/blamejs/lib/guard-template.js +490 -0
- package/lib/vendor/blamejs/lib/guard-tenant-id.js +138 -0
- package/lib/vendor/blamejs/lib/guard-time.js +586 -0
- package/lib/vendor/blamejs/lib/guard-trace-context.js +172 -0
- package/lib/vendor/blamejs/lib/guard-uuid.js +548 -0
- package/lib/vendor/blamejs/lib/guard-xml.js +666 -0
- package/lib/vendor/blamejs/lib/guard-yaml.js +726 -0
- package/lib/vendor/blamejs/lib/hal.js +125 -0
- package/lib/vendor/blamejs/lib/handlers.js +350 -0
- package/lib/vendor/blamejs/lib/honeytoken.js +168 -0
- package/lib/vendor/blamejs/lib/html-balance.js +347 -0
- package/lib/vendor/blamejs/lib/http-client-cache.js +923 -0
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +519 -0
- package/lib/vendor/blamejs/lib/http-client.js +2152 -0
- package/lib/vendor/blamejs/lib/http-message-signature.js +589 -0
- package/lib/vendor/blamejs/lib/http2-teardown.js +34 -0
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +398 -0
- package/lib/vendor/blamejs/lib/i18n.js +931 -0
- package/lib/vendor/blamejs/lib/iab-mspa.js +257 -0
- package/lib/vendor/blamejs/lib/iab-tcf.js +461 -0
- package/lib/vendor/blamejs/lib/importmap-integrity.js +90 -0
- package/lib/vendor/blamejs/lib/inbox.js +435 -0
- package/lib/vendor/blamejs/lib/incident-report.js +314 -0
- package/lib/vendor/blamejs/lib/ip-utils.js +102 -0
- package/lib/vendor/blamejs/lib/jobs.js +185 -0
- package/lib/vendor/blamejs/lib/jose-jwe-experimental.js +228 -0
- package/lib/vendor/blamejs/lib/jsonapi.js +230 -0
- package/lib/vendor/blamejs/lib/keychain.js +865 -0
- package/lib/vendor/blamejs/lib/lazy-require.js +48 -0
- package/lib/vendor/blamejs/lib/legal-hold.js +374 -0
- package/lib/vendor/blamejs/lib/local-db-thin.js +321 -0
- package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +369 -0
- package/lib/vendor/blamejs/lib/log-stream-local.js +146 -0
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +410 -0
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +286 -0
- package/lib/vendor/blamejs/lib/log-stream-syslog.js +310 -0
- package/lib/vendor/blamejs/lib/log-stream-webhook.js +199 -0
- package/lib/vendor/blamejs/lib/log-stream.js +584 -0
- package/lib/vendor/blamejs/lib/log.js +625 -0
- package/lib/vendor/blamejs/lib/lro.js +200 -0
- package/lib/vendor/blamejs/lib/mail-agent.js +786 -0
- package/lib/vendor/blamejs/lib/mail-arc-sign.js +417 -0
- package/lib/vendor/blamejs/lib/mail-arf.js +343 -0
- package/lib/vendor/blamejs/lib/mail-auth.js +2144 -0
- package/lib/vendor/blamejs/lib/mail-bimi.js +1047 -0
- package/lib/vendor/blamejs/lib/mail-bounce.js +955 -0
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +1286 -0
- package/lib/vendor/blamejs/lib/mail-crypto-smime.js +789 -0
- package/lib/vendor/blamejs/lib/mail-crypto.js +108 -0
- package/lib/vendor/blamejs/lib/mail-dav.js +1224 -0
- package/lib/vendor/blamejs/lib/mail-deploy.js +1119 -0
- package/lib/vendor/blamejs/lib/mail-dkim.js +1250 -0
- package/lib/vendor/blamejs/lib/mail-greylist.js +448 -0
- package/lib/vendor/blamejs/lib/mail-helo.js +473 -0
- package/lib/vendor/blamejs/lib/mail-journal.js +435 -0
- package/lib/vendor/blamejs/lib/mail-mdn.js +424 -0
- package/lib/vendor/blamejs/lib/mail-rbl.js +392 -0
- package/lib/vendor/blamejs/lib/mail-require-tls.js +198 -0
- package/lib/vendor/blamejs/lib/mail-scan.js +502 -0
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +629 -0
- package/lib/vendor/blamejs/lib/mail-server-imap.js +1858 -0
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +1565 -0
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +908 -0
- package/lib/vendor/blamejs/lib/mail-server-mx.js +969 -0
- package/lib/vendor/blamejs/lib/mail-server-pop3.js +915 -0
- package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +315 -0
- package/lib/vendor/blamejs/lib/mail-server-registry.js +378 -0
- package/lib/vendor/blamejs/lib/mail-server-submission.js +1396 -0
- package/lib/vendor/blamejs/lib/mail-server-tls.js +445 -0
- package/lib/vendor/blamejs/lib/mail-sieve.js +557 -0
- package/lib/vendor/blamejs/lib/mail-spam-score.js +284 -0
- package/lib/vendor/blamejs/lib/mail-srs.js +248 -0
- package/lib/vendor/blamejs/lib/mail-store-fts.js +394 -0
- package/lib/vendor/blamejs/lib/mail-store.js +929 -0
- package/lib/vendor/blamejs/lib/mail-unsubscribe.js +400 -0
- package/lib/vendor/blamejs/lib/mail.js +1971 -0
- package/lib/vendor/blamejs/lib/mcp-tool-registry.js +473 -0
- package/lib/vendor/blamejs/lib/mcp.js +950 -0
- package/lib/vendor/blamejs/lib/metrics.js +1503 -0
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +177 -0
- package/lib/vendor/blamejs/lib/middleware/ai-act-disclosure.js +203 -0
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +981 -0
- package/lib/vendor/blamejs/lib/middleware/assetlinks.js +137 -0
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +171 -0
- package/lib/vendor/blamejs/lib/middleware/attach-user.js +220 -0
- package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +293 -0
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +1519 -0
- package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +183 -0
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +217 -0
- package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +122 -0
- package/lib/vendor/blamejs/lib/middleware/compose-pipeline.js +355 -0
- package/lib/vendor/blamejs/lib/middleware/compression.js +489 -0
- package/lib/vendor/blamejs/lib/middleware/cookies.js +130 -0
- package/lib/vendor/blamejs/lib/middleware/cors.js +386 -0
- package/lib/vendor/blamejs/lib/middleware/csp-nonce.js +388 -0
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +167 -0
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +499 -0
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +243 -0
- package/lib/vendor/blamejs/lib/middleware/db-role-for.js +304 -0
- package/lib/vendor/blamejs/lib/middleware/dpop.js +402 -0
- package/lib/vendor/blamejs/lib/middleware/error-handler.js +69 -0
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +168 -0
- package/lib/vendor/blamejs/lib/middleware/flag-context.js +110 -0
- package/lib/vendor/blamejs/lib/middleware/gpc.js +153 -0
- package/lib/vendor/blamejs/lib/middleware/headers.js +242 -0
- package/lib/vendor/blamejs/lib/middleware/health.js +438 -0
- package/lib/vendor/blamejs/lib/middleware/host-allowlist.js +189 -0
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +964 -0
- package/lib/vendor/blamejs/lib/middleware/index.js +183 -0
- package/lib/vendor/blamejs/lib/middleware/nel.js +214 -0
- package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +237 -0
- package/lib/vendor/blamejs/lib/middleware/no-cache.js +106 -0
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +177 -0
- package/lib/vendor/blamejs/lib/middleware/protected-resource-metadata.js +277 -0
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +556 -0
- package/lib/vendor/blamejs/lib/middleware/request-id.js +79 -0
- package/lib/vendor/blamejs/lib/middleware/request-log.js +205 -0
- package/lib/vendor/blamejs/lib/middleware/require-aal.js +138 -0
- package/lib/vendor/blamejs/lib/middleware/require-auth.js +144 -0
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +290 -0
- package/lib/vendor/blamejs/lib/middleware/require-content-type.js +113 -0
- package/lib/vendor/blamejs/lib/middleware/require-methods.js +97 -0
- package/lib/vendor/blamejs/lib/middleware/require-mtls.js +212 -0
- package/lib/vendor/blamejs/lib/middleware/require-step-up.js +226 -0
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +375 -0
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +285 -0
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +170 -0
- package/lib/vendor/blamejs/lib/middleware/span-http-server.js +280 -0
- package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +323 -0
- package/lib/vendor/blamejs/lib/middleware/sse.js +200 -0
- package/lib/vendor/blamejs/lib/middleware/trace-log-correlation.js +167 -0
- package/lib/vendor/blamejs/lib/middleware/trace-propagate.js +148 -0
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +749 -0
- package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +164 -0
- package/lib/vendor/blamejs/lib/migration-files.js +37 -0
- package/lib/vendor/blamejs/lib/migrations.js +385 -0
- package/lib/vendor/blamejs/lib/mime-parse.js +198 -0
- package/lib/vendor/blamejs/lib/money.js +699 -0
- package/lib/vendor/blamejs/lib/mtls-ca.js +572 -0
- package/lib/vendor/blamejs/lib/mtls-engine-default.js +501 -0
- package/lib/vendor/blamejs/lib/network-byte-quota.js +308 -0
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +533 -0
- package/lib/vendor/blamejs/lib/network-dns.js +1930 -0
- package/lib/vendor/blamejs/lib/network-heartbeat.js +425 -0
- package/lib/vendor/blamejs/lib/network-nts.js +574 -0
- package/lib/vendor/blamejs/lib/network-proxy.js +265 -0
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +836 -0
- package/lib/vendor/blamejs/lib/network-tls.js +3126 -0
- package/lib/vendor/blamejs/lib/network.js +346 -0
- package/lib/vendor/blamejs/lib/nis2-report.js +181 -0
- package/lib/vendor/blamejs/lib/nist-crosswalk.js +293 -0
- package/lib/vendor/blamejs/lib/nonce-store.js +177 -0
- package/lib/vendor/blamejs/lib/notify.js +683 -0
- package/lib/vendor/blamejs/lib/ntp-check.js +458 -0
- package/lib/vendor/blamejs/lib/numeric-bounds.js +111 -0
- package/lib/vendor/blamejs/lib/numeric-checks.js +40 -0
- package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +349 -0
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +488 -0
- package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +351 -0
- package/lib/vendor/blamejs/lib/object-store/gcs.js +515 -0
- package/lib/vendor/blamejs/lib/object-store/http-put.js +153 -0
- package/lib/vendor/blamejs/lib/object-store/http-request.js +38 -0
- package/lib/vendor/blamejs/lib/object-store/index.js +197 -0
- package/lib/vendor/blamejs/lib/object-store/local.js +163 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +1133 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +957 -0
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +420 -0
- package/lib/vendor/blamejs/lib/observability-tracer.js +395 -0
- package/lib/vendor/blamejs/lib/observability.js +720 -0
- package/lib/vendor/blamejs/lib/openapi-paths-builder.js +248 -0
- package/lib/vendor/blamejs/lib/openapi-schema-walk.js +192 -0
- package/lib/vendor/blamejs/lib/openapi-security.js +169 -0
- package/lib/vendor/blamejs/lib/openapi-yaml.js +154 -0
- package/lib/vendor/blamejs/lib/openapi.js +489 -0
- package/lib/vendor/blamejs/lib/otel-export.js +278 -0
- package/lib/vendor/blamejs/lib/outbox.js +547 -0
- package/lib/vendor/blamejs/lib/pagination.js +542 -0
- package/lib/vendor/blamejs/lib/parsers/index.js +91 -0
- package/lib/vendor/blamejs/lib/parsers/safe-env.js +642 -0
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +293 -0
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +784 -0
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +390 -0
- package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +1015 -0
- package/lib/vendor/blamejs/lib/permissions.js +793 -0
- package/lib/vendor/blamejs/lib/pick.js +105 -0
- package/lib/vendor/blamejs/lib/pqc-agent.js +351 -0
- package/lib/vendor/blamejs/lib/pqc-gate.js +279 -0
- package/lib/vendor/blamejs/lib/pqc-software.js +271 -0
- package/lib/vendor/blamejs/lib/problem-details.js +482 -0
- package/lib/vendor/blamejs/lib/process-spawn.js +196 -0
- package/lib/vendor/blamejs/lib/promise-pool.js +162 -0
- package/lib/vendor/blamejs/lib/protobuf-encoder.js +190 -0
- package/lib/vendor/blamejs/lib/protocol-dispatcher.js +161 -0
- package/lib/vendor/blamejs/lib/public-suffix.js +403 -0
- package/lib/vendor/blamejs/lib/pubsub-cluster.js +154 -0
- package/lib/vendor/blamejs/lib/pubsub-redis.js +167 -0
- package/lib/vendor/blamejs/lib/pubsub.js +463 -0
- package/lib/vendor/blamejs/lib/queue-local.js +476 -0
- package/lib/vendor/blamejs/lib/queue-redis.js +745 -0
- package/lib/vendor/blamejs/lib/queue-sqs.js +319 -0
- package/lib/vendor/blamejs/lib/queue.js +1016 -0
- package/lib/vendor/blamejs/lib/redact.js +1007 -0
- package/lib/vendor/blamejs/lib/redis-client.js +520 -0
- package/lib/vendor/blamejs/lib/render.js +285 -0
- package/lib/vendor/blamejs/lib/request-helpers.js +767 -0
- package/lib/vendor/blamejs/lib/resource-access-lock.js +116 -0
- package/lib/vendor/blamejs/lib/restore-bundle.js +340 -0
- package/lib/vendor/blamejs/lib/restore-rollback.js +365 -0
- package/lib/vendor/blamejs/lib/restore.js +409 -0
- package/lib/vendor/blamejs/lib/retention.js +640 -0
- package/lib/vendor/blamejs/lib/retry.js +523 -0
- package/lib/vendor/blamejs/lib/router.js +1289 -0
- package/lib/vendor/blamejs/lib/safe-async.js +1184 -0
- package/lib/vendor/blamejs/lib/safe-buffer.js +562 -0
- package/lib/vendor/blamejs/lib/safe-decompress.js +297 -0
- package/lib/vendor/blamejs/lib/safe-dns.js +665 -0
- package/lib/vendor/blamejs/lib/safe-ical.js +634 -0
- package/lib/vendor/blamejs/lib/safe-icap.js +502 -0
- package/lib/vendor/blamejs/lib/safe-json.js +946 -0
- package/lib/vendor/blamejs/lib/safe-jsonpath.js +285 -0
- package/lib/vendor/blamejs/lib/safe-mime.js +831 -0
- package/lib/vendor/blamejs/lib/safe-mount-info.js +306 -0
- package/lib/vendor/blamejs/lib/safe-path.js +254 -0
- package/lib/vendor/blamejs/lib/safe-redirect.js +106 -0
- package/lib/vendor/blamejs/lib/safe-schema.js +1810 -0
- package/lib/vendor/blamejs/lib/safe-sieve.js +684 -0
- package/lib/vendor/blamejs/lib/safe-smtp.js +185 -0
- package/lib/vendor/blamejs/lib/safe-sql.js +363 -0
- package/lib/vendor/blamejs/lib/safe-url.js +428 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +473 -0
- package/lib/vendor/blamejs/lib/sandbox-worker.js +135 -0
- package/lib/vendor/blamejs/lib/sandbox.js +358 -0
- package/lib/vendor/blamejs/lib/scheduler.js +827 -0
- package/lib/vendor/blamejs/lib/sd-notify.js +269 -0
- package/lib/vendor/blamejs/lib/sec-cyber.js +214 -0
- package/lib/vendor/blamejs/lib/security-assert.js +395 -0
- package/lib/vendor/blamejs/lib/seeders.js +620 -0
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +309 -0
- package/lib/vendor/blamejs/lib/self-update.js +804 -0
- package/lib/vendor/blamejs/lib/server-timing.js +174 -0
- package/lib/vendor/blamejs/lib/session-device-binding.js +431 -0
- package/lib/vendor/blamejs/lib/session-stores.js +138 -0
- package/lib/vendor/blamejs/lib/session.js +1162 -0
- package/lib/vendor/blamejs/lib/slug.js +381 -0
- package/lib/vendor/blamejs/lib/sse.js +349 -0
- package/lib/vendor/blamejs/lib/ssrf-guard.js +792 -0
- package/lib/vendor/blamejs/lib/standard-webhooks.js +183 -0
- package/lib/vendor/blamejs/lib/static.js +1249 -0
- package/lib/vendor/blamejs/lib/storage.js +1272 -0
- package/lib/vendor/blamejs/lib/stream-throttle.js +235 -0
- package/lib/vendor/blamejs/lib/structured-fields.js +244 -0
- package/lib/vendor/blamejs/lib/subject.js +667 -0
- package/lib/vendor/blamejs/lib/tcpa-10dlc.js +175 -0
- package/lib/vendor/blamejs/lib/template.js +931 -0
- package/lib/vendor/blamejs/lib/tenant-quota.js +545 -0
- package/lib/vendor/blamejs/lib/test-harness.js +275 -0
- package/lib/vendor/blamejs/lib/testing.js +1185 -0
- package/lib/vendor/blamejs/lib/time.js +578 -0
- package/lib/vendor/blamejs/lib/tls-exporter.js +239 -0
- package/lib/vendor/blamejs/lib/totp.js +318 -0
- package/lib/vendor/blamejs/lib/tracing.js +546 -0
- package/lib/vendor/blamejs/lib/uuid.js +207 -0
- package/lib/vendor/blamejs/lib/validate-opts.js +381 -0
- package/lib/vendor/blamejs/lib/vault/index.js +638 -0
- package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +311 -0
- package/lib/vendor/blamejs/lib/vault/passphrase-source.js +198 -0
- package/lib/vendor/blamejs/lib/vault/rotate.js +803 -0
- package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +471 -0
- package/lib/vendor/blamejs/lib/vault/wrap.js +296 -0
- package/lib/vendor/blamejs/lib/vault-aad.js +259 -0
- package/lib/vendor/blamejs/lib/vendor/.vendor-data-pubkey +4 -0
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +161 -0
- package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.data.js +68 -0
- package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.pem +33 -0
- package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.data.js +1325 -0
- package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.txt +10002 -0
- package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +9 -0
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +18 -0
- package/lib/vendor/blamejs/lib/vendor/pki.cjs +181 -0
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +16382 -0
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5881 -0
- package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +328 -0
- package/lib/vendor/blamejs/lib/vendor/vendor-data-pubkey.js +16 -0
- package/lib/vendor/blamejs/lib/vendor-data.js +520 -0
- package/lib/vendor/blamejs/lib/vex.js +630 -0
- package/lib/vendor/blamejs/lib/watcher.js +608 -0
- package/lib/vendor/blamejs/lib/web-push-vapid.js +322 -0
- package/lib/vendor/blamejs/lib/webhook.js +977 -0
- package/lib/vendor/blamejs/lib/websocket-channels.js +327 -0
- package/lib/vendor/blamejs/lib/websocket.js +1561 -0
- package/lib/vendor/blamejs/lib/wiki-concepts.js +338 -0
- package/lib/vendor/blamejs/lib/worker-pool.js +464 -0
- package/lib/vendor/blamejs/lib/ws-client.js +978 -0
- package/lib/vendor/blamejs/lib/xml-c14n.js +506 -0
- package/lib/vendor/blamejs/memory/specs/node-26-map-getorinsert-migration.md +164 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +19 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/README.md +88 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/build.sh +26 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/project.yaml +28 -0
- package/lib/vendor/blamejs/package.json +81 -0
- package/lib/vendor/blamejs/release-notes/v0.0.x.json +310 -0
- package/lib/vendor/blamejs/release-notes/v0.1.x.json +1798 -0
- package/lib/vendor/blamejs/release-notes/v0.10.x.json +1288 -0
- package/lib/vendor/blamejs/release-notes/v0.11.x.json +2551 -0
- package/lib/vendor/blamejs/release-notes/v0.12.0.json +64 -0
- package/lib/vendor/blamejs/release-notes/v0.12.1.json +32 -0
- package/lib/vendor/blamejs/release-notes/v0.12.2.json +45 -0
- package/lib/vendor/blamejs/release-notes/v0.2.x.json +706 -0
- package/lib/vendor/blamejs/release-notes/v0.3.x.json +786 -0
- package/lib/vendor/blamejs/release-notes/v0.4.x.json +588 -0
- package/lib/vendor/blamejs/release-notes/v0.5.x.json +390 -0
- package/lib/vendor/blamejs/release-notes/v0.6.x.json +1947 -0
- package/lib/vendor/blamejs/release-notes/v0.7.x.json +3811 -0
- package/lib/vendor/blamejs/release-notes/v0.8.x.json +3318 -0
- package/lib/vendor/blamejs/release-notes/v0.9.x.json +2257 -0
- package/lib/vendor/blamejs/scripts/build-vendored-sbom.js +325 -0
- package/lib/vendor/blamejs/scripts/check-api-snapshot.js +62 -0
- package/lib/vendor/blamejs/scripts/check-changelog-extract.js +108 -0
- package/lib/vendor/blamejs/scripts/check-pack-against-gitignore.js +83 -0
- package/lib/vendor/blamejs/scripts/check-services.js +483 -0
- package/lib/vendor/blamejs/scripts/check-vendor-currency.js +349 -0
- package/lib/vendor/blamejs/scripts/consolidate-release-notes.js +216 -0
- package/lib/vendor/blamejs/scripts/gen-migrating.js +275 -0
- package/lib/vendor/blamejs/scripts/generate-changelog-entry.js +577 -0
- package/lib/vendor/blamejs/scripts/generate-release-signing-key.js +79 -0
- package/lib/vendor/blamejs/scripts/publish-dep-confusion-placeholder.sh +101 -0
- package/lib/vendor/blamejs/scripts/refresh-api-snapshot.js +31 -0
- package/lib/vendor/blamejs/scripts/refresh-vendor-manifest.js +132 -0
- package/lib/vendor/blamejs/scripts/release.js +652 -0
- package/lib/vendor/blamejs/scripts/sha3-digest.js +62 -0
- package/lib/vendor/blamejs/scripts/sign-release-artifact.js +92 -0
- package/lib/vendor/blamejs/scripts/test-integration.js +181 -0
- package/lib/vendor/blamejs/scripts/test-wiki-integration.js +126 -0
- package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +77 -0
- package/lib/vendor/blamejs/scripts/vendor-data-gen.js +186 -0
- package/lib/vendor/blamejs/scripts/vendor-data-keygen.js +101 -0
- package/lib/vendor/blamejs/scripts/vendor-update.sh +278 -0
- package/lib/vendor/blamejs/test/00-primitives.js +19075 -0
- package/lib/vendor/blamejs/test/10-state.js +622 -0
- package/lib/vendor/blamejs/test/20-db.js +561 -0
- package/lib/vendor/blamejs/test/30-chain.js +2110 -0
- package/lib/vendor/blamejs/test/40-consumers.js +2453 -0
- package/lib/vendor/blamejs/test/50-integration.js +486 -0
- package/lib/vendor/blamejs/test/_helpers.js +10 -0
- package/lib/vendor/blamejs/test/_smoke-worker.js +69 -0
- package/lib/vendor/blamejs/test/fixtures/exploit-corpus/corpus.json +368 -0
- package/lib/vendor/blamejs/test/fixtures/http-client-stream-payload.txt +2 -0
- package/lib/vendor/blamejs/test/fixtures/worker-pool/echo.js +52 -0
- package/lib/vendor/blamejs/test/helpers/_codebase-shingle-worker.js +24 -0
- package/lib/vendor/blamejs/test/helpers/_codebase-shingle.js +203 -0
- package/lib/vendor/blamejs/test/helpers/_shape-match.js +513 -0
- package/lib/vendor/blamejs/test/helpers/check.js +36 -0
- package/lib/vendor/blamejs/test/helpers/cluster.js +70 -0
- package/lib/vendor/blamejs/test/helpers/db.js +143 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +207 -0
- package/lib/vendor/blamejs/test/helpers/fs-watch.js +101 -0
- package/lib/vendor/blamejs/test/helpers/http.js +14 -0
- package/lib/vendor/blamejs/test/helpers/index.js +93 -0
- package/lib/vendor/blamejs/test/helpers/json-round-trip.js +120 -0
- package/lib/vendor/blamejs/test/helpers/mocks.js +20 -0
- package/lib/vendor/blamejs/test/helpers/otel.js +13 -0
- package/lib/vendor/blamejs/test/helpers/services.js +380 -0
- package/lib/vendor/blamejs/test/helpers/wait.js +206 -0
- package/lib/vendor/blamejs/test/integration/cache.test.js +235 -0
- package/lib/vendor/blamejs/test/integration/cluster-provider-mysql.test.js +174 -0
- package/lib/vendor/blamejs/test/integration/federation-auth.test.js +611 -0
- package/lib/vendor/blamejs/test/integration/http-client.test.js +129 -0
- package/lib/vendor/blamejs/test/integration/log-stream.test.js +219 -0
- package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +181 -0
- package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +152 -0
- package/lib/vendor/blamejs/test/integration/mail-smtp.test.js +161 -0
- package/lib/vendor/blamejs/test/integration/mtls-ca.test.js +289 -0
- package/lib/vendor/blamejs/test/integration/network-dns.test.js +123 -0
- package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +101 -0
- package/lib/vendor/blamejs/test/integration/ntp-check.test.js +89 -0
- package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +403 -0
- package/lib/vendor/blamejs/test/integration/pqc-pkcs8-forward-compat.test.js +271 -0
- package/lib/vendor/blamejs/test/integration/pubsub.test.js +137 -0
- package/lib/vendor/blamejs/test/integration/queue-redis.test.js +352 -0
- package/lib/vendor/blamejs/test/integration/redis-client-tls.test.js +96 -0
- package/lib/vendor/blamejs/test/integration/ssrf-guard.test.js +98 -0
- package/lib/vendor/blamejs/test/integration/websocket-permessage-deflate.test.js +261 -0
- package/lib/vendor/blamejs/test/integration/ws-client-roundtrip.test.js +230 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +211 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/access-lock.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +219 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +262 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-orchestrator.test.js +390 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-posture-chain.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +279 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +322 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-stream.test.js +227 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-tenant.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-trace.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-adverse-decision.test.js +44 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-content-detect.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-input.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-model-manifest.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-pref.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +1080 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +311 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-zip-stream.test.js +291 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +267 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +108 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asyncapi.test.js +929 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-conflict-path.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-cve-defensive.test.js +176 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-export-cadf.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +141 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-segregation.test.js +115 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-ml-dsa-65.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +246 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge-verifier.test.js +485 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +331 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +352 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +572 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-password-audit.test.js +61 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-bucket-ops.test.js +258 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-worker.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/bearer-auth.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-chunked-malformed.test.js +131 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-smuggling.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/boot-gates.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/breach-deadline.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +861 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/budr.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/bundler-engine.test.js +209 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache-status.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +871 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +891 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/canonical-json-jcs.test.js +43 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cdn-cache-control.test.js +243 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +550 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-audit-verify-chain.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-backup.test.js +135 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-config-drift.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +75 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-file-type.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-helpers.test.js +145 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-mtls.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-password.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-restore.test.js +160 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-retention.test.js +84 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-security.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-vault.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/client-hints.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +237 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +9600 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-cascade.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-eaa.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +712 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/config-drift.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/config.test.js +424 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +357 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cra-report.test.js +31 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-envelope.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +193 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke-pq.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke.test.js +155 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-mlkem768-x25519.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-namespace-hash.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-random-int.test.js +72 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +210 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daily-byte-quota.test.js +153 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-collection-extensions.test.js +226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-collection.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-init-extensions.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-extensions.test.js +191 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-role-for.test.js +228 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-vacuum.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +184 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/declare-row-policy.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/declare-view.test.js +303 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dns-dnssec-algorithm.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dns-null-mx.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dr-runbook.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr-state-rules.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +786 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/early-hints.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/events.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/exploit-replay.test.js +243 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +181 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-routing.test.js +531 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fapi2.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +156 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fdx.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +434 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +432 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/file-type.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +887 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/forensic-snapshot.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fsm.test.js +375 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gcs-bucket-ops.test.js +321 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +41 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-agent-registry.test.js +87 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-all.test.js +328 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +339 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +694 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-dsn.test.js +296 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +234 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-envelope.test.js +192 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-payload.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-topic.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +386 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html-wcag.test.js +859 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +357 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +317 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-id.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-unsubscribe.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-compose.test.js +111 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-move.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-query.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-reply.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-sieve.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +301 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +265 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-message-id.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +161 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-posture-chain.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-saga-config.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-smtp-command.test.js +269 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-snapshot-envelope.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-stream-args.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +288 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-tenant-id.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-trace-context.test.js +102 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +202 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/hal.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/honeytoken.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +692 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +280 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +225 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +991 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/iab-mspa.test.js +63 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/iab-tcf.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +612 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +56 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +166 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/incident-report.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jose-jwe-experimental.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-api.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-round-trip-helper.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +159 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/local-db-thin.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-cloudwatch.test.js +489 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp-grpc.test.js +207 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/lro.test.js +65 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +417 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +208 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +910 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +502 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +680 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-canspam.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +297 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +514 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy-tlsrpt.test.js +369 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +627 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-feedback-id.test.js +56 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +217 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +217 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-mdn.test.js +334 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-rbl.test.js +271 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-require-tls.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +215 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +336 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +732 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +840 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +285 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +229 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +394 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-spam-score.test.js +204 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-srs.test.js +152 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +279 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-unsubscribe.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +439 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp-tool-registry.test.js +202 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +155 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-shadow-registry.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +224 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-compose-pipeline.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +376 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-paths.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nel.test.js +200 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-byte-quota.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +372 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +635 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-heartbeat-passive.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-build-options.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-ct-inclusion.test.js +179 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +447 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +369 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nis2-report.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nist-crosswalk.test.js +42 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/no-cache.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/notify.test.js +707 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/numeric-bounds.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +72 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +597 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/openapi.test.js +877 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +257 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pagination.test.js +522 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +324 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +546 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +153 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-software.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/problem-details.test.js +195 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/process-spawn.test.js +62 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/promise-pool.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protected-resource-metadata.test.js +68 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protobuf-encoder.test.js +138 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protocol-dispatcher.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/public-suffix.test.js +197 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +232 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-dlq-extend-lease.test.js +178 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +322 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-priority-rate-progress.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-sqs.test.js +300 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-cluster.test.js +338 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-registry.test.js +75 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +246 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +335 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-log.test.js +170 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-auth-cache-control.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-mtls.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/resource-access-lock.test.js +52 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retry.test.js +535 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-cross-origin-redirect.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-parallel.test.js +170 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +248 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +451 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +289 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-icap.test.js +206 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +339 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mount-info.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-sieve.test.js +123 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-smtp.test.js +95 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-idn-homograph.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +257 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/saml-slo.test.js +249 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +228 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-exactly-once.test.js +238 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +700 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-notify.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sec-cyber.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +175 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/seeders.test.js +816 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update-standalone-verifier.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/server-timing.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +247 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +295 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/shape-match.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +952 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-multipart-sse.test.js +441 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/slug.test.js +330 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/smtp-policy.test.js +233 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/source-comment-blocks.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/speculation-rules.test.js +319 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sse.test.js +148 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/standard-webhooks.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +487 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-chunk-scratch.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +773 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/stream-throttle.test.js +173 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tcpa-10dlc.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +571 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/test-harness.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/testing-request.test.js +119 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/testing.test.js +522 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-exporter.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-ct.test.js +275 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-verify.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-pinset-drift.test.js +35 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-preferred-groups.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tracing.test.js +280 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/uuid.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-aad.test.js +277 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-seal-pem-file.test.js +252 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vendor-data.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vendor-manifest.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vex.test.js +661 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +308 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/web-push-vapid.test.js +144 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +674 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket-channels.test.js +360 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +349 -0
- package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +717 -0
- package/lib/vendor/blamejs/test/layer-5-integration/bundler-output.test.js +444 -0
- package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +597 -0
- package/lib/vendor/blamejs/test/layer-5-integration/security-chaos.test.js +308 -0
- package/lib/vendor/blamejs/test/smoke.js +431 -0
- package/lib/webhooks.js +305 -0
- package/package.json +43 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
One entry per released tag, grouped by minor. Latest first.
|
|
4
|
+
|
|
5
|
+
Pre-1.0 the surface is intentionally evolving — every release may
|
|
6
|
+
change something operators depend on. Read each entry before
|
|
7
|
+
upgrading across more than a few patches at a time.
|
|
8
|
+
|
|
9
|
+
## v0.0.x
|
|
10
|
+
|
|
11
|
+
- v0.0.44 (2026-05-22) — **Package rename — `@blamejs/blamejs-shop` (scoped under the org alongside `@blamejs/core` + `@blamejs/exceptd-skills`).** The npm package is now published under the `blamejs` organization scope as `@blamejs/blamejs-shop`. Installation switches from `npm install blamejs-shop` to `npm install @blamejs/blamejs-shop`; the import surface is unchanged — `require("@blamejs/blamejs-shop")` returns the same shop primitive set the unscoped name did. The legacy unscoped package will be deprecated on the registry with a pointer to the new name so existing operators see the upgrade path on their next install. **Changed:** *`package.json#name` → `@blamejs/blamejs-shop`* — Matches the existing org-scoped packages (`@blamejs/core`, `@blamejs/exceptd-skills`). The publish workflow already passes `--access public` to `npm publish`, which is the access mode scoped packages need to land as publicly-installable. · *Install command* — `npm install @blamejs/blamejs-shop` replaces `npm install blamejs-shop`. The `require` path follows: `var bShop = require("@blamejs/blamejs-shop");`. The entry point + export shape are byte-for-byte identical to v0.0.43 — only the resolution path changes. **Migration:** *Operator upgrade path* — Operators on the unscoped `blamejs-shop` change one line in their `package.json` dependencies: `"blamejs-shop": "^0.0.43"` → `"@blamejs/blamejs-shop": "^0.0.44"`. Every `require("blamejs-shop")` call site needs the matching update (`require("@blamejs/blamejs-shop")`). The unscoped name will be deprecated on the registry with a pointer to the new scoped path so a fresh `npm install` on the old name surfaces the migration message in npm's stderr.
|
|
12
|
+
|
|
13
|
+
- v0.0.43 (2026-05-22) — **Search results — image-bearing product cards (consistent with the home grid).** The search results page rendered text-only `PRODUCT_CARD` tiles — title + price + 'View product →' link — while the home catalog grid (v0.0.42) shifted to clickable image-bearing `product-card` tiles. This release unifies the two surfaces: search results now go through the same `_buildProductCard(p)` picker so a hit lands a real hero-image tile when the product carries media, and the text-only fallback when it doesn't. The same `asset_prefix` override the home renderer accepts also works on the search renderer. **Changed:** *`storefront.renderSearch({ products, asset_prefix? })` uses `_buildProductCard`* — Same render-time picker the home grid uses — when a result product carries `hero_media`, the card renders as the image-bearing tile; without media, the text-only fallback. `asset_prefix` defaults to `/assets/` and can be overridden for operators on a different R2 binding or CDN remap. · *Search route fetches `catalog.media.listForProduct` per hit* — `GET /search` now calls the media lookup alongside the existing variants + prices loop. The first attached media row becomes `product.hero_media` on the data shape `renderSearch` consumes — same shape the home route v0.0.42 emits.
|
|
14
|
+
|
|
15
|
+
- v0.0.42 (2026-05-22) — **Home catalog grid — product cards now render the hero image alongside title + price.** The home page catalog grid used text-only cards (`<h2>` + price + 'View product →' link). When a product carries at least one `catalog.media` row, the card now renders as a clickable image-bearing tile — square hero image at the top, then a single-row meta strip with title + accent-colored price. Products without media keep the existing text-only card so a freshly-listed product with no images yet renders cleanly. **Added:** *`PRODUCT_CARD_IMAGE` template + `_buildProductCard(p)` picker* — When a product carries an `image_url`, the renderer emits an `<a class="product-card">` wrapper with a square `<figure class="product-card__media">` hero (`object-fit: cover`) above a meta strip holding the title and price. Hover lifts the card and darkens the border. When no media exists the existing `PRODUCT_CARD` text-only tile is the fallback. The picker keeps the template engine's HTML-escape behavior — `image_url` + `alt_text` flow through `_render`, never bypassing the escape. · *Home route fetches media per product* — `GET /` now calls `deps.catalog.media.listForProduct(product.id)` alongside the existing `variants.listForProduct` + `prices.current` lookups. The first media row becomes `product.hero_media` on the data shape `renderHome` consumes; products with no attached media stay at `hero_media = null` and the renderer drops back to the text-only card. **Changed:** *`storefront.renderHome({ products, asset_prefix? })` — `asset_prefix` defaults to `/assets/`* — Image URLs are built as `assetPrefix + p.hero_media.r2_key` so operators on a custom asset prefix (different R2 binding, CDN remap) can override without forking the renderer. Backward-compatible — when `asset_prefix` is omitted the default lands at the Worker's `/assets/*` static-asset bridge.
|
|
16
|
+
|
|
17
|
+
- v0.0.41 (2026-05-22) — **Newsletter signup primitive — POST `/newsletter` enrolls a visitor, designed thank-you page on either branch.** The storefront footer + newsletter band already rendered an email form that posted to `/newsletter`, but no handler was mounted — submitting the form 404'd. This release ships a `newsletter` primitive (`lib/newsletter.js`) that composes `b.guardEmail` for RFC-shape validation, `b.crypto.namespaceHash` for dedup, and stores rows in `newsletter_signups` (new migration `0010_newsletter_signups.sql`). The storefront's POST `/newsletter` route hands the form payload to the primitive and renders a designed thank-you card on success — with separate copy for the `new` (just enrolled) and `dedup` (already on the list) branches — and a designed error card on validation refusal. **Added:** *`newsletter` primitive (`lib/newsletter.js`)* — `bShop.newsletter.create({ query? })` returns `{ signup, byEmailHash, count, EMAIL_NAMESPACE }`. `signup({ email, source })` normalises the email (trim + lowercase), validates via `b.guardEmail(addr, { profile: 'strict' })`, hashes through `b.crypto.namespaceHash('newsletter-email', normalised)` for the dedup key, and runs an `INSERT OR IGNORE` so a repeat signup is an idempotent no-op. Returns `{ id, status: 'new' | 'dedup', email_normalized }`. `byEmailHash(hash)` is the operator lookup for an unsubscribe flow. `count()` returns the active signups for an optional live newsletter-band stat. · *Migration `0010_newsletter_signups.sql`* — New table — `id` UUID PRIMARY KEY, `email_hash` UNIQUE (the namespaceHash dedup key), `email_normalized` (the canonical address an operator needs to actually send a message; D1's encrypted-at-rest default + the operator's access controls cover the PII posture), `source` TEXT (defaults to `storefront-footer`, validated against `/[a-z0-9][a-z0-9._-]*[a-z0-9]/`), `created_at` epoch ms, `unsubscribed_at` NULL until the user opts out (the opt-out flow ships in a follow-up; the column lands now so existing rows don't need a schema rewrite). Two indexes — `created_at` for time-range broadcasts, `source` for channel-attribution filters. · *Storefront route — POST `/newsletter`* — Mounts only when `deps.newsletter` is wired (operators that don't construct the primitive get a clean 404 instead of a misleading 200). Catches `TypeError` (input refusals — bad email format, oversized source string, control bytes) and renders the designed error card with HTTP 400; everything else (D1 unreachable, vault hiccup) renders the same card with HTTP 500. Success renders the thank-you card with HTTP 200 and adapts the copy to the `new` vs `dedup` branch. · *Designed thank-you + error cards* — `renderNewsletterThanks(opts)` and `renderNewsletterError(opts)` both wrap the layout shell with an `eyebrow` + centred title + lede + dual-CTA card (`Back to the shop →` primary, `Star on GitHub` ghost). The `dedup` branch reads 'You're already on the list.' so a double-submit isn't a silent failure. **Changed:** *`server.js` wires `bShop.newsletter.create({})` into `sfDeps`* — Constructed alongside `customers` inside the `if (catalog && cart)` block; the primitive only needs `b.externalDb.query` which the deploy already provisions via the Worker's `D1_BRIDGE_URL`. · *`lib/index.js` exports `newsletter`* — Same shape as the rest of the shop primitives — `var n = bShop.newsletter.create({});`. **Detectors:** *Layer 1 coverage continues to gate input refusal at every entry point* — The newsletter primitive defers shape checks to `b.guardEmail` (already covered by the framework's own test suite) and `b.crypto.namespaceHash` (ditto). The shop layer's contribution is `_normalizeSource` (regex + length cap) and the idempotent dedup flow; the layer-1 smoke surface continues to refuse missing-input + wrong-type + over-length cases on every public entry point in the shop primitives.
|
|
18
|
+
|
|
19
|
+
- v0.0.40 (2026-05-22) — **Product detail page — gallery wired to real `media` rows with a branded SVG placeholder fallback.** The PDP gallery used to render a giant initial-letter mark as a placeholder regardless of what the product looked like. The storefront now reads `catalog.media.listForProduct(product.id)` on every PDP request — when at least one media row exists, the first row drives the hero `<figure>` (with `alt_text` for a11y) and up to three more rows feed the thumbnail strip. The letter-mark falls through as a clean default when no media has been attached yet. A demo-seed pair (`scripts/seed-sample-product-media.sql` + four brand-colored SVG images under `scripts/sample-product-images/`) ships alongside the existing sample-products seed. **Added:** *`storefront._buildPdpGallery(product, media, assetPrefix)`* — Composes the PDP hero figure + thumbnail strip from `catalog.media` rows. When `media` is non-empty, the first row becomes `<figure class="pdp__media pdp__media--image"><img src="<asset_prefix><r2_key>" alt="<alt_text>"></figure>` (with `loading="eager"` since it's above-the-fold), the next three drive thumbs, and missing thumb slots render as dashed-border placeholders so a single-image product still occupies the four-slot grid. When `media` is empty the gallery falls back to the letter-mark placeholder so a freshly-seeded product never renders an empty square. All template substitutions go through `_render`'s HTML-escape; URLs and alt text are attribute-escaped via a local `_escAttr` helper so an operator-supplied `r2_key` containing `"` or `<` lands as escaped text inside the attribute. · *`scripts/seed-sample-product-media.sql`* — Idempotent media seed: one `media` row per seeded product pointing at `products/<slug>.svg` with `content_type = image/svg+xml`, 800×800, `position = 0`, and human-readable `alt_text`. Run alongside the existing `scripts/seed-sample-products.sql` via `wrangler d1 execute blamejs-shop --remote --file=scripts/seed-sample-product-media.sql`. Drop the rows with `DELETE FROM media WHERE id LIKE '00000000-0000-7000-8000-0000000000%';` when replacing with operator-supplied media. · *`scripts/sample-product-images/` — reference SVGs* — Four 800×800 SVG product placeholders matching the seeded catalog: `operator-tee.svg` (charcoal + accent shield silhouette + tee mark), `edge-reader.svg` (navy + hardware silhouette with status LEDs + monospace label), `operator-license.svg` (purple + ML-DSA-signed card mockup), `starter-bundle.svg` (orange gradient + stacked-box composition representing the three component SKUs). Each uses only the design-system palette + system font stack — no external font fetches, no raster assets. Operators copy these into their own R2 prefix as a starting point or replace them entirely; the demo seed expects them at R2 key `products/<slug>.svg`. **Changed:** *`storefront.renderProduct({ product, variants, prices, media, ... })`* — Accepts an optional `media` array of media rows. When supplied, the gallery renders the real image; when omitted (the current contract for callers that don't read media — including the layer-1 test fixtures), the gallery renders the letter-mark placeholder. Backward-compatible — existing callers that don't pass `media` continue to render the placeholder, exactly the v0.0.39 behavior. The PDP storefront route (`GET /products/:slug`) now calls `deps.catalog.media.listForProduct(product.id)` and threads the result through. · *Theme CSS — `.pdp__media--image` variant* — When the gallery hero is a real image, the `--image` modifier swaps the gradient placeholder backdrop for `var(--paper)`, removes the orange radial-glow `::after` decoration, and lets the `<img>` fill the square via `object-fit: cover`. Thumbnail `<img>` elements get the same `object-fit: cover` treatment so the strip stays uniform across portrait and landscape source images.
|
|
20
|
+
|
|
21
|
+
- v0.0.39 (2026-05-22) — **Publish workflow — retry the post-publish `npm view` so CDN propagation delay doesn't surface as a red X.** The post-publish `Verify the version landed on the registry` step ran `npm view <pkg> version` immediately after `npm publish`. The npm registry CDN takes several seconds to publish a fresh manifest, so the immediate read returned a 404 even on a successful publish — leaving the otherwise-green release run with one red X. Replaced with a six-attempt retry loop (6 second backoff, ~36s total budget) that exits cleanly the moment the registry serves the target version. **Fixed:** *Post-publish registry-verify retry loop* — The single-shot `npm view` after `npm publish` raced the npm registry's CDN — the publish call returned 200, the package landed, but the manifest GET endpoint still returned 404 for several seconds. The verify step now polls `npm view <pkg> version` up to six times with a six-second backoff (~36 seconds total budget). It exits success the moment the registry returns the just-published version, and only flags a real mismatch (`exit 1`) when the propagation never lands inside the budget.
|
|
22
|
+
|
|
23
|
+
- v0.0.38 (2026-05-22) — **Publish workflow — install devDeps before `npm sbom` so the runtime-dep tree resolves.** `npm sbom` walks the installed dep tree; without `node_modules` it errors `ESBOMPROBLEMS missing: <devDep>` even when `--omit=dev` would have excluded the devDep from the output. The validate job now runs `npm install --no-audit --no-fund --ignore-scripts` before the SBOM step so the tree resolves; the `--omit=dev` filter on `npm sbom` continues to keep the SBOM clean. **Fixed:** *`npm install` before `npm sbom` in the publish workflow* — The SBOM step was running against a missing dep tree. Added `npm install --no-audit --no-fund --ignore-scripts` so the local install resolves before `npm sbom --omit=dev` walks it. The zero-runtime-deps invariant check downstream is unchanged — it counts components in the emitted SBOM, which `--omit=dev` keeps at zero.
|
|
24
|
+
|
|
25
|
+
- v0.0.37 (2026-05-22) — **ESLint configuration — flat-config + bug-class rules so the publish workflow's lint gate runs.** ESLint 9+ requires a flat-config file at the repo root. The publish workflow's `npx eslint@latest --max-warnings 0 .` step couldn't find one and exited with `ESLint couldn't find an eslint.config.(js|mjs|cjs) file`. Added `eslint.config.mjs` configured for the project's posture (Node 24 LTS, CommonJS, ES2024) and pruned four pre-existing warnings the new config surfaced — three unused-variable hygiene fixes, one `var config` redeclaration in `server.js`, and one `_cartCountForReq` hoisting inside `lib/storefront.js` so the `/admin` landing + catch-all `onNotFound` handler can reach it regardless of `deps.customers` wiring. **Added:** *`eslint.config.mjs` — flat-config* — Bug-class rule set mirroring the vendored framework's posture: `no-undef`, `no-redeclare`, `no-const-assign`, `eqeqeq` (with the `== null` idiom carve-out), `no-this-before-super`, `no-throw-literal`, `no-unused-vars` (underscore-prefix exception). Stylistic rules (`no-useless-escape`, `no-promise-executor-return`, `no-prototype-builtins`, `no-control-regex`) are intentionally `off` — they're idiomatic patterns the codebase relies on, not bug signals. Three config blocks: CJS `.js` (default), ESM `.mjs`, and Cloudflare Workers `worker/**/*.js` with the Workers runtime global set. Ignores cover the usual `node_modules`, `lib/vendor`, `.test-output`, `.scratch`, `.template`, `.wrangler`, `.playwright-mcp`, and `.claude` worktree paths. **Fixed:** *`_cartCountForReq` hoisted to mount-scope* — The helper that reads `shop_sid` and returns the cart-line count for the header pill was nested inside the `if (deps.customers)` block at the bottom of `storefront.mount`. The `/admin` landing handler and the `onNotFound` catch-all 404 (both added in v0.0.35, mounted outside that block) reached for `_cartCountForReq` and got a `ReferenceError` at runtime when `deps.customers` was absent — in production both deps are wired together so the path never fired, but the path was real. The helper now lives at the top of `mount()` so every handler can reach it. · *`server.js` — duplicate `var config` removed* — `var config = catalog && cart ? bShop.config.create({}) : null;` at the top of the routes function already binds `config` for the whole scope. A second `var config = bShop.config.create({});` inside the admin-mount block was a JavaScript no-op (var declarations don't shadow inside nested blocks) but a real lint signal. Removed; the admin block reuses the outer handle. · *Test-scope unused locals + admin checkout placeholder* — Three values — `var now`, `var bad`, and `var checkout` — were assigned but never read in `test/layer-1-state/analytics.test.js`, `test/layer-1-state/catalog-import.test.js`, and `lib/admin.js` respectively. Renamed with the underscore prefix the project uses for intentional unused locals (`_now`, `_bad`, `_checkout`) so the `no-unused-vars` rule's allowlist matches them.
|
|
26
|
+
|
|
27
|
+
- v0.0.36 (2026-05-22) — **Publish workflow YAML — refactor the SLSA download-artifact step out of flow mapping so the parser accepts it.** The release `npm-publish.yml` workflow couldn't start. `download-artifact` for the SLSA provenance file used YAML flow-mapping form (`with: { name: blamejs-shop-${{ … }}.intoto.jsonl }`) and the parser read the `}}` inside the GitHub expression as the flow-collection close. Rewritten as block form, the workflow parses and the publish pipeline runs. **Fixed:** *`npm-publish.yml` — `download-artifact` step parses correctly* — The SLSA provenance download step at the publish job mixed YAML flow-mapping `{ … }` with a GitHub `${{ … }}` expression. The parser hit the `}}` inside the expression as a flow-mapping close, rejecting the whole document at parse time (no jobs ever materialised — the run surfaced as `startup_failure`). Rewriting the step as block form (`with:` / ` name: …` on its own line) fixes the parse error. No semantic change to the workflow.
|
|
28
|
+
|
|
29
|
+
- v0.0.35 (2026-05-22) — **Storefront redesign — multi-section landing, designed cart / PDP / checkout, theme CSS extracted to an external stylesheet.** Every storefront page now ships through the same design system — utility bar, sticky header with search + cart pill, dark hero with code-preview card, primitives marquee, collections grid, framework feature band, designed catalog empty state, newsletter band, and a four-column footer. Cart, product, checkout, pay, order, account login / register / dashboard, search, /admin, and 404 each got their own designed treatment. The theme's design tokens moved out of inline `<style>` blocks (which `style-src 'self'` blocks) into `themes/default/assets/css/main.css`, served same-origin from R2 with a build-time version cache-buster. Operators override the look by uploading a replacement CSS at the same R2 key or by passing `theme_css` to the storefront renderers. **Added:** *`/admin` landing page* — Operators (and the footer link) now land on a designed HTML page at `/admin` that explains the API-only posture and shows four curl examples (create a product, search products, restock inventory, issue a refund) as syntax-highlighted code cards, plus a sidebar note linking to `lib/admin.js` on GitHub. Every other `/admin/*` route remains a bearer-token-gated JSON endpoint. The HTML route only mounts inside the storefront's standard mount; no admin API behavior changed. · *Designed 404 page via `router.onNotFound`* — Every unmatched route — `GET`, `POST`, anything — now renders a designed not-found page (gradient `404` numeral + 'That page slipped the catalog.' copy + Back-to-shop + View-your-cart CTAs) inside the standard layout, instead of the framework's default `<h1>404 Not Found</h1>` text body. Wired through `router.onNotFound`, so it covers paths and verbs uniformly. · *Live hero stat — `Products live` count* — The first stat in the hero now reflects the actual catalog size (the count of `status='active'` products returned to the home renderer). Empty catalogs show an em-dash. The remaining three stats stay hardcoded brand-facing values (`npm runtime deps: 0`, `Default crypto: PQC`, `License: Apache 2.0`). · *Customer accounts wired into storefront mount* — `server.js` constructs `bShop.customers.create({})` and threads it into `sfDeps.customers`, opting the `/account/login`, `/account/register`, `/account` dashboard, and the passkey ceremony JSON endpoints into the deploy. The customers primitive itself shipped in `v0.0.28` but its routes were never mounted in the storefront. · *`scripts/seed-sample-products.sql` — demo catalog seed* — One-shot SQL seed for the demo storefront: four products (Operator Tee, Edge Reader v1, Operator License, Starter Bundle), four variants, four current-price rows, and an inventory row each. Run with `wrangler d1 execute blamejs-shop --remote --file=scripts/seed-sample-products.sql`. Uses `INSERT OR IGNORE` so re-running is idempotent. Operators replace this with their own catalog through the admin API once they have one. **Changed:** *Storefront layout — utility bar + designed header + multi-column footer* — `LAYOUT` in `lib/storefront.js` now wraps every page in a thin top utility bar (live status pill, primitive strapline, GitHub call-to-action), a sticky header with the wordmark logo + pill search input + Shop / Framework nav + circular account icon + cart pill with count badge, and a four-column footer (brand + GitHub / npm / RSS social, Shop, Framework, Operators) plus a bottom strip with copyright + Security / Privacy / Terms links. The same shell wraps every page renderer. · *Home page composition* — Six sections, all server-rendered. Dark hero with eyebrow + version pill, headline with accent on `nothing`, lede, primary + ghost CTAs, a four-stat row, and a tilted glass code-preview card showing a `bShop.checkout.finalize(…)` snippet with syntax highlighting. A CSS-only infinite-scroll marquee lists twelve framework primitives (ML-KEM-1024, ML-DSA-65, XChaCha20-Poly1305, SHAKE256, Argon2id, SLSA L3 provenance, Sigstore-keyless SBOM, Trusted Types, Stripe-first payments, WebAuthn passkeys, server-rendered HTML, zero npm runtime deps). A six-tile collections grid (Apparel, Hardware, Digital, Subscriptions, Bundles, Gift cards) with per-tile gradient art and hover-arrow circles. A dark framework feature band with split copy + four numbered feature cards. A catalog section that renders product cards when seeded and a designed empty state otherwise — dashed-placeholder tile grid + 'Add the first product' copy + a literal `curl POST /admin/products` snippet. · *Product detail page* — Two-column layout with breadcrumb (Shop / Product), a square gallery placeholder showing the product initial as a large semi-transparent mark with an orange radial glow + four thumbnail squares, and an info column with eyebrow + title + description + three status badges (In stock, Ships from origin, Stripe-secured checkout) + a variant table with title / SKU code chip / accent-colored price / qty input + Add to cart button. The mobile breakpoint stacks the gallery above the info column and hides the SKU + Action header columns on narrow viewports. · *Cart / checkout / pay / order page redesigns* — Cart page is a two-column grid: line table on the left (SKU code chip, qty input with Update button, unit + line price, Remove button), sticky Order Summary card on the right (totals list with grand-total row, full-width Continue to checkout CTA, tax + shipping note). Checkout form is a vertical form-stack with grouped uppercase labels, inline country / state / postal row, and a designed Order Summary panel. Pay page hosts the Stripe Payment Element inside a designed card with a full-width Pay button + payment message line. Order confirmation shows a status badge (`In stock`-style chip) + a two-column items / totals layout. Every form input + button + table now uses the shared design tokens. · *Account login / register / dashboard* — Login + register are centered single-column auth cards with the design tokens — eyebrow + title + lede + form-stack + full-width submit + auth-message line + alt link (`New here?` / `Already have one?`). The passkey ceremony JS is unchanged. Dashboard shows a head row (eyebrow + name + lede on the left, Sign-out button on the right) followed by a recent-orders table in a designed body card. · *Search page* — Search now opens with a left-aligned section head (eyebrow + dynamic title + summary + `All products →` shortcut) followed by either the product grid or a dashed-border empty card with a magnifier icon + `We don't carry that yet` + `Browse the full catalog` CTA. The empty state copy adapts to a blank query (`Use the search box in the header to look for a product…`) vs a no-match query (`Nothing in the catalog matched …`). · *Default theme stylesheet — extracted to `themes/default/assets/css/main.css`* — The 346-line inline `<style>` block in the layout is gone. Every design token (palette, type scale, spacing, radius, shadow, motion, container width), reset, atom (eyebrow, link-arrow, btn-primary, btn-ghost, btn-secondary, dot), and component (header, utility bar, cart pill, hero, marquee, collections, framework band, value cards, PDP, cart, checkout, pay, order, auth, account dash, search, 404, admin landing, newsletter, footer) ships from `themes/default/assets/css/main.css` (~12 KB). The layout references it as `<link rel="stylesheet" href="/assets/themes/default/css/main.css?v=<package-version>">`. The Worker's static-asset bridge passes the request straight to R2 with `Cache-Control: public, max-age=300`. Operators override by uploading their own stylesheet to the same R2 key, or by passing `opts.theme_css` to any storefront renderer. · *Worker cold-start envelope + warming-up fallback page* — `worker/index.js` bumps `sleepAfter` from `30s` to `15m` so normal browsing keeps the container warm. The cold-start retry budget grows to roughly 60 seconds (`[0, 2000, 4000, 8000, 16000, 30000]` ms backoff slots) to cover Cloudflare's container provisioning + the framework's boot-time SLH-DSA-SHAKE-256f audit-signing keypair generation. If every retry still hits a closed port, the visitor lands on a designed `Warming up — blamejs.shop` page that auto-refreshes every eight seconds, instead of the SDK's raw `Failed to start container` text. · *Container instance type → `standard-2`* — `wrangler.toml` sets `instance_type = "standard-2"`. The `standard-1` profile (0.5 vCPU) couldn't reliably finish the boot-time SLH-DSA-SHAKE-256f keypair generation inside the worker's retry budget on cold starts; `standard-2` reduces the cold-start window comfortably under the new 60-second budget. **Removed:** *Inline `<style>` block + Google Fonts dependency* — The framework's default `Content-Security-Policy: style-src 'self'` blocks both inline `<style>` blocks and external-host stylesheets. The 346-line layout style block + the `fonts.googleapis.com` + `fonts.gstatic.com` `<link>` tags are gone; the layout now uses a system font stack (`ui-sans-serif, system-ui, -apple-system, …`) so no third-party host needs to be allow-listed in CSP. The theme stylesheet is the single source of truth for typography. · *`style=""` attributes on every storefront renderer* — Twenty-six inline `style=""` attributes across the cart, checkout, pay, order, and account renderers were the other half of the inline-style CSP problem. They're replaced by semantic class hooks (`cart-line__update`, `cart-line__btn`, `form-stack`, `form-row`, `form-row--inline`, `form-field__input--xs`, `pay-card`, `pay-card__element`, `pay-card__submit`, `pay-card__message`, `checkout-summary`, etc.) defined in the theme stylesheet. **Fixed:** *License copy — three places said `MIT` when the framework ships under Apache 2.0* — The utility bar pill, the hero stats row, and the footer copyright line each labelled the project `MIT`. The actual `LICENSE` is Apache 2.0 and `package.json#license` has always been `Apache-2.0`. All three render the correct text now. · *Collection-tile gradients* — The six home-page collection tiles ship per-tile gradient art (orange, charcoal, purple, green, coral, navy) plus a corner-highlight overlay. A later `.collection-card__art` rule was clobbering the per-tile `--N` modifiers via `background-image` shorthand specificity, leaving every tile gray. Tiles now store the gradient as a `--card-gradient` custom property per modifier so both the highlight overlay and the base gradient compose correctly. · *Hover specificity on the on-dark secondary CTA* — The hero's `VIEW ON GITHUB` ghost button rendered with the default dark text (`a.btn-secondary` selector outranked `.btn-secondary--on-dark`) so the text was invisible on the dark hero. The on-dark modifier now uses `a.btn-secondary.btn-secondary--on-dark` to bump specificity, restoring the white text + translucent border. **Migration:** *Theme override path* — Operators replace the default look in one of three ways: (1) upload a replacement `main.css` to R2 at `themes/default/css/main.css` — same key, same `<link>` URL, no code change required; (2) pass `opts.theme_css` to any storefront renderer (`renderHome`, `renderProduct`, `renderCart`, …) to point a request at a different stylesheet URL; (3) register a named theme via the `theme` primitive and let the storefront's `assetUrl("css/main.css")` resolve to `/assets/themes/<name>/css/main.css`. The page-level `?v=<package-version>` cache-buster appends automatically when no explicit `theme_css` is supplied. · *Demo seed* — `wrangler d1 execute blamejs-shop --remote --file=scripts/seed-sample-products.sql` lands four demo products with one active USD price each + initial inventory. Idempotent. Drop the rows with `DELETE FROM products WHERE id LIKE '00000000-0000-7000-8000-%';` when replacing with a real catalog. · *Vendor refresh — blamejs `v0.11.44`* — `scripts/vendor-update.sh blamejs latest` refreshed the vendored framework to `v0.11.44`. Carries the framework's own storefront-test, security-header, csp middleware, and router refinements through to this deploy.
|
|
30
|
+
|
|
31
|
+
- v0.0.33 (2026-05-21) — **Subscriptions primitive — Stripe-backed recurring billing.** New `subscriptions` primitive composes the Stripe Subscriptions API for recurring billing. Operators model recurring offers as `subscription_plans` (mirroring a pre-created Stripe Price), bind customers to plans via `subscriptions.create`, and let the webhook handler replay `customer.subscription.*` events into the local row. The one-time-order PaymentIntent path is unchanged. **Added:** *Migration `0009_subscriptions.sql`* — Two new tables. `subscription_plans` mirrors a Stripe recurring Price: `stripe_price_id`, `interval` (`day|week|month|year`), `interval_count` (1..12), `currency`, `amount_minor`, `trial_days` (0..730), optional `variant_id` FK (NULL allowed — standalone plans without a catalog variant are valid). `subscriptions` mirrors Stripe's subscription object byte-for-byte: `stripe_subscription_id UNIQUE`, `status` matching Stripe's enum (`trialing|active|past_due|canceled|incomplete|incomplete_expired|unpaid`), `current_period_start/_end`, `cancel_at_period_end`. Indexed by variant, active, customer, status, and stripe id. · *`subscriptions` primitive* — `lib/subscriptions.js` ships `create({ query, payment })` returning `{ plans, subscriptions }`. `plans.{create, get, list, update, archive}` covers CRUD over the catalog-side recurring offer. `subscriptions.create({ customer_id, plan_id, payment_method_id })` POSTs to Stripe via the payment dep, then persists the returned object locally so the shop has an authoritative view without round-tripping to Stripe on every read. `subscriptions.cancel(id, { at_period_end })` routes at-period-end through Stripe's UPDATE (`cancel_at_period_end: true`) while immediate cancel uses DELETE. `subscriptions.byStripeId(stripeId)` is the webhook lookup. `subscriptions.handleStripeEvent(event)` dispatches `customer.subscription.created/updated/deleted` into the local row. · *`payment.subscriptions` extension* — `lib/payment.js` gains a `subscriptions` namespace alongside `createPaymentIntent` / `refund`: `create(input, idempotencyKey)` → `POST /v1/subscriptions`, `retrieve(id)` → `GET`, `update(id, input, idempotencyKey)` → `POST /v1/subscriptions/:id`, `cancel(id, { at_period_end }, idempotencyKey)` → `DELETE` or `POST` with `cancel_at_period_end`. Input validation refuses missing customer / empty items / negative trial period at the entry point so the Stripe round-trip never starts with bad arguments. Existing one-time-PaymentIntent API is unchanged. · *Checkout webhook routing* — `checkout.handleStripeEvent` recognises `customer.subscription.created/updated/deleted` and routes them to `deps.subscriptions.handleStripeEvent` (when wired). The one-time-order `payment_intent.*` + `charge.refunded` event map is unchanged — both paths coexist on the same webhook endpoint, gated by `event.type`. With no `subscriptions` dep wired, subscription events return `{ handled: false, reason: "no-subscriptions-handler" }`. · *Admin routes* — `POST /admin/subscription-plans` creates a plan. `GET /admin/subscription-plans?variant_id=&active=` lists with optional filters. `GET /admin/subscription-plans/:id`, `PATCH /admin/subscription-plans/:id`, `POST /admin/subscription-plans/:id/archive`. `GET /admin/subscriptions?customer_id=&status=` lists subscriptions filtered by customer or Stripe status. `GET /admin/subscriptions/:id`. `POST /admin/subscriptions/:id/cancel` accepts `{ at_period_end }`. Every mutating route writes the standard audit row alongside the existing admin write events. **Detectors:** *Layer 1 — `subscriptions`* — `test/layer-1-state/subscriptions.test.js` exercises plans CRUD (create with + without variant, get, list with variant/active filters, update, archive), subscriptions.create with a stubbed Stripe surface (asserts idempotency key + price + customer flow through), refusal when the plan is archived, cancel at-period-end vs immediate, byStripeId lookup, handleStripeEvent upsert (updated + created replay), handleStripeEvent delete, unknown event types, and checkout routing for `customer.subscription.*` events (with + without subscriptions dep wired). Validation covers every entry point — bad interval, interval_count out of [1,12], trial_days out of [0,730], non-lowercase currency, non-positive amount_minor, malformed variant_id, missing customer_id / plan_id / payment_method_id at subscriptions.create, malformed status filter on list, missing event on handleStripeEvent.
|
|
32
|
+
|
|
33
|
+
- v0.0.32 (2026-05-21) — **Theme primitive — file-backed templates with fallback resolution.** Operators ship a custom storefront look without forking `lib/storefront.js`. A theme is a directory under `themes/<name>/` holding `layout.html` plus per-page views (`home.html`, `product.html`, `cart.html`, `checkout.html`, `pay.html`, `order.html`, `notfound.html`). When set, the storefront dispatches every render through `b.template`; any view missing from the active theme falls back to the bundled `themes/default/` baseline. The inline-string templates stay in force when no theme is configured. **Added:** *`theme` primitive* — `lib/theme.js` ships `create({ themesDir, name, fallback? })` returning `{ render, exists, assetUrl, name, fallback }`. Each theme owns a `b.template` engine bound to its own directory; render walks the active engine first, falls back to the default engine when the file is missing, and throws `ThemeError` when both miss. Slug-shaped (`^[a-z0-9][a-z0-9-]{0,63}$`) view names and theme names defend against path-traversal via request-derived input. · *Bundled `themes/default/`* — Reference theme matching the prior inline look: `layout.html` (header + nav + `{% block body %}` insertion point), per-page views for home / product / cart / checkout / pay / order / notfound, and `assets/css/main.css` (lifted out of the inline `<style>` block). Operators copy the directory and edit in place to fork the visual identity. · *Storefront integration* — `storefront.mount(router, deps)` accepts `deps.theme`; when set, every route handler renders via the theme's file-backed views. The `renderHome` / `renderProduct` / `renderCart` / `renderCheckoutForm` / `renderPayPage` / `renderOrder` / `renderNotFound` functions all accept an optional `opts.theme` so callers outside the mount path get the same dispatch shape. Absence of `opts.theme` preserves the inline-string templates byte-for-byte — no breaking change for current deploys. · *`SHOP_THEME` env wiring* — `server.js` builds a theme via `bShop.theme.create({ themesDir: process.env.SHOP_THEMES_DIR || "./themes", name: process.env.SHOP_THEME })` whenever `SHOP_THEME` is set. `SHOP_THEME_FALLBACK` overrides the chained fallback name (default `default`). Theme assets ship via R2 at `/assets/themes/<name>/...`; upload once via `wrangler r2 object put` so the Worker's static pass-through serves them with the existing cache headers. **Detectors:** *Layer 1 — `theme`* — `test/layer-1-state/theme.test.js` builds a temp themes directory, exercises active-then-fallback resolution, verifies `assetUrl` shape + traversal refusal, asserts `exists` reports active-OR-fallback hits, and covers the validation matrix (missing themesDir, bad slug, missing active-theme dir, bad viewName at render time).
|
|
34
|
+
|
|
35
|
+
- v0.0.31 (2026-05-21) — **Inventory low-stock alerts.** Per-SKU low-stock thresholds with optional alert fan-out. When a SKU's available stock (`stock_on_hand - stock_held`) drops below its configured threshold, the framework writes an `inventory_alerts` row, emits a `b.log.warn` line, and (when an outbound-webhooks dep is wired) fans out an `inventory.low_stock` event. The hot-path decrement DO triggers the alert; admin routes set thresholds and list recent fires. **Added:** *`inventoryAlerts` primitive* — `lib/inventory-alerts.js` ships `create({ query, webhooks?, logger? })` returning `{ check, fire, checkAndFire, list }`. `check(sku)` is a pure SELECT that returns `{ alert, available, threshold }`. `fire(sku, available, threshold)` persists a row in `inventory_alerts`, calls `webhooks.send("inventory.low_stock", payload)` when the webhooks dep is wired, and always calls `logger.warn(...)`. `checkAndFire(sku)` is the common-case one-call wrapper. The logger defaults to `b.log` bound with `component: "inventory-alerts"` so emitted lines are filterable in the aggregator. Webhooks and logger sinks are drop-silent on throw — the persisted alert row is the source of truth, observability failures never roll it back. · *`catalog.inventory.setThreshold` + `checkLowStock`* — `catalog.inventory.setThreshold(sku, threshold)` writes the per-SKU threshold (non-negative integer or `null` to disable). `catalog.inventory.checkLowStock(sku)` returns the same `{ alert, available, threshold }` shape as the alerts primitive's `check`. The catalog factory accepts an `onStockChange(sku)` callback that fires after every `inventory.release` / `inventory.restock` so the alerts primitive can hook in without the catalog needing to know about it. · *Migration `0008_inventory_thresholds.sql`* — Adds `low_stock_threshold INTEGER` (nullable) to the existing `inventory` table via `ALTER TABLE`. Creates `inventory_alerts` (`id` TEXT PK uuid7, `sku` TEXT, `available_at_alert` INTEGER, `threshold` INTEGER, `fired_at` INTEGER) with composite indexes on `(sku, fired_at)` and `(fired_at)` for admin listing. The `sku` column is a loose FK — alert rows survive inventory deletion so the audit trail outlives the SKU. · *Worker InventoryLock decrement → alert callback* — After every decrement that succeeds, the DO reads `low_stock_threshold` alongside the stock columns. If post-decrement available is strictly below the threshold, the DO POSTs to a new `/_/low-stock-alert` Worker endpoint (gated by the same `D1_BRIDGE_SECRET` as the SQL bridge). The Worker forwards to the container, which runs the alerts primitive — writes the row, fans out webhooks, emits the log line. Fire-and-forget at every hop so alert delivery never gates the stock hold. · *Admin routes* — `PATCH /admin/inventory/:sku/threshold` (body `{ threshold }`) sets or clears the threshold; the mutation is audited under `shop_admin.inventory.set_threshold`. `GET /admin/inventory/alerts` returns the most recent alerts (defaults to the 100 newest by `fired_at` DESC); optional `?sku=` narrows to a single SKU's history, `?limit=` + `?offset=` page through older alerts. **Detectors:** *Layer 1 — `inventory-alerts`* — `test/layer-1-state/inventory-alerts.test.js` exercises setThreshold + checkLowStock round-trip (no-threshold default, above-threshold, below-threshold, cleared, unknown SKU), below-threshold fire writes the row + logger line + webhook send with the full payload, above-threshold returns null without touching any sink, threshold-null disables the alert path, the webhooks dep is genuinely optional (logger still fires), list pagination with limit + offset and SKU narrowing, validation refusals at every entry point (bad sku / threshold / available / limit / offset / mis-shaped deps), and the catalog `onStockChange` callback firing the alert path on `inventory.release` end-to-end.
|
|
36
|
+
|
|
37
|
+
- v0.0.30 (2026-05-21) — **Bulk catalog CSV import via admin.** Operators upload a CSV to bulk-create products + variants + prices + inventory in a single request. The admin API gains `POST /admin/catalog/import` (Content-Type: `text/csv`, optional `?dry_run=true`) — rows sharing a `product_slug` collapse to one parent product (first row wins for title / status / description), each row attaches a variant + price + inventory entry, and per-row errors are collected and returned alongside the success counts so the operator can re-upload with fixes. **Added:** *`catalogImport` primitive* — `lib/catalog-import.js` ships `create({ catalog })` returning `{ importCsv }`. Parses through `b.csv` (RFC 4180), content-safety-filters every cell through `b.guardCsv` strict profile (refuses formula-injection cells starting with `=` / `+` / `-` / `@`, bidi overrides, C0 control bytes, null bytes, dangerous-function denylist including `WEBSERVICE` / `HYPERLINK` / `IMPORTXML`), then validates the exact 10-column header before any row is processed. Numeric columns (`variant_weight_grams`, `price_amount_minor`, `inventory_qty`) accept only `/^\d+$/` — trailing garbage like `"100abc"` refuses outright rather than coercing through `parseInt`. Slug + SKU pass through the catalog primitive's existing validators. · *Admin route `POST /admin/catalog/import`* — Accepts `Content-Type: text/csv` body + `?dry_run=true|false` query param. Returns `{ created: { products, variants, prices, inventory_rows }, errors: [{ row_index, message }], rows, dry_run }`. The audit row is written to the `shop_admin.catalog.import` action with the per-run summary (row count, error count, created counts). Mounts only when `catalogImport` is wired into `admin.mount()` deps — operators opt in implicitly by passing the dep. · *`text/csv` body parser* — `server.js` extends the body parser's `text` sub-parser content-type list to include `text/csv` alongside `text/plain` and bumps the limit to 2 MiB so the importer's own 1 MiB cap binds first. Existing JSON / urlencoded / multipart routes are unaffected. **Security:** *Size caps default 1 MiB / 10000 rows* — Configurable per call via `opts.maxBytes` / `opts.maxRows`. Catches accidental wrong-file uploads (an OS image, a database dump) before any parse cycle is spent. Refuses with a `TypeError` rather than a row-error — the whole upload is rejected. · *Not atomic — partial failure leaves partial state* — D1 doesn't expose multi-row transactions cleanly across the HTTP bridge. Inserts run sequentially and rely on the catalog primitive's existing `slug` + `sku` UNIQUE constraints for idempotency. A row that errors midway leaves the rows before it persisted; the operator re-uploads the same CSV to fill in the gaps, and rows that already landed surface as duplicate-slug / duplicate-SKU row-errors on the retry. **Detectors:** *Layer 1 — `catalog-import`* — `test/layer-1-state/catalog-import.test.js` exercises the 3-product / 5-variant happy path against an in-memory SQLite loaded from `migrations-d1/0001_catalog.sql`, multi-variant-per-product de-dupe (first row's title / status / description win), `dry_run: true` returning the same counts without writing, header validation refusing wrong-column-order / short / empty CSV, per-row errors collected without aborting (bad slug / bad SKU / non-numeric cell), duplicate-slug-across-runs surfacing as a row-error without corrupting the first upload, `maxBytes` / `maxRows` refusing outright, and `b.guardCsv` refusing formula-injection cells (`=cmd|/c calc!A1`, `+SUM(...)`, `=WEBSERVICE(...)`).
|
|
38
|
+
|
|
39
|
+
- v0.0.28 (2026-05-21) — **Customer accounts primitive (passkey-only).** Shoppers register an account with an email + display name, enroll a WebAuthn passkey on their device, and sign in passwordlessly thereafter. The customer row stores the SHA3-512 namespaced hash of the address (never the address itself); the storefront route layer drives the registration + assertion ceremonies, persists per-credential rows with monotonic counter tracking, and seals the authenticated session in an AEAD-encrypted cookie keyed off the vault. **Added:** *Migration `0006_customers.sql`* — Two tables. `customers` carries `id` (TEXT PK uuid7), `email_hash` (TEXT, UNIQUE — `b.crypto.namespaceHash("customer-email", email)`, hex SHA3-512), `display_name` (TEXT, 128-char cap), `created_at`, `updated_at`. `customer_passkeys` carries `id` / `customer_id` (FK CASCADE) / `credential_id` (TEXT UNIQUE, base64url WebAuthn handle) / `public_key` (TEXT, COSE bytes base64) / `counter` (INTEGER, monotonic) / `transports` (comma list) / `created_at`. Indexed by `email_hash` for login lookups and `customer_id` for the per-account credential listing. · *`customers` primitive* — `lib/customers.js` ships `create({ query })` returning `{ register, get, byEmailHash, hashEmail, listPasskeys, addPasskey, getPasskeyByCredentialId, updatePasskeyCounter, removePasskey }`. Every email input runs through `b.guardEmail.validate` at the strict profile (refuses smuggling / header-injection / multi-@ / mixed-script) before the domain is case-folded and hashed; duplicate registrations refuse with `CUSTOMER_DUPLICATE`. `addPasskey` refuses a duplicate `credential_id` with `PASSKEY_DUPLICATE`; `updatePasskeyCounter` refuses a non-monotonic counter with `PASSKEY_COUNTER_REGRESSION` (the WebAuthn L3 clone-detection signal). Counter == 0 is the authenticator-doesn't-track marker and skips the write. · *Order pagination by customer* — `order.listForCustomer(customerId, { limit, cursor })` returns the customer's history ordered by `updated_at DESC, id DESC`. The cursor format matches `catalog.products.list` — HMAC-tagged via `b.pagination`, refuses orderKey-mismatched or tamper-bit-flipped values. Order rows arrive hydrated with `ship_to` + `lines` so the account dashboard avoids a per-row second trip. The HMAC secret is `opts.cursorSecret` (required in production, dev placeholder otherwise — same posture as `catalog`). · *Storefront account routes* — `GET /account/login` and `GET /account/register` render the email / display-name forms with an inline `<script>` that drives `navigator.credentials.get` / `.create` from the JSON challenge endpoints. `POST /account/passkey/register-begin` + `/register-finish` and `/login-begin` + `/login-finish` carry the WebAuthn options + verify the attestation / assertion via `b.auth.passkey.verifyRegistration` / `verifyAuthentication`. The login flow merges any anonymous cart into the now-customer-owned cart via `cart.setCustomer` before issuing the session. `GET /account` renders the customer name + the last 10 orders via `order.listForCustomer`. `POST /account/logout` clears the session cookie. · *Sealed authenticated-session cookie* — Cookie name `shop_auth`. The payload is an AEAD-encrypted envelope (`b.vault.seal` — XChaCha20-Poly1305 keyed off the deployment's vault KEK) holding `{ customer_id, exp }` with a 14-day TTL. Attributes are `HttpOnly; Secure; SameSite=Lax; Path=/`. The challenge round-trip uses a sibling `shop_auth_chal` cookie that's also vault-sealed, Path=/account scoped, and expires after 5 minutes. A rotated vault invalidates every outstanding authenticated session — operators get logout-everywhere without a separate revocation list. **Detectors:** *Layer 1 — `customers`* — `test/layer-1-state/customers.test.js` covers register + get round-trip, email-hash uniqueness, case-fold collision (same address with capital-letter domain refuses), strict-profile validation (multi-@ / header-injection refusal), passkey enroll + list + remove, duplicate-credential refusal across customers, and counter monotonic enforcement including the WebAuthn 0-counter no-op case. · *Layer 1 — `order.listForCustomer`* — `test/layer-1-state/order.test.js` gains a `_listForCustomer` cluster: rows arrive hydrated with `lines` + `ship_to`, ordering is `updated_at DESC` (a transitioned order surfaces above newer rows), pagination round-trips the HMAC-tagged cursor, a tampered cursor refuses, customer scoping excludes other customers' orders, and bad `limit` values refuse.
|
|
40
|
+
|
|
41
|
+
- v0.0.24 (2026-05-21) — **Design-system foundation for the storefront.** The default theme's layout shell is rebuilt around a published token system. Operators forking the storefront now compose against CSS custom properties for palette, typography, spacing, radius, shadow, and motion — page renderers no longer redeclare values inline. The header gains a search form and the layout ships a brand-tinted footer. **Changed:** *Storefront `LAYOUT` exposes a CSS token system* — `:root` now declares the palette (`--ink`, `--ink-2`, `--mute`, `--hair`, `--paper`, `--bg`, `--accent`, `--accent-d`, `--accent-l`, `--danger`), a typography scale (`--font-display`, `--font-body`, `--font-mono`, `--text-xs` through `--text-3xl`, `--lh-tight`/`--lh-snug`/`--lh-body`), a 4px-base spacing scale (`--space-0` through `--space-8`), radius tokens (`--radius-sm`/`--radius-md`/`--radius-lg`/`--radius-pill`), shadow tokens (`--shadow-sm`/`--shadow-md`/`--shadow-lg`), and motion tokens (`--ease-out`, `--duration-fast`, `--duration-mid`). Forks override at `:root` instead of patching individual rules. · *Header gains a search form* — The sticky header now renders a `GET /search` form alongside the brand and cart pill (`<input type="search" name="q">`). The form posts to a route the catalog primitive will own; until that route lands the search button returns a `Not found` page. Mobile breakpoint wraps the search input onto its own row. · *Site footer* — Layout ships a brand-tinted footer carrying the shop name, a one-line tagline ("server-rendered HTML, zero npm runtime dependencies, security defaults on"), a primitive list (Built on blamejs · Server-rendered · PQC-first), and a copyright with the current UTC year. The wrapper layout adds a flexbox column on `<body>` so the footer pins to the viewport bottom on short pages. · *Accessibility + motion defaults* — Layout reset adds a skip-link to `#main`, `:focus-visible` outlines (2px accent, 2px offset) on every interactive element, ARIA labels on the cart pill + primary nav, and wraps every transition behind `@media (prefers-reduced-motion: no-preference)`. Price + total cells render in `font-variant-numeric: tabular-nums` so column alignment holds across digit widths. · *Shared building-block classes* — The layout `<style>` block defines `.grid`, `.card`, `.btn`, `.btn-secondary`, `.summary-table`, `.empty`, `.price`, `.total`, `.cart-pill`, and `.hero` against the new tokens so per-page renderers (home / product / cart / checkout / pay / order) compose them instead of redeclaring colors + spacing. **Detectors:** *Layer 1 — `storefront._layoutTokens`* — `test/layer-1-state/storefront.test.js` gains an assertion cluster that pins every required CSS custom property (palette, typography scale, spacing scale, radius, shadow, motion), the reset + a11y hooks (`box-sizing`, `:focus-visible`, `prefers-reduced-motion`, `tabular-nums`, `id="main"`), the shared classes (`.grid`/`.card`/`.btn`/`.btn-secondary`/`.summary-table`/`.empty`/`.cart-pill`/`.hero`), the search form shape (`action="/search"`, `method="get"`, `name="q"`, `type="search"`), and the footer (primitive list + copyright).
|
|
42
|
+
|
|
43
|
+
- v0.0.23 (2026-05-21) — **Storefront purchase flow — full HTTP integration test.** The smoke gate now boots a real HTTP server, seeds a product, and walks the storefront purchase flow end-to-end (home → product detail → add-to-cart → cart view → line update → line remove). A failure anywhere in the storefront route mount, the body parser, the cart session cookie, or the cart/catalog SQL surfaces in CI instead of in a production rollout. **Added:** *Layer 2 integration suite* — `test/smoke.js` already walked `test/layer-2-integration/` when present; this release populates that directory with the first layer-2 test (`storefront-flow.test.js`). The smoke orchestrator picks it up automatically — no change to the smoke gate itself. · *`storefront-flow.test.js` — end-to-end HTTP purchase flow* — Boots `b.createApp` on an ephemeral 127.0.0.1 port with the storefront routes mounted exactly as `server.js` mounts them in pure-storefront mode. Catalog + cart wire against an in-memory `node:sqlite` database loaded from the live `0001_catalog.sql` + `0002_cart.sql` migrations so the test exercises the same SQL the live D1 sees. Vault, local DB at-rest, and audit-signing all opt into plaintext mode (the temp data dir is removed at teardown); the boot-time SNTP drift check is suppressed via `BLAMEJS_SKIP_NTP_CHECK=1` so the test never touches the network. The flow walks `GET /`, `GET /products/:slug`, `POST /cart/lines`, `GET /cart`, `POST /cart/lines/:id/update`, `GET /cart`, `POST /cart/lines/:id/remove`, `GET /cart` — asserting on HTTP status, redirect targets, body shape, the `shop_sid` session cookie, line totals, and the empty-cart state. The server is shut down via `app.shutdown()` so the port releases cleanly. · *HTTP integration helpers in `test/helpers/index.js`* — Two new helpers usable by every layer-2 test: `cookieJar()` returns a minimal in-memory jar that captures `Set-Cookie` headers and replays them as a single `Cookie` header on subsequent requests (parses `Max-Age=0` for explicit eviction; ignores `Secure` since loopback traffic is plaintext by design). `httpRequest({ port, path, method, headers, form, body, jar })` wraps `node:http.request` in a promise that resolves to `{ status, headers, body }` — `body` is a UTF-8 string. Form-encoded POSTs are the dominant storefront shape; pass `opts.form` as a plain object and the helper sets the content-type and serializes the body. Default headers (User-Agent, Accept-Language, Sec-Fetch-Mode) match a realistic browser shape so tests don't trip the framework's bot-guard heuristics in setups that keep it enabled.
|
|
44
|
+
|
|
45
|
+
- v0.0.22 (2026-05-21) — **Analytics primitive + admin dashboard.** Operator-facing read-only aggregates over the orders table: window summary (order counts + net revenue + per-status buckets), revenue-by-day, top SKUs by units sold, and recent orders. Surfaced as JSON under `/admin/analytics/*` and rendered as a single-page server-rendered HTML dashboard at `/admin/dashboard`. Revenue counts `cancelled` orders at zero and subtracts `refunded` orders so the headline number tracks what reached the bank. **Added:** *`analytics` primitive* — `lib/analytics.js` ships `create({ query })` returning `{ summary, revenueByDay, topSKUs, recentOrders }`. Each method takes an `{ since, until }` window (epoch milliseconds, defaults to last 30 days, refused above 1 year span). `summary` returns `{ currency, total_orders, total_revenue_minor, by_status }` per currency — a single object for single-currency windows, an array when multiple currencies are in scope. `revenueByDay` groups by `date(updated_at/1000, 'unixepoch')` so the bins are calendar-aligned UTC days. `topSKUs` joins `order_lines` to `orders` for the window filter and excludes cancelled + refunded orders from the units count. `recentOrders` returns the most-recent N orders for the activity feed. Revenue policy: `cancelled` excluded entirely, `refunded` subtracts, every other status adds at face value. · *Admin analytics routes* — `lib/admin.js` mounts `GET /admin/analytics/summary`, `GET /admin/analytics/revenue-by-day`, `GET /admin/analytics/top-skus`, `GET /admin/analytics/recent-orders` returning JSON, plus `GET /admin/dashboard` returning a server-rendered HTML page. Routes only register when `deps.analytics` is supplied — operators opt in by constructing the primitive and passing it into `admin.mount`. The dashboard is `noindex,nofollow` and bearer-token gated alongside the existing admin surface. Query-param validation refuses non-integer `since` / `until` / `limit` with a 400. · *Server-rendered HTML dashboard* — `admin.renderDashboard` lays out an eight-card stat grid (orders + net revenue + the six FSM status buckets), an inline SVG sparkline of revenue-by-day, a top-SKUs table, and a recent-orders activity panel with status pills. Matches the storefront brand palette (`#191919` ink, `#fa4f09` accent, Montserrat headlines, Inter body). Multi-currency operators see a secondary `Other currencies in window` block with per-currency totals. Zero client-side JavaScript — every value is rendered server-side and HTML-escaped through a strict `{{var}}` substitution that refuses unknown / unused placeholders. **Detectors:** *Layer 1 — `analytics`* — `test/layer-1-state/analytics.test.js` seeds rows across pending / paid / fulfilling / refunded / cancelled statuses + multiple UTC days + multiple currencies, then asserts: `summary` returns the per-status bucket counts with refunded subtracting and cancelled excluded from revenue; the empty-window case returns a zero-filled USD shape; the multi-currency window returns an alphabetically-sorted array. `revenueByDay` groups by UTC calendar day, sorts day ASC, applies the refund-subtracts / cancelled-excluded policy. `topSKUs` aggregates units across multiple orders, sorts by units_sold DESC, excludes cancelled order lines, honors LIMIT. `recentOrders` orders by created_at DESC with the right row shape. Validation covers non-integer `since` / `until`, `since >= until`, windows > 1 year, and limits outside `[1, 100]`. Admin-route smoke covers the bearer gate, JSON route shapes, HTML dashboard shape (DOCTYPE + SVG + status pill + escaped shop name), and the bad-param 400 path.
|
|
46
|
+
|
|
47
|
+
- v0.0.21 (2026-05-21) — **Outbound merchant webhooks.** Operators register HTTPS endpoints to receive order-state-change events. Each delivery is signed via `b.webhook.signer` using a per-endpoint secret (returned ONCE at create); receivers verify with the framework's standard `Webhook-Signature` header recipe. The order primitive accepts an optional `webhooks` dependency and fans every transition out to subscribed endpoints automatically. **Added:** *Migration `0005_webhooks.sql`* — Two tables: `webhook_endpoints` (id, url, secret, events allowlist or `*`, active flag, created_at/updated_at; index on active) and `webhook_deliveries` (id, endpoint_id FK with cascade, event_type, payload_json, attempts, last_status, last_error, delivered_at, created_at; composite index on endpoint_id+created_at). The secret is generated by the framework at create time and returned ONCE — operators record it for verification; subsequent reads never reveal it. · *`webhooks` primitive* — `lib/webhooks.js` ships `create({ query, transport?, retry? })` returning `{ endpoints: { create, get, list, update, delete }, deliveries: { list, retry }, send(eventType, payload), KNOWN_EVENTS }`. `send` queries active endpoints, filters by event subscription (`*` or comma-list), signs each delivery via `b.webhook.signer({ algo: "hmac-sha3-512", keys: { v1: <secret> } })`, persists the delivery row before the POST, and updates status (1xx-3xx = delivered, 4xx/5xx or transport error = failed with `last_error`). Transient transport errors (ECONNRESET / ECONNREFUSED / etc.) retry once via `b.retry.withRetry`. Idempotency key bound into the signed string is a fresh `b.uuid.v7()` per delivery so manual retries replay safely on the consumer side. · *URL + event validation* — `endpoints.create` refuses any non-HTTPS URL via `b.safeUrl.parse({ allowedProtocols: ["https:"] })` so an operator typo (`http://`) surfaces at admin-write time rather than leaking cleartext deliveries. `events` accepts the wildcard `*` or a comma-separated allowlist drawn from the recognized event types (`order.mark_paid`, `order.start_fulfillment`, `order.mark_shipped`, `order.mark_delivered`, `order.cancel`, `order.refund`); unknown event types are refused. · *Order transition fan-out* — `lib/order.js`'s `create({ query, webhooks? })` accepts an optional `webhooks` dependency. When present, every successful `transition()` call fires `webhooks.send("order." + event, { order, transition })` after the transition persists. Delivery failures never roll back the transition — the failure already lives in `webhook_deliveries.last_error` for operator review. Backward-compatible default of `null` so existing callers (and the test suite) keep working without a webhooks instance. · *Admin routes* — `lib/admin.js` mounts `POST /admin/webhooks` (returns the row including the one-time secret), `GET /admin/webhooks`, `PATCH /admin/webhooks/:id` (url / events / active), `DELETE /admin/webhooks/:id`, `GET /admin/webhooks/:id/deliveries?limit=`, and `POST /admin/webhooks/deliveries/:id/retry` for manual re-delivery. Every mutation writes to the existing `shop_admin` audit namespace. **Detectors:** *Layer 1 — `webhooks`* — `test/layer-1-state/webhooks.test.js` exercises endpoint CRUD, URL validation (refuses http://, ftp://, malformed), event-type allowlist enforcement, signing round-trip (verifies the emitted `Webhook-Signature` against `b.webhook.verifier`), event filtering (single-event vs wildcard subscriber + inactive endpoint skip), failure persistence (5xx leaves `last_error` set + no `delivered_at`), retry on transient transport error (single retry via `b.retry.withRetry`), manual retry endpoint (failure row flips to delivered + attempts bumped), and order-transition fan-out (a `mark_paid` transition fires a `order.mark_paid` delivery against the wired-in dispatcher).
|
|
48
|
+
|
|
49
|
+
- v0.0.20 (2026-05-21) — **Catalog product search — storefront + admin.** Customers and operators can now search the product catalog by free-text query. The storefront header gains a search box that routes to `GET /search`, and the admin API gains `GET /admin/products/search?q=` for draft + archived visibility. The matcher runs case-insensitive `LIKE` against `title` and `description`, escaping the `%` / `_` LIKE wildcards so a query like `100%` matches only the literal substring. **Added:** *`catalog.products.search({ q, status?, limit?, cursor? })`* — Lowercased substring match against `title` + `description` via SQLite `LIKE ... ESCAPE '\'`. The user-supplied `q` is trimmed, capped at 200 chars, and has `%` / `_` / `\` escaped before binding so wildcard characters in the query never widen the match. Results are sorted `updated_at DESC, id DESC` and paginated through the same HMAC-tagged tuple cursor that `products.list` uses — operators can hand-roll their own admin search UIs on top without re-implementing keyset pagination. Empty / whitespace-only `q` returns `{rows: [], next_cursor: null}` rather than throwing, so storefront and admin route handlers can render an empty-state page without a try/catch. · *Storefront search route + header form* — `GET /search?q=<query>` calls `catalog.products.search({ q, status: "active", limit: 24 })` and renders the new `renderSearch(opts)` page. The shared layout header gains a `<form action="/search" method="get">` input that pre-fills with the current query on the results page. The query is HTML-escaped through the strict template engine so a reflected `<script>` payload lands as escaped text inside both the summary line and the input's `value` attribute. · *Admin search route* — `GET /admin/products/search?q=&limit=&cursor=` returns the full `{rows, next_cursor}` page with no status filter — admins see draft + archived products alongside active ones so a mis-published slug is findable before promotion. The route is bearer-token gated under the existing `ADMIN_API_KEY` and slices `q` to 200 chars before handing to the primitive. **Detectors:** *Layer 1 — `catalog._search`* — `test/layer-1-state/catalog.test.js` covers: title match, description match, case-insensitivity in both directions, empty / whitespace-only query returning empty rows, LIKE-metacharacter escape (`100%` matches only the literal `100%` product, `_idget` returns zero rows), status filter behavior (no-status returns draft + archived), pagination round-trip with cursor distinctness, and TypeError shape for non-string / over-length / bad-status / bad-limit input. · *Layer 1 — `storefront._search`* — `test/layer-1-state/storefront.test.js` covers `renderSearch` output shape (header, summary, product grid, pre-filled input), singular vs plural summary, empty-state copy distinguishing blank `q` from `q with no matches`, and reflected-XSS escape on a `<script>`-bearing query.
|
|
50
|
+
|
|
51
|
+
- v0.0.19 (2026-05-21) — **Media upload admin route — container → Worker → R2.** Admin API gains `POST /admin/media/upload` so operators can attach product imagery without pre-uploading to R2 via the wrangler CLI. The container fetches the source URL through `b.httpClient` (SSRF gate, retry, TLS 1.3 minimum), validates the served content-type matches the operator's declared one, generates a UUIDv7 key under `media/`, pushes the bytes to a new Worker R2 bridge, then records the media row via `catalog.media.attach`. The Worker holds the R2 binding so the container never carries an R2 API token; the upload bridge is gated by the same shared secret the D1 bridge uses. **Added:** *`r2Bridge` — container → Worker upload adapter* — `lib/r2-bridge.js` ships `create({ bridgeUrl, bridgeSecret, bridgePath?, timeoutMs?, httpClient? })` returning `{ put(key, body, contentType) }`. POSTs to the Worker's `/_/r2/put` endpoint with `application/octet-stream` body, `x-d1-bridge-secret` auth header, `x-r2-key` + `x-r2-content-type` metadata headers. Composes on `b.httpClient.request` so every outbound call inherits the SSRF gate, retry policy, circuit breaker, ALPN HTTP/2 transport, and TLS 1.3 minimum. Returns `{ ok, key, size }` on success; surfaces Worker error envelopes + HTTP 4xx/5xx + timeouts as typed throws (`R2_HTTP_<status>`, `R2_TIMEOUT`, `R2_BAD_RESPONSE`). · *Worker `/_/r2/put` endpoint* — `worker/index.js` accepts POST on the configurable `R2_BRIDGE_PATH` (default `/_/r2/put`). Same constant-time `D1_BRIDGE_SECRET` gate as the SQL bridge. Re-validates the `x-r2-key` shape (no leading `/`, no `..` segments, ≤ 1024 chars) + the `x-r2-content-type` matches the RFC 7231 `type/subtype` grammar (≤ 255 chars) so a compromised secret can't write arbitrary paths or smuggle control bytes into the bucket's object metadata. Writes via `env.ASSETS.put(key, body, { httpMetadata: { contentType } })`. Returns `{ ok, key, size }` JSON; refuses empty bodies + missing R2 binding with descriptive 4xx/503 envelopes. · *`POST /admin/media/upload` admin route* — `lib/admin.js` mounts the upload route when the operator wires an `r2_bridge` instance. Body shape: `{ product_id?, variant_id?, content_type, source_url, alt_text?, position?, width?, height? }`. Fetches `source_url` via `b.httpClient.request` (SSRF gate refuses cloud-metadata + RFC 1918 + loopback destinations), refuses content-type mismatches between the declared MIME and the served MIME with 422, generates a UUIDv7 key under `media/<id>.<ext>` (extension inferred from the declared content-type), uploads via the bridge, then calls `catalog.media.attach` to record the row. Returns the media row plus `asset_url` (the public `/assets/...` URL operators preview in the admin UI). The route is omitted entirely when no bridge is wired — operator opts in by setting `D1_BRIDGE_URL` + `D1_BRIDGE_SECRET`. · *`server.js` wires the bridge into the admin mount* — The application boot constructs an `r2Bridge` instance when `D1_BRIDGE_URL` + `D1_BRIDGE_SECRET` are present (the same env pair that wires the D1 backend), then hands it to `admin.mount` as `deps.r2_bridge`. The Worker passes `R2_BRIDGE_PATH` through to the container env alongside `D1_BRIDGE_PATH` so an operator can move the upload endpoint without touching the container code. **Detectors:** *Layer 1 — `r2-bridge`* — `test/layer-1-state/r2-bridge.test.js` exercises factory validation (every required + optional opt), put() happy path (URL+path concat, method, every header, octet-stream content-type, Buffer body), custom bridgePath, Worker error envelope as typed throw, HTTP 5xx with message surfaced, malformed-JSON response as `R2_BAD_RESPONSE`, AbortError → `R2_TIMEOUT`, network error preserves the original code, put() argument validation (empty key, absolute path, parent-segment escape, missing body, empty content-type, malformed MIME), and string + Uint8Array body encoding to the wire Buffer.
|
|
52
|
+
|
|
53
|
+
- v0.0.18 (2026-05-21) — **Storefront tax + shipping read from `shop_config`.** The storefront mount stops hardcoding empty tax rules + a single $0 standard shipping service and instead reads `tax.rules`, `shipping.services`, and `shipping.default_id` from the `config` primitive on every checkout. Operators set these via `PUT /admin/config/:key` and the next checkout picks up the new values (modulo the config primitive's 30s read cache); zero-rate tax + a `std` $0 shipping zone remain the documented defaults when no row is present. **Changed:** *`server.js` wires config-backed tax + shipping into the storefront checkout* — The storefront mount now constructs a single `config = bShop.config.create({})` instance at boot and hands the storefront a `tax` adapter + `shipping` adapter whose `calculate(ctx)` / `rates(ctx)` methods rebuild a fresh `bShop.tax.create({ rules })` / `bShop.shipping.create({ services })` from the latest config rows on each call. `selected_shipping_id` likewise resolves from `shipping.default_id` per request via an async resolver passed as `deps.default_shipping_id`. The admin mount shares the same config instance so writes invalidate the cache the storefront reads. · *`storefront.checkout` accepts an async `default_shipping_id` resolver* — `POST /checkout` now `await`s `deps.default_shipping_id()` when the dep is a function, falling back to treating it as a literal string otherwise. Existing operators passing a string keep working; the new shape lets the resolver re-read `shipping.default_id` from config without a container restart. **Detectors:** *Layer 1 — `storefront-config-wiring`* — `test/layer-1-state/storefront-config-wiring.test.js` exercises the config-backed wrappers against an in-memory `shop_config` table: seeds `tax.rules` + `shipping.services` + `shipping.default_id`, asserts the wrapped adapters return the operator-configured values, and confirms zero-rate defaults kick in when the config table is empty.
|
|
54
|
+
|
|
55
|
+
- v0.0.17 (2026-05-20) — **Shop config primitive + admin routes.** Operator-tunable runtime configuration keyed by name with JSON-shaped values. Backed by a new `shop_config` table in D1. Admin API gains `GET/PUT/DELETE /admin/config/:key` + `GET /admin/config?prefix=` so operators set tax rules, shipping services, brand name, support email, and any other runtime tunable without re-deploying. **Added:** *Migration `0004_shop_config.sql`* — Single key/value table: `key` (TEXT PRIMARY KEY, matches `^[a-z][a-z0-9._]{0,63}$`), `value_json` (TEXT, ≤ 64 KiB after JSON.stringify), `version` (INTEGER, bumped on every UPSERT), `updated_at` (epoch ms). Indexed by `updated_at` for change-feed semantics later. · *`config` primitive* — `lib/config.js` ships `create({ query })` returning `{ get, getFresh, put, delete, list }`. Bounded 30s in-memory cache on reads; writes + deletes invalidate the entry. Every value round-trips through `JSON.parse` at write so a corrupted blob surfaces at admin-write time rather than at customer-checkout. `list(prefix)` filters by key prefix and sorts by key for stable admin paging. · *Admin routes* — `GET /admin/config?prefix=`, `GET /admin/config/:key`, `PUT /admin/config/:key` (body: `{ value }`), `DELETE /admin/config/:key`. The PUT mutation writes a row to the `shop_admin.config.put` audit namespace alongside the existing admin write events. **Detectors:** *Layer 1 — `config`* — `test/layer-1-state/config.test.js` exercises put+get round-trip for primitives / arrays / nested objects, default-value fallback on miss, version bump on second put, prefix-filtered list with stable sort, delete + idempotent re-delete, cache invalidation on put/delete (cache returns NEW value), and corrupted-at-rest row surfacing as a typed error. Validation covers bad key shape, value > 64KiB, undefined value, and non-string prefix.
|
|
56
|
+
|
|
57
|
+
- v0.0.16 (2026-05-20) — **`pricing.format` composes upstream `b.money`.** The currency-rendering path on every storefront / email / order page now flows through the framework's Money class (`b.money.fromMinorUnits(bigint, currency).format(locale)`) instead of constructing `Intl.NumberFormat` inline. Output is byte-identical for every supported currency (USD / EUR / GBP / JPY zero-decimal all match prior renders); the win is framework-policy alignment — Money owns ISO 4217 currency exponents and locale-correct fraction-digit selection across the entire blamejs ecosystem. **Changed:** *`pricing.format` swaps inline `Intl.NumberFormat` for `b.money`* — `lib/pricing.js` now coerces the `Number` minor-unit at the boundary into a `BigInt`, hands it to `b.money.fromMinorUnits(bigint, currency)`, and calls `.format(locale)`. The upstream Money primitive carries the ISO 4217 catalog (code → exponent) so JPY (exp=0), KRW (exp=0), and JOD (exp=3) all render correctly without us re-implementing the table. The pricing primitive's external API (`Number` minor units) is unchanged — every existing consumer (cart, checkout, order, storefront, email) keeps its current call shape.
|
|
58
|
+
|
|
59
|
+
- v0.0.15 (2026-05-20) — **README refresh — full primitive surface documented.** The README's `What ships` section now reflects every primitive landed since the foundation patch: catalog, cart, pricing, tax, shipping, payment, order, checkout, email, storefront, admin. Includes a `Operator quick-start` block walking through `wrangler login` → resource provisioning → secret setting → migration apply → deploy → seed-a-product. **Changed:** *README documents every primitive* — The `What ships` section is now split into Platform / Commerce primitives / Migrations applied to D1 / Tests subsections. Each primitive entry lists its module path, its function, and the composed blamejs surface it relies on. The Operator quick-start block carries the canonical wrangler one-time setup + deploy + seed-a-product command sequence so an operator landing on the repo has an unambiguous path from clone to live shop.
|
|
60
|
+
|
|
61
|
+
- v0.0.14 (2026-05-20) — **Worker container cold-start retry — 3 attempts, exponential backoff.** Container cold-start can still surface `Failed to start container: The container is not running` when the underlying SDK's default 8-second port-wait window is exceeded under provisioning load. The single-retry-with-1.5s-backoff shipped in v0.0.9 wasn't always enough; this patch ups it to three retries with 2s / 4s / 8s backoff (~14 seconds total patience for the cold-start window). **Changed:** *Vendor refresh blamejs v0.11.36 → v0.11.37* — Caught up to upstream. **Fixed:** *`worker/index.js` cold-start retry — 3 attempts* — `_forwardToContainer` now retries up to three times on `Failed to start container` / `no Container instance` 5xx responses with 2s / 4s / 8s exponential backoff. The first attempt is immediate; legitimate 5xx (non-cold-start body shapes) short-circuit so application errors still surface immediately. POST bodies buffer once on entry and re-serve from the ArrayBuffer on each retry; GET / HEAD have no body and clone cheaply.
|
|
62
|
+
|
|
63
|
+
- v0.0.13 (2026-05-20) — **Cart line mutations — update qty + remove.** Cart page becomes interactive: every line shows an inline qty input + Update button and a Remove button. POST routes wire to `cart.updateLine` and `cart.removeLine`. A Checkout call-to-action button anchors the cart summary so customers can advance through the flow without typing a URL. **Added:** *Editable cart lines* — `lib/storefront.js` now ships `CART_LINE_EDITABLE` — replaces the read-only line template with one that includes an inline `<form method="post" action="/cart/lines/:id/update">` carrying the qty input and a separate `<form method="post" action="/cart/lines/:id/remove">` for line removal. HTML forms only support GET/POST so the verb lives in the path (no `_method` override hack). · *POST /cart/lines/:id/update + /remove* — Two new route handlers in `storefront.mount`. Update validates qty (1..99) + calls `cart.updateLine(lineId, { qty })`; returns 404 when the line is unknown. Remove calls `cart.removeLine(lineId)`. Both 303 redirect to `/cart` on success so a refresh of the result doesn't replay the mutation. Errors from the cart primitive map to 400 (TypeError) or 500 (anything else). · *Checkout CTA on the cart page* — Cart summary now anchors a `<a class="btn" href="/checkout">Checkout →</a>` button so customers can progress without typing the URL. The button inherits the accent color from the default theme — same affordance as the in-page Update/Add-to-Cart buttons. · *Vendor refresh blamejs v0.11.35 → v0.11.36* — Caught up to upstream.
|
|
64
|
+
|
|
65
|
+
- v0.0.12 (2026-05-20) — **End-to-end checkout flow — shipping form, Stripe Elements, order confirmation.** Storefront completes the cart → checkout → pay → confirmation loop. The shipping form collects email + name + ISO 3166 country/state/postal, hands the values to `checkout.confirm`, persists the order in `pending`, and redirects to a Stripe Elements payment page with the per-order `client_secret`. After payment, Stripe redirects back to a server-rendered order confirmation page that shows status + lines + totals. **Added:** *Checkout flow routes* — `lib/storefront.js` mounts `GET /checkout` (shipping form pre-filled with cart subtotal), `POST /checkout` (calls `checkout.confirm` with idempotency key + redirects to `/pay/:order_id` with a short-lived `shop_pay` cookie scoped Path=/pay/ + SameSite=Strict carrying the `client_secret`), `GET /pay/:order_id` (renders Stripe Elements payment page — loads Stripe.js from `js.stripe.com/v3/`, mounts the Payment Element, redirects to the order page on success via Stripe's `return_url`), and `GET /orders/:order_id` (server-rendered confirmation showing status, line items, and the subtotal/tax/shipping/total breakdown). · *Wired through `server.js` when Stripe is configured* — The storefront mount picks up `checkout` / `payment` / `order` / `tax` / `shipping` / `default_shipping_id` / `stripe_publishable_key` deps when `STRIPE_API_KEY` + `STRIPE_WEBHOOK_SECRET` are set. The default-fallback tax + shipping are zero-rate / zero-cost (operator-configured proper rules in `wrangler.toml` `[vars]` or a config primitive land later). Without Stripe configured, the storefront stays browseable (home / product / cart) but the checkout routes don't mount. · *Worker env passthrough* — `worker/index.js` forwards `STRIPE_PUBLISHABLE_KEY` into the container env alongside the existing `STRIPE_API_KEY` + `STRIPE_WEBHOOK_SECRET` + `ADMIN_API_KEY` set. **Detectors:** *Layer 1 — storefront checkout renderers* — `test/layer-1-state/storefront.test.js` gains `_checkoutForm` (form action + field shape + subtotal rendering), `_payPage` (Stripe.js loaded + pk + client_secret injected as JSON literals + total rendered + order id surfaced), and `_orderPage` (status + line + tax + total surfaced) tests. Six new assertion clusters.
|
|
66
|
+
|
|
67
|
+
- v0.0.11 (2026-05-20) — **Admin API — bearer-token-gated CRUD.** Single-bearer-token admin surface composed on `b.crypto.timingSafeEqual`, `b.problemDetails`, and `b.audit`. Operators set `ADMIN_API_KEY` as a Worker secret and use it as the bearer for every `/admin/*` route. Coverage: products + variants + prices + inventory + media CRUD, order get + transition, Stripe-backed refund flow that fires the order FSM refund transition automatically. Multi-admin passkey-enrolled surface lands alongside the admin browser UI in v1.x. **Added:** *`admin` — bearer-token admin API* — `lib/admin.js` exposes `mount(router, deps)` that wires `/admin/*` routes behind a `Bearer` token check. Token comparison uses `b.crypto.timingSafeEqual` so a side-channel timing attack can't recover the value byte-by-byte. Length-mismatch short-circuits before the constant-time compare (the compare requires equal lengths). Every mutation writes an audit row to namespace `shop_admin` via `b.audit.emit`; failures are RFC 9457 problem documents via `b.problemDetails.send`. TypeError from a primitive surfaces as 400; any other thrown error as 500. · *Catalog + order + refund coverage* — Routes shipped in v1: `POST/GET/PATCH /admin/products`, `POST /admin/products/:id/archive|restore`, `POST/PATCH/DELETE /admin/variants`, `POST/GET /admin/variants/:id/prices`, `POST /admin/inventory` + `POST /admin/inventory/:sku/restock`, `POST/DELETE /admin/media`, `GET /admin/orders/:id`, `POST /admin/orders/:id/transition`, `POST /admin/orders/:id/refund` (when payment + Stripe API key are wired — the refund call goes through `payment.refund` with a stable idempotency key derived from the order id, then fires `order.transition(id, "refund", ...)` so the FSM advances atomically with the Stripe side). · *Wired into `server.js`* — Admin routes mount only when `ADMIN_API_KEY` is present in env — operators opt in by setting the secret (`wrangler secret put ADMIN_API_KEY`). The Worker passes the secret through to the container at start. Stripe-backed refund routes additionally require `STRIPE_API_KEY` + `STRIPE_WEBHOOK_SECRET`. **Detectors:** *Layer 1 — `admin`* — `test/layer-1-state/admin.test.js` exercises the bearer gate (missing → 401, wrong-same-length → 401, wrong-different-length → 401 short-circuit, right → 200, lowercase `bearer` accepted), product create + update + archive round-trip, order transition round-trip + illegal-transition surface as 4xx, and factory validation. Uses an in-memory fake router that supports `:param` route registration so the path matching matches what the real `b.router` does.
|
|
68
|
+
|
|
69
|
+
- v0.0.10 (2026-05-20) — **Storefront visual upgrade — brand identity + theme palette.** The default storefront theme adopts the framework's brand identity: the `blamejs.shop` logo served from R2, a monochrome-plus-accent palette (`#191919` / `#fa4f09` / `#ffffff`) sourced from the reference ecommerce templates shipped under `.template/`, Montserrat headlines and Inter body text. The home page gains a hero section that frames the framework's identity. The CSS is still inline; the theme primitive that lifts these into a swappable directory ships in v1.x. **Added:** *Brand identity in the default theme* — `lib/storefront.js`'s LAYOUT template now references `/assets/brand/logo.png` (served from the R2 bucket the Worker is bound to) and renders the wordmark next to the logo image in the site header. The logo PNG is uploaded once via `npx wrangler r2 object put blamejs-shop-assets/brand/logo.png --file=.template/blamejs.shop_logo.png --content-type=image/png --remote`; the source asset stays local-only under `.template/` (gitignored). · *Palette + typography from the reference templates* — The default theme palette derives from the `odor-buyer-file` reference template under `.template/`: `--ink: #191919`, `--ink-2: #414141`, `--mute: #727272`, `--hair: #d9d9d9`, `--accent: #fa4f09`, `--accent-d: #d8410a`, `--paper: #ffffff`, `--bg: #fafafa`. Headlines render in Montserrat (700), body text in Inter (400-600), both from Google Fonts with `preconnect` hints. Buttons, links, and the cart pill use the accent color for interaction state. · *Hero on the home page* — `renderHome` now prepends a hero section above the product grid — communicates the framework identity ("An open-source shop, built on blamejs") to first-time visitors and gives the page presence when the catalog is empty. The hero is part of the default theme and ships in the same LAYOUT; future themes can override via the theme primitive in v1.x. · *Card + table + form refinements* — Product cards gain hover state (subtle lift + shadow), prices render in the accent color, links show a bottom border that flips to the accent on hover. Table headers adopt all-caps Montserrat 600 with a 2px ink underline, total rows render with a thick ink top border. Cart summary moves into a `.summary-table` block with `--bg` fill. Forms inherit consistent input + button styling.
|
|
70
|
+
|
|
71
|
+
- v0.0.9 (2026-05-20) — **Cart-write routes + container cold-start retry.** Storefront gains the `POST /cart/lines` route plus a session-id cookie binding so the "Add to cart" form on the product detail page actually works end-to-end. Worker forwards now retry once on the cold-start "Failed to start container" 5xx so a single cold provisioning doesn't bubble to the shopper. Body parser middleware mounted in the application boot for form-encoded + JSON request bodies. **Added:** *Cart-write route — `POST /cart/lines`* — `lib/storefront.js` mounts the cart-add route alongside the read-only HTML pages. The handler resolves the cart via a `shop_sid` HttpOnly cookie (UUIDv7 session id, SameSite=Lax — blocks cross-site form POSTs from carrying the session, which is the load-bearing CSRF defense for cart-add). When the cookie is absent, the handler mints a fresh session id, sets the cookie, and creates the cart. On success the response is `303 See Other` to `/cart` so a refresh of the result page doesn't re-submit the form. · *Cart count on every storefront page* — `renderHome` / `renderProduct` / `renderCart` accept a `cart_count` opt; the route handlers compute it by looking up the session's active cart and reading `cart.listLines(c.id).length`. The header badge (`Cart (N)`) reflects the actual session state without a separate JSON ping. · *Body parser middleware mounted at boot* — `server.js` now wires `b.middleware.bodyParser()` so every route receives `req.body` parsed from `application/x-www-form-urlencoded` (the storefront's cart forms) and `application/json` (future admin API). Mounted before any route handler so the surface is uniform. · *Container cold-start retry in the Worker* — `worker/index.js`'s `_forwardToContainer` now buffers the request body and retries once on the `@cloudflare/containers` 5xx "Failed to start container" / "There is no Container instance" responses with a 1.5s backoff. A single cold-start race during deploy rollout or instance recycling no longer surfaces to the shopper as a 500. GET / HEAD short-circuit the body buffer; POST bodies are read into an ArrayBuffer once and re-served on the retry.
|
|
72
|
+
|
|
73
|
+
- v0.0.8 (2026-05-20) — **Storefront — server-rendered HTML for end customers.** Minimum viable storefront: read-only HTML for home (product list), product detail, and cart. Renderers are pure functions composable in isolation; `mount(router, deps)` wires them into a `b.router` instance. Inline string templates with the strict `{{var}}` renderer the email primitive uses — HTML-escaped substitution, refusal of unknown / unused placeholders. The full theme primitive (file-backed templates via `b.template`, asset fingerprinting, theme inheritance, customer-buildable themes) lands in v1.x. **Added:** *`storefront` — server-rendered HTML* — `lib/storefront.js` ships pure-function renderers (`renderHome`, `renderProduct`, `renderCart`, `renderNotFound`) plus a `mount(router, deps)` that registers the read-only GET routes against a `b.router` instance. The home page lists active products with their starting USD price; the product page shows title, description, and a variant table with SKUs + per-variant prices; the cart page renders lines + subtotal + grand total. Every substituted value is HTML-escaped via the strict renderer — XSS attempts through a product title surface as `<script>` in the rendered markup, never as executable HTML. · *Wired into `server.js`* — When the data layer is configured (`D1_BRIDGE_URL` + `D1_BRIDGE_SECRET` present), the container boot mounts `bShop.storefront.mount(router, { catalog, cart })` so `GET /`, `GET /products/:slug`, and `GET /cart` serve HTML directly. Without the data layer, the container falls back to the JSON identity ping (useful for local smoke without wrangler dev). **Detectors:** *Layer 1 — `storefront`* — `test/layer-1-state/storefront.test.js` exercises each renderer: home with products + empty state + cart count, product detail with variants + missing-variants empty state, cart with lines + subtotal + grand total + empty state. XSS escape verified by injecting `<script>` into a product title and asserting it's rendered as `<script>`. Validation tests at every entry point.
|
|
74
|
+
|
|
75
|
+
- v0.0.7 (2026-05-20) — **Transactional email primitive.** Transactional templates (order receipt, ship notification, refund confirmation) composed on `b.mail` with a strict `{{var}}` renderer that HTML-escapes every substituted value and refuses unknown / unused placeholders at composition time. Operators inject a `b.mail.create(...)` mailer at boot — transports include console / memory / smtp / http / resend out of the box. **Added:** *`email` — transactional templates* — `lib/email.js` exposes `create({ mailer, from })` returning `{ orderReceipt, shipNotification, refundConfirmation }`. Each method takes the domain object (order + customer plus a per-message extra like `tracking` or `amount_minor`), renders an HTML + text body via the strict templater, and hands the message to the injected mailer. Address shape is validated against `b.guardEmail.validate` (strict profile) before sanitization — `sanitize()` strips unicode / BIDI / control bytes but does not reject malformed shapes, so the validate-first-sanitize-after order is load-bearing. · *Strict `{{var}}` renderer* — `email._render(template, vars)` substitutes `{{name}}` placeholders, HTML-escapes every value (XSS defense), and throws if the template references an unknown variable OR if any provided variable wasn't referenced. Catches both the typo-in-template bug and the rename-without-updating-caller bug at composition time, before a customer-facing email ships with `{{customer_name}}` literal text or a missing field. · *Pluggable transport via `b.mail.transports`* — blamejs ships `b.mail.transports.{console, memory, smtp, http, resend}` — operators choose at app boot. `memory` records every send in an array (used by the layer-1 test to assert on message shape without a real SMTP server). The `email.create` factory takes the mailer; no transport coupling in the shop module itself. **Detectors:** *Layer 1 — `email`* — `test/layer-1-state/email.test.js` exercises every template against a fake mailer: order receipt with totals (subtotal, tax with jurisdiction, shipping, grand total), ship notification with carrier + tracking, refund confirmation with formatted amount. Covers HTML escaping (XSS attempt via `customer.name`), strict-renderer refusals (unknown placeholder + unused variable), and address-shape validation.
|
|
76
|
+
|
|
77
|
+
- v0.0.6 (2026-05-20) — **Checkout orchestrator + webhook upgrade to upstream b.webhook.** Checkout primitive that ties cart + catalog + pricing + tax + shipping + payment + order into a two-call API (`quote` + `confirm`) plus a webhook dispatcher that maps Stripe events to FSM transitions. Payment verifier swapped from a local node:crypto fallback to the upstream `b.webhook.verify` primitive (alg `hmac-sha256-stripe`, available since blamejs v0.11.25) — the local `node:crypto` allow marker is gone. **Added:** *`checkout` — orchestrator* — `lib/checkout.js` ships `create({ catalog, cart, pricing, tax, shipping, payment, order })` returning `{ quote, confirm, handleStripeEvent, STRIPE_EVENT_MAP }`. `quote({ cart_id, ship_to, selected_shipping_id })` is read-only — composes the priced quote (lines + totals + shipping rates + tax jurisdiction). `confirm({ cart_id, ship_to, selected_shipping_id, customer, idempotency_key })` creates the Stripe PaymentIntent, persists the order in `pending`, marks the cart converted, returns `{ order, payment_intent: { id, client_secret, status } }`. `handleStripeEvent({ headers, rawBody })` verifies the signature via `payment.verifyWebhook`, looks up the order by `payment_intent_id`, and fires the appropriate FSM transition (`payment_intent.succeeded` → `mark_paid`, `payment_intent.canceled` → `cancel`, `charge.refunded` → `refund`). Re-delivered events are idempotent — if the order is already at or past the target state, the handler returns `{ handled: true, skipped: "already-advanced" }`. · *Payment verifier composes upstream `b.webhook.verify`* — `payment.verifyWebhook` now wraps `b.webhook.verify({ alg: "hmac-sha256-stripe", ... })` instead of reaching for `node:crypto.createHmac("sha256", ...)` locally. The upstream primitive ships full Stripe-spec verification (constant-time compare, multi-v1= rotation support, timestamp tolerance, optional `nonceStore` for replay defense) — composing it shrinks `lib/payment.js`, drops the `allow:non-shop-require` marker, and brings the verifier into framework-policy alignment. The `verifyWebhook` shape stays `{ ok, reason }` so checkout's handler doesn't need to change. **Detectors:** *Layer 1 — `checkout`* — `test/layer-1-state/checkout.test.js` stitches every prior primitive (catalog, cart, pricing, tax, shipping, payment, order) into an end-to-end flow against in-memory SQLite. Coverage: quote returns lines + totals + shipping rates + tax jurisdiction, confirm creates a PaymentIntent + pending order + converts the cart, confirm refuses zero-total carts, handleStripeEvent maps `payment_intent.succeeded` → `mark_paid`, re-delivered events are idempotent (`skipped: "already-advanced"`), bad signature throws `WEBHOOK_INVALID`. Payment outbound is stubbed (the orchestration is what we're testing); the real Stripe-API integration is exercised by `payment.test.js`. **References:** [blamejs v0.11.25 b.webhook.verify](https://github.com/blamejs/blamejs/blob/v0.11.25/lib/webhook.js)
|
|
78
|
+
|
|
79
|
+
- v0.0.5 (2026-05-20) — **Order primitive — FSM-driven post-checkout record.** The order primitive composes the freshly-landed `b.fsm` upstream surface to drive the post-checkout lifecycle. Orders persist in D1 with a versioned transition log; every state change goes through the FSM so illegal transitions throw at the framework boundary instead of corrupting the order record. **Added:** *`order` — FSM-driven post-checkout record* — `lib/order.js` ships `create({ query })` returning `{ createFromCart, get, byPaymentIntent, transition, setPaymentIntent, TERMINAL_STATES }`. States: pending → paid → fulfilling → shipped → delivered, plus refunded / cancelled (terminal). Events: mark_paid, start_fulfillment, mark_shipped, mark_delivered, cancel, refund. Each transition fires through `b.fsm` (which refuses illegal events at the framework boundary) and appends a row to `order_transitions` so the lifecycle is auditable end-to-end. `byPaymentIntent(piId)` is the lookup webhook handlers use to map Stripe events back to the local order. · *Migration `0003_order.sql`* — Three tables: `orders` (row per checkout, captures cart snapshot + totals + ship_to JSON + payment_intent_id with a unique index), `order_lines` (snapshot of cart_lines at order creation — immutable post-checkout), `order_transitions` (one row per FSM transition, including the initial `__init__ → pending` create-event). FK cascade on order delete removes lines + transitions. · *Vendor refresh blamejs v0.11.24 → v0.11.25* — Upstream v0.11.25 ships `b.fsm` (auditable in-process FSM with guards + onEnter/onExit + concurrent-transition serialization + toJSON/restore round-trip) and `b.money` (decimal-safe money with currency-aware arithmetic and conversion). Order composes `b.fsm`. Pricing will adopt `b.money` in a follow-up patch — the current `Intl.NumberFormat`-based formatter stays for now since it covers the storefront rendering use case. **Detectors:** *Layer 1 — `order`* — `test/layer-1-state/order.test.js` exercises createFromCart (persist + lines + init transition), the happy path (pending → paid → fulfilling → shipped → delivered with metadata captured on each transition), illegal transition refusal (can't ship before paying, can't deliver from pending, unknown events refused), cancel + refund branches, setPaymentIntent's pending-only constraint + byPaymentIntent lookup, and every validation entry point.
|
|
80
|
+
|
|
81
|
+
- v0.0.4 (2026-05-20) — **Payment primitive — Stripe adapter.** Stripe inbound webhook signature verification and outbound API calls (PaymentIntent create / retrieve / confirm / cancel + Refund) composed on `b.httpClient` and `b.crypto.timingSafeEqual`. No `stripe` npm dependency — every byte is either a Node built-in or a vendored blamejs primitive. The pluggable adapter contract lets future Adyen / Mollie / Paddle adapters land without changing caller code. **Added:** *`payment.stripe` — Stripe adapter* — `lib/payment.js` exposes `payment.create({ apiKey, webhookSecret })` returning `{ name, verifyWebhook, createPaymentIntent, retrievePaymentIntent, confirmPaymentIntent, cancelPaymentIntent, refund }`. Every outbound call accepts an explicit `idempotencyKey` so the caller (checkout / refund worker) controls retry safety. `verifyWebhook(headers, rawBody)` parses the `stripe-signature` header (multiple `v1=` entries supported for secret rotation), enforces a ±5-minute timestamp tolerance, runs constant-time signature compare via `b.crypto.timingSafeEqual`, and returns `{ ok, event }` on success or `{ ok: false, reason }` on rejection (`no-signature`, `timestamp-outside-tolerance`, `signature-mismatch`, `bad-json`). The body MUST be the raw request string — passing a parsed object throws. · *Outbound API via `b.httpClient`* — Stripe calls flow through `b.httpClient.request()` so the SSRF gate, retry policy, circuit breaker, ALPN HTTP/2 transport, and TLS 1.3 minimum all apply by default. Bodies are form-encoded with Stripe's bracket-notation for nested params (`metadata[order_id]=ord_1`, `automatic_payment_methods[enabled]=true`). The 15-second per-request timeout is operator-tunable via `payment.create({ timeoutMs })`. · *Pluggable adapter contract* — `payment.create({ adapter: "stripe", ... })` is the v1 surface. Unknown adapter names throw at construction time so a typo (`paddle` / `mollie`) surfaces before any payment flow runs. Future adapters expose the same `{ verifyWebhook, createPaymentIntent, ... }` shape — callers (checkout / order) bind to the contract, not the provider. **Detectors:** *Layer 1 — `payment`* — `test/layer-1-state/payment.test.js` exercises the webhook verifier (valid signature, case-insensitive header, multiple v1= entries for secret rotation, signature mismatch, timestamp-outside-tolerance, mutated body, missing timestamp, malformed JSON), refuses pre-parsed-object bodies, exercises the form encoder for nested + array params, exercises factory validation (`apiKey` + `webhookSecret` required, unknown adapter rejected), and exercises `createPaymentIntent` / `refund` input validation. Outbound API integration tests run against real Stripe in a later patch. **References:** [Stripe Webhooks](https://docs.stripe.com/webhooks) · [Stripe Payment Intents API](https://docs.stripe.com/api/payment_intents)
|
|
82
|
+
|
|
83
|
+
- v0.0.3 (2026-05-20) — **Tax + shipping primitives.** Pure-function tax and shipping computation against operator-declared rule tables. Both primitives ship a pluggable adapter contract; the `operatorTable` adapter built into v1 lets the framework run offline. Future Stripe Tax / TaxJar / EasyPost / Shippo adapters land as drop-in factory swaps without changing the call sites. **Added:** *`tax` — operator-table adapter* — `lib/tax.js` exposes `tax.create({ rules })` returning `{ name, calculate(ctx) }`. Rules declare `country` (ISO 3166-1 alpha-2), optional `state` and `postal_prefix`, and `rate_bps` (basis points — 1 bp = 0.01%). Match precedence is most-specific-first: country + state + postal_prefix → country + state → country → fallback (`rate_bps: 0`, `jurisdiction: "fallback"`). Tax computes against `subtotal_minor` with banker's rounding (round-half-to-even) so cumulative rounding bias across many small carts cancels out instead of drifting upward. The returned `jurisdiction` string (e.g. `"US/CA/941"`) is what storefront templates show under the tax line. · *`shipping` — operator-table adapter* — `lib/shipping.js` exposes `shipping.create({ services })` returning `{ name, rates(ctx) }`. Services declare an id, label, and zones; each zone is either flat-amount or per-gram (with optional `base_minor`, `min_amount_minor`, `max_amount_minor`). Free-over-threshold via `free_over_minor`. Zone matching uses the same most-specific-first precedence as tax. Digital-only services (`digital_only: true`) are offered only when every cart line has `requires_shipping: false`; physical services are filtered out when the cart is digital-only. `rates()` returns `{ services: [{ id, label, amount_minor, free, jurisdiction }], total_grams }` — the storefront renders one row per available service. **Detectors:** *Layer 1 — `tax`* — `test/layer-1-state/tax.test.js` covers rule validation, match precedence (postal > state > country > fallback), banker's rounding on .5 boundaries (round-half-to-even), shipTo / subtotal validation, and `subtotal × rate_bps / 10000` arithmetic on multiple bps values. · *Layer 1 — `shipping`* — `test/layer-1-state/shipping.test.js` covers flat-amount zones, per-gram zones with base + min/max clamping, free-over-threshold thresholding, zone specificity precedence, digital-only filtering, and rule-shape validation.
|
|
84
|
+
|
|
85
|
+
- v0.0.2 (2026-05-20) — **Cloudflare deploy + D1 backend + first commerce primitives.** First feature patch: complete Cloudflare deploy topology (Container + Worker + D1 + R2 + KV + Durable Objects), a `b.externalDb` adapter that targets D1 over the Worker service binding, and the first three commerce primitives — catalog (products, variants, prices, inventory, media), cart (anonymous + authenticated, price-snapshotted lines, merge on login), pricing (pure-function money math). All composed on blamejs primitives — UUIDs from `b.uuid.v7`, identifier safety from `b.guardUuid` and `b.guardMime`, cursor HMAC tagging from `b.pagination`, identifier quoting from `b.safeSql`, error responses via `b.problemDetails`, key derivation via `b.crypto.namespaceHash`. **Added:** *Cloudflare deploy topology* — `Dockerfile` (multi-stage Node 24-alpine build, non-root runtime, tini PID 1, in-image smoke gate), `.dockerignore`, and `wrangler.toml` wiring the Worker, the Container, a D1 database binding, an R2 assets bucket, a KV sessions namespace, and the Durable Object classes. Operators provision the resources with `wrangler d1 create` / `wrangler r2 bucket create` / `wrangler kv namespace create`, paste the returned ids into `wrangler.toml`, set five `BLAMEJS_*_PASSPHRASE` secrets via `wrangler secret put`, and run `wrangler deploy`. · *Edge router Worker* — `worker/index.js` — serves `/_/health` inline, passes `/assets/*` through to R2 with fingerprint-aware cache headers, verifies Stripe webhook signatures (`stripe-signature` HMAC-SHA256 over `<timestamp>.<body>` with a 5-minute tolerance window) before forwarding to the container, exposes the D1 query bridge under `/_/db/query` (gated by a shared-secret header), and forwards everything else to the container via the `Container` base class from `@cloudflare/containers` (handles lifecycle, readiness wait, port routing, scheme rewrite). · *InventoryLock Durable Object* — Per-SKU serialization point for stock decrement and release operations. Each SKU resolves to a single Durable Object instance so concurrent `decrement-if-available` calls from multiple container replicas queue safely; authoritative stock counts live in D1. Exposed as the `INVENTORY` binding. · *`externaldbD1` — Cloudflare D1 adapter for `b.externalDb`* — `lib/externaldb-d1.js` implements the `{ connect, query, close, dialect }` shape `b.externalDb.init` consumes, with two operating modes: service-binding (recommended — container reaches D1 through a sibling Worker, no D1 API token in the container) and rest-api (direct calls for development). Wire-protocol contract: SQLite parameter placeholders (`?1, ?2, ...`), `{ rows, rowCount, lastRowId }` result shape normalized across modes, AbortController-backed timeouts, jittered exponential retry on 5xx / 429 / transient network errors via `b.crypto.randomInt`. · *`catalog` — products, variants, prices, inventory, media* — `lib/catalog.js` ships five sub-modules composed on `b.externalDb` against the `0001_catalog.sql` schema. Products with slug + status (draft/active/archived), variants with options JSON + position + weight + shipping flag, versioned prices (set closes prior, multi-currency independent), inventory with stock-on-hand + held counts, media attached at product or variant scope with R2 keys and content-type validation. v7 UUID primary keys for B-tree locality. `b.guardUuid` for id validation (RFC 9562 threat catalog), `b.guardMime` for content-type validation, `b.safeSql.assertOneOf` + `b.safeSql.quoteIdentifier` for update-column allowlist, `b.pagination.encodeCursor` / `decodeCursor` for HMAC-tagged tuple cursors on `products.list`. · *`cart` — anonymous + authenticated carts* — `lib/cart.js` ships against the `0002_cart.sql` schema. Carts are keyed by `session_id` (sealed-cookie origin), survive container restarts (D1, not session memory), enforce one active cart per session via a partial unique index. `addLine` snapshots `unit_amount_minor` + `unit_currency` at add time from `catalog.prices.current()` (or an explicit override), de-duplicates by `(cart_id, variant_id)` by bumping qty. `merge(fromCartId, toCartId)` adopts an anonymous cart into a customer cart on login — line collisions sum qty, the source cart marks abandoned. `setStatus(cartId, 'converted')` makes a cart immutable post-checkout. · *`pricing` — pure-function money math* — `lib/pricing.js` ships `lineTotal(line)`, `subtotal(lines)`, `totals(cart, lines, ctx)`, and `format(amount_minor, currency, opts?)`. Every primitive operates in integer minor units (no floats), refuses to add across currencies (multi-currency carts throw), refuses negative discount/tax/shipping, and refuses discount > subtotal. `format()` composes `Intl.NumberFormat` for locale-correct rendering — zero-decimal currencies like JPY are handled automatically via the ISO 4217 minor-digit count. · *Read-only public catalog API* — `GET /api/catalog/products?status=&limit=&cursor=` returns a paginated product list (cursor is HMAC-tagged via `b.pagination`). `GET /api/catalog/products/:slug` returns one product with its variants + media. Errors surface as RFC 9457 problem documents via `b.problemDetails.respond` (TypeError → 400, missing slug → 404 with a stable `type` URN). Admin writes land later behind `lib/admin.js` (passkey + step-up); until then writes go through the wrangler CLI or direct D1 access. · *`docs/deploy-cloudflare.md`* — Operator-facing deploy recipe: one-time `wrangler` resource setup, secret management (`BLAMEJS_*_PASSPHRASE`, `D1_BRIDGE_SECRET`, `STRIPE_WEBHOOK_SECRET`), container env reference, `wrangler deploy`, verification curl commands, local development (`wrangler dev --remote` + `docker run` for offline smoke), and rollback flow. **Detectors:** *Layer 0 — `non-shop-require`* — `test/layer-0-primitives/codebase-patterns.test.js` adds a detector that refuses any `require()` in `lib/` whose target isn't a relative shop module (`./…` or `../…`). Forces operators to either compose with the blamejs equivalent (`b.crypto.sha3Hash` replaces `node:crypto.createHash`, `b.uuid.v7` replaces `node:crypto.randomUUID`, `b.safeUrl` replaces `node:url`, `b.atomicFile` replaces `node:fs` writes, etc.) or document the unavoidable dependency with a per-line `// allow:non-shop-require — <reason>` marker. Bare package names also surface here, reinforcing the zero-npm-runtime-deps rule. · *Layer 1 — `externaldb-d1` adapter contract* — `test/layer-1-state/externaldb-d1.test.js` covers factory validation, service-binding wire shape, rest-api wire shape, worker-side error envelope mapping, HTTP 5xx retry, HTTP 4xx terminal, transient network error retry, and AbortController-backed timeout surfacing as a `D1_TIMEOUT` typed error. · *Layer 1 — `catalog`* — `test/layer-1-state/catalog.test.js` runs every catalog op (products / variants / prices / inventory / media — create, read, list, update, archive/restore, cascade delete) against an in-memory `node:sqlite` database loaded from the live `0001_catalog.sql` so every CHECK / UNIQUE / FOREIGN KEY in the shipped schema is exercised end-to-end. · *Layer 1 — `cart`* — `test/layer-1-state/cart.test.js` exercises cart lifecycle (create, add/update/remove lines, listLines), price-snapshot fallback, partial-unique active-cart constraint, merge with collision/non-collision lines, customer attachment, post-conversion immutability, and validation error shapes. · *Layer 1 — `pricing`* — `test/layer-1-state/pricing.test.js` exercises `lineTotal`, `subtotal` (multi-currency refusal, empty-cart shape), `totals` (discount/tax/shipping arithmetic, discount-exceeds-subtotal refusal, cart-vs-lines currency mismatch refusal), and `format` against USD, EUR, and JPY (zero-decimal currency). **References:** [Cloudflare Containers](https://developers.cloudflare.com/containers/) · [Cloudflare D1](https://developers.cloudflare.com/d1/) · [blamejs externalDb](https://github.com/blamejs/blamejs/blob/main/lib/external-db.js)
|
|
86
|
+
|
|
87
|
+
- v0.0.1 (2026-05-19) — **Foundation.** Project scaffold for blamejs.shop — vendored blamejs framework + the release pipeline disciplines (structured release-notes generator, smoke-gated CHANGELOG rebuild, SLSA L3 provenance, Sigstore-keyless SBOM signatures, PQC sidecar signing). No feature surface yet; subsequent releases extend by composing the vendored blamejs primitives. **Added:** *Project skeleton* — Initial repository layout: `lib/vendor/` for the vendored blamejs tree, `scripts/` for the release-pipeline helpers (generator, consolidator, sha3-digest, sign-release-artifact, generate-release-signing-key, vendor-update.sh), `test/smoke.js` orchestrator, `test/layer-0-primitives/codebase-patterns.test.js` discipline gate, `release-notes/` JSON source of truth, plus the standard operator-facing artifacts (README, SECURITY, CHANGELOG, LICENSE). · *Vendor toolchain for blamejs* — `scripts/vendor-update.sh blamejs <tag>` shallow-clones the requested release tag from `github.com/blamejs/blamejs` into `lib/vendor/blamejs/` and updates `lib/vendor/MANIFEST.json` with the version + bundled-at date. The script's `--check` mode is wired into the smoke gate so drift between the vendored copy and the latest published blamejs release fails pre-push. · *Release pipeline disciplines* — Carries the same release flow blamejs runs: structured `release-notes/v<X>.json` generator with leak-vocabulary validation, consolidator that rolls non-current minors into `v<minor>.x.json`, `CHANGELOG.md` rebuilt end-to-end from the JSON tree, smoke gates on both `--check` modes so any drift between the JSONs and the markdown fails pre-push. **References:** [blamejs framework](https://github.com/blamejs/blamejs)
|
package/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
|
|
17
|
+
See http://www.apache.org/licenses/LICENSE-2.0 for the full license text.
|
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# blamejs.shop
|
|
2
|
+
|
|
3
|
+
Open-source framework built on [blamejs](https://github.com/blamejs/blamejs). Vendored stack, zero npm runtime deps, PQC-first crypto, security-on by default.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js LTS (>= 24.14.1)
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
git clone https://github.com/blamejs/blamejs.shop.git
|
|
13
|
+
cd blamejs.shop
|
|
14
|
+
bash scripts/vendor-update.sh blamejs latest
|
|
15
|
+
node test/smoke.js
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## What ships
|
|
19
|
+
|
|
20
|
+
### Platform
|
|
21
|
+
|
|
22
|
+
- **Cloudflare deploy topology** — `Dockerfile` (multi-stage Node LTS, non-root, tini PID 1, vendor refresh + smoke run as build stages), `wrangler.toml` (Container + Worker + D1 + R2 + KV + Durable Objects), `worker/index.js` (edge router: health, asset pass-through, Stripe webhook signature pre-verification, D1 service-binding bridge, container forward, cold-start retry).
|
|
23
|
+
- **`b.externalDb` adapter for Cloudflare D1** (`lib/externaldb-d1.js`) — service-binding + REST-API modes, normalized result envelope, AbortController timeouts, jittered retry on transient errors.
|
|
24
|
+
- **`InventoryLock` Durable Object** — per-SKU serialization point so concurrent checkouts across container replicas can't oversell.
|
|
25
|
+
- **`docs/deploy-cloudflare.md`** — operator deploy recipe end-to-end.
|
|
26
|
+
|
|
27
|
+
### Commerce primitives
|
|
28
|
+
|
|
29
|
+
Every primitive is composed on the vendored blamejs surface — no npm runtime deps anywhere.
|
|
30
|
+
|
|
31
|
+
| Module | What |
|
|
32
|
+
|---|---|
|
|
33
|
+
| **`lib/catalog.js`** | Products / variants / prices (versioned, multi-currency) / inventory / media. v7 UUID PKs, `b.guardUuid` + `b.guardMime` validation, `b.safeSql` column allowlist, `b.pagination` HMAC-tagged cursors. |
|
|
34
|
+
| **`lib/cart.js`** | Anonymous + authenticated carts. Price snapshot at add-time. Partial-unique active-cart-per-session constraint. `merge(from, to)` on login sums qty on variant collision. |
|
|
35
|
+
| **`lib/pricing.js`** | Pure-function money math — `lineTotal`, `subtotal`, `totals`, `format`. Multi-currency refused, banker's-style rounding, locale-aware via `Intl.NumberFormat`. |
|
|
36
|
+
| **`lib/tax.js`** | Operator-table adapter. Country / state / postal_prefix → rate_bps. Most-specific-first match, banker's rounding. Pluggable adapter shape for future Stripe Tax / TaxJar / Avalara. |
|
|
37
|
+
| **`lib/shipping.js`** | Operator-table adapter. Services with zones (flat or per-gram + base + min/max), free-over-threshold, `digital_only` flag. |
|
|
38
|
+
| **`lib/payment.js`** | Stripe adapter — verify webhook (HMAC-SHA256 via upstream `b.webhook.verify` alg `hmac-sha256-stripe`), create / retrieve / confirm / cancel PaymentIntent, refund. No `stripe` npm dep — outbound through `b.httpClient` (SSRF-gated, retried, circuit-broken). |
|
|
39
|
+
| **`lib/order.js`** | FSM-driven post-checkout record via upstream `b.fsm`. States: pending → paid → fulfilling → shipped → delivered (+ refunded / cancelled). Every transition appends to `order_transitions`. |
|
|
40
|
+
| **`lib/checkout.js`** | Orchestrator. `quote()` returns priced quote; `confirm()` creates PaymentIntent + persists order in pending; `handleStripeEvent()` verifies webhook + fires the FSM transition (idempotent on re-delivery). |
|
|
41
|
+
| **`lib/email.js`** | Transactional templates — order receipt, ship notification, refund confirmation. Strict `{{var}}` renderer with HTML escape + refusal of unknown / unused placeholders. Composed on `b.mail` (DKIM/SPF/DMARC/BIMI upstream). |
|
|
42
|
+
| **`lib/storefront.js`** | Server-rendered HTML — home (product grid), product detail, cart (editable lines), checkout shipping form, Stripe Elements pay page, order confirmation. Default theme uses the `blamejs.shop` brand identity (R2-served logo, `#191919` ink + `#fa4f09` accent palette, Montserrat + Inter typography). |
|
|
43
|
+
| **`lib/admin.js`** | Bearer-token-gated CRUD over catalog + orders + refunds + bulk CSV import. Token compared via `b.crypto.timingSafeEqual`. Errors as RFC 9457 problem documents via `b.problemDetails`. Audit emission on every mutation. |
|
|
44
|
+
| **`lib/catalog-import.js`** | Bulk CSV import — `POST /admin/catalog/import` accepts a `text/csv` body, parses via `b.csv`, content-safety-filters every cell through `b.guardCsv` (formula-injection / bidi / control / dangerous-function denylist), validates exact header order, de-dupes rows by `product_slug`, returns per-row errors without aborting. Default 1 MiB / 10000 rows caps. |
|
|
45
|
+
|
|
46
|
+
### Migrations applied to D1
|
|
47
|
+
|
|
48
|
+
- `migrations-d1/0001_catalog.sql` — products, variants, prices, inventory, media
|
|
49
|
+
- `migrations-d1/0002_cart.sql` — carts, cart_lines (partial-unique active-cart-per-session)
|
|
50
|
+
- `migrations-d1/0003_order.sql` — orders, order_lines, order_transitions (FSM audit log)
|
|
51
|
+
|
|
52
|
+
### Tests
|
|
53
|
+
|
|
54
|
+
14 layer-1 test suites all running against in-memory `node:sqlite` loaded from the live migrations. Schema CHECK / UNIQUE / FK constraints exercised end-to-end.
|
|
55
|
+
|
|
56
|
+
## Operator quick-start
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
# 1. Provision CF resources
|
|
60
|
+
npx wrangler login
|
|
61
|
+
npx wrangler d1 create blamejs-shop
|
|
62
|
+
npx wrangler r2 bucket create blamejs-shop-assets
|
|
63
|
+
npx wrangler kv namespace create SESSIONS
|
|
64
|
+
# (paste returned ids into wrangler.toml)
|
|
65
|
+
|
|
66
|
+
# 2. Set secrets
|
|
67
|
+
node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('base64url'))" \
|
|
68
|
+
| npx wrangler secret put D1_BRIDGE_SECRET
|
|
69
|
+
# Repeat for: VAULT_PASSPHRASE, AUDIT_PASSPHRASE, AUDIT_SIGNING_PASSPHRASE,
|
|
70
|
+
# BACKUP_PASSPHRASE, KEYCHAIN_PASSPHRASE, ADMIN_API_KEY
|
|
71
|
+
# Stripe (optional — enables checkout):
|
|
72
|
+
# STRIPE_API_KEY (sk_test_… or sk_live_…)
|
|
73
|
+
# STRIPE_WEBHOOK_SECRET (whsec_…)
|
|
74
|
+
# STRIPE_PUBLISHABLE_KEY (pk_test_… or pk_live_…)
|
|
75
|
+
|
|
76
|
+
# 3. Apply database migrations
|
|
77
|
+
npx wrangler d1 migrations apply blamejs-shop --remote
|
|
78
|
+
|
|
79
|
+
# 4. Deploy
|
|
80
|
+
npx wrangler deploy
|
|
81
|
+
|
|
82
|
+
# 5. Seed a product via the admin API
|
|
83
|
+
curl -X POST https://<your-worker>.workers.dev/admin/products \
|
|
84
|
+
-H "Authorization: Bearer $ADMIN_API_KEY" \
|
|
85
|
+
-H "Content-Type: application/json" \
|
|
86
|
+
-d '{"slug":"first","title":"First product","status":"active"}'
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
See [`docs/deploy-cloudflare.md`](docs/deploy-cloudflare.md) for the full deploy recipe.
|
|
90
|
+
|
|
91
|
+
## Vendoring blamejs
|
|
92
|
+
|
|
93
|
+
`blamejs.shop` vendors blamejs as a shallow git clone of the release tag
|
|
94
|
+
into `lib/vendor/blamejs/`. Refresh:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
bash scripts/vendor-update.sh blamejs <tag>
|
|
98
|
+
bash scripts/vendor-update.sh blamejs latest
|
|
99
|
+
bash scripts/vendor-update.sh --check # CI gate: fails on drift
|
|
100
|
+
bash scripts/vendor-update.sh --diff # show changelog vendored vs latest
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The vendored tree is read-only; hand-edits are forbidden. The
|
|
104
|
+
`vendor-hand-edit` codebase-patterns detector blocks deep-imports
|
|
105
|
+
into vendored internals. Need a feature blamejs doesn't ship?
|
|
106
|
+
File the issue upstream OR extend in this repo by composing the
|
|
107
|
+
existing surface.
|
|
108
|
+
|
|
109
|
+
## Security
|
|
110
|
+
|
|
111
|
+
See [`SECURITY.md`](SECURITY.md) for the verification recipe (SLSA L3
|
|
112
|
+
provenance + Sigstore-keyless SBOM signatures + SHA-256 + SHA3-512 +
|
|
113
|
+
ML-DSA-65 release-signing).
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
Apache-2.0 — see [`LICENSE`](LICENSE).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Pre-1.0 — only the latest tagged release is supported. Operators
|
|
6
|
+
upgrade across breaking changes; deprecation warnings ship at least
|
|
7
|
+
one minor before removal.
|
|
8
|
+
|
|
9
|
+
## Reporting
|
|
10
|
+
|
|
11
|
+
Report security issues privately via [GitHub Security Advisories](https://github.com/blamejs/blamejs.shop/security/advisories/new) — do NOT open a public issue for a vulnerability.
|
|
12
|
+
|
|
13
|
+
Acknowledgement within 72 hours; remediation timeline scales with
|
|
14
|
+
severity per the standard CVD playbook (24h critical / 7d high / 30d
|
|
15
|
+
medium / 90d low). CVE assignment via the GHSA flow.
|
|
16
|
+
|
|
17
|
+
## Verifying release authenticity
|
|
18
|
+
|
|
19
|
+
Every release ships with FOUR independent trust roots, each verifiable
|
|
20
|
+
without trusting any of the others:
|
|
21
|
+
|
|
22
|
+
### 1. Signed commit + signed tag
|
|
23
|
+
|
|
24
|
+
Commits and tags are SSH-signed. Verify against the published key:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
curl -fsSL https://github.com/<maintainer>.keys > /tmp/maintainer.keys
|
|
28
|
+
# Write a local `allowed_signers` file binding the key to the
|
|
29
|
+
# maintainer email + `git` namespace, then:
|
|
30
|
+
git tag -v vX.Y.Z
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Expected: `Good "git" signature`. The maintainer SSH-signing-key
|
|
34
|
+
fingerprint is published at the bottom of this file.
|
|
35
|
+
|
|
36
|
+
### 2. SLSA L3 provenance
|
|
37
|
+
|
|
38
|
+
Every GitHub Release ships `<tarball>.intoto.jsonl` produced by
|
|
39
|
+
`slsa-framework/slsa-github-generator` (commit-SHA-pinned). Verify
|
|
40
|
+
the npm tarball against the attestation:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
slsa-verifier verify-artifact <tarball> \
|
|
44
|
+
--provenance-path <tarball>.intoto.jsonl \
|
|
45
|
+
--source-uri github.com/blamejs/blamejs.shop \
|
|
46
|
+
--source-tag vX.Y.Z
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 3. Sigstore-keyless SBOM signatures
|
|
50
|
+
|
|
51
|
+
Both SBOMs (`sbom.cdx.json` + `sbom.vendored.cdx.json`) ship with
|
|
52
|
+
`.sigstore` bundles signed via OIDC + Fulcio + Rekor (no
|
|
53
|
+
long-lived keys). Verify:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
cosign verify-blob sbom.cdx.json \
|
|
57
|
+
--bundle sbom.cdx.json.sigstore \
|
|
58
|
+
--certificate-identity-regexp 'https://github.com/blamejs/blamejs\.shop/' \
|
|
59
|
+
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 4. Byte digests + ML-DSA-65 signature (PQC-first)
|
|
63
|
+
|
|
64
|
+
The release tarball ships with three digest / signature sidecars
|
|
65
|
+
covering its exact bytes:
|
|
66
|
+
|
|
67
|
+
- `<tarball>.sha256` — conventional checksum (`sha256sum -c`)
|
|
68
|
+
- `<tarball>.sha3-512` — SHA3-512 digest (`openssl dgst -sha3-512`)
|
|
69
|
+
- `<tarball>.mldsa.sig` — ML-DSA-65 signature (FIPS 204) over the
|
|
70
|
+
tarball bytes, verifiable with the vendored noble-post-quantum
|
|
71
|
+
primitive
|
|
72
|
+
|
|
73
|
+
The ML-DSA-65 public key is committed at `keys/release-pqc-pub.json`.
|
|
74
|
+
Its SHA3-512 fingerprint is published below (this file is itself
|
|
75
|
+
commit-signed, so the fingerprint is verifiable out-of-band against
|
|
76
|
+
the signed git history).
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
# Verify the PQC sig sidecar (no Sigstore dependency)
|
|
80
|
+
node -e "
|
|
81
|
+
var b = require('./lib/vendor/blamejs');
|
|
82
|
+
var fs = require('node:fs');
|
|
83
|
+
var pub = JSON.parse(fs.readFileSync('keys/release-pqc-pub.json', 'utf8')).publicKey;
|
|
84
|
+
var sig = fs.readFileSync(process.argv[1]);
|
|
85
|
+
var msg = fs.readFileSync(process.argv[2]);
|
|
86
|
+
var pubBytes = Buffer.from(pub, 'base64url');
|
|
87
|
+
if (!b.pqcSoftware.ml_dsa_65.verify(sig, msg, pubBytes)) process.exit(1);
|
|
88
|
+
" <tarball>.mldsa.sig <tarball>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Public keys + fingerprints
|
|
92
|
+
|
|
93
|
+
| Purpose | Algorithm | Fingerprint |
|
|
94
|
+
|-----------------------------------|------------|---------------------------|
|
|
95
|
+
| Maintainer commit/tag signing key | SSH-ED25519 | *(populate on first signed tag — see below)* |
|
|
96
|
+
| Release-signing public key | ML-DSA-65 (FIPS 204) | `0d9d241e23c333201911afd6d6d0b0ba9a2feb4f60bf5fdd976bb33e0678f7ff0ec3db816c3cb2d9caf50c681caf8b04939ffe8cf4652eae9e6c90c988bfb87e` (SHA3-512 of `keys/release-pqc-pub.json#publicKey`) |
|
|
97
|
+
|
|
98
|
+
To populate the maintainer SSH fingerprint:
|
|
99
|
+
```
|
|
100
|
+
ssh-keygen -lf <(curl -fsSL https://github.com/<maintainer>.keys)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
To populate the ML-DSA-65 fingerprint:
|
|
104
|
+
```
|
|
105
|
+
node -e "
|
|
106
|
+
var b = require('./lib/vendor/blamejs');
|
|
107
|
+
var fs = require('node:fs');
|
|
108
|
+
var pub = JSON.parse(fs.readFileSync('keys/release-pqc-pub.json', 'utf8')).publicKey;
|
|
109
|
+
process.stdout.write(JSON.parse(fs.readFileSync('keys/release-pqc-pub.json', 'utf8')).fingerprint_sha3_512);
|
|
110
|
+
"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Application checklist
|
|
114
|
+
|
|
115
|
+
- **D1 bridge secret.** When deploying on Cloudflare, the container
|
|
116
|
+
reaches D1 through a Worker service binding. The bridge is gated by
|
|
117
|
+
a shared-secret header (`X-D1-Bridge-Secret`) so the route only
|
|
118
|
+
accepts SQL from the bound container even if the binding is
|
|
119
|
+
accidentally exposed. Generate ≥ 32 bytes of OS randomness and set
|
|
120
|
+
the value identically on the Worker (`wrangler secret put
|
|
121
|
+
D1_BRIDGE_SECRET`) and the container env. Rotate quarterly or after
|
|
122
|
+
any Worker-credential compromise.
|
|
123
|
+
- **Stripe webhook signature.** Inbound `POST` to
|
|
124
|
+
`/api/webhooks/stripe` is signature-verified at the Worker edge
|
|
125
|
+
(HMAC-SHA256 over `<timestamp>.<body>`, 5-minute tolerance window)
|
|
126
|
+
before forwarding to the container. The container also re-verifies
|
|
127
|
+
defense-in-depth once the payment primitive lands. An unsigned or
|
|
128
|
+
out-of-window delivery never touches origin resources.
|
|
129
|
+
- **Worker → Container trust boundary.** The Worker treats the
|
|
130
|
+
container as untrusted-for-D1: it never proxies arbitrary headers
|
|
131
|
+
into D1, only the explicit `sql` + `params` from the bridge body.
|
|
132
|
+
The container treats the Worker as untrusted-for-customer-data: it
|
|
133
|
+
re-validates every input from forwarded requests against the
|
|
134
|
+
framework's `b.guard*` primitives.
|
|
135
|
+
- **Vault passphrase at boot.** `VAULT_PASSPHRASE` is read from
|
|
136
|
+
`wrangler secret`, never logged, and used once to unseal the
|
|
137
|
+
framework's at-rest key material. Operators MUST rotate the
|
|
138
|
+
passphrase via `b.vault.rotate` after any container image rebuild
|
|
139
|
+
that changed a vendored crypto dependency.
|