@storyshelf/core 0.7.0 → 0.9.0-next-d2cc082
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/dist/adapter/capture-queue.d.mts +0 -2
- package/dist/adapter/capture-runner.d.mts +10 -4
- package/dist/adapter/capture-runner.mjs +7 -2
- package/dist/adapter/database.d.mts +63 -3
- package/dist/adapter/database.mjs +4 -3
- package/dist/adapter/database.mjs.map +1 -1
- package/dist/adapter/design.d.mts +0 -2
- package/dist/adapter/design.mjs +1 -2
- package/dist/adapter/email-sender.d.mts +0 -2
- package/dist/adapter/metadata.d.mts +0 -2
- package/dist/adapter/oauth.d.mts +0 -2
- package/dist/adapter/setup.d.mts +0 -2
- package/dist/adapter/setup.mjs +1 -2
- package/dist/adapter/storage.d.mts +1 -3
- package/dist/adapter/webhook-events.d.mts +0 -2
- package/dist/adapter/webhook-events.mjs +12 -13
- package/dist/adapter/webhook-events.mjs.map +1 -1
- package/dist/adapters/capture-target-offers.d.mts +0 -2
- package/dist/adapters/capture-target-offers.mjs +1 -2
- package/dist/adapters/capture-target.d.mts +0 -2
- package/dist/adapters/capture-target.mjs +1 -2
- package/dist/adapters/notifier/build-comment.d.mts +0 -2
- package/dist/adapters/notifier/build-comment.mjs +1 -2
- package/dist/adapters/notifier/build-state.d.mts +0 -2
- package/dist/adapters/notifier/build-state.mjs +1 -2
- package/dist/adapters/notifier/events.d.mts +0 -2
- package/dist/adapters/notifier/events.mjs +1 -2
- package/dist/adapters/notifier/format.d.mts +0 -2
- package/dist/adapters/notifier/format.mjs +1 -2
- package/dist/adapters/notifier/provider.d.mts +0 -2
- package/dist/adapters/notifier/provider.mjs +1 -2
- package/dist/adapters/notifier/state.d.mts +0 -2
- package/dist/adapters/notifier/state.mjs +1 -2
- package/dist/adapters/notifier/types.d.mts +0 -2
- package/dist/adapters/remote-browser.d.mts +120 -31
- package/dist/adapters/remote-browser.mjs +134 -34
- package/dist/adapters/remote-browser.mjs.map +1 -1
- 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/remote-sizing.d.mts +44 -0
- package/dist/adapters/remote-sizing.mjs +53 -0
- package/dist/adapters/remote-sizing.mjs.map +1 -0
- package/dist/adapters/render-runs.d.mts +0 -2
- package/dist/adapters/render-runs.mjs +1 -2
- package/dist/adapters/setup-runner.d.mts +0 -2
- package/dist/adapters/setup-runner.mjs +1 -2
- package/dist/adapters/sources.d.mts +0 -2
- package/dist/adapters/sources.mjs +1 -2
- package/dist/adapters/validate.d.mts +0 -2
- package/dist/adapters/validate.mjs +2 -2
- package/dist/adapters/validate.mjs.map +1 -1
- package/dist/ai.d.mts +0 -2
- package/dist/ai.mjs +1 -2
- 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 +0 -2
- package/dist/capture/a11y/axe-source.mjs +1 -2
- package/dist/capture/a11y/in-page.d.mts +1 -3
- package/dist/capture/a11y/in-page.mjs +3 -4
- package/dist/capture/a11y/in-page.mjs.map +1 -1
- package/dist/capture/a11y/map.d.mts +0 -2
- package/dist/capture/a11y/map.mjs +1 -2
- package/dist/capture/a11y/options.d.mts +0 -2
- package/dist/capture/a11y/options.mjs +1 -2
- package/dist/capture/adapter.d.mts +5 -2
- package/dist/capture/adapter.mjs +1 -2
- package/dist/capture/adapter.mjs.map +1 -1
- package/dist/capture/affected.d.mts +0 -2
- package/dist/capture/affected.mjs +1 -2
- package/dist/capture/attempt-logger.mjs +1 -2
- package/dist/capture/browsers.d.mts +0 -2
- package/dist/capture/browsers.mjs +1 -2
- package/dist/capture/build-state/deliver.d.mts +0 -2
- package/dist/capture/build-state/deliver.mjs +1 -2
- package/dist/capture/build-state/notify-job.d.mts +0 -2
- package/dist/capture/build-state/notify-job.mjs +1 -2
- package/dist/capture/build-state/publisher.d.mts +0 -2
- package/dist/capture/build-state/publisher.mjs +1 -2
- package/dist/capture/build-state/resume.d.mts +0 -2
- package/dist/capture/build-state/resume.mjs +1 -2
- package/dist/capture/build-state/types.d.mts +1 -3
- package/dist/capture/catalog/catalogue.d.mts +0 -2
- package/dist/capture/catalog/catalogue.mjs +1 -2
- package/dist/capture/catalog/components.d.mts +0 -2
- package/dist/capture/catalog/components.mjs +1 -2
- package/dist/capture/catalog/history.d.mts +0 -2
- package/dist/capture/catalog/history.mjs +1 -2
- package/dist/capture/catalog/hook.d.mts +0 -2
- package/dist/capture/catalog/hook.mjs +1 -2
- package/dist/capture/catalog/index.d.mts +2 -2
- package/dist/capture/catalog/load.d.mts +0 -2
- package/dist/capture/catalog/load.mjs +1 -2
- package/dist/capture/catalog/parse.d.mts +0 -2
- package/dist/capture/catalog/parse.mjs +1 -2
- package/dist/capture/catalog/read.d.mts +6 -3
- package/dist/capture/catalog/read.mjs +14 -8
- package/dist/capture/catalog/read.mjs.map +1 -1
- package/dist/capture/catalog/types.d.mts +0 -2
- 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 +1 -3
- package/dist/capture/consumer/capture-handler.mjs +1 -2
- package/dist/capture/consumer/idle.d.mts +0 -2
- package/dist/capture/consumer/idle.mjs +1 -2
- package/dist/capture/consumer/index.d.mts +0 -2
- package/dist/capture/consumer/index.mjs +1 -2
- package/dist/capture/consumer/loop.mjs +1 -2
- package/dist/capture/consumer/metrics.d.mts +0 -2
- package/dist/capture/consumer/metrics.mjs +1 -2
- package/dist/capture/consumer/retry.d.mts +0 -2
- package/dist/capture/consumer/retry.mjs +1 -2
- package/dist/capture/consumer/run-job.mjs +1 -2
- package/dist/capture/consumer/startup.mjs +1 -2
- package/dist/capture/consumer/types.d.mts +0 -2
- package/dist/capture/crash-failure.d.mts +0 -2
- package/dist/capture/crash-failure.mjs +1 -2
- package/dist/capture/db-queue/cadence.d.mts +0 -2
- package/dist/capture/db-queue/cadence.mjs +1 -2
- package/dist/capture/db-queue/claim.d.mts +0 -2
- package/dist/capture/db-queue/claim.mjs +20 -4
- package/dist/capture/db-queue/claim.mjs.map +1 -1
- package/dist/capture/db-queue/clock.mjs +1 -2
- package/dist/capture/db-queue/codec.mjs +1 -2
- package/dist/capture/db-queue/index.d.mts +0 -2
- package/dist/capture/db-queue/index.mjs +3 -3
- package/dist/capture/db-queue/index.mjs.map +1 -1
- package/dist/capture/db-queue/keeper.d.mts +0 -2
- package/dist/capture/db-queue/keeper.mjs +1 -2
- package/dist/capture/db-queue/lease.mjs +1 -2
- package/dist/capture/db-queue/lifecycle.mjs +1 -2
- package/dist/capture/db-queue/operations.mjs +1 -2
- package/dist/capture/db-queue/poll-loop.d.mts +0 -2
- package/dist/capture/db-queue/poll-loop.mjs +1 -2
- package/dist/capture/db-queue/poll.d.mts +0 -2
- package/dist/capture/db-queue/poll.mjs +1 -2
- package/dist/capture/db-queue/timers.d.mts +0 -2
- package/dist/capture/db-queue/timers.mjs +1 -2
- package/dist/capture/db-queue/types.d.mts +0 -2
- package/dist/capture/db-queue/types.mjs +1 -2
- package/dist/capture/db-queue/types.mjs.map +1 -1
- package/dist/capture/db-queue/wake.mjs +1 -2
- package/dist/capture/design.mjs +1 -2
- package/dist/capture/diff-record.mjs +1 -2
- package/dist/capture/dispatch.d.mts +1 -3
- package/dist/capture/dispatch.mjs +17 -5
- package/dist/capture/dispatch.mjs.map +1 -1
- package/dist/capture/enrich.mjs +1 -2
- package/dist/capture/failure-sets.mjs +1 -2
- package/dist/capture/fingerprint.d.mts +19 -8
- package/dist/capture/fingerprint.mjs +43 -14
- package/dist/capture/fingerprint.mjs.map +1 -1
- package/dist/capture/forked/channel.d.mts +0 -2
- package/dist/capture/forked/child.d.mts +0 -2
- package/dist/capture/forked/child.mjs +1 -2
- package/dist/capture/forked/crash-tracker.mjs +1 -2
- package/dist/capture/forked/decision.d.mts +0 -2
- package/dist/capture/forked/decision.mjs +1 -2
- package/dist/capture/forked/exit.mjs +1 -2
- package/dist/capture/forked/fork.d.mts +0 -2
- package/dist/capture/forked/fork.mjs +1 -2
- package/dist/capture/forked/forked-capture.d.mts +0 -2
- package/dist/capture/forked/forked-capture.mjs +1 -2
- package/dist/capture/forked/lease-book.mjs +1 -2
- package/dist/capture/forked/protocol.d.mts +0 -2
- package/dist/capture/forked/protocol.mjs +1 -2
- package/dist/capture/forked/runs.mjs +1 -2
- 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 +1 -2
- package/dist/capture/job-lease.d.mts +0 -2
- package/dist/capture/job-lease.mjs +1 -2
- package/dist/capture/matrix.mjs +4 -4
- package/dist/capture/matrix.mjs.map +1 -1
- package/dist/capture/modes.d.mts +0 -2
- package/dist/capture/modes.mjs +2 -3
- package/dist/capture/modes.mjs.map +1 -1
- package/dist/capture/orchestrator.d.mts +0 -2
- package/dist/capture/orchestrator.mjs +2 -3
- package/dist/capture/pipeline.d.mts +0 -2
- package/dist/capture/pipeline.mjs +44 -10
- package/dist/capture/pipeline.mjs.map +1 -1
- package/dist/capture/progress.d.mts +0 -2
- package/dist/capture/progress.mjs +1 -2
- package/dist/capture/publish/accept.d.mts +0 -2
- package/dist/capture/publish/accept.mjs +1 -2
- package/dist/capture/publish/complete.d.mts +1 -3
- package/dist/capture/publish/complete.mjs +1 -2
- package/dist/capture/publish/extract.d.mts +0 -2
- package/dist/capture/publish/extract.mjs +6 -5
- package/dist/capture/publish/extract.mjs.map +1 -1
- package/dist/capture/publish/handler.d.mts +1 -3
- package/dist/capture/publish/handler.mjs +1 -2
- package/dist/capture/publish/index.d.mts +2 -1
- 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 +0 -2
- package/dist/capture/publish/limits.mjs +1 -2
- package/dist/capture/publish/published.d.mts +0 -2
- package/dist/capture/publish/published.mjs +1 -2
- package/dist/capture/publish/run.d.mts +1 -3
- package/dist/capture/publish/run.mjs +1 -2
- package/dist/capture/rediff.d.mts +1 -3
- package/dist/capture/rediff.mjs +19 -6
- package/dist/capture/rediff.mjs.map +1 -1
- package/dist/capture/render.mjs +1 -2
- package/dist/capture/render.mjs.map +1 -1
- package/dist/capture/scratch.d.mts +0 -2
- package/dist/capture/scratch.mjs +2 -4
- package/dist/capture/scratch.mjs.map +1 -1
- package/dist/capture/shard-plan.mjs +1 -2
- package/dist/capture/shards/context.mjs +3 -3
- package/dist/capture/shards/context.mjs.map +1 -1
- package/dist/capture/shards/execute.mjs +4 -3
- package/dist/capture/shards/execute.mjs.map +1 -1
- package/dist/capture/shards/fan-out.mjs +1 -2
- package/dist/capture/shards/history.mjs +1 -2
- package/dist/capture/shards/reduce.mjs +1 -2
- package/dist/capture/sizing.d.mts +0 -2
- package/dist/capture/sizing.mjs +1 -2
- package/dist/capture/skip-checks.mjs +1 -2
- package/dist/capture/statics.d.mts +0 -2
- package/dist/capture/statics.mjs +2 -4
- package/dist/capture/statics.mjs.map +1 -1
- package/dist/capture/storybook-urls.d.mts +0 -2
- package/dist/capture/storybook-urls.mjs +3 -3
- package/dist/capture/storybook-urls.mjs.map +1 -1
- package/dist/capture/storybook.d.mts +0 -2
- package/dist/capture/storybook.mjs +8 -4
- package/dist/capture/storybook.mjs.map +1 -1
- package/dist/capture/target.mjs +1 -2
- package/dist/capture/targets.d.mts +0 -2
- package/dist/capture/targets.mjs +1 -2
- package/dist/capture/tests.d.mts +0 -2
- package/dist/capture/tests.mjs +13 -3
- package/dist/capture/tests.mjs.map +1 -1
- package/dist/capture/token-chunks.mjs +24 -7
- package/dist/capture/token-chunks.mjs.map +1 -1
- package/dist/capture.d.mts +5 -2
- package/dist/capture.mjs +5 -2
- package/dist/config.d.mts +16 -3
- package/dist/config.mjs +6 -3
- package/dist/config.mjs.map +1 -1
- package/dist/diff.d.mts +0 -2
- package/dist/diff.mjs +1 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/insights/budget.d.mts +0 -2
- package/dist/insights/budget.mjs +1 -2
- package/dist/insights/envelope.d.mts +0 -2
- package/dist/insights/envelope.mjs +1 -2
- package/dist/insights/evidence-health.d.mts +0 -2
- package/dist/insights/evidence-health.mjs +1 -2
- package/dist/insights/evidence.d.mts +0 -2
- package/dist/insights/evidence.mjs +1 -2
- package/dist/insights/hash.d.mts +0 -2
- package/dist/insights/hash.mjs +1 -2
- package/dist/insights/limits.d.mts +0 -2
- package/dist/insights/limits.mjs +1 -2
- package/dist/insights/prompts/v1.d.mts +0 -2
- package/dist/insights/prompts/v1.mjs +1 -2
- package/dist/insights/redact.d.mts +0 -2
- package/dist/insights/redact.mjs +1 -2
- package/dist/insights/text.mjs +1 -2
- package/dist/logger.d.mts +0 -2
- package/dist/logger.mjs +1 -2
- package/dist/models/ai-budget-alert.d.mts +0 -2
- package/dist/models/ai-budget-alert.mjs +1 -2
- package/dist/models/ai-usage.d.mts +0 -2
- package/dist/models/ai-usage.mjs +1 -2
- 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 +0 -2
- package/dist/models/baseline-archive.mjs +1 -2
- 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 +0 -2
- package/dist/models/baseline-export.mjs +1 -2
- package/dist/models/baseline-import.mjs +1 -2
- 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 +1 -2
- package/dist/models/baseline-transfer.mjs +30 -2
- package/dist/models/baseline-transfer.mjs.map +1 -1
- package/dist/models/baseline.d.mts +5 -2
- package/dist/models/baseline.mjs +91 -12
- package/dist/models/baseline.mjs.map +1 -1
- package/dist/models/build-component.d.mts +0 -2
- package/dist/models/build-component.mjs +1 -2
- package/dist/models/build-review-status.d.mts +0 -2
- package/dist/models/build-review-status.mjs +1 -2
- package/dist/models/build-review.d.mts +0 -2
- package/dist/models/build-review.mjs +1 -2
- package/dist/models/build.d.mts +1 -3
- package/dist/models/build.mjs +14 -15
- package/dist/models/build.mjs.map +1 -1
- package/dist/models/capture-attempt.d.mts +0 -2
- package/dist/models/capture-attempt.mjs +1 -2
- package/dist/models/capture-job.d.mts +0 -2
- package/dist/models/capture-job.mjs +1 -2
- package/dist/models/capture-log.d.mts +0 -2
- package/dist/models/capture-log.mjs +1 -2
- package/dist/models/capture-shard.d.mts +0 -2
- package/dist/models/capture-shard.mjs +1 -2
- package/dist/models/changeset.d.mts +0 -2
- package/dist/models/changeset.mjs +1 -2
- package/dist/models/columns.mjs +1 -2
- package/dist/models/comment.d.mts +0 -2
- package/dist/models/comment.mjs +1 -2
- package/dist/models/component.d.mts +0 -2
- package/dist/models/component.mjs +1 -2
- package/dist/models/connections.d.mts +0 -2
- package/dist/models/connections.mjs +1 -2
- package/dist/models/content-ref.d.mts +0 -2
- package/dist/models/content-ref.mjs +1 -2
- package/dist/models/credentials.d.mts +0 -2
- package/dist/models/credentials.mjs +1 -2
- package/dist/models/design-credentials.d.mts +0 -2
- package/dist/models/design-credentials.mjs +1 -2
- package/dist/models/design-health.d.mts +16 -3
- package/dist/models/design-health.mjs +21 -3
- package/dist/models/design-health.mjs.map +1 -1
- package/dist/models/design-nodes.d.mts +11 -4
- package/dist/models/design-nodes.mjs +18 -3
- package/dist/models/design-nodes.mjs.map +1 -1
- package/dist/models/design-renders.mjs +1 -2
- package/dist/models/design-resolve.d.mts +0 -2
- package/dist/models/design-resolve.mjs +1 -2
- package/dist/models/design.d.mts +0 -2
- package/dist/models/design.mjs +1 -2
- package/dist/models/inherited-ratio.d.mts +0 -2
- package/dist/models/inherited-ratio.mjs +1 -2
- package/dist/models/insight.d.mts +0 -2
- package/dist/models/insight.mjs +1 -2
- package/dist/models/label.d.mts +0 -2
- package/dist/models/label.mjs +1 -2
- package/dist/models/member.d.mts +0 -2
- package/dist/models/member.mjs +1 -2
- package/dist/models/notification-channel.d.mts +0 -2
- package/dist/models/notification-channel.mjs +1 -2
- package/dist/models/notification-subscription.d.mts +0 -2
- package/dist/models/notification-subscription.mjs +1 -2
- package/dist/models/project-group-mapping.d.mts +0 -2
- package/dist/models/project-group-mapping.mjs +1 -2
- package/dist/models/project.d.mts +0 -2
- package/dist/models/project.mjs +1 -2
- package/dist/models/public-origin.d.mts +0 -2
- package/dist/models/public-origin.mjs +1 -2
- package/dist/models/review-switch-off.d.mts +0 -2
- package/dist/models/review-switch-off.mjs +1 -2
- package/dist/models/site-settings.d.mts +0 -2
- package/dist/models/site-settings.mjs +1 -2
- package/dist/models/snapshot.d.mts +3 -2
- package/dist/models/snapshot.mjs +4 -2
- package/dist/models/snapshot.mjs.map +1 -1
- package/dist/models/token.d.mts +0 -2
- package/dist/models/token.mjs +1 -2
- package/dist/models/usage.d.mts +0 -2
- package/dist/models/usage.mjs +1 -2
- package/dist/models/user.d.mts +0 -2
- package/dist/models/user.mjs +1 -2
- package/dist/models/webhook.d.mts +0 -2
- package/dist/models/webhook.mjs +1 -2
- package/dist/models.d.mts +6 -3
- package/dist/models.mjs +6 -3
- package/dist/options.d.mts +0 -2
- package/dist/options.mjs +2 -4
- package/dist/options.mjs.map +1 -1
- package/dist/paths.d.mts +3 -3
- package/dist/paths.mjs +7 -3
- package/dist/paths.mjs.map +1 -1
- package/dist/retention/ai.d.mts +1 -3
- package/dist/retention/ai.mjs +0 -1
- package/dist/retention/pending.mjs +1 -2
- 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 +0 -2
- package/dist/retention/screenshot-sweep.mjs +1 -2
- package/dist/retention.d.mts +0 -2
- package/dist/retention.mjs +5 -2
- package/dist/retention.mjs.map +1 -1
- package/dist/schema/baseline.d.mts +2 -2
- package/dist/schema/build-component.d.mts +0 -2
- package/dist/schema/build-review.d.mts +0 -2
- package/dist/schema/build.d.mts +0 -2
- package/dist/schema/capture-attempt.d.mts +0 -2
- package/dist/schema/capture-job.d.mts +0 -2
- package/dist/schema/capture-shard.d.mts +0 -2
- package/dist/schema/comment.d.mts +0 -2
- package/dist/schema/connection.d.mts +0 -2
- package/dist/schema/content-ref.d.mts +0 -2
- package/dist/schema/design.d.mts +2 -2
- package/dist/schema/insight.d.mts +0 -2
- package/dist/schema/label.d.mts +0 -2
- package/dist/schema/member.d.mts +0 -2
- package/dist/schema/notification.d.mts +0 -2
- package/dist/schema/project-group-mapping.d.mts +0 -2
- package/dist/schema/project.d.mts +0 -2
- package/dist/schema/site-setting.d.mts +0 -2
- package/dist/schema/snapshot.d.mts +5 -2
- package/dist/schema/token.d.mts +0 -2
- package/dist/schema/usage.d.mts +0 -2
- package/dist/schema/user.d.mts +0 -2
- package/dist/schema/webhook.d.mts +0 -2
- package/dist/schema.d.mts +4 -6
- package/dist/serverless.d.mts +0 -2
- package/dist/serverless.mjs +1 -2
- 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 +0 -2
- 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 +0 -2
- package/dist/test-helpers/deferred.mjs +1 -2
- package/dist/test-helpers/design-contract.d.mts +0 -2
- package/dist/test-helpers/design-contract.mjs +1 -2
- 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 +7 -2
- package/dist/test-helpers/fake-database.mjs.map +1 -1
- package/dist/test-helpers/fake-design.d.mts +0 -2
- package/dist/test-helpers/fake-design.mjs +1 -2
- package/dist/test-helpers/fake-notifier.d.mts +0 -2
- package/dist/test-helpers/fake-notifier.mjs +1 -2
- 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 +6 -2
- package/dist/test-helpers/fake-tables.mjs.map +1 -1
- package/dist/test-helpers/manual-clock.d.mts +0 -2
- package/dist/test-helpers/manual-clock.mjs +1 -2
- package/dist/test-helpers/notifier-contract.d.mts +0 -2
- package/dist/test-helpers/notifier-contract.mjs +1 -2
- package/dist/test-helpers/queue-contract.d.mts +0 -2
- package/dist/test-helpers/queue-contract.mjs +1 -2
- package/dist/test-helpers/queue-multi-instance.d.mts +0 -2
- package/dist/test-helpers/queue-multi-instance.mjs +1 -2
- package/dist/test-helpers/runner-contract.d.mts +0 -2
- package/dist/test-helpers/runner-contract.mjs +1 -2
- package/dist/test-helpers/sql-chunks.mjs +2 -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 +1 -2
- package/dist/test-helpers.d.mts +2 -1
- package/dist/test-helpers.mjs +2 -1
- package/dist/tracing.mjs +36 -6
- package/dist/tracing.mjs.map +1 -1
- package/dist/types.d.mts +0 -2
- package/dist/types.mjs +1 -2
- package/dist/urls.d.mts +0 -2
- package/dist/urls.mjs +1 -2
- package/dist/utils/adaptive-concurrency.d.mts +0 -2
- package/dist/utils/adaptive-concurrency.mjs +1 -2
- package/dist/utils/connect-retry.d.mts +2 -2
- package/dist/utils/connect-retry.mjs +2 -3
- package/dist/utils/connect-retry.mjs.map +1 -1
- package/dist/utils/encrypt.d.mts +0 -2
- package/dist/utils/encrypt.mjs +1 -2
- package/dist/utils/environment.d.mts +0 -2
- package/dist/utils/environment.mjs +1 -2
- package/dist/utils/hash.d.mts +0 -2
- package/dist/utils/hash.mjs +1 -2
- package/dist/utils/http.d.mts +13 -3
- package/dist/utils/http.mjs +79 -17
- package/dist/utils/http.mjs.map +1 -1
- package/dist/utils/map-adaptive.d.mts +0 -2
- package/dist/utils/map-adaptive.mjs +1 -2
- package/dist/utils/map-limit.d.mts +0 -2
- package/dist/utils/map-limit.mjs +1 -2
- package/dist/utils/mime.d.mts +0 -2
- package/dist/utils/mime.mjs +1 -2
- package/dist/utils/page-limiter.d.mts +0 -2
- package/dist/utils/page-limiter.mjs +1 -2
- 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 +0 -2
- package/dist/utils/public-origin.mjs +1 -2
- package/dist/utils/redact.d.mts +0 -2
- package/dist/utils/redact.mjs +1 -2
- package/dist/utils/remote-environment.d.mts +40 -3
- package/dist/utils/remote-environment.mjs +52 -3
- package/dist/utils/remote-environment.mjs.map +1 -1
- package/dist/utils/resources.d.mts +0 -2
- package/dist/utils/resources.mjs +1 -2
- package/dist/utils/screenshot-store.d.mts +0 -2
- package/dist/utils/screenshot-store.mjs +1 -2
- package/dist/utils/session-gate.d.mts +7 -6
- package/dist/utils/session-gate.mjs +28 -12
- package/dist/utils/session-gate.mjs.map +1 -1
- package/dist/utils/storybook-token.d.mts +11 -3
- package/dist/utils/storybook-token.mjs +10 -9
- package/dist/utils/storybook-token.mjs.map +1 -1
- package/dist/utils/storybook-url.d.mts +0 -2
- package/dist/utils/storybook-url.mjs +1 -2
- package/dist/utils/timing.d.mts +0 -2
- package/dist/utils/timing.mjs +1 -2
- package/dist/utils/ulid.d.mts +0 -2
- package/dist/utils/ulid.mjs +1 -2
- package/dist/utils/zip-read.mjs +1 -2
- package/dist/utils/zip-write.d.mts +0 -2
- package/dist/utils/zip-write.mjs +1 -2
- package/dist/utils.d.mts +5 -5
- package/dist/utils.mjs +5 -5
- package/package.json +6 -15
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
|
|
4
|
+
// src/capture/db-queue/types.ts
|
|
5
5
|
/** Default lease per attempt: long enough for a slow stage, short enough to recover a crash. */
|
|
6
6
|
const DEFAULT_LEASE_MS = 3e5;
|
|
7
7
|
/** Default `testing.retries` (ADR 0006, decision 11). */
|
|
8
8
|
const DEFAULT_RETRIES = 2;
|
|
9
|
-
//#endregion
|
|
10
9
|
export { DEFAULT_LEASE_MS, DEFAULT_RETRIES };
|
|
11
10
|
|
|
12
11
|
//# sourceMappingURL=types.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","names":[],"sources":["../../../src/capture/db-queue/types.ts"],"sourcesContent":["/** Option, job and runtime types of the database capture queue. */\nimport type {\n CaptureJob,\n LeaseRenewal,\n PollableCaptureQueue,\n PollableJob,\n} from \"../../adapters/capture-queue.ts\";\nimport type { AdapterLifecycle } from \"../../adapters/metadata.ts\";\nimport type { Logger } from \"../../logger.ts\";\nimport type { CaptureJobModel } from \"../../models/capture-job.ts\";\nimport type { CaptureJobKind } from \"../../schema/capture-job.ts\";\nimport type { QueueTimers } from \"./timers.ts\";\nimport type { WakeSignal } from \"./wake.ts\";\n\n/** Options of {@link createDatabaseCaptureQueue}. */\nexport interface DatabaseCaptureQueueOptions {\n /** Job kinds this instance polls (default `[\"capture\"]`); enqueue accepts every kind. */\n kinds?: readonly CaptureJobKind[];\n /** Lease granted per attempt, renewed by a heartbeat and by progress (default {@link DEFAULT_LEASE_MS}, 5 min; `testing.leaseSeconds`). */\n leaseMs?: number;\n /** Retries after the first attempt (`testing.retries`, default 2: three attempts in total). */\n retries?: number;\n /** Identity written on the attempt rows this instance holds (default host, pid and a random tag). */\n owner?: string;\n /** Clock in epoch ms (default `Date.now`); tests inject one to drive leases and visibility. */\n now?: () => number;\n /** Timers of the local wake wait (default the global timers); tests inject a manual clock. */\n timers?: QueueTimers;\n /** Explicit logger override; the host normally binds one through `setLogger`. */\n logger?: Logger;\n /**\n * Called after a job failed because its last attempt lost its lease: nothing was running to\n * record the failure, so the host writes it (a build left `capturing`). May run on every\n * instance that finds the job, so it must be idempotent; a throw is logged and ignored.\n */\n onExhausted?: (job: DatabaseJob, error: string) => Promise<void>;\n}\n\n/** Default lease per attempt: long enough for a slow stage, short enough to recover a crash. */\nexport const DEFAULT_LEASE_MS = 5 * 60_000;\n\n/** Default `testing.retries` (ADR 0006, decision 11). */\nexport const DEFAULT_RETRIES = 2;\n\n/** A job of any kind, as `enqueueJob` takes it. */\nexport interface QueueJobInput {\n kind: CaptureJobKind;\n /** Build the job works on; notify jobs may have none. */\n buildId?: string | null;\n /** `capture_shards` row, for a shard capture job. */\n shard?: string;\n reqId?: string;\n traceparent?: string;\n /** Kind-specific fields (channel id, zip key, …), stored as JSON. */\n data?: Record<string, unknown>;\n /** Attempts allowed in total for this job; defaults to the queue's (`retries` + 1). */\n maxAttempts?: number;\n}\n\n/** A job claimed from the database queue. */\nexport interface DatabaseJob extends PollableJob {\n /** Id of the job row (`receipt` is the attempt row, `<jobId>:<attempt>`). */\n jobId: string;\n kind: CaptureJobKind;\n /** Attempt number, from 1 (`attempts` is the number made before this one). */\n attempt: number;\n maxAttempts: number;\n /** Kind-specific fields given at enqueue. */\n data: Record<string, unknown>;\n}\n\n/** The database queue: a {@link PollableCaptureQueue} plus multi-kind enqueue and a local wake. */\nexport interface DatabaseCaptureQueue extends PollableCaptureQueue {\n readonly lifecycle: AdapterLifecycle;\n poll(options?: { waitMs?: number }): Promise<DatabaseJob | null>;\n extend(job: PollableJob): Promise<LeaseRenewal>;\n /** Put a job of any kind on the queue; resolves to its job id. */\n enqueueJob(job: QueueJobInput): Promise<string>;\n /** Cancel a job by job id, or every unfinished job of a build (every kind) by build id. */\n cancel(id: string): Promise<boolean>;\n /** Read the job's state without renewing its lease (the 5 s cancel check). */\n inspect(job: PollableJob): Promise<LeaseRenewal>;\n /**\n * Resolve true when this instance enqueues a job (including one enqueued since the last `poll`\n * began, so no wake-up is lost), false after `ms`.\n */\n waitForWork(ms: number): Promise<boolean>;\n}\n\n/** State shared by the queue's modules. */\nexport interface QueueRuntime {\n model: CaptureJobModel;\n kinds: readonly CaptureJobKind[];\n leaseMs: number;\n maxAttempts: number;\n owner: string;\n now: () => number;\n wake: WakeSignal;\n /** Wake version read when the latest poll began. */\n pollVersion: number;\n logger?: Logger;\n onExhausted?: DatabaseCaptureQueueOptions[\"onExhausted\"];\n}\n\n/** The capture-shaped job `enqueue` takes, re-exported for the modules. */\nexport type { CaptureJob };\n"],"mappings":";;;;;AAuCA,MAAa,mBAAmB;;AAGhC,MAAa,kBAAkB"}
|
|
1
|
+
{"version":3,"file":"types.mjs","names":[],"sources":["../../../src/capture/db-queue/types.ts"],"sourcesContent":["/** Option, job and runtime types of the database capture queue. */\nimport type {\n CaptureJob,\n LeaseRenewal,\n PollableCaptureQueue,\n PollableJob,\n} from \"../../adapters/capture-queue.ts\";\nimport type { AdapterLifecycle } from \"../../adapters/metadata.ts\";\nimport type { Logger } from \"../../logger.ts\";\nimport type { CaptureJobModel } from \"../../models/capture-job.ts\";\nimport type { CaptureJobKind } from \"../../schema/capture-job.ts\";\nimport type { QueueTimers } from \"./timers.ts\";\nimport type { WakeSignal } from \"./wake.ts\";\n\n/** Options of {@link createDatabaseCaptureQueue}. */\nexport interface DatabaseCaptureQueueOptions {\n /** Job kinds this instance polls (default `[\"capture\"]`); enqueue accepts every kind. */\n kinds?: readonly CaptureJobKind[];\n /** Lease granted per attempt, renewed by a heartbeat and by progress (default {@link DEFAULT_LEASE_MS}, 5 min; `testing.leaseSeconds`). */\n leaseMs?: number;\n /** Retries after the first attempt (`testing.retries`, default 2: three attempts in total). */\n retries?: number;\n /** Identity written on the attempt rows this instance holds (default host, pid and a random tag). */\n owner?: string;\n /** Clock in epoch ms (default `Date.now`); tests inject one to drive leases and visibility. */\n now?: () => number;\n /** Timers of the local wake wait (default the global timers); tests inject a manual clock. */\n timers?: QueueTimers;\n /** Explicit logger override; the host normally binds one through `setLogger`. */\n logger?: Logger;\n /**\n * Called after a job failed because its last attempt lost its lease: nothing was running to\n * record the failure, so the host writes it (a build left `capturing`). May run on every\n * instance that finds the job, so it must be idempotent; a throw is logged and ignored.\n */\n onExhausted?: (job: DatabaseJob, error: string) => Promise<void>;\n}\n\n/** Default lease per attempt: long enough for a slow stage, short enough to recover a crash. */\nexport const DEFAULT_LEASE_MS = 5 * 60_000;\n\n/** Default `testing.retries` (ADR 0006, decision 11). */\nexport const DEFAULT_RETRIES = 2;\n\n/** A job of any kind, as `enqueueJob` takes it. */\nexport interface QueueJobInput {\n kind: CaptureJobKind;\n /** Build the job works on; notify jobs may have none. */\n buildId?: string | null;\n /** `capture_shards` row, for a shard capture job. */\n shard?: string;\n reqId?: string;\n traceparent?: string;\n /** Kind-specific fields (channel id, zip key, …), stored as JSON. */\n data?: Record<string, unknown>;\n /** Attempts allowed in total for this job; defaults to the queue's (`retries` + 1). */\n maxAttempts?: number;\n}\n\n/** A job claimed from the database queue. */\nexport interface DatabaseJob extends PollableJob {\n /** Id of the job row (`receipt` is the attempt row, `<jobId>:<attempt>`). */\n jobId: string;\n kind: CaptureJobKind;\n /** Attempt number, from 1 (`attempts` is the number made before this one). */\n attempt: number;\n maxAttempts: number;\n /** Kind-specific fields given at enqueue. */\n data: Record<string, unknown>;\n}\n\n/** The database queue: a {@link PollableCaptureQueue} plus multi-kind enqueue and a local wake. */\nexport interface DatabaseCaptureQueue extends PollableCaptureQueue {\n readonly lifecycle: AdapterLifecycle;\n poll(options?: { waitMs?: number }): Promise<DatabaseJob | null>;\n extend(job: PollableJob): Promise<LeaseRenewal>;\n /** Put a job of any kind on the queue; resolves to its job id. */\n enqueueJob(job: QueueJobInput): Promise<string>;\n /** Cancel a job by job id, or every unfinished job of a build (every kind) by build id. */\n cancel(id: string): Promise<boolean>;\n /** Read the job's state without renewing its lease (the 5 s cancel check). */\n inspect(job: PollableJob): Promise<LeaseRenewal>;\n /**\n * Resolve true when this instance enqueues a job (including one enqueued since the last `poll`\n * began, so no wake-up is lost), false after `ms`.\n */\n waitForWork(ms: number): Promise<boolean>;\n}\n\n/** State shared by the queue's modules. */\nexport interface QueueRuntime {\n model: CaptureJobModel;\n kinds: readonly CaptureJobKind[];\n leaseMs: number;\n maxAttempts: number;\n owner: string;\n now: () => number;\n timers?: QueueTimers;\n wake: WakeSignal;\n /** Wake version read when the latest poll began. */\n pollVersion: number;\n logger?: Logger;\n onExhausted?: DatabaseCaptureQueueOptions[\"onExhausted\"];\n}\n\n/** The capture-shaped job `enqueue` takes, re-exported for the modules. */\nexport type { CaptureJob };\n"],"mappings":";;;;;AAuCA,MAAa,mBAAmB;;AAGhC,MAAa,kBAAkB"}
|
|
@@ -2,7 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { REAL_TIMERS } from "./timers.mjs";
|
|
5
|
-
|
|
5
|
+
// src/capture/db-queue/wake.ts
|
|
6
6
|
/** In-process wake signal: an enqueue on this instance wakes its waiting poller at once. */
|
|
7
7
|
/** Create a wake signal over `timers` (unref'd globals by default). */
|
|
8
8
|
function createWakeSignal(timers = REAL_TIMERS) {
|
|
@@ -42,7 +42,6 @@ async function waitFor(timers, waiters, ms) {
|
|
|
42
42
|
waiters.add(settle);
|
|
43
43
|
return await promise;
|
|
44
44
|
}
|
|
45
|
-
//#endregion
|
|
46
45
|
export { createWakeSignal };
|
|
47
46
|
|
|
48
47
|
//# sourceMappingURL=wake.mjs.map
|
package/dist/capture/design.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
|
|
4
|
+
// src/capture/design.ts
|
|
5
5
|
/**
|
|
6
6
|
* Resolve a story's design URL. `storyshelf.figma` (plain string) wins over the
|
|
7
7
|
* `design` addon shape (`string | {url} | {type,url} | {type,url}[]`, first URL wins).
|
|
@@ -33,7 +33,6 @@ function logInvalidDesigns(logger, stories) {
|
|
|
33
33
|
design: story.designInvalid
|
|
34
34
|
}, "ignored invalid design url");
|
|
35
35
|
}
|
|
36
|
-
//#endregion
|
|
37
36
|
export { extractDesignUrl, logInvalidDesigns };
|
|
38
37
|
|
|
39
38
|
//# sourceMappingURL=design.mjs.map
|
|
@@ -2,7 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { DEFAULT_DIFF_OPTIONS, diffImagesAsync } from "@storyshelf/image";
|
|
5
|
-
|
|
5
|
+
// src/capture/diff-record.ts
|
|
6
6
|
/** Diff a stored screenshot against a baseline and persist the overlay; shared by capture and re-diff. */
|
|
7
7
|
/** Per-story `diffThreshold` when it is a finite number in 0..1; otherwise the project threshold. */
|
|
8
8
|
function resolvePixelThreshold(projectThreshold, override) {
|
|
@@ -44,7 +44,6 @@ async function writeDiffOverlay(storage, path, result, passed) {
|
|
|
44
44
|
await storage.write(path, result.diffImage);
|
|
45
45
|
return path;
|
|
46
46
|
}
|
|
47
|
-
//#endregion
|
|
48
47
|
export { diffStoredScreenshots, resolvePixelThreshold, writeDiffOverlay };
|
|
49
48
|
|
|
50
49
|
//# sourceMappingURL=diff-record.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
|
-
import { DatabaseAdapter } from "../adapter/database.mjs";
|
|
4
3
|
import { Logger } from "../logger.mjs";
|
|
4
|
+
import { DatabaseAdapter } from "../adapter/database.mjs";
|
|
5
5
|
import { BuildTables } from "../models/build.mjs";
|
|
6
6
|
import { CaptureAttemptTables } from "../models/capture-attempt.mjs";
|
|
7
7
|
import { CaptureLogTables } from "../models/capture-log.mjs";
|
|
@@ -9,7 +9,6 @@ import { ProjectTables } from "../models/project.mjs";
|
|
|
9
9
|
import { JobLease } from "./job-lease.mjs";
|
|
10
10
|
import { CaptureJobOptions } from "./orchestrator.mjs";
|
|
11
11
|
import { BuildStatePublisher } from "./build-state/types.mjs";
|
|
12
|
-
//#region src/capture/dispatch.d.ts
|
|
13
12
|
/** Build the queue's job runner: post pending, apply skip rules, capture, report. */
|
|
14
13
|
declare function createDispatchJob(deps: DispatchDeps): (job: CaptureDispatchJob, lease?: JobLease) => Promise<void>;
|
|
15
14
|
/** Table handles required by dispatch. */
|
|
@@ -36,6 +35,5 @@ interface CaptureDispatchJob {
|
|
|
36
35
|
/** W3C `traceparent` continuing the enqueueing request's trace. */
|
|
37
36
|
traceparent?: string;
|
|
38
37
|
}
|
|
39
|
-
//#endregion
|
|
40
38
|
export { CaptureDispatchJob, DispatchDeps, DispatchTables, createDispatchJob };
|
|
41
39
|
//# sourceMappingURL=dispatch.d.mts.map
|
|
@@ -4,6 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { redactSecrets } from "../utils/redact.mjs";
|
|
5
5
|
import { CaptureAttemptModel, emitAttemptLog } from "../models/capture-attempt.mjs";
|
|
6
6
|
import { BuildModel } from "../models/build.mjs";
|
|
7
|
+
import { SignedUrlLifetimeError } from "./token-chunks.mjs";
|
|
7
8
|
import { CaptureShardModel } from "../models/capture-shard.mjs";
|
|
8
9
|
import { ProjectModel } from "../models/project.mjs";
|
|
9
10
|
import { executeCaptureJob } from "./orchestrator.mjs";
|
|
@@ -11,7 +12,7 @@ import { CaptureLogModel } from "../models/capture-log.mjs";
|
|
|
11
12
|
import { leaseProgress } from "./progress.mjs";
|
|
12
13
|
import { executeCaptureShard } from "./shards/execute.mjs";
|
|
13
14
|
import { hasApprovedBuildForSha } from "./skip-checks.mjs";
|
|
14
|
-
|
|
15
|
+
// src/capture/dispatch.ts
|
|
15
16
|
/** Build the queue's job runner: post pending, apply skip rules, capture, report. */
|
|
16
17
|
function createDispatchJob(deps) {
|
|
17
18
|
return async (job, lease) => {
|
|
@@ -119,11 +120,23 @@ async function runAndReport(ctx, job) {
|
|
|
119
120
|
progress: ctx.progress
|
|
120
121
|
}, deps.jobOptions));
|
|
121
122
|
} catch (error) {
|
|
122
|
-
await
|
|
123
|
-
await deps.buildState.request(build.id);
|
|
124
|
-
throw error;
|
|
123
|
+
await reportFailure(ctx, error);
|
|
125
124
|
}
|
|
126
125
|
}
|
|
126
|
+
/** Record a failed run, then rethrow so the job is redelivered, unless another try cannot help. */
|
|
127
|
+
async function reportFailure(ctx, error) {
|
|
128
|
+
const { deps, build } = ctx;
|
|
129
|
+
await finishAttempt(ctx, "failed", errorText(error));
|
|
130
|
+
await deps.buildState.request(build.id);
|
|
131
|
+
if (error instanceof SignedUrlLifetimeError) {
|
|
132
|
+
deps.logger.error({
|
|
133
|
+
buildId: build.id,
|
|
134
|
+
err: error
|
|
135
|
+
}, "capture not retried");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
127
140
|
/** Load the build + project for a job, running orphan jobs directly. */
|
|
128
141
|
async function loadJobTarget(deps, job) {
|
|
129
142
|
const build = await new BuildModel(deps.db, deps.tables).get(job.buildId);
|
|
@@ -180,7 +193,6 @@ async function loadClosing(deps, buildId) {
|
|
|
180
193
|
project
|
|
181
194
|
} : null;
|
|
182
195
|
}
|
|
183
|
-
//#endregion
|
|
184
196
|
export { createDispatchJob };
|
|
185
197
|
|
|
186
198
|
//# sourceMappingURL=dispatch.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.mjs","names":[],"sources":["../../src/capture/dispatch.ts"],"sourcesContent":["import type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { Logger } from \"../logger.ts\";\nimport { BuildModel, type BuildTables } from \"../models/build.ts\";\nimport {\n CaptureAttemptModel,\n emitAttemptLog,\n type AttemptLogRecorder,\n type CaptureAttemptTables,\n} from \"../models/capture-attempt.ts\";\nimport { CaptureLogModel, type CaptureLogTables } from \"../models/capture-log.ts\";\nimport { CaptureShardModel } from \"../models/capture-shard.ts\";\nimport { ProjectModel, type ProjectTables } from \"../models/project.ts\";\nimport type { Build } from \"../schema/build.ts\";\nimport type { CaptureAttempt } from \"../schema/capture-attempt.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport { redactSecrets } from \"../utils/redact.ts\";\nimport type { BuildStatePublisher } from \"./build-state/types.ts\";\nimport type { JobLease } from \"./job-lease.ts\";\nimport { executeCaptureJob, type CaptureJobOptions, type CaptureSummary } from \"./orchestrator.ts\";\nimport { leaseProgress, type CaptureProgress } from \"./progress.ts\";\nimport { executeCaptureShard } from \"./shards/execute.ts\";\nimport type { FinalSummary } from \"./shards/reduce.ts\";\nimport { hasApprovedBuildForSha } from \"./skip-checks.ts\";\n\n/** Build the queue's job runner: post pending, apply skip rules, capture, report. */\nexport function createDispatchJob(\n deps: DispatchDeps,\n): (job: CaptureDispatchJob, lease?: JobLease) => Promise<void> {\n return async (job: CaptureDispatchJob, lease?: JobLease): Promise<void> => {\n await (job.shard\n ? runShardJob(deps, { ...job, shard: job.shard }, lease)\n : runBuildJob(deps, job, lease));\n };\n}\n\n/** The build's own job: post pending, apply skip rules, capture (or plan), report. */\nasync function runBuildJob(\n deps: DispatchDeps,\n job: CaptureDispatchJob,\n lease?: JobLease,\n): Promise<void> {\n const target = await loadJobTarget(deps, job);\n if (!target) {\n return;\n }\n await deps.buildState.request(job.buildId);\n const { attempt, recordLog } = await beginAttempt(\n deps,\n target.project,\n target.build,\n job.reqId,\n lease,\n );\n const ctx: JobContext = {\n deps,\n build: target.build,\n project: target.project,\n attempt,\n recordLog,\n progress: leaseProgress(lease),\n };\n if (await maybeSkipDuplicate(ctx)) {\n return;\n }\n await runAndReport(ctx, job);\n}\n\n/** Table handles required by dispatch. */\nexport type DispatchTables = BuildTables & ProjectTables & CaptureAttemptTables & CaptureLogTables;\n\n/** Dependencies for building the capture queue's job runner. */\nexport interface DispatchDeps {\n db: DatabaseAdapter;\n tables: DispatchTables;\n jobOptions: CaptureJobOptions;\n /** Shows a build's current state on its git channels; called at every transition. */\n buildState: BuildStatePublisher;\n logger: Logger;\n /** Redeliveries the queue allows a failing job; a shard's last try is its final word. */\n maxRetries?: number | undefined;\n}\n\n/** A queued capture job. */\nexport interface CaptureDispatchJob {\n buildId: string;\n /** A `capture_shards` row to render; absent for the build's own (plan or whole-build) job. */\n shard?: string | undefined;\n /** Times the queue has already delivered this job and seen it fail. */\n attempts?: number | undefined;\n reqId?: string;\n /** W3C `traceparent` continuing the enqueueing request's trace. */\n traceparent?: string;\n}\n\ninterface JobContext {\n deps: DispatchDeps;\n build: Build;\n project: Project;\n attempt: CaptureAttempt;\n recordLog: AttemptLogRecorder;\n progress: CaptureProgress | undefined;\n}\n\n/** Open a new attempt row for this run and return its log recorder. */\nasync function beginAttempt(\n deps: DispatchDeps,\n project: Project,\n build: Build,\n reqId: string | undefined,\n lease?: JobLease,\n): Promise<{ attempt: CaptureAttempt; recordLog: AttemptLogRecorder }> {\n const attempts = new CaptureAttemptModel(deps.db, deps.tables);\n const logs = new CaptureLogModel(deps.db, deps.tables);\n const attempt = await attempts.startAttempt(project.id, build.id, reqId);\n // Every attempt-log line (stages, render progress, runner output) counts as progress.\n const recordLog: AttemptLogRecorder = async (level, message, fields) => {\n lease?.touch();\n await logs.append(project.id, build.id, attempt.id, level, message, fields);\n };\n await emitAttemptLog(recordLog, deps.logger, \"info\", \"capture queued\", {\n buildId: build.id,\n attemptNo: attempt.attemptNo,\n });\n return { attempt, recordLog };\n}\n\n/** Close the attempt row with its terminal status, counts, and error. */\nasync function finishAttempt(\n ctx: JobContext,\n status: \"completed\" | \"failed\" | \"cancelled\",\n error?: string,\n counts?: { storyCount: number; failedCount: number },\n): Promise<void> {\n const { deps, attempt } = ctx;\n await new CaptureAttemptModel(deps.db, deps.tables).markFinished(\n attempt.id,\n status,\n error,\n counts,\n );\n await emitAttemptLog(\n ctx.recordLog,\n deps.logger,\n status === \"failed\" ? \"error\" : \"info\",\n `capture ${status}`,\n { attemptNo: attempt.attemptNo },\n );\n}\n\n/** Full error text for an attempt row (message plus stack when available). */\nfunction errorText(reason: unknown): string {\n // A runner's error can quote the signed Storybook URL it failed to open.\n return redactSecrets(reason instanceof Error ? (reason.stack ?? reason.message) : String(reason));\n}\n\nasync function approveWithoutCapture(ctx: JobContext, reason: string): Promise<void> {\n const { deps, build } = ctx;\n deps.logger.info({ buildId: build.id, sha: build.gitSha, branch: build.gitBranch }, reason);\n await emitAttemptLog(ctx.recordLog, deps.logger, \"info\", reason, {\n sha: build.gitSha,\n branch: build.gitBranch,\n });\n await finishAttempt(ctx, \"completed\");\n await new BuildModel(deps.db, deps.tables).setStatus(build.id, \"approved\").catch(() => {}); // Intentionally empty — fire-and-forget\n await deps.buildState.request(build.id);\n}\n\nasync function maybeSkipDuplicate(ctx: JobContext): Promise<boolean> {\n const { deps, build, project } = ctx;\n const dup = await hasApprovedBuildForSha(\n deps.db,\n deps.tables,\n project.id,\n build.gitSha,\n build.id,\n );\n if (dup) {\n await approveWithoutCapture(ctx, \"skipping capture — duplicate sha already approved\");\n return true;\n }\n return false;\n}\n\n/** A sharded build's attempt stays open: the worker that finishes the last shard closes it. */\nasync function finishUnlessSharded(ctx: JobContext, summary: CaptureSummary): Promise<void> {\n if (summary.shards) {\n await emitAttemptLog(ctx.recordLog, ctx.deps.logger, \"info\", \"capture sharded\", {\n shards: summary.shards,\n });\n return;\n }\n await finishAttempt(ctx, \"completed\", undefined, summary);\n await ctx.deps.buildState.request(ctx.build.id);\n}\n\nasync function runAndReport(ctx: JobContext, job: CaptureDispatchJob): Promise<void> {\n const { deps, build } = ctx;\n await new CaptureAttemptModel(deps.db, deps.tables).markRunning(ctx.attempt.id);\n await emitAttemptLog(ctx.recordLog, deps.logger, \"info\", \"capture started\", {\n buildId: build.id,\n attemptNo: ctx.attempt.attemptNo,\n });\n try {\n const summary = await executeCaptureJob(\n {\n buildId: job.buildId,\n reqId: job.reqId,\n traceparent: job.traceparent,\n attempt: {\n id: ctx.attempt.id,\n attemptNo: ctx.attempt.attemptNo,\n projectId: ctx.project.id,\n },\n recordLog: ctx.recordLog,\n progress: ctx.progress,\n },\n deps.jobOptions,\n );\n await finishUnlessSharded(ctx, summary);\n } catch (error: unknown) {\n await finishAttempt(ctx, \"failed\", errorText(error));\n await deps.buildState.request(build.id);\n throw error;\n }\n}\n\n/** Load the build + project for a job, running orphan jobs directly. */\nasync function loadJobTarget(\n deps: DispatchDeps,\n job: CaptureDispatchJob,\n): Promise<{ build: Build; project: Project } | null> {\n const build = await new BuildModel(deps.db, deps.tables).get(job.buildId);\n const project = build ? await new ProjectModel(deps.db, deps.tables).get(build.projectId) : null;\n if (!build || !project) {\n await executeCaptureJob(\n { buildId: job.buildId, reqId: job.reqId, traceparent: job.traceparent },\n deps.jobOptions,\n );\n return null;\n }\n return { build, project };\n}\n\n/**\n * Run one render shard. Only the run that finalized the build closes the plan's attempt and posts\n * the terminal status, whether its shard succeeded or failed; every other run leaves them alone.\n */\nasync function runShardJob(\n deps: DispatchDeps,\n job: CaptureDispatchJob & { shard: string },\n lease?: JobLease,\n): Promise<void> {\n const final = (job.attempts ?? 0) >= (deps.maxRetries ?? 0);\n await executeCaptureShard(\n {\n buildId: job.buildId,\n shard: job.shard,\n reqId: job.reqId,\n final,\n progress: leaseProgress(lease),\n onFinalized: async (summary, error) => {\n await closeShardedBuild(deps, job.buildId, summary, error);\n },\n },\n deps.jobOptions,\n );\n}\n\n/** End the plan's attempt with the finalizer's counts and report the build's terminal status. */\nasync function closeShardedBuild(\n deps: DispatchDeps,\n buildId: string,\n summary: FinalSummary,\n error?: unknown,\n): Promise<void> {\n const loaded = await loadClosing(deps, buildId);\n if (!loaded) {\n return;\n }\n const failure = error === undefined ? summary.error : errorText(error);\n const failed = failure !== undefined || summary.buildStatus === \"failed\";\n const attemptId = summary.attemptId ?? (await planAttemptId(deps, buildId));\n if (attemptId) {\n await new CaptureAttemptModel(deps.db, deps.tables)\n .markFinished(attemptId, failed ? \"failed\" : \"completed\", failure, summary)\n .catch((closeError: unknown) => {\n deps.logger.error({ err: closeError }, \"failed to close attempt\");\n });\n }\n await deps.buildState.request(buildId);\n}\n\nasync function planAttemptId(deps: DispatchDeps, buildId: string): Promise<string | null> {\n const plan = await new CaptureShardModel(deps.db).plan(buildId);\n return plan?.attemptId ?? null;\n}\n\nasync function loadClosing(\n deps: DispatchDeps,\n buildId: string,\n): Promise<{ build: Build; project: Project } | null> {\n const build = await new BuildModel(deps.db, deps.tables).get(buildId);\n const project = build ? await new ProjectModel(deps.db, deps.tables).get(build.projectId) : null;\n return build && project ? { build, project } : null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dispatch.mjs","names":[],"sources":["../../src/capture/dispatch.ts"],"sourcesContent":["import type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { Logger } from \"../logger.ts\";\nimport { BuildModel, type BuildTables } from \"../models/build.ts\";\nimport {\n CaptureAttemptModel,\n emitAttemptLog,\n type AttemptLogRecorder,\n type CaptureAttemptTables,\n} from \"../models/capture-attempt.ts\";\nimport { CaptureLogModel, type CaptureLogTables } from \"../models/capture-log.ts\";\nimport { CaptureShardModel } from \"../models/capture-shard.ts\";\nimport { ProjectModel, type ProjectTables } from \"../models/project.ts\";\nimport type { Build } from \"../schema/build.ts\";\nimport type { CaptureAttempt } from \"../schema/capture-attempt.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport { redactSecrets } from \"../utils/redact.ts\";\nimport type { BuildStatePublisher } from \"./build-state/types.ts\";\nimport type { JobLease } from \"./job-lease.ts\";\nimport { executeCaptureJob, type CaptureJobOptions, type CaptureSummary } from \"./orchestrator.ts\";\nimport { leaseProgress, type CaptureProgress } from \"./progress.ts\";\nimport { executeCaptureShard } from \"./shards/execute.ts\";\nimport type { FinalSummary } from \"./shards/reduce.ts\";\nimport { hasApprovedBuildForSha } from \"./skip-checks.ts\";\nimport { SignedUrlLifetimeError } from \"./token-chunks.ts\";\n\n/** Build the queue's job runner: post pending, apply skip rules, capture, report. */\nexport function createDispatchJob(\n deps: DispatchDeps,\n): (job: CaptureDispatchJob, lease?: JobLease) => Promise<void> {\n return async (job: CaptureDispatchJob, lease?: JobLease): Promise<void> => {\n await (job.shard\n ? runShardJob(deps, { ...job, shard: job.shard }, lease)\n : runBuildJob(deps, job, lease));\n };\n}\n\n/** The build's own job: post pending, apply skip rules, capture (or plan), report. */\nasync function runBuildJob(\n deps: DispatchDeps,\n job: CaptureDispatchJob,\n lease?: JobLease,\n): Promise<void> {\n const target = await loadJobTarget(deps, job);\n if (!target) {\n return;\n }\n await deps.buildState.request(job.buildId);\n const { attempt, recordLog } = await beginAttempt(\n deps,\n target.project,\n target.build,\n job.reqId,\n lease,\n );\n const ctx: JobContext = {\n deps,\n build: target.build,\n project: target.project,\n attempt,\n recordLog,\n progress: leaseProgress(lease),\n };\n if (await maybeSkipDuplicate(ctx)) {\n return;\n }\n await runAndReport(ctx, job);\n}\n\n/** Table handles required by dispatch. */\nexport type DispatchTables = BuildTables & ProjectTables & CaptureAttemptTables & CaptureLogTables;\n\n/** Dependencies for building the capture queue's job runner. */\nexport interface DispatchDeps {\n db: DatabaseAdapter;\n tables: DispatchTables;\n jobOptions: CaptureJobOptions;\n /** Shows a build's current state on its git channels; called at every transition. */\n buildState: BuildStatePublisher;\n logger: Logger;\n /** Redeliveries the queue allows a failing job; a shard's last try is its final word. */\n maxRetries?: number | undefined;\n}\n\n/** A queued capture job. */\nexport interface CaptureDispatchJob {\n buildId: string;\n /** A `capture_shards` row to render; absent for the build's own (plan or whole-build) job. */\n shard?: string | undefined;\n /** Times the queue has already delivered this job and seen it fail. */\n attempts?: number | undefined;\n reqId?: string;\n /** W3C `traceparent` continuing the enqueueing request's trace. */\n traceparent?: string;\n}\n\ninterface JobContext {\n deps: DispatchDeps;\n build: Build;\n project: Project;\n attempt: CaptureAttempt;\n recordLog: AttemptLogRecorder;\n progress: CaptureProgress | undefined;\n}\n\n/** Open a new attempt row for this run and return its log recorder. */\nasync function beginAttempt(\n deps: DispatchDeps,\n project: Project,\n build: Build,\n reqId: string | undefined,\n lease?: JobLease,\n): Promise<{ attempt: CaptureAttempt; recordLog: AttemptLogRecorder }> {\n const attempts = new CaptureAttemptModel(deps.db, deps.tables);\n const logs = new CaptureLogModel(deps.db, deps.tables);\n const attempt = await attempts.startAttempt(project.id, build.id, reqId);\n // Every attempt-log line (stages, render progress, runner output) counts as progress.\n const recordLog: AttemptLogRecorder = async (level, message, fields) => {\n lease?.touch();\n await logs.append(project.id, build.id, attempt.id, level, message, fields);\n };\n await emitAttemptLog(recordLog, deps.logger, \"info\", \"capture queued\", {\n buildId: build.id,\n attemptNo: attempt.attemptNo,\n });\n return { attempt, recordLog };\n}\n\n/** Close the attempt row with its terminal status, counts, and error. */\nasync function finishAttempt(\n ctx: JobContext,\n status: \"completed\" | \"failed\" | \"cancelled\",\n error?: string,\n counts?: { storyCount: number; failedCount: number },\n): Promise<void> {\n const { deps, attempt } = ctx;\n await new CaptureAttemptModel(deps.db, deps.tables).markFinished(\n attempt.id,\n status,\n error,\n counts,\n );\n await emitAttemptLog(\n ctx.recordLog,\n deps.logger,\n status === \"failed\" ? \"error\" : \"info\",\n `capture ${status}`,\n { attemptNo: attempt.attemptNo },\n );\n}\n\n/** Full error text for an attempt row (message plus stack when available). */\nfunction errorText(reason: unknown): string {\n // A runner's error can quote the signed Storybook URL it failed to open.\n return redactSecrets(reason instanceof Error ? (reason.stack ?? reason.message) : String(reason));\n}\n\nasync function approveWithoutCapture(ctx: JobContext, reason: string): Promise<void> {\n const { deps, build } = ctx;\n deps.logger.info({ buildId: build.id, sha: build.gitSha, branch: build.gitBranch }, reason);\n await emitAttemptLog(ctx.recordLog, deps.logger, \"info\", reason, {\n sha: build.gitSha,\n branch: build.gitBranch,\n });\n await finishAttempt(ctx, \"completed\");\n await new BuildModel(deps.db, deps.tables).setStatus(build.id, \"approved\").catch(() => {}); // Intentionally empty — fire-and-forget\n await deps.buildState.request(build.id);\n}\n\nasync function maybeSkipDuplicate(ctx: JobContext): Promise<boolean> {\n const { deps, build, project } = ctx;\n const dup = await hasApprovedBuildForSha(\n deps.db,\n deps.tables,\n project.id,\n build.gitSha,\n build.id,\n );\n if (dup) {\n await approveWithoutCapture(ctx, \"skipping capture — duplicate sha already approved\");\n return true;\n }\n return false;\n}\n\n/** A sharded build's attempt stays open: the worker that finishes the last shard closes it. */\nasync function finishUnlessSharded(ctx: JobContext, summary: CaptureSummary): Promise<void> {\n if (summary.shards) {\n await emitAttemptLog(ctx.recordLog, ctx.deps.logger, \"info\", \"capture sharded\", {\n shards: summary.shards,\n });\n return;\n }\n await finishAttempt(ctx, \"completed\", undefined, summary);\n await ctx.deps.buildState.request(ctx.build.id);\n}\n\nasync function runAndReport(ctx: JobContext, job: CaptureDispatchJob): Promise<void> {\n const { deps, build } = ctx;\n await new CaptureAttemptModel(deps.db, deps.tables).markRunning(ctx.attempt.id);\n await emitAttemptLog(ctx.recordLog, deps.logger, \"info\", \"capture started\", {\n buildId: build.id,\n attemptNo: ctx.attempt.attemptNo,\n });\n try {\n const summary = await executeCaptureJob(\n {\n buildId: job.buildId,\n reqId: job.reqId,\n traceparent: job.traceparent,\n attempt: {\n id: ctx.attempt.id,\n attemptNo: ctx.attempt.attemptNo,\n projectId: ctx.project.id,\n },\n recordLog: ctx.recordLog,\n progress: ctx.progress,\n },\n deps.jobOptions,\n );\n await finishUnlessSharded(ctx, summary);\n } catch (error: unknown) {\n await reportFailure(ctx, error);\n }\n}\n\n/** Record a failed run, then rethrow so the job is redelivered, unless another try cannot help. */\nasync function reportFailure(ctx: JobContext, error: unknown): Promise<void> {\n const { deps, build } = ctx;\n await finishAttempt(ctx, \"failed\", errorText(error));\n await deps.buildState.request(build.id);\n if (error instanceof SignedUrlLifetimeError) {\n // A configuration problem: another delivery would fail the same way. The build is failed.\n deps.logger.error({ buildId: build.id, err: error }, \"capture not retried\");\n return;\n }\n throw error;\n}\n\n/** Load the build + project for a job, running orphan jobs directly. */\nasync function loadJobTarget(\n deps: DispatchDeps,\n job: CaptureDispatchJob,\n): Promise<{ build: Build; project: Project } | null> {\n const build = await new BuildModel(deps.db, deps.tables).get(job.buildId);\n const project = build ? await new ProjectModel(deps.db, deps.tables).get(build.projectId) : null;\n if (!build || !project) {\n await executeCaptureJob(\n { buildId: job.buildId, reqId: job.reqId, traceparent: job.traceparent },\n deps.jobOptions,\n );\n return null;\n }\n return { build, project };\n}\n\n/**\n * Run one render shard. Only the run that finalized the build closes the plan's attempt and posts\n * the terminal status, whether its shard succeeded or failed; every other run leaves them alone.\n */\nasync function runShardJob(\n deps: DispatchDeps,\n job: CaptureDispatchJob & { shard: string },\n lease?: JobLease,\n): Promise<void> {\n const final = (job.attempts ?? 0) >= (deps.maxRetries ?? 0);\n await executeCaptureShard(\n {\n buildId: job.buildId,\n shard: job.shard,\n reqId: job.reqId,\n final,\n progress: leaseProgress(lease),\n onFinalized: async (summary, error) => {\n await closeShardedBuild(deps, job.buildId, summary, error);\n },\n },\n deps.jobOptions,\n );\n}\n\n/** End the plan's attempt with the finalizer's counts and report the build's terminal status. */\nasync function closeShardedBuild(\n deps: DispatchDeps,\n buildId: string,\n summary: FinalSummary,\n error?: unknown,\n): Promise<void> {\n const loaded = await loadClosing(deps, buildId);\n if (!loaded) {\n return;\n }\n const failure = error === undefined ? summary.error : errorText(error);\n const failed = failure !== undefined || summary.buildStatus === \"failed\";\n const attemptId = summary.attemptId ?? (await planAttemptId(deps, buildId));\n if (attemptId) {\n await new CaptureAttemptModel(deps.db, deps.tables)\n .markFinished(attemptId, failed ? \"failed\" : \"completed\", failure, summary)\n .catch((closeError: unknown) => {\n deps.logger.error({ err: closeError }, \"failed to close attempt\");\n });\n }\n await deps.buildState.request(buildId);\n}\n\nasync function planAttemptId(deps: DispatchDeps, buildId: string): Promise<string | null> {\n const plan = await new CaptureShardModel(deps.db).plan(buildId);\n return plan?.attemptId ?? null;\n}\n\nasync function loadClosing(\n deps: DispatchDeps,\n buildId: string,\n): Promise<{ build: Build; project: Project } | null> {\n const build = await new BuildModel(deps.db, deps.tables).get(buildId);\n const project = build ? await new ProjectModel(deps.db, deps.tables).get(build.projectId) : null;\n return build && project ? { build, project } : null;\n}\n"],"mappings":"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"}
|
package/dist/capture/enrich.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { filterModes } from "./modes.mjs";
|
|
5
5
|
import { renderBudgetMs } from "./render.mjs";
|
|
6
6
|
import { resolveStoryViewports } from "./storybook.mjs";
|
|
7
|
-
|
|
7
|
+
// src/capture/enrich.ts
|
|
8
8
|
/**
|
|
9
9
|
* Merge runtime-resolved parameters (project/component/story levels stacked by
|
|
10
10
|
* Storybook) over the index's, then apply the project's mode allowlist. A
|
|
@@ -54,7 +54,6 @@ async function extractSafely(input) {
|
|
|
54
54
|
return {};
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
//#endregion
|
|
58
57
|
export { assertModeCaps, enrichStories };
|
|
59
58
|
|
|
60
59
|
//# sourceMappingURL=enrich.mjs.map
|
|
@@ -2,7 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { isFlakyStory } from "./adapter.mjs";
|
|
5
|
-
|
|
5
|
+
// src/capture/failure-sets.ts
|
|
6
6
|
/** Classify render failures: `a11y:` errors, then flaky stories, then everything else is blocking. */
|
|
7
7
|
function classifyFailures(stories, failures) {
|
|
8
8
|
const flakyIds = new Set(stories.filter((story) => isFlakyStory(story)).map((story) => story.id));
|
|
@@ -16,7 +16,6 @@ function classifyFailures(stories, failures) {
|
|
|
16
16
|
else sets.blocking.add(failure.storyId);
|
|
17
17
|
return sets;
|
|
18
18
|
}
|
|
19
|
-
//#endregion
|
|
20
19
|
export { classifyFailures };
|
|
21
20
|
|
|
22
21
|
//# sourceMappingURL=failure-sets.mjs.map
|
|
@@ -3,9 +3,18 @@ import __tsdown_shims_url from 'node:url';
|
|
|
3
3
|
import { Viewport } from "./adapter.mjs";
|
|
4
4
|
import { CaptureEnvironment } from "../adapter/capture-runner.mjs";
|
|
5
5
|
import { SIZING_DEFAULTS } from "./sizing.mjs";
|
|
6
|
-
|
|
6
|
+
/** The components a comparison reads: the environment fields and the screenshot sizing. */
|
|
7
|
+
type MeasuredField = "engine" | "browserVersion" | "platform" | "deviceScaleFactor" | "fontsHash" | "sizing";
|
|
8
|
+
/** Components whose measurement changed, by the version that changed it. Tests pass their own. */
|
|
9
|
+
type MeasurementHistory = Readonly<Record<number, readonly MeasuredField[]>>;
|
|
7
10
|
/** The components behind a snapshot's `infraHash`, kept so a mismatch can say what changed. */
|
|
8
11
|
interface Fingerprint {
|
|
12
|
+
/**
|
|
13
|
+
* How the environment components were measured (see {@link MEASUREMENT_VERSION}). Absent means
|
|
14
|
+
* version 1. It is not part of `infraHash`: the baseline's identity must not change when only
|
|
15
|
+
* the measurement does.
|
|
16
|
+
*/
|
|
17
|
+
measurementVersion?: number | undefined;
|
|
9
18
|
engine: string;
|
|
10
19
|
browserVersion: string | null;
|
|
11
20
|
platform: string | null;
|
|
@@ -19,24 +28,26 @@ interface Fingerprint {
|
|
|
19
28
|
}
|
|
20
29
|
/** Build the fingerprint of one capture. Missing environment fields stay `null` (runner did not report them). */
|
|
21
30
|
declare function buildFingerprint(engine: string, viewport: Viewport, environment: CaptureEnvironment | undefined): Fingerprint;
|
|
22
|
-
/** Stable hash of a fingerprint: the value stored as `infraHash`. */
|
|
31
|
+
/** Stable hash of a fingerprint: the value stored as `infraHash`. `measurementVersion` is left out on purpose. */
|
|
23
32
|
declare function fingerprintHash(fingerprint: Fingerprint): string;
|
|
24
33
|
/**
|
|
25
34
|
* Names of the environment components that differ; `["unknown"]` when the earlier fingerprint was
|
|
26
35
|
* not recorded. A component one side did not report (`null`: a runner that does not report it, a
|
|
27
|
-
* capture spooled before a browser crash, a failed `fc-list`) is unknown, not changed
|
|
28
|
-
*
|
|
29
|
-
*
|
|
36
|
+
* capture spooled before a browser crash, a failed `fc-list`) is unknown, not changed, and so is a
|
|
37
|
+
* component measured differently in the two measurement versions. Viewport is never a change
|
|
38
|
+
* here: its size comes from story parameters (the PR's own code), so a new size must be reviewed,
|
|
39
|
+
* and it diffs on its own as a dimension change.
|
|
30
40
|
*/
|
|
31
|
-
declare function changedFields(from: Fingerprint | null, to: Fingerprint): string[];
|
|
41
|
+
declare function changedFields(from: Fingerprint | null, to: Fingerprint, history?: MeasurementHistory): string[];
|
|
32
42
|
/** Parse a stored fingerprint; null for a missing or malformed value. */
|
|
33
43
|
declare function parseFingerprint(raw: string | null | undefined): Fingerprint | null;
|
|
34
44
|
/** What a migrated snapshot records: which components changed, and the before and after. */
|
|
35
45
|
interface EnvironmentChange {
|
|
36
46
|
changed: string[];
|
|
47
|
+
/** Components not compared because their measurement changed between versions (absent: none). */
|
|
48
|
+
unknown?: string[] | undefined;
|
|
37
49
|
from: Fingerprint | null;
|
|
38
50
|
to: Fingerprint;
|
|
39
51
|
}
|
|
40
|
-
|
|
41
|
-
export { EnvironmentChange, Fingerprint, buildFingerprint, changedFields, fingerprintHash, parseFingerprint };
|
|
52
|
+
export { EnvironmentChange, Fingerprint, MeasuredField, MeasurementHistory, buildFingerprint, changedFields, fingerprintHash, parseFingerprint };
|
|
42
53
|
//# sourceMappingURL=fingerprint.d.mts.map
|
|
@@ -3,10 +3,16 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { sha256 } from "../utils/hash.mjs";
|
|
5
5
|
import { SIZING_DEFAULTS } from "./sizing.mjs";
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Components whose measurement changed when a version was introduced, by that version. Version 1
|
|
8
|
+
* is the baseline of the scheme, so nothing is listed yet. Between two versions, a listed
|
|
9
|
+
* component is compared as unknown, never as a mismatch (it must not cause an environment migration).
|
|
10
|
+
*/
|
|
11
|
+
const REMEASURED_IN = {};
|
|
7
12
|
/** Build the fingerprint of one capture. Missing environment fields stay `null` (runner did not report them). */
|
|
8
13
|
function buildFingerprint(engine, viewport, environment) {
|
|
9
14
|
return {
|
|
15
|
+
measurementVersion: 1,
|
|
10
16
|
engine,
|
|
11
17
|
browserVersion: environment?.browserVersion ?? null,
|
|
12
18
|
platform: environment?.platform ?? null,
|
|
@@ -19,7 +25,7 @@ function buildFingerprint(engine, viewport, environment) {
|
|
|
19
25
|
sizing: SIZING_DEFAULTS
|
|
20
26
|
};
|
|
21
27
|
}
|
|
22
|
-
/** Stable hash of a fingerprint: the value stored as `infraHash`. */
|
|
28
|
+
/** Stable hash of a fingerprint: the value stored as `infraHash`. `measurementVersion` is left out on purpose. */
|
|
23
29
|
function fingerprintHash(fingerprint) {
|
|
24
30
|
return sha256(JSON.stringify([
|
|
25
31
|
fingerprint.engine,
|
|
@@ -40,16 +46,38 @@ const ENVIRONMENT_FIELDS = [
|
|
|
40
46
|
"deviceScaleFactor",
|
|
41
47
|
"fontsHash"
|
|
42
48
|
];
|
|
49
|
+
/** The version a fingerprint was measured with; one stored before versions existed is version 1. */
|
|
50
|
+
function measurementVersionOf(fingerprint) {
|
|
51
|
+
return fingerprint.measurementVersion ?? 1;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Components measured differently in the two fingerprints: those listed for any version between
|
|
55
|
+
* theirs. Empty when the versions match (nothing about a same-version comparison changes).
|
|
56
|
+
*/
|
|
57
|
+
function remeasuredFields(from, to, history = REMEASURED_IN) {
|
|
58
|
+
const [low, high] = [measurementVersionOf(from), measurementVersionOf(to)].toSorted((left, right) => left - right);
|
|
59
|
+
const fields = Object.entries(history).filter(([version]) => Number(version) > (low ?? 1) && Number(version) <= (high ?? 1)).flatMap(([, listed]) => listed);
|
|
60
|
+
return [...new Set(fields)];
|
|
61
|
+
}
|
|
43
62
|
/**
|
|
44
63
|
* Names of the environment components that differ; `["unknown"]` when the earlier fingerprint was
|
|
45
64
|
* not recorded. A component one side did not report (`null`: a runner that does not report it, a
|
|
46
|
-
* capture spooled before a browser crash, a failed `fc-list`) is unknown, not changed
|
|
47
|
-
*
|
|
48
|
-
*
|
|
65
|
+
* capture spooled before a browser crash, a failed `fc-list`) is unknown, not changed, and so is a
|
|
66
|
+
* component measured differently in the two measurement versions. Viewport is never a change
|
|
67
|
+
* here: its size comes from story parameters (the PR's own code), so a new size must be reviewed,
|
|
68
|
+
* and it diffs on its own as a dimension change.
|
|
49
69
|
*/
|
|
50
|
-
function changedFields(from, to) {
|
|
70
|
+
function changedFields(from, to, history = REMEASURED_IN) {
|
|
51
71
|
if (!from) return ["unknown"];
|
|
52
|
-
|
|
72
|
+
const remeasured = new Set(remeasuredFields(from, to, history));
|
|
73
|
+
return [...ENVIRONMENT_FIELDS.filter((key) => !remeasured.has(key) && known(from[key]) && known(to[key]) && from[key] !== to[key]), ...remeasured.has("sizing") || JSON.stringify(from.sizing) === JSON.stringify(to.sizing) ? [] : ["sizing"]];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Components that could not be compared because their measurement changed between the two
|
|
77
|
+
* fingerprints' versions. The review says the environment is partly unknown; nothing migrates.
|
|
78
|
+
*/
|
|
79
|
+
function unknownFields(from, to, history = REMEASURED_IN) {
|
|
80
|
+
return from ? remeasuredFields(from, to, history) : [];
|
|
53
81
|
}
|
|
54
82
|
function known(value) {
|
|
55
83
|
return value !== null && value !== void 0;
|
|
@@ -58,13 +86,15 @@ function known(value) {
|
|
|
58
86
|
* The fingerprint to store on a baseline: the capture's, with any component it did not report kept
|
|
59
87
|
* from the baseline's earlier fingerprint, so an unknown component never overwrites a known one.
|
|
60
88
|
*/
|
|
61
|
-
function mergeFingerprint(earlier, now) {
|
|
89
|
+
function mergeFingerprint(earlier, now, history = REMEASURED_IN) {
|
|
90
|
+
const stale = new Set(earlier ? remeasuredFields(earlier, now, history) : []);
|
|
91
|
+
const kept = (key) => now[key] ?? (stale.has(key) ? null : earlier?.[key] ?? null);
|
|
62
92
|
return {
|
|
63
93
|
...now,
|
|
64
|
-
browserVersion:
|
|
65
|
-
platform:
|
|
66
|
-
deviceScaleFactor:
|
|
67
|
-
fontsHash:
|
|
94
|
+
browserVersion: kept("browserVersion"),
|
|
95
|
+
platform: kept("platform"),
|
|
96
|
+
deviceScaleFactor: kept("deviceScaleFactor"),
|
|
97
|
+
fontsHash: kept("fontsHash")
|
|
68
98
|
};
|
|
69
99
|
}
|
|
70
100
|
/** Parse a stored fingerprint; null for a missing or malformed value. */
|
|
@@ -77,7 +107,6 @@ function parseFingerprint(raw) {
|
|
|
77
107
|
return null;
|
|
78
108
|
}
|
|
79
109
|
}
|
|
80
|
-
|
|
81
|
-
export { buildFingerprint, changedFields, fingerprintHash, mergeFingerprint, parseFingerprint };
|
|
110
|
+
export { REMEASURED_IN, buildFingerprint, changedFields, fingerprintHash, measurementVersionOf, mergeFingerprint, parseFingerprint, remeasuredFields, unknownFields };
|
|
82
111
|
|
|
83
112
|
//# sourceMappingURL=fingerprint.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.mjs","names":[],"sources":["../../src/capture/fingerprint.ts"],"sourcesContent":["/** Capture fingerprint: everything that changes pixels without a code change (ADR 0005 phase 4). */\nimport type { CaptureEnvironment } from \"../adapters/capture-runner.ts\";\nimport { sha256 } from \"../utils/hash.ts\";\nimport type { Viewport } from \"./adapter.ts\";\nimport { SIZING_DEFAULTS } from \"./sizing.ts\";\n\n/** The components behind a snapshot's `infraHash`, kept so a mismatch can say what changed. */\nexport interface Fingerprint {\n engine: string;\n browserVersion: string | null;\n platform: string | null;\n deviceScaleFactor: number | null;\n fontsHash: string | null;\n viewport: { width: number; height: number };\n sizing: typeof SIZING_DEFAULTS;\n}\n\n/** Build the fingerprint of one capture. Missing environment fields stay `null` (runner did not report them). */\nexport function buildFingerprint(\n engine: string,\n viewport: Viewport,\n environment: CaptureEnvironment | undefined,\n): Fingerprint {\n return {\n engine,\n browserVersion: environment?.browserVersion ?? null,\n platform: environment?.platform ?? null,\n deviceScaleFactor: environment?.deviceScaleFactor ?? null,\n fontsHash: environment?.fontsHash ?? null,\n viewport: { width: viewport.width, height: viewport.height },\n sizing: SIZING_DEFAULTS,\n };\n}\n\n/** Stable hash of a fingerprint: the value stored as `infraHash`. */\nexport function fingerprintHash(fingerprint: Fingerprint): string {\n return sha256(\n JSON.stringify([\n fingerprint.engine,\n fingerprint.browserVersion,\n fingerprint.platform,\n fingerprint.deviceScaleFactor,\n fingerprint.fontsHash,\n fingerprint.viewport.width,\n fingerprint.viewport.height,\n fingerprint.sizing,\n ]),\n );\n}\n\n/** The components whose change is an environment migration. Viewport is not one (see below). */\nconst ENVIRONMENT_FIELDS = [\n \"engine\",\n \"browserVersion\",\n \"platform\",\n \"deviceScaleFactor\",\n \"fontsHash\",\n] as const;\n\n/**\n * Names of the environment components that differ; `[\"unknown\"]` when the earlier fingerprint was\n * not recorded. A component one side did not report (`null`: a runner that does not report it, a\n * capture spooled before a browser crash, a failed `fc-list`) is unknown, not changed
|
|
1
|
+
{"version":3,"file":"fingerprint.mjs","names":[],"sources":["../../src/capture/fingerprint.ts"],"sourcesContent":["/** Capture fingerprint: everything that changes pixels without a code change (ADR 0005 phase 4). */\nimport type { CaptureEnvironment } from \"../adapters/capture-runner.ts\";\nimport { sha256 } from \"../utils/hash.ts\";\nimport type { Viewport } from \"./adapter.ts\";\nimport { SIZING_DEFAULTS } from \"./sizing.ts\";\n\n/**\n * What this build of StoryShelf measures the environment with (the browser probe). Bump it only\n * together with a probe change, and list in {@link REMEASURED_IN} the components whose measurement\n * changed. A fingerprint stored without it is version 1.\n */\nexport const MEASUREMENT_VERSION = 1;\n\n/** The components a comparison reads: the environment fields and the screenshot sizing. */\nexport type MeasuredField =\n | \"engine\"\n | \"browserVersion\"\n | \"platform\"\n | \"deviceScaleFactor\"\n | \"fontsHash\"\n | \"sizing\";\n\n/**\n * Components whose measurement changed when a version was introduced, by that version. Version 1\n * is the baseline of the scheme, so nothing is listed yet. Between two versions, a listed\n * component is compared as unknown, never as a mismatch (it must not cause an environment migration).\n */\n// A test that needs a re-measured component adds a version here and deletes it again.\nexport const REMEASURED_IN: Record<number, readonly MeasuredField[]> = {};\n\n/** Components whose measurement changed, by the version that changed it. Tests pass their own. */\nexport type MeasurementHistory = Readonly<Record<number, readonly MeasuredField[]>>;\n\n/** The components behind a snapshot's `infraHash`, kept so a mismatch can say what changed. */\nexport interface Fingerprint {\n /**\n * How the environment components were measured (see {@link MEASUREMENT_VERSION}). Absent means\n * version 1. It is not part of `infraHash`: the baseline's identity must not change when only\n * the measurement does.\n */\n measurementVersion?: number | undefined;\n engine: string;\n browserVersion: string | null;\n platform: string | null;\n deviceScaleFactor: number | null;\n fontsHash: string | null;\n viewport: { width: number; height: number };\n sizing: typeof SIZING_DEFAULTS;\n}\n\n/** Build the fingerprint of one capture. Missing environment fields stay `null` (runner did not report them). */\nexport function buildFingerprint(\n engine: string,\n viewport: Viewport,\n environment: CaptureEnvironment | undefined,\n): Fingerprint {\n return {\n measurementVersion: MEASUREMENT_VERSION,\n engine,\n browserVersion: environment?.browserVersion ?? null,\n platform: environment?.platform ?? null,\n deviceScaleFactor: environment?.deviceScaleFactor ?? null,\n fontsHash: environment?.fontsHash ?? null,\n viewport: { width: viewport.width, height: viewport.height },\n sizing: SIZING_DEFAULTS,\n };\n}\n\n/** Stable hash of a fingerprint: the value stored as `infraHash`. `measurementVersion` is left out on purpose. */\nexport function fingerprintHash(fingerprint: Fingerprint): string {\n return sha256(\n JSON.stringify([\n fingerprint.engine,\n fingerprint.browserVersion,\n fingerprint.platform,\n fingerprint.deviceScaleFactor,\n fingerprint.fontsHash,\n fingerprint.viewport.width,\n fingerprint.viewport.height,\n fingerprint.sizing,\n ]),\n );\n}\n\n/** The components whose change is an environment migration. Viewport is not one (see below). */\nconst ENVIRONMENT_FIELDS = [\n \"engine\",\n \"browserVersion\",\n \"platform\",\n \"deviceScaleFactor\",\n \"fontsHash\",\n] as const;\n\n/** The version a fingerprint was measured with; one stored before versions existed is version 1. */\nexport function measurementVersionOf(fingerprint: Fingerprint): number {\n return fingerprint.measurementVersion ?? 1;\n}\n\n/**\n * Components measured differently in the two fingerprints: those listed for any version between\n * theirs. Empty when the versions match (nothing about a same-version comparison changes).\n */\nexport function remeasuredFields(\n from: Fingerprint,\n to: Fingerprint,\n history: MeasurementHistory = REMEASURED_IN,\n): MeasuredField[] {\n const [low, high] = [measurementVersionOf(from), measurementVersionOf(to)].toSorted(\n (left, right) => left - right,\n );\n const fields = Object.entries(history)\n .filter(([version]) => Number(version) > (low ?? 1) && Number(version) <= (high ?? 1))\n .flatMap(([, listed]) => listed);\n return [...new Set(fields)];\n}\n\n/**\n * Names of the environment components that differ; `[\"unknown\"]` when the earlier fingerprint was\n * not recorded. A component one side did not report (`null`: a runner that does not report it, a\n * capture spooled before a browser crash, a failed `fc-list`) is unknown, not changed, and so is a\n * component measured differently in the two measurement versions. Viewport is never a change\n * here: its size comes from story parameters (the PR's own code), so a new size must be reviewed,\n * and it diffs on its own as a dimension change.\n */\nexport function changedFields(\n from: Fingerprint | null,\n to: Fingerprint,\n history: MeasurementHistory = REMEASURED_IN,\n): string[] {\n if (!from) {\n return [\"unknown\"];\n }\n const remeasured = new Set<string>(remeasuredFields(from, to, history));\n return [\n ...ENVIRONMENT_FIELDS.filter(\n (key) => !remeasured.has(key) && known(from[key]) && known(to[key]) && from[key] !== to[key],\n ),\n ...(remeasured.has(\"sizing\") || JSON.stringify(from.sizing) === JSON.stringify(to.sizing)\n ? []\n : [\"sizing\"]),\n ];\n}\n\n/**\n * Components that could not be compared because their measurement changed between the two\n * fingerprints' versions. The review says the environment is partly unknown; nothing migrates.\n */\nexport function unknownFields(\n from: Fingerprint | null,\n to: Fingerprint,\n history: MeasurementHistory = REMEASURED_IN,\n): string[] {\n return from ? remeasuredFields(from, to, history) : [];\n}\n\nfunction known(value: unknown): boolean {\n return value !== null && value !== undefined;\n}\n\n/**\n * The fingerprint to store on a baseline: the capture's, with any component it did not report kept\n * from the baseline's earlier fingerprint, so an unknown component never overwrites a known one.\n */\nexport function mergeFingerprint(\n earlier: Fingerprint | null,\n now: Fingerprint,\n history: MeasurementHistory = REMEASURED_IN,\n): Fingerprint {\n // A value measured under another version is not carried over a changed measurement.\n const stale = new Set<string>(earlier ? remeasuredFields(earlier, now, history) : []);\n const kept = <Key extends \"browserVersion\" | \"platform\" | \"deviceScaleFactor\" | \"fontsHash\">(\n key: Key,\n ): Fingerprint[Key] => now[key] ?? (stale.has(key) ? null : (earlier?.[key] ?? null));\n return {\n ...now,\n browserVersion: kept(\"browserVersion\"),\n platform: kept(\"platform\"),\n deviceScaleFactor: kept(\"deviceScaleFactor\"),\n fontsHash: kept(\"fontsHash\"),\n };\n}\n\n/** Parse a stored fingerprint; null for a missing or malformed value. */\nexport function parseFingerprint(raw: string | null | undefined): Fingerprint | null {\n if (!raw) {\n return null;\n }\n try {\n const value = JSON.parse(raw) as Partial<Fingerprint>;\n return typeof value.engine === \"string\" && value.viewport ? (value as Fingerprint) : null;\n } catch {\n return null;\n }\n}\n\n/** What a migrated snapshot records: which components changed, and the before and after. */\nexport interface EnvironmentChange {\n changed: string[];\n /** Components not compared because their measurement changed between versions (absent: none). */\n unknown?: string[] | undefined;\n from: Fingerprint | null;\n to: Fingerprint;\n}\n"],"mappings":";;;;;;;;;;AA4BA,MAAa,gBAA0D,CAAC;;AAuBxE,SAAgB,iBACd,QACA,UACA,aACa;CACb,OAAO;EACL,oBAAA;EACA;EACA,gBAAgB,aAAa,kBAAkB;EAC/C,UAAU,aAAa,YAAY;EACnC,mBAAmB,aAAa,qBAAqB;EACrD,WAAW,aAAa,aAAa;EACrC,UAAU;GAAE,OAAO,SAAS;GAAO,QAAQ,SAAS;EAAO;EAC3D,QAAQ;CACV;AACF;;AAGA,SAAgB,gBAAgB,aAAkC;CAChE,OAAO,OACL,KAAK,UAAU;EACb,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY,SAAS;EACrB,YAAY,SAAS;EACrB,YAAY;CACd,CAAC,CACH;AACF;;AAGA,MAAM,qBAAqB;CACzB;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAgB,qBAAqB,aAAkC;CACrE,OAAO,YAAY,sBAAsB;AAC3C;;;;;AAMA,SAAgB,iBACd,MACA,IACA,UAA8B,eACb;CACjB,MAAM,CAAC,KAAK,QAAQ,CAAC,qBAAqB,IAAI,GAAG,qBAAqB,EAAE,CAAC,CAAC,CAAC,UACxE,MAAM,UAAU,OAAO,KAC1B;CACA,MAAM,SAAS,OAAO,QAAQ,OAAO,CAAC,CACnC,QAAQ,CAAC,aAAa,OAAO,OAAO,KAAK,OAAO,MAAM,OAAO,OAAO,MAAM,QAAQ,EAAE,CAAC,CACrF,SAAS,GAAG,YAAY,MAAM;CACjC,OAAO,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC;AAC5B;;;;;;;;;AAUA,SAAgB,cACd,MACA,IACA,UAA8B,eACpB;CACV,IAAI,CAAC,MACH,OAAO,CAAC,SAAS;CAEnB,MAAM,aAAa,IAAI,IAAY,iBAAiB,MAAM,IAAI,OAAO,CAAC;CACtE,OAAO,CACL,GAAG,mBAAmB,QACnB,QAAQ,CAAC,WAAW,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,KAAK,MAAM,GAAG,IAAI,KAAK,KAAK,SAAS,GAAG,IAC1F,GACA,GAAI,WAAW,IAAI,QAAQ,KAAK,KAAK,UAAU,KAAK,MAAM,MAAM,KAAK,UAAU,GAAG,MAAM,IACpF,CAAC,IACD,CAAC,QAAQ,CACf;AACF;;;;;AAMA,SAAgB,cACd,MACA,IACA,UAA8B,eACpB;CACV,OAAO,OAAO,iBAAiB,MAAM,IAAI,OAAO,IAAI,CAAC;AACvD;AAEA,SAAS,MAAM,OAAyB;CACtC,OAAO,UAAU,QAAQ,UAAU,KAAA;AACrC;;;;;AAMA,SAAgB,iBACd,SACA,KACA,UAA8B,eACjB;CAEb,MAAM,QAAQ,IAAI,IAAY,UAAU,iBAAiB,SAAS,KAAK,OAAO,IAAI,CAAC,CAAC;CACpF,MAAM,QACJ,QACqB,IAAI,SAAS,MAAM,IAAI,GAAG,IAAI,OAAQ,UAAU,QAAQ;CAC/E,OAAO;EACL,GAAG;EACH,gBAAgB,KAAK,gBAAgB;EACrC,UAAU,KAAK,UAAU;EACzB,mBAAmB,KAAK,mBAAmB;EAC3C,WAAW,KAAK,WAAW;CAC7B;AACF;;AAGA,SAAgB,iBAAiB,KAAoD;CACnF,IAAI,CAAC,KACH,OAAO;CAET,IAAI;EACF,MAAM,QAAQ,KAAK,MAAM,GAAG;EAC5B,OAAO,OAAO,MAAM,WAAW,YAAY,MAAM,WAAY,QAAwB;CACvF,QAAQ;EACN,OAAO;CACT;AACF"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
3
|
import { ChildMessage, ParentMessage } from "./protocol.mjs";
|
|
4
|
-
//#region src/capture/forked/channel.d.ts
|
|
5
4
|
/** How the parent sees the capture child (`child_process.fork` adapts to this). */
|
|
6
5
|
interface ChildProcessHandle {
|
|
7
6
|
send(message: ParentMessage): void;
|
|
@@ -20,6 +19,5 @@ interface ParentPort {
|
|
|
20
19
|
onMessage(listener: (message: unknown) => void): void;
|
|
21
20
|
onDisconnect(listener: () => void): void;
|
|
22
21
|
}
|
|
23
|
-
//#endregion
|
|
24
22
|
export { ChildProcessHandle, ParentPort };
|
|
25
23
|
//# sourceMappingURL=channel.d.mts.map
|
|
@@ -4,7 +4,6 @@ import { Logger } from "../../logger.mjs";
|
|
|
4
4
|
import { CaptureHandlerOptions } from "../consumer/capture-handler.mjs";
|
|
5
5
|
import { CaptureConsumerOptions } from "../consumer/types.mjs";
|
|
6
6
|
import { ChildMessage } from "./protocol.mjs";
|
|
7
|
-
//#region src/capture/forked/child.d.ts
|
|
8
7
|
/** Handler options minus the shard hand-out, which the child wires to the database queue. */
|
|
9
8
|
type CaptureChildOptions = Omit<CaptureHandlerOptions, "enqueue" | "logger"> & Pick<CaptureConsumerOptions, "images" | "compare"> & {
|
|
10
9
|
logger?: Logger;
|
|
@@ -29,6 +28,5 @@ interface ChildHost {
|
|
|
29
28
|
* @throws When not running as a forked child (no IPC channel), or when the image engine cannot load.
|
|
30
29
|
*/
|
|
31
30
|
declare function runCaptureChild(options: CaptureChildOptions, host?: ChildHost): Promise<void>;
|
|
32
|
-
//#endregion
|
|
33
31
|
export { CaptureChildOptions, ChildHost, runCaptureChild };
|
|
34
32
|
//# sourceMappingURL=child.d.mts.map
|
|
@@ -10,7 +10,7 @@ import { createCaptureHandler, originOf } from "../consumer/capture-handler.mjs"
|
|
|
10
10
|
import { applyImageSettings, ensureImageEngine } from "../consumer/startup.mjs";
|
|
11
11
|
import "./fork.mjs";
|
|
12
12
|
import { isParentMessage } from "./protocol.mjs";
|
|
13
|
-
|
|
13
|
+
// src/capture/forked/child.ts
|
|
14
14
|
/**
|
|
15
15
|
* Entry helper for a forked capture child (`testing.workerEntry`). The app is the consumer: it
|
|
16
16
|
* polls the database queue, holds the slots and the lease, and pushes each leased job here over
|
|
@@ -196,7 +196,6 @@ function processHost() {
|
|
|
196
196
|
exit: (code) => process.exit(code)
|
|
197
197
|
};
|
|
198
198
|
}
|
|
199
|
-
//#endregion
|
|
200
199
|
export { runCaptureChild };
|
|
201
200
|
|
|
202
201
|
//# sourceMappingURL=child.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
|
|
4
|
+
// src/capture/forked/crash-tracker.ts
|
|
5
5
|
/** Counts child crashes inside a sliding window, to tell a flaky child from a crash loop. */
|
|
6
6
|
var CrashTracker = class {
|
|
7
7
|
#limit;
|
|
@@ -17,7 +17,6 @@ var CrashTracker = class {
|
|
|
17
17
|
return this.#times.length >= this.#limit;
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
|
-
//#endregion
|
|
21
20
|
export { CrashTracker };
|
|
22
21
|
|
|
23
22
|
//# sourceMappingURL=crash-tracker.mjs.map
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
|
-
//#region src/capture/forked/decision.d.ts
|
|
4
3
|
/** Whether a capture child is worth forking on this host (ADR 0005 phase 3 fallback rules). */
|
|
5
4
|
/** What the decision looks at. */
|
|
6
5
|
interface ForkHost {
|
|
@@ -21,6 +20,5 @@ declare const FORK_MIN_CPUS = 2;
|
|
|
21
20
|
declare const FORK_MIN_MEMORY_BYTES: number;
|
|
22
21
|
/** Pick the capture process model for a host. */
|
|
23
22
|
declare function decideCaptureProcess(host: ForkHost): ForkDecision;
|
|
24
|
-
//#endregion
|
|
25
23
|
export { FORK_MIN_CPUS, FORK_MIN_MEMORY_BYTES, ForkDecision, ForkHost, decideCaptureProcess };
|
|
26
24
|
//# sourceMappingURL=decision.d.mts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
|
|
4
|
+
// src/capture/forked/decision.ts
|
|
5
5
|
/** Smallest host that still gains from a second process: below this the child only costs memory. */
|
|
6
6
|
const FORK_MIN_CPUS = 2;
|
|
7
7
|
const FORK_MIN_MEMORY_BYTES = 2 * 1024 ** 3;
|
|
@@ -21,7 +21,6 @@ function decideCaptureProcess(host) {
|
|
|
21
21
|
};
|
|
22
22
|
return { mode: "fork" };
|
|
23
23
|
}
|
|
24
|
-
//#endregion
|
|
25
24
|
export { FORK_MIN_CPUS, FORK_MIN_MEMORY_BYTES, decideCaptureProcess };
|
|
26
25
|
|
|
27
26
|
//# sourceMappingURL=decision.mjs.map
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
|
|
4
|
+
// src/capture/forked/exit.ts
|
|
5
5
|
/** `signal SIGKILL` or `code 1`. */
|
|
6
6
|
function describeExit(info) {
|
|
7
7
|
return info.signal ? `signal ${info.signal}` : `code ${info.code}`;
|
|
8
8
|
}
|
|
9
|
-
//#endregion
|
|
10
9
|
export { describeExit };
|
|
11
10
|
|
|
12
11
|
//# sourceMappingURL=exit.mjs.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
3
|
import { ChildProcessHandle } from "./channel.mjs";
|
|
4
|
-
//#region src/capture/forked/fork.d.ts
|
|
5
4
|
/** Environment variable the forked child sees; set to this value so a module can tell it is the child. */
|
|
6
5
|
declare const CAPTURE_WORKER_ROLE = "capture-worker";
|
|
7
6
|
/** Environment variable carrying the parent's `testing.retries` to the child, which stamps it on the shard jobs it queues. */
|
|
@@ -26,6 +25,5 @@ interface ForkOptions {
|
|
|
26
25
|
* @throws When the runtime cannot fork, or the fork itself throws.
|
|
27
26
|
*/
|
|
28
27
|
declare function forkCaptureChild(options: ForkOptions): ChildProcessHandle;
|
|
29
|
-
//#endregion
|
|
30
28
|
export { CAPTURE_RETRIES_ENV, CAPTURE_SHARD_SIZE_ENV, CAPTURE_WORKER_ROLE, ForkOptions, canForkCaptureChild, forkCaptureChild };
|
|
31
29
|
//# sourceMappingURL=fork.d.mts.map
|