@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
package/dist/models/webhook.mjs
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
+
import { randomToken } from "../utils/hash.mjs";
|
|
4
5
|
import { decryptCredential, encrypt } from "../utils/encrypt.mjs";
|
|
5
6
|
import { ulid } from "../utils/ulid.mjs";
|
|
6
|
-
import {
|
|
7
|
-
|
|
7
|
+
import { col } from "./columns.mjs";
|
|
8
|
+
import { eq } from "drizzle-orm";
|
|
9
|
+
// src/models/webhook.ts
|
|
8
10
|
/** Webhook subscriptions for project events. */
|
|
9
11
|
/** Data operations for webhook subscriptions. */
|
|
10
12
|
var WebhookModel = class {
|
|
11
|
-
db;
|
|
12
13
|
tables;
|
|
13
14
|
secret;
|
|
15
|
+
db;
|
|
14
16
|
/**
|
|
15
17
|
* @param db - Database adapter.
|
|
16
18
|
* @param tables - Table handles.
|
|
@@ -23,7 +25,34 @@ var WebhookModel = class {
|
|
|
23
25
|
}
|
|
24
26
|
/** List all webhooks for a project. */
|
|
25
27
|
async list(projectId) {
|
|
26
|
-
return await this.db.list(this.tables.webhooks, { where: eq(
|
|
28
|
+
return await this.db.list(this.tables.webhooks, { where: eq(col(this.tables.webhooks, "projectId"), projectId) });
|
|
29
|
+
}
|
|
30
|
+
/** Validate a webhook target URL; returns an error message, or null when acceptable. */
|
|
31
|
+
static urlError(url) {
|
|
32
|
+
if (!url) return "A valid URL is required";
|
|
33
|
+
let protocol;
|
|
34
|
+
try {
|
|
35
|
+
({protocol} = new URL(url));
|
|
36
|
+
} catch {
|
|
37
|
+
return "Enter a valid URL";
|
|
38
|
+
}
|
|
39
|
+
return protocol === "https:" || protocol === "http:" ? null : "URL must use http or https";
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a webhook with a freshly generated `whsec_` signing secret.
|
|
43
|
+
*
|
|
44
|
+
* @returns The stored webhook and the plaintext secret (shown to the user once).
|
|
45
|
+
*/
|
|
46
|
+
async issue(projectId, input) {
|
|
47
|
+
const secret = randomToken("whsec_").value;
|
|
48
|
+
return {
|
|
49
|
+
webhook: await this.create(projectId, {
|
|
50
|
+
url: input.url,
|
|
51
|
+
events: input.events,
|
|
52
|
+
secret
|
|
53
|
+
}),
|
|
54
|
+
secret
|
|
55
|
+
};
|
|
27
56
|
}
|
|
28
57
|
/**
|
|
29
58
|
* Create a webhook subscription for a project.
|
|
@@ -51,7 +80,7 @@ var WebhookModel = class {
|
|
|
51
80
|
/** Fetch a webhook by id scoped to a project, or null if not found. */
|
|
52
81
|
async get(projectId, id) {
|
|
53
82
|
const found = (await this.db.list(this.tables.webhooks, {
|
|
54
|
-
where: eq(
|
|
83
|
+
where: eq(col(this.tables.webhooks, "id"), id),
|
|
55
84
|
limit: 1
|
|
56
85
|
}))[0] ?? null;
|
|
57
86
|
return found?.projectId === projectId ? found : null;
|
|
@@ -72,7 +101,6 @@ var WebhookModel = class {
|
|
|
72
101
|
}
|
|
73
102
|
}
|
|
74
103
|
};
|
|
75
|
-
//#endregion
|
|
76
104
|
export { WebhookModel };
|
|
77
105
|
|
|
78
106
|
//# sourceMappingURL=webhook.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.mjs","names":[],"sources":["../../src/models/webhook.ts"],"sourcesContent":["/** Webhook subscriptions for project events. */\nimport { eq
|
|
1
|
+
{"version":3,"file":"webhook.mjs","names":[],"sources":["../../src/models/webhook.ts"],"sourcesContent":["/** Webhook subscriptions for project events. */\nimport { eq } from \"drizzle-orm\";\nimport type { Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { Webhook } from \"../schema/webhook.ts\";\nimport { decryptCredential, encrypt, type SecretInput } from \"../utils/encrypt.ts\";\nimport { randomToken } from \"../utils/hash.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\nimport { col } from \"./columns.ts\";\n\n/** Tables required by {@link WebhookModel}. */\nexport interface WebhookTables {\n webhooks: Table;\n}\n\n/** Data operations for webhook subscriptions. */\nexport class WebhookModel {\n private readonly tables: WebhookTables;\n private readonly secret?: SecretInput;\n private readonly db: DatabaseAdapter;\n\n /**\n * @param db - Database adapter.\n * @param tables - Table handles.\n * @param secret - Server secret for webhook-secret encryption (throws on write/decrypt when unset).\n */\n constructor(db: DatabaseAdapter, tables?: WebhookTables, secret?: SecretInput) {\n this.db = db;\n this.tables = tables ?? { webhooks: db.tables.webhooks };\n this.secret = secret;\n }\n\n /** List all webhooks for a project. */\n async list(projectId: string): Promise<Webhook[]> {\n return (await this.db.list(this.tables.webhooks, {\n where: eq(col(this.tables.webhooks, \"projectId\"), projectId),\n })) as unknown as Webhook[];\n }\n\n /** Validate a webhook target URL; returns an error message, or null when acceptable. */\n static urlError(url: string | undefined): string | null {\n if (!url) {\n return \"A valid URL is required\";\n }\n let protocol: string;\n try {\n ({ protocol } = new URL(url));\n } catch {\n return \"Enter a valid URL\";\n }\n return protocol === \"https:\" || protocol === \"http:\" ? null : \"URL must use http or https\";\n }\n\n /**\n * Create a webhook with a freshly generated `whsec_` signing secret.\n *\n * @returns The stored webhook and the plaintext secret (shown to the user once).\n */\n async issue(\n projectId: string,\n input: { url: string; events?: string[] },\n ): Promise<{ webhook: Webhook; secret: string }> {\n const secret = randomToken(\"whsec_\").value;\n const webhook = await this.create(projectId, { url: input.url, events: input.events, secret });\n return { webhook, secret };\n }\n\n /**\n * Create a webhook subscription for a project.\n *\n * @param projectId - Project ID.\n * @param input - Webhook creation input.\n * @returns The created webhook.\n */\n async create(projectId: string, input: WebhookCreateInput): Promise<Webhook> {\n const now = new Date().toISOString();\n return (await this.db.insert(this.tables.webhooks, {\n id: ulid(),\n projectId,\n url: input.url,\n secretEncrypted: encrypt(this.secret, input.secret),\n events: input.events && input.events.length > 0 ? JSON.stringify(input.events) : null,\n createdAt: now,\n updatedAt: now,\n })) as unknown as Webhook;\n }\n\n /** Decrypt the secret for a stored row (in memory only, at send time). */\n decryptSecret(row: Webhook): string {\n return decryptCredential(this.secret, row.secretEncrypted);\n }\n\n /** Fetch a webhook by id scoped to a project, or null if not found. */\n async get(projectId: string, id: string): Promise<Webhook | null> {\n const rows = (await this.db.list(this.tables.webhooks, {\n where: eq(col(this.tables.webhooks, \"id\"), id),\n limit: 1,\n })) as unknown as Webhook[];\n const found = rows[0] ?? null;\n return found?.projectId === projectId ? found : null;\n }\n\n /** Remove a webhook if it belongs to the given project. */\n async remove(projectId: string, id: string): Promise<void> {\n const existing = await this.get(projectId, id);\n if (existing) {\n await this.db.remove(this.tables.webhooks, existing.id);\n }\n }\n\n /** Decode the JSON-serialized event list of a webhook. */\n static eventsOf(webhook: Webhook): string[] {\n if (!webhook.events) {\n return [];\n }\n try {\n const parsed: unknown = JSON.parse(webhook.events);\n return Array.isArray(parsed)\n ? parsed.filter((event): event is string => typeof event === \"string\")\n : [];\n } catch {\n return [];\n }\n }\n}\n\n/** Input for creating a webhook subscription. */\nexport interface WebhookCreateInput {\n url: string;\n events?: string[];\n secret: string;\n}\n"],"mappings":";;;;;;;;;;;AAgBA,IAAa,eAAb,MAA0B;CACxB;CACA;CACA;;;;;;CAOA,YAAY,IAAqB,QAAwB,QAAsB;EAC7E,KAAK,KAAK;EACV,KAAK,SAAS,UAAU,EAAE,UAAU,GAAG,OAAO,SAAS;EACvD,KAAK,SAAS;CAChB;;CAGA,MAAM,KAAK,WAAuC;EAChD,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,UAAU,EAC/C,OAAO,GAAG,IAAI,KAAK,OAAO,UAAU,WAAW,GAAG,SAAS,EAC7D,CAAC;CACH;;CAGA,OAAO,SAAS,KAAwC;EACtD,IAAI,CAAC,KACH,OAAO;EAET,IAAI;EACJ,IAAI;GACF,CAAC,CAAE,YAAa,IAAI,IAAI,GAAG;EAC7B,QAAQ;GACN,OAAO;EACT;EACA,OAAO,aAAa,YAAY,aAAa,UAAU,OAAO;CAChE;;;;;;CAOA,MAAM,MACJ,WACA,OAC+C;EAC/C,MAAM,SAAS,YAAY,QAAQ,CAAC,CAAC;EAErC,OAAO;GAAE,SAAA,MADa,KAAK,OAAO,WAAW;IAAE,KAAK,MAAM;IAAK,QAAQ,MAAM;IAAQ;GAAO,CAAC;GAC3E;EAAO;CAC3B;;;;;;;;CASA,MAAM,OAAO,WAAmB,OAA6C;EAC3E,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU;GACjD,IAAI,KAAK;GACT;GACA,KAAK,MAAM;GACX,iBAAiB,QAAQ,KAAK,QAAQ,MAAM,MAAM;GAClD,QAAQ,MAAM,UAAU,MAAM,OAAO,SAAS,IAAI,KAAK,UAAU,MAAM,MAAM,IAAI;GACjF,WAAW;GACX,WAAW;EACb,CAAC;CACH;;CAGA,cAAc,KAAsB;EAClC,OAAO,kBAAkB,KAAK,QAAQ,IAAI,eAAe;CAC3D;;CAGA,MAAM,IAAI,WAAmB,IAAqC;EAKhE,MAAM,SAAQ,MAJM,KAAK,GAAG,KAAK,KAAK,OAAO,UAAU;GACrD,OAAO,GAAG,IAAI,KAAK,OAAO,UAAU,IAAI,GAAG,EAAE;GAC7C,OAAO;EACT,CAAC,EAAA,CACkB,MAAM;EACzB,OAAO,OAAO,cAAc,YAAY,QAAQ;CAClD;;CAGA,MAAM,OAAO,WAAmB,IAA2B;EACzD,MAAM,WAAW,MAAM,KAAK,IAAI,WAAW,EAAE;EAC7C,IAAI,UACF,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU,SAAS,EAAE;CAE1D;;CAGA,OAAO,SAAS,SAA4B;EAC1C,IAAI,CAAC,QAAQ,QACX,OAAO,CAAC;EAEV,IAAI;GACF,MAAM,SAAkB,KAAK,MAAM,QAAQ,MAAM;GACjD,OAAO,MAAM,QAAQ,MAAM,IACvB,OAAO,QAAQ,UAA2B,OAAO,UAAU,QAAQ,IACnE,CAAC;EACP,QAAQ;GACN,OAAO,CAAC;EACV;CACF;AACF"}
|
package/dist/models.d.mts
CHANGED
|
@@ -5,18 +5,44 @@ import { BuildCreateInput, BuildListFilter, BuildModel, isPublicBuild } from "./
|
|
|
5
5
|
import { AttemptLogRecorder, CaptureAttemptModel, CaptureAttemptTables, emitAttemptLog } from "./models/capture-attempt.mjs";
|
|
6
6
|
import { CaptureLogModel, CaptureLogTables } from "./models/capture-log.mjs";
|
|
7
7
|
import { ProjectCreateInput, ProjectModel } from "./models/project.mjs";
|
|
8
|
+
import { BaselineWriteConflict } from "./models/baseline-conflict.mjs";
|
|
9
|
+
import { BaselineStatus, NO_BASELINE, baselineStatus, isBaselineDrifted } from "./models/baseline-status.mjs";
|
|
10
|
+
import { BaselineApprovalConflict } from "./models/baseline-approval.mjs";
|
|
8
11
|
import { BaselineModel } from "./models/baseline.mjs";
|
|
9
12
|
import { SnapshotCreateInput, SnapshotModel } from "./models/snapshot.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
13
|
+
import { AttemptClaim, CaptureJobModel, CaptureJobTables, NewCaptureJob, TERMINAL_JOB_STATUSES, attemptRowId, isTerminalJob, parseAttemptRowId } from "./models/capture-job.mjs";
|
|
14
|
+
import { BuildComponentInput, BuildComponentModel, BuildComponentTables } from "./models/build-component.mjs";
|
|
15
|
+
import { ComponentHistoryRow, ComponentPresence, componentHistory, componentPresence, worstStatus } from "./models/component.mjs";
|
|
16
|
+
import { BaselineOriginReader, resolveBaselineOrigin } from "./models/baseline-origin.mjs";
|
|
17
|
+
import { BASELINE_ARCHIVE_FORMAT, BASELINE_ARCHIVE_LIMITS, BASELINE_ARCHIVE_VERSION, BaselineArchiveError, BaselineManifest, BaselineManifestEntry } from "./models/baseline-archive.mjs";
|
|
18
|
+
import { BaselineExportOptions } from "./models/baseline-export.mjs";
|
|
19
|
+
import { BaselineImportResult, BaselineTransferModel } from "./models/baseline-transfer.mjs";
|
|
20
|
+
import { CaptureShardModel, CaptureShardTables } from "./models/capture-shard.mjs";
|
|
21
|
+
import { AiBudgetAlertModel, AiBudgetAlertTables } from "./models/ai-budget-alert.mjs";
|
|
22
|
+
import { AiUsageInput, AiUsageModel, AiUsageTables } from "./models/ai-usage.mjs";
|
|
23
|
+
import { InsightModel, InsightResultInput, InsightStartInput, InsightStartResult, InsightTables } from "./models/insight.mjs";
|
|
24
|
+
import { InheritedRatio, RECENT_BUILDS_FOR_INHERITED_RATIO, averageInheritedRatio } from "./models/inherited-ratio.mjs";
|
|
25
|
+
import { BuildReviewModel, BuildReviewTables } from "./models/build-review.mjs";
|
|
26
|
+
import { ReviewStatusInput, deriveReviewStatus, latestVerdicts } from "./models/build-review-status.mjs";
|
|
27
|
+
import { BuildChangeset, ChangedComponent, Changeset, ChangesetComponent, changesetOf, computeChangeset, findChangesetBaseline } from "./models/changeset.mjs";
|
|
12
28
|
import { CommentCreateInput, CommentModel } from "./models/comment.mjs";
|
|
29
|
+
import { acceptPendingWithoutWork } from "./models/review-switch-off.mjs";
|
|
30
|
+
import { ConnectionModel, ConnectionTables } from "./models/connections.mjs";
|
|
31
|
+
import { DesignModel, DesignTables } from "./models/design.mjs";
|
|
32
|
+
import { DesignCredentialStatus, DesignResolution, DesignSource, normalizeImportPath, resolveDesigns } from "./models/design-resolve.mjs";
|
|
33
|
+
import { DesignCredentialModel, DesignCredentialTables, PROJECT_SCOPE } from "./models/design-credentials.mjs";
|
|
34
|
+
import { DesignNodeModel, DesignNodeTables, RefreshOptions } from "./models/design-nodes.mjs";
|
|
35
|
+
import { DESIGN_TTL_MS, credentialDaysLeft, isDesignStale } from "./models/design-health.mjs";
|
|
13
36
|
import { LabelModel } from "./models/label.mjs";
|
|
37
|
+
import { PackageUsageInput, PackageUsageModel, PackageUsageTables, UpstreamStory, matchUpstreamStory } from "./models/usage.mjs";
|
|
14
38
|
import { MemberModel } from "./models/member.mjs";
|
|
15
|
-
import { NotificationChannelCreateInput, NotificationChannelModel, NotificationChannelTables } from "./models/notification-channel.mjs";
|
|
39
|
+
import { ChannelValidation, NotificationChannelCreateInput, NotificationChannelModel, NotificationChannelTables } from "./models/notification-channel.mjs";
|
|
16
40
|
import { NotificationSubscriptionInput, NotificationSubscriptionModel, NotificationSubscriptionTables } from "./models/notification-subscription.mjs";
|
|
17
41
|
import { ProjectGroupMappingModel } from "./models/project-group-mapping.mjs";
|
|
18
42
|
import { TokenModel } from "./models/token.mjs";
|
|
19
43
|
import { UserModel } from "./models/user.mjs";
|
|
20
44
|
import { ContentRefModel } from "./models/content-ref.mjs";
|
|
21
45
|
import { CredentialProbe, ReencryptResult, UnreadableCredential, probeCredentials, reencryptCredentials } from "./models/credentials.mjs";
|
|
22
|
-
|
|
46
|
+
import { SiteSettingsModel, SiteSettingsTables } from "./models/site-settings.mjs";
|
|
47
|
+
import { PUBLIC_ORIGIN_KEY, PublicOriginOptions, PublicOriginResolver, PublicOriginSource, ResolvedPublicOrigin, StoredPublicOrigin, createPublicOriginResolver } from "./models/public-origin.mjs";
|
|
48
|
+
export { AiBudgetAlertModel, type AiBudgetAlertTables, type AiUsageInput, AiUsageModel, type AiUsageTables, type AttemptClaim, type AttemptLogRecorder, BASELINE_ARCHIVE_FORMAT, BASELINE_ARCHIVE_LIMITS, BASELINE_ARCHIVE_VERSION, BaselineApprovalConflict, BaselineArchiveError, type BaselineExportOptions, type BaselineImportResult, type BaselineManifest, type BaselineManifestEntry, BaselineModel, type BaselineOriginReader, type BaselineStatus, BaselineTransferModel, BaselineWriteConflict, type BuildChangeset, type BuildComponentInput, BuildComponentModel, type BuildComponentTables, type BuildCreateInput, type BuildListFilter, BuildModel, BuildReviewModel, type BuildReviewTables, CaptureAttemptModel, type CaptureAttemptTables, CaptureJobModel, type CaptureJobTables, CaptureLogModel, type CaptureLogTables, CaptureShardModel, type CaptureShardTables, type ChangedComponent, type Changeset, type ChangesetComponent, type ChannelValidation, type CommentCreateInput, CommentModel, type ComponentHistoryRow, type ComponentPresence, ConnectionModel, type ConnectionTables, ContentRefModel, type CredentialProbe, DESIGN_TTL_MS, DesignCredentialModel, type DesignCredentialStatus, type DesignCredentialTables, DesignModel, DesignNodeModel, type DesignNodeTables, type DesignResolution, type DesignSource, type DesignTables, type InheritedRatio, InsightModel, type InsightResultInput, type InsightStartInput, type InsightStartResult, type InsightTables, LabelModel, MemberModel, NO_BASELINE, type NewCaptureJob, type NotificationChannelCreateInput, NotificationChannelModel, type NotificationChannelTables, type NotificationSubscriptionInput, NotificationSubscriptionModel, type NotificationSubscriptionTables, PROJECT_SCOPE, PUBLIC_ORIGIN_KEY, type PackageUsageInput, PackageUsageModel, type PackageUsageTables, type ProjectCreateInput, ProjectGroupMappingModel, ProjectModel, type PublicOriginOptions, type PublicOriginResolver, type PublicOriginSource, RECENT_BUILDS_FOR_INHERITED_RATIO, type ReencryptResult, type RefreshOptions, type ResolvedPublicOrigin, type ReviewStatusInput, SiteSettingsModel, type SiteSettingsTables, type SnapshotCreateInput, SnapshotModel, type StoredPublicOrigin, TERMINAL_JOB_STATUSES, TokenModel, type UnreadableCredential, type UpstreamStory, UserModel, type WebhookCreateInput, WebhookModel, acceptPendingWithoutWork, attemptRowId, averageInheritedRatio, baselineStatus, changesetOf, componentHistory, componentPresence, computeChangeset, createPublicOriginResolver, credentialDaysLeft, deriveReviewStatus, emitAttemptLog, findChangesetBaseline, isBaselineDrifted, isDesignStale, isPublicBuild, isTerminalJob, latestVerdicts, matchUpstreamStory, normalizeImportPath, parseAttemptRowId, probeCredentials, reencryptCredentials, resolveBaselineOrigin, resolveDesigns, worstStatus };
|
package/dist/models.mjs
CHANGED
|
@@ -2,22 +2,47 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { WebhookModel } from "./models/webhook.mjs";
|
|
5
|
-
import { BuildModel, isPublicBuild } from "./models/build.mjs";
|
|
6
5
|
import { CaptureAttemptModel, emitAttemptLog } from "./models/capture-attempt.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { BuildModel, isPublicBuild } from "./models/build.mjs";
|
|
7
|
+
import { BaselineWriteConflict } from "./models/baseline-conflict.mjs";
|
|
9
8
|
import { NO_BASELINE, baselineStatus, isBaselineDrifted } from "./models/baseline-status.mjs";
|
|
9
|
+
import { BaselineApprovalConflict } from "./models/baseline-approval.mjs";
|
|
10
|
+
import { BaselineModel } from "./models/baseline.mjs";
|
|
10
11
|
import { SnapshotModel } from "./models/snapshot.mjs";
|
|
11
|
-
import {
|
|
12
|
+
import { CaptureShardModel } from "./models/capture-shard.mjs";
|
|
13
|
+
import { ProjectModel } from "./models/project.mjs";
|
|
14
|
+
import { deriveReviewStatus, latestVerdicts } from "./models/build-review-status.mjs";
|
|
15
|
+
import { BuildReviewModel } from "./models/build-review.mjs";
|
|
16
|
+
import { NotificationChannelModel } from "./models/notification-channel.mjs";
|
|
17
|
+
import { CaptureJobModel, TERMINAL_JOB_STATUSES, attemptRowId, isTerminalJob, parseAttemptRowId } from "./models/capture-job.mjs";
|
|
18
|
+
import { SiteSettingsModel } from "./models/site-settings.mjs";
|
|
19
|
+
import { PUBLIC_ORIGIN_KEY, createPublicOriginResolver } from "./models/public-origin.mjs";
|
|
12
20
|
import { CaptureLogModel } from "./models/capture-log.mjs";
|
|
21
|
+
import { BuildComponentModel } from "./models/build-component.mjs";
|
|
22
|
+
import { normalizeImportPath, resolveDesigns } from "./models/design-resolve.mjs";
|
|
23
|
+
import { resolveBaselineOrigin } from "./models/baseline-origin.mjs";
|
|
24
|
+
import { BASELINE_ARCHIVE_FORMAT, BASELINE_ARCHIVE_LIMITS, BASELINE_ARCHIVE_VERSION, BaselineArchiveError } from "./models/baseline-archive.mjs";
|
|
25
|
+
import { BaselineTransferModel } from "./models/baseline-transfer.mjs";
|
|
26
|
+
import { AiBudgetAlertModel } from "./models/ai-budget-alert.mjs";
|
|
27
|
+
import { AiUsageModel } from "./models/ai-usage.mjs";
|
|
28
|
+
import { InsightModel } from "./models/insight.mjs";
|
|
29
|
+
import { RECENT_BUILDS_FOR_INHERITED_RATIO, averageInheritedRatio } from "./models/inherited-ratio.mjs";
|
|
30
|
+
import { changesetOf, computeChangeset, findChangesetBaseline } from "./models/changeset.mjs";
|
|
13
31
|
import { CommentModel } from "./models/comment.mjs";
|
|
32
|
+
import { acceptPendingWithoutWork } from "./models/review-switch-off.mjs";
|
|
33
|
+
import { componentHistory, componentPresence, worstStatus } from "./models/component.mjs";
|
|
34
|
+
import { ConnectionModel } from "./models/connections.mjs";
|
|
35
|
+
import { DesignModel } from "./models/design.mjs";
|
|
36
|
+
import { DesignCredentialModel, PROJECT_SCOPE } from "./models/design-credentials.mjs";
|
|
37
|
+
import { DESIGN_TTL_MS, credentialDaysLeft, isDesignStale } from "./models/design-health.mjs";
|
|
38
|
+
import { DesignNodeModel } from "./models/design-nodes.mjs";
|
|
14
39
|
import { LabelModel } from "./models/label.mjs";
|
|
40
|
+
import { PackageUsageModel, matchUpstreamStory } from "./models/usage.mjs";
|
|
15
41
|
import { MemberModel } from "./models/member.mjs";
|
|
16
|
-
import { NotificationChannelModel } from "./models/notification-channel.mjs";
|
|
17
42
|
import { NotificationSubscriptionModel } from "./models/notification-subscription.mjs";
|
|
18
43
|
import { ProjectGroupMappingModel } from "./models/project-group-mapping.mjs";
|
|
19
44
|
import { TokenModel } from "./models/token.mjs";
|
|
20
45
|
import { UserModel } from "./models/user.mjs";
|
|
21
46
|
import { ContentRefModel } from "./models/content-ref.mjs";
|
|
22
47
|
import { probeCredentials, reencryptCredentials } from "./models/credentials.mjs";
|
|
23
|
-
export { BaselineModel, BuildModel, CaptureAttemptModel, CaptureLogModel, CommentModel, ContentRefModel, LabelModel, MemberModel, NO_BASELINE, NotificationChannelModel, NotificationSubscriptionModel, ProjectGroupMappingModel, ProjectModel, SnapshotModel,
|
|
48
|
+
export { AiBudgetAlertModel, AiUsageModel, BASELINE_ARCHIVE_FORMAT, BASELINE_ARCHIVE_LIMITS, BASELINE_ARCHIVE_VERSION, BaselineApprovalConflict, BaselineArchiveError, BaselineModel, BaselineTransferModel, BaselineWriteConflict, BuildComponentModel, BuildModel, BuildReviewModel, CaptureAttemptModel, CaptureJobModel, CaptureLogModel, CaptureShardModel, CommentModel, ConnectionModel, ContentRefModel, DESIGN_TTL_MS, DesignCredentialModel, DesignModel, DesignNodeModel, InsightModel, LabelModel, MemberModel, NO_BASELINE, NotificationChannelModel, NotificationSubscriptionModel, PROJECT_SCOPE, PUBLIC_ORIGIN_KEY, PackageUsageModel, ProjectGroupMappingModel, ProjectModel, RECENT_BUILDS_FOR_INHERITED_RATIO, SiteSettingsModel, SnapshotModel, TERMINAL_JOB_STATUSES, TokenModel, UserModel, WebhookModel, acceptPendingWithoutWork, attemptRowId, averageInheritedRatio, baselineStatus, changesetOf, componentHistory, componentPresence, computeChangeset, createPublicOriginResolver, credentialDaysLeft, deriveReviewStatus, emitAttemptLog, findChangesetBaseline, isBaselineDrifted, isDesignStale, isPublicBuild, isTerminalJob, latestVerdicts, matchUpstreamStory, normalizeImportPath, parseAttemptRowId, probeCredentials, reencryptCredentials, resolveBaselineOrigin, resolveDesigns, worstStatus };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { ShelfOptions } from "./config.mjs";
|
|
4
|
+
/** Where capture scratch lives when `config.scratchDir` is not set. */
|
|
5
|
+
declare const DEFAULT_SCRATCH_DIR: string;
|
|
6
|
+
/**
|
|
7
|
+
* Validate and complete the options.
|
|
8
|
+
*
|
|
9
|
+
* - `testing.compare.threads` must be a non-negative integer.
|
|
10
|
+
* - `notifications.config` must match its schema (it used to live in `ShelfConfig`, which validated it).
|
|
11
|
+
* - `config.scratchDir` defaults to {@link DEFAULT_SCRATCH_DIR}: publishing extracts zips there,
|
|
12
|
+
* with or without `testing`.
|
|
13
|
+
*/
|
|
14
|
+
declare function resolveShelfOptions(options: ShelfOptions): ShelfOptions;
|
|
15
|
+
export { DEFAULT_SCRATCH_DIR, resolveShelfOptions };
|
|
16
|
+
//# sourceMappingURL=options.d.mts.map
|
package/dist/options.mjs
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { notificationsConfigSchema } from "./config.mjs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
// src/options.ts
|
|
7
|
+
/** Resolves `ShelfOptions` once at boot: validates `testing.compare` and fills the scratch default. */
|
|
8
|
+
/** Where capture scratch lives when `config.scratchDir` is not set. */
|
|
9
|
+
const DEFAULT_SCRATCH_DIR = join(tmpdir(), "storyshelf");
|
|
10
|
+
/**
|
|
11
|
+
* Validate and complete the options.
|
|
12
|
+
*
|
|
13
|
+
* - `testing.compare.threads` must be a non-negative integer.
|
|
14
|
+
* - `notifications.config` must match its schema (it used to live in `ShelfConfig`, which validated it).
|
|
15
|
+
* - `config.scratchDir` defaults to {@link DEFAULT_SCRATCH_DIR}: publishing extracts zips there,
|
|
16
|
+
* with or without `testing`.
|
|
17
|
+
*/
|
|
18
|
+
function resolveShelfOptions(options) {
|
|
19
|
+
assertThreads(options.testing?.compare?.threads);
|
|
20
|
+
assertTestingProcess(options.testing);
|
|
21
|
+
assertTestingBackable(options);
|
|
22
|
+
assertNotificationsConfig(options.notifications?.config);
|
|
23
|
+
if (options.config?.scratchDir !== void 0) return options;
|
|
24
|
+
return {
|
|
25
|
+
...options,
|
|
26
|
+
config: {
|
|
27
|
+
...options.config,
|
|
28
|
+
scratchDir: DEFAULT_SCRATCH_DIR
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A `testing` instance renders here, so it needs a database a long-running server can keep.
|
|
34
|
+
*/
|
|
35
|
+
function assertTestingBackable(options) {
|
|
36
|
+
if (options.testing === void 0) return;
|
|
37
|
+
if (options.database.metadata.supportsTesting === false) throw new Error(`The ${options.database.metadata.name} database cannot back testing: it is reachable only from a platform that ends the process after each request, so nothing would run capture jobs. Remove the testing option to host Storybooks only, or use a network database (Turso, Postgres, MySQL, SQLite on a volume).`);
|
|
38
|
+
}
|
|
39
|
+
function assertTestingProcess(testing) {
|
|
40
|
+
if (testing !== void 0 && testing.runner === void 0) throw new Error("testing requires testing.runner");
|
|
41
|
+
if (testing?.workerEntry !== void 0 && testing.runner === void 0) throw new Error("testing.workerEntry requires testing.runner (it is the in-process fallback)");
|
|
42
|
+
if (testing?.mode === "fork" && testing.workerEntry === void 0) throw new Error("testing.mode \"fork\" requires testing.workerEntry");
|
|
43
|
+
assertShardSize(testing);
|
|
44
|
+
assertTestingNumbers(testing);
|
|
45
|
+
}
|
|
46
|
+
/** Numeric `testing` options: concurrency, retries and the Storybook URL rate limit. */
|
|
47
|
+
function assertTestingNumbers(testing) {
|
|
48
|
+
assertConcurrency(testing?.concurrency);
|
|
49
|
+
assertRetries(testing?.retries);
|
|
50
|
+
assertLeaseSeconds(testing?.leaseSeconds);
|
|
51
|
+
assertStorybookUrlRateLimit(testing?.storybookUrlRateLimit);
|
|
52
|
+
}
|
|
53
|
+
/** A whole number of requests per minute; `0` would refuse every render. */
|
|
54
|
+
function assertStorybookUrlRateLimit(limit) {
|
|
55
|
+
if (limit !== void 0 && (!Number.isInteger(limit) || limit < 1)) throw new Error(`testing.storybookUrlRateLimit must be a positive whole number of requests per minute, got ${String(limit)}`);
|
|
56
|
+
}
|
|
57
|
+
/** Retries are counted after the first attempt: `0` runs a job once. */
|
|
58
|
+
function assertRetries(retries) {
|
|
59
|
+
if (retries !== void 0 && (!Number.isInteger(retries) || retries < 0)) throw new Error(`testing.retries must be a non-negative integer, got ${String(retries)}`);
|
|
60
|
+
}
|
|
61
|
+
/** A lease must be a positive length: `0` would expire every job at once. */
|
|
62
|
+
function assertLeaseSeconds(seconds) {
|
|
63
|
+
if (seconds !== void 0 && (!Number.isFinite(seconds) || seconds <= 0)) throw new Error(`testing.leaseSeconds must be a positive number of seconds, got ${String(seconds)}`);
|
|
64
|
+
}
|
|
65
|
+
/** `0` would deadlock the consumer. */
|
|
66
|
+
function assertConcurrency(concurrency) {
|
|
67
|
+
if (concurrency !== void 0 && (!Number.isInteger(concurrency) || concurrency < 1)) throw new Error(`testing.concurrency must be a positive integer, got ${String(concurrency)}`);
|
|
68
|
+
}
|
|
69
|
+
function assertShardSize(testing) {
|
|
70
|
+
const size = testing?.shardSize;
|
|
71
|
+
if (size === void 0) return;
|
|
72
|
+
if (!Number.isInteger(size) || size < 1) throw new Error(`testing.shardSize must be a positive integer, got ${String(size)}`);
|
|
73
|
+
if (testing?.runner === void 0) throw new Error("testing.shardSize requires testing.runner (workers set their own shardSize)");
|
|
74
|
+
}
|
|
75
|
+
function assertThreads(threads) {
|
|
76
|
+
if (threads !== void 0 && (!Number.isInteger(threads) || threads < 0)) throw new Error(`testing.compare.threads must be a non-negative integer, got ${String(threads)}`);
|
|
77
|
+
}
|
|
78
|
+
function assertNotificationsConfig(config) {
|
|
79
|
+
if (config === void 0) return;
|
|
80
|
+
const result = notificationsConfigSchema.safeParse(config);
|
|
81
|
+
if (!result.success) {
|
|
82
|
+
const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
83
|
+
throw new Error(`Invalid notifications.config: ${issues}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export { DEFAULT_SCRATCH_DIR, resolveShelfOptions };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=options.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.mjs","names":[],"sources":["../src/options.ts"],"sourcesContent":["/** Resolves `ShelfOptions` once at boot: validates `testing.compare` and fills the scratch default. */\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { notificationsConfigSchema, type ShelfOptions } from \"./config.ts\";\n\n/** Where capture scratch lives when `config.scratchDir` is not set. */\nexport const DEFAULT_SCRATCH_DIR: string = join(tmpdir(), \"storyshelf\");\n\n/**\n * Validate and complete the options.\n *\n * - `testing.compare.threads` must be a non-negative integer.\n * - `notifications.config` must match its schema (it used to live in `ShelfConfig`, which validated it).\n * - `config.scratchDir` defaults to {@link DEFAULT_SCRATCH_DIR}: publishing extracts zips there,\n * with or without `testing`.\n */\nexport function resolveShelfOptions(options: ShelfOptions): ShelfOptions {\n assertThreads(options.testing?.compare?.threads);\n assertTestingProcess(options.testing);\n assertTestingBackable(options);\n assertNotificationsConfig(options.notifications?.config);\n if (options.config?.scratchDir !== undefined) {\n return options;\n }\n return { ...options, config: { ...options.config, scratchDir: DEFAULT_SCRATCH_DIR } };\n}\n\n/**\n * A `testing` instance renders here, so it needs a database a long-running server can keep.\n */\nfunction assertTestingBackable(options: ShelfOptions): void {\n if (options.testing === undefined) {\n return;\n }\n if (options.database.metadata.supportsTesting === false) {\n throw new Error(\n `The ${options.database.metadata.name} database cannot back testing: it is reachable only ` +\n `from a platform that ends the process after each request, so nothing would run capture ` +\n `jobs. Remove the testing option to host Storybooks only, or use a network database ` +\n `(Turso, Postgres, MySQL, SQLite on a volume).`,\n );\n }\n}\n\nfunction assertTestingProcess(testing: ShelfOptions[\"testing\"]): void {\n if (testing !== undefined && testing.runner === undefined) {\n throw new Error(\"testing requires testing.runner\");\n }\n if (testing?.workerEntry !== undefined && testing.runner === undefined) {\n throw new Error(\"testing.workerEntry requires testing.runner (it is the in-process fallback)\");\n }\n if (testing?.mode === \"fork\" && testing.workerEntry === undefined) {\n throw new Error('testing.mode \"fork\" requires testing.workerEntry');\n }\n assertShardSize(testing);\n assertTestingNumbers(testing);\n}\n\n/** Numeric `testing` options: concurrency, retries and the Storybook URL rate limit. */\nfunction assertTestingNumbers(testing: ShelfOptions[\"testing\"]): void {\n assertConcurrency(testing?.concurrency);\n assertRetries(testing?.retries);\n assertLeaseSeconds(testing?.leaseSeconds);\n assertStorybookUrlRateLimit(testing?.storybookUrlRateLimit);\n}\n\n/** A whole number of requests per minute; `0` would refuse every render. */\nfunction assertStorybookUrlRateLimit(limit: number | undefined): void {\n if (limit !== undefined && (!Number.isInteger(limit) || limit < 1)) {\n throw new Error(\n `testing.storybookUrlRateLimit must be a positive whole number of requests per minute, got ${String(limit)}`,\n );\n }\n}\n\n/** Retries are counted after the first attempt: `0` runs a job once. */\nfunction assertRetries(retries: number | undefined): void {\n if (retries !== undefined && (!Number.isInteger(retries) || retries < 0)) {\n throw new Error(`testing.retries must be a non-negative integer, got ${String(retries)}`);\n }\n}\n\n/** A lease must be a positive length: `0` would expire every job at once. */\nfunction assertLeaseSeconds(seconds: number | undefined): void {\n if (seconds !== undefined && (!Number.isFinite(seconds) || seconds <= 0)) {\n throw new Error(\n `testing.leaseSeconds must be a positive number of seconds, got ${String(seconds)}`,\n );\n }\n}\n\n/** `0` would deadlock the consumer. */\nfunction assertConcurrency(concurrency: number | undefined): void {\n if (concurrency !== undefined && (!Number.isInteger(concurrency) || concurrency < 1)) {\n throw new Error(`testing.concurrency must be a positive integer, got ${String(concurrency)}`);\n }\n}\n\nfunction assertShardSize(testing: ShelfOptions[\"testing\"]): void {\n const size = testing?.shardSize;\n if (size === undefined) {\n return;\n }\n if (!Number.isInteger(size) || size < 1) {\n throw new Error(`testing.shardSize must be a positive integer, got ${String(size)}`);\n }\n if (testing?.runner === undefined) {\n throw new Error(\"testing.shardSize requires testing.runner (workers set their own shardSize)\");\n }\n}\n\nfunction assertThreads(threads: number | undefined): void {\n if (threads !== undefined && (!Number.isInteger(threads) || threads < 0)) {\n throw new Error(\n `testing.compare.threads must be a non-negative integer, got ${String(threads)}`,\n );\n }\n}\n\nfunction assertNotificationsConfig(config: unknown): void {\n if (config === undefined) {\n return;\n }\n const result = notificationsConfigSchema.safeParse(config);\n if (!result.success) {\n const issues = result.error.issues.map((i) => `${i.path.join(\".\")}: ${i.message}`).join(\"; \");\n throw new Error(`Invalid notifications.config: ${issues}`);\n }\n}\n"],"mappings":";;;;;;;;AAMA,MAAa,sBAA8B,KAAK,OAAO,GAAG,YAAY;;;;;;;;;AAUtE,SAAgB,oBAAoB,SAAqC;CACvE,cAAc,QAAQ,SAAS,SAAS,OAAO;CAC/C,qBAAqB,QAAQ,OAAO;CACpC,sBAAsB,OAAO;CAC7B,0BAA0B,QAAQ,eAAe,MAAM;CACvD,IAAI,QAAQ,QAAQ,eAAe,KAAA,GACjC,OAAO;CAET,OAAO;EAAE,GAAG;EAAS,QAAQ;GAAE,GAAG,QAAQ;GAAQ,YAAY;EAAoB;CAAE;AACtF;;;;AAKA,SAAS,sBAAsB,SAA6B;CAC1D,IAAI,QAAQ,YAAY,KAAA,GACtB;CAEF,IAAI,QAAQ,SAAS,SAAS,oBAAoB,OAChD,MAAM,IAAI,MACR,OAAO,QAAQ,SAAS,SAAS,KAAK,4QAIxC;AAEJ;AAEA,SAAS,qBAAqB,SAAwC;CACpE,IAAI,YAAY,KAAA,KAAa,QAAQ,WAAW,KAAA,GAC9C,MAAM,IAAI,MAAM,iCAAiC;CAEnD,IAAI,SAAS,gBAAgB,KAAA,KAAa,QAAQ,WAAW,KAAA,GAC3D,MAAM,IAAI,MAAM,6EAA6E;CAE/F,IAAI,SAAS,SAAS,UAAU,QAAQ,gBAAgB,KAAA,GACtD,MAAM,IAAI,MAAM,oDAAkD;CAEpE,gBAAgB,OAAO;CACvB,qBAAqB,OAAO;AAC9B;;AAGA,SAAS,qBAAqB,SAAwC;CACpE,kBAAkB,SAAS,WAAW;CACtC,cAAc,SAAS,OAAO;CAC9B,mBAAmB,SAAS,YAAY;CACxC,4BAA4B,SAAS,qBAAqB;AAC5D;;AAGA,SAAS,4BAA4B,OAAiC;CACpE,IAAI,UAAU,KAAA,MAAc,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,IAC9D,MAAM,IAAI,MACR,6FAA6F,OAAO,KAAK,GAC3G;AAEJ;;AAGA,SAAS,cAAc,SAAmC;CACxD,IAAI,YAAY,KAAA,MAAc,CAAC,OAAO,UAAU,OAAO,KAAK,UAAU,IACpE,MAAM,IAAI,MAAM,uDAAuD,OAAO,OAAO,GAAG;AAE5F;;AAGA,SAAS,mBAAmB,SAAmC;CAC7D,IAAI,YAAY,KAAA,MAAc,CAAC,OAAO,SAAS,OAAO,KAAK,WAAW,IACpE,MAAM,IAAI,MACR,kEAAkE,OAAO,OAAO,GAClF;AAEJ;;AAGA,SAAS,kBAAkB,aAAuC;CAChE,IAAI,gBAAgB,KAAA,MAAc,CAAC,OAAO,UAAU,WAAW,KAAK,cAAc,IAChF,MAAM,IAAI,MAAM,uDAAuD,OAAO,WAAW,GAAG;AAEhG;AAEA,SAAS,gBAAgB,SAAwC;CAC/D,MAAM,OAAO,SAAS;CACtB,IAAI,SAAS,KAAA,GACX;CAEF,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,GACpC,MAAM,IAAI,MAAM,qDAAqD,OAAO,IAAI,GAAG;CAErF,IAAI,SAAS,WAAW,KAAA,GACtB,MAAM,IAAI,MAAM,6EAA6E;AAEjG;AAEA,SAAS,cAAc,SAAmC;CACxD,IAAI,YAAY,KAAA,MAAc,CAAC,OAAO,UAAU,OAAO,KAAK,UAAU,IACpE,MAAM,IAAI,MACR,+DAA+D,OAAO,OAAO,GAC/E;AAEJ;AAEA,SAAS,0BAA0B,QAAuB;CACxD,IAAI,WAAW,KAAA,GACb;CAEF,MAAM,SAAS,0BAA0B,UAAU,MAAM;CACzD,IAAI,CAAC,OAAO,SAAS;EACnB,MAAM,SAAS,OAAO,MAAM,OAAO,KAAK,MAAM,GAAG,EAAE,KAAK,KAAK,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,KAAK,IAAI;EAC5F,MAAM,IAAI,MAAM,iCAAiC,QAAQ;CAC3D;AACF"}
|
package/dist/paths.d.mts
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Path segment for a mode on a given engine. Chromium keeps the bare mode key
|
|
5
|
+
* so pre-multi-browser objects stay addressable; other engines get `~browser`.
|
|
6
|
+
*/
|
|
7
|
+
declare function modeSegment(viewport: string, browser?: string): string;
|
|
4
8
|
/** Storage path for a captured snapshot screenshot. */
|
|
5
|
-
declare function screenshotPath(projectId: string, buildId: string, storyId: string, viewport: string): string;
|
|
9
|
+
declare function screenshotPath(projectId: string, buildId: string, storyId: string, viewport: string, browser?: string): string;
|
|
10
|
+
/** Storage prefix of a project's content-addressed screenshots. */
|
|
11
|
+
declare function contentDir(projectId: string): string;
|
|
12
|
+
/** Storage path of a screenshot stored by the SHA-256 of its bytes (shared by builds and baselines). */
|
|
13
|
+
declare function contentPath(projectId: string, hash: string): string;
|
|
14
|
+
/** Whether `path` is one of `projectId`'s content-addressed screenshots. */
|
|
15
|
+
declare function isContentPath(projectId: string, path: string): boolean;
|
|
6
16
|
/** Storage path for a snapshot diff overlay image. */
|
|
7
|
-
declare function diffPath(projectId: string, buildId: string, storyId: string, viewport: string): string;
|
|
17
|
+
declare function diffPath(projectId: string, buildId: string, storyId: string, viewport: string, browser?: string): string;
|
|
18
|
+
/** Storage path for a cached design node render (overwritten in place when the file version moves). */
|
|
19
|
+
declare function designRenderPath(projectId: string, provider: string, fileKey: string, nodeId: string, viewerId?: string): string;
|
|
8
20
|
/** Storage path for a branch baseline screenshot. */
|
|
9
|
-
declare function baselinePath(projectId: string, branch: string, storyId: string, viewport: string): string;
|
|
21
|
+
declare function baselinePath(projectId: string, branch: string, storyId: string, viewport: string, browser?: string): string;
|
|
10
22
|
/** Storage prefix for an extracted published Storybook. */
|
|
11
23
|
declare function storybookDir(projectId: string, buildId: string): string;
|
|
24
|
+
/** Disposable gzip representation of a content-addressed published file. */
|
|
25
|
+
declare function publishedGzipPath(hash: string): string;
|
|
12
26
|
/** Storage path for an uploaded Storybook zip. */
|
|
13
27
|
declare function storybookZipPath(projectId: string, buildId: string): string;
|
|
14
|
-
|
|
15
|
-
|
|
28
|
+
/** Storage path of a build's persisted catalog (ADR 0006, decision 9), next to its `storybook/` statics. */
|
|
29
|
+
declare function catalogPath(projectId: string, buildId: string): string;
|
|
30
|
+
export { baselinePath, catalogPath, contentDir, contentPath, designRenderPath, diffPath, isContentPath, modeSegment, publishedGzipPath, screenshotPath, storybookDir, storybookZipPath };
|
|
16
31
|
//# sourceMappingURL=paths.d.mts.map
|
package/dist/paths.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { isSafeSegment } from "./utils/path-security.mjs";
|
|
5
|
-
|
|
5
|
+
// src/utils/paths.ts
|
|
6
6
|
/** Storage path builders. Every segment is validated — a third-party
|
|
7
7
|
* capture runner echoing `story.id = "../../x"` must fail here, not in an
|
|
8
8
|
* adapter with its own key-jailing quirks. */
|
|
@@ -11,47 +11,92 @@ function assertSegments(segments) {
|
|
|
11
11
|
const bad = segments.filter((segment) => !isSafeSegment(segment) || segment.length === 0);
|
|
12
12
|
if (bad.length > 0) throw new Error(`Unsafe storage path segment: ${bad.join(",")}`);
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Path segment for a mode on a given engine. Chromium keeps the bare mode key
|
|
16
|
+
* so pre-multi-browser objects stay addressable; other engines get `~browser`.
|
|
17
|
+
*/
|
|
18
|
+
function modeSegment(viewport, browser) {
|
|
19
|
+
return browser && browser !== "chromium" ? `${viewport}~${browser}` : viewport;
|
|
20
|
+
}
|
|
14
21
|
/** Storage path for a captured snapshot screenshot. */
|
|
15
|
-
function screenshotPath(projectId, buildId, storyId, viewport) {
|
|
22
|
+
function screenshotPath(projectId, buildId, storyId, viewport, browser) {
|
|
23
|
+
const segment = modeSegment(viewport, browser);
|
|
16
24
|
assertSegments([
|
|
17
25
|
projectId,
|
|
18
26
|
buildId,
|
|
19
27
|
storyId,
|
|
20
|
-
|
|
28
|
+
segment
|
|
21
29
|
]);
|
|
22
|
-
return `${projectId}/builds/${buildId}/screenshots/${storyId}/${
|
|
30
|
+
return `${projectId}/builds/${buildId}/screenshots/${storyId}/${segment}.png`;
|
|
31
|
+
}
|
|
32
|
+
/** Storage prefix of a project's content-addressed screenshots. */
|
|
33
|
+
function contentDir(projectId) {
|
|
34
|
+
assertSegments([projectId]);
|
|
35
|
+
return `${projectId}/content`;
|
|
36
|
+
}
|
|
37
|
+
/** Storage path of a screenshot stored by the SHA-256 of its bytes (shared by builds and baselines). */
|
|
38
|
+
function contentPath(projectId, hash) {
|
|
39
|
+
assertSegments([projectId, hash]);
|
|
40
|
+
return `${contentDir(projectId)}/${hash}.png`;
|
|
41
|
+
}
|
|
42
|
+
/** Whether `path` is one of `projectId`'s content-addressed screenshots. */
|
|
43
|
+
function isContentPath(projectId, path) {
|
|
44
|
+
return path.startsWith(`${contentDir(projectId)}/`) && path.endsWith(".png");
|
|
23
45
|
}
|
|
24
46
|
/** Storage path for a snapshot diff overlay image. */
|
|
25
|
-
function diffPath(projectId, buildId, storyId, viewport) {
|
|
47
|
+
function diffPath(projectId, buildId, storyId, viewport, browser) {
|
|
48
|
+
const segment = modeSegment(viewport, browser);
|
|
26
49
|
assertSegments([
|
|
27
50
|
projectId,
|
|
28
51
|
buildId,
|
|
29
52
|
storyId,
|
|
30
|
-
|
|
53
|
+
segment
|
|
31
54
|
]);
|
|
32
|
-
return `${projectId}/builds/${buildId}/diffs/${storyId}/${
|
|
55
|
+
return `${projectId}/builds/${buildId}/diffs/${storyId}/${segment}.png`;
|
|
56
|
+
}
|
|
57
|
+
/** Storage path for a cached design node render (overwritten in place when the file version moves). */
|
|
58
|
+
function designRenderPath(projectId, provider, fileKey, nodeId, viewerId = "") {
|
|
59
|
+
const node = nodeId.replaceAll(":", "-");
|
|
60
|
+
assertSegments([
|
|
61
|
+
projectId,
|
|
62
|
+
provider,
|
|
63
|
+
fileKey,
|
|
64
|
+
node,
|
|
65
|
+
...viewerId ? [viewerId] : []
|
|
66
|
+
]);
|
|
67
|
+
return `${projectId}/design/${provider}/${viewerId ? `user-${viewerId}/` : ""}${fileKey}/${node}.png`;
|
|
33
68
|
}
|
|
34
69
|
/** Storage path for a branch baseline screenshot. */
|
|
35
|
-
function baselinePath(projectId, branch, storyId, viewport) {
|
|
70
|
+
function baselinePath(projectId, branch, storyId, viewport, browser) {
|
|
71
|
+
const segment = modeSegment(viewport, browser);
|
|
36
72
|
assertSegments([
|
|
37
73
|
projectId,
|
|
38
74
|
branch,
|
|
39
75
|
storyId,
|
|
40
|
-
|
|
76
|
+
segment
|
|
41
77
|
]);
|
|
42
|
-
return `${projectId}/baselines/${branch}/${storyId}/${
|
|
78
|
+
return `${projectId}/baselines/${branch}/${storyId}/${segment}.png`;
|
|
43
79
|
}
|
|
44
80
|
/** Storage prefix for an extracted published Storybook. */
|
|
45
81
|
function storybookDir(projectId, buildId) {
|
|
46
82
|
assertSegments([projectId, buildId]);
|
|
47
83
|
return `${projectId}/builds/${buildId}/storybook`;
|
|
48
84
|
}
|
|
85
|
+
/** Disposable gzip representation of a content-addressed published file. */
|
|
86
|
+
function publishedGzipPath(hash) {
|
|
87
|
+
if (!/^[a-f0-9]{64}$/u.test(hash)) throw new Error("Invalid published content hash");
|
|
88
|
+
return `derived/published-gzip/${hash}.gz`;
|
|
89
|
+
}
|
|
49
90
|
/** Storage path for an uploaded Storybook zip. */
|
|
50
91
|
function storybookZipPath(projectId, buildId) {
|
|
51
92
|
assertSegments([projectId, buildId]);
|
|
52
93
|
return `${projectId}/builds/${buildId}/storybook.zip`;
|
|
53
94
|
}
|
|
54
|
-
|
|
55
|
-
|
|
95
|
+
/** Storage path of a build's persisted catalog (ADR 0006, decision 9), next to its `storybook/` statics. */
|
|
96
|
+
function catalogPath(projectId, buildId) {
|
|
97
|
+
assertSegments([projectId, buildId]);
|
|
98
|
+
return `${projectId}/builds/${buildId}/catalog.json`;
|
|
99
|
+
}
|
|
100
|
+
export { baselinePath, catalogPath, contentDir, contentPath, designRenderPath, diffPath, isContentPath, modeSegment, publishedGzipPath, screenshotPath, storybookDir, storybookZipPath };
|
|
56
101
|
|
|
57
102
|
//# sourceMappingURL=paths.mjs.map
|
package/dist/paths.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.mjs","names":[],"sources":["../src/utils/paths.ts"],"sourcesContent":["/** Storage path builders. Every segment is validated — a third-party\n * capture runner echoing `story.id = \"../../x\"` must fail here, not in an\n * adapter with its own key-jailing quirks. */\nimport { isSafeSegment } from \"./path-security.ts\";\n\n/** Throw when any key segment could escape its storage prefix. */\nfunction assertSegments(segments: string[]): void {\n const bad = segments.filter((segment) => !isSafeSegment(segment) || segment.length === 0);\n if (bad.length > 0) {\n throw new Error(`Unsafe storage path segment: ${bad.join(\",\")}`);\n }\n}\n/** Storage path for a captured snapshot screenshot. */\nexport function screenshotPath(\n projectId: string,\n buildId: string,\n storyId: string,\n viewport: string,\n): string {\n assertSegments([projectId, buildId, storyId,
|
|
1
|
+
{"version":3,"file":"paths.mjs","names":[],"sources":["../src/utils/paths.ts"],"sourcesContent":["/** Storage path builders. Every segment is validated — a third-party\n * capture runner echoing `story.id = \"../../x\"` must fail here, not in an\n * adapter with its own key-jailing quirks. */\nimport { isSafeSegment } from \"./path-security.ts\";\n\n/** Throw when any key segment could escape its storage prefix. */\nfunction assertSegments(segments: string[]): void {\n const bad = segments.filter((segment) => !isSafeSegment(segment) || segment.length === 0);\n if (bad.length > 0) {\n throw new Error(`Unsafe storage path segment: ${bad.join(\",\")}`);\n }\n}\n/**\n * Path segment for a mode on a given engine. Chromium keeps the bare mode key\n * so pre-multi-browser objects stay addressable; other engines get `~browser`.\n */\nexport function modeSegment(viewport: string, browser?: string): string {\n return browser && browser !== \"chromium\" ? `${viewport}~${browser}` : viewport;\n}\n\n/** Storage path for a captured snapshot screenshot. */\nexport function screenshotPath(\n projectId: string,\n buildId: string,\n storyId: string,\n viewport: string,\n browser?: string,\n): string {\n const segment = modeSegment(viewport, browser);\n assertSegments([projectId, buildId, storyId, segment]);\n return `${projectId}/builds/${buildId}/screenshots/${storyId}/${segment}.png`;\n}\n\n/** Storage prefix of a project's content-addressed screenshots. */\nexport function contentDir(projectId: string): string {\n assertSegments([projectId]);\n return `${projectId}/content`;\n}\n\n/** Storage path of a screenshot stored by the SHA-256 of its bytes (shared by builds and baselines). */\nexport function contentPath(projectId: string, hash: string): string {\n assertSegments([projectId, hash]);\n return `${contentDir(projectId)}/${hash}.png`;\n}\n\n/** Whether `path` is one of `projectId`'s content-addressed screenshots. */\nexport function isContentPath(projectId: string, path: string): boolean {\n return path.startsWith(`${contentDir(projectId)}/`) && path.endsWith(\".png\");\n}\n\n/** Storage path for a snapshot diff overlay image. */\nexport function diffPath(\n projectId: string,\n buildId: string,\n storyId: string,\n viewport: string,\n browser?: string,\n): string {\n const segment = modeSegment(viewport, browser);\n assertSegments([projectId, buildId, storyId, segment]);\n return `${projectId}/builds/${buildId}/diffs/${storyId}/${segment}.png`;\n}\n\n/** Storage path for a cached design node render (overwritten in place when the file version moves). */\nexport function designRenderPath(\n projectId: string,\n provider: string,\n fileKey: string,\n nodeId: string,\n viewerId = \"\",\n): string {\n const node = nodeId.replaceAll(\":\", \"-\");\n assertSegments([projectId, provider, fileKey, node, ...(viewerId ? [viewerId] : [])]);\n const owner = viewerId ? `user-${viewerId}/` : \"\";\n return `${projectId}/design/${provider}/${owner}${fileKey}/${node}.png`;\n}\n\n/** Storage path for a branch baseline screenshot. */\nexport function baselinePath(\n projectId: string,\n branch: string,\n storyId: string,\n viewport: string,\n browser?: string,\n): string {\n const segment = modeSegment(viewport, browser);\n assertSegments([projectId, branch, storyId, segment]);\n return `${projectId}/baselines/${branch}/${storyId}/${segment}.png`;\n}\n\n/** Storage prefix for an extracted published Storybook. */\nexport function storybookDir(projectId: string, buildId: string): string {\n assertSegments([projectId, buildId]);\n return `${projectId}/builds/${buildId}/storybook`;\n}\n\n/** Disposable gzip representation of a content-addressed published file. */\nexport function publishedGzipPath(hash: string): string {\n if (!/^[a-f0-9]{64}$/u.test(hash)) throw new Error(\"Invalid published content hash\");\n return `derived/published-gzip/${hash}.gz`;\n}\n\n/** Storage path for an uploaded Storybook zip. */\nexport function storybookZipPath(projectId: string, buildId: string): string {\n assertSegments([projectId, buildId]);\n return `${projectId}/builds/${buildId}/storybook.zip`;\n}\n\n/** Storage path of a build's persisted catalog (ADR 0006, decision 9), next to its `storybook/` statics. */\nexport function catalogPath(projectId: string, buildId: string): string {\n assertSegments([projectId, buildId]);\n return `${projectId}/builds/${buildId}/catalog.json`;\n}\n"],"mappings":";;;;;;;;;AAMA,SAAS,eAAe,UAA0B;CAChD,MAAM,MAAM,SAAS,QAAQ,YAAY,CAAC,cAAc,OAAO,KAAK,QAAQ,WAAW,CAAC;CACxF,IAAI,IAAI,SAAS,GACf,MAAM,IAAI,MAAM,gCAAgC,IAAI,KAAK,GAAG,GAAG;AAEnE;;;;;AAKA,SAAgB,YAAY,UAAkB,SAA0B;CACtE,OAAO,WAAW,YAAY,aAAa,GAAG,SAAS,GAAG,YAAY;AACxE;;AAGA,SAAgB,eACd,WACA,SACA,SACA,UACA,SACQ;CACR,MAAM,UAAU,YAAY,UAAU,OAAO;CAC7C,eAAe;EAAC;EAAW;EAAS;EAAS;CAAO,CAAC;CACrD,OAAO,GAAG,UAAU,UAAU,QAAQ,eAAe,QAAQ,GAAG,QAAQ;AAC1E;;AAGA,SAAgB,WAAW,WAA2B;CACpD,eAAe,CAAC,SAAS,CAAC;CAC1B,OAAO,GAAG,UAAU;AACtB;;AAGA,SAAgB,YAAY,WAAmB,MAAsB;CACnE,eAAe,CAAC,WAAW,IAAI,CAAC;CAChC,OAAO,GAAG,WAAW,SAAS,EAAE,GAAG,KAAK;AAC1C;;AAGA,SAAgB,cAAc,WAAmB,MAAuB;CACtE,OAAO,KAAK,WAAW,GAAG,WAAW,SAAS,EAAE,EAAE,KAAK,KAAK,SAAS,MAAM;AAC7E;;AAGA,SAAgB,SACd,WACA,SACA,SACA,UACA,SACQ;CACR,MAAM,UAAU,YAAY,UAAU,OAAO;CAC7C,eAAe;EAAC;EAAW;EAAS;EAAS;CAAO,CAAC;CACrD,OAAO,GAAG,UAAU,UAAU,QAAQ,SAAS,QAAQ,GAAG,QAAQ;AACpE;;AAGA,SAAgB,iBACd,WACA,UACA,SACA,QACA,WAAW,IACH;CACR,MAAM,OAAO,OAAO,WAAW,KAAK,GAAG;CACvC,eAAe;EAAC;EAAW;EAAU;EAAS;EAAM,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAC;CAAE,CAAC;CAEpF,OAAO,GAAG,UAAU,UAAU,SAAS,GADzB,WAAW,QAAQ,SAAS,KAAK,KACG,QAAQ,GAAG,KAAK;AACpE;;AAGA,SAAgB,aACd,WACA,QACA,SACA,UACA,SACQ;CACR,MAAM,UAAU,YAAY,UAAU,OAAO;CAC7C,eAAe;EAAC;EAAW;EAAQ;EAAS;CAAO,CAAC;CACpD,OAAO,GAAG,UAAU,aAAa,OAAO,GAAG,QAAQ,GAAG,QAAQ;AAChE;;AAGA,SAAgB,aAAa,WAAmB,SAAyB;CACvE,eAAe,CAAC,WAAW,OAAO,CAAC;CACnC,OAAO,GAAG,UAAU,UAAU,QAAQ;AACxC;;AAGA,SAAgB,kBAAkB,MAAsB;CACtD,IAAI,CAAC,kBAAkB,KAAK,IAAI,GAAG,MAAM,IAAI,MAAM,gCAAgC;CACnF,OAAO,0BAA0B,KAAK;AACxC;;AAGA,SAAgB,iBAAiB,WAAmB,SAAyB;CAC3E,eAAe,CAAC,WAAW,OAAO,CAAC;CACnC,OAAO,GAAG,UAAU,UAAU,QAAQ;AACxC;;AAGA,SAAgB,YAAY,WAAmB,SAAyB;CACtE,eAAe,CAAC,WAAW,OAAO,CAAC;CACnC,OAAO,GAAG,UAAU,UAAU,QAAQ;AACxC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { Logger } from "../logger.mjs";
|
|
4
|
+
import { DatabaseAdapter } from "../adapter/database.mjs";
|
|
5
|
+
/** Pending/running rows older than this are marked `interrupted`. */
|
|
6
|
+
declare const STALE_RUN_MS: number;
|
|
7
|
+
/** What one AI retention pass removed. */
|
|
8
|
+
interface AiPurgeResult {
|
|
9
|
+
health: number;
|
|
10
|
+
usage: number;
|
|
11
|
+
interrupted: number;
|
|
12
|
+
}
|
|
13
|
+
/** Run one AI retention pass (safe to call from any instance, any time). */
|
|
14
|
+
declare function purgeAiData(db: DatabaseAdapter, now?: Date, logger?: Logger): Promise<AiPurgeResult>;
|
|
15
|
+
export { AiPurgeResult, STALE_RUN_MS, purgeAiData };
|
|
16
|
+
//# sourceMappingURL=ai.d.mts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { AiUsageModel } from "../models/ai-usage.mjs";
|
|
5
|
+
import { InsightModel } from "../models/insight.mjs";
|
|
6
|
+
/** Pending/running rows older than this are marked `interrupted`. */
|
|
7
|
+
const STALE_RUN_MS = 18e5;
|
|
8
|
+
/** Run one AI retention pass (safe to call from any instance, any time). */
|
|
9
|
+
async function purgeAiData(db, now = /* @__PURE__ */ new Date(), logger) {
|
|
10
|
+
const insights = new InsightModel(db);
|
|
11
|
+
const day = 864e5;
|
|
12
|
+
const result = {
|
|
13
|
+
health: await insights.purgeHealthBefore((/* @__PURE__ */ new Date(now.getTime() - 90 * day)).toISOString()),
|
|
14
|
+
usage: await new AiUsageModel(db).purgeBefore((/* @__PURE__ */ new Date(now.getTime() - 90 * day)).toISOString()),
|
|
15
|
+
interrupted: await insights.sweepStale((/* @__PURE__ */ new Date(now.getTime() - STALE_RUN_MS)).toISOString())
|
|
16
|
+
};
|
|
17
|
+
if (result.health > 0 || result.usage > 0 || result.interrupted > 0) logger?.info(result, "ai data retention pass complete");
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
export { STALE_RUN_MS, purgeAiData };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=ai.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai.mjs","names":[],"sources":["../../src/retention/ai.ts"],"sourcesContent":["/** Retention for AI data: old health digests, old usage rows and interrupted runs. */\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { Logger } from \"../logger.ts\";\nimport { AiUsageModel } from \"../models/ai-usage.ts\";\nimport { InsightModel } from \"../models/insight.ts\";\n\n/** Health digests older than this are deleted (ADR 0016 §5). */\nexport const HEALTH_RETENTION_DAYS = 90;\n\n/** Usage rows older than this are deleted (budgets only look at days/hours). */\nexport const USAGE_RETENTION_DAYS = 90;\n\n/** Pending/running rows older than this are marked `interrupted`. */\nexport const STALE_RUN_MS = 30 * 60_000;\n\n/** What one AI retention pass removed. */\nexport interface AiPurgeResult {\n health: number;\n usage: number;\n interrupted: number;\n}\n\n/** Run one AI retention pass (safe to call from any instance, any time). */\nexport async function purgeAiData(\n db: DatabaseAdapter,\n now: Date = new Date(),\n logger?: Logger,\n): Promise<AiPurgeResult> {\n const insights = new InsightModel(db);\n const day = 86_400_000;\n const result: AiPurgeResult = {\n health: await insights.purgeHealthBefore(\n new Date(now.getTime() - HEALTH_RETENTION_DAYS * day).toISOString(),\n ),\n usage: await new AiUsageModel(db).purgeBefore(\n new Date(now.getTime() - USAGE_RETENTION_DAYS * day).toISOString(),\n ),\n interrupted: await insights.sweepStale(new Date(now.getTime() - STALE_RUN_MS).toISOString()),\n };\n if (result.health > 0 || result.usage > 0 || result.interrupted > 0) {\n logger?.info(result, \"ai data retention pass complete\");\n }\n return result;\n}\n"],"mappings":";;;;;;AAaA,MAAa,eAAe;;AAU5B,eAAsB,YACpB,IACA,sBAAY,IAAI,KAAK,GACrB,QACwB;CACxB,MAAM,WAAW,IAAI,aAAa,EAAE;CACpC,MAAM,MAAM;CACZ,MAAM,SAAwB;EAC5B,QAAQ,MAAM,SAAS,mCACrB,IAAI,KAAK,IAAI,QAAQ,IAAA,KAA4B,GAAG,EAAA,CAAE,YAAY,CACpE;EACA,OAAO,MAAM,IAAI,aAAa,EAAE,CAAC,CAAC,6BAChC,IAAI,KAAK,IAAI,QAAQ,IAAA,KAA2B,GAAG,EAAA,CAAE,YAAY,CACnE;EACA,aAAa,MAAM,SAAS,4BAAW,IAAI,KAAK,IAAI,QAAQ,IAAI,YAAY,EAAA,CAAE,YAAY,CAAC;CAC7F;CACA,IAAI,OAAO,SAAS,KAAK,OAAO,QAAQ,KAAK,OAAO,cAAc,GAChE,QAAQ,KAAK,QAAQ,iCAAiC;CAExD,OAAO;AACT"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { BuildModel } from "../models/build.mjs";
|
|
5
|
+
import { BuildReviewModel } from "../models/build-review.mjs";
|
|
6
|
+
import { CommentModel } from "../models/comment.mjs";
|
|
7
|
+
// src/retention/pending.ts
|
|
8
|
+
/**
|
|
9
|
+
* The project's pending builds whose last activity (upload, comment or verdict) is before
|
|
10
|
+
* `cutoff`. `capture_attempts` need no check: a build capture worked on leaves `pending`.
|
|
11
|
+
*/
|
|
12
|
+
async function pendingCandidates(db, projectId, cutoff) {
|
|
13
|
+
const builds = new BuildModel(db);
|
|
14
|
+
const pending = await builds.list(projectId, { status: "pending" });
|
|
15
|
+
if (pending.length === 0) return [];
|
|
16
|
+
const all = await builds.list(projectId);
|
|
17
|
+
return (await Promise.all(pending.map(async (build) => {
|
|
18
|
+
const activity = await activityOf(db, build);
|
|
19
|
+
if (activity.last >= cutoff) return null;
|
|
20
|
+
const superseded = !activity.touched && hasNewerOnBranch(all, build);
|
|
21
|
+
return {
|
|
22
|
+
buildId: build.id,
|
|
23
|
+
reason: superseded ? "superseded" : "idle"
|
|
24
|
+
};
|
|
25
|
+
}))).filter((candidate) => candidate !== null);
|
|
26
|
+
}
|
|
27
|
+
async function activityOf(db, build) {
|
|
28
|
+
const [comments, reviews] = await Promise.all([new CommentModel(db).listByBuild(build.id), new BuildReviewModel(db).listByBuild(build.id)]);
|
|
29
|
+
return {
|
|
30
|
+
last: [
|
|
31
|
+
build.updatedAt,
|
|
32
|
+
...comments.map((item) => stampOf(item)),
|
|
33
|
+
...reviews.map((item) => stampOf(item))
|
|
34
|
+
].toSorted().at(-1) ?? build.updatedAt,
|
|
35
|
+
touched: comments.length > 0 || reviews.length > 0
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function stampOf(item) {
|
|
39
|
+
return item.createdAt;
|
|
40
|
+
}
|
|
41
|
+
function hasNewerOnBranch(all, build) {
|
|
42
|
+
return all.some((other) => other.id !== build.id && other.gitBranch === build.gitBranch && other.createdAt > build.createdAt);
|
|
43
|
+
}
|
|
44
|
+
export { pendingCandidates };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=pending.mjs.map
|