@storyshelf/core 0.6.2 → 0.8.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/README.md +49 -32
- package/dist/adapter/capture-queue.d.mts +44 -4
- package/dist/adapter/capture-runner.d.mts +134 -12
- package/dist/adapter/capture-runner.mjs +9 -12
- package/dist/adapter/database.d.mts +89 -10
- package/dist/adapter/database.mjs +4 -3
- package/dist/adapter/database.mjs.map +1 -1
- package/dist/adapter/design.d.mts +83 -0
- package/dist/adapter/design.mjs +27 -0
- package/dist/adapter/design.mjs.map +1 -0
- package/dist/adapter/email-sender.d.mts +0 -2
- package/dist/adapter/metadata.d.mts +3 -12
- package/dist/adapter/notifier.d.mts +6 -3
- package/dist/adapter/notifier.mjs +5 -1
- package/dist/adapter/oauth.d.mts +50 -0
- package/dist/adapter/setup.d.mts +4 -7
- package/dist/adapter/setup.mjs +3 -3
- package/dist/adapter/setup.mjs.map +1 -1
- package/dist/adapter/storage.d.mts +1 -3
- package/dist/adapter/webhook-events.d.mts +0 -2
- package/dist/adapter/webhook-events.mjs +13 -14
- package/dist/adapter/webhook-events.mjs.map +1 -1
- package/dist/adapters/capture-target-offers.d.mts +26 -0
- package/dist/adapters/capture-target-offers.mjs +57 -0
- package/dist/adapters/capture-target-offers.mjs.map +1 -0
- package/dist/adapters/capture-target.d.mts +69 -0
- package/dist/adapters/capture-target.mjs +75 -0
- package/dist/adapters/capture-target.mjs.map +1 -0
- package/dist/adapters/notifier/build-comment.d.mts +22 -0
- package/dist/adapters/notifier/build-comment.mjs +23 -0
- package/dist/adapters/notifier/build-comment.mjs.map +1 -0
- package/dist/adapters/notifier/build-state.d.mts +97 -0
- package/dist/adapters/notifier/build-state.mjs +217 -0
- package/dist/adapters/notifier/build-state.mjs.map +1 -0
- package/dist/adapters/notifier/events.d.mts +4 -4
- package/dist/adapters/notifier/events.mjs +32 -20
- package/dist/adapters/notifier/events.mjs.map +1 -1
- package/dist/adapters/notifier/format.d.mts +0 -2
- package/dist/adapters/notifier/format.mjs +1 -2
- package/dist/adapters/notifier/provider.d.mts +53 -9
- package/dist/adapters/notifier/provider.mjs +11 -0
- package/dist/adapters/notifier/provider.mjs.map +1 -0
- package/dist/adapters/notifier/state.d.mts +22 -0
- package/dist/adapters/notifier/state.mjs +65 -0
- package/dist/adapters/notifier/state.mjs.map +1 -0
- package/dist/adapters/notifier/types.d.mts +51 -4
- package/dist/adapters/remote-browser.d.mts +168 -0
- package/dist/adapters/remote-browser.mjs +201 -0
- package/dist/adapters/remote-browser.mjs.map +1 -0
- package/dist/adapters/remote-lease-attempt.mjs +39 -0
- package/dist/adapters/remote-lease-attempt.mjs.map +1 -0
- package/dist/adapters/remote-lease-error.d.mts +25 -0
- package/dist/adapters/remote-lease-error.mjs +54 -0
- package/dist/adapters/remote-lease-error.mjs.map +1 -0
- package/dist/adapters/remote-lease-held.d.mts +15 -0
- package/dist/adapters/remote-lease-held.mjs +86 -0
- package/dist/adapters/remote-lease-held.mjs.map +1 -0
- package/dist/adapters/remote-lease-shutdown.d.mts +12 -0
- package/dist/adapters/remote-lease-shutdown.mjs +32 -0
- package/dist/adapters/remote-lease-shutdown.mjs.map +1 -0
- package/dist/adapters/remote-lease.d.mts +39 -0
- package/dist/adapters/remote-lease.mjs +175 -0
- package/dist/adapters/remote-lease.mjs.map +1 -0
- package/dist/adapters/remote-limiter.mjs +121 -0
- package/dist/adapters/remote-limiter.mjs.map +1 -0
- package/dist/adapters/remote-pool.d.mts +56 -0
- package/dist/adapters/remote-pool.mjs +195 -0
- package/dist/adapters/remote-pool.mjs.map +1 -0
- package/dist/adapters/render-runs.d.mts +23 -0
- package/dist/adapters/render-runs.mjs +40 -0
- package/dist/adapters/render-runs.mjs.map +1 -0
- package/dist/adapters/setup-runner.d.mts +0 -2
- package/dist/adapters/setup-runner.mjs +3 -6
- package/dist/adapters/setup-runner.mjs.map +1 -1
- package/dist/adapters/sources.d.mts +10 -0
- package/dist/adapters/sources.mjs +19 -0
- package/dist/adapters/sources.mjs.map +1 -0
- package/dist/adapters/validate.d.mts +0 -2
- package/dist/adapters/validate.mjs +27 -20
- package/dist/adapters/validate.mjs.map +1 -1
- package/dist/ai.d.mts +103 -0
- package/dist/ai.mjs +18 -0
- package/dist/ai.mjs.map +1 -0
- package/dist/auth.d.mts +0 -2
- package/dist/auth.mjs +1 -2
- package/dist/brand-packs.d.mts +0 -2
- package/dist/brand-packs.mjs +0 -1
- package/dist/capture/a11y/axe-source.d.mts +16 -0
- package/dist/capture/a11y/axe-source.mjs +36 -0
- package/dist/capture/a11y/axe-source.mjs.map +1 -0
- package/dist/capture/a11y/in-page.d.mts +25 -0
- package/dist/capture/a11y/in-page.mjs +59 -0
- package/dist/capture/a11y/in-page.mjs.map +1 -0
- package/dist/capture/a11y/map.d.mts +22 -0
- package/dist/capture/a11y/map.mjs +47 -0
- package/dist/capture/a11y/map.mjs.map +1 -0
- package/dist/capture/a11y/options.d.mts +21 -0
- package/dist/capture/a11y/options.mjs +74 -0
- package/dist/capture/a11y/options.mjs.map +1 -0
- package/dist/capture/adapter.d.mts +46 -5
- package/dist/capture/adapter.mjs +1 -2
- package/dist/capture/adapter.mjs.map +1 -1
- package/dist/capture/affected.d.mts +2 -2
- package/dist/capture/affected.mjs +14 -6
- package/dist/capture/affected.mjs.map +1 -1
- package/dist/capture/attempt-logger.mjs +83 -0
- package/dist/capture/attempt-logger.mjs.map +1 -0
- package/dist/capture/browsers.d.mts +33 -0
- package/dist/capture/browsers.mjs +66 -0
- package/dist/capture/browsers.mjs.map +1 -0
- package/dist/capture/build-state/deliver.d.mts +30 -0
- package/dist/capture/build-state/deliver.mjs +117 -0
- package/dist/capture/build-state/deliver.mjs.map +1 -0
- package/dist/capture/build-state/index.d.mts +8 -0
- package/dist/capture/build-state/notify-job.d.mts +54 -0
- package/dist/capture/build-state/notify-job.mjs +132 -0
- package/dist/capture/build-state/notify-job.mjs.map +1 -0
- package/dist/capture/build-state/publisher.d.mts +21 -0
- package/dist/capture/build-state/publisher.mjs +106 -0
- package/dist/capture/build-state/publisher.mjs.map +1 -0
- package/dist/capture/build-state/resume.d.mts +7 -0
- package/dist/capture/build-state/resume.mjs +46 -0
- package/dist/capture/build-state/resume.mjs.map +1 -0
- package/dist/capture/build-state/types.d.mts +47 -0
- package/dist/capture/catalog/catalogue.d.mts +20 -0
- package/dist/capture/catalog/catalogue.mjs +52 -0
- package/dist/capture/catalog/catalogue.mjs.map +1 -0
- package/dist/capture/catalog/components.d.mts +21 -0
- package/dist/capture/catalog/components.mjs +54 -0
- package/dist/capture/catalog/components.mjs.map +1 -0
- package/dist/capture/catalog/history.d.mts +28 -0
- package/dist/capture/catalog/history.mjs +50 -0
- package/dist/capture/catalog/history.mjs.map +1 -0
- package/dist/capture/catalog/hook.d.mts +12 -0
- package/dist/capture/catalog/hook.mjs +18 -0
- package/dist/capture/catalog/hook.mjs.map +1 -0
- package/dist/capture/catalog/index.d.mts +11 -0
- package/dist/capture/catalog/load.d.mts +24 -0
- package/dist/capture/catalog/load.mjs +48 -0
- package/dist/capture/catalog/load.mjs.map +1 -0
- package/dist/capture/catalog/parse.d.mts +13 -0
- package/dist/capture/catalog/parse.mjs +55 -0
- package/dist/capture/catalog/parse.mjs.map +1 -0
- package/dist/capture/catalog/read.d.mts +15 -0
- package/dist/capture/catalog/read.mjs +39 -0
- package/dist/capture/catalog/read.mjs.map +1 -0
- package/dist/capture/catalog/types.d.mts +31 -0
- package/dist/capture/comparison-reference.d.mts +27 -0
- package/dist/capture/comparison-reference.mjs +75 -0
- package/dist/capture/comparison-reference.mjs.map +1 -0
- package/dist/capture/consumer/capture-handler.d.mts +56 -0
- package/dist/capture/consumer/capture-handler.mjs +117 -0
- package/dist/capture/consumer/capture-handler.mjs.map +1 -0
- package/dist/capture/consumer/idle.d.mts +15 -0
- package/dist/capture/consumer/idle.mjs +24 -0
- package/dist/capture/consumer/idle.mjs.map +1 -0
- package/dist/capture/consumer/index.d.mts +11 -0
- package/dist/capture/consumer/index.mjs +138 -0
- package/dist/capture/consumer/index.mjs.map +1 -0
- package/dist/capture/consumer/loop.mjs +109 -0
- package/dist/capture/consumer/loop.mjs.map +1 -0
- package/dist/capture/consumer/metrics.d.mts +39 -0
- package/dist/capture/consumer/metrics.mjs +37 -0
- package/dist/capture/consumer/metrics.mjs.map +1 -0
- package/dist/capture/consumer/retry.d.mts +31 -0
- package/dist/capture/consumer/retry.mjs +33 -0
- package/dist/capture/consumer/retry.mjs.map +1 -0
- package/dist/capture/consumer/run-job.mjs +194 -0
- package/dist/capture/consumer/run-job.mjs.map +1 -0
- package/dist/capture/consumer/startup.mjs +37 -0
- package/dist/capture/consumer/startup.mjs.map +1 -0
- package/dist/capture/consumer/types.d.mts +95 -0
- package/dist/capture/crash-failure.d.mts +23 -0
- package/dist/capture/crash-failure.mjs +69 -0
- package/dist/capture/crash-failure.mjs.map +1 -0
- package/dist/capture/db-queue/cadence.d.mts +30 -0
- package/dist/capture/db-queue/cadence.mjs +37 -0
- package/dist/capture/db-queue/cadence.mjs.map +1 -0
- package/dist/capture/db-queue/claim.d.mts +7 -0
- package/dist/capture/db-queue/claim.mjs +148 -0
- package/dist/capture/db-queue/claim.mjs.map +1 -0
- package/dist/capture/db-queue/clock.mjs +11 -0
- package/dist/capture/db-queue/clock.mjs.map +1 -0
- package/dist/capture/db-queue/codec.mjs +75 -0
- package/dist/capture/db-queue/codec.mjs.map +1 -0
- package/dist/capture/db-queue/index.d.mts +18 -0
- package/dist/capture/db-queue/index.mjs +89 -0
- package/dist/capture/db-queue/index.mjs.map +1 -0
- package/dist/capture/db-queue/keeper.d.mts +34 -0
- package/dist/capture/db-queue/keeper.mjs +91 -0
- package/dist/capture/db-queue/keeper.mjs.map +1 -0
- package/dist/capture/db-queue/lease.mjs +45 -0
- package/dist/capture/db-queue/lease.mjs.map +1 -0
- package/dist/capture/db-queue/lifecycle.mjs +35 -0
- package/dist/capture/db-queue/lifecycle.mjs.map +1 -0
- package/dist/capture/db-queue/operations.mjs +93 -0
- package/dist/capture/db-queue/operations.mjs.map +1 -0
- package/dist/capture/db-queue/poll-loop.d.mts +28 -0
- package/dist/capture/db-queue/poll-loop.mjs +88 -0
- package/dist/capture/db-queue/poll-loop.mjs.map +1 -0
- package/dist/capture/db-queue/poll.d.mts +8 -0
- package/dist/capture/db-queue/poll.mjs +68 -0
- package/dist/capture/db-queue/poll.mjs.map +1 -0
- package/dist/capture/db-queue/timers.d.mts +10 -0
- package/dist/capture/db-queue/timers.mjs +36 -0
- package/dist/capture/db-queue/timers.mjs.map +1 -0
- package/dist/capture/db-queue/types.d.mts +81 -0
- package/dist/capture/db-queue/types.mjs +11 -0
- package/dist/capture/db-queue/types.mjs.map +1 -0
- package/dist/capture/db-queue/wake.mjs +47 -0
- package/dist/capture/db-queue/wake.mjs.map +1 -0
- package/dist/capture/design.mjs +38 -0
- package/dist/capture/design.mjs.map +1 -0
- package/dist/capture/diff-record.mjs +24 -5
- package/dist/capture/diff-record.mjs.map +1 -1
- package/dist/capture/dispatch.d.mts +13 -10
- package/dist/capture/dispatch.mjs +102 -111
- package/dist/capture/dispatch.mjs.map +1 -1
- package/dist/capture/enrich.mjs +59 -0
- package/dist/capture/enrich.mjs.map +1 -0
- package/dist/capture/failure-sets.mjs +21 -0
- package/dist/capture/failure-sets.mjs.map +1 -0
- package/dist/capture/fingerprint.d.mts +40 -0
- package/dist/capture/fingerprint.mjs +82 -0
- package/dist/capture/fingerprint.mjs.map +1 -0
- package/dist/capture/forked/channel.d.mts +23 -0
- package/dist/capture/forked/child.d.mts +32 -0
- package/dist/capture/forked/child.mjs +201 -0
- package/dist/capture/forked/child.mjs.map +1 -0
- package/dist/capture/forked/crash-tracker.mjs +22 -0
- package/dist/capture/forked/crash-tracker.mjs.map +1 -0
- package/dist/capture/forked/decision.d.mts +24 -0
- package/dist/capture/forked/decision.mjs +26 -0
- package/dist/capture/forked/decision.mjs.map +1 -0
- package/dist/capture/forked/exit.mjs +11 -0
- package/dist/capture/forked/exit.mjs.map +1 -0
- package/dist/capture/forked/fork.d.mts +29 -0
- package/dist/capture/forked/fork.mjs +92 -0
- package/dist/capture/forked/fork.mjs.map +1 -0
- package/dist/capture/forked/forked-capture.d.mts +38 -0
- package/dist/capture/forked/forked-capture.mjs +239 -0
- package/dist/capture/forked/forked-capture.mjs.map +1 -0
- package/dist/capture/forked/lease-book.mjs +45 -0
- package/dist/capture/forked/lease-book.mjs.map +1 -0
- package/dist/capture/forked/protocol.d.mts +36 -0
- package/dist/capture/forked/protocol.mjs +24 -0
- package/dist/capture/forked/protocol.mjs.map +1 -0
- package/dist/capture/forked/runs.mjs +74 -0
- package/dist/capture/forked/runs.mjs.map +1 -0
- package/dist/capture/guards.mjs +1 -2
- package/dist/capture/ignore-regions.d.mts +36 -0
- package/dist/capture/ignore-regions.mjs +65 -0
- package/dist/capture/ignore-regions.mjs.map +1 -0
- package/dist/capture/isolate.mjs +140 -0
- package/dist/capture/isolate.mjs.map +1 -0
- package/dist/capture/job-lease.d.mts +26 -0
- package/dist/capture/job-lease.mjs +56 -0
- package/dist/capture/job-lease.mjs.map +1 -0
- package/dist/capture/matrix.mjs +298 -0
- package/dist/capture/matrix.mjs.map +1 -0
- package/dist/capture/modes.d.mts +23 -0
- package/dist/capture/modes.mjs +106 -0
- package/dist/capture/modes.mjs.map +1 -0
- package/dist/capture/orchestrator.d.mts +37 -7
- package/dist/capture/orchestrator.mjs +120 -110
- package/dist/capture/orchestrator.mjs.map +1 -1
- package/dist/capture/pipeline.d.mts +9 -4
- package/dist/capture/pipeline.mjs +284 -48
- package/dist/capture/pipeline.mjs.map +1 -1
- package/dist/capture/progress.d.mts +9 -0
- package/dist/capture/progress.mjs +27 -0
- package/dist/capture/progress.mjs.map +1 -0
- package/dist/capture/publish/accept.d.mts +37 -0
- package/dist/capture/publish/accept.mjs +27 -0
- package/dist/capture/publish/accept.mjs.map +1 -0
- package/dist/capture/publish/complete.d.mts +44 -0
- package/dist/capture/publish/complete.mjs +63 -0
- package/dist/capture/publish/complete.mjs.map +1 -0
- package/dist/capture/publish/extract.d.mts +18 -0
- package/dist/capture/publish/extract.mjs +120 -0
- package/dist/capture/publish/extract.mjs.map +1 -0
- package/dist/capture/publish/handler.d.mts +26 -0
- package/dist/capture/publish/handler.mjs +61 -0
- package/dist/capture/publish/handler.mjs.map +1 -0
- package/dist/capture/publish/index.d.mts +11 -0
- package/dist/capture/publish/invalid-zip.d.mts +8 -0
- package/dist/capture/publish/invalid-zip.mjs +11 -0
- package/dist/capture/publish/invalid-zip.mjs.map +1 -0
- package/dist/capture/publish/limits.d.mts +35 -0
- package/dist/capture/publish/limits.mjs +38 -0
- package/dist/capture/publish/limits.mjs.map +1 -0
- package/dist/capture/publish/published.d.mts +13 -0
- package/dist/capture/publish/published.mjs +17 -0
- package/dist/capture/publish/published.mjs.map +1 -0
- package/dist/capture/publish/run.d.mts +31 -0
- package/dist/capture/publish/run.mjs +29 -0
- package/dist/capture/publish/run.mjs.map +1 -0
- package/dist/capture/rediff.d.mts +1 -3
- package/dist/capture/rediff.mjs +23 -9
- package/dist/capture/rediff.mjs.map +1 -1
- package/dist/capture/render.mjs +52 -0
- package/dist/capture/render.mjs.map +1 -0
- package/dist/capture/scratch.d.mts +42 -0
- package/dist/capture/scratch.mjs +136 -0
- package/dist/capture/scratch.mjs.map +1 -0
- package/dist/capture/shard-plan.mjs +127 -0
- package/dist/capture/shard-plan.mjs.map +1 -0
- package/dist/capture/shards/context.mjs +51 -0
- package/dist/capture/shards/context.mjs.map +1 -0
- package/dist/capture/shards/execute.mjs +175 -0
- package/dist/capture/shards/execute.mjs.map +1 -0
- package/dist/capture/shards/fan-out.mjs +125 -0
- package/dist/capture/shards/fan-out.mjs.map +1 -0
- package/dist/capture/shards/history.mjs +34 -0
- package/dist/capture/shards/history.mjs.map +1 -0
- package/dist/capture/shards/reduce.mjs +96 -0
- package/dist/capture/shards/reduce.mjs.map +1 -0
- package/dist/capture/sizing.d.mts +0 -2
- package/dist/capture/sizing.mjs +2 -13
- package/dist/capture/sizing.mjs.map +1 -1
- package/dist/capture/skip-checks.mjs +3 -67
- package/dist/capture/skip-checks.mjs.map +1 -1
- package/dist/capture/statics.d.mts +7 -10
- package/dist/capture/statics.mjs +26 -74
- package/dist/capture/statics.mjs.map +1 -1
- package/dist/capture/storybook-urls.d.mts +38 -0
- package/dist/capture/storybook-urls.mjs +41 -0
- package/dist/capture/storybook-urls.mjs.map +1 -0
- package/dist/capture/storybook.d.mts +12 -6
- package/dist/capture/storybook.mjs +63 -19
- package/dist/capture/storybook.mjs.map +1 -1
- package/dist/capture/target.mjs +20 -0
- package/dist/capture/target.mjs.map +1 -0
- package/dist/capture/targets.d.mts +23 -0
- package/dist/capture/targets.mjs +31 -0
- package/dist/capture/targets.mjs.map +1 -0
- package/dist/capture/tests.d.mts +35 -0
- package/dist/capture/tests.mjs +136 -0
- package/dist/capture/tests.mjs.map +1 -0
- package/dist/capture/token-chunks.mjs +91 -0
- package/dist/capture/token-chunks.mjs.map +1 -0
- package/dist/capture.d.mts +63 -7
- package/dist/capture.mjs +51 -3
- package/dist/config.d.mts +136 -14
- package/dist/config.mjs +14 -8
- package/dist/config.mjs.map +1 -1
- package/dist/diff.d.mts +7 -3
- package/dist/diff.mjs +15 -3
- package/dist/diff.mjs.map +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/insights/budget.d.mts +18 -0
- package/dist/insights/budget.mjs +32 -0
- package/dist/insights/budget.mjs.map +1 -0
- package/dist/insights/envelope.d.mts +57 -0
- package/dist/insights/envelope.mjs +59 -0
- package/dist/insights/envelope.mjs.map +1 -0
- package/dist/insights/evidence-health.d.mts +30 -0
- package/dist/insights/evidence-health.mjs +27 -0
- package/dist/insights/evidence-health.mjs.map +1 -0
- package/dist/insights/evidence.d.mts +53 -0
- package/dist/insights/evidence.mjs +63 -0
- package/dist/insights/evidence.mjs.map +1 -0
- package/dist/insights/hash.d.mts +16 -0
- package/dist/insights/hash.mjs +20 -0
- package/dist/insights/hash.mjs.map +1 -0
- package/dist/insights/limits.d.mts +22 -0
- package/dist/insights/limits.mjs +23 -0
- package/dist/insights/limits.mjs.map +1 -0
- package/dist/insights/prompts/v1.d.mts +11 -0
- package/dist/insights/prompts/v1.mjs +33 -0
- package/dist/insights/prompts/v1.mjs.map +1 -0
- package/dist/insights/redact.d.mts +7 -0
- package/dist/insights/redact.mjs +23 -0
- package/dist/insights/redact.mjs.map +1 -0
- package/dist/insights/text.mjs +43 -0
- package/dist/insights/text.mjs.map +1 -0
- package/dist/insights.d.mts +11 -0
- package/dist/insights.mjs +12 -0
- package/dist/logger.d.mts +0 -2
- package/dist/logger.mjs +18 -3
- package/dist/logger.mjs.map +1 -1
- package/dist/models/ai-budget-alert.d.mts +21 -0
- package/dist/models/ai-budget-alert.mjs +37 -0
- package/dist/models/ai-budget-alert.mjs.map +1 -0
- package/dist/models/ai-usage.d.mts +38 -0
- package/dist/models/ai-usage.mjs +60 -0
- package/dist/models/ai-usage.mjs.map +1 -0
- package/dist/models/baseline-approval.d.mts +18 -0
- package/dist/models/baseline-approval.mjs +41 -0
- package/dist/models/baseline-approval.mjs.map +1 -0
- package/dist/models/baseline-archive.d.mts +82 -0
- package/dist/models/baseline-archive.mjs +105 -0
- package/dist/models/baseline-archive.mjs.map +1 -0
- package/dist/models/baseline-atomic.mjs +66 -0
- package/dist/models/baseline-atomic.mjs.map +1 -0
- package/dist/models/baseline-conflict.d.mts +6 -0
- package/dist/models/baseline-conflict.mjs +9 -0
- package/dist/models/baseline-conflict.mjs.map +1 -0
- package/dist/models/baseline-export.d.mts +17 -0
- package/dist/models/baseline-export.mjs +135 -0
- package/dist/models/baseline-export.mjs.map +1 -0
- package/dist/models/baseline-import.mjs +117 -0
- package/dist/models/baseline-import.mjs.map +1 -0
- package/dist/models/baseline-origin.d.mts +16 -0
- package/dist/models/baseline-origin.mjs +35 -0
- package/dist/models/baseline-origin.mjs.map +1 -0
- package/dist/models/baseline-status.d.mts +0 -2
- package/dist/models/baseline-status.mjs +1 -2
- package/dist/models/baseline-transfer.d.mts +48 -0
- package/dist/models/baseline-transfer.mjs +149 -0
- package/dist/models/baseline-transfer.mjs.map +1 -0
- package/dist/models/baseline.d.mts +37 -7
- package/dist/models/baseline.mjs +152 -28
- package/dist/models/baseline.mjs.map +1 -1
- package/dist/models/build-component.d.mts +26 -0
- package/dist/models/build-component.mjs +54 -0
- package/dist/models/build-component.mjs.map +1 -0
- package/dist/models/build-review-status.d.mts +27 -0
- package/dist/models/build-review-status.mjs +36 -0
- package/dist/models/build-review-status.mjs.map +1 -0
- package/dist/models/build-review.d.mts +26 -0
- package/dist/models/build-review.mjs +53 -0
- package/dist/models/build-review.mjs.map +1 -0
- package/dist/models/build.d.mts +25 -5
- package/dist/models/build.mjs +53 -15
- package/dist/models/build.mjs.map +1 -1
- package/dist/models/capture-attempt.d.mts +7 -3
- package/dist/models/capture-attempt.mjs +30 -6
- package/dist/models/capture-attempt.mjs.map +1 -1
- package/dist/models/capture-job.d.mts +104 -0
- package/dist/models/capture-job.mjs +287 -0
- package/dist/models/capture-job.mjs.map +1 -0
- package/dist/models/capture-log.d.mts +1 -3
- package/dist/models/capture-log.mjs +5 -5
- package/dist/models/capture-log.mjs.map +1 -1
- package/dist/models/capture-shard.d.mts +60 -0
- package/dist/models/capture-shard.mjs +189 -0
- package/dist/models/capture-shard.mjs.map +1 -0
- package/dist/models/changeset.d.mts +46 -0
- package/dist/models/changeset.mjs +80 -0
- package/dist/models/changeset.mjs.map +1 -0
- package/dist/models/columns.mjs +18 -0
- package/dist/models/columns.mjs.map +1 -0
- package/dist/models/comment.d.mts +4 -3
- package/dist/models/comment.mjs +8 -6
- package/dist/models/comment.mjs.map +1 -1
- package/dist/models/component.d.mts +41 -0
- package/dist/models/component.mjs +59 -0
- package/dist/models/component.mjs.map +1 -0
- package/dist/models/connections.d.mts +39 -0
- package/dist/models/connections.mjs +111 -0
- package/dist/models/connections.mjs.map +1 -0
- package/dist/models/content-ref.d.mts +1 -3
- package/dist/models/content-ref.mjs +2 -3
- package/dist/models/content-ref.mjs.map +1 -1
- package/dist/models/credentials.d.mts +0 -2
- package/dist/models/credentials.mjs +13 -4
- package/dist/models/credentials.mjs.map +1 -1
- package/dist/models/design-credentials.d.mts +39 -0
- package/dist/models/design-credentials.mjs +85 -0
- package/dist/models/design-credentials.mjs.map +1 -0
- package/dist/models/design-health.d.mts +14 -0
- package/dist/models/design-health.mjs +24 -0
- package/dist/models/design-health.mjs.map +1 -0
- package/dist/models/design-nodes.d.mts +81 -0
- package/dist/models/design-nodes.mjs +221 -0
- package/dist/models/design-nodes.mjs.map +1 -0
- package/dist/models/design-renders.mjs +73 -0
- package/dist/models/design-renders.mjs.map +1 -0
- package/dist/models/design-resolve.d.mts +27 -0
- package/dist/models/design-resolve.mjs +40 -0
- package/dist/models/design-resolve.mjs.map +1 -0
- package/dist/models/design.d.mts +37 -0
- package/dist/models/design.mjs +89 -0
- package/dist/models/design.mjs.map +1 -0
- package/dist/models/inherited-ratio.d.mts +19 -0
- package/dist/models/inherited-ratio.mjs +21 -0
- package/dist/models/inherited-ratio.mjs.map +1 -0
- package/dist/models/insight.d.mts +68 -0
- package/dist/models/insight.mjs +161 -0
- package/dist/models/insight.mjs.map +1 -0
- package/dist/models/label.d.mts +4 -4
- package/dist/models/label.mjs +26 -12
- package/dist/models/label.mjs.map +1 -1
- package/dist/models/member.d.mts +1 -3
- package/dist/models/member.mjs +6 -6
- package/dist/models/member.mjs.map +1 -1
- package/dist/models/notification-channel.d.mts +37 -5
- package/dist/models/notification-channel.mjs +89 -11
- package/dist/models/notification-channel.mjs.map +1 -1
- package/dist/models/notification-subscription.d.mts +1 -4
- package/dist/models/notification-subscription.mjs +8 -11
- package/dist/models/notification-subscription.mjs.map +1 -1
- package/dist/models/project-group-mapping.d.mts +6 -3
- package/dist/models/project-group-mapping.mjs +15 -6
- package/dist/models/project-group-mapping.mjs.map +1 -1
- package/dist/models/project.d.mts +9 -3
- package/dist/models/project.mjs +10 -6
- package/dist/models/project.mjs.map +1 -1
- package/dist/models/public-origin.d.mts +61 -0
- package/dist/models/public-origin.mjs +113 -0
- package/dist/models/public-origin.mjs.map +1 -0
- package/dist/models/review-switch-off.d.mts +12 -0
- package/dist/models/review-switch-off.mjs +25 -0
- package/dist/models/review-switch-off.mjs.map +1 -0
- package/dist/models/site-settings.d.mts +21 -0
- package/dist/models/site-settings.mjs +47 -0
- package/dist/models/site-settings.mjs.map +1 -0
- package/dist/models/snapshot.d.mts +39 -3
- package/dist/models/snapshot.mjs +54 -5
- package/dist/models/snapshot.mjs.map +1 -1
- package/dist/models/token.d.mts +13 -3
- package/dist/models/token.mjs +24 -7
- package/dist/models/token.mjs.map +1 -1
- package/dist/models/usage.d.mts +74 -0
- package/dist/models/usage.mjs +148 -0
- package/dist/models/usage.mjs.map +1 -0
- package/dist/models/user.d.mts +1 -3
- package/dist/models/user.mjs +5 -5
- package/dist/models/user.mjs.map +1 -1
- package/dist/models/webhook.d.mts +15 -3
- package/dist/models/webhook.mjs +34 -6
- package/dist/models/webhook.mjs.map +1 -1
- package/dist/models.d.mts +30 -4
- package/dist/models.mjs +31 -6
- package/dist/options.d.mts +16 -0
- package/dist/options.mjs +88 -0
- package/dist/options.mjs.map +1 -0
- package/dist/paths.d.mts +21 -6
- package/dist/paths.mjs +57 -12
- package/dist/paths.mjs.map +1 -1
- package/dist/retention/ai.d.mts +16 -0
- package/dist/retention/ai.mjs +22 -0
- package/dist/retention/ai.mjs.map +1 -0
- package/dist/retention/pending.mjs +46 -0
- package/dist/retention/pending.mjs.map +1 -0
- package/dist/retention/published-gzip-sweep.mjs +28 -0
- package/dist/retention/published-gzip-sweep.mjs.map +1 -0
- package/dist/retention/screenshot-sweep.d.mts +49 -0
- package/dist/retention/screenshot-sweep.mjs +127 -0
- package/dist/retention/screenshot-sweep.mjs.map +1 -0
- package/dist/retention.d.mts +16 -4
- package/dist/retention.mjs +76 -16
- package/dist/retention.mjs.map +1 -1
- package/dist/schema/baseline.d.mts +8 -2
- package/dist/schema/build-component.d.mts +23 -0
- package/dist/schema/build-review.d.mts +15 -0
- package/dist/schema/build.d.mts +7 -2
- package/dist/schema/capture-attempt.d.mts +0 -2
- package/dist/schema/capture-job.d.mts +58 -0
- package/dist/schema/capture-shard.d.mts +33 -0
- package/dist/schema/comment.d.mts +2 -2
- package/dist/schema/connection.d.mts +22 -0
- package/dist/schema/content-ref.d.mts +0 -2
- package/dist/schema/design.d.mts +56 -0
- package/dist/schema/insight.d.mts +52 -0
- package/dist/schema/label.d.mts +0 -2
- package/dist/schema/member.d.mts +0 -2
- package/dist/schema/notification.d.mts +4 -2
- package/dist/schema/project-group-mapping.d.mts +0 -2
- package/dist/schema/project.d.mts +21 -2
- package/dist/schema/site-setting.d.mts +19 -0
- package/dist/schema/snapshot.d.mts +17 -2
- package/dist/schema/token.d.mts +0 -2
- package/dist/schema/usage.d.mts +28 -0
- package/dist/schema/user.d.mts +0 -2
- package/dist/schema/webhook.d.mts +0 -2
- package/dist/schema.d.mts +12 -6
- package/dist/serverless.d.mts +19 -0
- package/dist/serverless.mjs +36 -0
- package/dist/serverless.mjs.map +1 -0
- package/dist/test-helpers/build-reference-contract.d.mts +14 -0
- package/dist/test-helpers/build-reference-contract.mjs +66 -0
- package/dist/test-helpers/build-reference-contract.mjs.map +1 -0
- package/dist/test-helpers/create-project.d.mts +1 -3
- package/dist/test-helpers/create-project.mjs +1 -2
- package/dist/test-helpers/database-contract.d.mts +0 -2
- package/dist/test-helpers/database-contract.mjs +37 -2
- package/dist/test-helpers/database-contract.mjs.map +1 -1
- package/dist/test-helpers/deferred.d.mts +37 -0
- package/dist/test-helpers/deferred.mjs +60 -0
- package/dist/test-helpers/deferred.mjs.map +1 -0
- package/dist/test-helpers/design-contract.d.mts +19 -0
- package/dist/test-helpers/design-contract.mjs +39 -0
- package/dist/test-helpers/design-contract.mjs.map +1 -0
- package/dist/test-helpers/fake-adapters.d.mts +0 -2
- package/dist/test-helpers/fake-adapters.mjs +1 -2
- package/dist/test-helpers/fake-database.d.mts +0 -2
- package/dist/test-helpers/fake-database.mjs +21 -4
- package/dist/test-helpers/fake-database.mjs.map +1 -1
- package/dist/test-helpers/fake-design.d.mts +41 -0
- package/dist/test-helpers/fake-design.mjs +113 -0
- package/dist/test-helpers/fake-design.mjs.map +1 -0
- package/dist/test-helpers/fake-notifier.d.mts +19 -0
- package/dist/test-helpers/fake-notifier.mjs +43 -0
- package/dist/test-helpers/fake-notifier.mjs.map +1 -0
- package/dist/test-helpers/fake-storage.d.mts +0 -2
- package/dist/test-helpers/fake-storage.mjs +1 -2
- package/dist/test-helpers/fake-tables.mjs +260 -69
- package/dist/test-helpers/fake-tables.mjs.map +1 -1
- package/dist/test-helpers/manual-clock.d.mts +25 -0
- package/dist/test-helpers/manual-clock.mjs +55 -0
- package/dist/test-helpers/manual-clock.mjs.map +1 -0
- package/dist/test-helpers/notifier-contract.d.mts +7 -3
- package/dist/test-helpers/notifier-contract.mjs +33 -5
- package/dist/test-helpers/notifier-contract.mjs.map +1 -1
- package/dist/test-helpers/queue-contract.d.mts +16 -4
- package/dist/test-helpers/queue-contract.mjs +196 -3
- package/dist/test-helpers/queue-contract.mjs.map +1 -1
- package/dist/test-helpers/queue-multi-instance.d.mts +18 -0
- package/dist/test-helpers/queue-multi-instance.mjs +205 -0
- package/dist/test-helpers/queue-multi-instance.mjs.map +1 -0
- package/dist/test-helpers/runner-contract.d.mts +0 -2
- package/dist/test-helpers/runner-contract.mjs +12 -2
- package/dist/test-helpers/runner-contract.mjs.map +1 -1
- package/dist/test-helpers/sql-chunks.mjs +25 -2
- package/dist/test-helpers/sql-chunks.mjs.map +1 -1
- package/dist/test-helpers/storage-contract.d.mts +0 -2
- package/dist/test-helpers/storage-contract.mjs +2 -3
- package/dist/test-helpers.d.mts +10 -4
- package/dist/test-helpers.mjs +9 -3
- package/dist/tracing.mjs +36 -6
- package/dist/tracing.mjs.map +1 -1
- package/dist/types.d.mts +14 -5
- package/dist/types.mjs +22 -6
- package/dist/types.mjs.map +1 -1
- package/dist/urls.d.mts +4 -2
- package/dist/urls.mjs +12 -4
- package/dist/urls.mjs.map +1 -1
- package/dist/utils/adaptive-concurrency.d.mts +64 -0
- package/dist/utils/adaptive-concurrency.mjs +148 -0
- package/dist/utils/adaptive-concurrency.mjs.map +1 -0
- package/dist/utils/connect-retry.d.mts +26 -0
- package/dist/utils/connect-retry.mjs +42 -0
- package/dist/utils/connect-retry.mjs.map +1 -0
- package/dist/utils/encrypt.d.mts +0 -2
- package/dist/utils/encrypt.mjs +1 -2
- package/dist/utils/environment.d.mts +17 -0
- package/dist/utils/environment.mjs +58 -0
- package/dist/utils/environment.mjs.map +1 -0
- package/dist/utils/hash.d.mts +0 -2
- package/dist/utils/hash.mjs +1 -2
- package/dist/utils/http.d.mts +29 -3
- package/dist/utils/http.mjs +100 -19
- package/dist/utils/http.mjs.map +1 -1
- package/dist/utils/map-adaptive.d.mts +13 -0
- package/dist/utils/map-adaptive.mjs +71 -0
- package/dist/utils/map-adaptive.mjs.map +1 -0
- package/dist/utils/map-limit.d.mts +8 -0
- package/dist/utils/map-limit.mjs +31 -0
- package/dist/utils/map-limit.mjs.map +1 -0
- package/dist/utils/mime.d.mts +0 -2
- package/dist/utils/mime.mjs +1 -2
- package/dist/utils/page-limiter.d.mts +35 -0
- package/dist/utils/page-limiter.mjs +55 -0
- package/dist/utils/page-limiter.mjs.map +1 -0
- package/dist/utils/path-security.d.mts +0 -2
- package/dist/utils/path-security.mjs +2 -4
- package/dist/utils/path-security.mjs.map +1 -1
- package/dist/utils/public-origin.d.mts +18 -0
- package/dist/utils/public-origin.mjs +74 -0
- package/dist/utils/public-origin.mjs.map +1 -0
- package/dist/utils/redact.d.mts +0 -2
- package/dist/utils/redact.mjs +4 -2
- package/dist/utils/redact.mjs.map +1 -1
- package/dist/utils/remote-environment.d.mts +76 -0
- package/dist/utils/remote-environment.mjs +163 -0
- package/dist/utils/remote-environment.mjs.map +1 -0
- package/dist/utils/resources.d.mts +62 -0
- package/dist/utils/resources.mjs +121 -0
- package/dist/utils/resources.mjs.map +1 -0
- package/dist/utils/screenshot-store.d.mts +13 -0
- package/dist/utils/screenshot-store.mjs +40 -0
- package/dist/utils/screenshot-store.mjs.map +1 -0
- package/dist/utils/session-gate.d.mts +23 -0
- package/dist/utils/session-gate.mjs +69 -0
- package/dist/utils/session-gate.mjs.map +1 -0
- package/dist/utils/storybook-token.d.mts +89 -0
- package/dist/utils/storybook-token.mjs +135 -0
- package/dist/utils/storybook-token.mjs.map +1 -0
- package/dist/utils/storybook-url.d.mts +13 -0
- package/dist/utils/storybook-url.mjs +20 -0
- package/dist/utils/storybook-url.mjs.map +1 -0
- package/dist/utils/timing.d.mts +0 -2
- package/dist/utils/timing.mjs +2 -3
- package/dist/utils/timing.mjs.map +1 -1
- package/dist/utils/ulid.d.mts +0 -2
- package/dist/utils/ulid.mjs +1 -2
- package/dist/utils/zip-read.mjs +128 -0
- package/dist/utils/zip-read.mjs.map +1 -0
- package/dist/utils/zip-write.d.mts +16 -0
- package/dist/utils/zip-write.mjs +187 -0
- package/dist/utils/zip-write.mjs.map +1 -0
- package/dist/utils.d.mts +17 -3
- package/dist/utils.mjs +18 -4
- package/package.json +35 -26
- package/dist/adapter/capture-runner.mjs.map +0 -1
- package/dist/adapter/git-host/comments.d.mts +0 -41
- package/dist/adapter/git-host/comments.mjs +0 -54
- package/dist/adapter/git-host/comments.mjs.map +0 -1
- package/dist/adapter/git-host/helpers.d.mts +0 -13
- package/dist/adapter/git-host/helpers.mjs +0 -30
- package/dist/adapter/git-host/helpers.mjs.map +0 -1
- package/dist/adapter/git-host.d.mts +0 -42
- package/dist/capture/queue.d.mts +0 -38
- package/dist/capture/queue.mjs +0 -98
- package/dist/capture/queue.mjs.map +0 -1
- package/dist/capture/recovery.d.mts +0 -21
- package/dist/capture/recovery.mjs +0 -83
- package/dist/capture/recovery.mjs.map +0 -1
- package/dist/capture/status-fanout.mjs +0 -72
- package/dist/capture/status-fanout.mjs.map +0 -1
- package/dist/diff/engine.d.mts +0 -16
- package/dist/diff/engine.mjs +0 -87
- package/dist/diff/engine.mjs.map +0 -1
- package/dist/diff/options.d.mts +0 -42
- package/dist/diff/options.mjs +0 -15
- package/dist/diff/options.mjs.map +0 -1
- package/dist/models/status-config.d.mts +0 -38
- package/dist/models/status-config.mjs +0 -63
- package/dist/models/status-config.mjs.map +0 -1
- package/dist/schema/status-config.d.mts +0 -16
- package/dist/test-helpers/git-contract.d.mts +0 -11
- package/dist/test-helpers/git-contract.mjs +0 -34
- package/dist/test-helpers/git-contract.mjs.map +0 -1
- /package/dist/adapter/{git-host.mjs → oauth.mjs} +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
|
|
4
|
+
// src/adapters/database.ts
|
|
5
|
+
/** A fenced reference write lost its generation race and should be retried. */
|
|
6
|
+
var ReferenceGenerationConflict = class extends Error {};
|
|
5
7
|
/** Table keys every DatabaseAdapter must expose (contract + validation share this). */
|
|
6
8
|
const REQUIRED_TABLE_KEYS = [
|
|
7
9
|
"projects",
|
|
@@ -24,7 +26,6 @@ function clampListLimit(limit) {
|
|
|
24
26
|
if (!Number.isFinite(limit)) return MAX_LIST_LIMIT;
|
|
25
27
|
return Math.min(Math.max(Math.floor(limit), 1), MAX_LIST_LIMIT);
|
|
26
28
|
}
|
|
27
|
-
|
|
28
|
-
export { MAX_LIST_LIMIT, REQUIRED_TABLE_KEYS, clampListLimit };
|
|
29
|
+
export { MAX_LIST_LIMIT, REQUIRED_TABLE_KEYS, ReferenceGenerationConflict, clampListLimit };
|
|
29
30
|
|
|
30
31
|
//# sourceMappingURL=database.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.mjs","names":[],"sources":["../../src/adapters/database.ts"],"sourcesContent":["/**\n * Database adapter interface: query builders over explicitly typed tables.\n *\n * Canonical home of the database contract — {@link DatabaseAdapter},\n * {@link Tables}, {@link TxStore}, {@link ListOptions}, and\n * {@link DrizzleAdapterOptions}. Driver machinery lives in the database\n * packages (`@storyshelf/db-sqlite`, `@storyshelf/db-postgres`).\n */\nimport type { SQL } from \"drizzle-orm\";\nimport type { Table } from \"drizzle-orm\";\nimport type { Adapter, AdapterMetadata } from \"./metadata.ts\";\n\n/** Type-safe table map enforced on every DatabaseAdapter. */\nexport interface Tables {\n projects: Table;\n projectStatusConfigs: Table;\n builds: Table;\n captureAttempts: Table;\n captureLogs: Table;\n snapshots: Table;\n baselines: Table;\n comments: Table;\n labelTypes: Table;\n buildLabels: Table;\n tokens: Table;\n webhooks: Table;\n notificationChannels: Table;\n notificationSubscriptions: Table;\n users: Table;\n userInviteTokens: Table;\n projectMembers: Table;\n projectGroupMappings: Table;\n contentRefs: Table;\n}\n\n/** Table keys every DatabaseAdapter must expose (contract + validation share this). */\nexport const REQUIRED_TABLE_KEYS = [\n \"projects\",\n \"builds\",\n \"snapshots\",\n \"baselines\",\n \"comments\",\n \"labelTypes\",\n \"buildLabels\",\n \"tokens\",\n \"webhooks\",\n \"users\",\n \"projectMembers\",\n];\n\n/** Largest page any adapter serves in one list call. */\nexport const MAX_LIST_LIMIT = 1000;\n\n/** Clamp a list limit into [1, MAX_LIST_LIMIT]; undefined stays undefined. */\nexport function clampListLimit(limit?: number): number | undefined {\n if (limit === undefined) {\n return undefined;\n }\n if (!Number.isFinite(limit)) {\n return MAX_LIST_LIMIT;\n }\n return Math.min(Math.max(Math.floor(limit), 1), MAX_LIST_LIMIT);\n}\n\n/** Options that narrow and page a list query. */\nexport interface ListOptions {\n /** SQL WHERE condition. */\n where?: SQL;\n /** SQL ORDER BY condition. */\n orderBy?: SQL;\n /** Maximum number of rows to return. */\n limit?: number;\n /** Number of rows to skip. */\n offset?: number;\n}\n\n/**\n * Transactional CRUD subset available inside {@link DatabaseAdapter.transact}.\n * Mirrors the adapter surface minus metadata, lifecycle, and raw `all`\n * (opaque to transactions on some drivers).\n */\nexport interface TxStore {\n /** Insert a row and return the inserted record. */\n insert<T extends Table>(table: T, values: T[\"$inferInsert\"]): Promise<T[\"$inferSelect\"]>;\n /** Update a row by id and return the updated record. */\n update<T extends Table>(\n table: T,\n id: string,\n values: Partial<T[\"$inferInsert\"]>,\n ): Promise<T[\"$inferSelect\"]>;\n /** Fetch a single row by id, or null if not found. */\n get<T extends Table>(table: T, id: string): Promise<T[\"$inferSelect\"] | null>;\n /** Delete a row by id. */\n remove(table: Table, id: string): Promise<void>;\n /** List rows matching the given options. */\n list<T extends Table>(table: T, opts?: ListOptions): Promise<T[\"$inferSelect\"][]>;\n /** Count rows matching an optional where condition. */\n count(table: Table, where?: SQL): Promise<number>;\n}\n\n/** Database abstraction over Drizzle tables, agnostic of dialect and driver. */\nexport interface DatabaseAdapter extends Adapter<{ readonly category: \"database\" }> {\n /** Table handles for this adapter's dialect, enforced with type safety. */\n readonly tables: Tables;\n /** Insert a row and return the inserted record. */\n insert<T extends Table>(table: T, values: T[\"$inferInsert\"]): Promise<T[\"$inferSelect\"]>;\n /** Update a row by id and return the updated record. */\n update<T extends Table>(\n table: T,\n id: string,\n values: Partial<T[\"$inferInsert\"]>,\n ): Promise<T[\"$inferSelect\"]>;\n /** Fetch a single row by id, or null if not found. */\n get<T extends Table>(table: T, id: string): Promise<T[\"$inferSelect\"] | null>;\n /** Delete a row by id. */\n remove(table: Table, id: string): Promise<void>;\n /** List rows matching the given options. */\n list<T extends Table>(table: T, opts?: ListOptions): Promise<T[\"$inferSelect\"][]>;\n /** Count rows matching an optional where condition. */\n count(table: Table, where?: SQL): Promise<number>;\n /** Run an arbitrary SQL query and return typed rows. */\n all<T>(query: SQL): Promise<T[]>;\n /**\n * Run `fn` inside a transaction when the driver supports one.\n * Commits on resolve, rolls back on throw. Drivers without transaction\n * support omit this; callers must use `?.` and accept sequential execution.\n */\n transact?<R>(fn: (tx: TxStore) => Promise<R>): Promise<R>;\n}\n\n/** Driver-supplied identity plus lifecycle hooks. */\nexport interface DrizzleAdapterOptions {\n metadata: AdapterMetadata & { readonly category: \"database\" };\n tables: Tables;\n migrate: () => Promise<void> | void;\n close: () => Promise<void> | void;\n /** Cheap liveness probe (e.g. `SELECT 1`); omitted when the driver has none. */\n ping?: () => Promise<void> | void;\n}\n"],"mappings":";;;;;AAoCA,MAAa,sBAAsB;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAa,iBAAiB;;AAG9B,SAAgB,eAAe,OAAoC;CACjE,IAAI,UAAU,KAAA,GACZ;CAEF,IAAI,CAAC,OAAO,SAAS,KAAK,GACxB,OAAO;CAET,OAAO,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC,GAAG,cAAc;AAChE"}
|
|
1
|
+
{"version":3,"file":"database.mjs","names":[],"sources":["../../src/adapters/database.ts"],"sourcesContent":["/**\n * Database adapter interface: query builders over explicitly typed tables.\n *\n * Canonical home of the database contract — {@link DatabaseAdapter},\n * {@link Tables}, {@link TxStore}, {@link ListOptions}, and\n * {@link DrizzleAdapterOptions}. Driver machinery lives in the database\n * packages (`@storyshelf/db-sqlite`, `@storyshelf/db-postgres`).\n */\nimport type { SQL } from \"drizzle-orm\";\nimport type { Table } from \"drizzle-orm\";\nimport type { Adapter, AdapterMetadata } from \"./metadata.ts\";\n\n/** A fenced reference write lost its generation race and should be retried. */\nexport class ReferenceGenerationConflict extends Error {}\n\n/** Type-safe table map enforced on every DatabaseAdapter. */\nexport interface Tables {\n projects: Table;\n builds: Table;\n captureAttempts: Table;\n captureLogs: Table;\n captureShards: Table;\n captureJobs: Table;\n buildComponents: Table;\n buildReviews: Table;\n siteSettings: Table;\n snapshots: Table;\n baselines: Table;\n comments: Table;\n labelTypes: Table;\n buildLabels: Table;\n projectLinks: Table;\n designLinks: Table;\n designCredentials: Table;\n userConnections: Table;\n designNodes: Table;\n buildPackageUsage: Table;\n tokens: Table;\n webhooks: Table;\n insights: Table;\n aiUsage: Table;\n aiBudgetAlerts: Table;\n notificationChannels: Table;\n notificationSubscriptions: Table;\n users: Table;\n userInviteTokens: Table;\n projectMembers: Table;\n projectGroupMappings: Table;\n contentRefs: Table;\n}\n\n/** Table keys every DatabaseAdapter must expose (contract + validation share this). */\nexport const REQUIRED_TABLE_KEYS = [\n \"projects\",\n \"builds\",\n \"snapshots\",\n \"baselines\",\n \"comments\",\n \"labelTypes\",\n \"buildLabels\",\n \"tokens\",\n \"webhooks\",\n \"users\",\n \"projectMembers\",\n];\n\n/** Largest page any adapter serves in one list call. */\nexport const MAX_LIST_LIMIT = 1000;\n\n/** Clamp a list limit into [1, MAX_LIST_LIMIT]; undefined stays undefined. */\nexport function clampListLimit(limit?: number): number | undefined {\n if (limit === undefined) {\n return undefined;\n }\n if (!Number.isFinite(limit)) {\n return MAX_LIST_LIMIT;\n }\n return Math.min(Math.max(Math.floor(limit), 1), MAX_LIST_LIMIT);\n}\n\n/** Options that narrow and page a list query. */\nexport interface ListOptions {\n /** SQL WHERE condition. */\n where?: SQL;\n /** SQL ORDER BY condition. */\n orderBy?: SQL;\n /** Maximum number of rows to return. */\n limit?: number;\n /** Number of rows to skip. */\n offset?: number;\n}\n\n/**\n * Transactional CRUD subset available inside {@link DatabaseAdapter.transact}.\n * Mirrors the adapter surface minus metadata, lifecycle, and raw `all`\n * (opaque to transactions on some drivers).\n */\nexport interface TxStore {\n /** Insert a row and return the inserted record. */\n insert<T extends Table>(table: T, values: T[\"$inferInsert\"]): Promise<T[\"$inferSelect\"]>;\n /** Update a row by id and return the updated record. */\n update<T extends Table>(\n table: T,\n id: string,\n values: Partial<T[\"$inferInsert\"]>,\n ): Promise<T[\"$inferSelect\"]>;\n /** Fetch a single row by id, or null if not found. */\n get<T extends Table>(table: T, id: string): Promise<T[\"$inferSelect\"] | null>;\n /** Delete a row by id. */\n remove(table: Table, id: string): Promise<void>;\n /** List rows matching the given options. */\n list<T extends Table>(table: T, opts?: ListOptions): Promise<T[\"$inferSelect\"][]>;\n /** Count rows matching an optional where condition. */\n count(table: Table, where?: SQL): Promise<number>;\n}\n\n/** An owner of durable protection for a build. Historical comparisons are not build owners. */\nexport interface BuildReferenceOwner {\n type: \"baseline\" | \"investigation\";\n id: string;\n projectId: string;\n}\n\n/** One owner's complete new reference set for an atomic multi-owner mutation. */\nexport interface BuildReferenceChange {\n owner: BuildReferenceOwner;\n buildIds: readonly string[];\n}\n\n/** A complete owner reference replacement guarded by its last observed generation. */\nexport interface FencedBuildReferenceChange extends BuildReferenceChange {\n expectedGeneration: number;\n}\n\n/**\n * An explicit database capability; an ordinary transaction does not establish this contract.\n * Implementations serialize admissions, reference changes, and deletion claims across processes.\n * Their tests must use independent connections, including promotion/purge and pin/purge races.\n */\nexport interface BuildReferenceLifecycle {\n /** Return the durable generation for an owner, or zero before its first reference mutation.\n * This is a snapshot: callers must pass it to a fenced mutation, which rechecks atomically. */\n referenceGeneration(owner: BuildReferenceOwner): Promise<number>;\n /** Atomically fence and replace multiple owners, or roll back all owners and domain writes. */\n replaceManyFencedReferences<T>(\n changes: readonly FencedBuildReferenceChange[],\n writeDomain: (tx: TxStore) => Promise<T>,\n ): Promise<{ result: T; generations: number[] }>;\n /** Compare and advance an owner's durable generation with its reference and domain writes.\n * Generation zero denotes an owner with no earlier mutations. A stale generation rejects the\n * whole transaction. Generations survive release so an old worker cannot release a newer pin. */\n replaceFencedReferences<T>(\n owner: BuildReferenceOwner,\n expectedGeneration: number,\n buildIds: readonly string[],\n writeDomain: (tx: TxStore) => Promise<T>,\n ): Promise<{ result: T; generation: number }>;\n /**\n * Atomically replace one owner's complete reference set and make its domain writes. Both old and\n * new builds must be locked in stable order, checked for project ownership and availability,\n * and committed with the domain mutation. Unknown or tombstoned builds reject admission.\n */\n replaceReferences<T>(\n owner: BuildReferenceOwner,\n buildIds: readonly string[],\n writeDomain: (tx: TxStore) => Promise<T>,\n ): Promise<T>;\n /** Atomically replace several owners' reference sets and the shared domain writes. */\n replaceManyReferences<T>(\n changes: readonly BuildReferenceChange[],\n writeDomain: (tx: TxStore) => Promise<T>,\n ): Promise<T>;\n /**\n * In the same concurrency domain as admissions, irreversibly tombstone a build only if no\n * protecting reference remains. Existing tombstones are resumable and never become available.\n * Storage deletion must happen after this operation commits, outside database locks.\n */\n claimDeletion(\n projectId: string,\n buildId: string,\n ): Promise<\"claimed\" | \"protected\" | \"deleting\" | \"missing\">;\n}\n\n/** Database-specific metadata: the family plus what the backing platform can carry. */\nexport interface DatabaseAdapterMetadata {\n readonly category: \"database\";\n /**\n * `false` when the database cannot back a deployment with `testing` (ADR 0006, decision 3): it\n * is reachable only from a platform that ends the process after each request (Cloudflare D1).\n * Unset means it can.\n */\n readonly supportsTesting?: boolean;\n}\n\n/** Database abstraction over Drizzle tables, agnostic of dialect and driver. */\nexport interface DatabaseAdapter extends Adapter<DatabaseAdapterMetadata> {\n /**\n * Present only when the adapter implements the cross-process retention safety contract.\n * `transact` by itself is not evidence of this capability.\n */\n readonly buildReferenceLifecycle?: BuildReferenceLifecycle;\n /** Table handles for this adapter's dialect, enforced with type safety. */\n readonly tables: Tables;\n /** Insert a row and return the inserted record. */\n insert<T extends Table>(table: T, values: T[\"$inferInsert\"]): Promise<T[\"$inferSelect\"]>;\n /** Update a row by id and return the updated record. */\n update<T extends Table>(\n table: T,\n id: string,\n values: Partial<T[\"$inferInsert\"]>,\n ): Promise<T[\"$inferSelect\"]>;\n /** Atomically update a row only while `where` matches; return the current row, or null if absent.\n * Custom adapters must implement the condition in the same database statement as the update.\n */\n updateWhere<T extends Table>(\n table: T,\n id: string,\n values: Partial<T[\"$inferInsert\"]>,\n where: SQL,\n ): Promise<T[\"$inferSelect\"] | null>;\n /** Fetch a single row by id, or null if not found. */\n get<T extends Table>(table: T, id: string): Promise<T[\"$inferSelect\"] | null>;\n /** Delete a row by id. */\n remove(table: Table, id: string): Promise<void>;\n /** List rows matching the given options. */\n list<T extends Table>(table: T, opts?: ListOptions): Promise<T[\"$inferSelect\"][]>;\n /** Count rows matching an optional where condition. */\n count(table: Table, where?: SQL): Promise<number>;\n /** Run an arbitrary SQL query and return typed rows. */\n all<T>(query: SQL): Promise<T[]>;\n /**\n * Run `fn` inside a transaction when the driver supports one.\n * Commits on resolve, rolls back on throw. Drivers without transaction\n * support omit this; callers must use `?.` and accept sequential execution.\n */\n transact?<R>(fn: (tx: TxStore) => Promise<R>): Promise<R>;\n}\n\n/** Driver-supplied identity plus lifecycle hooks. */\nexport interface DrizzleAdapterOptions {\n metadata: AdapterMetadata & DatabaseAdapterMetadata;\n tables: Tables;\n migrate: () => Promise<void> | void;\n close: () => Promise<void> | void;\n /** Cheap liveness probe (e.g. `SELECT 1`); omitted when the driver has none. */\n ping?: () => Promise<void> | void;\n}\n"],"mappings":";;;;;AAaA,IAAa,8BAAb,cAAiD,MAAM,CAAC;;AAuCxD,MAAa,sBAAsB;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAa,iBAAiB;;AAG9B,SAAgB,eAAe,OAAoC;CACjE,IAAI,UAAU,KAAA,GACZ;CAEF,IAAI,CAAC,OAAO,SAAS,KAAK,GACxB,OAAO;CAET,OAAO,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC,GAAG,cAAc;AAChE"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { Logger } from "../logger.mjs";
|
|
4
|
+
import { OAuthClient } from "./oauth.mjs";
|
|
5
|
+
import { Adapter, AdapterMetadata } from "./metadata.mjs";
|
|
6
|
+
import { Buffer } from "node:buffer";
|
|
7
|
+
/** Design-provider metadata: identity plus the copy the settings UI shows for its credential. */
|
|
8
|
+
interface DesignAdapterMetadata extends AdapterMetadata {
|
|
9
|
+
readonly category: "design";
|
|
10
|
+
/** Credential field label, e.g. "Figma access token". */
|
|
11
|
+
readonly credentialLabel: string;
|
|
12
|
+
/** Help text under the credential field (scopes needed, expiry). */
|
|
13
|
+
readonly credentialHelp: string;
|
|
14
|
+
/** Placeholder for the credential input, e.g. "figd_…". */
|
|
15
|
+
readonly credentialPlaceholder?: string;
|
|
16
|
+
/** Example of a link this provider accepts, shown on rejection. */
|
|
17
|
+
readonly urlHint: string;
|
|
18
|
+
/** Longest lifetime of a credential, so the UI can count down to rotation. */
|
|
19
|
+
readonly credentialMaxAgeDays?: number;
|
|
20
|
+
}
|
|
21
|
+
/** A parsed design link. */
|
|
22
|
+
interface DesignRef {
|
|
23
|
+
/** Provider file identifier. */
|
|
24
|
+
fileKey: string;
|
|
25
|
+
/** Node id inside the file, or null when the link targets the whole file. */
|
|
26
|
+
nodeId: string | null;
|
|
27
|
+
/** URL to open: the pasted link without credentials or fragment. */
|
|
28
|
+
url: string;
|
|
29
|
+
}
|
|
30
|
+
/** Outcome of a metadata fetch. `error` is transient (outage/rate limit) and never persisted. */
|
|
31
|
+
type DesignState = "ok" | "deleted" | "unauthorized" | "forbidden" | "error";
|
|
32
|
+
/** Metadata of a design file or node. */
|
|
33
|
+
interface DesignMeta {
|
|
34
|
+
state: DesignState;
|
|
35
|
+
name: string | null;
|
|
36
|
+
version: string | null;
|
|
37
|
+
lastModified: string | null;
|
|
38
|
+
}
|
|
39
|
+
/** Per-call options: a signal cancelling the whole call (page-render budget) plus a logger. */
|
|
40
|
+
interface DesignCallOptions {
|
|
41
|
+
logger?: Logger;
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
}
|
|
44
|
+
/** How a stored credential authenticates: a pasted personal token or a user's OAuth access token. */
|
|
45
|
+
type DesignAuthType = "token" | "oauth";
|
|
46
|
+
/** Descriptor — registered at startup, parses links and binds a credential. */
|
|
47
|
+
interface DesignProvider extends Adapter<DesignAdapterMetadata> {
|
|
48
|
+
/** Parse a pasted link; null when it is not one of this provider's links. */
|
|
49
|
+
parseUrl(raw: string): DesignRef | null;
|
|
50
|
+
/** Create a client bound to a decrypted credential (`authType` defaults to a personal token). */
|
|
51
|
+
create(opts: {
|
|
52
|
+
credential: string;
|
|
53
|
+
authType?: DesignAuthType;
|
|
54
|
+
logger?: Logger;
|
|
55
|
+
}): DesignClient;
|
|
56
|
+
/** Present only when the operator configured OAuth for this provider. */
|
|
57
|
+
readonly oauth?: OAuthClient;
|
|
58
|
+
}
|
|
59
|
+
/** Runtime — bound to a credential, talks to the vendor API. */
|
|
60
|
+
interface DesignClient {
|
|
61
|
+
/**
|
|
62
|
+
* Metadata for several refs of one file, keyed by node id (`""` = whole file).
|
|
63
|
+
* API failures map to a {@link DesignState} per ref rather than throwing.
|
|
64
|
+
*/
|
|
65
|
+
fetchMetas(fileKey: string, refs: readonly DesignRef[], options?: DesignCallOptions): Promise<Map<string, DesignMeta>>;
|
|
66
|
+
/**
|
|
67
|
+
* PNG renders of several nodes of one file, keyed by node id. Nodes the vendor
|
|
68
|
+
* cannot render are omitted; throws when the render API call itself fails.
|
|
69
|
+
*/
|
|
70
|
+
fetchRenders(fileKey: string, nodeIds: readonly string[], options?: DesignCallOptions): Promise<Map<string, Buffer>>;
|
|
71
|
+
}
|
|
72
|
+
/** Thrown when a design link is not accepted by any configured provider. */
|
|
73
|
+
declare class InvalidDesignUrlError extends Error {
|
|
74
|
+
readonly value: string;
|
|
75
|
+
constructor(value: string, hint?: string);
|
|
76
|
+
}
|
|
77
|
+
/** First provider that accepts the link, with its parsed ref. */
|
|
78
|
+
declare function parseDesignUrl(providers: readonly DesignProvider[], raw: string): {
|
|
79
|
+
provider: DesignProvider;
|
|
80
|
+
ref: DesignRef;
|
|
81
|
+
} | null;
|
|
82
|
+
export { DesignAdapterMetadata, DesignAuthType, DesignCallOptions, DesignClient, DesignMeta, DesignProvider, DesignRef, DesignState, InvalidDesignUrlError, parseDesignUrl };
|
|
83
|
+
//# sourceMappingURL=design.d.mts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
// src/adapters/design.ts
|
|
5
|
+
/** Thrown when a design link is not accepted by any configured provider. */
|
|
6
|
+
var InvalidDesignUrlError = class extends Error {
|
|
7
|
+
value;
|
|
8
|
+
constructor(value, hint) {
|
|
9
|
+
super(hint ? `Enter a supported design link, e.g. ${hint}` : "No design provider is configured");
|
|
10
|
+
this.value = value;
|
|
11
|
+
this.name = "InvalidDesignUrlError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
/** First provider that accepts the link, with its parsed ref. */
|
|
15
|
+
function parseDesignUrl(providers, raw) {
|
|
16
|
+
for (const provider of providers) {
|
|
17
|
+
const ref = provider.parseUrl(raw);
|
|
18
|
+
if (ref) return {
|
|
19
|
+
provider,
|
|
20
|
+
ref
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
export { InvalidDesignUrlError, parseDesignUrl };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=design.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design.mjs","names":[],"sources":["../../src/adapters/design.ts"],"sourcesContent":["/**\n * Design-provider adapter interface: link validation, file/node metadata and\n * rendered previews from a design tool (Figma, …). Core owns link resolution,\n * the metadata/render cache and credential storage; a provider owns only the\n * vendor specifics below.\n */\nimport type { Buffer } from \"node:buffer\";\nimport type { Logger } from \"../logger.ts\";\nimport type { Adapter, AdapterMetadata } from \"./metadata.ts\";\nimport type { OAuthClient } from \"./oauth.ts\";\n\n/** Design-provider metadata: identity plus the copy the settings UI shows for its credential. */\nexport interface DesignAdapterMetadata extends AdapterMetadata {\n readonly category: \"design\";\n /** Credential field label, e.g. \"Figma access token\". */\n readonly credentialLabel: string;\n /** Help text under the credential field (scopes needed, expiry). */\n readonly credentialHelp: string;\n /** Placeholder for the credential input, e.g. \"figd_…\". */\n readonly credentialPlaceholder?: string;\n /** Example of a link this provider accepts, shown on rejection. */\n readonly urlHint: string;\n /** Longest lifetime of a credential, so the UI can count down to rotation. */\n readonly credentialMaxAgeDays?: number;\n}\n\n/** A parsed design link. */\nexport interface DesignRef {\n /** Provider file identifier. */\n fileKey: string;\n /** Node id inside the file, or null when the link targets the whole file. */\n nodeId: string | null;\n /** URL to open: the pasted link without credentials or fragment. */\n url: string;\n}\n\n/** Outcome of a metadata fetch. `error` is transient (outage/rate limit) and never persisted. */\nexport type DesignState = \"ok\" | \"deleted\" | \"unauthorized\" | \"forbidden\" | \"error\";\n\n/** Metadata of a design file or node. */\nexport interface DesignMeta {\n state: DesignState;\n name: string | null;\n version: string | null;\n lastModified: string | null;\n}\n\n/** Per-call options: a signal cancelling the whole call (page-render budget) plus a logger. */\nexport interface DesignCallOptions {\n logger?: Logger;\n signal?: AbortSignal;\n}\n\n/** How a stored credential authenticates: a pasted personal token or a user's OAuth access token. */\nexport type DesignAuthType = \"token\" | \"oauth\";\n\n/** Descriptor — registered at startup, parses links and binds a credential. */\nexport interface DesignProvider extends Adapter<DesignAdapterMetadata> {\n /** Parse a pasted link; null when it is not one of this provider's links. */\n parseUrl(raw: string): DesignRef | null;\n /** Create a client bound to a decrypted credential (`authType` defaults to a personal token). */\n create(opts: { credential: string; authType?: DesignAuthType; logger?: Logger }): DesignClient;\n /** Present only when the operator configured OAuth for this provider. */\n readonly oauth?: OAuthClient;\n}\n\n/** Runtime — bound to a credential, talks to the vendor API. */\nexport interface DesignClient {\n /**\n * Metadata for several refs of one file, keyed by node id (`\"\"` = whole file).\n * API failures map to a {@link DesignState} per ref rather than throwing.\n */\n fetchMetas(\n fileKey: string,\n refs: readonly DesignRef[],\n options?: DesignCallOptions,\n ): Promise<Map<string, DesignMeta>>;\n /**\n * PNG renders of several nodes of one file, keyed by node id. Nodes the vendor\n * cannot render are omitted; throws when the render API call itself fails.\n */\n fetchRenders(\n fileKey: string,\n nodeIds: readonly string[],\n options?: DesignCallOptions,\n ): Promise<Map<string, Buffer>>;\n}\n\n/** Thrown when a design link is not accepted by any configured provider. */\nexport class InvalidDesignUrlError extends Error {\n readonly value: string;\n\n constructor(value: string, hint?: string) {\n super(\n hint ? `Enter a supported design link, e.g. ${hint}` : \"No design provider is configured\",\n );\n this.value = value;\n this.name = \"InvalidDesignUrlError\";\n }\n}\n\n/** First provider that accepts the link, with its parsed ref. */\nexport function parseDesignUrl(\n providers: readonly DesignProvider[],\n raw: string,\n): { provider: DesignProvider; ref: DesignRef } | null {\n for (const provider of providers) {\n const ref = provider.parseUrl(raw);\n if (ref) return { provider, ref };\n }\n return null;\n}\n"],"mappings":";;;;;AAyFA,IAAa,wBAAb,cAA2C,MAAM;CAC/C;CAEA,YAAY,OAAe,MAAe;EACxC,MACE,OAAO,uCAAuC,SAAS,kCACzD;EACA,KAAK,QAAQ;EACb,KAAK,OAAO;CACd;AACF;;AAGA,SAAgB,eACd,WACA,KACqD;CACrD,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,MAAM,SAAS,SAAS,GAAG;EACjC,IAAI,KAAK,OAAO;GAAE;GAAU;EAAI;CAClC;CACA,OAAO;AACT"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
3
|
import { Adapter } from "./metadata.mjs";
|
|
4
|
-
//#region src/adapters/email-sender.d.ts
|
|
5
4
|
/** A single email message (transport-agnostic). */
|
|
6
5
|
interface EmailMessage {
|
|
7
6
|
to: string;
|
|
@@ -22,6 +21,5 @@ interface EmailSender extends Adapter<{
|
|
|
22
21
|
}> {
|
|
23
22
|
send(message: EmailMessage): Promise<void>;
|
|
24
23
|
}
|
|
25
|
-
//#endregion
|
|
26
24
|
export { EmailMessage, EmailSender };
|
|
27
25
|
//# sourceMappingURL=email-sender.d.mts.map
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
|
-
import { ShelfConfig } from "../config.mjs";
|
|
4
3
|
import { Logger } from "../logger.mjs";
|
|
5
|
-
import {
|
|
6
|
-
//#region src/adapters/metadata.d.ts
|
|
4
|
+
import { ShelfConfig } from "../config.mjs";
|
|
7
5
|
/**
|
|
8
6
|
* Adapter family — which concern an adapter supplies.
|
|
9
7
|
*
|
|
@@ -11,7 +9,7 @@ import { z } from "zod";
|
|
|
11
9
|
* `category` tells a reader which slot the adapter fills without knowing
|
|
12
10
|
* which adapter instance supplied the metadata.
|
|
13
11
|
*/
|
|
14
|
-
type AdapterCategory = "database" | "storage" | "capture-runner" | "capture-queue" | "
|
|
12
|
+
type AdapterCategory = "database" | "storage" | "capture-runner" | "capture-queue" | "design" | "notifier";
|
|
15
13
|
/** Common adapter identity — every adapter instance exposes this. */
|
|
16
14
|
interface AdapterMetadata {
|
|
17
15
|
/** Human label for UI/logs. */
|
|
@@ -25,12 +23,6 @@ interface AdapterMetadata {
|
|
|
25
23
|
/** Adapter family — which concern this adapter supplies. */
|
|
26
24
|
readonly category: AdapterCategory;
|
|
27
25
|
}
|
|
28
|
-
/** Git-specific metadata extension (adds logo + validation schema). */
|
|
29
|
-
interface GitAdapterMetadata extends AdapterMetadata {
|
|
30
|
-
readonly category: "git-host";
|
|
31
|
-
readonly logo?: string;
|
|
32
|
-
readonly schema: z.ZodType;
|
|
33
|
-
}
|
|
34
26
|
/** Context passed to an adapter's `setup` on server startup. */
|
|
35
27
|
interface AdapterSetupContext {
|
|
36
28
|
/** Resolved shelf configuration (scratchDir, secret, …). Never log the secret. */
|
|
@@ -84,6 +76,5 @@ interface Adapter<Extra extends object = Record<string, unknown>> {
|
|
|
84
76
|
*/
|
|
85
77
|
setLogger?(logger: Logger): void;
|
|
86
78
|
}
|
|
87
|
-
|
|
88
|
-
export { Adapter, AdapterCategory, AdapterHealth, AdapterLifecycle, AdapterMetadata, AdapterSetupContext, GitAdapterMetadata };
|
|
79
|
+
export { Adapter, AdapterCategory, AdapterHealth, AdapterLifecycle, AdapterMetadata, AdapterSetupContext };
|
|
89
80
|
//# sourceMappingURL=metadata.d.mts.map
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
|
-
import { ChannelToggles, FormattedNotification, NotificationBrand, NotificationChannel, NotificationEvent, SystemEventName, SystemNotification } from "../adapters/notifier/types.mjs";
|
|
4
|
-
import { NotifierAdapter, NotifierMetadata, NotifierProvider } from "../adapters/notifier/provider.mjs";
|
|
3
|
+
import { ChannelOutcome, ChannelToggles, FormattedNotification, NotificationBrand, NotificationChannel, NotificationEvent, NotifierState, NotifierStateTarget, StateAnnotation, SystemEventName, SystemNotification } from "../adapters/notifier/types.mjs";
|
|
4
|
+
import { MessageNotifierAdapter, MessageNotifierMetadata, MessageNotifierProvider, NotifierAdapter, NotifierDelivery, NotifierMetadata, NotifierProvider, SetStateInput, StateNotifierAdapter, StateNotifierMetadata, StateNotifierProvider, isStateProvider } from "../adapters/notifier/provider.mjs";
|
|
5
5
|
import { emitNotifications, emitSystemNotification } from "../adapters/notifier/events.mjs";
|
|
6
|
+
import { BuildStateBuild, BuildStateChange, BuildStateFlags, BuildStateInput, BuildStateSet, DesiredComment, DesiredStatus, MAX_ANNOTATIONS, PublishingState, StatusName, statusesForBuild } from "../adapters/notifier/build-state.mjs";
|
|
7
|
+
import { buildCommentMarkdown } from "../adapters/notifier/build-comment.mjs";
|
|
8
|
+
import { DEFAULT_STATUS_PREFIX, channelPrefix, writeBuildState } from "../adapters/notifier/state.mjs";
|
|
6
9
|
import { formatNotification, formatSystemNotification } from "../adapters/notifier/format.mjs";
|
|
7
|
-
export { type ChannelToggles, type FormattedNotification, type NotificationBrand, type NotificationChannel, type NotificationEvent, type NotifierAdapter, type NotifierMetadata, type NotifierProvider, type SystemEventName, type SystemNotification, emitNotifications, emitSystemNotification, formatNotification, formatSystemNotification };
|
|
10
|
+
export { type BuildStateBuild, type BuildStateChange, type BuildStateFlags, type BuildStateInput, type BuildStateSet, type ChannelOutcome, type ChannelToggles, DEFAULT_STATUS_PREFIX, type DesiredComment, type DesiredStatus, type FormattedNotification, MAX_ANNOTATIONS, type MessageNotifierAdapter, type MessageNotifierMetadata, type MessageNotifierProvider, type NotificationBrand, type NotificationChannel, type NotificationEvent, type NotifierAdapter, type NotifierDelivery, type NotifierMetadata, type NotifierProvider, type NotifierState, type NotifierStateTarget, type PublishingState, type SetStateInput, type StateAnnotation, type StateNotifierAdapter, type StateNotifierMetadata, type StateNotifierProvider, type StatusName, type SystemEventName, type SystemNotification, buildCommentMarkdown, channelPrefix, emitNotifications, emitSystemNotification, formatNotification, formatSystemNotification, isStateProvider, statusesForBuild, writeBuildState };
|
|
@@ -2,5 +2,9 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { formatNotification, formatSystemNotification } from "../adapters/notifier/format.mjs";
|
|
5
|
+
import { isStateProvider } from "../adapters/notifier/provider.mjs";
|
|
5
6
|
import { emitNotifications, emitSystemNotification } from "../adapters/notifier/events.mjs";
|
|
6
|
-
|
|
7
|
+
import { buildCommentMarkdown } from "../adapters/notifier/build-comment.mjs";
|
|
8
|
+
import { MAX_ANNOTATIONS, statusesForBuild } from "../adapters/notifier/build-state.mjs";
|
|
9
|
+
import { DEFAULT_STATUS_PREFIX, channelPrefix, writeBuildState } from "../adapters/notifier/state.mjs";
|
|
10
|
+
export { DEFAULT_STATUS_PREFIX, MAX_ANNOTATIONS, buildCommentMarkdown, channelPrefix, emitNotifications, emitSystemNotification, formatNotification, formatSystemNotification, isStateProvider, statusesForBuild, writeBuildState };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
/**
|
|
4
|
+
* Service-neutral OAuth 2 contract for "connect your own account" flows. Any
|
|
5
|
+
* adapter that talks to a third party on behalf of a user (design tools,
|
|
6
|
+
* issue trackers, …) can expose an {@link OAuthClient}; the app owns the
|
|
7
|
+
* redirect/callback routes and core owns token storage and refresh.
|
|
8
|
+
*/
|
|
9
|
+
/** Tokens returned by an authorization-code exchange or a refresh. */
|
|
10
|
+
interface OAuthTokens {
|
|
11
|
+
accessToken: string;
|
|
12
|
+
/** Absent when the service keeps the previous refresh token valid. */
|
|
13
|
+
refreshToken?: string | null;
|
|
14
|
+
/** ISO time the access token stops working, or null when it never expires. */
|
|
15
|
+
expiresAt: string | null;
|
|
16
|
+
}
|
|
17
|
+
/** Authorization-code grant against one service, with the operator's client credentials held inside. */
|
|
18
|
+
interface OAuthClient {
|
|
19
|
+
/** Consent-screen URL to send the user to. */
|
|
20
|
+
authorizeUrl(opts: {
|
|
21
|
+
state: string;
|
|
22
|
+
redirectUri: string;
|
|
23
|
+
}): string;
|
|
24
|
+
/** Exchange the callback `code` for tokens. */
|
|
25
|
+
exchangeCode(opts: {
|
|
26
|
+
code: string;
|
|
27
|
+
redirectUri: string;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}): Promise<OAuthTokens>;
|
|
30
|
+
/** Mint a new access token from a refresh token. */
|
|
31
|
+
refresh(opts: {
|
|
32
|
+
refreshToken: string;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
}): Promise<OAuthTokens>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Anything a user can connect an account to. Structurally satisfied by adapters
|
|
38
|
+
* (`metadata.kind` identifies the service), so registering one is just
|
|
39
|
+
* listing its adapter.
|
|
40
|
+
*/
|
|
41
|
+
interface OAuthConnectable {
|
|
42
|
+
readonly metadata: {
|
|
43
|
+
readonly kind: string;
|
|
44
|
+
readonly name: string;
|
|
45
|
+
};
|
|
46
|
+
/** Present only when the operator configured OAuth for the service. */
|
|
47
|
+
readonly oauth?: OAuthClient;
|
|
48
|
+
}
|
|
49
|
+
export { OAuthClient, OAuthConnectable, OAuthTokens };
|
|
50
|
+
//# sourceMappingURL=oauth.d.mts.map
|
package/dist/adapter/setup.d.mts
CHANGED
|
@@ -2,22 +2,20 @@ import __tsdown_shims_path from 'node:path';
|
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
3
|
import { CaptureRunner } from "./capture-runner.mjs";
|
|
4
4
|
import { DatabaseAdapter } from "./database.mjs";
|
|
5
|
+
import { DesignProvider } from "./design.mjs";
|
|
5
6
|
import { EmailSender } from "./email-sender.mjs";
|
|
6
|
-
import { GitHostProvider } from "./git-host.mjs";
|
|
7
7
|
import { NotifierProvider } from "../adapters/notifier/provider.mjs";
|
|
8
8
|
import { StorageAdapter } from "./storage.mjs";
|
|
9
9
|
import { AdapterSetupContext } from "./metadata.mjs";
|
|
10
|
-
import { CaptureQueue } from "./capture-queue.mjs";
|
|
11
10
|
import { bindAdapterLoggers, collectSetups, collectTeardowns, runAdapterSetups, runAdapterTeardowns } from "../adapters/setup-runner.mjs";
|
|
12
11
|
import { validateAdapter, validateAdapterSources, validateAuth, validateBootAssembly } from "../adapters/validate.mjs";
|
|
13
|
-
|
|
12
|
+
import { adapterSourcesOf } from "../adapters/sources.mjs";
|
|
14
13
|
/** Adapters that can take part in lifecycle runs. */
|
|
15
14
|
interface AdapterSetupSources {
|
|
16
15
|
database: DatabaseAdapter;
|
|
17
16
|
storage: StorageAdapter;
|
|
18
17
|
captureRunner?: CaptureRunner;
|
|
19
|
-
|
|
20
|
-
gitHosts?: GitHostProvider[];
|
|
18
|
+
design?: DesignProvider[];
|
|
21
19
|
notifiers?: NotifierProvider[];
|
|
22
20
|
emailSender?: EmailSender;
|
|
23
21
|
}
|
|
@@ -56,6 +54,5 @@ declare class AdapterLifecycleError extends Error {
|
|
|
56
54
|
readonly failures: AdapterSetupFailure[];
|
|
57
55
|
constructor(phase: LifecyclePhase, failures: AdapterSetupFailure[]);
|
|
58
56
|
}
|
|
59
|
-
|
|
60
|
-
export { AdapterLifecycleError, AdapterSetupFailure, AdapterSetupResult, AdapterSetupSources, HookEntry, LifecyclePhase, bindAdapterLoggers, collectSetups, collectTeardowns, runAdapterSetups, runAdapterTeardowns, validateAdapter, validateAdapterSources, validateAuth, validateBootAssembly };
|
|
57
|
+
export { AdapterLifecycleError, AdapterSetupFailure, AdapterSetupResult, AdapterSetupSources, HookEntry, LifecyclePhase, adapterSourcesOf, bindAdapterLoggers, collectSetups, collectTeardowns, runAdapterSetups, runAdapterTeardowns, validateAdapter, validateAdapterSources, validateAuth, validateBootAssembly };
|
|
61
58
|
//# sourceMappingURL=setup.d.mts.map
|
package/dist/adapter/setup.mjs
CHANGED
|
@@ -3,7 +3,8 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { bindAdapterLoggers, collectSetups, collectTeardowns, runAdapterSetups, runAdapterTeardowns } from "../adapters/setup-runner.mjs";
|
|
5
5
|
import { validateAdapter, validateAdapterSources, validateAuth, validateBootAssembly } from "../adapters/validate.mjs";
|
|
6
|
-
|
|
6
|
+
import { adapterSourcesOf } from "../adapters/sources.mjs";
|
|
7
|
+
// src/adapters/setup.ts
|
|
7
8
|
/**
|
|
8
9
|
* Thrown when an `app.lifecycle.setup()` or `teardown()` run finishes with failures.
|
|
9
10
|
*
|
|
@@ -23,7 +24,6 @@ var AdapterLifecycleError = class extends Error {
|
|
|
23
24
|
this.failures = failures;
|
|
24
25
|
}
|
|
25
26
|
};
|
|
26
|
-
|
|
27
|
-
export { AdapterLifecycleError, bindAdapterLoggers, collectSetups, collectTeardowns, runAdapterSetups, runAdapterTeardowns, validateAdapter, validateAdapterSources, validateAuth, validateBootAssembly };
|
|
27
|
+
export { AdapterLifecycleError, adapterSourcesOf, bindAdapterLoggers, collectSetups, collectTeardowns, runAdapterSetups, runAdapterTeardowns, validateAdapter, validateAdapterSources, validateAuth, validateBootAssembly };
|
|
28
28
|
|
|
29
29
|
//# sourceMappingURL=setup.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.mjs","names":[],"sources":["../../src/adapters/setup.ts"],"sourcesContent":["/**\n * Adapter lifecycle contract: hooks every adapter can expose, plus the\n * settled-result and error types. The runner (`setup-runner.ts`) collects\n * and executes the hooks; `createShelfApp` kicks `setup` eagerly and\n * gates the first request on the shared result. All hooks must be\n * idempotent.\n */\nimport type {
|
|
1
|
+
{"version":3,"file":"setup.mjs","names":[],"sources":["../../src/adapters/setup.ts"],"sourcesContent":["/**\n * Adapter lifecycle contract: hooks every adapter can expose, plus the\n * settled-result and error types. The runner (`setup-runner.ts`) collects\n * and executes the hooks; `createShelfApp` kicks `setup` eagerly and\n * gates the first request on the shared result. All hooks must be\n * idempotent.\n */\nimport type { CaptureRunner } from \"./capture-runner.ts\";\nimport type { DatabaseAdapter } from \"./database.ts\";\nimport type { DesignProvider } from \"./design.ts\";\nimport type { EmailSender } from \"./email-sender.ts\";\nimport type { AdapterSetupContext } from \"./metadata.ts\";\nimport type { NotifierProvider } from \"./notifier/provider.ts\";\nimport type { StorageAdapter } from \"./storage.ts\";\n\n/** Adapters that can take part in lifecycle runs. */\nexport interface AdapterSetupSources {\n database: DatabaseAdapter;\n storage: StorageAdapter;\n captureRunner?: CaptureRunner;\n design?: DesignProvider[];\n notifiers?: NotifierProvider[];\n emailSender?: EmailSender;\n}\n\n/** One collected hook bound to its adapter identity. */\nexport interface HookEntry {\n readonly category: string;\n readonly kind: string;\n readonly name: string;\n readonly run: (ctx: AdapterSetupContext) => Promise<void>;\n}\n\n/** One failed hook, with its adapter identity attached. */\nexport interface AdapterSetupFailure {\n readonly category: string;\n readonly kind: string;\n readonly name: string;\n readonly error: string;\n}\n\n/** Settled outcome of a lifecycle run (never rejects — use `ok`). */\nexport interface AdapterSetupResult {\n readonly ok: boolean;\n readonly failures: AdapterSetupFailure[];\n}\n\n/** Lifecycle phase a run covers. */\nexport type LifecyclePhase = \"setup\" | \"teardown\";\n\n/**\n * Thrown when an `app.lifecycle.setup()` or `teardown()` run finishes with failures.\n *\n * Inspect `phase` to know which hook failed and `failures` for per-adapter\n * diagnostics. The router converts this into a 500 with structured details\n * during health checks.\n */\nexport class AdapterLifecycleError extends Error {\n /** Which lifecycle phase failed (`setup` or `teardown`). */\n readonly phase: LifecyclePhase;\n /** One entry per adapter hook that failed. */\n readonly failures: AdapterSetupFailure[];\n constructor(phase: LifecyclePhase, failures: AdapterSetupFailure[]) {\n super(`Adapter ${phase} failed: ${failures.map((f) => `${f.category}/${f.kind}`).join(\", \")}`);\n this.name = \"AdapterLifecycleError\";\n this.phase = phase;\n this.failures = failures;\n }\n}\n\n/** Collect every `setup` hook from the configured adapters. */\nexport {\n bindAdapterLoggers,\n collectSetups,\n collectTeardowns,\n runAdapterSetups,\n runAdapterTeardowns,\n} from \"./setup-runner.ts\";\n\n/** Boot-time shape validation for third-party adapters. */\nexport {\n validateAdapter,\n validateAdapterSources,\n validateAuth,\n validateBootAssembly,\n} from \"./validate.ts\";\nexport { adapterSourcesOf } from \"./sources.ts\";\n"],"mappings":";;;;;;;;;;;;;;AAyDA,IAAa,wBAAb,cAA2C,MAAM;;CAE/C;;CAEA;CACA,YAAY,OAAuB,UAAiC;EAClE,MAAM,WAAW,MAAM,WAAW,SAAS,KAAK,MAAM,GAAG,EAAE,SAAS,GAAG,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI,GAAG;EAC7F,KAAK,OAAO;EACZ,KAAK,QAAQ;EACb,KAAK,WAAW;CAClB;AACF"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
3
|
import { Adapter } from "./metadata.mjs";
|
|
4
|
-
import { Readable } from "node:stream";
|
|
5
4
|
import { Buffer } from "node:buffer";
|
|
6
|
-
|
|
5
|
+
import { Readable } from "node:stream";
|
|
7
6
|
/** Blob storage abstraction for screenshots, diffs and Storybook archives. */
|
|
8
7
|
interface StorageAdapter extends Adapter<{
|
|
9
8
|
readonly category: "storage";
|
|
@@ -29,6 +28,5 @@ interface StorageAdapter extends Adapter<{
|
|
|
29
28
|
*/
|
|
30
29
|
readStream(path: string): Promise<Readable>;
|
|
31
30
|
}
|
|
32
|
-
//#endregion
|
|
33
31
|
export { StorageAdapter };
|
|
34
32
|
//# sourceMappingURL=storage.d.mts.map
|
|
@@ -4,7 +4,6 @@ import { DatabaseAdapter } from "./database.mjs";
|
|
|
4
4
|
import { SecretInput } from "../utils/encrypt.mjs";
|
|
5
5
|
import { WebhookTables } from "../models/webhook.mjs";
|
|
6
6
|
import { Logger } from "pino";
|
|
7
|
-
//#region src/adapters/webhook-events.d.ts
|
|
8
7
|
/**
|
|
9
8
|
* Deliver an event to every subscribed webhook of a project.
|
|
10
9
|
*
|
|
@@ -24,6 +23,5 @@ interface WebhookEvent {
|
|
|
24
23
|
data: Record<string, unknown>;
|
|
25
24
|
timestamp: string;
|
|
26
25
|
}
|
|
27
|
-
//#endregion
|
|
28
26
|
export { WebhookEvent, emitWebhookEvent };
|
|
29
27
|
//# sourceMappingURL=webhook-events.d.mts.map
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
import { WebhookModel } from "../models/webhook.mjs";
|
|
5
4
|
import { hmacSha256 } from "../utils/hash.mjs";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import { WebhookModel } from "../models/webhook.mjs";
|
|
6
|
+
import { httpStatus } from "../utils/http.mjs";
|
|
7
|
+
// src/adapters/webhook-events.ts
|
|
9
8
|
/**
|
|
10
9
|
* Deliver an event to every subscribed webhook of a project.
|
|
11
10
|
*
|
|
@@ -42,7 +41,7 @@ async function deliverToWebhook(webhookModel, webhook, eventPayload, logger) {
|
|
|
42
41
|
return;
|
|
43
42
|
}
|
|
44
43
|
try {
|
|
45
|
-
await sendWebhook(webhook.url, plaintext, eventPayload);
|
|
44
|
+
await sendWebhook(webhook.url, plaintext, eventPayload, logger);
|
|
46
45
|
logger?.info({
|
|
47
46
|
webhookId: webhook.id,
|
|
48
47
|
host: hostOf(webhook.url)
|
|
@@ -63,21 +62,21 @@ function hostOf(url) {
|
|
|
63
62
|
return "[invalid-url]";
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
/**
|
|
66
|
+
* POST one event through `httpStatus` (default timeout and retry policy). The signature covers the
|
|
67
|
+
* exact body string, and `json` serializes the event with the same `JSON.stringify`.
|
|
68
|
+
*/
|
|
69
|
+
async function sendWebhook(url, secret, event, logger) {
|
|
70
|
+
await httpStatus(url, {
|
|
70
71
|
method: "POST",
|
|
72
|
+
json: event,
|
|
71
73
|
headers: {
|
|
72
|
-
"Content-Type": "application/json",
|
|
73
74
|
"X-StoryShelf-Event": event.event,
|
|
74
|
-
"X-StoryShelf-Signature":
|
|
75
|
+
"X-StoryShelf-Signature": hmacSha256(secret, JSON.stringify(event))
|
|
75
76
|
},
|
|
76
|
-
|
|
77
|
-
signal: AbortSignal.timeout(WEBHOOK_TIMEOUT_MS)
|
|
77
|
+
...logger ? { logger } : {}
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
-
//#endregion
|
|
81
80
|
export { emitWebhookEvent };
|
|
82
81
|
|
|
83
82
|
//# sourceMappingURL=webhook-events.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-events.mjs","names":[],"sources":["../../src/adapters/webhook-events.ts"],"sourcesContent":["import type { Logger } from \"pino\";\nimport { WebhookModel, type WebhookTables } from \"../models/webhook.ts\";\nimport type { Webhook } from \"../schema/webhook.ts\";\nimport type { SecretInput } from \"../utils/encrypt.ts\";\nimport { hmacSha256 } from \"../utils/hash.ts\";\nimport
|
|
1
|
+
{"version":3,"file":"webhook-events.mjs","names":[],"sources":["../../src/adapters/webhook-events.ts"],"sourcesContent":["import type { Logger } from \"pino\";\nimport { WebhookModel, type WebhookTables } from \"../models/webhook.ts\";\nimport type { Webhook } from \"../schema/webhook.ts\";\nimport type { SecretInput } from \"../utils/encrypt.ts\";\nimport { hmacSha256 } from \"../utils/hash.ts\";\nimport { httpStatus } from \"../utils/http.ts\";\nimport type { DatabaseAdapter } from \"./database.ts\";\n\n/**\n * Deliver an event to every subscribed webhook of a project.\n *\n * @param db - Database adapter for loading subscriptions.\n * @param tables - Webhook table handles.\n * @param projectId - Project whose webhooks receive the event.\n * @param event - Event name (e.g. \"baseline:created\").\n * @param data - Event payload.\n * @param secret - Server secret for decrypting webhook secrets (in memory only).\n * @param logger - Optional logger for per-delivery outcomes.\n */\nexport async function emitWebhookEvent(\n db: DatabaseAdapter,\n tables: WebhookTables,\n projectId: string,\n event: string,\n data: Record<string, unknown>,\n secret: SecretInput,\n logger?: Logger,\n): Promise<void> {\n const webhookModel = new WebhookModel(db, tables, secret);\n const webhooks = await webhookModel.list(projectId);\n const eventPayload: WebhookEvent = {\n event,\n projectId,\n data,\n timestamp: new Date().toISOString(),\n };\n\n await Promise.allSettled(\n webhooks.map(async (webhook) => {\n const events = WebhookModel.eventsOf(webhook);\n if (events.length > 0 && !events.includes(event)) {\n return;\n }\n await deliverToWebhook(webhookModel, webhook, eventPayload, logger);\n }),\n );\n}\n\n/** Decrypt, send, and log one webhook delivery (failures stay non-fatal). */\nasync function deliverToWebhook(\n webhookModel: WebhookModel,\n webhook: Webhook,\n eventPayload: WebhookEvent,\n logger: Logger | undefined,\n): Promise<void> {\n let plaintext: string;\n try {\n plaintext = webhookModel.decryptSecret(webhook);\n } catch {\n // Undecryptable secret (e.g. rotated server SECRET) — skip, don't leak\n logger?.warn({ webhookId: webhook.id }, \"skipping webhook with undecryptable secret\");\n return;\n }\n try {\n // A non-2xx answer throws HttpError, so only a delivery the subscriber accepted is \"delivered\".\n await sendWebhook(webhook.url, plaintext, eventPayload, logger);\n logger?.info({ webhookId: webhook.id, host: hostOf(webhook.url) }, \"webhook delivered\");\n } catch (error) {\n // Webhook delivery failures are non-fatal\n logger?.warn(\n { webhookId: webhook.id, host: hostOf(webhook.url), err: error },\n \"webhook delivery failed\",\n );\n }\n}\n\n/** Outbound webhook payload delivered to subscribers. */\nexport interface WebhookEvent {\n event: string;\n projectId: string;\n data: Record<string, unknown>;\n timestamp: string;\n}\n\n/** Hostname of a webhook URL for logs (never the full URL — may carry secrets). */\nfunction hostOf(url: string): string {\n try {\n return new URL(url).host;\n } catch {\n return \"[invalid-url]\";\n }\n}\n\n/**\n * POST one event through `httpStatus` (default timeout and retry policy). The signature covers the\n * exact body string, and `json` serializes the event with the same `JSON.stringify`.\n */\nasync function sendWebhook(\n url: string,\n secret: string,\n event: WebhookEvent,\n logger: Logger | undefined,\n): Promise<void> {\n await httpStatus(url, {\n method: \"POST\",\n json: event,\n headers: {\n \"X-StoryShelf-Event\": event.event,\n \"X-StoryShelf-Signature\": hmacSha256(secret, JSON.stringify(event)),\n },\n ...(logger ? { logger } : {}),\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,eAAsB,iBACpB,IACA,QACA,WACA,OACA,MACA,QACA,QACe;CACf,MAAM,eAAe,IAAI,aAAa,IAAI,QAAQ,MAAM;CACxD,MAAM,WAAW,MAAM,aAAa,KAAK,SAAS;CAClD,MAAM,eAA6B;EACjC;EACA;EACA;EACA,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;CACpC;CAEA,MAAM,QAAQ,WACZ,SAAS,IAAI,OAAO,YAAY;EAC9B,MAAM,SAAS,aAAa,SAAS,OAAO;EAC5C,IAAI,OAAO,SAAS,KAAK,CAAC,OAAO,SAAS,KAAK,GAC7C;EAEF,MAAM,iBAAiB,cAAc,SAAS,cAAc,MAAM;CACpE,CAAC,CACH;AACF;;AAGA,eAAe,iBACb,cACA,SACA,cACA,QACe;CACf,IAAI;CACJ,IAAI;EACF,YAAY,aAAa,cAAc,OAAO;CAChD,QAAQ;EAEN,QAAQ,KAAK,EAAE,WAAW,QAAQ,GAAG,GAAG,4CAA4C;EACpF;CACF;CACA,IAAI;EAEF,MAAM,YAAY,QAAQ,KAAK,WAAW,cAAc,MAAM;EAC9D,QAAQ,KAAK;GAAE,WAAW,QAAQ;GAAI,MAAM,OAAO,QAAQ,GAAG;EAAE,GAAG,mBAAmB;CACxF,SAAS,OAAO;EAEd,QAAQ,KACN;GAAE,WAAW,QAAQ;GAAI,MAAM,OAAO,QAAQ,GAAG;GAAG,KAAK;EAAM,GAC/D,yBACF;CACF;AACF;;AAWA,SAAS,OAAO,KAAqB;CACnC,IAAI;EACF,OAAO,IAAI,IAAI,GAAG,CAAC,CAAC;CACtB,QAAQ;EACN,OAAO;CACT;AACF;;;;;AAMA,eAAe,YACb,KACA,QACA,OACA,QACe;CACf,MAAM,WAAW,KAAK;EACpB,QAAQ;EACR,MAAM;EACN,SAAS;GACP,sBAAsB,MAAM;GAC5B,0BAA0B,WAAW,QAAQ,KAAK,UAAU,KAAK,CAAC;EACpE;EACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAC7B,CAAC;AACH"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { CaptureTarget, RunnerTarget } from "./capture-target.mjs";
|
|
4
|
+
import { AdapterLifecycle } from "../adapter/metadata.mjs";
|
|
5
|
+
/** A runner's live target list. */
|
|
6
|
+
interface TargetOffers {
|
|
7
|
+
/** First declared target: what a project with no `browsers` setting resolves to. */
|
|
8
|
+
readonly defaultTarget: CaptureTarget;
|
|
9
|
+
/** The targets with their current status; reads `metadata.targets`. */
|
|
10
|
+
current(): readonly RunnerTarget[];
|
|
11
|
+
/**
|
|
12
|
+
* Wrap `launch` so a target the runner does not offer fails with a {@link TargetLaunchError}, and
|
|
13
|
+
* a launch that fails marks its target unavailable with the launch error as the reason (not a
|
|
14
|
+
* transient one: a remote service that is down stays offered).
|
|
15
|
+
*/
|
|
16
|
+
guard<T, Rest extends unknown[]>(launch: (target: CaptureTarget, ...rest: Rest) => Promise<T>): (target: CaptureTarget, ...rest: Rest) => Promise<T>;
|
|
17
|
+
/** Lifecycle whose `setup` replaces the statuses with what `verify` finds, and `health` reports them. */
|
|
18
|
+
lifecycle(verify: () => Promise<readonly RunnerTarget[]>): AdapterLifecycle;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Offer `declared`, default first. Until verified every target reads as ready, so a runner used
|
|
22
|
+
* without `lifecycle.setup` behaves as before and a failed launch still marks its target.
|
|
23
|
+
*/
|
|
24
|
+
declare function createTargetOffers(declared: readonly RunnerTarget[]): TargetOffers;
|
|
25
|
+
export { TargetOffers, createTargetOffers };
|
|
26
|
+
//# sourceMappingURL=capture-target-offers.d.mts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { TargetLaunchError } from "./capture-target.mjs";
|
|
5
|
+
// src/adapters/capture-target-offers.ts
|
|
6
|
+
/**
|
|
7
|
+
* What a runner offers right now, shared by the runners (ADR 0007): the targets it declared, whether
|
|
8
|
+
* each can render, and the lifecycle that keeps that honest. A launch failure marks its target
|
|
9
|
+
* unavailable from then on.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Offer `declared`, default first. Until verified every target reads as ready, so a runner used
|
|
13
|
+
* without `lifecycle.setup` behaves as before and a failed launch still marks its target.
|
|
14
|
+
*/
|
|
15
|
+
function createTargetOffers(declared) {
|
|
16
|
+
let targets = declared;
|
|
17
|
+
const first = declared[0];
|
|
18
|
+
if (first === void 0) throw new Error("A runner must offer at least one target");
|
|
19
|
+
const fail = (target, reason) => {
|
|
20
|
+
targets = targets.map((entry) => entry.target === target ? {
|
|
21
|
+
...entry,
|
|
22
|
+
status: { unavailable: reason }
|
|
23
|
+
} : entry);
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
defaultTarget: first.target,
|
|
27
|
+
current: () => targets,
|
|
28
|
+
guard: (launch) => async (target, ...rest) => {
|
|
29
|
+
if (!targets.some((entry) => entry.target === target)) throw new TargetLaunchError(target, "not offered by this runner");
|
|
30
|
+
try {
|
|
31
|
+
return await launch(target, ...rest);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error instanceof TargetLaunchError && !error.transient) fail(target, error.reason);
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
lifecycle: (verify) => ({
|
|
38
|
+
setup: async () => {
|
|
39
|
+
targets = await verify();
|
|
40
|
+
},
|
|
41
|
+
teardown: async () => {
|
|
42
|
+
await Promise.resolve();
|
|
43
|
+
},
|
|
44
|
+
health: async () => {
|
|
45
|
+
await Promise.resolve();
|
|
46
|
+
const down = targets.flatMap((entry) => entry.status === "ready" ? [] : [`${entry.target}: ${entry.status.unavailable}`]);
|
|
47
|
+
return {
|
|
48
|
+
ok: down.length < targets.length,
|
|
49
|
+
...down.length > 0 ? { detail: down.join("; ") } : {}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export { createTargetOffers };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=capture-target-offers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-target-offers.mjs","names":[],"sources":["../../src/adapters/capture-target-offers.ts"],"sourcesContent":["/**\n * What a runner offers right now, shared by the runners (ADR 0007): the targets it declared, whether\n * each can render, and the lifecycle that keeps that honest. A launch failure marks its target\n * unavailable from then on.\n */\nimport { TargetLaunchError, type CaptureTarget, type RunnerTarget } from \"./capture-target.ts\";\nimport type { AdapterLifecycle } from \"./metadata.ts\";\n\n/** A runner's live target list. */\nexport interface TargetOffers {\n /** First declared target: what a project with no `browsers` setting resolves to. */\n readonly defaultTarget: CaptureTarget;\n /** The targets with their current status; reads `metadata.targets`. */\n current(): readonly RunnerTarget[];\n /**\n * Wrap `launch` so a target the runner does not offer fails with a {@link TargetLaunchError}, and\n * a launch that fails marks its target unavailable with the launch error as the reason (not a\n * transient one: a remote service that is down stays offered).\n */\n guard<T, Rest extends unknown[]>(\n launch: (target: CaptureTarget, ...rest: Rest) => Promise<T>,\n ): (target: CaptureTarget, ...rest: Rest) => Promise<T>;\n /** Lifecycle whose `setup` replaces the statuses with what `verify` finds, and `health` reports them. */\n lifecycle(verify: () => Promise<readonly RunnerTarget[]>): AdapterLifecycle;\n}\n\n/**\n * Offer `declared`, default first. Until verified every target reads as ready, so a runner used\n * without `lifecycle.setup` behaves as before and a failed launch still marks its target.\n */\nexport function createTargetOffers(declared: readonly RunnerTarget[]): TargetOffers {\n let targets: readonly RunnerTarget[] = declared;\n const first = declared[0];\n if (first === undefined) {\n throw new Error(\"A runner must offer at least one target\");\n }\n const fail = (target: CaptureTarget, reason: string): void => {\n targets = targets.map((entry) =>\n entry.target === target ? { ...entry, status: { unavailable: reason } } : entry,\n );\n };\n return {\n defaultTarget: first.target,\n current: () => targets,\n guard:\n (launch) =>\n async (target, ...rest) => {\n if (!targets.some((entry) => entry.target === target)) {\n throw new TargetLaunchError(target, \"not offered by this runner\");\n }\n try {\n return await launch(target, ...rest);\n } catch (error) {\n if (error instanceof TargetLaunchError && !error.transient) {\n fail(target, error.reason);\n }\n throw error;\n }\n },\n lifecycle: (verify) => ({\n setup: async () => {\n targets = await verify();\n },\n teardown: async () => {\n await Promise.resolve();\n },\n health: async () => {\n await Promise.resolve();\n const down = targets.flatMap((entry) =>\n entry.status === \"ready\" ? [] : [`${entry.target}: ${entry.status.unavailable}`],\n );\n return {\n ok: down.length < targets.length,\n ...(down.length > 0 ? { detail: down.join(\"; \") } : {}),\n };\n },\n }),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AA8BA,SAAgB,mBAAmB,UAAiD;CAClF,IAAI,UAAmC;CACvC,MAAM,QAAQ,SAAS;CACvB,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,MAAM,yCAAyC;CAE3D,MAAM,QAAQ,QAAuB,WAAyB;EAC5D,UAAU,QAAQ,KAAK,UACrB,MAAM,WAAW,SAAS;GAAE,GAAG;GAAO,QAAQ,EAAE,aAAa,OAAO;EAAE,IAAI,KAC5E;CACF;CACA,OAAO;EACL,eAAe,MAAM;EACrB,eAAe;EACf,QACG,WACD,OAAO,QAAQ,GAAG,SAAS;GACzB,IAAI,CAAC,QAAQ,MAAM,UAAU,MAAM,WAAW,MAAM,GAClD,MAAM,IAAI,kBAAkB,QAAQ,4BAA4B;GAElE,IAAI;IACF,OAAO,MAAM,OAAO,QAAQ,GAAG,IAAI;GACrC,SAAS,OAAO;IACd,IAAI,iBAAiB,qBAAqB,CAAC,MAAM,WAC/C,KAAK,QAAQ,MAAM,MAAM;IAE3B,MAAM;GACR;EACF;EACF,YAAY,YAAY;GACtB,OAAO,YAAY;IACjB,UAAU,MAAM,OAAO;GACzB;GACA,UAAU,YAAY;IACpB,MAAM,QAAQ,QAAQ;GACxB;GACA,QAAQ,YAAY;IAClB,MAAM,QAAQ,QAAQ;IACtB,MAAM,OAAO,QAAQ,SAAS,UAC5B,MAAM,WAAW,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,OAAO,IAAI,MAAM,OAAO,aAAa,CACjF;IACA,OAAO;KACL,IAAI,KAAK,SAAS,QAAQ;KAC1B,GAAI,KAAK,SAAS,IAAI,EAAE,QAAQ,KAAK,KAAK,IAAI,EAAE,IAAI,CAAC;IACvD;GACF;EACF;CACF;AACF"}
|