@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
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import "../adapter/database.mjs";
|
|
4
|
+
import { Snapshot } from "../schema/snapshot.mjs";
|
|
5
|
+
import { BaselineWriteConflict } from "./baseline-conflict.mjs";
|
|
6
|
+
import { BaselineStatus } from "./baseline-status.mjs";
|
|
7
|
+
interface AtomicBaselineApproval {
|
|
8
|
+
snapshot: Snapshot;
|
|
9
|
+
reviewedBy: string | null;
|
|
10
|
+
force: boolean;
|
|
11
|
+
branch: string;
|
|
12
|
+
}
|
|
13
|
+
declare class BaselineApprovalConflict extends BaselineWriteConflict {
|
|
14
|
+
readonly driftStatus?: BaselineStatus;
|
|
15
|
+
constructor(message: string, driftStatus?: BaselineStatus);
|
|
16
|
+
}
|
|
17
|
+
export { AtomicBaselineApproval, BaselineApprovalConflict };
|
|
18
|
+
//# sourceMappingURL=baseline-approval.d.mts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { col } from "./columns.mjs";
|
|
5
|
+
import { BaselineWriteConflict } from "./baseline-conflict.mjs";
|
|
6
|
+
import { baselineStatus, isBaselineDrifted } from "./baseline-status.mjs";
|
|
7
|
+
import { and, eq } from "drizzle-orm";
|
|
8
|
+
// src/models/baseline-approval.ts
|
|
9
|
+
/** Review checks and decision persisted inside the baseline/reference transaction. */
|
|
10
|
+
var BaselineApprovalConflict = class extends BaselineWriteConflict {
|
|
11
|
+
driftStatus;
|
|
12
|
+
constructor(message, driftStatus) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.driftStatus = driftStatus;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
async function approveInTransaction(tx, tables, input) {
|
|
18
|
+
const snapshot = await tx.get(tables.snapshots, input.snapshot.id);
|
|
19
|
+
if (!snapshot || snapshot.projectId !== input.snapshot.projectId || snapshot.buildId !== input.snapshot.buildId || snapshot.status !== input.snapshot.status || snapshot.updatedAt !== input.snapshot.updatedAt || snapshot.screenshotPath !== input.snapshot.screenshotPath || snapshot.baselineId !== input.snapshot.baselineId || snapshot.baselineVersion !== input.snapshot.baselineVersion) throw new BaselineApprovalConflict("Snapshot changed during approval; reload and retry");
|
|
20
|
+
const build = await tx.get(tables.builds, snapshot.buildId);
|
|
21
|
+
const project = await tx.get(tables.projects, snapshot.projectId);
|
|
22
|
+
if (!build || !project || build.projectId !== project.id || build.status === "cancelled" || build.gitBranch !== input.branch) throw new BaselineApprovalConflict("Build is unavailable for approval");
|
|
23
|
+
const current = await baselineFor(tx, tables, snapshot, build.gitBranch) ?? (build.gitBranch === project.gitDefaultBranch ? null : await baselineFor(tx, tables, snapshot, project.gitDefaultBranch));
|
|
24
|
+
const status = baselineStatus(snapshot, current);
|
|
25
|
+
if ((snapshot.status === "new" || snapshot.status === "changed") && isBaselineDrifted(status) && !input.force) throw new BaselineApprovalConflict("Baseline changed after this diff was computed", status);
|
|
26
|
+
await tx.update(tables.snapshots, snapshot.id, {
|
|
27
|
+
status: "approved",
|
|
28
|
+
reviewedBy: input.reviewedBy,
|
|
29
|
+
reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async function baselineFor(tx, tables, snapshot, branch) {
|
|
34
|
+
return (await tx.list(tables.baselines, {
|
|
35
|
+
where: and(eq(col(tables.baselines, "projectId"), snapshot.projectId), eq(col(tables.baselines, "storyId"), snapshot.storyId), eq(col(tables.baselines, "viewportName"), snapshot.viewportName), eq(col(tables.baselines, "browser"), snapshot.browser ?? "chromium"), eq(col(tables.baselines, "branch"), branch)),
|
|
36
|
+
limit: 1
|
|
37
|
+
}))[0] ?? null;
|
|
38
|
+
}
|
|
39
|
+
export { BaselineApprovalConflict, approveInTransaction };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=baseline-approval.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline-approval.mjs","names":[],"sources":["../../src/models/baseline-approval.ts"],"sourcesContent":["/** Review checks and decision persisted inside the baseline/reference transaction. */\nimport { and, eq } from \"drizzle-orm\";\nimport type { Tables, TxStore } from \"../adapters/database.ts\";\nimport type { Baseline } from \"../schema/baseline.ts\";\nimport type { Build } from \"../schema/build.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport type { Snapshot } from \"../schema/snapshot.ts\";\nimport { BaselineWriteConflict } from \"./baseline-conflict.ts\";\nimport { baselineStatus, isBaselineDrifted, type BaselineStatus } from \"./baseline-status.ts\";\nimport { col } from \"./columns.ts\";\n\nexport interface AtomicBaselineApproval {\n snapshot: Snapshot;\n reviewedBy: string | null;\n force: boolean;\n branch: string;\n}\nexport class BaselineApprovalConflict extends BaselineWriteConflict {\n readonly driftStatus?: BaselineStatus;\n constructor(message: string, driftStatus?: BaselineStatus) {\n super(message);\n this.driftStatus = driftStatus;\n }\n}\n\nexport async function approveInTransaction(\n tx: TxStore,\n tables: Tables,\n input: AtomicBaselineApproval,\n): Promise<void> {\n const snapshot = (await tx.get(\n tables.snapshots,\n input.snapshot.id,\n )) as unknown as Snapshot | null;\n if (\n !snapshot ||\n snapshot.projectId !== input.snapshot.projectId ||\n snapshot.buildId !== input.snapshot.buildId ||\n snapshot.status !== input.snapshot.status ||\n snapshot.updatedAt !== input.snapshot.updatedAt ||\n snapshot.screenshotPath !== input.snapshot.screenshotPath ||\n snapshot.baselineId !== input.snapshot.baselineId ||\n snapshot.baselineVersion !== input.snapshot.baselineVersion\n )\n throw new BaselineApprovalConflict(\"Snapshot changed during approval; reload and retry\");\n const build = (await tx.get(tables.builds, snapshot.buildId)) as unknown as Build | null;\n const project = (await tx.get(tables.projects, snapshot.projectId)) as unknown as Project | null;\n if (\n !build ||\n !project ||\n build.projectId !== project.id ||\n build.status === \"cancelled\" ||\n build.gitBranch !== input.branch\n )\n throw new BaselineApprovalConflict(\"Build is unavailable for approval\");\n const own = await baselineFor(tx, tables, snapshot, build.gitBranch);\n const current =\n own ??\n (build.gitBranch === project.gitDefaultBranch\n ? null\n : await baselineFor(tx, tables, snapshot, project.gitDefaultBranch));\n const status = baselineStatus(snapshot, current);\n if (\n (snapshot.status === \"new\" || snapshot.status === \"changed\") &&\n isBaselineDrifted(status) &&\n !input.force\n )\n throw new BaselineApprovalConflict(\"Baseline changed after this diff was computed\", status);\n await tx.update(tables.snapshots, snapshot.id, {\n status: \"approved\",\n reviewedBy: input.reviewedBy,\n reviewedAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n}\n\nasync function baselineFor(\n tx: TxStore,\n tables: Tables,\n snapshot: Snapshot,\n branch: string,\n): Promise<Baseline | null> {\n const rows = await tx.list(tables.baselines, {\n where: and(\n eq(col(tables.baselines, \"projectId\"), snapshot.projectId),\n eq(col(tables.baselines, \"storyId\"), snapshot.storyId),\n eq(col(tables.baselines, \"viewportName\"), snapshot.viewportName),\n eq(col(tables.baselines, \"browser\"), snapshot.browser ?? \"chromium\"),\n eq(col(tables.baselines, \"branch\"), branch),\n ),\n limit: 1,\n });\n return (rows[0] as unknown as Baseline | undefined) ?? null;\n}\n"],"mappings":";;;;;;;;;AAiBA,IAAa,2BAAb,cAA8C,sBAAsB;CAClE;CACA,YAAY,SAAiB,aAA8B;EACzD,MAAM,OAAO;EACb,KAAK,cAAc;CACrB;AACF;AAEA,eAAsB,qBACpB,IACA,QACA,OACe;CACf,MAAM,WAAY,MAAM,GAAG,IACzB,OAAO,WACP,MAAM,SAAS,EACjB;CACA,IACE,CAAC,YACD,SAAS,cAAc,MAAM,SAAS,aACtC,SAAS,YAAY,MAAM,SAAS,WACpC,SAAS,WAAW,MAAM,SAAS,UACnC,SAAS,cAAc,MAAM,SAAS,aACtC,SAAS,mBAAmB,MAAM,SAAS,kBAC3C,SAAS,eAAe,MAAM,SAAS,cACvC,SAAS,oBAAoB,MAAM,SAAS,iBAE5C,MAAM,IAAI,yBAAyB,oDAAoD;CACzF,MAAM,QAAS,MAAM,GAAG,IAAI,OAAO,QAAQ,SAAS,OAAO;CAC3D,MAAM,UAAW,MAAM,GAAG,IAAI,OAAO,UAAU,SAAS,SAAS;CACjE,IACE,CAAC,SACD,CAAC,WACD,MAAM,cAAc,QAAQ,MAC5B,MAAM,WAAW,eACjB,MAAM,cAAc,MAAM,QAE1B,MAAM,IAAI,yBAAyB,mCAAmC;CAExE,MAAM,UACJ,MAFgB,YAAY,IAAI,QAAQ,UAAU,MAAM,SAAS,MAGhE,MAAM,cAAc,QAAQ,mBACzB,OACA,MAAM,YAAY,IAAI,QAAQ,UAAU,QAAQ,gBAAgB;CACtE,MAAM,SAAS,eAAe,UAAU,OAAO;CAC/C,KACG,SAAS,WAAW,SAAS,SAAS,WAAW,cAClD,kBAAkB,MAAM,KACxB,CAAC,MAAM,OAEP,MAAM,IAAI,yBAAyB,iDAAiD,MAAM;CAC5F,MAAM,GAAG,OAAO,OAAO,WAAW,SAAS,IAAI;EAC7C,QAAQ;EACR,YAAY,MAAM;EAClB,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;CACpC,CAAC;AACH;AAEA,eAAe,YACb,IACA,QACA,UACA,QAC0B;CAW1B,QAAQ,MAVW,GAAG,KAAK,OAAO,WAAW;EAC3C,OAAO,IACL,GAAG,IAAI,OAAO,WAAW,WAAW,GAAG,SAAS,SAAS,GACzD,GAAG,IAAI,OAAO,WAAW,SAAS,GAAG,SAAS,OAAO,GACrD,GAAG,IAAI,OAAO,WAAW,cAAc,GAAG,SAAS,YAAY,GAC/D,GAAG,IAAI,OAAO,WAAW,SAAS,GAAG,SAAS,WAAW,UAAU,GACnE,GAAG,IAAI,OAAO,WAAW,QAAQ,GAAG,MAAM,CAC5C;EACA,OAAO;CACT,CAAC,EAAA,CACY,MAA0C;AACzD"}
|
|
@@ -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 { z } from "zod";
|
|
4
|
-
//#region src/models/baseline-archive.d.ts
|
|
5
4
|
/** Identifies a StoryShelf baseline archive. */
|
|
6
5
|
declare const BASELINE_ARCHIVE_FORMAT = "storyshelf-baselines";
|
|
7
6
|
/** Current archive format version. */
|
|
@@ -79,6 +78,5 @@ type BaselineSkipped = z.infer<typeof baselineSkippedSchema>;
|
|
|
79
78
|
declare class BaselineArchiveError extends Error {
|
|
80
79
|
readonly name = "BaselineArchiveError";
|
|
81
80
|
}
|
|
82
|
-
//#endregion
|
|
83
81
|
export { BASELINE_ARCHIVE_FORMAT, BASELINE_ARCHIVE_LIMITS, BASELINE_ARCHIVE_VERSION, BaselineArchiveError, BaselineManifest, BaselineManifestEntry, BaselineSkipped, baselineManifestEntrySchema, baselineManifestSchema, baselineSkippedSchema };
|
|
84
82
|
//# sourceMappingURL=baseline-archive.d.mts.map
|
|
@@ -3,7 +3,7 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { modeSegment } from "../paths.mjs";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
|
|
6
|
+
// src/models/baseline-archive.ts
|
|
7
7
|
/**
|
|
8
8
|
* Baseline archive format (v1): a zip holding `manifest.json` plus one PNG per
|
|
9
9
|
* baseline at `baselines/<branch>/<storyId>/<mode>.png` — the storage layout
|
|
@@ -100,7 +100,6 @@ const PNG_SIGNATURE = Buffer.from([
|
|
|
100
100
|
function isPng(data) {
|
|
101
101
|
return data.length >= PNG_SIGNATURE.length && data.subarray(0, 8).equals(PNG_SIGNATURE);
|
|
102
102
|
}
|
|
103
|
-
//#endregion
|
|
104
103
|
export { BASELINE_ARCHIVE_FORMAT, BASELINE_ARCHIVE_LIMITS, BASELINE_ARCHIVE_VERSION, BASELINE_MANIFEST_NAME, BaselineArchiveError, archiveFileName, baselineIdentity, baselineManifestEntrySchema, baselineManifestSchema, baselineSkippedSchema, isPng };
|
|
105
104
|
|
|
106
105
|
//# sourceMappingURL=baseline-archive.mjs.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import "../adapters/capture-target.mjs";
|
|
5
|
+
import { col } from "./columns.mjs";
|
|
6
|
+
import { BaselineWriteConflict } from "./baseline-conflict.mjs";
|
|
7
|
+
import { and, eq } from "drizzle-orm";
|
|
8
|
+
// src/models/baseline-atomic.ts
|
|
9
|
+
/** Transactional baseline mutation for adapters with explicit reference lifecycle support. */
|
|
10
|
+
/** Atomically change the baseline row and its complete build-reference set. */
|
|
11
|
+
async function upsertAtomicBaseline(lifecycle, tables, input) {
|
|
12
|
+
const owner = {
|
|
13
|
+
projectId: input.projectId,
|
|
14
|
+
type: "baseline",
|
|
15
|
+
id: input.id
|
|
16
|
+
};
|
|
17
|
+
const generation = await lifecycle.referenceGeneration(owner);
|
|
18
|
+
return (await lifecycle.replaceFencedReferences(owner, generation, input.sourceBuildId ? [input.sourceBuildId] : [], async (tx) => {
|
|
19
|
+
await input.beforeWrite?.(tx);
|
|
20
|
+
return await writeBaseline(tx, tables, input);
|
|
21
|
+
})).result;
|
|
22
|
+
}
|
|
23
|
+
async function writeBaseline(tx, tables, input) {
|
|
24
|
+
const existing = (await tx.list(tables.baselines, {
|
|
25
|
+
where: and(eq(col(tables.baselines, "projectId"), input.projectId), eq(col(tables.baselines, "storyId"), input.storyId), eq(col(tables.baselines, "viewportName"), input.viewport), eq(col(tables.baselines, "branch"), input.branch), eq(col(tables.baselines, "browser"), input.browser)),
|
|
26
|
+
limit: 1
|
|
27
|
+
}))[0] ?? null;
|
|
28
|
+
assertBaselineUnchanged(existing, input);
|
|
29
|
+
if (input.sourceBuildId) await assertSource(tx, tables.snapshots, input);
|
|
30
|
+
const now = nextBaselineVersion(existing?.updatedAt ?? null, /* @__PURE__ */ new Date());
|
|
31
|
+
const fields = {
|
|
32
|
+
snapshotId: input.snapshotId,
|
|
33
|
+
sourceBuildId: input.sourceBuildId,
|
|
34
|
+
screenshotPath: input.screenshotPath,
|
|
35
|
+
infraHash: input.infraHash ?? existing?.infraHash ?? null,
|
|
36
|
+
fingerprint: input.fingerprint ?? existing?.fingerprint ?? null,
|
|
37
|
+
mode: input.mode ?? existing?.mode ?? null,
|
|
38
|
+
updatedAt: now
|
|
39
|
+
};
|
|
40
|
+
return existing ? await tx.update(tables.baselines, existing.id, fields) : await tx.insert(tables.baselines, {
|
|
41
|
+
...fields,
|
|
42
|
+
id: input.id,
|
|
43
|
+
projectId: input.projectId,
|
|
44
|
+
storyId: input.storyId,
|
|
45
|
+
viewportName: input.viewport,
|
|
46
|
+
branch: input.branch,
|
|
47
|
+
browser: input.browser,
|
|
48
|
+
createdAt: now
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function assertBaselineUnchanged(existing, input) {
|
|
52
|
+
if ((existing?.id ?? null) !== input.existingId || (existing?.updatedAt ?? null) !== input.existingVersion) throw new BaselineWriteConflict("Baseline changed during promotion; retry");
|
|
53
|
+
}
|
|
54
|
+
/** Keep the version advancing even when updates share a millisecond or clocks move backwards. */
|
|
55
|
+
function nextBaselineVersion(previous, now) {
|
|
56
|
+
const last = previous === null ? NaN : Date.parse(previous);
|
|
57
|
+
return new Date(Number.isFinite(last) ? Math.max(now.getTime(), last + 1) : now.getTime()).toISOString();
|
|
58
|
+
}
|
|
59
|
+
async function assertSource(tx, table, input) {
|
|
60
|
+
const row = await tx.get(table, input.snapshotId);
|
|
61
|
+
const origin = row?.inherited ? row.sourceBuildId : row?.buildId;
|
|
62
|
+
if (!row || row.projectId !== input.projectId || row.storyId !== input.storyId || row.viewportName !== input.viewport || (row.browser ?? "chromium") !== input.browser || row.screenshotPath !== input.originalPath || origin !== input.sourceBuildId) throw new BaselineWriteConflict("Source snapshot changed during promotion; retry");
|
|
63
|
+
}
|
|
64
|
+
export { nextBaselineVersion, upsertAtomicBaseline };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=baseline-atomic.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline-atomic.mjs","names":[],"sources":["../../src/models/baseline-atomic.ts"],"sourcesContent":["/** Transactional baseline mutation for adapters with explicit reference lifecycle support. */\nimport { and, eq } from \"drizzle-orm\";\nimport type { Table } from \"drizzle-orm\";\nimport { DEFAULT_BROWSER } from \"../adapters/capture-runner.ts\";\nimport type { BuildReferenceLifecycle, TxStore } from \"../adapters/database.ts\";\nimport type { Baseline } from \"../schema/baseline.ts\";\nimport type { Snapshot } from \"../schema/snapshot.ts\";\nimport { BaselineWriteConflict } from \"./baseline-conflict.ts\";\nimport { col } from \"./columns.ts\";\n\nexport interface AtomicBaselineInput {\n id: string;\n existingId: string | null;\n existingVersion: string | null;\n projectId: string;\n storyId: string;\n viewport: string;\n branch: string;\n browser: string;\n snapshotId: string;\n sourceBuildId: string | null;\n originalPath: string;\n screenshotPath: string;\n infraHash: string | null | undefined;\n fingerprint: string | null | undefined;\n mode: string | null | undefined;\n beforeWrite?: (tx: TxStore) => Promise<void>;\n}\n\n/** Atomically change the baseline row and its complete build-reference set. */\nexport async function upsertAtomicBaseline(\n lifecycle: BuildReferenceLifecycle,\n tables: { baselines: Table; snapshots: Table },\n input: AtomicBaselineInput,\n): Promise<Baseline> {\n const owner = { projectId: input.projectId, type: \"baseline\" as const, id: input.id };\n const generation = await lifecycle.referenceGeneration(owner);\n const updated = await lifecycle.replaceFencedReferences(\n owner,\n generation,\n input.sourceBuildId ? [input.sourceBuildId] : [],\n async (tx) => {\n await input.beforeWrite?.(tx);\n return await writeBaseline(tx, tables, input);\n },\n );\n return updated.result;\n}\n\nasync function writeBaseline(\n tx: TxStore,\n tables: { baselines: Table; snapshots: Table },\n input: AtomicBaselineInput,\n): Promise<Baseline> {\n const rows = (await tx.list(tables.baselines, {\n where: and(\n eq(col(tables.baselines, \"projectId\"), input.projectId),\n eq(col(tables.baselines, \"storyId\"), input.storyId),\n eq(col(tables.baselines, \"viewportName\"), input.viewport),\n eq(col(tables.baselines, \"branch\"), input.branch),\n eq(col(tables.baselines, \"browser\"), input.browser),\n ),\n limit: 1,\n })) as unknown as Baseline[];\n const existing = rows[0] ?? null;\n assertBaselineUnchanged(existing, input);\n if (input.sourceBuildId) await assertSource(tx, tables.snapshots, input);\n const now = nextBaselineVersion(existing?.updatedAt ?? null, new Date());\n const fields = {\n snapshotId: input.snapshotId,\n sourceBuildId: input.sourceBuildId,\n screenshotPath: input.screenshotPath,\n infraHash: input.infraHash ?? existing?.infraHash ?? null,\n fingerprint: input.fingerprint ?? existing?.fingerprint ?? null,\n mode: input.mode ?? existing?.mode ?? null,\n updatedAt: now,\n };\n return (existing\n ? await tx.update(tables.baselines, existing.id, fields)\n : await tx.insert(tables.baselines, {\n ...fields,\n id: input.id,\n projectId: input.projectId,\n storyId: input.storyId,\n viewportName: input.viewport,\n branch: input.branch,\n browser: input.browser,\n createdAt: now,\n })) as unknown as Baseline;\n}\n\nfunction assertBaselineUnchanged(existing: Baseline | null, input: AtomicBaselineInput): void {\n if (\n (existing?.id ?? null) !== input.existingId ||\n (existing?.updatedAt ?? null) !== input.existingVersion\n )\n throw new BaselineWriteConflict(\"Baseline changed during promotion; retry\");\n}\n\n/** Keep the version advancing even when updates share a millisecond or clocks move backwards. */\nexport function nextBaselineVersion(previous: string | null, now: Date): string {\n const last = previous === null ? Number.NaN : Date.parse(previous);\n return new Date(\n Number.isFinite(last) ? Math.max(now.getTime(), last + 1) : now.getTime(),\n ).toISOString();\n}\n\nasync function assertSource(tx: TxStore, table: Table, input: AtomicBaselineInput): Promise<void> {\n const row = (await tx.get(table, input.snapshotId)) as unknown as Snapshot | null;\n const origin = row?.inherited ? row.sourceBuildId : row?.buildId;\n if (\n !row ||\n row.projectId !== input.projectId ||\n row.storyId !== input.storyId ||\n row.viewportName !== input.viewport ||\n (row.browser ?? DEFAULT_BROWSER) !== input.browser ||\n row.screenshotPath !== input.originalPath ||\n origin !== input.sourceBuildId\n ) {\n throw new BaselineWriteConflict(\"Source snapshot changed during promotion; retry\");\n }\n}\n"],"mappings":";;;;;;;;;;AA8BA,eAAsB,qBACpB,WACA,QACA,OACmB;CACnB,MAAM,QAAQ;EAAE,WAAW,MAAM;EAAW,MAAM;EAAqB,IAAI,MAAM;CAAG;CACpF,MAAM,aAAa,MAAM,UAAU,oBAAoB,KAAK;CAU5D,QAAO,MATe,UAAU,wBAC9B,OACA,YACA,MAAM,gBAAgB,CAAC,MAAM,aAAa,IAAI,CAAC,GAC/C,OAAO,OAAO;EACZ,MAAM,MAAM,cAAc,EAAE;EAC5B,OAAO,MAAM,cAAc,IAAI,QAAQ,KAAK;CAC9C,CACF,EAAA,CACe;AACjB;AAEA,eAAe,cACb,IACA,QACA,OACmB;CAWnB,MAAM,YAAW,MAVG,GAAG,KAAK,OAAO,WAAW;EAC5C,OAAO,IACL,GAAG,IAAI,OAAO,WAAW,WAAW,GAAG,MAAM,SAAS,GACtD,GAAG,IAAI,OAAO,WAAW,SAAS,GAAG,MAAM,OAAO,GAClD,GAAG,IAAI,OAAO,WAAW,cAAc,GAAG,MAAM,QAAQ,GACxD,GAAG,IAAI,OAAO,WAAW,QAAQ,GAAG,MAAM,MAAM,GAChD,GAAG,IAAI,OAAO,WAAW,SAAS,GAAG,MAAM,OAAO,CACpD;EACA,OAAO;CACT,CAAC,EAAA,CACqB,MAAM;CAC5B,wBAAwB,UAAU,KAAK;CACvC,IAAI,MAAM,eAAe,MAAM,aAAa,IAAI,OAAO,WAAW,KAAK;CACvE,MAAM,MAAM,oBAAoB,UAAU,aAAa,sBAAM,IAAI,KAAK,CAAC;CACvE,MAAM,SAAS;EACb,YAAY,MAAM;EAClB,eAAe,MAAM;EACrB,gBAAgB,MAAM;EACtB,WAAW,MAAM,aAAa,UAAU,aAAa;EACrD,aAAa,MAAM,eAAe,UAAU,eAAe;EAC3D,MAAM,MAAM,QAAQ,UAAU,QAAQ;EACtC,WAAW;CACb;CACA,OAAQ,WACJ,MAAM,GAAG,OAAO,OAAO,WAAW,SAAS,IAAI,MAAM,IACrD,MAAM,GAAG,OAAO,OAAO,WAAW;EAChC,GAAG;EACH,IAAI,MAAM;EACV,WAAW,MAAM;EACjB,SAAS,MAAM;EACf,cAAc,MAAM;EACpB,QAAQ,MAAM;EACd,SAAS,MAAM;EACf,WAAW;CACb,CAAC;AACP;AAEA,SAAS,wBAAwB,UAA2B,OAAkC;CAC5F,KACG,UAAU,MAAM,UAAU,MAAM,eAChC,UAAU,aAAa,UAAU,MAAM,iBAExC,MAAM,IAAI,sBAAsB,0CAA0C;AAC9E;;AAGA,SAAgB,oBAAoB,UAAyB,KAAmB;CAC9E,MAAM,OAAO,aAAa,OAAO,MAAa,KAAK,MAAM,QAAQ;CACjE,OAAO,IAAI,KACT,OAAO,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,QAAQ,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,CAC1E,CAAC,CAAC,YAAY;AAChB;AAEA,eAAe,aAAa,IAAa,OAAc,OAA2C;CAChG,MAAM,MAAO,MAAM,GAAG,IAAI,OAAO,MAAM,UAAU;CACjD,MAAM,SAAS,KAAK,YAAY,IAAI,gBAAgB,KAAK;CACzD,IACE,CAAC,OACD,IAAI,cAAc,MAAM,aACxB,IAAI,YAAY,MAAM,WACtB,IAAI,iBAAiB,MAAM,aAC1B,IAAI,WAAA,gBAAgC,MAAM,WAC3C,IAAI,mBAAmB,MAAM,gBAC7B,WAAW,MAAM,eAEjB,MAAM,IAAI,sBAAsB,iDAAiD;AAErF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
/** A baseline write lost a concurrency check and should be retried. */
|
|
4
|
+
declare class BaselineWriteConflict extends Error {}
|
|
5
|
+
export { BaselineWriteConflict };
|
|
6
|
+
//# sourceMappingURL=baseline-conflict.d.mts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
// src/models/baseline-conflict.ts
|
|
5
|
+
/** A baseline write lost a concurrency check and should be retried. */
|
|
6
|
+
var BaselineWriteConflict = class extends Error {};
|
|
7
|
+
export { BaselineWriteConflict };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=baseline-conflict.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline-conflict.mjs","names":[],"sources":["../../src/models/baseline-conflict.ts"],"sourcesContent":["/** A baseline write lost a concurrency check and should be retried. */\nexport class BaselineWriteConflict extends Error {}\n"],"mappings":";;;;;AACA,IAAa,wBAAb,cAA2C,MAAM,CAAC"}
|
|
@@ -2,7 +2,6 @@ import __tsdown_shims_path from 'node:path';
|
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
3
|
import "../adapter/storage.mjs";
|
|
4
4
|
import { BaselineSkipped } from "./baseline-archive.mjs";
|
|
5
|
-
//#region src/models/baseline-export.d.ts
|
|
6
5
|
/** Options for {@link exportBaselineArchive}. */
|
|
7
6
|
interface BaselineExportOptions {
|
|
8
7
|
/** Export only this branch; omit (or null) for every branch. */
|
|
@@ -14,6 +13,5 @@ interface BaselineExportOptions {
|
|
|
14
13
|
/** Clock override for `exportedAt` (tests). */
|
|
15
14
|
now?: () => Date;
|
|
16
15
|
}
|
|
17
|
-
//#endregion
|
|
18
16
|
export { BaselineExportOptions };
|
|
19
17
|
//# sourceMappingURL=baseline-export.d.mts.map
|
|
@@ -5,7 +5,7 @@ import "../adapters/capture-target.mjs";
|
|
|
5
5
|
import { BASELINE_ARCHIVE_FORMAT, BASELINE_ARCHIVE_LIMITS, BASELINE_MANIFEST_NAME, BaselineArchiveError, archiveFileName } from "./baseline-archive.mjs";
|
|
6
6
|
import { zipStream } from "../utils/zip-write.mjs";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
|
-
|
|
8
|
+
// src/models/baseline-export.ts
|
|
9
9
|
/** Stream a project's baselines as a portable zip archive (format v1). */
|
|
10
10
|
/**
|
|
11
11
|
* Prepare a baseline archive for `rows`. Validation (the entry limit) runs
|
|
@@ -130,7 +130,6 @@ function uniqueName(name, names) {
|
|
|
130
130
|
names.add(candidate);
|
|
131
131
|
return candidate;
|
|
132
132
|
}
|
|
133
|
-
//#endregion
|
|
134
133
|
export { exportBaselineArchive };
|
|
135
134
|
|
|
136
135
|
//# sourceMappingURL=baseline-export.mjs.map
|
|
@@ -6,7 +6,7 @@ import { BASELINE_ARCHIVE_LIMITS, BASELINE_MANIFEST_NAME, BaselineArchiveError,
|
|
|
6
6
|
import { ZipFormatError, readZip } from "../utils/zip-read.mjs";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
import { setImmediate } from "node:timers/promises";
|
|
9
|
-
|
|
9
|
+
// src/models/baseline-import.ts
|
|
10
10
|
/**
|
|
11
11
|
* Validate and apply a baseline archive (format v1).
|
|
12
12
|
*
|
|
@@ -112,7 +112,6 @@ function readEntry(zipEntry) {
|
|
|
112
112
|
throw error;
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
//#endregion
|
|
116
115
|
export { planBaselineImport, writePlannedImage };
|
|
117
116
|
|
|
118
117
|
//# sourceMappingURL=baseline-import.mjs.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { Build } from "../schema/build.mjs";
|
|
4
|
+
import { Baseline } from "../schema/baseline.mjs";
|
|
5
|
+
import { Snapshot } from "../schema/snapshot.mjs";
|
|
6
|
+
import "../schema.mjs";
|
|
7
|
+
/** The records needed to prove which build rendered a baseline image. */
|
|
8
|
+
interface BaselineOriginReader {
|
|
9
|
+
baseline(id: string): Promise<Baseline | null>;
|
|
10
|
+
snapshot(id: string): Promise<Snapshot | null>;
|
|
11
|
+
build(id: string): Promise<Build | null>;
|
|
12
|
+
}
|
|
13
|
+
/** A proven source, or null when the recorded history is incomplete or has changed. */
|
|
14
|
+
declare function resolveBaselineOrigin(baseline: Baseline, reader: BaselineOriginReader): Promise<Build | null>;
|
|
15
|
+
export { BaselineOriginReader, resolveBaselineOrigin };
|
|
16
|
+
//# sourceMappingURL=baseline-origin.d.mts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import "../adapters/capture-target.mjs";
|
|
5
|
+
// src/models/baseline-origin.ts
|
|
6
|
+
/** A proven source, or null when the recorded history is incomplete or has changed. */
|
|
7
|
+
async function resolveBaselineOrigin(baseline, reader) {
|
|
8
|
+
return await traceOrigin(baseline, baseline.projectId, reader, /* @__PURE__ */ new Set());
|
|
9
|
+
}
|
|
10
|
+
async function traceOrigin(current, projectId, reader, seen) {
|
|
11
|
+
if (current.sourceBuildId) return await verifiedBuild(current.sourceBuildId, projectId, reader);
|
|
12
|
+
if (seen.size >= 32 || seen.has(current.id) || !current.snapshotId) return null;
|
|
13
|
+
seen.add(current.id);
|
|
14
|
+
const snapshot = await reader.snapshot(current.snapshotId);
|
|
15
|
+
if (!snapshot || !matchesImage(current, snapshot)) return null;
|
|
16
|
+
if (!snapshot.inherited) return await verifiedBuild(snapshot.buildId, projectId, reader);
|
|
17
|
+
return await traceInherited(snapshot, projectId, reader, seen);
|
|
18
|
+
}
|
|
19
|
+
async function traceInherited(snapshot, projectId, reader, seen) {
|
|
20
|
+
if (snapshot.sourceBuildId) return await verifiedBuild(snapshot.sourceBuildId, projectId, reader);
|
|
21
|
+
if (!snapshot.baselineId || !snapshot.baselineVersion) return null;
|
|
22
|
+
const parent = await reader.baseline(snapshot.baselineId);
|
|
23
|
+
if (!parent || parent.updatedAt !== snapshot.baselineVersion || !matchesImage(parent, snapshot)) return null;
|
|
24
|
+
return await traceOrigin(parent, projectId, reader, seen);
|
|
25
|
+
}
|
|
26
|
+
function matchesImage(baseline, snapshot) {
|
|
27
|
+
return baseline.projectId === snapshot.projectId && baseline.storyId === snapshot.storyId && baseline.viewportName === snapshot.viewportName && (baseline.browser ?? "chromium") === (snapshot.browser ?? "chromium") && baseline.screenshotPath === snapshot.screenshotPath;
|
|
28
|
+
}
|
|
29
|
+
async function verifiedBuild(buildId, projectId, reader) {
|
|
30
|
+
const build = await reader.build(buildId);
|
|
31
|
+
return build?.projectId === projectId ? build : null;
|
|
32
|
+
}
|
|
33
|
+
export { resolveBaselineOrigin };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=baseline-origin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline-origin.mjs","names":[],"sources":["../../src/models/baseline-origin.ts"],"sourcesContent":["import { DEFAULT_BROWSER } from \"../adapters/capture-runner.ts\";\nimport type { Baseline, Build, Snapshot } from \"../schema/index.ts\";\n\n/** The records needed to prove which build rendered a baseline image. */\nexport interface BaselineOriginReader {\n baseline(id: string): Promise<Baseline | null>;\n snapshot(id: string): Promise<Snapshot | null>;\n build(id: string): Promise<Build | null>;\n}\n\n/** A proven source, or null when the recorded history is incomplete or has changed. */\nexport async function resolveBaselineOrigin(\n baseline: Baseline,\n reader: BaselineOriginReader,\n): Promise<Build | null> {\n return await traceOrigin(baseline, baseline.projectId, reader, new Set());\n}\n\nasync function traceOrigin(\n current: Baseline,\n projectId: string,\n reader: BaselineOriginReader,\n seen: Set<string>,\n): Promise<Build | null> {\n if (current.sourceBuildId) return await verifiedBuild(current.sourceBuildId, projectId, reader);\n if (seen.size >= 32 || seen.has(current.id) || !current.snapshotId) return null;\n seen.add(current.id);\n const snapshot = await reader.snapshot(current.snapshotId);\n if (!snapshot || !matchesImage(current, snapshot)) return null;\n if (!snapshot.inherited) return await verifiedBuild(snapshot.buildId, projectId, reader);\n return await traceInherited(snapshot, projectId, reader, seen);\n}\n\nasync function traceInherited(\n snapshot: Snapshot,\n projectId: string,\n reader: BaselineOriginReader,\n seen: Set<string>,\n): Promise<Build | null> {\n if (snapshot.sourceBuildId) return await verifiedBuild(snapshot.sourceBuildId, projectId, reader);\n if (!snapshot.baselineId || !snapshot.baselineVersion) return null;\n const parent = await reader.baseline(snapshot.baselineId);\n if (!parent || parent.updatedAt !== snapshot.baselineVersion || !matchesImage(parent, snapshot))\n return null;\n return await traceOrigin(parent, projectId, reader, seen);\n}\n\nfunction matchesImage(baseline: Baseline, snapshot: Snapshot): boolean {\n return (\n baseline.projectId === snapshot.projectId &&\n baseline.storyId === snapshot.storyId &&\n baseline.viewportName === snapshot.viewportName &&\n (baseline.browser ?? DEFAULT_BROWSER) === (snapshot.browser ?? DEFAULT_BROWSER) &&\n baseline.screenshotPath === snapshot.screenshotPath\n );\n}\n\nasync function verifiedBuild(\n buildId: string,\n projectId: string,\n reader: BaselineOriginReader,\n): Promise<Build | null> {\n const build = await reader.build(buildId);\n return build?.projectId === projectId ? build : null;\n}\n"],"mappings":";;;;;;AAWA,eAAsB,sBACpB,UACA,QACuB;CACvB,OAAO,MAAM,YAAY,UAAU,SAAS,WAAW,wBAAQ,IAAI,IAAI,CAAC;AAC1E;AAEA,eAAe,YACb,SACA,WACA,QACA,MACuB;CACvB,IAAI,QAAQ,eAAe,OAAO,MAAM,cAAc,QAAQ,eAAe,WAAW,MAAM;CAC9F,IAAI,KAAK,QAAQ,MAAM,KAAK,IAAI,QAAQ,EAAE,KAAK,CAAC,QAAQ,YAAY,OAAO;CAC3E,KAAK,IAAI,QAAQ,EAAE;CACnB,MAAM,WAAW,MAAM,OAAO,SAAS,QAAQ,UAAU;CACzD,IAAI,CAAC,YAAY,CAAC,aAAa,SAAS,QAAQ,GAAG,OAAO;CAC1D,IAAI,CAAC,SAAS,WAAW,OAAO,MAAM,cAAc,SAAS,SAAS,WAAW,MAAM;CACvF,OAAO,MAAM,eAAe,UAAU,WAAW,QAAQ,IAAI;AAC/D;AAEA,eAAe,eACb,UACA,WACA,QACA,MACuB;CACvB,IAAI,SAAS,eAAe,OAAO,MAAM,cAAc,SAAS,eAAe,WAAW,MAAM;CAChG,IAAI,CAAC,SAAS,cAAc,CAAC,SAAS,iBAAiB,OAAO;CAC9D,MAAM,SAAS,MAAM,OAAO,SAAS,SAAS,UAAU;CACxD,IAAI,CAAC,UAAU,OAAO,cAAc,SAAS,mBAAmB,CAAC,aAAa,QAAQ,QAAQ,GAC5F,OAAO;CACT,OAAO,MAAM,YAAY,QAAQ,WAAW,QAAQ,IAAI;AAC1D;AAEA,SAAS,aAAa,UAAoB,UAA6B;CACrE,OACE,SAAS,cAAc,SAAS,aAChC,SAAS,YAAY,SAAS,WAC9B,SAAS,iBAAiB,SAAS,iBAClC,SAAS,WAAA,iBAAiC,SAAS,WAAA,eACpD,SAAS,mBAAmB,SAAS;AAEzC;AAEA,eAAe,cACb,SACA,WACA,QACuB;CACvB,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO;CACxC,OAAO,OAAO,cAAc,YAAY,QAAQ;AAClD"}
|
|
@@ -2,7 +2,6 @@ import __tsdown_shims_path from 'node:path';
|
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
3
|
import { Baseline } from "../schema/baseline.mjs";
|
|
4
4
|
import { Snapshot } from "../schema/snapshot.mjs";
|
|
5
|
-
//#region src/models/baseline-status.d.ts
|
|
6
5
|
/** `baselineVersion` recorded when a story had no baseline at diff time. */
|
|
7
6
|
declare const NO_BASELINE = "none";
|
|
8
7
|
/**
|
|
@@ -24,6 +23,5 @@ type TrackedSnapshot = Pick<Snapshot, "baselineId" | "baselineVersion">;
|
|
|
24
23
|
declare function baselineStatus(snapshot: TrackedSnapshot, current: Baseline | null): BaselineStatus;
|
|
25
24
|
/** True when approving should be refused until the diff is recomputed (or forced). */
|
|
26
25
|
declare function isBaselineDrifted(status: BaselineStatus): boolean;
|
|
27
|
-
//#endregion
|
|
28
26
|
export { BaselineStatus, NO_BASELINE, baselineStatus, isBaselineDrifted };
|
|
29
27
|
//# sourceMappingURL=baseline-status.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/models/baseline-status.ts
|
|
5
5
|
/** `baselineVersion` recorded when a story had no baseline at diff time. */
|
|
6
6
|
const NO_BASELINE = "none";
|
|
7
7
|
/**
|
|
@@ -20,7 +20,6 @@ function baselineStatus(snapshot, current) {
|
|
|
20
20
|
function isBaselineDrifted(status) {
|
|
21
21
|
return status === "stale" || status === "removed";
|
|
22
22
|
}
|
|
23
|
-
//#endregion
|
|
24
23
|
export { NO_BASELINE, baselineStatus, isBaselineDrifted };
|
|
25
24
|
|
|
26
25
|
//# sourceMappingURL=baseline-status.mjs.map
|
|
@@ -4,7 +4,6 @@ import { DatabaseAdapter } from "../adapter/database.mjs";
|
|
|
4
4
|
import { StorageAdapter } from "../adapter/storage.mjs";
|
|
5
5
|
import { BaselineTables } from "./baseline.mjs";
|
|
6
6
|
import { BaselineExportOptions } from "./baseline-export.mjs";
|
|
7
|
-
//#region src/models/baseline-transfer.d.ts
|
|
8
7
|
/** Outcome of {@link BaselineTransferModel.import}. */
|
|
9
8
|
interface BaselineImportResult {
|
|
10
9
|
/** Baselines in the archive (all applied). */
|
|
@@ -41,9 +40,9 @@ declare class BaselineTransferModel {
|
|
|
41
40
|
private existingByIdentity;
|
|
42
41
|
/** Apply every row, in a transaction when available; returns how many were created. */
|
|
43
42
|
private applyRows;
|
|
43
|
+
private assertUnchangedIdentities;
|
|
44
44
|
/** Write one planned row; resolves true when it was created. */
|
|
45
45
|
private applyRow;
|
|
46
46
|
}
|
|
47
|
-
//#endregion
|
|
48
47
|
export { BaselineImportResult, BaselineTransferModel };
|
|
49
48
|
//# sourceMappingURL=baseline-transfer.d.mts.map
|
|
@@ -4,11 +4,12 @@ import.meta.url;
|
|
|
4
4
|
import "../adapters/capture-target.mjs";
|
|
5
5
|
import { ulid } from "../utils/ulid.mjs";
|
|
6
6
|
import { withContentClaim } from "../utils/screenshot-store.mjs";
|
|
7
|
+
import { BaselineWriteConflict } from "./baseline-conflict.mjs";
|
|
7
8
|
import { BaselineModel } from "./baseline.mjs";
|
|
8
9
|
import { baselineIdentity } from "./baseline-archive.mjs";
|
|
9
10
|
import { exportBaselineArchive } from "./baseline-export.mjs";
|
|
10
11
|
import { planBaselineImport, writePlannedImage } from "./baseline-import.mjs";
|
|
11
|
-
|
|
12
|
+
// src/models/baseline-transfer.ts
|
|
12
13
|
/**
|
|
13
14
|
* Baseline portability: export a project's baselines as a zip archive and
|
|
14
15
|
* import (upsert) them from the same format. Format and limits live in
|
|
@@ -73,13 +74,41 @@ var BaselineTransferModel = class {
|
|
|
73
74
|
for (const planned of plan) created += await this.applyRow(store, projectId, planned, existing) ? 1 : 0;
|
|
74
75
|
return created;
|
|
75
76
|
};
|
|
77
|
+
const lifecycle = this.db.buildReferenceLifecycle;
|
|
78
|
+
if (lifecycle) {
|
|
79
|
+
const touched = plan.map((planned) => existing.get(baselineIdentity(planned.entry))).filter((row) => row !== void 0);
|
|
80
|
+
const changes = await Promise.all(touched.map(async (row) => {
|
|
81
|
+
const owner = {
|
|
82
|
+
type: "baseline",
|
|
83
|
+
id: row.id,
|
|
84
|
+
projectId
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
owner,
|
|
88
|
+
expectedGeneration: await lifecycle.referenceGeneration(owner),
|
|
89
|
+
buildIds: []
|
|
90
|
+
};
|
|
91
|
+
}));
|
|
92
|
+
return (await lifecycle.replaceManyFencedReferences(changes, async (store) => {
|
|
93
|
+
await this.assertUnchangedIdentities(store, touched);
|
|
94
|
+
return await run(store);
|
|
95
|
+
})).result;
|
|
96
|
+
}
|
|
76
97
|
return this.db.transact ? await this.db.transact(run) : await run(this.db);
|
|
77
98
|
}
|
|
99
|
+
async assertUnchangedIdentities(store, rows) {
|
|
100
|
+
const current = await Promise.all(rows.map(async (row) => await store.get(this.tables.baselines, row.id)));
|
|
101
|
+
for (const [index, row] of rows.entries()) {
|
|
102
|
+
const found = current[index];
|
|
103
|
+
if (!found || found.projectId !== row.projectId || found.storyId !== row.storyId || found.viewportName !== row.viewportName || found.branch !== row.branch || found.updatedAt !== row.updatedAt || found.snapshotId !== row.snapshotId || found.sourceBuildId !== row.sourceBuildId || found.screenshotPath !== row.screenshotPath || (found.browser ?? "chromium") !== (row.browser ?? "chromium")) throw new BaselineWriteConflict("Baseline changed during import; retry");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
78
106
|
/** Write one planned row; resolves true when it was created. */
|
|
79
107
|
async applyRow(store, projectId, planned, existing) {
|
|
80
108
|
const { entry, storagePath } = planned;
|
|
81
109
|
const fields = {
|
|
82
110
|
snapshotId: null,
|
|
111
|
+
sourceBuildId: null,
|
|
83
112
|
screenshotPath: storagePath,
|
|
84
113
|
infraHash: entry.infraHash,
|
|
85
114
|
fingerprint: entry.fingerprint ?? null,
|
|
@@ -115,7 +144,6 @@ async function serialized(key, task) {
|
|
|
115
144
|
if (importQueues.get(key) === run) importQueues.delete(key);
|
|
116
145
|
}
|
|
117
146
|
}
|
|
118
|
-
//#endregion
|
|
119
147
|
export { BaselineTransferModel };
|
|
120
148
|
|
|
121
149
|
//# sourceMappingURL=baseline-transfer.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseline-transfer.mjs","names":[],"sources":["../../src/models/baseline-transfer.ts"],"sourcesContent":["/**\n * Baseline portability: export a project's baselines as a zip archive and\n * import (upsert) them from the same format. Format and limits live in\n * `baseline-archive.ts`; see the portability guide in the docs site.\n */\nimport { DEFAULT_BROWSER } from \"../adapters/capture-runner.ts\";\nimport type { DatabaseAdapter, TxStore } from \"../adapters/database.ts\";\nimport type { StorageAdapter } from \"../adapters/storage.ts\";\nimport type { Baseline } from \"../schema/baseline.ts\";\nimport { withContentClaim } from \"../utils/screenshot-store.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\nimport { baselineIdentity } from \"./baseline-archive.ts\";\nimport { exportBaselineArchive, type BaselineExportOptions } from \"./baseline-export.ts\";\nimport { planBaselineImport, writePlannedImage, type PlannedBaseline } from \"./baseline-import.ts\";\nimport { BaselineModel, type BaselineTables } from \"./baseline.ts\";\n\n/** Outcome of {@link BaselineTransferModel.import}. */\nexport interface BaselineImportResult {\n /** Baselines in the archive (all applied). */\n imported: number;\n /** Baselines that did not exist before. */\n created: number;\n /** Existing baselines that were overwritten. */\n updated: number;\n}\n\n/** Export/import of baselines between StoryShelf instances (or for backup). */\nexport class BaselineTransferModel {\n private readonly tables: BaselineTables;\n private readonly baselines: BaselineModel;\n private readonly db: DatabaseAdapter;\n private readonly storage: StorageAdapter;\n\n constructor(db: DatabaseAdapter, storage: StorageAdapter, tables?: BaselineTables) {\n this.db = db;\n this.storage = storage;\n this.tables = tables ?? { baselines: db.tables.baselines };\n this.baselines = new BaselineModel(db, this.tables, storage);\n }\n\n /**\n * Stream the project's baselines (optionally one branch) as a zip archive.\n *\n * @throws {BaselineArchiveError} Before streaming, when over the archive entry limit.\n */\n async export(\n projectId: string,\n options: BaselineExportOptions = {},\n ): Promise<AsyncIterable<Buffer>> {\n return exportBaselineArchive(this.storage, await this.baselines.list(projectId), options);\n }\n\n /**\n * Upsert every baseline in `archive` into the project. The whole archive is\n * validated before anything is written; images are then stored (idempotent,\n * safe to retry) and all rows are applied in one transaction when the driver\n * supports it, so a failure leaves the rows untouched. Imports into the same\n * project run one at a time. Imported rows keep their original timestamps;\n * `snapshotId` is cleared because snapshots are not portable.\n *\n * @throws {BaselineArchiveError} On a malformed, unsafe, or inconsistent archive.\n */\n async import(projectId: string, archive: Buffer): Promise<BaselineImportResult> {\n const plan = await planBaselineImport(archive, projectId);\n // Images that already exist are reused, not written: claim the project's content so the\n // screenshot sweep cannot delete one before the rows pointing at it are committed.\n return await serialized(\n projectId,\n async () =>\n await withContentClaim(this.storage, projectId, async () => {\n for (const planned of plan) {\n // oxlint-disable-next-line eslint/no-await-in-loop -- sequential writes bound storage load\n await writePlannedImage(this.storage, planned);\n }\n const existing = await this.existingByIdentity(projectId);\n const created = await this.applyRows(projectId, plan, existing);\n return { imported: plan.length, created, updated: plan.length - created };\n }),\n );\n }\n\n private async existingByIdentity(projectId: string): Promise<Map<string, Baseline>> {\n const rows = await this.baselines.list(projectId);\n return new Map(\n rows.map((row) => [\n baselineIdentity({\n storyId: row.storyId,\n viewport: row.viewportName,\n browser: row.browser ?? DEFAULT_BROWSER,\n branch: row.branch,\n }),\n row,\n ]),\n );\n }\n\n /** Apply every row, in a transaction when available; returns how many were created. */\n private async applyRows(\n projectId: string,\n plan: PlannedBaseline[],\n existing: Map<string, Baseline>,\n ): Promise<number> {\n const run = async (store: TxStore): Promise<number> => {\n let created = 0;\n for (const planned of plan) {\n // oxlint-disable-next-line eslint/no-await-in-loop -- rows are applied in order within one transaction\n created += (await this.applyRow(store, projectId, planned, existing)) ? 1 : 0;\n }\n return created;\n };\n return this.db.transact ? await this.db.transact(run) : await run(this.db);\n }\n\n /** Write one planned row; resolves true when it was created. */\n private async applyRow(\n store: TxStore,\n projectId: string,\n planned: PlannedBaseline,\n existing: Map<string, Baseline>,\n ): Promise<boolean> {\n const { entry, storagePath } = planned;\n const fields = {\n snapshotId: null,\n screenshotPath: storagePath,\n infraHash: entry.infraHash,\n fingerprint: entry.fingerprint ?? null,\n mode: entry.mode,\n createdAt: entry.createdAt,\n updatedAt: entry.updatedAt,\n } satisfies Partial<Baseline>;\n const current = existing.get(baselineIdentity(entry));\n if (current) {\n await store.update(this.tables.baselines, current.id, fields);\n return false;\n }\n await store.insert(this.tables.baselines, {\n ...fields,\n id: ulid(),\n projectId,\n storyId: entry.storyId,\n viewportName: entry.viewport,\n branch: entry.branch,\n browser: entry.browser,\n });\n return true;\n }\n}\n\nconst importQueues = new Map<string, Promise<unknown>>();\n\n/** Run `task` after earlier work for the same key settles (in-process serialization). */\nasync function serialized<T>(key: string, task: () => Promise<T>): Promise<T> {\n const run = (importQueues.get(key) ?? Promise.resolve()).then(task, task);\n importQueues.set(key, run);\n try {\n return await run;\n } finally {\n if (importQueues.get(key) === run) {\n importQueues.delete(key);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA2BA,IAAa,wBAAb,MAAmC;CACjC;CACA;CACA;CACA;CAEA,YAAY,IAAqB,SAAyB,QAAyB;EACjF,KAAK,KAAK;EACV,KAAK,UAAU;EACf,KAAK,SAAS,UAAU,EAAE,WAAW,GAAG,OAAO,UAAU;EACzD,KAAK,YAAY,IAAI,cAAc,IAAI,KAAK,QAAQ,OAAO;CAC7D;;;;;;CAOA,MAAM,OACJ,WACA,UAAiC,CAAC,GACF;EAChC,OAAO,sBAAsB,KAAK,SAAS,MAAM,KAAK,UAAU,KAAK,SAAS,GAAG,OAAO;CAC1F;;;;;;;;;;;CAYA,MAAM,OAAO,WAAmB,SAAgD;EAC9E,MAAM,OAAO,MAAM,mBAAmB,SAAS,SAAS;EAGxD,OAAO,MAAM,WACX,WACA,YACE,MAAM,iBAAiB,KAAK,SAAS,WAAW,YAAY;GAC1D,KAAK,MAAM,WAAW,MAEpB,MAAM,kBAAkB,KAAK,SAAS,OAAO;GAE/C,MAAM,WAAW,MAAM,KAAK,mBAAmB,SAAS;GACxD,MAAM,UAAU,MAAM,KAAK,UAAU,WAAW,MAAM,QAAQ;GAC9D,OAAO;IAAE,UAAU,KAAK;IAAQ;IAAS,SAAS,KAAK,SAAS;GAAQ;EAC1E,CAAC,CACL;CACF;CAEA,MAAc,mBAAmB,WAAmD;EAClF,MAAM,OAAO,MAAM,KAAK,UAAU,KAAK,SAAS;EAChD,OAAO,IAAI,IACT,KAAK,KAAK,QAAQ,CAChB,iBAAiB;GACf,SAAS,IAAI;GACb,UAAU,IAAI;GACd,SAAS,IAAI,WAAA;GACb,QAAQ,IAAI;EACd,CAAC,GACD,GACF,CAAC,CACH;CACF;;CAGA,MAAc,UACZ,WACA,MACA,UACiB;EACjB,MAAM,MAAM,OAAO,UAAoC;GACrD,IAAI,UAAU;GACd,KAAK,MAAM,WAAW,MAEpB,WAAY,MAAM,KAAK,SAAS,OAAO,WAAW,SAAS,QAAQ,IAAK,IAAI;GAE9E,OAAO;EACT;EACA,OAAO,KAAK,GAAG,WAAW,MAAM,KAAK,GAAG,SAAS,GAAG,IAAI,MAAM,IAAI,KAAK,EAAE;CAC3E;;CAGA,MAAc,SACZ,OACA,WACA,SACA,UACkB;EAClB,MAAM,EAAE,OAAO,gBAAgB;EAC/B,MAAM,SAAS;GACb,YAAY;GACZ,gBAAgB;GAChB,WAAW,MAAM;GACjB,aAAa,MAAM,eAAe;GAClC,MAAM,MAAM;GACZ,WAAW,MAAM;GACjB,WAAW,MAAM;EACnB;EACA,MAAM,UAAU,SAAS,IAAI,iBAAiB,KAAK,CAAC;EACpD,IAAI,SAAS;GACX,MAAM,MAAM,OAAO,KAAK,OAAO,WAAW,QAAQ,IAAI,MAAM;GAC5D,OAAO;EACT;EACA,MAAM,MAAM,OAAO,KAAK,OAAO,WAAW;GACxC,GAAG;GACH,IAAI,KAAK;GACT;GACA,SAAS,MAAM;GACf,cAAc,MAAM;GACpB,QAAQ,MAAM;GACd,SAAS,MAAM;EACjB,CAAC;EACD,OAAO;CACT;AACF;AAEA,MAAM,+BAAe,IAAI,IAA8B;;AAGvD,eAAe,WAAc,KAAa,MAAoC;CAC5E,MAAM,OAAO,aAAa,IAAI,GAAG,KAAK,QAAQ,QAAQ,EAAA,CAAG,KAAK,MAAM,IAAI;CACxE,aAAa,IAAI,KAAK,GAAG;CACzB,IAAI;EACF,OAAO,MAAM;CACf,UAAU;EACR,IAAI,aAAa,IAAI,GAAG,MAAM,KAC5B,aAAa,OAAO,GAAG;CAE3B;AACF"}
|
|
1
|
+
{"version":3,"file":"baseline-transfer.mjs","names":[],"sources":["../../src/models/baseline-transfer.ts"],"sourcesContent":["/**\n * Baseline portability: export a project's baselines as a zip archive and\n * import (upsert) them from the same format. Format and limits live in\n * `baseline-archive.ts`; see the portability guide in the docs site.\n */\nimport { DEFAULT_BROWSER } from \"../adapters/capture-runner.ts\";\nimport type { DatabaseAdapter, TxStore } from \"../adapters/database.ts\";\nimport type { StorageAdapter } from \"../adapters/storage.ts\";\nimport type { Baseline } from \"../schema/baseline.ts\";\nimport { withContentClaim } from \"../utils/screenshot-store.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\nimport { baselineIdentity } from \"./baseline-archive.ts\";\nimport { BaselineWriteConflict } from \"./baseline-conflict.ts\";\nimport { exportBaselineArchive, type BaselineExportOptions } from \"./baseline-export.ts\";\nimport { planBaselineImport, writePlannedImage, type PlannedBaseline } from \"./baseline-import.ts\";\nimport { BaselineModel, type BaselineTables } from \"./baseline.ts\";\n\n/** Outcome of {@link BaselineTransferModel.import}. */\nexport interface BaselineImportResult {\n /** Baselines in the archive (all applied). */\n imported: number;\n /** Baselines that did not exist before. */\n created: number;\n /** Existing baselines that were overwritten. */\n updated: number;\n}\n\n/** Export/import of baselines between StoryShelf instances (or for backup). */\nexport class BaselineTransferModel {\n private readonly tables: BaselineTables;\n private readonly baselines: BaselineModel;\n private readonly db: DatabaseAdapter;\n private readonly storage: StorageAdapter;\n\n constructor(db: DatabaseAdapter, storage: StorageAdapter, tables?: BaselineTables) {\n this.db = db;\n this.storage = storage;\n this.tables = tables ?? { baselines: db.tables.baselines };\n this.baselines = new BaselineModel(db, this.tables, storage);\n }\n\n /**\n * Stream the project's baselines (optionally one branch) as a zip archive.\n *\n * @throws {BaselineArchiveError} Before streaming, when over the archive entry limit.\n */\n async export(\n projectId: string,\n options: BaselineExportOptions = {},\n ): Promise<AsyncIterable<Buffer>> {\n return exportBaselineArchive(this.storage, await this.baselines.list(projectId), options);\n }\n\n /**\n * Upsert every baseline in `archive` into the project. The whole archive is\n * validated before anything is written; images are then stored (idempotent,\n * safe to retry) and all rows are applied in one transaction when the driver\n * supports it, so a failure leaves the rows untouched. Imports into the same\n * project run one at a time. Imported rows keep their original timestamps;\n * `snapshotId` is cleared because snapshots are not portable.\n *\n * @throws {BaselineArchiveError} On a malformed, unsafe, or inconsistent archive.\n */\n async import(projectId: string, archive: Buffer): Promise<BaselineImportResult> {\n const plan = await planBaselineImport(archive, projectId);\n // Images that already exist are reused, not written: claim the project's content so the\n // screenshot sweep cannot delete one before the rows pointing at it are committed.\n return await serialized(\n projectId,\n async () =>\n await withContentClaim(this.storage, projectId, async () => {\n for (const planned of plan) {\n // oxlint-disable-next-line eslint/no-await-in-loop -- sequential writes bound storage load\n await writePlannedImage(this.storage, planned);\n }\n const existing = await this.existingByIdentity(projectId);\n const created = await this.applyRows(projectId, plan, existing);\n return { imported: plan.length, created, updated: plan.length - created };\n }),\n );\n }\n\n private async existingByIdentity(projectId: string): Promise<Map<string, Baseline>> {\n const rows = await this.baselines.list(projectId);\n return new Map(\n rows.map((row) => [\n baselineIdentity({\n storyId: row.storyId,\n viewport: row.viewportName,\n browser: row.browser ?? DEFAULT_BROWSER,\n branch: row.branch,\n }),\n row,\n ]),\n );\n }\n\n /** Apply every row, in a transaction when available; returns how many were created. */\n private async applyRows(\n projectId: string,\n plan: PlannedBaseline[],\n existing: Map<string, Baseline>,\n ): Promise<number> {\n const run = async (store: TxStore): Promise<number> => {\n let created = 0;\n for (const planned of plan) {\n // oxlint-disable-next-line eslint/no-await-in-loop -- rows are applied in order within one transaction\n created += (await this.applyRow(store, projectId, planned, existing)) ? 1 : 0;\n }\n return created;\n };\n const lifecycle = this.db.buildReferenceLifecycle;\n if (lifecycle) {\n const touched = plan\n .map((planned) => existing.get(baselineIdentity(planned.entry)))\n .filter((row): row is Baseline => row !== undefined);\n const changes = await Promise.all(\n touched.map(async (row) => {\n const owner = { type: \"baseline\" as const, id: row.id, projectId };\n return {\n owner,\n expectedGeneration: await lifecycle.referenceGeneration(owner),\n buildIds: [],\n };\n }),\n );\n const updated = await lifecycle.replaceManyFencedReferences(changes, async (store) => {\n await this.assertUnchangedIdentities(store, touched);\n return await run(store);\n });\n return updated.result;\n }\n return this.db.transact ? await this.db.transact(run) : await run(this.db);\n }\n\n private async assertUnchangedIdentities(store: TxStore, rows: Baseline[]): Promise<void> {\n const current = await Promise.all(\n rows.map(\n async (row) =>\n (await store.get(this.tables.baselines, row.id)) as unknown as Baseline | null,\n ),\n );\n for (const [index, row] of rows.entries()) {\n const found = current[index];\n if (\n !found ||\n found.projectId !== row.projectId ||\n found.storyId !== row.storyId ||\n found.viewportName !== row.viewportName ||\n found.branch !== row.branch ||\n found.updatedAt !== row.updatedAt ||\n found.snapshotId !== row.snapshotId ||\n found.sourceBuildId !== row.sourceBuildId ||\n found.screenshotPath !== row.screenshotPath ||\n (found.browser ?? DEFAULT_BROWSER) !== (row.browser ?? DEFAULT_BROWSER)\n ) {\n throw new BaselineWriteConflict(\"Baseline changed during import; retry\");\n }\n }\n }\n\n /** Write one planned row; resolves true when it was created. */\n private async applyRow(\n store: TxStore,\n projectId: string,\n planned: PlannedBaseline,\n existing: Map<string, Baseline>,\n ): Promise<boolean> {\n const { entry, storagePath } = planned;\n const fields = {\n snapshotId: null,\n sourceBuildId: null,\n screenshotPath: storagePath,\n infraHash: entry.infraHash,\n fingerprint: entry.fingerprint ?? null,\n mode: entry.mode,\n createdAt: entry.createdAt,\n updatedAt: entry.updatedAt,\n } satisfies Partial<Baseline>;\n const current = existing.get(baselineIdentity(entry));\n if (current) {\n await store.update(this.tables.baselines, current.id, fields);\n return false;\n }\n await store.insert(this.tables.baselines, {\n ...fields,\n id: ulid(),\n projectId,\n storyId: entry.storyId,\n viewportName: entry.viewport,\n branch: entry.branch,\n browser: entry.browser,\n });\n return true;\n }\n}\n\nconst importQueues = new Map<string, Promise<unknown>>();\n\n/** Run `task` after earlier work for the same key settles (in-process serialization). */\nasync function serialized<T>(key: string, task: () => Promise<T>): Promise<T> {\n const run = (importQueues.get(key) ?? Promise.resolve()).then(task, task);\n importQueues.set(key, run);\n try {\n return await run;\n } finally {\n if (importQueues.get(key) === run) {\n importQueues.delete(key);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA4BA,IAAa,wBAAb,MAAmC;CACjC;CACA;CACA;CACA;CAEA,YAAY,IAAqB,SAAyB,QAAyB;EACjF,KAAK,KAAK;EACV,KAAK,UAAU;EACf,KAAK,SAAS,UAAU,EAAE,WAAW,GAAG,OAAO,UAAU;EACzD,KAAK,YAAY,IAAI,cAAc,IAAI,KAAK,QAAQ,OAAO;CAC7D;;;;;;CAOA,MAAM,OACJ,WACA,UAAiC,CAAC,GACF;EAChC,OAAO,sBAAsB,KAAK,SAAS,MAAM,KAAK,UAAU,KAAK,SAAS,GAAG,OAAO;CAC1F;;;;;;;;;;;CAYA,MAAM,OAAO,WAAmB,SAAgD;EAC9E,MAAM,OAAO,MAAM,mBAAmB,SAAS,SAAS;EAGxD,OAAO,MAAM,WACX,WACA,YACE,MAAM,iBAAiB,KAAK,SAAS,WAAW,YAAY;GAC1D,KAAK,MAAM,WAAW,MAEpB,MAAM,kBAAkB,KAAK,SAAS,OAAO;GAE/C,MAAM,WAAW,MAAM,KAAK,mBAAmB,SAAS;GACxD,MAAM,UAAU,MAAM,KAAK,UAAU,WAAW,MAAM,QAAQ;GAC9D,OAAO;IAAE,UAAU,KAAK;IAAQ;IAAS,SAAS,KAAK,SAAS;GAAQ;EAC1E,CAAC,CACL;CACF;CAEA,MAAc,mBAAmB,WAAmD;EAClF,MAAM,OAAO,MAAM,KAAK,UAAU,KAAK,SAAS;EAChD,OAAO,IAAI,IACT,KAAK,KAAK,QAAQ,CAChB,iBAAiB;GACf,SAAS,IAAI;GACb,UAAU,IAAI;GACd,SAAS,IAAI,WAAA;GACb,QAAQ,IAAI;EACd,CAAC,GACD,GACF,CAAC,CACH;CACF;;CAGA,MAAc,UACZ,WACA,MACA,UACiB;EACjB,MAAM,MAAM,OAAO,UAAoC;GACrD,IAAI,UAAU;GACd,KAAK,MAAM,WAAW,MAEpB,WAAY,MAAM,KAAK,SAAS,OAAO,WAAW,SAAS,QAAQ,IAAK,IAAI;GAE9E,OAAO;EACT;EACA,MAAM,YAAY,KAAK,GAAG;EAC1B,IAAI,WAAW;GACb,MAAM,UAAU,KACb,KAAK,YAAY,SAAS,IAAI,iBAAiB,QAAQ,KAAK,CAAC,CAAC,CAAC,CAC/D,QAAQ,QAAyB,QAAQ,KAAA,CAAS;GACrD,MAAM,UAAU,MAAM,QAAQ,IAC5B,QAAQ,IAAI,OAAO,QAAQ;IACzB,MAAM,QAAQ;KAAE,MAAM;KAAqB,IAAI,IAAI;KAAI;IAAU;IACjE,OAAO;KACL;KACA,oBAAoB,MAAM,UAAU,oBAAoB,KAAK;KAC7D,UAAU,CAAC;IACb;GACF,CAAC,CACH;GAKA,QAAO,MAJe,UAAU,4BAA4B,SAAS,OAAO,UAAU;IACpF,MAAM,KAAK,0BAA0B,OAAO,OAAO;IACnD,OAAO,MAAM,IAAI,KAAK;GACxB,CAAC,EAAA,CACc;EACjB;EACA,OAAO,KAAK,GAAG,WAAW,MAAM,KAAK,GAAG,SAAS,GAAG,IAAI,MAAM,IAAI,KAAK,EAAE;CAC3E;CAEA,MAAc,0BAA0B,OAAgB,MAAiC;EACvF,MAAM,UAAU,MAAM,QAAQ,IAC5B,KAAK,IACH,OAAO,QACJ,MAAM,MAAM,IAAI,KAAK,OAAO,WAAW,IAAI,EAAE,CAClD,CACF;EACA,KAAK,MAAM,CAAC,OAAO,QAAQ,KAAK,QAAQ,GAAG;GACzC,MAAM,QAAQ,QAAQ;GACtB,IACE,CAAC,SACD,MAAM,cAAc,IAAI,aACxB,MAAM,YAAY,IAAI,WACtB,MAAM,iBAAiB,IAAI,gBAC3B,MAAM,WAAW,IAAI,UACrB,MAAM,cAAc,IAAI,aACxB,MAAM,eAAe,IAAI,cACzB,MAAM,kBAAkB,IAAI,iBAC5B,MAAM,mBAAmB,IAAI,mBAC5B,MAAM,WAAA,iBAAiC,IAAI,WAAA,aAE5C,MAAM,IAAI,sBAAsB,uCAAuC;EAE3E;CACF;;CAGA,MAAc,SACZ,OACA,WACA,SACA,UACkB;EAClB,MAAM,EAAE,OAAO,gBAAgB;EAC/B,MAAM,SAAS;GACb,YAAY;GACZ,eAAe;GACf,gBAAgB;GAChB,WAAW,MAAM;GACjB,aAAa,MAAM,eAAe;GAClC,MAAM,MAAM;GACZ,WAAW,MAAM;GACjB,WAAW,MAAM;EACnB;EACA,MAAM,UAAU,SAAS,IAAI,iBAAiB,KAAK,CAAC;EACpD,IAAI,SAAS;GACX,MAAM,MAAM,OAAO,KAAK,OAAO,WAAW,QAAQ,IAAI,MAAM;GAC5D,OAAO;EACT;EACA,MAAM,MAAM,OAAO,KAAK,OAAO,WAAW;GACxC,GAAG;GACH,IAAI,KAAK;GACT;GACA,SAAS,MAAM;GACf,cAAc,MAAM;GACpB,QAAQ,MAAM;GACd,SAAS,MAAM;EACjB,CAAC;EACD,OAAO;CACT;AACF;AAEA,MAAM,+BAAe,IAAI,IAA8B;;AAGvD,eAAe,WAAc,KAAa,MAAoC;CAC5E,MAAM,OAAO,aAAa,IAAI,GAAG,KAAK,QAAQ,QAAQ,EAAA,CAAG,KAAK,MAAM,IAAI;CACxE,aAAa,IAAI,KAAK,GAAG;CACzB,IAAI;EACF,OAAO,MAAM;CACf,UAAU;EACR,IAAI,aAAa,IAAI,GAAG,MAAM,KAC5B,aAAa,OAAO,GAAG;CAE3B;AACF"}
|
|
@@ -5,10 +5,11 @@ import { StorageAdapter } from "../adapter/storage.mjs";
|
|
|
5
5
|
import { SecretInput } from "../utils/encrypt.mjs";
|
|
6
6
|
import { WebhookTables } from "./webhook.mjs";
|
|
7
7
|
import { Baseline } from "../schema/baseline.mjs";
|
|
8
|
+
import { AtomicBaselineApproval } from "./baseline-approval.mjs";
|
|
8
9
|
import { Table } from "drizzle-orm";
|
|
9
|
-
//#region src/models/baseline.d.ts
|
|
10
10
|
/** Extra identity/metadata for {@link BaselineModel.upsert}. */
|
|
11
11
|
interface BaselineUpsertOptions {
|
|
12
|
+
approval?: AtomicBaselineApproval;
|
|
12
13
|
/** Engine the baseline belongs to (default chromium). */
|
|
13
14
|
browser?: string;
|
|
14
15
|
/** Resolved mode definition as JSON (display only). */
|
|
@@ -45,16 +46,18 @@ declare class BaselineModel {
|
|
|
45
46
|
private contentFor;
|
|
46
47
|
read(baseline: Baseline): Promise<Buffer>;
|
|
47
48
|
upsert(projectId: string, storyId: string, viewport: string, branch: string, snapshotId: string, sourcePath: string, infraHash?: string | null, options?: BaselineUpsertOptions): Promise<Baseline>;
|
|
49
|
+
private sourceBuildId;
|
|
48
50
|
list(projectId: string): Promise<Baseline[]>;
|
|
49
51
|
/**
|
|
50
52
|
* Delete a baseline's own file. A content-addressed screenshot is shared with snapshots and other
|
|
51
53
|
* baselines, so it is left for the retention sweep instead.
|
|
52
54
|
*/
|
|
53
55
|
private discardFile;
|
|
56
|
+
/** Drop the reference and row together when the adapter supports lifecycle protection. */
|
|
57
|
+
private removeRecord;
|
|
54
58
|
removeOrphans(projectId: string, validStoryIds: Set<string>): Promise<number>;
|
|
55
59
|
removeForBranch(projectId: string, branch: string): Promise<number>;
|
|
56
60
|
removeStaleBranches(projectId: string, staleBranches: ReadonlySet<string>): Promise<number>;
|
|
57
61
|
}
|
|
58
|
-
//#endregion
|
|
59
62
|
export { BaselineModel, BaselineTables, BaselineUpsertOptions };
|
|
60
63
|
//# sourceMappingURL=baseline.d.mts.map
|