rcf-lite 0.21.0 → 0.23.0
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 +36 -0
- package/bin/rcf.js +13 -2
- package/blueprints/application-account-settings/CHANGELOG.md +12 -0
- package/blueprints/application-account-settings/README.md +114 -0
- package/blueprints/application-account-settings/blueprint.json +234 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2601-application-account-settings-capability-vocabulary.json +20 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +20 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2603-application-account-settings-theme-persistence.json +20 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2604-application-account-settings-reauth-window.json +20 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-001.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-002.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-003.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-004.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-005.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-006.json +18 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2601-application-account-settings-shell.json +41 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2602-application-account-settings-capability-discovery.json +28 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2603-application-account-settings-hosted-ui-bridge.json +35 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2604-application-account-settings-session-store.json +40 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25101.json +34 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25102.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25103.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25104.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25105.json +33 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25106.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25107.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25108.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25109.json +33 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25110.json +27 -0
- package/blueprints/application-account-settings/docs/topics.md +50 -0
- package/blueprints/application-account-settings/guide/application-account-settings.md +30 -0
- package/blueprints/application-account-settings/probe-packs/application-account-settings.pack.mjs +246 -0
- package/blueprints/application-admin-console/docs/topics.md +9 -0
- package/blueprints/application-api-rest/docs/topics.md +10 -1
- package/blueprints/application-charts/docs/topics.md +9 -0
- package/blueprints/application-dashboard/docs/topics.md +9 -0
- package/blueprints/application-datatable/docs/topics.md +9 -0
- package/blueprints/application-empty-error-states/CHANGELOG.md +9 -0
- package/blueprints/application-empty-error-states/README.md +88 -0
- package/blueprints/application-empty-error-states/blueprint.json +119 -0
- package/blueprints/application-empty-error-states/contributions/adrs/adr-2301-application-empty-error-states-status-contract.json +25 -0
- package/blueprints/application-empty-error-states/contributions/adrs/adr-2302-application-empty-error-states-stack-trace-visibility.json +25 -0
- package/blueprints/application-empty-error-states/contributions/adrs/adr-2303-application-empty-error-states-offline-strategy.json +25 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-001.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-002.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-003.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-004.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-005.json +18 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2301-application-empty-error-states-state-machine.json +46 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2302-application-empty-error-states-recovery-router.json +36 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2303-application-empty-error-states-offline-buffer.json +40 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22101.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22102.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22103.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22104.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22105.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22106.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22107.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22108.json +29 -0
- package/blueprints/application-empty-error-states/docs/topics.md +55 -0
- package/blueprints/application-empty-error-states/guide/application-empty-error-states.md +50 -0
- package/blueprints/application-empty-error-states/probe-packs/application-empty-error-states.pack.mjs +284 -0
- package/blueprints/application-error-handling/docs/topics.md +9 -0
- package/blueprints/application-file-upload/CHANGELOG.md +9 -0
- package/blueprints/application-file-upload/README.md +85 -0
- package/blueprints/application-file-upload/blueprint.json +114 -0
- package/blueprints/application-file-upload/contributions/adrs/adr-2401-application-file-upload-transport.json +25 -0
- package/blueprints/application-file-upload/contributions/adrs/adr-2402-application-file-upload-accepted-set.json +25 -0
- package/blueprints/application-file-upload/contributions/adrs/adr-2403-application-file-upload-virus-scan.json +25 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +18 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2401-application-file-upload-input.json +46 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2402-application-file-upload-transport.json +47 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2403-application-file-upload-progress-announcer.json +46 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23101.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23102.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23103.json +29 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23104.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23105.json +29 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23106.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23107.json +28 -0
- package/blueprints/application-file-upload/docs/topics.md +60 -0
- package/blueprints/application-file-upload/guide/application-file-upload.md +48 -0
- package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +238 -0
- package/blueprints/application-forms-wizard/CHANGELOG.md +9 -0
- package/blueprints/application-forms-wizard/README.md +102 -0
- package/blueprints/application-forms-wizard/blueprint.json +120 -0
- package/blueprints/application-forms-wizard/contributions/adrs/adr-2501-application-forms-wizard-navigation.json +25 -0
- package/blueprints/application-forms-wizard/contributions/adrs/adr-2502-application-forms-wizard-save-and-return.json +25 -0
- package/blueprints/application-forms-wizard/contributions/adrs/adr-2503-application-forms-wizard-step-indicator.json +25 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +18 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2501-application-forms-wizard-task-list.json +46 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2502-application-forms-wizard-error-summary.json +40 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2503-application-forms-wizard-draft-store.json +40 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24101.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24102.json +29 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24103.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24104.json +29 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24105.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24106.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24107.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24108.json +29 -0
- package/blueprints/application-forms-wizard/docs/topics.md +51 -0
- package/blueprints/application-forms-wizard/guide/application-forms-wizard.md +48 -0
- package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +233 -0
- package/blueprints/application-notifications-in-app/docs/topics.md +9 -0
- package/blueprints/application-onboarding-tour/CHANGELOG.md +12 -0
- package/blueprints/application-onboarding-tour/README.md +77 -0
- package/blueprints/application-onboarding-tour/blueprint.json +164 -0
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2701-application-onboarding-tour-dismissal-policy.json +20 -0
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2702-application-onboarding-tour-completion-store-shape.json +20 -0
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2703-application-onboarding-tour-checklist-anchor.json +20 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-001.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-002.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-003.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-004.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2701-application-onboarding-tour-step-runner.json +41 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2702-application-onboarding-tour-checklist-slot.json +35 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2703-application-onboarding-tour-completion-store.json +34 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26101.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26102.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26103.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26104.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26105.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26106.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26107.json +27 -0
- package/blueprints/application-onboarding-tour/docs/topics.md +50 -0
- package/blueprints/application-onboarding-tour/guide/application-onboarding-tour.md +59 -0
- package/blueprints/application-onboarding-tour/probe-packs/application-onboarding-tour.pack.mjs +231 -0
- package/blueprints/application-spa/docs/topics.md +11 -2
- package/blueprints/delivery-ci-workflows/docs/topics.md +10 -1
- package/blueprints/deploy-cloudflare-workers/CHANGELOG.md +69 -0
- package/blueprints/deploy-cloudflare-workers/README.md +12 -0
- package/blueprints/deploy-cloudflare-workers/blueprint.json +234 -36
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1306-deploy-cloudflare-workers-spa-shape.json +30 -0
- package/blueprints/deploy-cloudflare-workers/contributions/probes/assets-manifest-scan.mjs +207 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-013.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-014.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12113.json +36 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12114.json +27 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12115.json +27 -0
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +11 -2
- package/blueprints/deploy-cloudflare-workers/guide/deploy-cloudflare-workers.md +25 -0
- package/blueprints/email-smtp-resend/docs/topics.md +10 -1
- package/blueprints/jobs-background/CHANGELOG.md +16 -0
- package/blueprints/jobs-background/README.md +105 -0
- package/blueprints/jobs-background/blueprint.json +149 -0
- package/blueprints/jobs-background/contributions/adrs/adr-3101-jobs-background-model.json +27 -0
- package/blueprints/jobs-background/contributions/adrs/adr-3102-jobs-background-scheduler-mode.json +25 -0
- package/blueprints/jobs-background/contributions/adrs/adr-3103-jobs-background-requires-applied-capabilities.json +25 -0
- package/blueprints/jobs-background/contributions/adrs/adr-3104-jobs-background-timeout-floor.json +25 -0
- package/blueprints/jobs-background/contributions/probes/apply-time-override.mjs +95 -0
- package/blueprints/jobs-background/contributions/probes/apply-time-refusal.mjs +82 -0
- package/blueprints/jobs-background/contributions/probes/event-secrecy.mjs +69 -0
- package/blueprints/jobs-background/contributions/probes/fake-clock-cron.mjs +65 -0
- package/blueprints/jobs-background/contributions/probes/probe-utils.mjs +91 -0
- package/blueprints/jobs-background/contributions/probes/retry-and-fail.mjs +65 -0
- package/blueprints/jobs-background/contributions/probes/run-apply-time-override.mjs +10 -0
- package/blueprints/jobs-background/contributions/probes/run-apply-time-refusal.mjs +11 -0
- package/blueprints/jobs-background/contributions/probes/run-event-secrecy.mjs +11 -0
- package/blueprints/jobs-background/contributions/probes/run-fake-clock-cron.mjs +11 -0
- package/blueprints/jobs-background/contributions/probes/run-retry-and-fail.mjs +11 -0
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-001.json +18 -0
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-002.json +18 -0
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-003.json +18 -0
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-004.json +18 -0
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-005.json +18 -0
- package/blueprints/jobs-background/contributions/requirements/jobs-background-req-006.json +18 -0
- package/blueprints/jobs-background/contributions/tacs/tac-3101-jobs-background-job-definition.json +50 -0
- package/blueprints/jobs-background/contributions/tacs/tac-3102-jobs-background-scheduler.json +50 -0
- package/blueprints/jobs-background/contributions/tacs/tac-3103-jobs-background-run-log.json +49 -0
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30101.json +25 -0
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30102.json +25 -0
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30103.json +25 -0
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30104.json +25 -0
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30105.json +25 -0
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30106.json +25 -0
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30107.json +25 -0
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30108.json +25 -0
- package/blueprints/jobs-background/contributions/user-stories/jobs-background-us-30109.json +25 -0
- package/blueprints/jobs-background/docs/topics.md +62 -0
- package/blueprints/jobs-background/guide/jobs-background.md +147 -0
- package/blueprints/messaging-queue-cloudflare/CHANGELOG.md +15 -0
- package/blueprints/messaging-queue-cloudflare/README.md +125 -0
- package/blueprints/messaging-queue-cloudflare/blueprint.json +67 -0
- package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3001-messaging-queue-cloudflare-adapter.json +30 -0
- package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3002-messaging-queue-cloudflare-delivery-semantics.json +25 -0
- package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3003-messaging-queue-cloudflare-max-attempts-floor.json +25 -0
- package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3004-messaging-queue-cloudflare-batch-defaults.json +25 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/event-secrecy.mjs +137 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/probe-utils.mjs +82 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/producer-facade-ready.mjs +35 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/publish-to-delivery.mjs +94 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/real-account-concurrency-smoke.mjs +54 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/retry-and-dlq.mjs +87 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/run-event-secrecy.mjs +5 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/run-producer-facade-ready.mjs +11 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/run-publish-to-delivery.mjs +5 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/run-real-account-concurrency-smoke.mjs +5 -0
- package/blueprints/messaging-queue-cloudflare/contributions/probes/run-retry-and-dlq.mjs +5 -0
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-001.json +18 -0
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-002.json +18 -0
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-003.json +18 -0
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-004.json +18 -0
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-005.json +18 -0
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-006.json +18 -0
- package/blueprints/messaging-queue-cloudflare/contributions/tacs/tac-3001-messaging-queue-cloudflare-producer-facade.json +56 -0
- package/blueprints/messaging-queue-cloudflare/contributions/tacs/tac-3002-messaging-queue-cloudflare-consumer-registration.json +40 -0
- package/blueprints/messaging-queue-cloudflare/contributions/tacs/tac-3003-messaging-queue-cloudflare-event-sink.json +39 -0
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29101.json +34 -0
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29102.json +34 -0
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29103.json +25 -0
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29104.json +25 -0
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29105.json +25 -0
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29106.json +25 -0
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29107.json +25 -0
- package/blueprints/messaging-queue-cloudflare/contributions/user-stories/messaging-queue-cloudflare-us-29108.json +25 -0
- package/blueprints/messaging-queue-cloudflare/docs/topics.md +62 -0
- package/blueprints/messaging-queue-cloudflare/guide/messaging-queue-cloudflare.md +110 -0
- package/blueprints/object-storage-s3/CHANGELOG.md +13 -0
- package/blueprints/object-storage-s3/README.md +108 -0
- package/blueprints/object-storage-s3/blueprint.json +72 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2901-object-storage-s3-adapter.json +30 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2902-object-storage-s3-presigned-ttl-floor.json +25 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2903-object-storage-s3-multipart-threshold.json +25 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2904-object-storage-s3-contract.json +25 -0
- package/blueprints/object-storage-s3/contributions/probes/event-secrecy.mjs +103 -0
- package/blueprints/object-storage-s3/contributions/probes/facade-round-trip.mjs +43 -0
- package/blueprints/object-storage-s3/contributions/probes/multipart-upload.mjs +84 -0
- package/blueprints/object-storage-s3/contributions/probes/presigned-url.mjs +101 -0
- package/blueprints/object-storage-s3/contributions/probes/probe-utils.mjs +85 -0
- package/blueprints/object-storage-s3/contributions/probes/put-get-round-trip.mjs +84 -0
- package/blueprints/object-storage-s3/contributions/probes/r2-real-account-smoke.mjs +64 -0
- package/blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs +10 -0
- package/blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs +7 -0
- package/blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-001.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-002.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-003.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-004.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-005.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +18 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2901-object-storage-s3-facade.json +57 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2902-object-storage-s3-multipart-uploader.json +36 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2903-object-storage-s3-event-sink.json +36 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28101.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28102.json +43 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28103.json +25 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28104.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28105.json +25 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28106.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28107.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28108.json +34 -0
- package/blueprints/object-storage-s3/docs/topics.md +64 -0
- package/blueprints/object-storage-s3/guide/object-storage-s3.md +207 -0
- package/blueprints/observability-essentials/docs/topics.md +10 -1
- package/blueprints/observability-logging/CHANGELOG.md +4 -0
- package/blueprints/observability-logging/README.md +3 -0
- package/blueprints/observability-logging/blueprint.json +3 -2
- package/blueprints/observability-logging/docs/topics.md +9 -0
- package/blueprints/observability-probe-endpoints/docs/topics.md +10 -1
- package/blueprints/persistence-data-d1/docs/topics.md +10 -1
- package/blueprints/persistence-data-postgres/CHANGELOG.md +12 -0
- package/blueprints/persistence-data-postgres/README.md +101 -0
- package/blueprints/persistence-data-postgres/blueprint.json +80 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +30 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2802-persistence-data-postgres-migration-shape.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2803-persistence-data-postgres-runner-mode.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2804-persistence-data-postgres-recovery.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2805-persistence-data-postgres-connection-pool-posture.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/probes/facade-round-trip.mjs +56 -0
- package/blueprints/persistence-data-postgres/contributions/probes/migration-apply.mjs +75 -0
- package/blueprints/persistence-data-postgres/contributions/probes/pool-posture-smoke.mjs +56 -0
- package/blueprints/persistence-data-postgres/contributions/probes/prepared-statement-scan.mjs +186 -0
- package/blueprints/persistence-data-postgres/contributions/probes/probe-utils.mjs +76 -0
- package/blueprints/persistence-data-postgres/contributions/probes/recovery-restore-round-trip.mjs +173 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-facade-round-trip.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-migration-apply.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-pool-posture-smoke.mjs +9 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-prepared-statement-scan.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-recovery-restore-round-trip.mjs +9 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-transaction-atomicity.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/transaction-atomicity.mjs +79 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-001.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-002.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-004.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-005.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-006.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-007.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2801-persistence-data-postgres-facade.json +58 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2802-persistence-data-postgres-migration-runner.json +40 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2803-persistence-data-postgres-transaction-helper.json +35 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2804-persistence-data-postgres-recovery-runner.json +40 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27101.json +34 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27102.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27103.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27104.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27105.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27106.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27107.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27108.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27109.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27110.json +25 -0
- package/blueprints/persistence-data-postgres/docs/topics.md +66 -0
- package/blueprints/persistence-data-postgres/guide/persistence-data-postgres.md +172 -0
- package/blueprints/persistence-data-sqlite/docs/topics.md +10 -1
- package/blueprints/security-auth-clerk/CHANGELOG.md +4 -0
- package/blueprints/security-auth-clerk/README.md +3 -0
- package/blueprints/security-auth-clerk/blueprint.json +147 -30
- package/blueprints/security-auth-clerk/docs/topics.md +10 -1
- package/blueprints/security-auth-keycloak/CHANGELOG.md +4 -0
- package/blueprints/security-auth-keycloak/README.md +3 -0
- package/blueprints/security-auth-keycloak/blueprint.json +182 -37
- package/blueprints/security-auth-keycloak/docs/topics.md +10 -1
- package/blueprints/security-auth-magic-link/CHANGELOG.md +4 -0
- package/blueprints/security-auth-magic-link/README.md +3 -0
- package/blueprints/security-auth-magic-link/blueprint.json +159 -33
- package/blueprints/security-auth-magic-link/docs/topics.md +10 -1
- package/blueprints/security-auth-oauth2/CHANGELOG.md +4 -0
- package/blueprints/security-auth-oauth2/README.md +3 -0
- package/blueprints/security-auth-oauth2/blueprint.json +158 -32
- package/blueprints/security-auth-oauth2/docs/topics.md +10 -1
- package/blueprints/security-secrets-management/CHANGELOG.md +11 -0
- package/blueprints/security-secrets-management/blueprint.json +2 -1
- package/blueprints/security-secrets-management/docs/topics.md +10 -1
- package/fixtures/canary-manifest.json +9 -9
- package/package.json +1 -1
- package/rcf/code-nodes/cn-134.json +13 -0
- package/rcf/code-nodes/cn-135.json +12 -0
- package/rcf/code-nodes/cn-136.json +13 -0
- package/rcf/code-nodes/cn-137.json +13 -0
- package/rcf/code-nodes/cn-138.json +12 -0
- package/rcf/code-nodes/cn-139.json +12 -0
- package/rcf/code-nodes/cn-140.json +13 -0
- package/rcf/code-nodes/cn-141.json +13 -0
- package/rcf/code-nodes/cn-142.json +12 -0
- package/rcf/code-nodes/cn-143.json +13 -0
- package/rcf/code-nodes/cn-144.json +13 -0
- package/rcf/code-nodes/cn-145.json +12 -0
- package/rcf/code-nodes/cn-146.json +12 -0
- package/rcf/code-nodes/cn-147.json +13 -0
- package/rcf/code-nodes/cn-148.json +13 -0
- package/rcf/code-nodes/cn-149.json +12 -0
- package/rcf/code-nodes/cn-150.json +13 -0
- package/rcf/code-nodes/cn-151.json +13 -0
- package/rcf/code-nodes/cn-152.json +12 -0
- package/rcf/code-nodes/cn-153.json +12 -0
- package/rcf/code-nodes/cn-154.json +13 -0
- package/rcf/code-nodes/cn-155.json +14 -0
- package/rcf/code-nodes/cn-156.json +13 -0
- package/rcf/code-nodes/cn-157.json +13 -0
- package/rcf/code-nodes/cn-158.json +12 -0
- package/rcf/code-nodes/cn-159.json +13 -0
- package/rcf/code-nodes/cn-160.json +12 -0
- package/rcf/code-nodes/cn-161.json +12 -0
- package/rcf/code-nodes/cn-162.json +13 -0
- package/rcf/code-nodes/cn-163.json +12 -0
- package/rcf/code-nodes/cn-164.json +13 -0
- package/rcf/code-nodes/cn-165.json +12 -0
- package/rcf/code-nodes/cn-166.json +12 -0
- package/rcf/code-nodes/cn-167.json +12 -0
- package/rcf/code-nodes/cn-168.json +12 -0
- package/rcf/code-nodes/cn-169.json +12 -0
- package/rcf/code-nodes/cn-170.json +12 -0
- package/rcf/code-nodes/cn-171.json +12 -0
- package/rcf/code-nodes/cn-172.json +12 -0
- package/rcf/code-nodes/cn-173.json +12 -0
- package/rcf/code-nodes/cn-174.json +12 -0
- package/rcf/code-nodes/cn-175.json +13 -0
- package/rcf/code-nodes/cn-176.json +12 -0
- package/rcf/code-nodes/cn-177.json +12 -0
- package/rcf/code-nodes/cn-178.json +12 -0
- package/rcf/code-nodes/cn-179.json +12 -0
- package/rcf/code-nodes/cn-180.json +13 -0
- package/rcf/code-nodes/cn-181.json +12 -0
- package/rcf/code-nodes/cn-182.json +13 -0
- package/rcf/code-nodes/cn-183.json +12 -0
- package/rcf/code-nodes/cn-184.json +13 -0
- package/rcf/code-nodes/cn-185.json +12 -0
- package/rcf/code-nodes/cn-186.json +12 -0
- package/rcf/code-nodes/cn-200.json +14 -0
- package/rcf/code-nodes/cn-201.json +13 -0
- package/rcf/code-nodes/cn-202.json +14 -0
- package/rcf/code-nodes/cn-203.json +14 -0
- package/rcf/code-nodes/cn-204.json +13 -0
- package/rcf/code-nodes/cn-205.json +14 -0
- package/rcf/code-nodes/cn-206.json +14 -0
- package/rcf/code-nodes/cn-207.json +13 -0
- package/rcf/code-nodes/cn-208.json +14 -0
- package/rcf/code-nodes/cn-209.json +14 -0
- package/rcf/code-nodes/cn-210.json +13 -0
- package/rcf/code-nodes/cn-211.json +12 -0
- package/rcf/code-nodes/cn-212.json +12 -0
- package/rcf/code-nodes/cn-213.json +12 -0
- package/rcf/code-nodes/cn-214.json +15 -0
- package/rcf/code-nodes/cn-215.json +13 -0
- package/rcf/code-nodes/cn-216.json +14 -0
- package/rcf/code-nodes/cn-217.json +13 -0
- package/rcf/fbs/fbs-043.json +23 -0
- package/rcf/fbs/fbs-044.json +23 -0
- package/rcf/fbs/fbs-045.json +23 -0
- package/rcf/fbs/fbs-046.json +24 -0
- package/rcf/fbs/fbs-047.json +24 -0
- package/rcf/fbs/fbs-060.json +22 -0
- package/rcf/fbs/fbs-061.json +20 -0
- package/rcf/fbs/fbs-062.json +20 -0
- package/rcf/fbs/fbs-063.json +22 -0
- package/rcf/fbs/fbs-064.json +23 -0
- package/rcf/requirements/req-024.json +69 -0
- package/rcf/requirements/req-025.json +59 -0
- package/rcf/requirements/req-026.json +154 -0
- package/rcf/requirements/req-027.json +33 -0
- package/rcf/requirements/req-028.json +13 -0
- package/rcf/requirements/req-029.json +57 -0
- package/rcf/requirements/req-030.json +67 -0
- package/rcf/requirements/req-040.json +13 -0
- package/rcf/requirements/req-041.json +125 -0
- package/rcf/requirements/req-042.json +59 -0
- package/rcf/requirements/req-043.json +39 -0
- package/rcf/test-suites/ts-053.json +70 -0
- package/rcf/test-suites/ts-054.json +70 -0
- package/rcf/test-suites/ts-055.json +77 -0
- package/rcf/test-suites/ts-056.json +78 -0
- package/rcf/test-suites/ts-057.json +78 -0
- package/rcf/test-suites/ts-070.json +62 -0
- package/rcf/test-suites/ts-071.json +62 -0
- package/rcf/test-suites/ts-072.json +62 -0
- package/rcf/test-suites/ts-073.json +38 -0
- package/rcf/test-suites/ts-074.json +30 -0
- package/rcf/test-suites/ts-075.json +38 -0
- package/rcf/test-suites/ts-076.json +70 -0
- package/rcf/user-stories/us-2401.json +62 -0
- package/rcf/user-stories/us-2501.json +58 -0
- package/rcf/user-stories/us-2601.json +51 -0
- package/rcf/user-stories/us-2701.json +55 -0
- package/rcf/user-stories/us-2801.json +55 -0
- package/rcf/user-stories/us-2901.json +45 -0
- package/rcf/user-stories/us-2902.json +36 -0
- package/rcf/user-stories/us-3001.json +45 -0
- package/rcf/user-stories/us-4001.json +69 -0
- package/rcf/user-stories/us-4101.json +69 -0
- package/rcf/user-stories/us-4201.json +69 -0
- package/rcf/user-stories/us-4301.json +78 -0
- package/releases/releases.yaml +21 -1
- package/src/blueprint/apply.js +13 -1
- package/src/blueprint/capabilities.js +66 -2
- package/src/cli/blueprint.js +15 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "messaging-queue-cloudflare-US-29103",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "messaging-queue-cloudflare-REQ-003",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Consumer returning retry re-delivers the same message-id with an incremented attempt counter",
|
|
8
|
+
"asA": "developer whose consumer needs to handle transient failures without human intervention",
|
|
9
|
+
"iWant": "a consumer that returns retry to observe the same message-id on the next delivery with an incremented attempt counter",
|
|
10
|
+
"soThat": "policy decisions like log at attempt 2, alert at attempt N-1 are trivially expressed in code",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-29103-1",
|
|
14
|
+
"description": "Given the SIMULATE_CONSUMER_RETRY=true induced-failure switch on the fixture, when the consumer returns retry on the first delivery, then the second delivery observes the same stable message-id with attempts incremented to 2; the same holds on the third delivery with attempts 3. The retry-and-dlq probe records the full trajectory 1 to 3 attempts on the same message-id.",
|
|
15
|
+
"given": "a message published with the SIMULATE_CONSUMER_RETRY switch true on the fixture",
|
|
16
|
+
"when": "the consumer is invoked across successive deliveries",
|
|
17
|
+
"then": "the message-id is stable across attempts 1 to 3; the attempt counter increments on each delivery; body, headers and producer-supplied trace-id remain byte-equal across attempts",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": ["TAC-3002-messaging-queue-cloudflare-consumer-registration"],
|
|
23
|
+
"createdAt": "2026-09-06T21:00:00.000Z",
|
|
24
|
+
"updatedAt": "2026-09-06T21:00:00.000Z"
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "messaging-queue-cloudflare-US-29104",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "messaging-queue-cloudflare-REQ-004",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "After max-attempts the message lands on the DLQ with messageDeadLettered and the DLQ contents match",
|
|
8
|
+
"asA": "developer whose consumer needs a receipt for permanent failures without blocking the queue",
|
|
9
|
+
"iWant": "a message that fails past max-attempts to land on the configured DLQ with a lifecycle event and inspectable DLQ contents",
|
|
10
|
+
"soThat": "operational triage of a bad message is a matter of reading the DLQ, not of grepping application logs",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-29104-1",
|
|
14
|
+
"description": "Given a message that returns retry across max_retries deliveries (default 3), when the third delivery returns retry, then a messageDeadLettered event fires on the sink with the stable message-id, the queue name, and attempts equal to the terminal attempt count. The message is present on the DLQ; inspecting the DLQ through the fixture DLQ-inspector helper returns the body byte-equal to the original publish.",
|
|
15
|
+
"given": "the fixture with max_retries 3 and SIMULATE_CONSUMER_RETRY=true published once",
|
|
16
|
+
"when": "the delivery loop runs to exhaustion",
|
|
17
|
+
"then": "the retry-and-dlq probe records attempts 1, 2, 3 with the same message-id; messageDeadLettered fires with attempts equal to the terminal count; the DLQ-inspector reads the message body back byte-equal",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": ["TAC-3002-messaging-queue-cloudflare-consumer-registration", "TAC-3003-messaging-queue-cloudflare-event-sink"],
|
|
23
|
+
"createdAt": "2026-09-06T21:00:00.000Z",
|
|
24
|
+
"updatedAt": "2026-09-06T21:00:00.000Z"
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "messaging-queue-cloudflare-US-29105",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "messaging-queue-cloudflare-REQ-005",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Batch consume bounded by Cloudflare limits with per-message ack semantics",
|
|
8
|
+
"asA": "developer publishing bursty traffic",
|
|
9
|
+
"iWant": "the consumer to process a batch of messages in one Worker invocation with the elicited batch size and batch timeout, acking each message individually",
|
|
10
|
+
"soThat": "one bad message in a batch does not roll back the twenty good ones behind it",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-29105-1",
|
|
14
|
+
"description": "Given the fixture consumer configured with max_batch_size 10 and max_batch_timeout 5, when 5 messages are published in rapid succession, then the consumer receives them in one batched invocation and acknowledges each per message; every message is delivered exactly to the count published (barring redeliveries the AC does not test); no batch-level rollback fires on a per-message retry.",
|
|
15
|
+
"given": "the fixture consumer with the elicited batch settings",
|
|
16
|
+
"when": "the publish-to-delivery probe publishes 5 messages",
|
|
17
|
+
"then": "the consumer receives them in one batch; per-message ack fires 5 times; the messageAcked events on the sink number 5",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": ["TAC-3002-messaging-queue-cloudflare-consumer-registration"],
|
|
23
|
+
"createdAt": "2026-09-06T21:00:00.000Z",
|
|
24
|
+
"updatedAt": "2026-09-06T21:00:00.000Z"
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "messaging-queue-cloudflare-US-29106",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "messaging-queue-cloudflare-REQ-006",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Every lifecycle event carries a metadata-only whitelist with no body bytes, no header values and no consumer context",
|
|
8
|
+
"asA": "developer whose queue traffic may carry PII bodies",
|
|
9
|
+
"iWant": "the lifecycle event whitelist to be enforced in code so my consumer logging cannot accidentally leak a body byte, a header value, or a consumer-context field",
|
|
10
|
+
"soThat": "the shipped shape composes with a PII-bearing body without redaction gymnastics at every log site",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-29106-1",
|
|
14
|
+
"description": "Given the SIMULATE_PII_IN_BODY=true induced-failure switch driving publish and ack with a PII fixture body (userId 1234, ssn 123-45-6789), when the event-secrecy probe captures the events, then every event record carries exactly the whitelist fields (event, messageId, queueName, attempts, timestamp) and no more; no body bytes, no header value, no userId string, no ssn string, no consumer-context field appears in any record, verified by JSON-stringify substring grep.",
|
|
15
|
+
"given": "the PII fixture body driven through publish, consume and ack",
|
|
16
|
+
"when": "the event-secrecy probe reads the captured event records",
|
|
17
|
+
"then": "every record carries only the whitelist; JSON-stringify substring grep for the fixture PII strings returns no match on any record",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": ["TAC-3003-messaging-queue-cloudflare-event-sink"],
|
|
23
|
+
"createdAt": "2026-09-06T21:00:00.000Z",
|
|
24
|
+
"updatedAt": "2026-09-06T21:00:00.000Z"
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "messaging-queue-cloudflare-US-29107",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "messaging-queue-cloudflare-REQ-002",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Wrangler-dev round-trip: full publish-to-delivery cycle observable under wrangler dev",
|
|
8
|
+
"asA": "developer running the fixture under wrangler dev on my laptop",
|
|
9
|
+
"iWant": "the producer-facade-ready and publish-to-delivery cycles to complete inside the fixture wrangler-dev seam without a real Cloudflare account",
|
|
10
|
+
"soThat": "I can iterate on the facade contract without a live account and CI can gate a change without live-account access",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-29108-1",
|
|
14
|
+
"description": "Given the fixture booted with the in-memory queue-driver mode (the wrangler-dev-equivalent seam the probes drive), when the producer-facade-ready and publish-to-delivery probes run in sequence, then producerReady fires with the queueName, publish delivers all 5 messages to the consumer with body byte-equal, and the per-blueprint reports at .rcf/reports/blueprints/messaging-queue-cloudflare/producer-facade-ready.json and publish-to-delivery.json each carry aggregateVerdict pass.",
|
|
15
|
+
"given": "the fixture with the in-memory queue-driver mode active (SDR-3-a: wrangler-dev-equivalent seam per the local-development doc's stated limitations)",
|
|
16
|
+
"when": "the producer-facade-ready and publish-to-delivery run-shims execute",
|
|
17
|
+
"then": "each shim exits 0; the per-blueprint reports carry aggregateVerdict pass; the event records observed include producerReady with queueName and 5 messageAcked events with matching messageIds",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": ["TAC-3001-messaging-queue-cloudflare-producer-facade", "TAC-3002-messaging-queue-cloudflare-consumer-registration"],
|
|
23
|
+
"createdAt": "2026-09-06T21:00:00.000Z",
|
|
24
|
+
"updatedAt": "2026-09-06T21:00:00.000Z"
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "messaging-queue-cloudflare-US-29108",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "messaging-queue-cloudflare-REQ-002",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Real-account concurrency smoke: 500 messages processed concurrently up to the 250 cap",
|
|
8
|
+
"asA": "developer verifying the facade works against a real Cloudflare account",
|
|
9
|
+
"iWant": "a smoke test that publishes 500 messages against the shared HQ queue rcf-lite-ci-queue-smoke and asserts the consumer processes them concurrently up to the documented 250-invocation cap",
|
|
10
|
+
"soThat": "the shipped shape's compatibility with the real Cloudflare Queues surface is proven end-to-end at least once per release, without requiring every CI run to be account-bound",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-29108-2",
|
|
14
|
+
"description": "Given CI_HAS_CLOUDFLARE_ACCOUNT=1 and the credentials for the shared HQ queue rcf-lite-ci-queue-smoke wired via security-secrets-management, when the real-account-concurrency-smoke probe runs against the real queue, then 500 messages are published, the consumer processes them concurrently up to the 250 push-based invocation cap Cloudflare documents at https://developers.cloudflare.com/queues/platform/limits/, and the smoke drains the queue on exit. Without CI_HAS_CLOUDFLARE_ACCOUNT the probe records accountBoundSkipped true per spec section 3.5 and the per-blueprint report carries aggregateVerdict pass.",
|
|
15
|
+
"given": "the shared HQ queue rcf-lite-ci-queue-smoke on Baz's account, or the env var unset",
|
|
16
|
+
"when": "the real-account-concurrency-smoke run-shim executes",
|
|
17
|
+
"then": "with the env var set, 500 messages round-trip with observed concurrency below or equal to 250; with the env var unset, the report carries accountBoundSkipped true and aggregateVerdict pass; the shim exits 0 in both paths",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": ["TAC-3001-messaging-queue-cloudflare-producer-facade", "TAC-3002-messaging-queue-cloudflare-consumer-registration"],
|
|
23
|
+
"createdAt": "2026-09-06T21:00:00.000Z",
|
|
24
|
+
"updatedAt": "2026-09-06T21:00:00.000Z"
|
|
25
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# messaging-queue-cloudflare blueprint coordination vocabulary
|
|
2
|
+
|
|
3
|
+
This file is the messaging-queue-cloudflare half of the cross-blueprint contract. The Phase 1 conflict detector matches scope:global ADR topics by EXACT string equality, and AC ids are unnamespaced by the 0.4.4 grammar. Any blueprint intended to compose with this one must reuse these exact strings and respect these bands.
|
|
4
|
+
|
|
5
|
+
## Global ADR topics this blueprint contributes (exact strings)
|
|
6
|
+
|
|
7
|
+
| Topic string | messaging-queue-cloudflare contribution | Origin | Composition note |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| `deliverySemantics` | ADR-3002-messaging-queue-cloudflare-delivery-semantics | Minted by this blueprint. Names the wire-shape contract for message-delivery guarantees; the shipped answer is at-least-once (Cloudflare Queues implements at-least-once with a stable message-id the consumer uses for its own dedup per https://developers.cloudflare.com/queues/configuration/javascript-apis/, and WSD-005 makes at-least-once and out-of-order tolerance the shipped default for domain event handoffs). | The one project-wide decision on delivery semantics for the primary worklist queue. A future exactly-once or at-most-once sibling would contribute the same topic string with a different answer, forcing a DELIBERATE conflict the operator resolves with a project-level ADR |
|
|
10
|
+
|
|
11
|
+
The messaging-queue-cloudflare blueprint claims one global topic. Every other contribution is scope-local (ADR-3001 adapter, ADR-3003 max-attempts floor, ADR-3004 batch defaults do not contribute global topics; a composing blueprint that holds an opinion on any of them authors its own project-level ADR).
|
|
12
|
+
|
|
13
|
+
Rules for new topics: lower camel case, one concept per topic, no version suffixes. A topic names the decision area, not the chosen answer.
|
|
14
|
+
|
|
15
|
+
## Id number bands (registry bootstrap)
|
|
16
|
+
|
|
17
|
+
This table is maintained shelf-wide across every blueprint's `docs/topics.md`. Rows are recorded at ship, never predicted.
|
|
18
|
+
|
|
19
|
+
| Blueprint | US band | ADR/TAC suffix block | Status | Global topics |
|
|
20
|
+
|---|---|---|---|---|
|
|
21
|
+
| application-spa | 1101-1899 | 2xx | shipped v1.3.0 | `clientRouting`, `theming`, `clientState`, `errorEnvelope`, `authModel` |
|
|
22
|
+
| application-api-rest | 2101-2899 | 3xx | shipped v1.0.0 | `errorEnvelope`, `authModel`, `apiVersioning`, `logging` |
|
|
23
|
+
| security-auth-magic-link | 3101-3899 | 5xx | shipped v1.0.0 | `authModel` |
|
|
24
|
+
| email-smtp-resend | 4101-4899 | 4xx | shipped v1.0.0 | none |
|
|
25
|
+
| hello-panel (walkthrough exemplar) | 4101-4899 | 4xx | doc-reserved; teaching exemplar in `packages/rcf-lite/docs/blueprint-authoring-walkthrough.md`, not shipped as a blueprint directory | `operatorPanel` |
|
|
26
|
+
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
27
|
+
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
28
|
+
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
29
|
+
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
|
|
30
|
+
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
31
|
+
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
32
|
+
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
33
|
+
| deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.0.0 | `deploymentTarget` |
|
|
34
|
+
| persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
35
|
+
| observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
|
|
36
|
+
| observability-logging | 15101-15899 | 16xx | shipped v1.0.0 | `logging` |
|
|
37
|
+
| application-error-handling | 16101-16899 | 17xx | shipped v1.0.0 | `errorHandling` |
|
|
38
|
+
| application-datatable | 17101-17899 | 18xx | shipped v1.0.0 | none |
|
|
39
|
+
| application-charts | 18101-18899 | 19xx | shipped v1.0.0 | none |
|
|
40
|
+
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
41
|
+
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
42
|
+
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
43
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
44
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
45
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
46
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
47
|
+
| messaging-queue-cloudflare | 29101-29899 | 30xx | shipped v1.0.0 | `deliverySemantics` |
|
|
48
|
+
| jobs-background | 30101-30899 | 31xx | shipped v1.0.0 | `backgroundJobModel` |
|
|
49
|
+
|
|
50
|
+
US 29101-29108 sit at the LOW end of the 29101-29899 band on purpose (watchpost run-4 lesson). A project-side story mechanically derived from a messaging-queue-cloudflare REQ id into the number 29110 would collide against a shipped US-29110; band headroom (29109-29899) leaves that space.
|
|
51
|
+
|
|
52
|
+
ADR/TAC suffixes for this blueprint use the 3001-3099 block, continuing the shelf pattern.
|
|
53
|
+
|
|
54
|
+
## Shared expectations for future composing blueprints
|
|
55
|
+
|
|
56
|
+
- Reuse `deliverySemantics` exactly as spelled here when your blueprint holds an opinion on the delivery-guarantee contract for the primary worklist queue; contribute your own scope:global ADR on that string and let composition surface the pairing.
|
|
57
|
+
- A future exactly-once, at-most-once, or `messaging-queue-postgres` sibling mints on demand; each claims `deliverySemantics` and conflicts by design.
|
|
58
|
+
- `jobs-background` (round-5 track T-4) reads the `queue` capability declared on `blueprint.json` per section 6a of `blueprint-authoring.md` to obtain the producer facade at apply time via the T-5 visual-round capability-declaration mechanism.
|
|
59
|
+
|
|
60
|
+
## Deliberate-conflict statement
|
|
61
|
+
|
|
62
|
+
This blueprint's ADR-3002 on `deliverySemantics` is a first shipped answer to a topic that will conflict, by design, with future exactly-once or at-most-once siblings, and with the reserved `messaging-queue-postgres` sibling (Baz decision 7). Applying `messaging-queue-cloudflare` alongside a hypothetical `messaging-queue-postgres` raises one `globalAdrTopic` conflict the operator resolves via one of the four documented resolutions per topic (adopt one, keep the existing one, author a project-level supersede ADR, or `--resolve <topic>=project:<ADR-id>` on the add).
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# messaging-queue-cloudflare guide
|
|
2
|
+
|
|
3
|
+
## What this blueprint gets you
|
|
4
|
+
|
|
5
|
+
A directed producer-to-consumer worklist queue on Cloudflare Queues: publish, consume, ack, retry, DLQ. The producer facade is the sole reader of the Queues binding declared in your wrangler config (a `[[queues.producers]]` block); the consumer registration attaches to the Worker's `queue` handler through the paired `[[queues.consumers]]` block. Consumer code calls typed named domain verbs on the facade (`publish`, `publishBatch`) and never touches the raw binding. Every publish attaches a producer-supplied trace-id header so downstream consumers stitch the enqueue-to-process boundary; every consumer receipt records `messageAcked` on the sink with the stable platform-assigned message-id.
|
|
6
|
+
|
|
7
|
+
Four lifecycle events fire on the injected event sink with a rigid metadata-only whitelist (`event`, `ts`, `messageId`, `queueName`, `attempts`); consumer logging cannot leak object body bytes, header values, consumer-context fields or PII from the message body. The whitelist is enforced in code by the sink adapter (`event-sink.mjs`), not just documented.
|
|
8
|
+
|
|
9
|
+
The reserved sibling `messaging-queue-postgres` (Baz decision 7, deferred v1.0.0 pending demand) mints on demand and conflicts by design on `deliverySemantics` with this blueprint; the operator picks one queue backend per project via a project-level ADR.
|
|
10
|
+
|
|
11
|
+
## Apply this blueprint
|
|
12
|
+
|
|
13
|
+
`deploy-cloudflare-workers` is the composition target this blueprint expects on a Workers project. The v1.0.0 shipped shape does NOT declare a `requiresAppliedCapabilities` block: the queue binding is wired through wrangler config (not through the capability mechanism), and `jobs-background` composes on the `queue` capability this blueprint provides (per spec section 5.6).
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
rcf define blueprint add messaging-queue-cloudflare
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Exits 0 on any Workers-adjacent project. Contributes ADR-3002 on `scope: global` topic `deliverySemantics` (at-least-once as the shipped shape); a project that already declares a different answer on `deliverySemantics` (an exactly-once or at-most-once sibling minted on demand) surfaces a DELIBERATE conflict for operator resolution.
|
|
20
|
+
|
|
21
|
+
## Producer facade shape
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { createProducer, queueConfigFromEnv } from './producer.mjs';
|
|
25
|
+
|
|
26
|
+
const cfg = queueConfigFromEnv();
|
|
27
|
+
const producer = createProducer({
|
|
28
|
+
binding: env.RCF_TEST_QUEUE, // the wrangler-bound Queues producer
|
|
29
|
+
queueName: cfg.queueName,
|
|
30
|
+
onEvent: (record) => logger.log('messaging-queue', record),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await producer.ready;
|
|
34
|
+
|
|
35
|
+
// publish one message with a producer-supplied trace-id
|
|
36
|
+
const { id } = await producer.publish({ userId: '42', action: 'sendConfirmation' }, {
|
|
37
|
+
headers: { 'x-trace-id': crypto.randomUUID() },
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// publish a batch
|
|
41
|
+
await producer.publishBatch([
|
|
42
|
+
{ body: { seq: 1 }, headers: { 'x-trace-id': 't-1' } },
|
|
43
|
+
{ body: { seq: 2 }, headers: { 'x-trace-id': 't-2' } },
|
|
44
|
+
]);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The facade is the sole holder of the queue binding reference per REQ-001. A call site that reaches into `env.<binding>.send()` directly is refused at author-side review.
|
|
48
|
+
|
|
49
|
+
## Consumer registration shape
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import { createConsumer } from './consumer.mjs';
|
|
53
|
+
|
|
54
|
+
export default {
|
|
55
|
+
queue: createConsumer({
|
|
56
|
+
handler: async (msg) => {
|
|
57
|
+
// msg.id, msg.body, msg.headers, msg.attempts, msg.timestamp
|
|
58
|
+
try {
|
|
59
|
+
await processBackgroundWork(msg.body);
|
|
60
|
+
return 'ack';
|
|
61
|
+
} catch (err) {
|
|
62
|
+
// Return 'retry' to redeliver with an incremented attempt counter;
|
|
63
|
+
// after max_retries the message lands on the DLQ per REQ-004.
|
|
64
|
+
return 'retry';
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
onEvent: (record) => logger.log('messaging-queue', record),
|
|
68
|
+
env: process.env,
|
|
69
|
+
}),
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Wrangler dev section
|
|
74
|
+
|
|
75
|
+
Local iteration on the fixture uses `wrangler dev` (v3.1.0+ per the Cloudflare Queues local-development doc). The wrangler-dev seam brings up producer and consumer in a single command with `--persist-to` for reproducible state:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
cd packages/rcf-lite/test/fixtures/infra-s3-and-queue
|
|
79
|
+
npx wrangler dev --persist-to .wrangler-state
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Consumer concurrency is NOT supported under `wrangler dev` per https://developers.cloudflare.com/queues/configuration/local-development/; the local run proves the facade contract, publish, consume, ack, retry, and DLQ landing, but does not exercise the 250-invocation concurrency cap. That assertion is the accountBound `real-account-concurrency-smoke` probe. Similarly, Cloudflare Queues does not support `wrangler dev --remote` per the same page.
|
|
83
|
+
|
|
84
|
+
The shipped v1.0.0 probes drive the wrangler-dev-equivalent seam (in-memory queue driver realising the same binding shape) so CI stays reproducible without a live Cloudflare account; the boundary at the facade is indistinguishable from a live-Queues run.
|
|
85
|
+
|
|
86
|
+
## Miniflare in CI section
|
|
87
|
+
|
|
88
|
+
Miniflare (`https://developers.cloudflare.com/workers/testing/miniflare/`, fetched 2026-09-06 status 200) documents itself as full-featured and supports KV, Durable Objects, WebSockets, modules, and more, without listing Queues explicitly. The Miniflare Queues sub-page returned 404 during spec ratification, so no citation ships at that URL. In CI, the wrangler-dev-equivalent seam the fixture ships is the reference; a project that needs the full Miniflare surface for a broader integration test wires it separately and defers to the Cloudflare Queues local-development page above for the Queues-specific behaviour.
|
|
89
|
+
|
|
90
|
+
## Real-account smoke section
|
|
91
|
+
|
|
92
|
+
`node ../../../../blueprints/messaging-queue-cloudflare/contributions/probes/run-real-account-concurrency-smoke.mjs` is the accountBound probe. Without `CI_HAS_CLOUDFLARE_ACCOUNT` it exits 0 with `accountBoundSkipped: true` per spec section 3.5 and the per-blueprint report reads `aggregateVerdict: pass`. With `CI_HAS_CLOUDFLARE_ACCOUNT=1` plus credentials for the shared HQ queue `rcf-lite-ci-queue-smoke` (Q2 default) wired via `security-secrets-management`, a live-account run is queued as a v1.0.0 follow-up: the run itself rides `deploy-cloudflare-workers`' surface (not a Node probe module) since Cloudflare Queues does not support `wrangler dev --remote`, and the v1.0.0 probe stops short of driving deployment machinery.
|
|
93
|
+
|
|
94
|
+
## Retry and DLQ discipline
|
|
95
|
+
|
|
96
|
+
ADR-3003 sets `max_retries` to 3 (matching the Cloudflare Queues documented default at https://developers.cloudflare.com/queues/configuration/dead-letter-queues/) with a floor of 1 and a ceiling of 100 (matching the Cloudflare Queues documented per-message max at https://developers.cloudflare.com/queues/platform/limits/). On overflow, the message lands on the elicited DLQ declared via the `dead_letter_queue` field on the wrangler `[[queues.consumers]]` block; the DLQ has its own retention (4 days when no active consumer is attached per the DLQ doc). A DLQ inspector helper (`src/dlq-inspector.mjs` in the fixture; `wrangler queues consumer add --dead-letter-queue` in production per the DLQ doc's CLI form) reads the DLQ contents for triage.
|
|
97
|
+
|
|
98
|
+
## Batch consume discipline
|
|
99
|
+
|
|
100
|
+
ADR-3004 sets `max_batch_size` to 10 (ceiling 100) and `max_batch_timeout` to 5 seconds (ceiling 60 seconds) per the Cloudflare Queues platform limits. Batch settings live on the `[[queues.consumers]]` block in wrangler config; a project running closer to the ceiling changes the config values, not the code. Per-message ack semantics keep one bad message in a batch from rolling back its peers.
|
|
101
|
+
|
|
102
|
+
## Composition with jobs-background
|
|
103
|
+
|
|
104
|
+
`jobs-background` (round-5 track T-4) declares `requiresAppliedCapabilities: ["queue"]`; applying `jobs-background` on a project that already applied `messaging-queue-cloudflare` gets the T-4 apply-time capability check to pass with the `queue` capability discovered on the applied manifest. The T-4 blueprint enqueues jobs through the producer facade this blueprint exposes; the retry-and-DLQ trajectory is what turns transient job failures into eventual success and permanent failures into a DLQ receipt.
|
|
105
|
+
|
|
106
|
+
## What this blueprint does not do
|
|
107
|
+
|
|
108
|
+
- No exactly-once transport (Cloudflare Queues does not implement transport-level dedup); consumer code that needs exactly-once processing dedups on the stable message-id.
|
|
109
|
+
- No fan-out / broadcast pub-sub; that shape lives in the parked `messaging-eventbus` candidate on a different global topic.
|
|
110
|
+
- No schema registry on the message bodies (they are opaque to the blueprint boundary).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# object-storage-s3 changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 - 2026-09-06
|
|
4
|
+
|
|
5
|
+
Initial release. Contract for S3-shape object storage on any S3-compatible endpoint (Cloudflare R2 first, MinIO for local dev, AWS S3, Backblaze B2, Wasabi, self-hosted). Accessed through a store facade that is the sole reader of the S3 client (`@aws-sdk/client-s3` on Node targets or `aws4fetch` on Workers targets). Landed via the infra round 5 spec (ratified 2026-09-06) as track T-2.
|
|
6
|
+
|
|
7
|
+
- 21 contributions: 6 REQs on facade sole-reader / put-get-delete-list / presigned URL / multipart / lifecycle events / credential-pair discipline; 8 USs at 28101-28108; 3 TACs (2901 facade, 2902 multipart uploader, 2903 event sink); 4 ADRs (2901 adapter elicited between AWS SDK and aws4fetch, 2902 presigned TTL default 15 minutes floor 1 minute, 2903 multipart threshold default 8 MiB, 2904 objectStorageContract with scope global).
|
|
8
|
+
- Six Node-only probes under `contributions/probes/` proven against a live MinIO container: `facade-round-trip`, `put-get-round-trip`, `presigned-url`, `multipart-upload`, `event-secrecy`, and the accountBound `r2-real-account-smoke`. The R2 smoke records `accountBoundSkipped: true` when `CI_HAS_CLOUDFLARE_ACCOUNT` is unset per spec section 3.5.
|
|
9
|
+
- T-2 slice of the shared sample-app fixture at `packages/rcf-lite/test/fixtures/infra-s3-and-queue/` boots MinIO via docker compose, exposes the facade over `@aws-sdk/client-s3`, ships a security-secrets-management shim realising the `secretRef` opaque-string contract, and hosts four wired induced-failure switches for the negative-run paths (SIMULATE_MINIO_DOWN, SIMULATE_403_ON_GET, SIMULATE_PART_UPLOAD_FAIL, SIMULATE_PRESIGN_MALFORMED).
|
|
10
|
+
- Declares `capabilities: ["objectStorage"]`, `suggestedCompanions: [{role: "logging"}, {role: "errorHandling"}]`, `providesRoles` absent, `requiresAppliedCapabilities` absent.
|
|
11
|
+
- Contributes ADR-2904 as `scope: global` on new topic `objectStorageContract`. Future non-S3-shape siblings (`object-storage-native-gcs`, `object-storage-native-azure`, reserved slugs) conflict here by design.
|
|
12
|
+
- Refuses composition when `security-secrets-management` v1.0.1+ is not applied. Declares `requiresAppliedCapabilities: {capabilities: ["secretsProvider"], allowSkipFlag: "allow-no-secrets-yet", refusalMessageId: "object-storage-s3-no-secrets"}` per the T-5 capability mechanism. `rcf define blueprint add object-storage-s3` on a bare project exits 3 with `[object-storage-s3-no-secrets]` on stderr, names the shipped predecessor, and points at the override. `--allow-no-secrets-yet` records a `notes` line on `rcf/blueprints/object-storage-s3.applied.json` for later reconciliation. Companion runner extensions (added by this PR to keep the mechanism whole): `src/blueprint/capabilities.js` `buildRefusalMessage` gains a bespoke template branch for `object-storage-s3-no-secrets` (echoes the message id as the first-line tag; other refusalMessageId values also gain a `[<id>]` tag on the first line of the generic fallback for dashboards/lint); `src/cli/blueprint.js` accepts the new `--allow-no-secrets-yet` flag; `src/blueprint/apply.js` sidecar `notes` prose derives predecessor family from the `allowSkipFlag` name (auth vs secrets-management) so the note reads sensibly for either predecessor.
|
|
13
|
+
- Every ADR contribution entry on `blueprint.json` carries a `standardsTraceClause` per section 8a.2 (per HQ mid-flight ruling after PR #154 gate).
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# object-storage-s3
|
|
2
|
+
|
|
3
|
+
Object storage on the S3 API, accessed through a store facade that is the sole reader of the S3 client. Cloudflare R2 is the first adapter, MinIO is the local dev target, any S3-compatible remote (AWS S3, Backblaze B2, Wasabi, self-hosted) composes cleanly. Ships put / get / delete / list, presigned GET URLs with a bounded TTL, and multipart-upload above an elicited threshold, plus a lifecycle-event sink with a metadata-only field discipline. Refuses composition without `security-secrets-management` applied (Baz decision 6): the credential pair is a `secretRef`, never a value.
|
|
4
|
+
|
|
5
|
+
## What this blueprint gives you
|
|
6
|
+
|
|
7
|
+
- **A store facade** (TAC-2901) that is the sole importer of the S3 client (`@aws-sdk/client-s3` on Node targets or `aws4fetch` on Workers targets per ADR-2901) in your source tree, opens the client on boot, and exposes typed named domain verbs. Emits `facadeReady` on the first successful ready-check.
|
|
8
|
+
- **A multipart uploader** (TAC-2902) that the facade delegates to for payloads above the elicited threshold (default 8 MiB per ADR-2903); initiates, part-uploads, completes; aborts in-flight on any part-upload failure so no orphan multipart uploads remain on the bucket.
|
|
9
|
+
- **An event sink** (TAC-2903) with a metadata-only field discipline: `facadeReady`, `objectPut`, `objectDeleted`, `presignedIssued`; no body bytes, no user id, no PII drawn from the object body.
|
|
10
|
+
- **Six Node-only probes** proving every runtime observable: five against a real MinIO container (facade round-trip, put/get, presigned URL, multipart 10 MiB, event secrecy against a PII fixture) plus one accountBound R2 real-account smoke that skips cleanly without `CI_HAS_CLOUDFLARE_ACCOUNT`.
|
|
11
|
+
|
|
12
|
+
## The six REQs
|
|
13
|
+
|
|
14
|
+
| REQ | What it commits |
|
|
15
|
+
|---|---|
|
|
16
|
+
| REQ-001 | Facade module is the sole reader of the S3 client; opens on boot; emits `facadeReady`. |
|
|
17
|
+
| REQ-002 | Put / get / delete / list contract on typed keys with `objectPut` and `objectDeleted` events. |
|
|
18
|
+
| REQ-003 | Presigned GET URL with bounded TTL (floor 1 minute, default 15 minutes per ADR-2902); 200 within TTL, 403 after. |
|
|
19
|
+
| REQ-004 | Multipart-upload above the ADR-2903 threshold (default 8 MiB); abort-on-failure with no orphan in-flight uploads. |
|
|
20
|
+
| REQ-005 | Four lifecycle events with metadata-only fields; event-secrecy probe asserts against a PII fixture. |
|
|
21
|
+
| REQ-006 | Credential-pair discipline via `security-secrets-management`; refuses composition without with stable message id `object-storage-s3-no-secrets`. |
|
|
22
|
+
|
|
23
|
+
## The three TACs
|
|
24
|
+
|
|
25
|
+
- **TAC-2901 facade**: the object-storage S3 facade module.
|
|
26
|
+
- **TAC-2902 multipart uploader**: initiate/part-upload/complete with abort-on-failure.
|
|
27
|
+
- **TAC-2903 event sink**: metadata-only lifecycle event contract.
|
|
28
|
+
|
|
29
|
+
## The four ADRs
|
|
30
|
+
|
|
31
|
+
- **ADR-2901 adapter**: `@aws-sdk/client-s3` on Node targets, `aws4fetch` on Workers targets; elicited, `recommendedDefault: true`. Standards trace clause: AWS S3 API and R2 S3-compatibility notes.
|
|
32
|
+
- **ADR-2902 presigned URL TTL**: default 15 minutes, floor 1 minute; elicited ceiling. Standards trace clause: generic enterprise practice.
|
|
33
|
+
- **ADR-2903 multipart threshold**: default 8 MiB, elicited. Standards trace clause: generic enterprise practice.
|
|
34
|
+
- **ADR-2904 object storage contract** (scope: global, topic `objectStorageContract`): S3 API as the shipped shape; conflicts by design with future non-S3-shape siblings. Standards trace clause: AWS S3 API and R2 S3-compatibility notes.
|
|
35
|
+
|
|
36
|
+
## Elicited parameters
|
|
37
|
+
|
|
38
|
+
Endpoint URL (R2 `https://<account-id>.r2.cloudflarestorage.com`, AWS S3 `https://s3.<region>.amazonaws.com`, MinIO `http://localhost:9000`, any S3-compatible remote); bucket name; credential-pair reference via `security-secrets-management` (never value); adapter (`awsSdk` or `aws4fetch`); presigned-URL default TTL (default 15 minutes); presigned-URL ceiling (elicited, no shipped default, S3 API 7-day outer bound); multipart-upload threshold (default 8 MiB); force path style (`true` for MinIO, `false` for AWS/R2 with virtual-hosted style); server-side encryption default (`sseNone` on R2 per the R2 compatibility notes; `sseS3` on AWS S3 when the operator elicits it).
|
|
39
|
+
|
|
40
|
+
## Companions
|
|
41
|
+
|
|
42
|
+
- **logging**: every lifecycle event (facadeReady, objectPut, objectDeleted, presignedIssued) writes through the applied logger; a logging companion supplies the factory.
|
|
43
|
+
- **errorHandling**: a put failure, a get 404, a presigned-URL malformed request constructs an internal error record; an error-handling companion supplies the record factory and the boundary.
|
|
44
|
+
|
|
45
|
+
## Composition and conflicts
|
|
46
|
+
|
|
47
|
+
Consumes `security-secrets-management` v1.0.1+ for the credential pair. Declares `requiresAppliedCapabilities: {capabilities: ["secretsProvider"], allowSkipFlag: "allow-no-secrets-yet", refusalMessageId: "object-storage-s3-no-secrets"}` per the T-5 capability mechanism (visual round spec 5.5.1). The apply verb refuses on a project without `secretsProvider` (exit 3, stderr carries `[object-storage-s3-no-secrets]` as the first-line tag and names the required capability, the shipped predecessor, and the override flag). `--allow-no-secrets-yet` overrides for a scaffolding pass and records a `notes` line on `rcf/blueprints/object-storage-s3.applied.json` for later reconciliation. Contributes ADR-2904 as `scope: global` on new topic `objectStorageContract`; future `object-storage-native-gcs` or `object-storage-native-azure` siblings would conflict here by design. `capabilities: ["objectStorage"]`; `providesRoles: []`.
|
|
48
|
+
|
|
49
|
+
## The six probes
|
|
50
|
+
|
|
51
|
+
Each probe is a Node module under `contributions/probes/` exporting the round-5 spec section 3.2 verdict envelope, with a matching `run-<probe-name>.mjs` shim that drives the probe against the shared fixture and writes the per-blueprint report at `.rcf/reports/blueprints/object-storage-s3/<probe-name>.json`.
|
|
52
|
+
|
|
53
|
+
| Probe | Anchor AC | What it proves | accountBound |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| `facade-round-trip` | AC-28101-1 | Facade opens against MinIO; `facadeReady` fires with endpointHost and bucketName. | false |
|
|
56
|
+
| `put-get-round-trip` | AC-28102-1, AC-28102-2, AC-28102-3 | 1 KiB round-trip byte-equal; delete and list round-trip; `objectPut` and `objectDeleted` fire. | false |
|
|
57
|
+
| `presigned-url` | AC-28103-1 | Presign at 60 s TTL returns 200 within TTL, 403 on tampered signature (or full TTL wall-clock with `SIMULATE_PRESIGN_EXPIRE=true`); floor refusal at 30 s. | false |
|
|
58
|
+
| `multipart-upload` | AC-28104-1, AC-28104-2 | 10 MiB payload above the 8 MiB threshold round-trips byte-equal via multipart; no orphan in-flight uploads after complete; abort-on-failure with `SIMULATE_PART_UPLOAD_FAIL=true`. | false |
|
|
59
|
+
| `event-secrecy` | AC-28105-1 | Every event record carries only whitelisted metadata fields; no PII fixture text; no forbidden field name. | false |
|
|
60
|
+
| `r2-real-account-smoke` | AC-28108-1 | Real R2 round-trip when `CI_HAS_CLOUDFLARE_ACCOUNT` is set; records `accountBoundSkipped: true` when it is not. | true |
|
|
61
|
+
|
|
62
|
+
## How to run the probes locally
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
cd packages/rcf-lite/test/fixtures/infra-s3-and-queue
|
|
66
|
+
docker compose up -d minio
|
|
67
|
+
sleep 4
|
|
68
|
+
npm install --silent
|
|
69
|
+
node src/create-bucket.mjs
|
|
70
|
+
node ../../../../blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs
|
|
71
|
+
node ../../../../blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs
|
|
72
|
+
node ../../../../blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs
|
|
73
|
+
node ../../../../blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs
|
|
74
|
+
node ../../../../blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs
|
|
75
|
+
node ../../../../blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs
|
|
76
|
+
docker compose down -v
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Each shim exits 0 on aggregate pass and 1 otherwise; every per-blueprint report at `.rcf/reports/blueprints/object-storage-s3/<probe-name>.json` carries `aggregateVerdict pass` on the canonical fixture state. The R2 smoke exits 0 with `accountBoundSkipped: true` when `CI_HAS_CLOUDFLARE_ACCOUNT` is unset.
|
|
80
|
+
|
|
81
|
+
## R2 deviations from full S3
|
|
82
|
+
|
|
83
|
+
Cloudflare R2 is S3-compatible per https://developers.cloudflare.com/r2/api/s3/api/ but explicitly does not implement:
|
|
84
|
+
|
|
85
|
+
- **ACLs**: no per-object or per-bucket ACLs; permissions go through Cloudflare account roles and bucket-level API tokens.
|
|
86
|
+
- **Bucket policies**: no S3-style JSON bucket policies.
|
|
87
|
+
- **Object Lock**: no WORM or retention hold surface.
|
|
88
|
+
- **Versioning**: no object versioning; a put replaces the object.
|
|
89
|
+
- **Lifecycle policies**: R2 marks lifecycle-configuration surface as "feature implementation is currently in progress"; do not depend on time-based expiration or class transitions on R2 at v1.0.0.
|
|
90
|
+
|
|
91
|
+
An operator relying on any of the four either picks a different endpoint (AWS S3 covers all four) or handles the equivalent semantics application-side. The guide's "R2 deviations" section names each and points at the vendor doc.
|
|
92
|
+
|
|
93
|
+
## The multipart re-upload gotcha
|
|
94
|
+
|
|
95
|
+
Per the R2 doc: re-uploading to the same part number replaces the previous part with loss-on-fail semantics. If a re-upload fails, the original part is gone. The facade avoids the case in the shipped path (part uploads are single-attempt; abort-on-failure covers the mid-multipart failure), but a project that layers its own retry on top of the facade's `putObject` should retry the whole put, not a partial multipart.
|
|
96
|
+
|
|
97
|
+
## Known mechanism-reach gaps
|
|
98
|
+
|
|
99
|
+
- **Adapter choice (ADR-2901)** is elicited at apply time; the facade's public surface is adapter-neutral so a consumer cannot tell at import time which adapter was picked. Mitigation: the checklist row on the applied blueprint records the adapter chosen; the shipped Node fixture uses `@aws-sdk/client-s3` for probe verifiability.
|
|
100
|
+
- **Server-side encryption default (elicited)** is set at apply time; the facade does not enforce a shipped default because R2 differs from AWS S3 here (R2: SSE-C only, no AWS KMS; AWS: sseS3 available). Mitigation: the guide's "Encryption at rest" section names the two per-target defaults and the applied ADR records the operator choice.
|
|
101
|
+
- **Multipart part re-upload loss-on-fail** per the R2 doc: the facade avoids the case internally but a consumer-side retry loop can walk into it. Mitigation: the README calls it out; the guide's "Retry semantics" section names the shipped-path guarantees.
|
|
102
|
+
|
|
103
|
+
## Standards trace
|
|
104
|
+
|
|
105
|
+
- Cloudflare R2 S3-compatibility surface: https://developers.cloudflare.com/r2/api/s3/api/ (documents supported ops and the four deviations enumerated above; SSE-C only; auto region only).
|
|
106
|
+
- Cloudflare R2 overview and presigned URLs: https://developers.cloudflare.com/r2/ (S3 API, zero egress fees, presigned URLs).
|
|
107
|
+
- MinIO S3 compatibility for local dev: https://docs.min.io/community/minio-object-store/administration/object-management/object-lifecycle-management.html.
|
|
108
|
+
- GitHub Actions service container shape (for the CI seam): https://docs.github.com/en/actions/using-containerized-services/about-service-containers.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "object-storage-s3",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"category": "object-storage",
|
|
5
|
+
"capabilities": ["objectStorage"],
|
|
6
|
+
"requiresAppliedCapabilities": {
|
|
7
|
+
"capabilities": ["secretsProvider"],
|
|
8
|
+
"allowSkipFlag": "allow-no-secrets-yet",
|
|
9
|
+
"refusalMessageId": "object-storage-s3-no-secrets"
|
|
10
|
+
},
|
|
11
|
+
"suggestedCompanions": [
|
|
12
|
+
{
|
|
13
|
+
"role": "logging",
|
|
14
|
+
"reason": "Every lifecycle event (facadeReady, objectPut, objectDeleted, presignedIssued) writes through the applied logger; a logging companion supplies the factory."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"role": "errorHandling",
|
|
18
|
+
"reason": "A put failure, a get 404, a presigned-URL malformed request constructs an internal error record; an error-handling companion supplies the record factory and the boundary."
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"contributions": [
|
|
22
|
+
{ "id": "object-storage-s3-REQ-001", "kind": "req", "path": "requirements/object-storage-s3-req-001.json" },
|
|
23
|
+
{ "id": "object-storage-s3-REQ-002", "kind": "req", "path": "requirements/object-storage-s3-req-002.json" },
|
|
24
|
+
{ "id": "object-storage-s3-REQ-003", "kind": "req", "path": "requirements/object-storage-s3-req-003.json" },
|
|
25
|
+
{ "id": "object-storage-s3-REQ-004", "kind": "req", "path": "requirements/object-storage-s3-req-004.json" },
|
|
26
|
+
{ "id": "object-storage-s3-REQ-005", "kind": "req", "path": "requirements/object-storage-s3-req-005.json" },
|
|
27
|
+
{ "id": "object-storage-s3-REQ-006", "kind": "req", "path": "requirements/object-storage-s3-req-006.json" },
|
|
28
|
+
{ "id": "object-storage-s3-US-28101", "kind": "us", "path": "user-stories/object-storage-s3-us-28101.json" },
|
|
29
|
+
{ "id": "object-storage-s3-US-28102", "kind": "us", "path": "user-stories/object-storage-s3-us-28102.json" },
|
|
30
|
+
{ "id": "object-storage-s3-US-28103", "kind": "us", "path": "user-stories/object-storage-s3-us-28103.json" },
|
|
31
|
+
{ "id": "object-storage-s3-US-28104", "kind": "us", "path": "user-stories/object-storage-s3-us-28104.json" },
|
|
32
|
+
{ "id": "object-storage-s3-US-28105", "kind": "us", "path": "user-stories/object-storage-s3-us-28105.json" },
|
|
33
|
+
{ "id": "object-storage-s3-US-28106", "kind": "us", "path": "user-stories/object-storage-s3-us-28106.json" },
|
|
34
|
+
{ "id": "object-storage-s3-US-28107", "kind": "us", "path": "user-stories/object-storage-s3-us-28107.json" },
|
|
35
|
+
{ "id": "object-storage-s3-US-28108", "kind": "us", "path": "user-stories/object-storage-s3-us-28108.json" },
|
|
36
|
+
{ "id": "TAC-2901-object-storage-s3-facade", "kind": "tac", "path": "tacs/tac-2901-object-storage-s3-facade.json" },
|
|
37
|
+
{ "id": "TAC-2902-object-storage-s3-multipart-uploader", "kind": "tac", "path": "tacs/tac-2902-object-storage-s3-multipart-uploader.json" },
|
|
38
|
+
{ "id": "TAC-2903-object-storage-s3-event-sink", "kind": "tac", "path": "tacs/tac-2903-object-storage-s3-event-sink.json" },
|
|
39
|
+
{
|
|
40
|
+
"id": "ADR-2901-object-storage-s3-adapter",
|
|
41
|
+
"kind": "adr",
|
|
42
|
+
"path": "adrs/adr-2901-object-storage-s3-adapter.json",
|
|
43
|
+
"recommendedDefault": true,
|
|
44
|
+
"elicited": true,
|
|
45
|
+
"standardsTraceClause": "AWS S3 API and Cloudflare R2 S3-compatibility notes"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "ADR-2902-object-storage-s3-presigned-ttl-floor",
|
|
49
|
+
"kind": "adr",
|
|
50
|
+
"path": "adrs/adr-2902-object-storage-s3-presigned-ttl-floor.json",
|
|
51
|
+
"recommendedDefault": true,
|
|
52
|
+
"elicited": true,
|
|
53
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "ADR-2903-object-storage-s3-multipart-threshold",
|
|
57
|
+
"kind": "adr",
|
|
58
|
+
"path": "adrs/adr-2903-object-storage-s3-multipart-threshold.json",
|
|
59
|
+
"recommendedDefault": true,
|
|
60
|
+
"elicited": true,
|
|
61
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "ADR-2904-object-storage-s3-contract",
|
|
65
|
+
"kind": "adr",
|
|
66
|
+
"path": "adrs/adr-2904-object-storage-s3-contract.json",
|
|
67
|
+
"scope": "global",
|
|
68
|
+
"topic": "objectStorageContract",
|
|
69
|
+
"standardsTraceClause": "AWS S3 API and Cloudflare R2 S3-compatibility notes"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
package/blueprints/object-storage-s3/contributions/adrs/adr-2901-object-storage-s3-adapter.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-2901-object-storage-s3-adapter",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "S3 client adapter: @aws-sdk/client-s3 on Node targets; aws4fetch on Workers targets; elicited",
|
|
8
|
+
"context": "A project deploying object storage on an S3-shape endpoint has two mainstream client choices for the two dominant deploy targets. On Node targets, @aws-sdk/client-s3 (the modular AWS JavaScript SDK v3) is the reference client with a mature multipart transferer, presigned URL helper, and Cloudflare R2 compatibility. On Cloudflare Workers targets, aws4fetch is the lightweight fetch-native client that avoids the AWS SDK's Node polyfills and ships tiny. Both speak the S3 wire protocol; both handle SigV4; both cover the ops the v1.0.0 facade surface needs (PutObject, GetObject, DeleteObject, ListObjectsV2, presigned URL via query-string, CreateMultipartUpload / UploadPart / CompleteMultipartUpload / AbortMultipartUpload). The v1.0.0 facade design has to hold the adapter reference opaque at the facade boundary so the operator picks per deploy target and a future adapter (a GCS shim, an Azure Blob shim under a sibling blueprint) slots in without a facade re-shape.",
|
|
9
|
+
"decision": "The shipped v1.0.0 default on a Node target is @aws-sdk/client-s3 (AWS SDK v3, modular client-s3 package). The shipped v1.0.0 default on a Workers target is aws4fetch. Both are elicited at apply time under the adapter parameter; the operator picks based on the deploy target. Every S3 request goes through the elicited client; the facade module is the sole importer of either package in the source tree per REQ-001. The adapter reference is OPAQUE at this ADR: the facade imports the elicited adapter at the top of the module and any consumer wanting a different adapter (a GCS shim, an Azure Blob shim inside a sibling blueprint that mints on demand) replaces the import here without touching the outward interface.",
|
|
10
|
+
"consequences": "The project inherits the elicited adapter's mature request-signing surface, its presigned-URL helper, and its multipart-upload transferer. Standards trace clause: AWS S3 API (the de facto interop standard, no single normative RFC) and the Cloudflare R2 S3-compatibility notes at https://developers.cloudflare.com/r2/api/s3/api/ enumerating the supported ops (PutObject, GetObject, DeleteObject, ListObjectsV2, HeadObject, HeadBucket, CopyObject, multipart upload, ListMultipartUploads) and the deviations (no ACLs, no bucket policies, no Object Lock, no versioning, no lifecycle policies, SSE-C only). Projects deploying to MinIO for local dev pick the AWS SDK adapter transparently; MinIO covers the S3 surface for the shipped ops per the MinIO S3 compatibility posture at https://docs.min.io/community/minio-object-store/administration/object-management/object-lifecycle-management.html. A future GCS or Azure Blob sibling mints on demand under a different global topic on objectStorageContract (ADR-2904); the operator resolution surfaces as a topic conflict per the round-2 pattern.",
|
|
11
|
+
"alternativesConsidered": [
|
|
12
|
+
{
|
|
13
|
+
"name": "aws-sdk v2 as the shipped Node default",
|
|
14
|
+
"summary": "Ship the monolithic aws-sdk v2 npm package as the Node default.",
|
|
15
|
+
"reasonNotChosen": "aws-sdk v2 is in maintenance mode as of 2024; the modular v3 package @aws-sdk/client-s3 is the recommended surface for new work and ships smaller. Choosing v2 would drag every consumer to a maintenance-mode dependency at v1.0.0."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "aws4fetch as the shipped Node default too",
|
|
19
|
+
"summary": "Ship aws4fetch on both Node and Workers targets to shrink the dependency footprint.",
|
|
20
|
+
"reasonNotChosen": "aws4fetch is fetch-native and Workers-friendly but lacks the presigned-URL helper and the multipart transferer the v1.0.0 REQ-003 and REQ-004 need out of the box; a Node target picking aws4fetch would need consumer-side glue for both, defeating the value of the shipped facade."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "Ship a hand-rolled SigV4 signer with fetch",
|
|
24
|
+
"summary": "Roll our own SigV4 signer as the v1.0.0 default and skip both AWS SDK and aws4fetch.",
|
|
25
|
+
"reasonNotChosen": "SigV4 is well-specified but the surface area (request signing, presigned URL, multipart) exceeds a shelf blueprint's maintenance envelope. Two mature adapters exist; picking one per target and eliciting is the shelf pattern."
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"createdAt": "2026-09-06T18:00:00.000Z",
|
|
29
|
+
"updatedAt": "2026-09-06T18:00:00.000Z"
|
|
30
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-2902-object-storage-s3-presigned-ttl-floor",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "Presigned-URL default TTL 15 minutes, floor 1 minute, ceiling elicited",
|
|
8
|
+
"context": "A presigned URL is the S3-shape mechanism for delegating read access to an object without handing out credentials. The URL carries a bounded TTL after which the storage endpoint refuses the request with 403 (S3 AccessDenied; MinIO returns a 403 XML with AccessDenied code; the R2 shape matches). Too-short a TTL and legitimate readers miss the window; too-long a TTL and a leaked URL becomes a persistent breach. The AWS SDK's default expires-in value is 900 seconds (15 minutes) which most enterprises match; the S3 API caps SigV4 presigned URLs at 604800 seconds (7 days) though few callers reach that ceiling. Local dev with MinIO handles the full range identically.",
|
|
9
|
+
"decision": "The shipped default TTL is 15 minutes (900 seconds). The floor is 1 minute (60 seconds); the facade refuses a presign request below the floor with a value error. The ceiling is elicited at apply time (no shipped default) with the S3 API's own 7-day ceiling as the outer bound; the operator picks a shorter cap when their threat model calls for it. Every presignedIssued event carries the ttl value used so downstream logging can flag long-lived URLs.",
|
|
10
|
+
"consequences": "The default is the AWS SDK's own default; most consumer code needs no override. Standards trace clause: generic enterprise practice (no single normative RFC for presigned URL TTL; the S3 API's 7-day ceiling is the outer bound). The 1-minute floor is a defensive against copy-paste ADRs that drift TTL toward seconds; a legitimate short-TTL use case (a 30-second CDN-signed URL) is handled by a dedicated CDN blueprint, not by object-storage-s3. Operators who want a longer default author a project-level ADR overriding the elicited ceiling; the shipped default stays at 15 minutes.",
|
|
11
|
+
"alternativesConsidered": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Ship a shorter default (5 minutes)",
|
|
14
|
+
"summary": "Ship 5 minutes as the default TTL, matching the tightest common threat model.",
|
|
15
|
+
"reasonNotChosen": "5 minutes trips legitimate browser-side retries and long-form downloads on slow connections; the AWS SDK's own default of 15 minutes has years of production burn-in without visible complaints."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Ship no floor",
|
|
19
|
+
"summary": "Let the operator set any TTL >= 1 second, matching the SDK's own minimum.",
|
|
20
|
+
"reasonNotChosen": "A 1-second TTL is a footgun for the copy-paste ADR class of failure; the 1-minute floor is a small defensive with no measured cost."
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"createdAt": "2026-09-06T18:00:00.000Z",
|
|
24
|
+
"updatedAt": "2026-09-06T18:00:00.000Z"
|
|
25
|
+
}
|