@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.mjs","names":[],"sources":["../../../src/capture/publish/handler.ts"],"sourcesContent":["import type { DatabaseAdapter } from \"../../adapters/database.ts\";\n/** The `publish` job handler of the consumer (ADR 0006, decision 10): publish a stored zip, then complete the build. */\nimport type { StorageAdapter } from \"../../adapters/storage.ts\";\nimport type { Logger } from \"../../logger.ts\";\nimport { BuildModel } from \"../../models/build.ts\";\nimport type { ConsumerJob, KindHandler } from \"../consumer/types.ts\";\nimport type { PublishCompleter } from \"./complete.ts\";\nimport { ZipLimitError, type ExtractionLimits } from \"./limits.ts\";\nimport { publishStoredZip } from \"./run.ts\";\n\n/** What {@link createPublishHandler} needs. */\nexport interface PublishHandlerOptions {\n db: DatabaseAdapter;\n storage: StorageAdapter;\n scratchDir: string;\n limits: ExtractionLimits;\n completer: PublishCompleter;\n logger: Logger;\n}\n\n/** A `publish` job needs the build to publish. */\nfunction hasBuild(job: ConsumerJob): boolean {\n return typeof job.buildId === \"string\" && job.buildId.length > 0;\n}\n\n/**\n * The handler. Resolving acks the job. A zip that breaks a cap is a final answer (retrying cannot\n * help): the build is failed and the job acked. Any other error is retried by the consumer, and\n * the build is failed on the last attempt. A redelivery after a lost lease repeats the extraction\n * (same keys) and leaves an already accepted build alone.\n */\nexport function createPublishHandler(options: PublishHandlerOptions): KindHandler {\n return {\n accepts: hasBuild,\n run: async (job, context) => {\n const build = await new BuildModel(options.db).get(job.buildId);\n if (!build) {\n context.logger.warn(\"build is gone; dropping publish job\");\n return;\n }\n await publishOnce(options, job, context, build.projectId);\n },\n };\n}\n\nasync function publishOnce(\n options: PublishHandlerOptions,\n job: ConsumerJob,\n context: { logger: Logger; touch: () => void },\n projectId: string,\n): Promise<void> {\n const { completer, storage, scratchDir, limits, db } = options;\n try {\n await publishStoredZip(\n { storage, scratchDir, limits, db, logger: context.logger, touch: context.touch },\n { projectId, buildId: job.buildId },\n );\n } catch (error) {\n const permanent = error instanceof ZipLimitError;\n if (permanent || (job.attempt ?? 1) >= (job.maxAttempts ?? 1)) {\n await completer.complete(job.buildId, { ok: false, error: messageOf(error) });\n }\n if (permanent) {\n return;\n }\n throw error;\n }\n await completer.complete(job.buildId, { ok: true });\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":";;;;;;;;AAqBA,SAAS,SAAS,KAA2B;CAC3C,OAAO,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,SAAS;AACjE;;;;;;;AAQA,SAAgB,qBAAqB,SAA6C;CAChF,OAAO;EACL,SAAS;EACT,KAAK,OAAO,KAAK,YAAY;GAC3B,MAAM,QAAQ,MAAM,IAAI,WAAW,QAAQ,EAAE,CAAC,CAAC,IAAI,IAAI,OAAO;GAC9D,IAAI,CAAC,OAAO;IACV,QAAQ,OAAO,KAAK,qCAAqC;IACzD;GACF;GACA,MAAM,YAAY,SAAS,KAAK,SAAS,MAAM,SAAS;EAC1D;CACF;AACF;AAEA,eAAe,YACb,SACA,KACA,SACA,WACe;CACf,MAAM,EAAE,WAAW,SAAS,YAAY,QAAQ,OAAO;CACvD,IAAI;EACF,MAAM,iBACJ;GAAE;GAAS;GAAY;GAAQ;GAAI,QAAQ,QAAQ;GAAQ,OAAO,QAAQ;EAAM,GAChF;GAAE;GAAW,SAAS,IAAI;EAAQ,CACpC;CACF,SAAS,OAAO;EACd,MAAM,YAAY,iBAAiB;EACnC,IAAI,cAAc,IAAI,WAAW,OAAO,IAAI,eAAe,IACzD,MAAM,UAAU,SAAS,IAAI,SAAS;GAAE,IAAI;GAAO,OAAO,UAAU,KAAK;EAAE,CAAC;EAE9E,IAAI,WACF;EAEF,MAAM;CACR;CACA,MAAM,UAAU,SAAS,IAAI,SAAS,EAAE,IAAI,KAAK,CAAC;AACpD;AAEA,SAAS,UAAU,OAAwB;CACzC,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { DEFAULT_MAX_INLINE_UNZIP_SIZE, DEFAULT_MAX_UNZIPPED_BYTES, DEFAULT_MAX_ZIP_ENTRIES, ExtractionLimits, FILE_BY_FILE_HINT, PublishLimits, ZipLimitError, extractionLimitsOf, publishRoute, resolvePublishLimits } from "./limits.mjs";
|
|
4
|
+
import { AfterPublishContext, AfterPublishHook, PublishCompleter, PublishCompleterOptions, PublishOutcome, createPublishCompleter } from "./complete.mjs";
|
|
5
|
+
import { PublishHandlerOptions, createPublishHandler } from "./handler.mjs";
|
|
6
|
+
import { PublishFacts, publishVerdict } from "./accept.mjs";
|
|
7
|
+
import { publishingOf } from "./published.mjs";
|
|
8
|
+
import { ExtractionResult, extractZipStream } from "./extract.mjs";
|
|
9
|
+
import { PUBLISH_SCRATCH_ID, PublishZipOptions, publishStoredZip } from "./run.mjs";
|
|
10
|
+
import { ZipInvalidError } from "./invalid-zip.mjs";
|
|
11
|
+
export { type AfterPublishContext, type AfterPublishHook, DEFAULT_MAX_INLINE_UNZIP_SIZE, DEFAULT_MAX_UNZIPPED_BYTES, DEFAULT_MAX_ZIP_ENTRIES, type ExtractionLimits, type ExtractionResult, FILE_BY_FILE_HINT, PUBLISH_SCRATCH_ID, type PublishCompleter, type PublishCompleterOptions, type PublishFacts, type PublishHandlerOptions, type PublishLimits, type PublishOutcome, type PublishZipOptions, ZipInvalidError, ZipLimitError, createPublishCompleter, createPublishHandler, extractZipStream, extractionLimitsOf, publishRoute, publishStoredZip, publishVerdict, publishingOf, resolvePublishLimits };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
/** An archive that cannot be parsed; retrying the same bytes cannot help. */
|
|
4
|
+
declare class ZipInvalidError extends Error {
|
|
5
|
+
readonly name = "ZipInvalidError";
|
|
6
|
+
}
|
|
7
|
+
export { ZipInvalidError };
|
|
8
|
+
//# sourceMappingURL=invalid-zip.d.mts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
// src/capture/publish/invalid-zip.ts
|
|
5
|
+
/** An archive that cannot be parsed; retrying the same bytes cannot help. */
|
|
6
|
+
var ZipInvalidError = class extends Error {
|
|
7
|
+
name = "ZipInvalidError";
|
|
8
|
+
};
|
|
9
|
+
export { ZipInvalidError };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=invalid-zip.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invalid-zip.mjs","names":[],"sources":["../../../src/capture/publish/invalid-zip.ts"],"sourcesContent":["/** An archive that cannot be parsed; retrying the same bytes cannot help. */\nexport class ZipInvalidError extends Error {\n override readonly name = \"ZipInvalidError\";\n}\n"],"mappings":";;;;;AACA,IAAa,kBAAb,cAAqC,MAAM;CACzC,OAAyB;AAC3B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { ShelfConfig } from "../../config.mjs";
|
|
4
|
+
/** Zip size (bytes) up to which a zip is extracted inline in the upload request: 50 MB. */
|
|
5
|
+
declare const DEFAULT_MAX_INLINE_UNZIP_SIZE: number;
|
|
6
|
+
/** Entries an uploaded Storybook zip may hold. A large Storybook has some thousands of files. */
|
|
7
|
+
declare const DEFAULT_MAX_ZIP_ENTRIES = 50000;
|
|
8
|
+
/** Total uncompressed bytes an uploaded Storybook zip may expand to: 2 GiB. */
|
|
9
|
+
declare const DEFAULT_MAX_UNZIPPED_BYTES: number;
|
|
10
|
+
/** Caps enforced while a zip is extracted; the compressed size alone is no bound. */
|
|
11
|
+
interface ExtractionLimits {
|
|
12
|
+
/** Most entries (files and directories) the archive may hold. */
|
|
13
|
+
maxEntries: number;
|
|
14
|
+
/** Most uncompressed bytes all files together may expand to, counted while streaming. */
|
|
15
|
+
maxBytes: number;
|
|
16
|
+
}
|
|
17
|
+
/** Everything the publish pipeline reads from `ShelfConfig`, defaults applied. */
|
|
18
|
+
interface PublishLimits extends ExtractionLimits {
|
|
19
|
+
/** Largest zip extracted inline in the upload request; `0` sends every zip to a `publish` job. */
|
|
20
|
+
inlineBytes: number;
|
|
21
|
+
}
|
|
22
|
+
/** The effective publish limits of a config. */
|
|
23
|
+
declare function resolvePublishLimits(config?: Pick<ShelfConfig, "maxInlineUnzipSize" | "maxZipEntries" | "maxUnzippedBytes">): PublishLimits;
|
|
24
|
+
/** The extraction caps alone. */
|
|
25
|
+
declare function extractionLimitsOf(limits: PublishLimits | ExtractionLimits): ExtractionLimits;
|
|
26
|
+
/** How an upload of `zipBytes` is published: inline in the request, or by a `publish` job. */
|
|
27
|
+
declare function publishRoute(zipBytes: number, limits: Pick<PublishLimits, "inlineBytes">): "inline" | "job";
|
|
28
|
+
/** An archive that breaks a cap or tries to write outside the target; retrying cannot help. */
|
|
29
|
+
declare class ZipLimitError extends Error {
|
|
30
|
+
readonly name = "ZipLimitError";
|
|
31
|
+
}
|
|
32
|
+
/** Message of the 413 an over-limit zip gets on a host with no `publish` consumer. */
|
|
33
|
+
declare const FILE_BY_FILE_HINT: string;
|
|
34
|
+
export { DEFAULT_MAX_INLINE_UNZIP_SIZE, DEFAULT_MAX_UNZIPPED_BYTES, DEFAULT_MAX_ZIP_ENTRIES, ExtractionLimits, FILE_BY_FILE_HINT, PublishLimits, ZipLimitError, extractionLimitsOf, publishRoute, resolvePublishLimits };
|
|
35
|
+
//# sourceMappingURL=limits.d.mts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
// src/capture/publish/limits.ts
|
|
5
|
+
/** Zip size (bytes) up to which a zip is extracted inline in the upload request: 50 MB. */
|
|
6
|
+
const DEFAULT_MAX_INLINE_UNZIP_SIZE = 52428800;
|
|
7
|
+
/** Entries an uploaded Storybook zip may hold. A large Storybook has some thousands of files. */
|
|
8
|
+
const DEFAULT_MAX_ZIP_ENTRIES = 5e4;
|
|
9
|
+
/** Total uncompressed bytes an uploaded Storybook zip may expand to: 2 GiB. */
|
|
10
|
+
const DEFAULT_MAX_UNZIPPED_BYTES = 2147483648;
|
|
11
|
+
/** The effective publish limits of a config. */
|
|
12
|
+
function resolvePublishLimits(config) {
|
|
13
|
+
return {
|
|
14
|
+
inlineBytes: config?.maxInlineUnzipSize ?? 52428800,
|
|
15
|
+
maxEntries: config?.maxZipEntries ?? 5e4,
|
|
16
|
+
maxBytes: config?.maxUnzippedBytes ?? 2147483648
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** The extraction caps alone. */
|
|
20
|
+
function extractionLimitsOf(limits) {
|
|
21
|
+
return {
|
|
22
|
+
maxEntries: limits.maxEntries,
|
|
23
|
+
maxBytes: limits.maxBytes
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** How an upload of `zipBytes` is published: inline in the request, or by a `publish` job. */
|
|
27
|
+
function publishRoute(zipBytes, limits) {
|
|
28
|
+
return zipBytes <= limits.inlineBytes ? "inline" : "job";
|
|
29
|
+
}
|
|
30
|
+
/** An archive that breaks a cap or tries to write outside the target; retrying cannot help. */
|
|
31
|
+
var ZipLimitError = class extends Error {
|
|
32
|
+
name = "ZipLimitError";
|
|
33
|
+
};
|
|
34
|
+
/** Message of the 413 an over-limit zip gets on a host with no `publish` consumer. */
|
|
35
|
+
const FILE_BY_FILE_HINT = "Zip is larger than the inline publish limit and this host runs no publish consumer. Upload the Storybook file by file instead: POST /dedup, then PUT /content, then POST /manifest (the storyshelf CLI does this when it is given a directory).";
|
|
36
|
+
export { DEFAULT_MAX_INLINE_UNZIP_SIZE, DEFAULT_MAX_UNZIPPED_BYTES, DEFAULT_MAX_ZIP_ENTRIES, FILE_BY_FILE_HINT, ZipLimitError, extractionLimitsOf, publishRoute, resolvePublishLimits };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=limits.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.mjs","names":[],"sources":["../../../src/capture/publish/limits.ts"],"sourcesContent":["/** Publish limits (ADR 0006, decision 10): the inline threshold and the extraction caps, with defaults. */\nimport type { ShelfConfig } from \"../../config.ts\";\n\n/** Zip size (bytes) up to which a zip is extracted inline in the upload request: 50 MB. */\nexport const DEFAULT_MAX_INLINE_UNZIP_SIZE = 50 * 1024 * 1024;\n\n/** Entries an uploaded Storybook zip may hold. A large Storybook has some thousands of files. */\nexport const DEFAULT_MAX_ZIP_ENTRIES = 50_000;\n\n/** Total uncompressed bytes an uploaded Storybook zip may expand to: 2 GiB. */\nexport const DEFAULT_MAX_UNZIPPED_BYTES = 2 * 1024 * 1024 * 1024;\n\n/** Caps enforced while a zip is extracted; the compressed size alone is no bound. */\nexport interface ExtractionLimits {\n /** Most entries (files and directories) the archive may hold. */\n maxEntries: number;\n /** Most uncompressed bytes all files together may expand to, counted while streaming. */\n maxBytes: number;\n}\n\n/** Everything the publish pipeline reads from `ShelfConfig`, defaults applied. */\nexport interface PublishLimits extends ExtractionLimits {\n /** Largest zip extracted inline in the upload request; `0` sends every zip to a `publish` job. */\n inlineBytes: number;\n}\n\n/** The effective publish limits of a config. */\nexport function resolvePublishLimits(\n config?: Pick<ShelfConfig, \"maxInlineUnzipSize\" | \"maxZipEntries\" | \"maxUnzippedBytes\">,\n): PublishLimits {\n return {\n inlineBytes: config?.maxInlineUnzipSize ?? DEFAULT_MAX_INLINE_UNZIP_SIZE,\n maxEntries: config?.maxZipEntries ?? DEFAULT_MAX_ZIP_ENTRIES,\n maxBytes: config?.maxUnzippedBytes ?? DEFAULT_MAX_UNZIPPED_BYTES,\n };\n}\n\n/** The extraction caps alone. */\nexport function extractionLimitsOf(limits: PublishLimits | ExtractionLimits): ExtractionLimits {\n return { maxEntries: limits.maxEntries, maxBytes: limits.maxBytes };\n}\n\n/** How an upload of `zipBytes` is published: inline in the request, or by a `publish` job. */\nexport function publishRoute(\n zipBytes: number,\n limits: Pick<PublishLimits, \"inlineBytes\">,\n): \"inline\" | \"job\" {\n return zipBytes <= limits.inlineBytes ? \"inline\" : \"job\";\n}\n\n/** An archive that breaks a cap or tries to write outside the target; retrying cannot help. */\nexport class ZipLimitError extends Error {\n override readonly name = \"ZipLimitError\";\n}\n\n/** Message of the 413 an over-limit zip gets on a host with no `publish` consumer. */\nexport const FILE_BY_FILE_HINT =\n \"Zip is larger than the inline publish limit and this host runs no publish consumer. \" +\n \"Upload the Storybook file by file instead: POST /dedup, then PUT /content, then POST /manifest \" +\n \"(the storyshelf CLI does this when it is given a directory).\";\n"],"mappings":";;;;;AAIA,MAAa,gCAAgC;;AAG7C,MAAa,0BAA0B;;AAGvC,MAAa,6BAA6B;;AAiB1C,SAAgB,qBACd,QACe;CACf,OAAO;EACL,aAAa,QAAQ,sBAAA;EACrB,YAAY,QAAQ,iBAAA;EACpB,UAAU,QAAQ,oBAAA;CACpB;AACF;;AAGA,SAAgB,mBAAmB,QAA4D;CAC7F,OAAO;EAAE,YAAY,OAAO;EAAY,UAAU,OAAO;CAAS;AACpE;;AAGA,SAAgB,aACd,UACA,QACkB;CAClB,OAAO,YAAY,OAAO,cAAc,WAAW;AACrD;;AAGA,IAAa,gBAAb,cAAmC,MAAM;CACvC,OAAyB;AAC3B;;AAGA,MAAa,oBACX"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { StorageAdapter } from "../../adapter/storage.mjs";
|
|
4
|
+
import { PublishingState } from "../../adapters/notifier/build-state.mjs";
|
|
5
|
+
import { Build } from "../../schema/build.mjs";
|
|
6
|
+
/**
|
|
7
|
+
* How publishing the build stands. The manifest is written last, so its presence means done. A
|
|
8
|
+
* `failed` or `cancelled` build without one did not publish (or never uploaded); any other build waits. Without
|
|
9
|
+
* a storage adapter nothing can be read, so publishing reads as pending.
|
|
10
|
+
*/
|
|
11
|
+
declare function publishingOf(storage: StorageAdapter | undefined, build: Pick<Build, "id" | "projectId" | "status">): Promise<PublishingState>;
|
|
12
|
+
export { publishingOf };
|
|
13
|
+
//# sourceMappingURL=published.d.mts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { storybookDir } from "../../paths.mjs";
|
|
5
|
+
// src/capture/publish/published.ts
|
|
6
|
+
/**
|
|
7
|
+
* How publishing the build stands. The manifest is written last, so its presence means done. A
|
|
8
|
+
* `failed` or `cancelled` build without one did not publish (or never uploaded); any other build waits. Without
|
|
9
|
+
* a storage adapter nothing can be read, so publishing reads as pending.
|
|
10
|
+
*/
|
|
11
|
+
async function publishingOf(storage, build) {
|
|
12
|
+
if (storage !== void 0 && await storage.exists(`${storybookDir(build.projectId, build.id)}/manifest.json`)) return "success";
|
|
13
|
+
return build.status === "failed" || build.status === "cancelled" ? "failure" : "pending";
|
|
14
|
+
}
|
|
15
|
+
export { publishingOf };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=published.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"published.mjs","names":[],"sources":["../../../src/capture/publish/published.ts"],"sourcesContent":["/**\n * Whether a build's Storybook is published: the one probe behind the `<prefix>/storybook` status\n * (ADR 0014) and the rule that a verdict waits for publishing to end (ADR 0013, decision 3).\n */\nimport type { PublishingState } from \"../../adapters/notifier/build-state.ts\";\nimport type { StorageAdapter } from \"../../adapters/storage.ts\";\nimport type { Build } from \"../../schema/build.ts\";\nimport { storybookDir } from \"../../utils/paths.ts\";\n\n/**\n * How publishing the build stands. The manifest is written last, so its presence means done. A\n * `failed` or `cancelled` build without one did not publish (or never uploaded); any other build waits. Without\n * a storage adapter nothing can be read, so publishing reads as pending.\n */\nexport async function publishingOf(\n storage: StorageAdapter | undefined,\n build: Pick<Build, \"id\" | \"projectId\" | \"status\">,\n): Promise<PublishingState> {\n const published =\n storage !== undefined &&\n (await storage.exists(`${storybookDir(build.projectId, build.id)}/manifest.json`));\n if (published) {\n return \"success\";\n }\n return build.status === \"failed\" || build.status === \"cancelled\" ? \"failure\" : \"pending\";\n}\n"],"mappings":";;;;;;;;;;AAcA,eAAsB,aACpB,SACA,OAC0B;CAI1B,IAFE,YAAY,KAAA,KACX,MAAM,QAAQ,OAAO,GAAG,aAAa,MAAM,WAAW,MAAM,EAAE,EAAE,eAAe,GAEhF,OAAO;CAET,OAAO,MAAM,WAAW,YAAY,MAAM,WAAW,cAAc,YAAY;AACjF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
import { StorageAdapter } from "../../adapter/storage.mjs";
|
|
6
|
+
import { ExtractionLimits } from "./limits.mjs";
|
|
7
|
+
/** Scratch id publishing uses, so it never shares a directory with the build's capture. */
|
|
8
|
+
declare const PUBLISH_SCRATCH_ID = "publish";
|
|
9
|
+
/** What {@link publishStoredZip} works with. */
|
|
10
|
+
interface PublishZipOptions {
|
|
11
|
+
storage: StorageAdapter;
|
|
12
|
+
scratchDir: string;
|
|
13
|
+
limits: ExtractionLimits;
|
|
14
|
+
/** Records the persisted content in `content_refs`, so retention knows who still uses it. */
|
|
15
|
+
db?: DatabaseAdapter | undefined;
|
|
16
|
+
logger: Logger;
|
|
17
|
+
/** Called between stages (renews a job's lease). */
|
|
18
|
+
touch?: () => void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extract `storybook.zip` of a build and persist its statics. The manifest is written last, so a
|
|
22
|
+
* build serves only once complete and a repeat run rewrites the same keys.
|
|
23
|
+
*
|
|
24
|
+
* @throws {ZipLimitError} When the zip breaks a cap or tries to escape the target.
|
|
25
|
+
*/
|
|
26
|
+
declare function publishStoredZip(options: PublishZipOptions, target: {
|
|
27
|
+
projectId: string;
|
|
28
|
+
buildId: string;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
export { PUBLISH_SCRATCH_ID, PublishZipOptions, publishStoredZip };
|
|
31
|
+
//# sourceMappingURL=run.d.mts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { removeShardScratch } from "../scratch.mjs";
|
|
5
|
+
import { extractStorybookToScratch, persistStorybookStatics } from "../statics.mjs";
|
|
6
|
+
// src/capture/publish/run.ts
|
|
7
|
+
/** Scratch id publishing uses, so it never shares a directory with the build's capture. */
|
|
8
|
+
const PUBLISH_SCRATCH_ID = "publish";
|
|
9
|
+
/**
|
|
10
|
+
* Extract `storybook.zip` of a build and persist its statics. The manifest is written last, so a
|
|
11
|
+
* build serves only once complete and a repeat run rewrites the same keys.
|
|
12
|
+
*
|
|
13
|
+
* @throws {ZipLimitError} When the zip breaks a cap or tries to escape the target.
|
|
14
|
+
*/
|
|
15
|
+
async function publishStoredZip(options, target) {
|
|
16
|
+
const { storage, scratchDir, logger } = options;
|
|
17
|
+
const { projectId, buildId } = target;
|
|
18
|
+
try {
|
|
19
|
+
const dir = await extractStorybookToScratch(storage, scratchDir, projectId, buildId, PUBLISH_SCRATCH_ID, options.limits);
|
|
20
|
+
options.touch?.();
|
|
21
|
+
await persistStorybookStatics(storage, dir, projectId, buildId, options.db);
|
|
22
|
+
options.touch?.();
|
|
23
|
+
} finally {
|
|
24
|
+
await removeShardScratch(scratchDir, projectId, buildId, PUBLISH_SCRATCH_ID, logger);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export { PUBLISH_SCRATCH_ID, publishStoredZip };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=run.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.mjs","names":[],"sources":["../../../src/capture/publish/run.ts"],"sourcesContent":["/** Publish a build's stored zip: extract with the caps, persist statics and manifest, clean the scratch. */\nimport type { DatabaseAdapter } from \"../../adapters/database.ts\";\nimport type { StorageAdapter } from \"../../adapters/storage.ts\";\nimport type { Logger } from \"../../logger.ts\";\nimport { removeShardScratch } from \"../scratch.ts\";\nimport { extractStorybookToScratch, persistStorybookStatics } from \"../statics.ts\";\nimport type { ExtractionLimits } from \"./limits.ts\";\n\n/** Scratch id publishing uses, so it never shares a directory with the build's capture. */\nexport const PUBLISH_SCRATCH_ID = \"publish\";\n\n/** What {@link publishStoredZip} works with. */\nexport interface PublishZipOptions {\n storage: StorageAdapter;\n scratchDir: string;\n limits: ExtractionLimits;\n /** Records the persisted content in `content_refs`, so retention knows who still uses it. */\n db?: DatabaseAdapter | undefined;\n logger: Logger;\n /** Called between stages (renews a job's lease). */\n touch?: () => void;\n}\n\n/**\n * Extract `storybook.zip` of a build and persist its statics. The manifest is written last, so a\n * build serves only once complete and a repeat run rewrites the same keys.\n *\n * @throws {ZipLimitError} When the zip breaks a cap or tries to escape the target.\n */\nexport async function publishStoredZip(\n options: PublishZipOptions,\n target: { projectId: string; buildId: string },\n): Promise<void> {\n const { storage, scratchDir, logger } = options;\n const { projectId, buildId } = target;\n try {\n const dir = await extractStorybookToScratch(\n storage,\n scratchDir,\n projectId,\n buildId,\n PUBLISH_SCRATCH_ID,\n options.limits,\n );\n options.touch?.();\n await persistStorybookStatics(storage, dir, projectId, buildId, options.db);\n options.touch?.();\n } finally {\n await removeShardScratch(scratchDir, projectId, buildId, PUBLISH_SCRATCH_ID, logger);\n }\n}\n"],"mappings":";;;;;;;AASA,MAAa,qBAAqB;;;;;;;AAoBlC,eAAsB,iBACpB,SACA,QACe;CACf,MAAM,EAAE,SAAS,YAAY,WAAW;CACxC,MAAM,EAAE,WAAW,YAAY;CAC/B,IAAI;EACF,MAAM,MAAM,MAAM,0BAChB,SACA,YACA,WACA,SACA,oBACA,QAAQ,MACV;EACA,QAAQ,QAAQ;EAChB,MAAM,wBAAwB,SAAS,KAAK,WAAW,SAAS,QAAQ,EAAE;EAC1E,QAAQ,QAAQ;CAClB,UAAU;EACR,MAAM,mBAAmB,YAAY,WAAW,SAAS,oBAAoB,MAAM;CACrF;AACF"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { Logger } from "../logger.mjs";
|
|
3
4
|
import { DatabaseAdapter } from "../adapter/database.mjs";
|
|
4
5
|
import { StorageAdapter } from "../adapter/storage.mjs";
|
|
5
|
-
import { Logger } from "../logger.mjs";
|
|
6
6
|
import { Build } from "../schema/build.mjs";
|
|
7
7
|
import { Project } from "../schema/project.mjs";
|
|
8
|
-
//#region src/capture/rediff.d.ts
|
|
9
8
|
/** Dependencies for {@link rediffBuild}. */
|
|
10
9
|
interface RediffDeps {
|
|
11
10
|
db: DatabaseAdapter;
|
|
@@ -30,6 +29,5 @@ declare const REDIFFABLE_BUILD_STATUSES: ReadonlySet<string>;
|
|
|
30
29
|
* rendered. The caller refreshes the build rollup afterwards.
|
|
31
30
|
*/
|
|
32
31
|
declare function rediffBuild(deps: RediffDeps, project: Project, build: Build): Promise<RediffResult>;
|
|
33
|
-
//#endregion
|
|
34
32
|
export { REDIFFABLE_BUILD_STATUSES, RediffDeps, RediffResult, rediffBuild };
|
|
35
33
|
//# sourceMappingURL=rediff.d.mts.map
|
package/dist/capture/rediff.mjs
CHANGED
|
@@ -2,12 +2,14 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { diffPath } from "../paths.mjs";
|
|
5
|
-
import { BaselineModel } from "../models/baseline.mjs";
|
|
6
5
|
import { NO_BASELINE } from "../models/baseline-status.mjs";
|
|
6
|
+
import { BaselineModel } from "../models/baseline.mjs";
|
|
7
7
|
import { SnapshotModel } from "../models/snapshot.mjs";
|
|
8
|
+
import { mapLimit } from "../utils/map-limit.mjs";
|
|
9
|
+
import { freezeComparison, isComparisonImagePath, parseComparisonReference, sourceSnapshotId } from "./comparison-reference.mjs";
|
|
8
10
|
import { diffStoredScreenshots, writeDiffOverlay } from "./diff-record.mjs";
|
|
9
11
|
import { diffStatus } from "./pipeline.mjs";
|
|
10
|
-
|
|
12
|
+
// src/capture/rediff.ts
|
|
11
13
|
/** Build statuses a re-diff may run in; earlier or failed builds have no complete snapshot set. */
|
|
12
14
|
const REDIFFABLE_BUILD_STATUSES = /* @__PURE__ */ new Set([
|
|
13
15
|
"reviewing",
|
|
@@ -27,7 +29,7 @@ const REDIFFABLE_SNAPSHOT_STATUSES = /* @__PURE__ */ new Set([
|
|
|
27
29
|
*/
|
|
28
30
|
async function rediffBuild(deps, project, build) {
|
|
29
31
|
const rows = (await new SnapshotModel(deps.db).listByBuild(build.id)).filter((row) => !row.inherited && REDIFFABLE_SNAPSHOT_STATUSES.has(row.status));
|
|
30
|
-
const outcomes = await
|
|
32
|
+
const outcomes = await mapLimit(rows, 4, async (row) => await rediffSnapshot(deps, project, build, row));
|
|
31
33
|
const result = {
|
|
32
34
|
rediffed: outcomes.filter((outcome) => outcome !== "missing").length,
|
|
33
35
|
statusChanged: outcomes.filter((outcome) => outcome === "changed").length,
|
|
@@ -41,9 +43,10 @@ async function rediffBuild(deps, project, build) {
|
|
|
41
43
|
}
|
|
42
44
|
async function rediffSnapshot(deps, project, build, row) {
|
|
43
45
|
if (!await deps.storage.exists(row.screenshotPath)) return "missing";
|
|
44
|
-
const baseline = await new BaselineModel(deps.db).resolve(project.id, row.storyId, row.viewportName, build.gitBranch, project.gitDefaultBranch);
|
|
46
|
+
const baseline = await new BaselineModel(deps.db).resolve(project.id, row.storyId, row.viewportName, build.gitBranch, project.gitDefaultBranch, row.browser);
|
|
45
47
|
const patch = baseline ? await diffPatch(deps, project, build, row, baseline) : noBaselinePatch();
|
|
46
48
|
await new SnapshotModel(deps.db).update(row.id, patch);
|
|
49
|
+
if (row.comparisonImagePath && row.comparisonImagePath !== patch.comparisonImagePath && isComparisonImagePath(row.comparisonImagePath, project.id, build.id)) await deps.storage.delete(row.comparisonImagePath).catch(() => {});
|
|
47
50
|
return patch.status === row.status ? "same" : "changed";
|
|
48
51
|
}
|
|
49
52
|
function noBaselinePatch() {
|
|
@@ -54,12 +57,23 @@ function noBaselinePatch() {
|
|
|
54
57
|
diffRatio: null,
|
|
55
58
|
diffPassed: null,
|
|
56
59
|
baselineId: null,
|
|
57
|
-
baselineVersion: NO_BASELINE
|
|
60
|
+
baselineVersion: NO_BASELINE,
|
|
61
|
+
comparisonImagePath: null,
|
|
62
|
+
comparisonMetadata: null
|
|
58
63
|
};
|
|
59
64
|
}
|
|
60
65
|
async function diffPatch(deps, project, build, row, baseline) {
|
|
61
|
-
const
|
|
62
|
-
|
|
66
|
+
const comparison = await freezeComparison(deps.storage, project.id, build.id, baseline, {
|
|
67
|
+
defaultBranch: project.gitDefaultBranch,
|
|
68
|
+
mode: row.mode ?? null,
|
|
69
|
+
target: row.browser ?? "chromium",
|
|
70
|
+
width: row.viewportWidth ?? null,
|
|
71
|
+
height: row.viewportHeight ?? null,
|
|
72
|
+
captureFingerprint: parseComparisonReference(row.comparisonMetadata)?.captureFingerprint ?? null,
|
|
73
|
+
sourceSnapshotId: await sourceSnapshotId(deps.db, baseline)
|
|
74
|
+
});
|
|
75
|
+
const result = await diffStoredScreenshots(deps.storage, project, baseline.screenshotPath === row.screenshotPath ? row.screenshotPath : comparison.comparisonImagePath, row.screenshotPath);
|
|
76
|
+
const target = diffPath(project.id, build.id, row.storyId, row.viewportName, row.browser);
|
|
63
77
|
const overlay = await writeDiffOverlay(deps.storage, target, result, result.passed);
|
|
64
78
|
return {
|
|
65
79
|
status: diffStatus(result.passed, false),
|
|
@@ -68,10 +82,10 @@ async function diffPatch(deps, project, build, row, baseline) {
|
|
|
68
82
|
diffRatio: result.diffRatio,
|
|
69
83
|
diffPassed: result.passed,
|
|
70
84
|
baselineId: baseline.id,
|
|
71
|
-
baselineVersion: baseline.updatedAt
|
|
85
|
+
baselineVersion: baseline.updatedAt,
|
|
86
|
+
...comparison
|
|
72
87
|
};
|
|
73
88
|
}
|
|
74
|
-
//#endregion
|
|
75
89
|
export { REDIFFABLE_BUILD_STATUSES, rediffBuild };
|
|
76
90
|
|
|
77
91
|
//# sourceMappingURL=rediff.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rediff.mjs","names":[],"sources":["../../src/capture/rediff.ts"],"sourcesContent":["/** Recompute a build's diffs against the baselines that apply now, without re-rendering. */\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { StorageAdapter } from \"../adapters/storage.ts\";\nimport type { Logger } from \"../logger.ts\";\nimport { NO_BASELINE } from \"../models/baseline-status.ts\";\nimport { BaselineModel } from \"../models/baseline.ts\";\nimport { SnapshotModel } from \"../models/snapshot.ts\";\nimport type { Baseline } from \"../schema/baseline.ts\";\nimport type { Build } from \"../schema/build.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport type { Snapshot } from \"../schema/snapshot.ts\";\nimport { diffPath } from \"../utils/paths.ts\";\nimport { diffStoredScreenshots, writeDiffOverlay } from \"./diff-record.ts\";\nimport { diffStatus } from \"./pipeline.ts\";\n\n/** Dependencies for {@link rediffBuild}. */\nexport interface RediffDeps {\n db: DatabaseAdapter;\n storage: StorageAdapter;\n logger?: Logger;\n}\n\n/** Outcome of a re-diff run. */\nexport interface RediffResult {\n /** Snapshots diffed against their current baseline. */\n rediffed: number;\n /** Snapshots whose status changed (for example `changed` to `unchanged`). */\n statusChanged: number;\n /** Snapshot ids skipped because their stored screenshot is gone. */\n missingScreenshots: string[];\n}\n\n/** Build statuses a re-diff may run in; earlier or failed builds have no complete snapshot set. */\nexport const REDIFFABLE_BUILD_STATUSES: ReadonlySet<string> = new Set([\n \"reviewing\",\n \"approved\",\n \"rejected\",\n]);\n\nconst REDIFFABLE_SNAPSHOT_STATUSES: ReadonlySet<string> = new Set([\"new\", \"changed\", \"unchanged\"]);\n\n/**\n * Re-diff the build's undecided snapshots against the baselines that apply today.\n *\n * Approved and rejected snapshots are decisions and stay untouched; inherited snapshots were never\n * rendered. The caller refreshes the build rollup afterwards.\n */\nexport async function rediffBuild(\n deps: RediffDeps,\n project: Project,\n build: Build,\n): Promise<RediffResult> {\n const snapshots = new SnapshotModel(deps.db);\n const rows = (await snapshots.listByBuild(build.id)).filter(\n (row) => !row.inherited && REDIFFABLE_SNAPSHOT_STATUSES.has(row.status),\n );\n const outcomes = await
|
|
1
|
+
{"version":3,"file":"rediff.mjs","names":[],"sources":["../../src/capture/rediff.ts"],"sourcesContent":["/** Recompute a build's diffs against the baselines that apply now, without re-rendering. */\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { StorageAdapter } from \"../adapters/storage.ts\";\nimport type { Logger } from \"../logger.ts\";\nimport { NO_BASELINE } from \"../models/baseline-status.ts\";\nimport { BaselineModel } from \"../models/baseline.ts\";\nimport { SnapshotModel } from \"../models/snapshot.ts\";\nimport type { Baseline } from \"../schema/baseline.ts\";\nimport type { Build } from \"../schema/build.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport type { Snapshot } from \"../schema/snapshot.ts\";\nimport { mapLimit } from \"../utils/map-limit.ts\";\nimport { diffPath } from \"../utils/paths.ts\";\nimport {\n freezeComparison,\n isComparisonImagePath,\n parseComparisonReference,\n sourceSnapshotId,\n} from \"./comparison-reference.ts\";\nimport { diffStoredScreenshots, writeDiffOverlay } from \"./diff-record.ts\";\nimport { diffStatus, PERSIST_CONCURRENCY } from \"./pipeline.ts\";\n\n/** Dependencies for {@link rediffBuild}. */\nexport interface RediffDeps {\n db: DatabaseAdapter;\n storage: StorageAdapter;\n logger?: Logger;\n}\n\n/** Outcome of a re-diff run. */\nexport interface RediffResult {\n /** Snapshots diffed against their current baseline. */\n rediffed: number;\n /** Snapshots whose status changed (for example `changed` to `unchanged`). */\n statusChanged: number;\n /** Snapshot ids skipped because their stored screenshot is gone. */\n missingScreenshots: string[];\n}\n\n/** Build statuses a re-diff may run in; earlier or failed builds have no complete snapshot set. */\nexport const REDIFFABLE_BUILD_STATUSES: ReadonlySet<string> = new Set([\n \"reviewing\",\n \"approved\",\n \"rejected\",\n]);\n\nconst REDIFFABLE_SNAPSHOT_STATUSES: ReadonlySet<string> = new Set([\"new\", \"changed\", \"unchanged\"]);\n\n/**\n * Re-diff the build's undecided snapshots against the baselines that apply today.\n *\n * Approved and rejected snapshots are decisions and stay untouched; inherited snapshots were never\n * rendered. The caller refreshes the build rollup afterwards.\n */\nexport async function rediffBuild(\n deps: RediffDeps,\n project: Project,\n build: Build,\n): Promise<RediffResult> {\n const snapshots = new SnapshotModel(deps.db);\n const rows = (await snapshots.listByBuild(build.id)).filter(\n (row) => !row.inherited && REDIFFABLE_SNAPSHOT_STATUSES.has(row.status),\n );\n const outcomes = await mapLimit(\n rows,\n PERSIST_CONCURRENCY,\n async (row) => await rediffSnapshot(deps, project, build, row),\n );\n const result: RediffResult = {\n rediffed: outcomes.filter((outcome) => outcome !== \"missing\").length,\n statusChanged: outcomes.filter((outcome) => outcome === \"changed\").length,\n missingScreenshots: rows\n .filter((_row, index) => outcomes[index] === \"missing\")\n .map((row) => row.id),\n };\n deps.logger?.info({ buildId: build.id, ...result }, \"build re-diffed against current baselines\");\n return result;\n}\n\ntype Outcome = \"same\" | \"changed\" | \"missing\";\n\nasync function rediffSnapshot(\n deps: RediffDeps,\n project: Project,\n build: Build,\n row: Snapshot,\n): Promise<Outcome> {\n if (!(await deps.storage.exists(row.screenshotPath))) {\n return \"missing\";\n }\n const baseline = await new BaselineModel(deps.db).resolve(\n project.id,\n row.storyId,\n row.viewportName,\n build.gitBranch,\n project.gitDefaultBranch,\n row.browser,\n );\n const patch = baseline ? await diffPatch(deps, project, build, row, baseline) : noBaselinePatch();\n await new SnapshotModel(deps.db).update(row.id, patch);\n if (\n row.comparisonImagePath &&\n row.comparisonImagePath !== patch.comparisonImagePath &&\n isComparisonImagePath(row.comparisonImagePath, project.id, build.id)\n ) {\n await deps.storage.delete(row.comparisonImagePath).catch(() => {});\n }\n return patch.status === row.status ? \"same\" : \"changed\";\n}\n\nfunction noBaselinePatch(): Partial<Snapshot> {\n return {\n status: \"new\",\n diffPath: null,\n diffPixels: null,\n diffRatio: null,\n diffPassed: null,\n baselineId: null,\n baselineVersion: NO_BASELINE,\n comparisonImagePath: null,\n comparisonMetadata: null,\n };\n}\n\nasync function diffPatch(\n deps: RediffDeps,\n project: Project,\n build: Build,\n row: Snapshot,\n baseline: Baseline,\n): Promise<Partial<Snapshot>> {\n const comparison = await freezeComparison(deps.storage, project.id, build.id, baseline, {\n defaultBranch: project.gitDefaultBranch,\n mode: row.mode ?? null,\n target: row.browser ?? \"chromium\",\n width: row.viewportWidth ?? null,\n height: row.viewportHeight ?? null,\n captureFingerprint:\n parseComparisonReference(row.comparisonMetadata)?.captureFingerprint ?? null,\n sourceSnapshotId: await sourceSnapshotId(deps.db, baseline),\n });\n const result = await diffStoredScreenshots(\n deps.storage,\n project,\n baseline.screenshotPath === row.screenshotPath\n ? row.screenshotPath\n : comparison.comparisonImagePath,\n row.screenshotPath,\n );\n const target = diffPath(project.id, build.id, row.storyId, row.viewportName, row.browser);\n const overlay = await writeDiffOverlay(deps.storage, target, result, result.passed);\n return {\n status: diffStatus(result.passed, false),\n diffPath: overlay,\n diffPixels: result.diffPixels,\n diffRatio: result.diffRatio,\n diffPassed: result.passed,\n baselineId: baseline.id,\n baselineVersion: baseline.updatedAt,\n ...comparison,\n };\n}\n"],"mappings":";;;;;;;;;;;;;AAwCA,MAAa,4CAAiD,IAAI,IAAI;CACpE;CACA;CACA;AACF,CAAC;AAED,MAAM,+CAAoD,IAAI,IAAI;CAAC;CAAO;CAAW;AAAW,CAAC;;;;;;;AAQjG,eAAsB,YACpB,MACA,SACA,OACuB;CAEvB,MAAM,QAAQ,MAAM,IADE,cAAc,KAAK,EACb,CAAC,CAAC,YAAY,MAAM,EAAE,EAAA,CAAG,QAClD,QAAQ,CAAC,IAAI,aAAa,6BAA6B,IAAI,IAAI,MAAM,CACxE;CACA,MAAM,WAAW,MAAM,SACrB,MAAA,GAEA,OAAO,QAAQ,MAAM,eAAe,MAAM,SAAS,OAAO,GAAG,CAC/D;CACA,MAAM,SAAuB;EAC3B,UAAU,SAAS,QAAQ,YAAY,YAAY,SAAS,CAAC,CAAC;EAC9D,eAAe,SAAS,QAAQ,YAAY,YAAY,SAAS,CAAC,CAAC;EACnE,oBAAoB,KACjB,QAAQ,MAAM,UAAU,SAAS,WAAW,SAAS,CAAC,CACtD,KAAK,QAAQ,IAAI,EAAE;CACxB;CACA,KAAK,QAAQ,KAAK;EAAE,SAAS,MAAM;EAAI,GAAG;CAAO,GAAG,2CAA2C;CAC/F,OAAO;AACT;AAIA,eAAe,eACb,MACA,SACA,OACA,KACkB;CAClB,IAAI,CAAE,MAAM,KAAK,QAAQ,OAAO,IAAI,cAAc,GAChD,OAAO;CAET,MAAM,WAAW,MAAM,IAAI,cAAc,KAAK,EAAE,CAAC,CAAC,QAChD,QAAQ,IACR,IAAI,SACJ,IAAI,cACJ,MAAM,WACN,QAAQ,kBACR,IAAI,OACN;CACA,MAAM,QAAQ,WAAW,MAAM,UAAU,MAAM,SAAS,OAAO,KAAK,QAAQ,IAAI,gBAAgB;CAChG,MAAM,IAAI,cAAc,KAAK,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI,KAAK;CACrD,IACE,IAAI,uBACJ,IAAI,wBAAwB,MAAM,uBAClC,sBAAsB,IAAI,qBAAqB,QAAQ,IAAI,MAAM,EAAE,GAEnE,MAAM,KAAK,QAAQ,OAAO,IAAI,mBAAmB,CAAC,CAAC,YAAY,CAAC,CAAC;CAEnE,OAAO,MAAM,WAAW,IAAI,SAAS,SAAS;AAChD;AAEA,SAAS,kBAAqC;CAC5C,OAAO;EACL,QAAQ;EACR,UAAU;EACV,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,YAAY;EACZ,iBAAiB;EACjB,qBAAqB;EACrB,oBAAoB;CACtB;AACF;AAEA,eAAe,UACb,MACA,SACA,OACA,KACA,UAC4B;CAC5B,MAAM,aAAa,MAAM,iBAAiB,KAAK,SAAS,QAAQ,IAAI,MAAM,IAAI,UAAU;EACtF,eAAe,QAAQ;EACvB,MAAM,IAAI,QAAQ;EAClB,QAAQ,IAAI,WAAW;EACvB,OAAO,IAAI,iBAAiB;EAC5B,QAAQ,IAAI,kBAAkB;EAC9B,oBACE,yBAAyB,IAAI,kBAAkB,CAAC,EAAE,sBAAsB;EAC1E,kBAAkB,MAAM,iBAAiB,KAAK,IAAI,QAAQ;CAC5D,CAAC;CACD,MAAM,SAAS,MAAM,sBACnB,KAAK,SACL,SACA,SAAS,mBAAmB,IAAI,iBAC5B,IAAI,iBACJ,WAAW,qBACf,IAAI,cACN;CACA,MAAM,SAAS,SAAS,QAAQ,IAAI,MAAM,IAAI,IAAI,SAAS,IAAI,cAAc,IAAI,OAAO;CACxF,MAAM,UAAU,MAAM,iBAAiB,KAAK,SAAS,QAAQ,QAAQ,OAAO,MAAM;CAClF,OAAO;EACL,QAAQ,WAAW,OAAO,QAAQ,KAAK;EACvC,UAAU;EACV,YAAY,OAAO;EACnB,WAAW,OAAO;EAClB,YAAY,OAAO;EACnB,YAAY,SAAS;EACrB,iBAAiB,SAAS;EAC1B,GAAG;CACL;AACF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import "../utils/storybook-token.mjs";
|
|
5
|
+
import { redactSecrets } from "../utils/redact.mjs";
|
|
6
|
+
// src/capture/render.ts
|
|
7
|
+
/** Default budget for one render call before the orchestrator cancels it. */
|
|
8
|
+
const RENDER_TIMEOUT_MS = 9e5;
|
|
9
|
+
/**
|
|
10
|
+
* Budget for one render call: an explicit setting wins; otherwise the default
|
|
11
|
+
* floor, raised to a per-capture allowance for large matrices. Bounded page
|
|
12
|
+
* concurrency on small hosts makes big builds legitimately take longer than 15 minutes.
|
|
13
|
+
*/
|
|
14
|
+
function renderBudgetMs(captureCount, explicitMs) {
|
|
15
|
+
return explicitMs ?? Math.max(9e5, captureCount * 15e3);
|
|
16
|
+
}
|
|
17
|
+
/** Failure error text cap (persisted rows and logs stay bounded). */
|
|
18
|
+
const FAILURE_ERROR_MAX = 500;
|
|
19
|
+
/** Cap failure error text so one chatty runner cannot flood rows and logs. */
|
|
20
|
+
function capFailures(result) {
|
|
21
|
+
return {
|
|
22
|
+
...result,
|
|
23
|
+
captures: result.captures,
|
|
24
|
+
failures: result.failures.map((failure) => ({
|
|
25
|
+
...failure,
|
|
26
|
+
error: redactSecrets(failure.error).slice(0, FAILURE_ERROR_MAX)
|
|
27
|
+
}))
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Render with a timeout; cancels the runner when the budget expires. */
|
|
31
|
+
async function renderWithTimeout(runner, request, timeoutMs) {
|
|
32
|
+
let timedOut = false;
|
|
33
|
+
let timer;
|
|
34
|
+
const timeout = new Promise((_, reject) => {
|
|
35
|
+
timer = setTimeout(() => {
|
|
36
|
+
timedOut = true;
|
|
37
|
+
reject(/* @__PURE__ */ new Error(`Render timed out after ${timeoutMs}ms`));
|
|
38
|
+
}, timeoutMs);
|
|
39
|
+
});
|
|
40
|
+
timer?.unref?.();
|
|
41
|
+
try {
|
|
42
|
+
return capFailures(await Promise.race([runner.render(request), timeout]));
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (timedOut) await runner.cancel(request.buildId, request.runId).catch(() => {});
|
|
45
|
+
throw error;
|
|
46
|
+
} finally {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export { RENDER_TIMEOUT_MS, renderBudgetMs, renderWithTimeout };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=render.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.mjs","names":[],"sources":["../../src/capture/render.ts"],"sourcesContent":["/** Render one engine's pass with a budget; shared by the orchestrator's browser loop. */\nimport type { Logger } from \"pino\";\nimport type {\n CaptureTarget,\n CaptureRunner,\n RenderResult,\n RenderedSnapshot,\n} from \"../adapters/capture-runner.ts\";\nimport { redactSecrets } from \"../utils/redact.ts\";\nimport { PER_CAPTURE_BUDGET_MS } from \"../utils/storybook-token.ts\";\n\n/** Default budget for one render call before the orchestrator cancels it. */\nexport const RENDER_TIMEOUT_MS = 15 * 60_000;\n\n/**\n * Budget for one render call: an explicit setting wins; otherwise the default\n * floor, raised to a per-capture allowance for large matrices. Bounded page\n * concurrency on small hosts makes big builds legitimately take longer than 15 minutes.\n */\nexport function renderBudgetMs(captureCount: number, explicitMs?: number): number {\n return explicitMs ?? Math.max(RENDER_TIMEOUT_MS, captureCount * PER_CAPTURE_BUDGET_MS);\n}\n\n/** Failure error text cap (persisted rows and logs stay bounded). */\nconst FAILURE_ERROR_MAX = 500;\n\n/** Render input assembled by the orchestrator for one build. */\nexport interface RenderRequest {\n buildId: string;\n /** This render's cancel handle within the build (see `CaptureRunner.render`). */\n runId?: string | undefined;\n /** The shard's 1-based position in the build's plan (see `CaptureRunner.render`). */\n shardIndex?: number | undefined;\n storybookDir: string;\n stories: Parameters<CaptureRunner[\"render\"]>[0][\"stories\"];\n viewports: Parameters<CaptureRunner[\"render\"]>[0][\"viewports\"];\n logger: Logger | undefined;\n executePlay: boolean;\n playTimeoutMs: number;\n runA11y: boolean;\n target: CaptureTarget;\n /** The signed URL a `reach: \"url\"` target opens (never logged); absent for every other target. */\n storybookUrl?: string | undefined;\n onCapture?: (capture: RenderedSnapshot) => Promise<void>;\n}\n\n/** Cap failure error text so one chatty runner cannot flood rows and logs. */\nfunction capFailures(result: RenderResult): RenderResult {\n return {\n ...result,\n captures: result.captures,\n failures: result.failures.map((failure) => ({\n ...failure,\n // A runner's error can quote the URL it failed to open, which carries a signed token.\n error: redactSecrets(failure.error).slice(0, FAILURE_ERROR_MAX),\n })),\n };\n}\n\n/** Render with a timeout; cancels the runner when the budget expires. */\nexport async function renderWithTimeout(\n runner: CaptureRunner,\n request: RenderRequest,\n timeoutMs: number,\n): Promise<RenderResult> {\n let timedOut = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n timedOut = true;\n reject(new Error(`Render timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n timer?.unref?.();\n try {\n return capFailures(await Promise.race([runner.render(request), timeout]));\n } catch (error) {\n if (timedOut) {\n // Only this render: a sibling shard of the same build may be rendering in this process.\n await runner.cancel(request.buildId, request.runId).catch(() => {});\n }\n throw error;\n } finally {\n clearTimeout(timer);\n }\n}\n"],"mappings":";;;;;;;AAYA,MAAa,oBAAoB;;;;;;AAOjC,SAAgB,eAAe,cAAsB,YAA6B;CAChF,OAAO,cAAc,KAAK,IAAA,KAAuB,eAAA,IAAoC;AACvF;;AAGA,MAAM,oBAAoB;;AAuB1B,SAAS,YAAY,QAAoC;CACvD,OAAO;EACL,GAAG;EACH,UAAU,OAAO;EACjB,UAAU,OAAO,SAAS,KAAK,aAAa;GAC1C,GAAG;GAEH,OAAO,cAAc,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG,iBAAiB;EAChE,EAAE;CACJ;AACF;;AAGA,eAAsB,kBACpB,QACA,SACA,WACuB;CACvB,IAAI,WAAW;CACf,IAAI;CACJ,MAAM,UAAU,IAAI,SAAgB,GAAG,WAAW;EAChD,QAAQ,iBAAiB;GACvB,WAAW;GACX,uBAAO,IAAI,MAAM,0BAA0B,UAAU,GAAG,CAAC;EAC3D,GAAG,SAAS;CACd,CAAC;CACD,OAAO,QAAQ;CACf,IAAI;EACF,OAAO,YAAY,MAAM,QAAQ,KAAK,CAAC,OAAO,OAAO,OAAO,GAAG,OAAO,CAAC,CAAC;CAC1E,SAAS,OAAO;EACd,IAAI,UAEF,MAAM,OAAO,OAAO,QAAQ,SAAS,QAAQ,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;EAEpE,MAAM;CACR,UAAU;EACR,aAAa,KAAK;CACpB;AACF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { Logger } from "../logger.mjs";
|
|
4
|
+
/**
|
|
5
|
+
* Subtree of `scratchDir` that holds extracted Storybooks.
|
|
6
|
+
*
|
|
7
|
+
* `scratchDir` is often also the local storage root (dev server, generated servers), where
|
|
8
|
+
* `<project>/builds/<build>/...` holds screenshots and published statics. Keeping scratch in its
|
|
9
|
+
* own subtree means removing it can never touch a storage key.
|
|
10
|
+
*/
|
|
11
|
+
declare const SCRATCH_DIRNAME = ".storyshelf-scratch";
|
|
12
|
+
/** Scratch dirs untouched for this long are assumed orphaned by a crash (no capture runs this long). */
|
|
13
|
+
declare const SCRATCH_MAX_AGE_MS: number;
|
|
14
|
+
/** Scratch directory owned by one build: `<scratchDir>/.storyshelf-scratch/<projectId>/<buildId>`. */
|
|
15
|
+
declare function buildScratchDir(scratchDir: string, projectId: string, buildId: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Remove the scratch of the build's own job (the plan, or the whole build when it is not sharded)
|
|
18
|
+
* and the build directory too if nothing else is left in it.
|
|
19
|
+
*
|
|
20
|
+
* Shards live in their own `shards/` directory beside `job/`, so this can never reach one: the plan
|
|
21
|
+
* hands its shards to the queue before it cleans up, and a worker may already be extracting.
|
|
22
|
+
*/
|
|
23
|
+
declare function removeJobScratch(scratchDir: string, projectId: string, buildId: string, logger?: Logger): Promise<void>;
|
|
24
|
+
/** Remove a build's scratch directory. Best effort: a failure is logged, never thrown. */
|
|
25
|
+
declare function removeBuildScratch(scratchDir: string, projectId: string, buildId: string, logger?: Logger): Promise<void>;
|
|
26
|
+
/** Options for {@link sweepOrphanedScratch}. */
|
|
27
|
+
interface ScratchSweepOptions {
|
|
28
|
+
/** Remove build scratch dirs not modified for this long (default {@link SCRATCH_MAX_AGE_MS}). */
|
|
29
|
+
maxAgeMs?: number;
|
|
30
|
+
/** Clock override for tests. */
|
|
31
|
+
now?: number;
|
|
32
|
+
logger?: Logger;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Boot-time sweep for scratch dirs a crash left behind. Age-gated rather than wholesale so a
|
|
36
|
+
* second process sharing the same `scratchDir` (server plus worker) keeps its live captures.
|
|
37
|
+
*
|
|
38
|
+
* @returns How many build scratch directories were removed.
|
|
39
|
+
*/
|
|
40
|
+
declare function sweepOrphanedScratch(scratchDir: string, options?: ScratchSweepOptions): Promise<number>;
|
|
41
|
+
export { SCRATCH_DIRNAME, SCRATCH_MAX_AGE_MS, ScratchSweepOptions, buildScratchDir, removeBuildScratch, removeJobScratch, sweepOrphanedScratch };
|
|
42
|
+
//# sourceMappingURL=scratch.d.mts.map
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { readdir, rm, rmdir, stat } from "node:fs/promises";
|
|
5
|
+
// src/capture/scratch.ts
|
|
6
|
+
/** Per-build scratch directories: where they live, removing them, and sweeping crash leftovers. */
|
|
7
|
+
/**
|
|
8
|
+
* Subtree of `scratchDir` that holds extracted Storybooks.
|
|
9
|
+
*
|
|
10
|
+
* `scratchDir` is often also the local storage root (dev server, generated servers), where
|
|
11
|
+
* `<project>/builds/<build>/...` holds screenshots and published statics. Keeping scratch in its
|
|
12
|
+
* own subtree means removing it can never touch a storage key.
|
|
13
|
+
*/
|
|
14
|
+
const SCRATCH_DIRNAME = ".storyshelf-scratch";
|
|
15
|
+
/** Scratch dirs untouched for this long are assumed orphaned by a crash (no capture runs this long). */
|
|
16
|
+
const SCRATCH_MAX_AGE_MS = 216e5;
|
|
17
|
+
/** Directory inside a build's scratch directory that holds one subdirectory per shard. */
|
|
18
|
+
const SHARDS_DIRNAME = "shards";
|
|
19
|
+
/** Directory inside a build's scratch directory for the build's own job, apart from its shards. */
|
|
20
|
+
const JOB_DIRNAME = "job";
|
|
21
|
+
/** Scratch directory owned by one build: `<scratchDir>/.storyshelf-scratch/<projectId>/<buildId>`. */
|
|
22
|
+
function buildScratchDir(scratchDir, projectId, buildId) {
|
|
23
|
+
return join(scratchDir, SCRATCH_DIRNAME, projectId, buildId);
|
|
24
|
+
}
|
|
25
|
+
/** Scratch directory of the build's own job (plan or whole build): `<build>/job`, beside `shards/`. */
|
|
26
|
+
function jobScratchDir(scratchDir, projectId, buildId) {
|
|
27
|
+
return join(buildScratchDir(scratchDir, projectId, buildId), JOB_DIRNAME);
|
|
28
|
+
}
|
|
29
|
+
/** Scratch directory of one shard of a build, inside the build's: shards of a build can share a host. */
|
|
30
|
+
function shardScratchDir(scratchDir, projectId, buildId, shardId) {
|
|
31
|
+
return join(buildScratchDir(scratchDir, projectId, buildId), SHARDS_DIRNAME, shardId);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Remove one shard's scratch directory, leaving the build's other shards alone, then the build's
|
|
35
|
+
* directories if that left them empty: whichever shard finishes last tidies up. Best effort.
|
|
36
|
+
*/
|
|
37
|
+
async function removeShardScratch(scratchDir, projectId, buildId, shardId, logger) {
|
|
38
|
+
try {
|
|
39
|
+
await rm(shardScratchDir(scratchDir, projectId, buildId, shardId), {
|
|
40
|
+
recursive: true,
|
|
41
|
+
force: true
|
|
42
|
+
});
|
|
43
|
+
await pruneBuildScratch(scratchDir, projectId, buildId);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
logger?.warn({
|
|
46
|
+
err: error,
|
|
47
|
+
buildId,
|
|
48
|
+
shardId
|
|
49
|
+
}, "failed to remove shard scratch directory");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Remove the scratch of the build's own job (the plan, or the whole build when it is not sharded)
|
|
54
|
+
* and the build directory too if nothing else is left in it.
|
|
55
|
+
*
|
|
56
|
+
* Shards live in their own `shards/` directory beside `job/`, so this can never reach one: the plan
|
|
57
|
+
* hands its shards to the queue before it cleans up, and a worker may already be extracting.
|
|
58
|
+
*/
|
|
59
|
+
async function removeJobScratch(scratchDir, projectId, buildId, logger) {
|
|
60
|
+
try {
|
|
61
|
+
await rm(jobScratchDir(scratchDir, projectId, buildId), {
|
|
62
|
+
recursive: true,
|
|
63
|
+
force: true
|
|
64
|
+
});
|
|
65
|
+
await pruneBuildScratch(scratchDir, projectId, buildId);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
logger?.warn({
|
|
68
|
+
err: error,
|
|
69
|
+
buildId
|
|
70
|
+
}, "failed to remove job scratch directory");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Remove the build's scratch directories that are empty, and nothing that is not. A shard that is
|
|
75
|
+
* still running (a redelivered duplicate of one that already finished) keeps its directory; its own
|
|
76
|
+
* cleanup, or the boot sweep, removes it later. `rmdir` fails on a non-empty directory, which is
|
|
77
|
+
* the point.
|
|
78
|
+
*/
|
|
79
|
+
async function pruneBuildScratch(scratchDir, projectId, buildId) {
|
|
80
|
+
const buildDir = buildScratchDir(scratchDir, projectId, buildId);
|
|
81
|
+
await rmdir(join(buildDir, SHARDS_DIRNAME)).catch(ignore);
|
|
82
|
+
await rmdir(buildDir).catch(ignore);
|
|
83
|
+
}
|
|
84
|
+
/** Remove a build's scratch directory. Best effort: a failure is logged, never thrown. */
|
|
85
|
+
async function removeBuildScratch(scratchDir, projectId, buildId, logger) {
|
|
86
|
+
try {
|
|
87
|
+
await rm(buildScratchDir(scratchDir, projectId, buildId), {
|
|
88
|
+
recursive: true,
|
|
89
|
+
force: true
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
logger?.warn({
|
|
93
|
+
err: error,
|
|
94
|
+
buildId
|
|
95
|
+
}, "failed to remove build scratch directory");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Boot-time sweep for scratch dirs a crash left behind. Age-gated rather than wholesale so a
|
|
100
|
+
* second process sharing the same `scratchDir` (server plus worker) keeps its live captures.
|
|
101
|
+
*
|
|
102
|
+
* @returns How many build scratch directories were removed.
|
|
103
|
+
*/
|
|
104
|
+
async function sweepOrphanedScratch(scratchDir, options = {}) {
|
|
105
|
+
const root = join(scratchDir, SCRATCH_DIRNAME);
|
|
106
|
+
const cutoff = (options.now ?? Date.now()) - (options.maxAgeMs ?? 216e5);
|
|
107
|
+
const projects = await readdir(root).catch(() => []);
|
|
108
|
+
const total = (await Promise.all(projects.map(async (projectId) => await sweepProject(join(root, projectId), cutoff)))).reduce((sum, count) => sum + count, 0);
|
|
109
|
+
if (total > 0) options.logger?.info({ removed: total }, "removed orphaned capture scratch directories");
|
|
110
|
+
return total;
|
|
111
|
+
}
|
|
112
|
+
async function sweepProject(projectDir, cutoff) {
|
|
113
|
+
const builds = await readdir(projectDir).catch(() => []);
|
|
114
|
+
const results = await Promise.all(builds.map(async (buildId) => await sweepBuild(join(projectDir, buildId), cutoff)));
|
|
115
|
+
if ((await readdir(projectDir).catch(() => ["x"])).length === 0) await rm(projectDir, {
|
|
116
|
+
recursive: true,
|
|
117
|
+
force: true
|
|
118
|
+
}).catch(ignore);
|
|
119
|
+
return results.filter(Boolean).length;
|
|
120
|
+
}
|
|
121
|
+
async function sweepBuild(buildDir, cutoff) {
|
|
122
|
+
try {
|
|
123
|
+
if ((await stat(buildDir)).mtimeMs >= cutoff) return false;
|
|
124
|
+
await rm(buildDir, {
|
|
125
|
+
recursive: true,
|
|
126
|
+
force: true
|
|
127
|
+
});
|
|
128
|
+
return true;
|
|
129
|
+
} catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function ignore() {}
|
|
134
|
+
export { SCRATCH_DIRNAME, SCRATCH_MAX_AGE_MS, buildScratchDir, jobScratchDir, pruneBuildScratch, removeBuildScratch, removeJobScratch, removeShardScratch, shardScratchDir, sweepOrphanedScratch };
|
|
135
|
+
|
|
136
|
+
//# sourceMappingURL=scratch.mjs.map
|