@storyshelf/core 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -32
- package/dist/adapter/capture-queue.d.mts +44 -2
- package/dist/adapter/capture-runner.d.mts +127 -10
- package/dist/adapter/capture-runner.mjs +5 -12
- package/dist/adapter/database.d.mts +27 -8
- package/dist/adapter/database.mjs.map +1 -1
- package/dist/adapter/design.d.mts +85 -0
- package/dist/adapter/design.mjs +28 -0
- package/dist/adapter/design.mjs.map +1 -0
- package/dist/adapter/metadata.d.mts +3 -10
- package/dist/adapter/notifier.d.mts +6 -3
- package/dist/adapter/notifier.mjs +5 -1
- package/dist/adapter/oauth.d.mts +52 -0
- package/dist/adapter/setup.d.mts +4 -5
- package/dist/adapter/setup.mjs +2 -1
- package/dist/adapter/setup.mjs.map +1 -1
- package/dist/adapter/webhook-events.mjs +1 -1
- package/dist/adapters/capture-target-offers.d.mts +28 -0
- package/dist/adapters/capture-target-offers.mjs +58 -0
- package/dist/adapters/capture-target-offers.mjs.map +1 -0
- package/dist/adapters/capture-target.d.mts +71 -0
- package/dist/adapters/capture-target.mjs +76 -0
- package/dist/adapters/capture-target.mjs.map +1 -0
- package/dist/adapters/notifier/build-comment.d.mts +24 -0
- package/dist/adapters/notifier/build-comment.mjs +24 -0
- package/dist/adapters/notifier/build-comment.mjs.map +1 -0
- package/dist/adapters/notifier/build-state.d.mts +99 -0
- package/dist/adapters/notifier/build-state.mjs +218 -0
- package/dist/adapters/notifier/build-state.mjs.map +1 -0
- package/dist/adapters/notifier/events.d.mts +4 -2
- package/dist/adapters/notifier/events.mjs +31 -18
- package/dist/adapters/notifier/events.mjs.map +1 -1
- package/dist/adapters/notifier/provider.d.mts +53 -7
- package/dist/adapters/notifier/provider.mjs +12 -0
- package/dist/adapters/notifier/provider.mjs.map +1 -0
- package/dist/adapters/notifier/state.d.mts +24 -0
- package/dist/adapters/notifier/state.mjs +66 -0
- package/dist/adapters/notifier/state.mjs.map +1 -0
- package/dist/adapters/notifier/types.d.mts +51 -2
- package/dist/adapters/remote-browser.d.mts +87 -0
- package/dist/adapters/remote-browser.mjs +103 -0
- package/dist/adapters/remote-browser.mjs.map +1 -0
- package/dist/adapters/render-runs.d.mts +25 -0
- package/dist/adapters/render-runs.mjs +41 -0
- package/dist/adapters/render-runs.mjs.map +1 -0
- package/dist/adapters/setup-runner.mjs +2 -4
- package/dist/adapters/setup-runner.mjs.map +1 -1
- package/dist/adapters/sources.d.mts +12 -0
- package/dist/adapters/sources.mjs +20 -0
- package/dist/adapters/sources.mjs.map +1 -0
- package/dist/adapters/validate.mjs +25 -18
- package/dist/adapters/validate.mjs.map +1 -1
- package/dist/ai.d.mts +105 -0
- package/dist/ai.mjs +19 -0
- package/dist/ai.mjs.map +1 -0
- package/dist/capture/a11y/axe-source.d.mts +18 -0
- package/dist/capture/a11y/axe-source.mjs +37 -0
- package/dist/capture/a11y/axe-source.mjs.map +1 -0
- package/dist/capture/a11y/in-page.d.mts +27 -0
- package/dist/capture/a11y/in-page.mjs +60 -0
- package/dist/capture/a11y/in-page.mjs.map +1 -0
- package/dist/capture/a11y/map.d.mts +24 -0
- package/dist/capture/a11y/map.mjs +48 -0
- package/dist/capture/a11y/map.mjs.map +1 -0
- package/dist/capture/a11y/options.d.mts +23 -0
- package/dist/capture/a11y/options.mjs +75 -0
- package/dist/capture/a11y/options.mjs.map +1 -0
- package/dist/capture/adapter.d.mts +41 -3
- package/dist/capture/adapter.mjs.map +1 -1
- package/dist/capture/affected.d.mts +2 -0
- package/dist/capture/affected.mjs +13 -4
- package/dist/capture/affected.mjs.map +1 -1
- package/dist/capture/attempt-logger.mjs +84 -0
- package/dist/capture/attempt-logger.mjs.map +1 -0
- package/dist/capture/browsers.d.mts +35 -0
- package/dist/capture/browsers.mjs +67 -0
- package/dist/capture/browsers.mjs.map +1 -0
- package/dist/capture/build-state/deliver.d.mts +32 -0
- package/dist/capture/build-state/deliver.mjs +118 -0
- package/dist/capture/build-state/deliver.mjs.map +1 -0
- package/dist/capture/build-state/index.d.mts +8 -0
- package/dist/capture/build-state/notify-job.d.mts +56 -0
- package/dist/capture/build-state/notify-job.mjs +133 -0
- package/dist/capture/build-state/notify-job.mjs.map +1 -0
- package/dist/capture/build-state/publisher.d.mts +23 -0
- package/dist/capture/build-state/publisher.mjs +107 -0
- package/dist/capture/build-state/publisher.mjs.map +1 -0
- package/dist/capture/build-state/resume.d.mts +9 -0
- package/dist/capture/build-state/resume.mjs +47 -0
- package/dist/capture/build-state/resume.mjs.map +1 -0
- package/dist/capture/build-state/types.d.mts +49 -0
- package/dist/capture/catalog/catalogue.d.mts +22 -0
- package/dist/capture/catalog/catalogue.mjs +53 -0
- package/dist/capture/catalog/catalogue.mjs.map +1 -0
- package/dist/capture/catalog/components.d.mts +23 -0
- package/dist/capture/catalog/components.mjs +55 -0
- package/dist/capture/catalog/components.mjs.map +1 -0
- package/dist/capture/catalog/history.d.mts +30 -0
- package/dist/capture/catalog/history.mjs +51 -0
- package/dist/capture/catalog/history.mjs.map +1 -0
- package/dist/capture/catalog/hook.d.mts +14 -0
- package/dist/capture/catalog/hook.mjs +19 -0
- package/dist/capture/catalog/hook.mjs.map +1 -0
- package/dist/capture/catalog/index.d.mts +11 -0
- package/dist/capture/catalog/load.d.mts +26 -0
- package/dist/capture/catalog/load.mjs +49 -0
- package/dist/capture/catalog/load.mjs.map +1 -0
- package/dist/capture/catalog/parse.d.mts +15 -0
- package/dist/capture/catalog/parse.mjs +56 -0
- package/dist/capture/catalog/parse.mjs.map +1 -0
- package/dist/capture/catalog/read.d.mts +12 -0
- package/dist/capture/catalog/read.mjs +33 -0
- package/dist/capture/catalog/read.mjs.map +1 -0
- package/dist/capture/catalog/types.d.mts +33 -0
- package/dist/capture/consumer/capture-handler.d.mts +58 -0
- package/dist/capture/consumer/capture-handler.mjs +118 -0
- package/dist/capture/consumer/capture-handler.mjs.map +1 -0
- package/dist/capture/consumer/idle.d.mts +17 -0
- package/dist/capture/consumer/idle.mjs +25 -0
- package/dist/capture/consumer/idle.mjs.map +1 -0
- package/dist/capture/consumer/index.d.mts +13 -0
- package/dist/capture/consumer/index.mjs +139 -0
- package/dist/capture/consumer/index.mjs.map +1 -0
- package/dist/capture/consumer/loop.mjs +110 -0
- package/dist/capture/consumer/loop.mjs.map +1 -0
- package/dist/capture/consumer/metrics.d.mts +41 -0
- package/dist/capture/consumer/metrics.mjs +38 -0
- package/dist/capture/consumer/metrics.mjs.map +1 -0
- package/dist/capture/consumer/retry.d.mts +33 -0
- package/dist/capture/consumer/retry.mjs +34 -0
- package/dist/capture/consumer/retry.mjs.map +1 -0
- package/dist/capture/consumer/run-job.mjs +195 -0
- package/dist/capture/consumer/run-job.mjs.map +1 -0
- package/dist/capture/consumer/startup.mjs +38 -0
- package/dist/capture/consumer/startup.mjs.map +1 -0
- package/dist/capture/consumer/types.d.mts +97 -0
- package/dist/capture/crash-failure.d.mts +25 -0
- package/dist/capture/crash-failure.mjs +70 -0
- package/dist/capture/crash-failure.mjs.map +1 -0
- package/dist/capture/db-queue/cadence.d.mts +32 -0
- package/dist/capture/db-queue/cadence.mjs +38 -0
- package/dist/capture/db-queue/cadence.mjs.map +1 -0
- package/dist/capture/db-queue/claim.d.mts +9 -0
- package/dist/capture/db-queue/claim.mjs +132 -0
- package/dist/capture/db-queue/claim.mjs.map +1 -0
- package/dist/capture/db-queue/clock.mjs +12 -0
- package/dist/capture/db-queue/clock.mjs.map +1 -0
- package/dist/capture/db-queue/codec.mjs +76 -0
- package/dist/capture/db-queue/codec.mjs.map +1 -0
- package/dist/capture/db-queue/index.d.mts +20 -0
- package/dist/capture/db-queue/index.mjs +89 -0
- package/dist/capture/db-queue/index.mjs.map +1 -0
- package/dist/capture/db-queue/keeper.d.mts +36 -0
- package/dist/capture/db-queue/keeper.mjs +92 -0
- package/dist/capture/db-queue/keeper.mjs.map +1 -0
- package/dist/capture/db-queue/lease.mjs +46 -0
- package/dist/capture/db-queue/lease.mjs.map +1 -0
- package/dist/capture/db-queue/lifecycle.mjs +36 -0
- package/dist/capture/db-queue/lifecycle.mjs.map +1 -0
- package/dist/capture/db-queue/operations.mjs +94 -0
- package/dist/capture/db-queue/operations.mjs.map +1 -0
- package/dist/capture/db-queue/poll-loop.d.mts +30 -0
- package/dist/capture/db-queue/poll-loop.mjs +89 -0
- package/dist/capture/db-queue/poll-loop.mjs.map +1 -0
- package/dist/capture/db-queue/poll.d.mts +10 -0
- package/dist/capture/db-queue/poll.mjs +69 -0
- package/dist/capture/db-queue/poll.mjs.map +1 -0
- package/dist/capture/db-queue/timers.d.mts +12 -0
- package/dist/capture/db-queue/timers.mjs +37 -0
- package/dist/capture/db-queue/timers.mjs.map +1 -0
- package/dist/capture/db-queue/types.d.mts +83 -0
- package/dist/capture/db-queue/types.mjs +12 -0
- package/dist/capture/db-queue/types.mjs.map +1 -0
- package/dist/capture/db-queue/wake.mjs +48 -0
- package/dist/capture/db-queue/wake.mjs.map +1 -0
- package/dist/capture/design.mjs +39 -0
- package/dist/capture/design.mjs.map +1 -0
- package/dist/capture/diff-record.mjs +23 -3
- package/dist/capture/diff-record.mjs.map +1 -1
- package/dist/capture/dispatch.d.mts +12 -7
- package/dist/capture/dispatch.mjs +86 -107
- package/dist/capture/dispatch.mjs.map +1 -1
- package/dist/capture/enrich.mjs +60 -0
- package/dist/capture/enrich.mjs.map +1 -0
- package/dist/capture/failure-sets.mjs +22 -0
- package/dist/capture/failure-sets.mjs.map +1 -0
- package/dist/capture/fingerprint.d.mts +42 -0
- package/dist/capture/fingerprint.mjs +83 -0
- package/dist/capture/fingerprint.mjs.map +1 -0
- package/dist/capture/forked/channel.d.mts +25 -0
- package/dist/capture/forked/child.d.mts +34 -0
- package/dist/capture/forked/child.mjs +202 -0
- package/dist/capture/forked/child.mjs.map +1 -0
- package/dist/capture/forked/crash-tracker.mjs +23 -0
- package/dist/capture/forked/crash-tracker.mjs.map +1 -0
- package/dist/capture/forked/decision.d.mts +26 -0
- package/dist/capture/forked/decision.mjs +27 -0
- package/dist/capture/forked/decision.mjs.map +1 -0
- package/dist/capture/forked/exit.mjs +12 -0
- package/dist/capture/forked/exit.mjs.map +1 -0
- package/dist/capture/forked/fork.d.mts +31 -0
- package/dist/capture/forked/fork.mjs +93 -0
- package/dist/capture/forked/fork.mjs.map +1 -0
- package/dist/capture/forked/forked-capture.d.mts +40 -0
- package/dist/capture/forked/forked-capture.mjs +240 -0
- package/dist/capture/forked/forked-capture.mjs.map +1 -0
- package/dist/capture/forked/lease-book.mjs +46 -0
- package/dist/capture/forked/lease-book.mjs.map +1 -0
- package/dist/capture/forked/protocol.d.mts +38 -0
- package/dist/capture/forked/protocol.mjs +25 -0
- package/dist/capture/forked/protocol.mjs.map +1 -0
- package/dist/capture/forked/runs.mjs +75 -0
- package/dist/capture/forked/runs.mjs.map +1 -0
- package/dist/capture/isolate.mjs +141 -0
- package/dist/capture/isolate.mjs.map +1 -0
- package/dist/capture/job-lease.d.mts +28 -0
- package/dist/capture/job-lease.mjs +57 -0
- package/dist/capture/job-lease.mjs.map +1 -0
- package/dist/capture/matrix.mjs +298 -0
- package/dist/capture/matrix.mjs.map +1 -0
- package/dist/capture/modes.d.mts +25 -0
- package/dist/capture/modes.mjs +107 -0
- package/dist/capture/modes.mjs.map +1 -0
- package/dist/capture/orchestrator.d.mts +37 -5
- package/dist/capture/orchestrator.mjs +118 -107
- package/dist/capture/orchestrator.mjs.map +1 -1
- package/dist/capture/pipeline.d.mts +9 -2
- package/dist/capture/pipeline.mjs +250 -45
- package/dist/capture/pipeline.mjs.map +1 -1
- package/dist/capture/progress.d.mts +11 -0
- package/dist/capture/progress.mjs +28 -0
- package/dist/capture/progress.mjs.map +1 -0
- package/dist/capture/publish/accept.d.mts +39 -0
- package/dist/capture/publish/accept.mjs +28 -0
- package/dist/capture/publish/accept.mjs.map +1 -0
- package/dist/capture/publish/complete.d.mts +46 -0
- package/dist/capture/publish/complete.mjs +64 -0
- package/dist/capture/publish/complete.mjs.map +1 -0
- package/dist/capture/publish/extract.d.mts +20 -0
- package/dist/capture/publish/extract.mjs +119 -0
- package/dist/capture/publish/extract.mjs.map +1 -0
- package/dist/capture/publish/handler.d.mts +28 -0
- package/dist/capture/publish/handler.mjs +62 -0
- package/dist/capture/publish/handler.mjs.map +1 -0
- package/dist/capture/publish/index.d.mts +10 -0
- package/dist/capture/publish/limits.d.mts +37 -0
- package/dist/capture/publish/limits.mjs +39 -0
- package/dist/capture/publish/limits.mjs.map +1 -0
- package/dist/capture/publish/published.d.mts +15 -0
- package/dist/capture/publish/published.mjs +18 -0
- package/dist/capture/publish/published.mjs.map +1 -0
- package/dist/capture/publish/run.d.mts +33 -0
- package/dist/capture/publish/run.mjs +30 -0
- package/dist/capture/publish/run.mjs.map +1 -0
- package/dist/capture/rediff.d.mts +1 -1
- package/dist/capture/rediff.mjs +4 -3
- package/dist/capture/rediff.mjs.map +1 -1
- package/dist/capture/render.mjs +53 -0
- package/dist/capture/render.mjs.map +1 -0
- package/dist/capture/scratch.d.mts +44 -0
- package/dist/capture/scratch.mjs +138 -0
- package/dist/capture/scratch.mjs.map +1 -0
- package/dist/capture/shard-plan.mjs +128 -0
- package/dist/capture/shard-plan.mjs.map +1 -0
- package/dist/capture/shards/context.mjs +51 -0
- package/dist/capture/shards/context.mjs.map +1 -0
- package/dist/capture/shards/execute.mjs +174 -0
- package/dist/capture/shards/execute.mjs.map +1 -0
- package/dist/capture/shards/fan-out.mjs +126 -0
- package/dist/capture/shards/fan-out.mjs.map +1 -0
- package/dist/capture/shards/history.mjs +35 -0
- package/dist/capture/shards/history.mjs.map +1 -0
- package/dist/capture/shards/reduce.mjs +97 -0
- package/dist/capture/shards/reduce.mjs.map +1 -0
- package/dist/capture/sizing.mjs +1 -11
- package/dist/capture/sizing.mjs.map +1 -1
- package/dist/capture/skip-checks.mjs +2 -65
- package/dist/capture/skip-checks.mjs.map +1 -1
- package/dist/capture/statics.d.mts +7 -8
- package/dist/capture/statics.mjs +25 -71
- package/dist/capture/statics.mjs.map +1 -1
- package/dist/capture/storybook-urls.d.mts +40 -0
- package/dist/capture/storybook-urls.mjs +41 -0
- package/dist/capture/storybook-urls.mjs.map +1 -0
- package/dist/capture/storybook.d.mts +12 -4
- package/dist/capture/storybook.mjs +56 -16
- package/dist/capture/storybook.mjs.map +1 -1
- package/dist/capture/target.mjs +21 -0
- package/dist/capture/target.mjs.map +1 -0
- package/dist/capture/targets.d.mts +25 -0
- package/dist/capture/targets.mjs +32 -0
- package/dist/capture/targets.mjs.map +1 -0
- package/dist/capture/tests.d.mts +37 -0
- package/dist/capture/tests.mjs +126 -0
- package/dist/capture/tests.mjs.map +1 -0
- package/dist/capture/token-chunks.mjs +74 -0
- package/dist/capture/token-chunks.mjs.map +1 -0
- package/dist/capture.d.mts +60 -7
- package/dist/capture.mjs +48 -3
- package/dist/config.d.mts +121 -12
- package/dist/config.mjs +9 -6
- package/dist/config.mjs.map +1 -1
- package/dist/diff.d.mts +9 -3
- package/dist/diff.mjs +16 -3
- package/dist/diff.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/insights/budget.d.mts +20 -0
- package/dist/insights/budget.mjs +33 -0
- package/dist/insights/budget.mjs.map +1 -0
- package/dist/insights/envelope.d.mts +59 -0
- package/dist/insights/envelope.mjs +60 -0
- package/dist/insights/envelope.mjs.map +1 -0
- package/dist/insights/evidence-health.d.mts +32 -0
- package/dist/insights/evidence-health.mjs +28 -0
- package/dist/insights/evidence-health.mjs.map +1 -0
- package/dist/insights/evidence.d.mts +55 -0
- package/dist/insights/evidence.mjs +64 -0
- package/dist/insights/evidence.mjs.map +1 -0
- package/dist/insights/hash.d.mts +18 -0
- package/dist/insights/hash.mjs +21 -0
- package/dist/insights/hash.mjs.map +1 -0
- package/dist/insights/limits.d.mts +24 -0
- package/dist/insights/limits.mjs +24 -0
- package/dist/insights/limits.mjs.map +1 -0
- package/dist/insights/prompts/v1.d.mts +13 -0
- package/dist/insights/prompts/v1.mjs +34 -0
- package/dist/insights/prompts/v1.mjs.map +1 -0
- package/dist/insights/redact.d.mts +9 -0
- package/dist/insights/redact.mjs +24 -0
- package/dist/insights/redact.mjs.map +1 -0
- package/dist/insights/text.mjs +44 -0
- package/dist/insights/text.mjs.map +1 -0
- package/dist/insights.d.mts +11 -0
- package/dist/insights.mjs +12 -0
- package/dist/logger.mjs +17 -1
- package/dist/logger.mjs.map +1 -1
- package/dist/models/ai-budget-alert.d.mts +23 -0
- package/dist/models/ai-budget-alert.mjs +38 -0
- package/dist/models/ai-budget-alert.mjs.map +1 -0
- package/dist/models/ai-usage.d.mts +40 -0
- package/dist/models/ai-usage.mjs +61 -0
- package/dist/models/ai-usage.mjs.map +1 -0
- package/dist/models/baseline-archive.d.mts +84 -0
- package/dist/models/baseline-archive.mjs +106 -0
- package/dist/models/baseline-archive.mjs.map +1 -0
- package/dist/models/baseline-export.d.mts +19 -0
- package/dist/models/baseline-export.mjs +136 -0
- package/dist/models/baseline-export.mjs.map +1 -0
- package/dist/models/baseline-import.mjs +118 -0
- package/dist/models/baseline-import.mjs.map +1 -0
- package/dist/models/baseline-transfer.d.mts +49 -0
- package/dist/models/baseline-transfer.mjs +121 -0
- package/dist/models/baseline-transfer.mjs.map +1 -0
- package/dist/models/baseline.d.mts +32 -5
- package/dist/models/baseline.mjs +65 -20
- package/dist/models/baseline.mjs.map +1 -1
- package/dist/models/build-component.d.mts +28 -0
- package/dist/models/build-component.mjs +55 -0
- package/dist/models/build-component.mjs.map +1 -0
- package/dist/models/build-review-status.d.mts +29 -0
- package/dist/models/build-review-status.mjs +37 -0
- package/dist/models/build-review-status.mjs.map +1 -0
- package/dist/models/build-review.d.mts +28 -0
- package/dist/models/build-review.mjs +54 -0
- package/dist/models/build-review.mjs.map +1 -0
- package/dist/models/build.d.mts +25 -3
- package/dist/models/build.mjs +50 -11
- package/dist/models/build.mjs.map +1 -1
- package/dist/models/capture-attempt.d.mts +7 -1
- package/dist/models/capture-attempt.mjs +29 -4
- package/dist/models/capture-attempt.mjs.map +1 -1
- package/dist/models/capture-job.d.mts +106 -0
- package/dist/models/capture-job.mjs +288 -0
- package/dist/models/capture-job.mjs.map +1 -0
- package/dist/models/capture-log.d.mts +1 -1
- package/dist/models/capture-log.mjs +4 -3
- package/dist/models/capture-log.mjs.map +1 -1
- package/dist/models/capture-shard.d.mts +62 -0
- package/dist/models/capture-shard.mjs +190 -0
- package/dist/models/capture-shard.mjs.map +1 -0
- package/dist/models/changeset.d.mts +48 -0
- package/dist/models/changeset.mjs +81 -0
- package/dist/models/changeset.mjs.map +1 -0
- package/dist/models/columns.mjs +19 -0
- package/dist/models/columns.mjs.map +1 -0
- package/dist/models/comment.d.mts +4 -1
- package/dist/models/comment.mjs +7 -4
- package/dist/models/comment.mjs.map +1 -1
- package/dist/models/component.d.mts +43 -0
- package/dist/models/component.mjs +60 -0
- package/dist/models/component.mjs.map +1 -0
- package/dist/models/connections.d.mts +41 -0
- package/dist/models/connections.mjs +112 -0
- package/dist/models/connections.mjs.map +1 -0
- package/dist/models/content-ref.d.mts +1 -1
- package/dist/models/content-ref.mjs +1 -1
- package/dist/models/content-ref.mjs.map +1 -1
- package/dist/models/credentials.mjs +12 -2
- package/dist/models/credentials.mjs.map +1 -1
- package/dist/models/design-credentials.d.mts +41 -0
- package/dist/models/design-credentials.mjs +86 -0
- package/dist/models/design-credentials.mjs.map +1 -0
- package/dist/models/design-health.d.mts +16 -0
- package/dist/models/design-health.mjs +25 -0
- package/dist/models/design-health.mjs.map +1 -0
- package/dist/models/design-nodes.d.mts +83 -0
- package/dist/models/design-nodes.mjs +222 -0
- package/dist/models/design-nodes.mjs.map +1 -0
- package/dist/models/design-renders.mjs +74 -0
- package/dist/models/design-renders.mjs.map +1 -0
- package/dist/models/design-resolve.d.mts +29 -0
- package/dist/models/design-resolve.mjs +41 -0
- package/dist/models/design-resolve.mjs.map +1 -0
- package/dist/models/design.d.mts +39 -0
- package/dist/models/design.mjs +90 -0
- package/dist/models/design.mjs.map +1 -0
- package/dist/models/inherited-ratio.d.mts +21 -0
- package/dist/models/inherited-ratio.mjs +22 -0
- package/dist/models/inherited-ratio.mjs.map +1 -0
- package/dist/models/insight.d.mts +70 -0
- package/dist/models/insight.mjs +162 -0
- package/dist/models/insight.mjs.map +1 -0
- package/dist/models/label.d.mts +4 -2
- package/dist/models/label.mjs +25 -10
- package/dist/models/label.mjs.map +1 -1
- package/dist/models/member.d.mts +1 -1
- package/dist/models/member.mjs +5 -4
- package/dist/models/member.mjs.map +1 -1
- package/dist/models/notification-channel.d.mts +37 -3
- package/dist/models/notification-channel.mjs +88 -9
- package/dist/models/notification-channel.mjs.map +1 -1
- package/dist/models/notification-subscription.d.mts +1 -2
- package/dist/models/notification-subscription.mjs +7 -9
- package/dist/models/notification-subscription.mjs.map +1 -1
- package/dist/models/project-group-mapping.d.mts +6 -1
- package/dist/models/project-group-mapping.mjs +14 -4
- package/dist/models/project-group-mapping.mjs.map +1 -1
- package/dist/models/project.d.mts +9 -1
- package/dist/models/project.mjs +9 -4
- package/dist/models/project.mjs.map +1 -1
- package/dist/models/public-origin.d.mts +63 -0
- package/dist/models/public-origin.mjs +114 -0
- package/dist/models/public-origin.mjs.map +1 -0
- package/dist/models/review-switch-off.d.mts +14 -0
- package/dist/models/review-switch-off.mjs +26 -0
- package/dist/models/review-switch-off.mjs.map +1 -0
- package/dist/models/site-settings.d.mts +23 -0
- package/dist/models/site-settings.mjs +48 -0
- package/dist/models/site-settings.mjs.map +1 -0
- package/dist/models/snapshot.d.mts +36 -1
- package/dist/models/snapshot.mjs +50 -3
- package/dist/models/snapshot.mjs.map +1 -1
- package/dist/models/token.d.mts +13 -1
- package/dist/models/token.mjs +23 -5
- package/dist/models/token.mjs.map +1 -1
- package/dist/models/usage.d.mts +76 -0
- package/dist/models/usage.mjs +149 -0
- package/dist/models/usage.mjs.map +1 -0
- package/dist/models/user.d.mts +1 -1
- package/dist/models/user.mjs +4 -3
- package/dist/models/user.mjs.map +1 -1
- package/dist/models/webhook.d.mts +15 -1
- package/dist/models/webhook.mjs +33 -4
- package/dist/models/webhook.mjs.map +1 -1
- package/dist/models.d.mts +26 -3
- package/dist/models.mjs +27 -5
- package/dist/options.d.mts +18 -0
- package/dist/options.mjs +90 -0
- package/dist/options.mjs.map +1 -0
- package/dist/paths.d.mts +19 -4
- package/dist/paths.mjs +51 -10
- package/dist/paths.mjs.map +1 -1
- package/dist/retention/ai.d.mts +18 -0
- package/dist/retention/ai.mjs +23 -0
- package/dist/retention/ai.mjs.map +1 -0
- package/dist/retention/pending.mjs +47 -0
- package/dist/retention/pending.mjs.map +1 -0
- package/dist/retention/screenshot-sweep.d.mts +51 -0
- package/dist/retention/screenshot-sweep.mjs +128 -0
- package/dist/retention/screenshot-sweep.mjs.map +1 -0
- package/dist/retention.d.mts +16 -2
- package/dist/retention.mjs +71 -14
- package/dist/retention.mjs.map +1 -1
- package/dist/schema/baseline.d.mts +6 -0
- package/dist/schema/build-component.d.mts +25 -0
- package/dist/schema/build-review.d.mts +17 -0
- package/dist/schema/build.d.mts +7 -0
- package/dist/schema/capture-job.d.mts +60 -0
- package/dist/schema/capture-shard.d.mts +35 -0
- package/dist/schema/comment.d.mts +2 -0
- package/dist/schema/connection.d.mts +24 -0
- package/dist/schema/design.d.mts +58 -0
- package/dist/schema/insight.d.mts +54 -0
- package/dist/schema/notification.d.mts +4 -0
- package/dist/schema/project.d.mts +21 -0
- package/dist/schema/site-setting.d.mts +21 -0
- package/dist/schema/snapshot.d.mts +12 -0
- package/dist/schema/usage.d.mts +30 -0
- package/dist/schema.d.mts +11 -3
- package/dist/serverless.d.mts +21 -0
- package/dist/serverless.mjs +37 -0
- package/dist/serverless.mjs.map +1 -0
- package/dist/test-helpers/create-project.d.mts +1 -1
- package/dist/test-helpers/deferred.d.mts +39 -0
- package/dist/test-helpers/deferred.mjs +61 -0
- package/dist/test-helpers/deferred.mjs.map +1 -0
- package/dist/test-helpers/design-contract.d.mts +21 -0
- package/dist/test-helpers/design-contract.mjs +40 -0
- package/dist/test-helpers/design-contract.mjs.map +1 -0
- package/dist/test-helpers/fake-database.mjs +14 -2
- package/dist/test-helpers/fake-database.mjs.map +1 -1
- package/dist/test-helpers/fake-design.d.mts +43 -0
- package/dist/test-helpers/fake-design.mjs +114 -0
- package/dist/test-helpers/fake-design.mjs.map +1 -0
- package/dist/test-helpers/fake-notifier.d.mts +21 -0
- package/dist/test-helpers/fake-notifier.mjs +44 -0
- package/dist/test-helpers/fake-notifier.mjs.map +1 -0
- package/dist/test-helpers/fake-tables.mjs +255 -67
- package/dist/test-helpers/fake-tables.mjs.map +1 -1
- package/dist/test-helpers/manual-clock.d.mts +27 -0
- package/dist/test-helpers/manual-clock.mjs +56 -0
- package/dist/test-helpers/manual-clock.mjs.map +1 -0
- package/dist/test-helpers/notifier-contract.d.mts +7 -1
- package/dist/test-helpers/notifier-contract.mjs +32 -3
- package/dist/test-helpers/notifier-contract.mjs.map +1 -1
- package/dist/test-helpers/queue-contract.d.mts +16 -2
- package/dist/test-helpers/queue-contract.mjs +195 -1
- package/dist/test-helpers/queue-contract.mjs.map +1 -1
- package/dist/test-helpers/queue-multi-instance.d.mts +20 -0
- package/dist/test-helpers/queue-multi-instance.mjs +206 -0
- package/dist/test-helpers/queue-multi-instance.mjs.map +1 -0
- package/dist/test-helpers/runner-contract.mjs +11 -0
- package/dist/test-helpers/runner-contract.mjs.map +1 -1
- package/dist/test-helpers/sql-chunks.mjs +23 -0
- package/dist/test-helpers/sql-chunks.mjs.map +1 -1
- package/dist/test-helpers/storage-contract.mjs +1 -1
- package/dist/test-helpers.d.mts +9 -4
- package/dist/test-helpers.mjs +8 -3
- package/dist/types.d.mts +14 -3
- package/dist/types.mjs +21 -4
- package/dist/types.mjs.map +1 -1
- package/dist/urls.d.mts +4 -0
- package/dist/urls.mjs +11 -2
- package/dist/urls.mjs.map +1 -1
- package/dist/utils/adaptive-concurrency.d.mts +66 -0
- package/dist/utils/adaptive-concurrency.mjs +149 -0
- package/dist/utils/adaptive-concurrency.mjs.map +1 -0
- package/dist/utils/connect-retry.d.mts +26 -0
- package/dist/utils/connect-retry.mjs +43 -0
- package/dist/utils/connect-retry.mjs.map +1 -0
- package/dist/utils/environment.d.mts +19 -0
- package/dist/utils/environment.mjs +59 -0
- package/dist/utils/environment.mjs.map +1 -0
- package/dist/utils/http.d.mts +17 -1
- package/dist/utils/http.mjs +22 -3
- package/dist/utils/http.mjs.map +1 -1
- package/dist/utils/map-adaptive.d.mts +15 -0
- package/dist/utils/map-adaptive.mjs +72 -0
- package/dist/utils/map-adaptive.mjs.map +1 -0
- package/dist/utils/map-limit.d.mts +10 -0
- package/dist/utils/map-limit.mjs +32 -0
- package/dist/utils/map-limit.mjs.map +1 -0
- package/dist/utils/page-limiter.d.mts +37 -0
- package/dist/utils/page-limiter.mjs +56 -0
- package/dist/utils/page-limiter.mjs.map +1 -0
- package/dist/utils/public-origin.d.mts +20 -0
- package/dist/utils/public-origin.mjs +75 -0
- package/dist/utils/public-origin.mjs.map +1 -0
- package/dist/utils/redact.mjs +3 -0
- package/dist/utils/redact.mjs.map +1 -1
- package/dist/utils/remote-environment.d.mts +39 -0
- package/dist/utils/remote-environment.mjs +114 -0
- package/dist/utils/remote-environment.mjs.map +1 -0
- package/dist/utils/resources.d.mts +64 -0
- package/dist/utils/resources.mjs +122 -0
- package/dist/utils/resources.mjs.map +1 -0
- package/dist/utils/screenshot-store.d.mts +15 -0
- package/dist/utils/screenshot-store.mjs +41 -0
- package/dist/utils/screenshot-store.mjs.map +1 -0
- package/dist/utils/session-gate.d.mts +22 -0
- package/dist/utils/session-gate.mjs +53 -0
- package/dist/utils/session-gate.mjs.map +1 -0
- package/dist/utils/storybook-token.d.mts +81 -0
- package/dist/utils/storybook-token.mjs +134 -0
- package/dist/utils/storybook-token.mjs.map +1 -0
- package/dist/utils/storybook-url.d.mts +15 -0
- package/dist/utils/storybook-url.mjs +21 -0
- package/dist/utils/storybook-url.mjs.map +1 -0
- package/dist/utils/timing.mjs +1 -1
- package/dist/utils/timing.mjs.map +1 -1
- package/dist/utils/zip-read.mjs +129 -0
- package/dist/utils/zip-read.mjs.map +1 -0
- package/dist/utils/zip-write.d.mts +18 -0
- package/dist/utils/zip-write.mjs +188 -0
- package/dist/utils/zip-write.mjs.map +1 -0
- package/dist/utils.d.mts +17 -3
- package/dist/utils.mjs +18 -4
- package/package.json +32 -23
- package/dist/adapter/capture-runner.mjs.map +0 -1
- package/dist/adapter/git-host/comments.d.mts +0 -41
- package/dist/adapter/git-host/comments.mjs +0 -54
- package/dist/adapter/git-host/comments.mjs.map +0 -1
- package/dist/adapter/git-host/helpers.d.mts +0 -13
- package/dist/adapter/git-host/helpers.mjs +0 -30
- package/dist/adapter/git-host/helpers.mjs.map +0 -1
- package/dist/adapter/git-host.d.mts +0 -42
- package/dist/capture/queue.d.mts +0 -38
- package/dist/capture/queue.mjs +0 -98
- package/dist/capture/queue.mjs.map +0 -1
- package/dist/capture/recovery.d.mts +0 -21
- package/dist/capture/recovery.mjs +0 -83
- package/dist/capture/recovery.mjs.map +0 -1
- package/dist/capture/status-fanout.mjs +0 -72
- package/dist/capture/status-fanout.mjs.map +0 -1
- package/dist/diff/engine.d.mts +0 -16
- package/dist/diff/engine.mjs +0 -87
- package/dist/diff/engine.mjs.map +0 -1
- package/dist/diff/options.d.mts +0 -42
- package/dist/diff/options.mjs +0 -15
- package/dist/diff/options.mjs.map +0 -1
- package/dist/models/status-config.d.mts +0 -38
- package/dist/models/status-config.mjs +0 -63
- package/dist/models/status-config.mjs.map +0 -1
- package/dist/schema/status-config.d.mts +0 -16
- package/dist/test-helpers/git-contract.d.mts +0 -11
- package/dist/test-helpers/git-contract.mjs +0 -34
- package/dist/test-helpers/git-contract.mjs.map +0 -1
- /package/dist/adapter/{git-host.mjs → oauth.mjs} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.mjs","names":[],"sources":["../../src/adapters/validate.ts"],"sourcesContent":["/**\n * Boot-time adapter validation: fail fast on third-party adapters that\n * cannot satisfy their slot contract.\n *\n * Types alone cannot stop a bad adapter — this module checks shape at\n * runtime before any I/O runs. `createShelfApp` throws synchronously;\n * the lifecycle runner returns failures without executing hooks.\n */\nimport { z } from \"zod\";\nimport type { Auth } from \"../auth.ts\";\nimport { REQUIRED_TABLE_KEYS } from \"./database.ts\";\nimport type { AdapterSetupFailure, AdapterSetupSources } from \"./setup.ts\";\n\nconst metadataSchema = z.object({\n name: z.string().min(1),\n version: z.string().min(1),\n kind: z.string().min(1),\n category: z.string().min(1),\n});\n\nconst DATABASE_METHODS = [\"insert\", \"update\", \"get\", \"remove\", \"list\", \"count\", \"all\"];\n\nconst STORAGE_METHODS = [\"read\", \"write\", \"delete\", \"exists\", \"list\", \"writeStream\", \"readStream\"];\n\nconst RUNNER_METHODS = [\"render\", \"cancel\"];\n\nconst QUEUE_METHODS = [\"enqueue\", \"status\", \"active\", \"recent\"];\n\n/** Unknown value narrowed to a property bag for shape checks. */\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : null;\n}\n\n/** String field of a record, or null when absent/non-string. */\nfunction stringField(record: Record<string, unknown> | null, key: string): string | null {\n const value = record?.[key];\n return typeof value === \"string\" ? value : null;\n}\n\n/** Reasons the adapter identity fails for the expected slot. */\nfunction metadataReasons(adapter: Record<string, unknown>, expected: string): string[] {\n const parsed = metadataSchema.safeParse(adapter[\"metadata\"]);\n if (!parsed.success) {\n return [`invalid metadata: ${parsed.error.issues.map((i) => i.path.join(\".\")).join(\",\")}`];\n }\n const category = (parsed.data as { category: string }).category;\n return category === expected ? [] : [`category \"${category}\" does not match slot \"${expected}\"`];\n}\n\n/** Reasons the optional lifecycle violates the all-or-nothing rule. */\nfunction lifecycleReasons(adapter: Record<string, unknown>): string[] {\n const lifecycle = adapter[\"lifecycle\"];\n if (lifecycle === undefined) {\n return [];\n }\n const hooks = asRecord(lifecycle);\n if (!hooks) {\n return [\"lifecycle must be an object with setup/teardown/health\"];\n }\n const missing = [\"setup\", \"teardown\", \"health\"].filter(\n (hook) => typeof hooks[hook] !== \"function\",\n );\n return missing.length > 0 ? [`partial lifecycle (missing: ${missing.join(\",\")})`] : [];\n}\n\n/** Reasons the adapter lacks required slot methods. */\nfunction methodReasons(adapter: Record<string, unknown>, methods: string[]): string[] {\n const missing = methods.filter((method) => typeof adapter[method] !== \"function\");\n return missing.length > 0 ? [`missing methods: ${missing.join(\",\")}`] : [];\n}\n\n/** Reasons a database adapter lacks its table map. */\nfunction tableReasons(adapter: Record<string, unknown>): string[] {\n const tables = asRecord(adapter[\"tables\"]);\n if (!tables) {\n return [\"missing tables map\"];\n }\n const missing = REQUIRED_TABLE_KEYS.filter((table) => tables[table] === undefined);\n return missing.length > 0 ? [`missing tables: ${missing.join(\",\")}`] : [];\n}\n\n/** Reasons a queue adapter has a partial poll extension. */\nfunction queuePollReasons(record: Record<string, unknown>): string[] {\n const present = [\"poll\", \"ack\", \"nack\"].filter((method) => record[method] !== undefined);\n if (present.length === 0 || present.length === 3) {\n const mistyped = [\"poll\", \"ack\", \"nack\"].filter(\n (method) => record[method] !== undefined && typeof record[method] !== \"function\",\n );\n return mistyped.map((method) => `queue poll extension \"${method}\" must be a function`);\n }\n return [`partial poll extension (present: ${present.join(\",\")}; need poll+ack+nack)`];\n}\n\n/** Whether a metadata schema looks like a zod schema (has parse). */\nfunction hasSchemaParse(provider: unknown): boolean {\n const schema = asRecord(asRecord(provider)?.[\"metadata\"])?.[\"schema\"];\n return typeof (schema as { parse?: unknown } | undefined)?.parse === \"function\";\n}\n\n/** Reasons a notifier provider lacks its descriptor shape. */\nfunction notifierReasons(provider: unknown): string[] {\n const record = asRecord(provider);\n if (!record) {\n return [\"notifier provider must be an object\"];\n }\n const reasons = metadataReasons(record, \"notifier\");\n if (typeof record[\"create\"] !== \"function\") {\n reasons.push(\"missing methods: create\");\n }\n if (!hasSchemaParse(provider)) {\n reasons.push(\"metadata.schema must be a zod schema\");\n }\n return reasons;\n}\n\n/** Reasons an email sender lacks its transport shape. */\nfunction emailSenderReasons(sender: unknown): string[] {\n const record = asRecord(sender);\n if (!record) {\n return [\"email sender must be an object\"];\n }\n const reasons = metadataReasons(record, \"notifier\");\n if (typeof record[\"send\"] !== \"function\") {\n reasons.push(\"missing methods: send\");\n }\n return reasons;\n}\n\n/** Reasons a git provider lacks its descriptor shape. */\nfunction gitReasons(provider: unknown): string[] {\n const record = asRecord(provider);\n if (!record) {\n return [\"git provider must be an object\"];\n }\n const reasons = metadataReasons(record, \"git-host\");\n if (typeof record[\"create\"] !== \"function\") {\n reasons.push(\"missing methods: create\");\n }\n if (!hasSchemaParse(provider)) {\n reasons.push(\"metadata.schema must be a zod schema\");\n }\n return reasons;\n}\n\n/** Required methods for a slot category. */\nfunction slotMethods(category: string): string[] {\n if (category === \"database\") {\n return DATABASE_METHODS;\n }\n if (category === \"storage\") {\n return STORAGE_METHODS;\n }\n if (category === \"capture-runner\") {\n return RUNNER_METHODS;\n }\n return QUEUE_METHODS;\n}\n\n/** Extra per-slot reasons (table map for databases, poll rule for queues). */\nfunction slotExtraReasons(record: Record<string, unknown>, category: string): string[] {\n if (category === \"database\") {\n return tableReasons(record);\n }\n return category === \"capture-queue\" ? queuePollReasons(record) : [];\n}\n\n/**\n * Validate one adapter against its slot. Returns human-readable reasons\n * (empty when valid). Never throws — callers decide fail-fast vs collect.\n */\nexport function validateAdapter(\n adapter: unknown,\n expectedCategory: string,\n slot: string,\n): string[] {\n const record = asRecord(adapter);\n if (!record) {\n return [`${slot} adapter must be an object`];\n }\n const reasons = metadataReasons(record, expectedCategory).map((r) => `${slot}: ${r}`);\n const extra = [\n ...lifecycleReasons(record),\n ...methodReasons(record, slotMethods(expectedCategory)),\n ...slotExtraReasons(record, expectedCategory),\n ];\n for (const reason of extra) {\n reasons.push(`${slot}: ${reason}`);\n }\n return reasons;\n}\n\n/** Auth surface methods every engine must expose. */\nconst AUTH_METHODS = [\n \"handler\",\n \"loginMethods\",\n \"setup\",\n \"issueInvite\",\n \"verifyInvite\",\n \"acceptInvite\",\n \"passkeysEnabled\",\n \"listSessions\",\n \"listPasskeys\",\n \"hasPassword\",\n \"setDisabled\",\n \"check\",\n \"createSession\",\n \"destroySession\",\n];\n\n/** Reasons a method-id list is unusable (blank or duplicate ids). */\nfunction methodIdReasons(ids: string[]): string[] {\n const reasons: string[] = [];\n if (ids.some((id) => id.length === 0)) {\n reasons.push(\"login method with blank id\");\n }\n if (new Set(ids).size !== ids.length) {\n reasons.push(\"duplicate login method ids\");\n }\n return reasons;\n}\n\n/** Reasons login method descriptors are unusable (duplicate/blank ids). */\nfunction loginMethodReasons(auth: Auth): string[] {\n let ids: string[];\n try {\n ids = auth.loginMethods().map((method) => method.id);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return [`loginMethods() threw: ${message}`];\n }\n return methodIdReasons(ids);\n}\n\n/**\n * Validate the auth engine shape (auth is optional — undefined is valid).\n * Returns human-readable reasons, empty when sound.\n */\nexport function validateAuth(auth?: unknown): string[] {\n if (auth === undefined) {\n return [];\n }\n const record = asRecord(auth);\n if (!record) {\n return [\"auth must be an object\"];\n }\n const reasons = methodReasons(record, AUTH_METHODS).map((reason) => `auth: ${reason}`);\n if (reasons.length === 0) {\n for (const reason of loginMethodReasons(auth as Auth)) {\n reasons.push(`auth: ${reason}`);\n }\n }\n return reasons;\n}\n\n/** Failure entry for an invalid auth engine. */\nfunction checkAuth(auth: unknown): AdapterSetupFailure[] {\n const reasons = validateAuth(auth);\n if (reasons.length === 0) {\n return [];\n }\n return [{ category: \"auth\", kind: \"auth\", name: \"auth\", error: reasons.join(\"; \") }];\n}\n\n/** One slot check for source validation. */\ninterface SlotCheck {\n adapter: unknown;\n category: string;\n slot: string;\n}\n\n/** Descriptor check for provider lists (git hosts, notifiers). */\ninterface ProviderCheck {\n provider: unknown;\n index: number;\n kinds: \"git\" | \"notifier\";\n}\n\n/** Failures for git-host or notifier provider lists. */\nfunction checkProviders(checks: ProviderCheck[]): AdapterSetupFailure[] {\n const failures: AdapterSetupFailure[] = [];\n for (const check of checks) {\n const reasons =\n check.kinds === \"git\" ? gitReasons(check.provider) : notifierReasons(check.provider);\n if (reasons.length === 0) {\n continue;\n }\n const slot = check.kinds === \"git\" ? `gitHosts[${check.index}]` : `notifiers[${check.index}]`;\n const category = check.kinds === \"git\" ? \"git-host\" : \"notifier\";\n const metadata = asRecord(asRecord(check.provider)?.[\"metadata\"]);\n failures.push({\n category,\n kind: stringField(metadata, \"kind\") ?? \"unknown\",\n name: stringField(metadata, \"name\") ?? slot,\n error: reasons.map((reason) => `${slot}: ${reason}`).join(\"; \"),\n });\n }\n return failures;\n}\n\n/** Failure for the email sender slot. */\nfunction checkEmailSender(sender: unknown): AdapterSetupFailure[] {\n if (sender === undefined) {\n return [];\n }\n const reasons = emailSenderReasons(sender);\n if (reasons.length === 0) {\n return [];\n }\n const metadata = asRecord(asRecord(sender)?.[\"metadata\"]);\n return [\n {\n category: \"notifier\",\n kind: stringField(metadata, \"kind\") ?? \"unknown\",\n name: stringField(metadata, \"name\") ?? \"emailSender\",\n error: reasons.map((reason) => `emailSender: ${reason}`).join(\"; \"),\n },\n ];\n}\n\n/** Failures for the core database/storage/runner/queue slots. */\nfunction checkSlots(checks: SlotCheck[]): AdapterSetupFailure[] {\n const failures: AdapterSetupFailure[] = [];\n for (const check of checks) {\n const reasons = validateAdapter(check.adapter, check.category, check.slot);\n if (reasons.length === 0) {\n continue;\n }\n const metadata = asRecord(asRecord(check.adapter)?.[\"metadata\"]);\n failures.push({\n category: check.category,\n kind: stringField(metadata, \"kind\") ?? \"unknown\",\n name: stringField(metadata, \"name\") ?? check.slot,\n error: reasons.join(\"; \"),\n });\n }\n return failures;\n}\n\n/**\n * Validate every adapter in the boot sources. Returns per-adapter failures\n * (empty when the whole assembly is sound).\n */\nexport function validateAdapterSources(sources: AdapterSetupSources): AdapterSetupFailure[] {\n const checks: SlotCheck[] = [\n { adapter: sources.database, category: \"database\", slot: \"database\" },\n { adapter: sources.storage, category: \"storage\", slot: \"storage\" },\n ];\n if (sources.captureRunner !== undefined) {\n checks.push({\n adapter: sources.captureRunner,\n category: \"capture-runner\",\n slot: \"captureRunner\",\n });\n }\n if (sources.captureQueue !== undefined) {\n checks.push({ adapter: sources.captureQueue, category: \"capture-queue\", slot: \"captureQueue\" });\n }\n const providers: ProviderCheck[] = [\n ...(sources.gitHosts ?? []).map((provider, index) => ({\n provider,\n index,\n kinds: \"git\" as const,\n })),\n ...(sources.notifiers ?? []).map((provider, index) => ({\n provider,\n index,\n kinds: \"notifier\" as const,\n })),\n ];\n return [\n ...checkSlots(checks),\n ...checkProviders(providers),\n ...checkEmailSender(sources.emailSender),\n ];\n}\n\n/**\n * Validate a full boot assembly: adapters plus the optional auth engine.\n * App assembly calls this — `ShelfOptions` carries `auth` alongside the\n * adapter slots, and an invalid engine fails boot like any adapter.\n */\nexport function validateBootAssembly(\n sources: AdapterSetupSources & { auth?: unknown },\n): AdapterSetupFailure[] {\n return [...validateAdapterSources(sources), ...checkAuth(sources.auth)];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validate.mjs","names":[],"sources":["../../src/adapters/validate.ts"],"sourcesContent":["/**\n * Boot-time adapter validation: fail fast on third-party adapters that\n * cannot satisfy their slot contract.\n *\n * Types alone cannot stop a bad adapter — this module checks shape at\n * runtime before any I/O runs. `createShelfApp` throws synchronously;\n * the lifecycle runner returns failures without executing hooks.\n */\nimport { z } from \"zod\";\nimport type { Auth } from \"../auth.ts\";\nimport { REQUIRED_TABLE_KEYS } from \"./database.ts\";\nimport type { AdapterSetupFailure, AdapterSetupSources } from \"./setup.ts\";\n\nconst metadataSchema = z.object({\n name: z.string().min(1),\n version: z.string().min(1),\n kind: z.string().min(1),\n category: z.string().min(1),\n});\n\nconst DATABASE_METHODS = [\"insert\", \"update\", \"get\", \"remove\", \"list\", \"count\", \"all\"];\n\nconst STORAGE_METHODS = [\"read\", \"write\", \"delete\", \"exists\", \"list\", \"writeStream\", \"readStream\"];\n\nconst RUNNER_METHODS = [\"render\", \"cancel\"];\n\nconst QUEUE_METHODS = [\"enqueue\", \"status\", \"active\", \"recent\"];\n\n/** Unknown value narrowed to a property bag for shape checks. */\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : null;\n}\n\n/** String field of a record, or null when absent/non-string. */\nfunction stringField(record: Record<string, unknown> | null, key: string): string | null {\n const value = record?.[key];\n return typeof value === \"string\" ? value : null;\n}\n\n/** Reasons the adapter identity fails for the expected slot. */\nfunction metadataReasons(adapter: Record<string, unknown>, expected: string): string[] {\n const parsed = metadataSchema.safeParse(adapter[\"metadata\"]);\n if (!parsed.success) {\n return [`invalid metadata: ${parsed.error.issues.map((i) => i.path.join(\".\")).join(\",\")}`];\n }\n const category = (parsed.data as { category: string }).category;\n return category === expected ? [] : [`category \"${category}\" does not match slot \"${expected}\"`];\n}\n\n/** Reasons the optional lifecycle violates the all-or-nothing rule. */\nfunction lifecycleReasons(adapter: Record<string, unknown>): string[] {\n const lifecycle = adapter[\"lifecycle\"];\n if (lifecycle === undefined) {\n return [];\n }\n const hooks = asRecord(lifecycle);\n if (!hooks) {\n return [\"lifecycle must be an object with setup/teardown/health\"];\n }\n const missing = [\"setup\", \"teardown\", \"health\"].filter(\n (hook) => typeof hooks[hook] !== \"function\",\n );\n return missing.length > 0 ? [`partial lifecycle (missing: ${missing.join(\",\")})`] : [];\n}\n\n/** Reasons the adapter lacks required slot methods. */\nfunction methodReasons(adapter: Record<string, unknown>, methods: string[]): string[] {\n const missing = methods.filter((method) => typeof adapter[method] !== \"function\");\n return missing.length > 0 ? [`missing methods: ${missing.join(\",\")}`] : [];\n}\n\n/** Reasons a database adapter lacks its table map. */\nfunction tableReasons(adapter: Record<string, unknown>): string[] {\n const tables = asRecord(adapter[\"tables\"]);\n if (!tables) {\n return [\"missing tables map\"];\n }\n const missing = REQUIRED_TABLE_KEYS.filter((table) => tables[table] === undefined);\n return missing.length > 0 ? [`missing tables: ${missing.join(\",\")}`] : [];\n}\n\n/** Reasons a queue adapter has a partial poll extension. */\nfunction queuePollReasons(record: Record<string, unknown>): string[] {\n const present = [\"poll\", \"ack\", \"nack\"].filter((method) => record[method] !== undefined);\n if (present.length === 0 || present.length === 3) {\n const mistyped = [\"poll\", \"ack\", \"nack\"].filter(\n (method) => record[method] !== undefined && typeof record[method] !== \"function\",\n );\n return mistyped.map((method) => `queue poll extension \"${method}\" must be a function`);\n }\n return [`partial poll extension (present: ${present.join(\",\")}; need poll+ack+nack)`];\n}\n\n/** Whether a metadata schema looks like a zod schema (has parse). */\nfunction hasSchemaParse(provider: unknown): boolean {\n const schema = asRecord(asRecord(provider)?.[\"metadata\"])?.[\"schema\"];\n return typeof (schema as { parse?: unknown } | undefined)?.parse === \"function\";\n}\n\n/** Reasons a notifier provider lacks its descriptor shape. */\nfunction notifierReasons(provider: unknown): string[] {\n const record = asRecord(provider);\n if (!record) {\n return [\"notifier provider must be an object\"];\n }\n const reasons = metadataReasons(record, \"notifier\");\n if (typeof record[\"create\"] !== \"function\") {\n reasons.push(\"missing methods: create\");\n }\n if (!hasSchemaParse(provider)) {\n reasons.push(\"metadata.schema must be a zod schema\");\n }\n return reasons;\n}\n\n/** Reasons an email sender lacks its transport shape. */\nfunction emailSenderReasons(sender: unknown): string[] {\n const record = asRecord(sender);\n if (!record) {\n return [\"email sender must be an object\"];\n }\n const reasons = metadataReasons(record, \"notifier\");\n if (typeof record[\"send\"] !== \"function\") {\n reasons.push(\"missing methods: send\");\n }\n return reasons;\n}\n\n/** Reasons a design provider lacks its descriptor shape. */\nfunction designReasons(provider: unknown): string[] {\n const record = asRecord(provider);\n if (!record) {\n return [\"design provider must be an object\"];\n }\n const reasons = metadataReasons(record, \"design\");\n const missing = [\"parseUrl\", \"create\"].filter((name) => typeof record[name] !== \"function\");\n if (missing.length > 0) {\n reasons.push(`missing methods: ${missing.join(\", \")}`);\n }\n return reasons;\n}\n\n/** Required methods for a slot category. */\nfunction slotMethods(category: string): string[] {\n if (category === \"database\") {\n return DATABASE_METHODS;\n }\n if (category === \"storage\") {\n return STORAGE_METHODS;\n }\n if (category === \"capture-runner\") {\n return RUNNER_METHODS;\n }\n return QUEUE_METHODS;\n}\n\n/** Extra per-slot reasons (table map for databases, poll rule for queues). */\nfunction slotExtraReasons(record: Record<string, unknown>, category: string): string[] {\n if (category === \"database\") {\n return tableReasons(record);\n }\n return category === \"capture-queue\" ? queuePollReasons(record) : [];\n}\n\n/**\n * Validate one adapter against its slot. Returns human-readable reasons\n * (empty when valid). Never throws — callers decide fail-fast vs collect.\n */\nexport function validateAdapter(\n adapter: unknown,\n expectedCategory: string,\n slot: string,\n): string[] {\n const record = asRecord(adapter);\n if (!record) {\n return [`${slot} adapter must be an object`];\n }\n const reasons = metadataReasons(record, expectedCategory).map((r) => `${slot}: ${r}`);\n const extra = [\n ...lifecycleReasons(record),\n ...methodReasons(record, slotMethods(expectedCategory)),\n ...slotExtraReasons(record, expectedCategory),\n ];\n for (const reason of extra) {\n reasons.push(`${slot}: ${reason}`);\n }\n return reasons;\n}\n\n/** Auth surface methods every engine must expose. */\nconst AUTH_METHODS = [\n \"handler\",\n \"loginMethods\",\n \"setup\",\n \"issueInvite\",\n \"verifyInvite\",\n \"acceptInvite\",\n \"passkeysEnabled\",\n \"listSessions\",\n \"listPasskeys\",\n \"hasPassword\",\n \"setDisabled\",\n \"check\",\n \"createSession\",\n \"destroySession\",\n];\n\n/** Reasons a method-id list is unusable (blank or duplicate ids). */\nfunction methodIdReasons(ids: string[]): string[] {\n const reasons: string[] = [];\n if (ids.some((id) => id.length === 0)) {\n reasons.push(\"login method with blank id\");\n }\n if (new Set(ids).size !== ids.length) {\n reasons.push(\"duplicate login method ids\");\n }\n return reasons;\n}\n\n/** Reasons login method descriptors are unusable (duplicate/blank ids). */\nfunction loginMethodReasons(auth: Auth): string[] {\n let ids: string[];\n try {\n ids = auth.loginMethods().map((method) => method.id);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return [`loginMethods() threw: ${message}`];\n }\n return methodIdReasons(ids);\n}\n\n/**\n * Validate the auth engine shape (auth is optional — undefined is valid).\n * Returns human-readable reasons, empty when sound.\n */\nexport function validateAuth(auth?: unknown): string[] {\n if (auth === undefined) {\n return [];\n }\n const record = asRecord(auth);\n if (!record) {\n return [\"auth must be an object\"];\n }\n const reasons = methodReasons(record, AUTH_METHODS).map((reason) => `auth: ${reason}`);\n if (reasons.length === 0) {\n for (const reason of loginMethodReasons(auth as Auth)) {\n reasons.push(`auth: ${reason}`);\n }\n }\n return reasons;\n}\n\n/** Failure entry for an invalid auth engine. */\nfunction checkAuth(auth: unknown): AdapterSetupFailure[] {\n const reasons = validateAuth(auth);\n if (reasons.length === 0) {\n return [];\n }\n return [{ category: \"auth\", kind: \"auth\", name: \"auth\", error: reasons.join(\"; \") }];\n}\n\n/** One slot check for source validation. */\ninterface SlotCheck {\n adapter: unknown;\n category: string;\n slot: string;\n}\n\n/** Descriptor check for provider lists (design providers, notifiers). */\ninterface ProviderCheck {\n provider: unknown;\n index: number;\n kinds: \"design\" | \"notifier\";\n}\n\nconst PROVIDER_KINDS = {\n design: { reasons: designReasons, list: \"design\", category: \"design\" },\n notifier: { reasons: notifierReasons, list: \"notifiers\", category: \"notifier\" },\n} as const;\n\n/** Failures for design or notifier provider lists. */\nfunction checkProviders(checks: ProviderCheck[]): AdapterSetupFailure[] {\n const failures: AdapterSetupFailure[] = [];\n for (const check of checks) {\n const kind = PROVIDER_KINDS[check.kinds];\n const reasons = kind.reasons(check.provider);\n if (reasons.length === 0) {\n continue;\n }\n const slot = `${kind.list}[${check.index}]`;\n const metadata = asRecord(asRecord(check.provider)?.[\"metadata\"]);\n failures.push({\n category: kind.category,\n kind: stringField(metadata, \"kind\") ?? \"unknown\",\n name: stringField(metadata, \"name\") ?? slot,\n error: reasons.map((reason) => `${slot}: ${reason}`).join(\"; \"),\n });\n }\n return failures;\n}\n\n/** Failure for the email sender slot. */\nfunction checkEmailSender(sender: unknown): AdapterSetupFailure[] {\n if (sender === undefined) {\n return [];\n }\n const reasons = emailSenderReasons(sender);\n if (reasons.length === 0) {\n return [];\n }\n const metadata = asRecord(asRecord(sender)?.[\"metadata\"]);\n return [\n {\n category: \"notifier\",\n kind: stringField(metadata, \"kind\") ?? \"unknown\",\n name: stringField(metadata, \"name\") ?? \"emailSender\",\n error: reasons.map((reason) => `emailSender: ${reason}`).join(\"; \"),\n },\n ];\n}\n\n/** Failures for the core database/storage/runner/queue slots. */\nfunction checkSlots(checks: SlotCheck[]): AdapterSetupFailure[] {\n const failures: AdapterSetupFailure[] = [];\n for (const check of checks) {\n const reasons = validateAdapter(check.adapter, check.category, check.slot);\n if (reasons.length === 0) {\n continue;\n }\n const metadata = asRecord(asRecord(check.adapter)?.[\"metadata\"]);\n failures.push({\n category: check.category,\n kind: stringField(metadata, \"kind\") ?? \"unknown\",\n name: stringField(metadata, \"name\") ?? check.slot,\n error: reasons.join(\"; \"),\n });\n }\n return failures;\n}\n\n/**\n * Validate every adapter in the boot sources. Returns per-adapter failures\n * (empty when the whole assembly is sound).\n */\nexport function validateAdapterSources(sources: AdapterSetupSources): AdapterSetupFailure[] {\n const checks: SlotCheck[] = [\n { adapter: sources.database, category: \"database\", slot: \"database\" },\n { adapter: sources.storage, category: \"storage\", slot: \"storage\" },\n ];\n if (sources.captureRunner !== undefined) {\n checks.push({\n adapter: sources.captureRunner,\n category: \"capture-runner\",\n slot: \"captureRunner\",\n });\n }\n const providers: ProviderCheck[] = [\n ...(sources.design ?? []).map((provider, index) => ({\n provider,\n index,\n kinds: \"design\" as const,\n })),\n ...(sources.notifiers ?? []).map((provider, index) => ({\n provider,\n index,\n kinds: \"notifier\" as const,\n })),\n ];\n return [\n ...checkSlots(checks),\n ...checkProviders(providers),\n ...checkEmailSender(sources.emailSender),\n ];\n}\n\n/**\n * Validate a full boot assembly: adapters plus the optional auth engine.\n * App assembly calls this — `ShelfOptions` carries `auth` alongside the\n * adapter slots, and an invalid engine fails boot like any adapter.\n */\nexport function validateBootAssembly(\n sources: AdapterSetupSources & { auth?: unknown },\n): AdapterSetupFailure[] {\n return [...validateAdapterSources(sources), ...checkAuth(sources.auth)];\n}\n"],"mappings":"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"}
|
package/dist/ai.d.mts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { Logger } from "./logger.mjs";
|
|
4
|
+
import { EvidenceLimits } from "./insights/limits.mjs";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
//#region src/ai.d.ts
|
|
7
|
+
/** Tasks the AI surface routes: build triage and project health. */
|
|
8
|
+
type AiTask = "triage" | "health";
|
|
9
|
+
/** One screenshot sent to a vision-capable model. */
|
|
10
|
+
interface AiImage {
|
|
11
|
+
mediaType: "image/png";
|
|
12
|
+
data: Uint8Array;
|
|
13
|
+
/** Short caption (story, viewport) shown to the model before the image. */
|
|
14
|
+
label: string;
|
|
15
|
+
}
|
|
16
|
+
/** Evidence handed to the model: delimited text plus optional images. */
|
|
17
|
+
interface AiEvidence {
|
|
18
|
+
text: string;
|
|
19
|
+
images: AiImage[];
|
|
20
|
+
}
|
|
21
|
+
/** Provider-reported (or estimated) token usage for one call. */
|
|
22
|
+
interface AiUsageReport {
|
|
23
|
+
inputTokens: number;
|
|
24
|
+
outputTokens: number;
|
|
25
|
+
/** True when the backend reported nothing and a char/4 estimate was used. */
|
|
26
|
+
estimated: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Input for {@link Ai.summarize}. */
|
|
29
|
+
interface AiSummarizeInput<T> {
|
|
30
|
+
task: AiTask;
|
|
31
|
+
/** Requested profile; falls back to the default profile with a warning. */
|
|
32
|
+
profile?: string;
|
|
33
|
+
system: string;
|
|
34
|
+
evidence: AiEvidence;
|
|
35
|
+
/** Result schema (the model output is validated against it). */
|
|
36
|
+
schema: z.ZodType<T>;
|
|
37
|
+
signal?: AbortSignal;
|
|
38
|
+
}
|
|
39
|
+
/** Result of one successful summarize call. */
|
|
40
|
+
interface AiSummarizeResult<T> {
|
|
41
|
+
object: T;
|
|
42
|
+
usage: AiUsageReport;
|
|
43
|
+
profileRequested: string | null;
|
|
44
|
+
profileEffective: string;
|
|
45
|
+
model: string;
|
|
46
|
+
/** Number of images actually sent to the model. */
|
|
47
|
+
imagesSent: number;
|
|
48
|
+
/** True when images were dropped (no vision model, or provider rejected them). */
|
|
49
|
+
visionSkipped: boolean;
|
|
50
|
+
warnings: string[];
|
|
51
|
+
}
|
|
52
|
+
/** Instance-level budget options (all optional). */
|
|
53
|
+
interface AiBudget {
|
|
54
|
+
/** Site-wide daily token cap (UTC day); undefined = no daily cap. */
|
|
55
|
+
dailyTokens?: number;
|
|
56
|
+
/** Multiplier applied to tokens counted for calls that sent images. */
|
|
57
|
+
visionWeight: number;
|
|
58
|
+
/** Per-project call cap per rolling hour. */
|
|
59
|
+
perProjectCallsPerHour: number;
|
|
60
|
+
}
|
|
61
|
+
/** Why a summarize call failed. */
|
|
62
|
+
type AiErrorCode = "timeout" | "provider" | "schema" | "aborted" | "unknown";
|
|
63
|
+
/** Failure from {@link Ai.summarize}; carries usage the provider still billed. */
|
|
64
|
+
declare class AiError extends Error {
|
|
65
|
+
readonly code: AiErrorCode;
|
|
66
|
+
readonly usage?: AiUsageReport;
|
|
67
|
+
constructor(code: AiErrorCode, message: string, usage?: AiUsageReport, options?: {
|
|
68
|
+
cause?: unknown;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Health probe result. */
|
|
72
|
+
interface AiHealth {
|
|
73
|
+
ok: boolean;
|
|
74
|
+
detail?: string;
|
|
75
|
+
}
|
|
76
|
+
/** The AI surface consumed by `ShelfOptions.ai`. */
|
|
77
|
+
interface Ai {
|
|
78
|
+
/** Run one structured summarize call against a profile's model. */
|
|
79
|
+
summarize<T>(input: AiSummarizeInput<T>): Promise<AiSummarizeResult<T>>;
|
|
80
|
+
/** Configured profile names. */
|
|
81
|
+
profileNames(): string[];
|
|
82
|
+
/** The profile used when none (or an unknown one) is requested. */
|
|
83
|
+
defaultProfile(): string;
|
|
84
|
+
/** Whether the profile has an effective vision model for the task. */
|
|
85
|
+
hasVision(profile: string | undefined, task: AiTask): boolean;
|
|
86
|
+
/** Stable identifier of the model a call would use (for hashing/rows). */
|
|
87
|
+
modelId(profile: string | undefined, task: AiTask, withImages?: boolean): string;
|
|
88
|
+
/** Budget options (with defaults applied). */
|
|
89
|
+
budget(): AiBudget;
|
|
90
|
+
/** Evidence limit overrides configured on the instance. */
|
|
91
|
+
limits(): Partial<EvidenceLimits>;
|
|
92
|
+
/** Per-slot timeout in milliseconds. */
|
|
93
|
+
timeoutMs(profile: string | undefined, task: AiTask, withImages?: boolean): number;
|
|
94
|
+
/** Host-bound scoped logger. */
|
|
95
|
+
setLogger?(logger: Logger): void;
|
|
96
|
+
/** Free boot checks (spec version, wiring); never a billed call. */
|
|
97
|
+
setup(): Promise<void>;
|
|
98
|
+
/** Cheap liveness probe; never inference. */
|
|
99
|
+
health(): Promise<AiHealth>;
|
|
100
|
+
/** Release resources (unregisters nothing global). */
|
|
101
|
+
teardown(): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { Ai, AiBudget, AiError, AiErrorCode, AiEvidence, AiHealth, AiImage, AiSummarizeInput, AiSummarizeResult, AiTask, AiUsageReport };
|
|
105
|
+
//# sourceMappingURL=ai.d.mts.map
|
package/dist/ai.mjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/ai.ts
|
|
5
|
+
/** Failure from {@link Ai.summarize}; carries usage the provider still billed. */
|
|
6
|
+
var AiError = class extends Error {
|
|
7
|
+
code;
|
|
8
|
+
usage;
|
|
9
|
+
constructor(code, message, usage, options) {
|
|
10
|
+
super(message, options);
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.usage = usage;
|
|
13
|
+
this.name = "AiError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { AiError };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=ai.mjs.map
|
package/dist/ai.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai.mjs","names":[],"sources":["../src/ai.ts"],"sourcesContent":["/**\n * AI singleton surface (not an adapter; see ADR 0016).\n *\n * Owned by core so `ShelfOptions.ai` needs no dependency edge into the\n * implementation package (`@storyshelf/ai` already depends on core). The\n * package implements and re-exports {@link Ai}.\n */\nimport type { z } from \"zod\";\nimport type { EvidenceLimits } from \"./insights/limits.ts\";\nimport type { Logger } from \"./logger.ts\";\n\n/** Tasks the AI surface routes: build triage and project health. */\nexport type AiTask = \"triage\" | \"health\";\n\n/** One screenshot sent to a vision-capable model. */\nexport interface AiImage {\n mediaType: \"image/png\";\n data: Uint8Array;\n /** Short caption (story, viewport) shown to the model before the image. */\n label: string;\n}\n\n/** Evidence handed to the model: delimited text plus optional images. */\nexport interface AiEvidence {\n text: string;\n images: AiImage[];\n}\n\n/** Provider-reported (or estimated) token usage for one call. */\nexport interface AiUsageReport {\n inputTokens: number;\n outputTokens: number;\n /** True when the backend reported nothing and a char/4 estimate was used. */\n estimated: boolean;\n}\n\n/** Input for {@link Ai.summarize}. */\nexport interface AiSummarizeInput<T> {\n task: AiTask;\n /** Requested profile; falls back to the default profile with a warning. */\n profile?: string;\n system: string;\n evidence: AiEvidence;\n /** Result schema (the model output is validated against it). */\n schema: z.ZodType<T>;\n signal?: AbortSignal;\n}\n\n/** Result of one successful summarize call. */\nexport interface AiSummarizeResult<T> {\n object: T;\n usage: AiUsageReport;\n profileRequested: string | null;\n profileEffective: string;\n model: string;\n /** Number of images actually sent to the model. */\n imagesSent: number;\n /** True when images were dropped (no vision model, or provider rejected them). */\n visionSkipped: boolean;\n warnings: string[];\n}\n\n/** Instance-level budget options (all optional). */\nexport interface AiBudget {\n /** Site-wide daily token cap (UTC day); undefined = no daily cap. */\n dailyTokens?: number;\n /** Multiplier applied to tokens counted for calls that sent images. */\n visionWeight: number;\n /** Per-project call cap per rolling hour. */\n perProjectCallsPerHour: number;\n}\n\n/** Why a summarize call failed. */\nexport type AiErrorCode = \"timeout\" | \"provider\" | \"schema\" | \"aborted\" | \"unknown\";\n\n/** Failure from {@link Ai.summarize}; carries usage the provider still billed. */\nexport class AiError extends Error {\n readonly code: AiErrorCode;\n readonly usage?: AiUsageReport;\n\n constructor(\n code: AiErrorCode,\n message: string,\n usage?: AiUsageReport,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.code = code;\n this.usage = usage;\n this.name = \"AiError\";\n }\n}\n\n/** Health probe result. */\nexport interface AiHealth {\n ok: boolean;\n detail?: string;\n}\n\n/** The AI surface consumed by `ShelfOptions.ai`. */\nexport interface Ai {\n /** Run one structured summarize call against a profile's model. */\n summarize<T>(input: AiSummarizeInput<T>): Promise<AiSummarizeResult<T>>;\n /** Configured profile names. */\n profileNames(): string[];\n /** The profile used when none (or an unknown one) is requested. */\n defaultProfile(): string;\n /** Whether the profile has an effective vision model for the task. */\n hasVision(profile: string | undefined, task: AiTask): boolean;\n /** Stable identifier of the model a call would use (for hashing/rows). */\n modelId(profile: string | undefined, task: AiTask, withImages?: boolean): string;\n /** Budget options (with defaults applied). */\n budget(): AiBudget;\n /** Evidence limit overrides configured on the instance. */\n limits(): Partial<EvidenceLimits>;\n /** Per-slot timeout in milliseconds. */\n timeoutMs(profile: string | undefined, task: AiTask, withImages?: boolean): number;\n /** Host-bound scoped logger. */\n setLogger?(logger: Logger): void;\n /** Free boot checks (spec version, wiring); never a billed call. */\n setup(): Promise<void>;\n /** Cheap liveness probe; never inference. */\n health(): Promise<AiHealth>;\n /** Release resources (unregisters nothing global). */\n teardown(): Promise<void>;\n}\n"],"mappings":";;;;;AA4EA,IAAa,UAAb,cAA6B,MAAM;CACjC;CACA;CAEA,YACE,MACA,SACA,OACA,SACA;EACA,MAAM,SAAS,OAAO;EACtB,KAAK,OAAO;EACZ,KAAK,QAAQ;EACb,KAAK,OAAO;CACd;AACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/capture/a11y/axe-source.d.ts
|
|
4
|
+
/** Lazy, cached loader for the axe-core browser bundle. */
|
|
5
|
+
/**
|
|
6
|
+
* Read `axe.min.js` (~550 KB) once per process, on first use. Lazy on purpose: servers that never run
|
|
7
|
+
* accessibility checks do not touch the file at boot. A failed read is not cached.
|
|
8
|
+
*/
|
|
9
|
+
declare function loadAxeSource(): Promise<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Wrap the axe source so evaluating it twice in one document is a no-op. Evaluate it as a string
|
|
12
|
+
* (CDP `Runtime.evaluate`: not bound by the page's CSP and works over remote browsers, since the
|
|
13
|
+
* source travels over the wire instead of a file path).
|
|
14
|
+
*/
|
|
15
|
+
declare function axeInjectionScript(source: string): string;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { axeInjectionScript, loadAxeSource };
|
|
18
|
+
//# sourceMappingURL=axe-source.d.mts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
//#region src/capture/a11y/axe-source.ts
|
|
7
|
+
/** Lazy, cached loader for the axe-core browser bundle. */
|
|
8
|
+
let cached;
|
|
9
|
+
/**
|
|
10
|
+
* Read `axe.min.js` (~550 KB) once per process, on first use. Lazy on purpose: servers that never run
|
|
11
|
+
* accessibility checks do not touch the file at boot. A failed read is not cached.
|
|
12
|
+
*/
|
|
13
|
+
async function loadAxeSource() {
|
|
14
|
+
cached ??= readAxeSource();
|
|
15
|
+
try {
|
|
16
|
+
return await cached;
|
|
17
|
+
} catch (error) {
|
|
18
|
+
cached = void 0;
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Wrap the axe source so evaluating it twice in one document is a no-op. Evaluate it as a string
|
|
24
|
+
* (CDP `Runtime.evaluate`: not bound by the page's CSP and works over remote browsers, since the
|
|
25
|
+
* source travels over the wire instead of a file path).
|
|
26
|
+
*/
|
|
27
|
+
function axeInjectionScript(source) {
|
|
28
|
+
return `(function(){if(typeof globalThis.axe!=="undefined")return;\n${source}\n})()`;
|
|
29
|
+
}
|
|
30
|
+
async function readAxeSource() {
|
|
31
|
+
const path = createRequire(import.meta.url).resolve("axe-core/axe.min.js");
|
|
32
|
+
return await readFile(path, "utf8");
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { axeInjectionScript, loadAxeSource };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=axe-source.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axe-source.mjs","names":[],"sources":["../../../src/capture/a11y/axe-source.ts"],"sourcesContent":["/** Lazy, cached loader for the axe-core browser bundle. */\n\nimport { readFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\n\nlet cached: Promise<string> | undefined;\n\n/**\n * Read `axe.min.js` (~550 KB) once per process, on first use. Lazy on purpose: servers that never run\n * accessibility checks do not touch the file at boot. A failed read is not cached.\n */\nexport async function loadAxeSource(): Promise<string> {\n cached ??= readAxeSource();\n try {\n return await cached;\n } catch (error) {\n cached = undefined;\n throw error;\n }\n}\n\n/**\n * Wrap the axe source so evaluating it twice in one document is a no-op. Evaluate it as a string\n * (CDP `Runtime.evaluate`: not bound by the page's CSP and works over remote browsers, since the\n * source travels over the wire instead of a file path).\n */\nexport function axeInjectionScript(source: string): string {\n return `(function(){if(typeof globalThis.axe!==\"undefined\")return;\\n${source}\\n})()`;\n}\n\n/** Drop the cached source (tests). */\nexport function resetAxeSourceCache(): void {\n cached = undefined;\n}\n\nasync function readAxeSource(): Promise<string> {\n const path = createRequire(import.meta.url).resolve(\"axe-core/axe.min.js\");\n return await readFile(path, \"utf8\");\n}\n"],"mappings":";;;;;;;AAKA,IAAI;;;;;AAMJ,eAAsB,gBAAiC;CACrD,WAAW,cAAc;CACzB,IAAI;EACF,OAAO,MAAM;CACf,SAAS,OAAO;EACd,SAAS,KAAA;EACT,MAAM;CACR;AACF;;;;;;AAOA,SAAgB,mBAAmB,QAAwB;CACzD,OAAO,+DAA+D,OAAO;AAC/E;AAOA,eAAe,gBAAiC;CAC9C,MAAM,OAAO,cAAc,YAAY,GAAG,CAAC,CAAC,QAAQ,qBAAqB;CACzE,OAAO,MAAM,SAAS,MAAM,MAAM;AACpC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { SlimViolation } from "./map.mjs";
|
|
4
|
+
import { A11yRunPlan } from "./options.mjs";
|
|
5
|
+
//#region src/capture/a11y/in-page.d.ts
|
|
6
|
+
/** What {@link inPageReadA11yParameters} found: the plain-data `parameters.a11y` and what was dropped. */
|
|
7
|
+
interface A11yParametersRead {
|
|
8
|
+
params: unknown;
|
|
9
|
+
/** Function values (and items that held nothing else) left out because a page cannot hand them over. */
|
|
10
|
+
dropped: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Read the current story's `parameters.a11y` from the running Storybook preview as plain data.
|
|
14
|
+
* Functions (`config.rules[].matches`, custom checks) cannot cross into the runner, so they are
|
|
15
|
+
* dropped, and an object or array item that held nothing else goes with them (an emptied rule item
|
|
16
|
+
* would otherwise reset to axe's default). Returns undefined when there is no `a11y` parameter or it
|
|
17
|
+
* cannot be read at all (cyclic).
|
|
18
|
+
*/
|
|
19
|
+
declare function inPageReadA11yParameters(): A11yParametersRead | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Run the injected axe over the plan's context and return only slim fields (id, impact, help, first
|
|
22
|
+
* target, node count). Throws when axe is not present in the page.
|
|
23
|
+
*/
|
|
24
|
+
declare function inPageRunAxe(plan: A11yRunPlan): Promise<SlimViolation[]>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { A11yParametersRead, inPageReadA11yParameters, inPageRunAxe };
|
|
27
|
+
//# sourceMappingURL=in-page.d.mts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/capture/a11y/in-page.ts
|
|
5
|
+
/**
|
|
6
|
+
* Read the current story's `parameters.a11y` from the running Storybook preview as plain data.
|
|
7
|
+
* Functions (`config.rules[].matches`, custom checks) cannot cross into the runner, so they are
|
|
8
|
+
* dropped, and an object or array item that held nothing else goes with them (an emptied rule item
|
|
9
|
+
* would otherwise reset to axe's default). Returns undefined when there is no `a11y` parameter or it
|
|
10
|
+
* cannot be read at all (cyclic).
|
|
11
|
+
*/
|
|
12
|
+
function inPageReadA11yParameters() {
|
|
13
|
+
const a11y = globalThis.__STORYBOOK_PREVIEW__?.currentRender?.story?.parameters?.a11y;
|
|
14
|
+
if (a11y === void 0) return void 0;
|
|
15
|
+
const state = { dropped: 0 };
|
|
16
|
+
const DROP = Symbol("drop");
|
|
17
|
+
const clean = (value, depth) => {
|
|
18
|
+
if (depth > 32) throw new Error("too deep");
|
|
19
|
+
if (typeof value === "function" || typeof value === "symbol" || value === void 0) {
|
|
20
|
+
state.dropped += 1;
|
|
21
|
+
return DROP;
|
|
22
|
+
}
|
|
23
|
+
if (value === null || typeof value !== "object") return value;
|
|
24
|
+
const before = state.dropped;
|
|
25
|
+
const entries = Array.isArray(value) ? value.map((item, index) => [String(index), item]) : Object.entries(value);
|
|
26
|
+
const kept = entries.map(([key, item]) => [key, clean(item, depth + 1)]).filter(([, item]) => item !== DROP);
|
|
27
|
+
if (kept.length === 0 && entries.length > 0 && state.dropped > before) return DROP;
|
|
28
|
+
return Array.isArray(value) ? kept.map(([, item]) => item) : Object.fromEntries(kept);
|
|
29
|
+
};
|
|
30
|
+
try {
|
|
31
|
+
const params = clean(a11y, 0);
|
|
32
|
+
return params === DROP ? void 0 : {
|
|
33
|
+
params,
|
|
34
|
+
dropped: state.dropped
|
|
35
|
+
};
|
|
36
|
+
} catch {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Run the injected axe over the plan's context and return only slim fields (id, impact, help, first
|
|
42
|
+
* target, node count). Throws when axe is not present in the page.
|
|
43
|
+
*/
|
|
44
|
+
async function inPageRunAxe(plan) {
|
|
45
|
+
const win = globalThis;
|
|
46
|
+
if (!win.axe) throw new Error("axe is not loaded in the page");
|
|
47
|
+
if (typeof plan.context === "string" && !win.document.querySelector(plan.context)) return [];
|
|
48
|
+
if (Object.keys(plan.config).length > 0) win.axe.configure(plan.config);
|
|
49
|
+
return (await win.axe.run(plan.context, plan.options)).violations.map((v) => ({
|
|
50
|
+
id: v.id,
|
|
51
|
+
impact: v.impact ?? null,
|
|
52
|
+
help: v.help,
|
|
53
|
+
target: (v.nodes[0]?.target ?? []).flat(Infinity).join(" "),
|
|
54
|
+
count: v.nodes.length
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { inPageReadA11yParameters, inPageRunAxe };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=in-page.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-page.mjs","names":["win"],"sources":["../../../src/capture/a11y/in-page.ts"],"sourcesContent":["/**\n * Functions evaluated inside the story page. Playwright and Puppeteer serialise only a function's\n * source, so each must stay ONE self-contained function: no imports, helpers or module bindings\n * (`in-page.test.ts` rebuilds them from source in a bare scope to guard that).\n */\n\nimport type { SlimViolation } from \"./map.ts\";\nimport type { A11yRunPlan } from \"./options.ts\";\n\n/** What {@link inPageReadA11yParameters} found: the plain-data `parameters.a11y` and what was dropped. */\nexport interface A11yParametersRead {\n params: unknown;\n /** Function values (and items that held nothing else) left out because a page cannot hand them over. */\n dropped: number;\n}\n\n/**\n * Read the current story's `parameters.a11y` from the running Storybook preview as plain data.\n * Functions (`config.rules[].matches`, custom checks) cannot cross into the runner, so they are\n * dropped, and an object or array item that held nothing else goes with them (an emptied rule item\n * would otherwise reset to axe's default). Returns undefined when there is no `a11y` parameter or it\n * cannot be read at all (cyclic).\n */\n// oxlint-disable-next-line eslint/max-statements -- must stay one self-contained function (see above)\nexport function inPageReadA11yParameters(): A11yParametersRead | undefined {\n const win = globalThis as unknown as {\n // oxlint-disable-next-line eslint/no-underscore-dangle -- Storybook global\n __STORYBOOK_PREVIEW__?: {\n currentRender?: { story?: { parameters?: { a11y?: unknown } } };\n };\n };\n // oxlint-disable-next-line eslint/no-underscore-dangle -- Storybook global\n const a11y = win.__STORYBOOK_PREVIEW__?.currentRender?.story?.parameters?.a11y;\n if (a11y === undefined) return undefined;\n const state = { dropped: 0 };\n const DROP = Symbol(\"drop\");\n const clean = (value: unknown, depth: number): unknown => {\n if (depth > 32) throw new Error(\"too deep\");\n if (typeof value === \"function\" || typeof value === \"symbol\" || value === undefined) {\n state.dropped += 1;\n return DROP;\n }\n if (value === null || typeof value !== \"object\") return value;\n const before = state.dropped;\n const entries: [string, unknown][] = Array.isArray(value)\n ? value.map((item, index): [string, unknown] => [String(index), item])\n : Object.entries(value);\n const kept = entries\n .map(([key, item]): [string, unknown] => [key, clean(item, depth + 1)])\n .filter(([, item]) => item !== DROP);\n if (kept.length === 0 && entries.length > 0 && state.dropped > before) return DROP;\n return Array.isArray(value) ? kept.map(([, item]) => item) : Object.fromEntries(kept);\n };\n try {\n const params = clean(a11y, 0);\n return params === DROP ? undefined : { params, dropped: state.dropped };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Run the injected axe over the plan's context and return only slim fields (id, impact, help, first\n * target, node count). Throws when axe is not present in the page.\n */\n// oxlint-disable-next-line eslint/max-statements, eslint/max-lines-per-function -- must stay one self-contained function (see above)\nexport async function inPageRunAxe(plan: A11yRunPlan): Promise<SlimViolation[]> {\n const win = globalThis as unknown as {\n axe?: {\n configure: (config: unknown) => void;\n run: (context: unknown, options: unknown) => Promise<{ violations: AxeViolation[] }>;\n };\n document: { querySelector: (selector: string) => unknown };\n };\n interface AxeViolation {\n id: string;\n impact?: string | null;\n help: string;\n nodes: { target: unknown[] }[];\n }\n if (!win.axe) throw new Error(\"axe is not loaded in the page\");\n if (typeof plan.context === \"string\" && !win.document.querySelector(plan.context)) return [];\n if (Object.keys(plan.config).length > 0) win.axe.configure(plan.config);\n const results = await win.axe.run(plan.context, plan.options);\n return results.violations.map((v) => ({\n id: v.id,\n impact: v.impact ?? null,\n help: v.help,\n target: (v.nodes[0]?.target ?? []).flat(Infinity).join(\" \"),\n count: v.nodes.length,\n }));\n}\n"],"mappings":";;;;;;;;;;;AAwBA,SAAgB,2BAA2D;CAQzE,MAAM,OAAOA,WAAI,uBAAuB,eAAe,OAAO,YAAY;CAC1E,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;CAC/B,MAAM,QAAQ,EAAE,SAAS,EAAE;CAC3B,MAAM,OAAO,OAAO,MAAM;CAC1B,MAAM,SAAS,OAAgB,UAA2B;EACxD,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM,UAAU;EAC1C,IAAI,OAAO,UAAU,cAAc,OAAO,UAAU,YAAY,UAAU,KAAA,GAAW;GACnF,MAAM,WAAW;GACjB,OAAO;EACT;EACA,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO;EACxD,MAAM,SAAS,MAAM;EACrB,MAAM,UAA+B,MAAM,QAAQ,KAAK,IACpD,MAAM,KAAK,MAAM,UAA6B,CAAC,OAAO,KAAK,GAAG,IAAI,CAAC,IACnE,OAAO,QAAQ,KAAK;EACxB,MAAM,OAAO,QACV,KAAK,CAAC,KAAK,UAA6B,CAAC,KAAK,MAAM,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC,CACtE,QAAQ,GAAG,UAAU,SAAS,IAAI;EACrC,IAAI,KAAK,WAAW,KAAK,QAAQ,SAAS,KAAK,MAAM,UAAU,QAAQ,OAAO;EAC9E,OAAO,MAAM,QAAQ,KAAK,IAAI,KAAK,KAAK,GAAG,UAAU,IAAI,IAAI,OAAO,YAAY,IAAI;CACtF;CACA,IAAI;EACF,MAAM,SAAS,MAAM,MAAM,CAAC;EAC5B,OAAO,WAAW,OAAO,KAAA,IAAY;GAAE;GAAQ,SAAS,MAAM;EAAQ;CACxE,QAAQ;EACN;CACF;AACF;;;;;AAOA,eAAsB,aAAa,MAA6C;CAC9E,MAAM,MAAM;CAaZ,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,+BAA+B;CAC7D,IAAI,OAAO,KAAK,YAAY,YAAY,CAAC,IAAI,SAAS,cAAc,KAAK,OAAO,GAAG,OAAO,CAAC;CAC3F,IAAI,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,SAAS,GAAG,IAAI,IAAI,UAAU,KAAK,MAAM;CAEtE,QAAO,MADe,IAAI,IAAI,IAAI,KAAK,SAAS,KAAK,OAAO,EAAA,CAC7C,WAAW,KAAK,OAAO;EACpC,IAAI,EAAE;EACN,QAAQ,EAAE,UAAU;EACpB,MAAM,EAAE;EACR,SAAS,EAAE,MAAM,EAAE,EAAE,UAAU,CAAC,EAAA,CAAG,KAAK,QAAQ,CAAC,CAAC,KAAK,GAAG;EAC1D,OAAO,EAAE,MAAM;CACjB,EAAE;AACJ"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/capture/a11y/map.d.ts
|
|
4
|
+
/** Map slim in-page axe results to `a11y:` violation strings. */
|
|
5
|
+
/** Most violations reported per snapshot; the rest collapse into "…and N more". */
|
|
6
|
+
declare const MAX_REPORTED_VIOLATIONS = 10;
|
|
7
|
+
/** The only per-violation fields that leave the page (raw axe nodes carry large html payloads). */
|
|
8
|
+
interface SlimViolation {
|
|
9
|
+
id: string;
|
|
10
|
+
impact: string | null;
|
|
11
|
+
help: string;
|
|
12
|
+
/** Selector of the first affected node. */
|
|
13
|
+
target: string;
|
|
14
|
+
/** Number of affected nodes. */
|
|
15
|
+
count: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* One string per violation: rule id, impact, help text, short target and node count, worst impact
|
|
19
|
+
* first. `;` is reserved (the pipeline joins annotations with it), so it never appears in a string.
|
|
20
|
+
*/
|
|
21
|
+
declare function mapAxeViolations(violations: readonly SlimViolation[]): string[];
|
|
22
|
+
//#endregion
|
|
23
|
+
export { MAX_REPORTED_VIOLATIONS, SlimViolation, mapAxeViolations };
|
|
24
|
+
//# sourceMappingURL=map.d.mts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/capture/a11y/map.ts
|
|
5
|
+
/** Map slim in-page axe results to `a11y:` violation strings. */
|
|
6
|
+
/** Most violations reported per snapshot; the rest collapse into "…and N more". */
|
|
7
|
+
const MAX_REPORTED_VIOLATIONS = 10;
|
|
8
|
+
const MAX_SELECTOR_LENGTH = 60;
|
|
9
|
+
const MAX_HELP_LENGTH = 90;
|
|
10
|
+
const IMPACT_ORDER = [
|
|
11
|
+
"critical",
|
|
12
|
+
"serious",
|
|
13
|
+
"moderate",
|
|
14
|
+
"minor"
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* One string per violation: rule id, impact, help text, short target and node count, worst impact
|
|
18
|
+
* first. `;` is reserved (the pipeline joins annotations with it), so it never appears in a string.
|
|
19
|
+
*/
|
|
20
|
+
function mapAxeViolations(violations) {
|
|
21
|
+
const sorted = violations.toSorted(compareViolations);
|
|
22
|
+
const lines = sorted.slice(0, 10).map((violation) => formatViolation(violation));
|
|
23
|
+
const more = sorted.length - lines.length;
|
|
24
|
+
if (more > 0) lines.push(`…and ${more} more`);
|
|
25
|
+
return lines;
|
|
26
|
+
}
|
|
27
|
+
function formatViolation(v) {
|
|
28
|
+
const nodes = `${v.count} node${v.count === 1 ? "" : "s"}`;
|
|
29
|
+
const target = truncate(v.target, MAX_SELECTOR_LENGTH);
|
|
30
|
+
return clean(`${v.id} (${v.impact ?? "unknown"}): ${truncate(v.help, MAX_HELP_LENGTH)} [${target}] ${nodes}`);
|
|
31
|
+
}
|
|
32
|
+
function compareViolations(a, b) {
|
|
33
|
+
return rank(a.impact) - rank(b.impact) || a.id.localeCompare(b.id);
|
|
34
|
+
}
|
|
35
|
+
function rank(impact) {
|
|
36
|
+
const index = IMPACT_ORDER.indexOf(impact ?? "");
|
|
37
|
+
return index === -1 ? IMPACT_ORDER.length : index;
|
|
38
|
+
}
|
|
39
|
+
function truncate(text, max) {
|
|
40
|
+
return text.length > max ? `${text.slice(0, max - 1)}…` : text;
|
|
41
|
+
}
|
|
42
|
+
function clean(text) {
|
|
43
|
+
return text.replaceAll(/\s+/gu, " ").replaceAll(";", ",");
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { MAX_REPORTED_VIOLATIONS, mapAxeViolations };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=map.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.mjs","names":[],"sources":["../../../src/capture/a11y/map.ts"],"sourcesContent":["/** Map slim in-page axe results to `a11y:` violation strings. */\n\n/** Most violations reported per snapshot; the rest collapse into \"…and N more\". */\nexport const MAX_REPORTED_VIOLATIONS = 10;\nconst MAX_SELECTOR_LENGTH = 60;\nconst MAX_HELP_LENGTH = 90;\nconst IMPACT_ORDER = [\"critical\", \"serious\", \"moderate\", \"minor\"];\n\n/** The only per-violation fields that leave the page (raw axe nodes carry large html payloads). */\nexport interface SlimViolation {\n id: string;\n impact: string | null;\n help: string;\n /** Selector of the first affected node. */\n target: string;\n /** Number of affected nodes. */\n count: number;\n}\n\n/**\n * One string per violation: rule id, impact, help text, short target and node count, worst impact\n * first. `;` is reserved (the pipeline joins annotations with it), so it never appears in a string.\n */\nexport function mapAxeViolations(violations: readonly SlimViolation[]): string[] {\n const sorted = violations.toSorted(compareViolations);\n const lines = sorted\n .slice(0, MAX_REPORTED_VIOLATIONS)\n .map((violation) => formatViolation(violation));\n const more = sorted.length - lines.length;\n if (more > 0) lines.push(`…and ${more} more`);\n return lines;\n}\n\nfunction formatViolation(v: SlimViolation): string {\n const nodes = `${v.count} node${v.count === 1 ? \"\" : \"s\"}`;\n const target = truncate(v.target, MAX_SELECTOR_LENGTH);\n return clean(\n `${v.id} (${v.impact ?? \"unknown\"}): ${truncate(v.help, MAX_HELP_LENGTH)} [${target}] ${nodes}`,\n );\n}\n\nfunction compareViolations(a: SlimViolation, b: SlimViolation): number {\n return rank(a.impact) - rank(b.impact) || a.id.localeCompare(b.id);\n}\n\nfunction rank(impact: string | null): number {\n const index = IMPACT_ORDER.indexOf(impact ?? \"\");\n return index === -1 ? IMPACT_ORDER.length : index;\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\nfunction clean(text: string): string {\n return text.replaceAll(/\\s+/gu, \" \").replaceAll(\";\", \",\");\n}\n"],"mappings":";;;;;;AAGA,MAAa,0BAA0B;AACvC,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;AACxB,MAAM,eAAe;CAAC;CAAY;CAAW;CAAY;AAAO;;;;;AAiBhE,SAAgB,iBAAiB,YAAgD;CAC/E,MAAM,SAAS,WAAW,SAAS,iBAAiB;CACpD,MAAM,QAAQ,OACX,MAAM,GAAA,EAA0B,CAAC,CACjC,KAAK,cAAc,gBAAgB,SAAS,CAAC;CAChD,MAAM,OAAO,OAAO,SAAS,MAAM;CACnC,IAAI,OAAO,GAAG,MAAM,KAAK,QAAQ,KAAK,MAAM;CAC5C,OAAO;AACT;AAEA,SAAS,gBAAgB,GAA0B;CACjD,MAAM,QAAQ,GAAG,EAAE,MAAM,OAAO,EAAE,UAAU,IAAI,KAAK;CACrD,MAAM,SAAS,SAAS,EAAE,QAAQ,mBAAmB;CACrD,OAAO,MACL,GAAG,EAAE,GAAG,IAAI,EAAE,UAAU,UAAU,KAAK,SAAS,EAAE,MAAM,eAAe,EAAE,IAAI,OAAO,IAAI,OAC1F;AACF;AAEA,SAAS,kBAAkB,GAAkB,GAA0B;CACrE,OAAO,KAAK,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,KAAK,EAAE,GAAG,cAAc,EAAE,EAAE;AACnE;AAEA,SAAS,KAAK,QAA+B;CAC3C,MAAM,QAAQ,aAAa,QAAQ,UAAU,EAAE;CAC/C,OAAO,UAAU,KAAK,aAAa,SAAS;AAC9C;AAEA,SAAS,SAAS,MAAc,KAAqB;CACnD,OAAO,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK;AAC5D;AAEA,SAAS,MAAM,MAAsB;CACnC,OAAO,KAAK,WAAW,SAAS,GAAG,CAAC,CAAC,WAAW,KAAK,GAAG;AAC1D"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/capture/a11y/options.d.ts
|
|
4
|
+
/** Turn Storybook's `parameters.a11y` into an axe run plan. */
|
|
5
|
+
/** The story root axe scans unless `parameters.a11y.element`/`context` says otherwise. */
|
|
6
|
+
declare const A11Y_ROOT_SELECTOR = "#storybook-root";
|
|
7
|
+
/** What to hand to `axe.configure` / `axe.run` in the page (JSON-serialisable). */
|
|
8
|
+
interface A11yRunPlan {
|
|
9
|
+
/** Why the story is skipped (`disable`, `test: "off"`); undefined when axe should run. */
|
|
10
|
+
skip?: string;
|
|
11
|
+
config: Record<string, unknown>;
|
|
12
|
+
options: Record<string, unknown>;
|
|
13
|
+
context: unknown;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the run plan from the JSON-serialisable subset of `parameters.a11y` (functions cannot be
|
|
17
|
+
* read from the page). `disable: true` and `test: "off"` skip the story; `test: "todo" | "error"`
|
|
18
|
+
* still only annotate, results never fail a build.
|
|
19
|
+
*/
|
|
20
|
+
declare function resolveA11yRun(raw: unknown): A11yRunPlan;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { A11Y_ROOT_SELECTOR, A11yRunPlan, resolveA11yRun };
|
|
23
|
+
//# sourceMappingURL=options.d.mts.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/capture/a11y/options.ts
|
|
5
|
+
/** Turn Storybook's `parameters.a11y` into an axe run plan. */
|
|
6
|
+
/** The story root axe scans unless `parameters.a11y.element`/`context` says otherwise. */
|
|
7
|
+
const A11Y_ROOT_SELECTOR = "#storybook-root";
|
|
8
|
+
/**
|
|
9
|
+
* Rule tags scanned by default: WCAG A/AA plus axe's `best-practice` rules; `parameters.a11y.options.runOnly`
|
|
10
|
+
* replaces them. The page-level best-practice rules (`region`, `landmark-one-main`,
|
|
11
|
+
* `page-has-heading-one`) need the whole document in scope and so stay silent for the default
|
|
12
|
+
* scan of `#storybook-root`; no rule is switched off by default (checked in a real browser).
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_RUN_ONLY = {
|
|
15
|
+
type: "tag",
|
|
16
|
+
values: [
|
|
17
|
+
"wcag2a",
|
|
18
|
+
"wcag2aa",
|
|
19
|
+
"wcag21a",
|
|
20
|
+
"wcag21aa",
|
|
21
|
+
"wcag22aa",
|
|
22
|
+
"best-practice"
|
|
23
|
+
]
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the run plan from the JSON-serialisable subset of `parameters.a11y` (functions cannot be
|
|
27
|
+
* read from the page). `disable: true` and `test: "off"` skip the story; `test: "todo" | "error"`
|
|
28
|
+
* still only annotate, results never fail a build.
|
|
29
|
+
*/
|
|
30
|
+
function resolveA11yRun(raw) {
|
|
31
|
+
const params = asRecord(raw) ?? {};
|
|
32
|
+
const skip = skipReason(params);
|
|
33
|
+
const config = asRecord(params["config"]) ?? {};
|
|
34
|
+
const userOptions = asRecord(params["options"]);
|
|
35
|
+
const rules = {
|
|
36
|
+
...disabledByConfig(config),
|
|
37
|
+
...asRecord(userOptions?.["rules"])
|
|
38
|
+
};
|
|
39
|
+
const options = {
|
|
40
|
+
runOnly: DEFAULT_RUN_ONLY,
|
|
41
|
+
...userOptions,
|
|
42
|
+
rules
|
|
43
|
+
};
|
|
44
|
+
const context = params["element"] ?? params["context"] ?? "#storybook-root";
|
|
45
|
+
return {
|
|
46
|
+
...skip ? { skip } : {},
|
|
47
|
+
config,
|
|
48
|
+
options,
|
|
49
|
+
context
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* `axe.configure({ rules: [{ id, enabled: false }] })` is ignored under a tag-based `runOnly`, so
|
|
54
|
+
* mirror those switches into the run options where they are honoured.
|
|
55
|
+
*/
|
|
56
|
+
function disabledByConfig(config) {
|
|
57
|
+
const out = {};
|
|
58
|
+
const rules = Array.isArray(config["rules"]) ? config["rules"] : [];
|
|
59
|
+
for (const rule of rules) {
|
|
60
|
+
const entry = asRecord(rule);
|
|
61
|
+
if (entry?.["enabled"] === false && typeof entry["id"] === "string") out[entry["id"]] = { enabled: false };
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
function skipReason(params) {
|
|
66
|
+
if (params["disable"] === true) return "parameters.a11y.disable";
|
|
67
|
+
if (params["test"] === "off") return "parameters.a11y.test is \"off\"";
|
|
68
|
+
}
|
|
69
|
+
function asRecord(value) {
|
|
70
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { A11Y_ROOT_SELECTOR, resolveA11yRun };
|
|
74
|
+
|
|
75
|
+
//# sourceMappingURL=options.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.mjs","names":[],"sources":["../../../src/capture/a11y/options.ts"],"sourcesContent":["/** Turn Storybook's `parameters.a11y` into an axe run plan. */\n\n/** The story root axe scans unless `parameters.a11y.element`/`context` says otherwise. */\nexport const A11Y_ROOT_SELECTOR = \"#storybook-root\";\n\n/**\n * Rule tags scanned by default: WCAG A/AA plus axe's `best-practice` rules; `parameters.a11y.options.runOnly`\n * replaces them. The page-level best-practice rules (`region`, `landmark-one-main`,\n * `page-has-heading-one`) need the whole document in scope and so stay silent for the default\n * scan of `#storybook-root`; no rule is switched off by default (checked in a real browser).\n */\nconst DEFAULT_RUN_ONLY = {\n type: \"tag\",\n values: [\"wcag2a\", \"wcag2aa\", \"wcag21a\", \"wcag21aa\", \"wcag22aa\", \"best-practice\"],\n};\n\n/** What to hand to `axe.configure` / `axe.run` in the page (JSON-serialisable). */\nexport interface A11yRunPlan {\n /** Why the story is skipped (`disable`, `test: \"off\"`); undefined when axe should run. */\n skip?: string;\n config: Record<string, unknown>;\n options: Record<string, unknown>;\n context: unknown;\n}\n\n/**\n * Resolve the run plan from the JSON-serialisable subset of `parameters.a11y` (functions cannot be\n * read from the page). `disable: true` and `test: \"off\"` skip the story; `test: \"todo\" | \"error\"`\n * still only annotate, results never fail a build.\n */\nexport function resolveA11yRun(raw: unknown): A11yRunPlan {\n const params = asRecord(raw) ?? {};\n const skip = skipReason(params);\n const config = asRecord(params[\"config\"]) ?? {};\n const userOptions = asRecord(params[\"options\"]);\n const rules = { ...disabledByConfig(config), ...asRecord(userOptions?.[\"rules\"]) };\n const options = { runOnly: DEFAULT_RUN_ONLY, ...userOptions, rules };\n const context = params[\"element\"] ?? params[\"context\"] ?? A11Y_ROOT_SELECTOR;\n return { ...(skip ? { skip } : {}), config, options, context };\n}\n\n/**\n * `axe.configure({ rules: [{ id, enabled: false }] })` is ignored under a tag-based `runOnly`, so\n * mirror those switches into the run options where they are honoured.\n */\nfunction disabledByConfig(config: Record<string, unknown>): Record<string, { enabled: false }> {\n const out: Record<string, { enabled: false }> = {};\n const rules = Array.isArray(config[\"rules\"]) ? (config[\"rules\"] as unknown[]) : [];\n for (const rule of rules) {\n const entry = asRecord(rule);\n if (entry?.[\"enabled\"] === false && typeof entry[\"id\"] === \"string\")\n out[entry[\"id\"]] = { enabled: false };\n }\n return out;\n}\n\nfunction skipReason(params: Record<string, unknown>): string | undefined {\n if (params[\"disable\"] === true) return \"parameters.a11y.disable\";\n if (params[\"test\"] === \"off\") return 'parameters.a11y.test is \"off\"';\n return undefined;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n"],"mappings":";;;;;;AAGA,MAAa,qBAAqB;;;;;;;AAQlC,MAAM,mBAAmB;CACvB,MAAM;CACN,QAAQ;EAAC;EAAU;EAAW;EAAW;EAAY;EAAY;CAAe;AAClF;;;;;;AAgBA,SAAgB,eAAe,KAA2B;CACxD,MAAM,SAAS,SAAS,GAAG,KAAK,CAAC;CACjC,MAAM,OAAO,WAAW,MAAM;CAC9B,MAAM,SAAS,SAAS,OAAO,SAAS,KAAK,CAAC;CAC9C,MAAM,cAAc,SAAS,OAAO,UAAU;CAC9C,MAAM,QAAQ;EAAE,GAAG,iBAAiB,MAAM;EAAG,GAAG,SAAS,cAAc,QAAQ;CAAE;CACjF,MAAM,UAAU;EAAE,SAAS;EAAkB,GAAG;EAAa;CAAM;CACnE,MAAM,UAAU,OAAO,cAAc,OAAO,cAAA;CAC5C,OAAO;EAAE,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;EAAI;EAAQ;EAAS;CAAQ;AAC/D;;;;;AAMA,SAAS,iBAAiB,QAAqE;CAC7F,MAAM,MAA0C,CAAC;CACjD,MAAM,QAAQ,MAAM,QAAQ,OAAO,QAAQ,IAAK,OAAO,WAAyB,CAAC;CACjF,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,SAAS,IAAI;EAC3B,IAAI,QAAQ,eAAe,SAAS,OAAO,MAAM,UAAU,UACzD,IAAI,MAAM,SAAS,EAAE,SAAS,MAAM;CACxC;CACA,OAAO;AACT;AAEA,SAAS,WAAW,QAAqD;CACvE,IAAI,OAAO,eAAe,MAAM,OAAO;CACvC,IAAI,OAAO,YAAY,OAAO,OAAO;AAEvC;AAEA,SAAS,SAAS,OAAqD;CACrE,OAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IACrE,QACD,KAAA;AACN"}
|