@storyshelf/core 0.3.2 → 0.5.3
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 +38 -31
- package/dist/adapter/capture-queue.d.mts +29 -1
- package/dist/adapter/capture-runner.d.mts +18 -2
- package/dist/adapter/capture-runner.mjs +12 -1
- package/dist/adapter/capture-runner.mjs.map +1 -0
- package/dist/adapter/database.d.mts +67 -17
- package/dist/adapter/database.mjs +22 -55
- package/dist/adapter/database.mjs.map +1 -1
- package/dist/adapter/email-sender.d.mts +27 -0
- package/dist/adapter/email-sender.mjs +4 -0
- package/dist/adapter/metadata.d.mts +21 -15
- package/dist/adapter/notifier.d.mts +7 -0
- package/dist/adapter/notifier.mjs +6 -0
- package/dist/adapter/setup.d.mts +61 -0
- package/dist/adapter/setup.mjs +29 -0
- package/dist/adapter/setup.mjs.map +1 -0
- package/dist/adapter/webhook-events.d.mts +29 -0
- package/dist/adapter/webhook-events.mjs +83 -0
- package/dist/adapter/webhook-events.mjs.map +1 -0
- package/dist/adapters/notifier/events.d.mts +26 -0
- package/dist/adapters/notifier/events.mjs +66 -0
- package/dist/adapters/notifier/events.mjs.map +1 -0
- package/dist/adapters/notifier/format.d.mts +14 -0
- package/dist/adapters/notifier/format.mjs +96 -0
- package/dist/adapters/notifier/format.mjs.map +1 -0
- package/dist/adapters/notifier/provider.d.mts +32 -0
- package/dist/adapters/notifier/types.d.mts +56 -0
- package/dist/adapters/setup-runner.d.mts +23 -0
- package/dist/adapters/setup-runner.mjs +149 -0
- package/dist/adapters/setup-runner.mjs.map +1 -0
- package/dist/adapters/validate.d.mts +30 -0
- package/dist/adapters/validate.mjs +313 -0
- package/dist/adapters/validate.mjs.map +1 -0
- package/dist/auth.d.mts +94 -0
- package/dist/auth.mjs +4 -0
- package/dist/brand-packs.d.mts +16 -0
- package/dist/brand-packs.mjs +130 -0
- package/dist/brand-packs.mjs.map +1 -0
- package/dist/capture/adapter.d.mts +51 -1
- package/dist/capture/adapter.mjs.map +1 -1
- package/dist/capture/affected.d.mts +16 -0
- package/dist/capture/affected.mjs +64 -0
- package/dist/capture/affected.mjs.map +1 -0
- package/dist/capture/diff-record.mjs +30 -0
- package/dist/capture/diff-record.mjs.map +1 -0
- package/dist/capture/dispatch.d.mts +36 -0
- package/dist/capture/dispatch.mjs +88 -31
- package/dist/capture/dispatch.mjs.map +1 -1
- package/dist/capture/guards.mjs +31 -0
- package/dist/capture/guards.mjs.map +1 -0
- package/dist/capture/orchestrator.d.mts +41 -6
- package/dist/capture/orchestrator.mjs +151 -28
- package/dist/capture/orchestrator.mjs.map +1 -1
- package/dist/capture/pipeline.d.mts +30 -16
- package/dist/capture/pipeline.mjs +143 -39
- package/dist/capture/pipeline.mjs.map +1 -1
- package/dist/capture/recovery.d.mts +21 -0
- package/dist/capture/recovery.mjs +83 -0
- package/dist/capture/recovery.mjs.map +1 -0
- package/dist/capture/rediff.d.mts +35 -0
- package/dist/capture/rediff.mjs +77 -0
- package/dist/capture/rediff.mjs.map +1 -0
- package/dist/capture/sizing.d.mts +58 -0
- package/dist/capture/sizing.mjs +119 -0
- package/dist/capture/sizing.mjs.map +1 -0
- package/dist/capture/skip-checks.mjs +3 -3
- package/dist/capture/skip-checks.mjs.map +1 -1
- package/dist/capture/statics.d.mts +38 -0
- package/dist/capture/statics.mjs +38 -4
- package/dist/capture/statics.mjs.map +1 -1
- package/dist/capture/status-fanout.mjs +7 -2
- package/dist/capture/status-fanout.mjs.map +1 -1
- package/dist/capture/storybook.d.mts +31 -2
- package/dist/capture/storybook.mjs +77 -2
- package/dist/capture/storybook.mjs.map +1 -1
- package/dist/capture.d.mts +10 -4
- package/dist/capture.mjs +7 -2
- package/dist/config.d.mts +121 -4
- package/dist/config.mjs +55 -8
- package/dist/config.mjs.map +1 -1
- package/dist/index.d.mts +5 -56
- package/dist/index.mjs +4 -284
- package/dist/logger.d.mts +26 -17
- package/dist/logger.mjs +10 -5
- package/dist/logger.mjs.map +1 -1
- package/dist/models/baseline-status.d.mts +29 -0
- package/dist/models/baseline-status.mjs +26 -0
- package/dist/models/baseline-status.mjs.map +1 -0
- package/dist/models/baseline.d.mts +33 -0
- package/dist/models/baseline.mjs +35 -13
- package/dist/models/baseline.mjs.map +1 -1
- package/dist/models/build.d.mts +87 -0
- package/dist/models/build.mjs +83 -35
- package/dist/models/build.mjs.map +1 -1
- package/dist/models/capture-attempt.d.mts +40 -0
- package/dist/models/capture-attempt.mjs +85 -0
- package/dist/models/capture-attempt.mjs.map +1 -0
- package/dist/models/capture-log.d.mts +21 -0
- package/dist/models/capture-log.mjs +44 -0
- package/dist/models/capture-log.mjs.map +1 -0
- package/dist/models/comment.d.mts +29 -0
- package/dist/models/comment.mjs +11 -8
- package/dist/models/comment.mjs.map +1 -1
- package/dist/models/content-ref.d.mts +21 -0
- package/dist/models/content-ref.mjs +49 -0
- package/dist/models/content-ref.mjs.map +1 -0
- package/dist/models/credentials.d.mts +36 -0
- package/dist/models/credentials.mjs +103 -0
- package/dist/models/credentials.mjs.map +1 -0
- package/dist/models/label.d.mts +58 -0
- package/dist/models/label.mjs +32 -27
- package/dist/models/label.mjs.map +1 -1
- package/dist/models/member.d.mts +34 -0
- package/dist/models/member.mjs +20 -11
- package/dist/models/member.mjs.map +1 -1
- package/dist/models/notification-channel.d.mts +52 -0
- package/dist/models/notification-channel.mjs +93 -0
- package/dist/models/notification-channel.mjs.map +1 -0
- package/dist/models/notification-subscription.d.mts +44 -0
- package/dist/models/notification-subscription.mjs +89 -0
- package/dist/models/notification-subscription.mjs.map +1 -0
- package/dist/models/project-group-mapping.d.mts +30 -0
- package/dist/models/project-group-mapping.mjs +46 -0
- package/dist/models/project-group-mapping.mjs.map +1 -0
- package/dist/models/project.d.mts +54 -0
- package/dist/models/project.mjs +15 -11
- package/dist/models/project.mjs.map +1 -1
- package/dist/models/snapshot.d.mts +58 -0
- package/dist/models/snapshot.mjs +13 -7
- package/dist/models/snapshot.mjs.map +1 -1
- package/dist/models/status-config.d.mts +38 -0
- package/dist/models/status-config.mjs +12 -11
- package/dist/models/status-config.mjs.map +1 -1
- package/dist/models/token.d.mts +44 -0
- package/dist/models/token.mjs +18 -15
- package/dist/models/token.mjs.map +1 -1
- package/dist/models/user.d.mts +42 -0
- package/dist/models/user.mjs +65 -0
- package/dist/models/user.mjs.map +1 -0
- package/dist/models/webhook.d.mts +50 -0
- package/dist/models/webhook.mjs +12 -10
- package/dist/models/webhook.mjs.map +1 -1
- package/dist/models.d.mts +22 -0
- package/dist/models.mjs +23 -0
- package/dist/paths.mjs +29 -0
- package/dist/paths.mjs.map +1 -1
- package/dist/retention.d.mts +45 -0
- package/dist/retention.mjs +145 -0
- package/dist/retention.mjs.map +1 -0
- package/dist/schema/baseline.d.mts +1 -0
- package/dist/schema/build.d.mts +8 -0
- package/dist/schema/capture-attempt.d.mts +38 -0
- package/dist/schema/comment.d.mts +1 -1
- package/dist/schema/content-ref.d.mts +13 -0
- package/dist/schema/member.d.mts +2 -0
- package/dist/schema/notification.d.mts +35 -0
- package/dist/schema/project-group-mapping.d.mts +15 -0
- package/dist/schema/project.d.mts +4 -0
- package/dist/schema/snapshot.d.mts +7 -0
- package/dist/schema/token.d.mts +2 -0
- package/dist/schema/user.d.mts +11 -1
- package/dist/schema.d.mts +9 -46
- package/dist/schema.mjs +1 -55
- package/dist/test-helpers/create-project.d.mts +15 -0
- package/dist/test-helpers/create-project.mjs +28 -0
- package/dist/test-helpers/create-project.mjs.map +1 -0
- package/dist/test-helpers/database-contract.d.mts +13 -0
- package/dist/test-helpers/database-contract.mjs +58 -0
- package/dist/test-helpers/database-contract.mjs.map +1 -0
- package/dist/test-helpers/fake-adapters.d.mts +14 -0
- package/dist/test-helpers/fake-adapters.mjs +20 -0
- package/dist/test-helpers/fake-adapters.mjs.map +1 -0
- package/dist/test-helpers/fake-database.d.mts +11 -0
- package/dist/test-helpers/fake-database.mjs +104 -0
- package/dist/test-helpers/fake-database.mjs.map +1 -0
- package/dist/test-helpers/fake-storage.d.mts +14 -0
- package/dist/test-helpers/fake-storage.mjs +49 -0
- package/dist/test-helpers/fake-storage.mjs.map +1 -0
- package/dist/test-helpers/fake-tables.mjs +276 -0
- package/dist/test-helpers/fake-tables.mjs.map +1 -0
- package/dist/test-helpers/git-contract.d.mts +11 -0
- package/dist/test-helpers/git-contract.mjs +34 -0
- package/dist/test-helpers/git-contract.mjs.map +1 -0
- package/dist/test-helpers/notifier-contract.d.mts +11 -0
- package/dist/test-helpers/notifier-contract.mjs +34 -0
- package/dist/test-helpers/notifier-contract.mjs.map +1 -0
- package/dist/test-helpers/queue-contract.d.mts +11 -0
- package/dist/test-helpers/queue-contract.mjs +64 -0
- package/dist/test-helpers/queue-contract.mjs.map +1 -0
- package/dist/test-helpers/runner-contract.d.mts +11 -0
- package/dist/test-helpers/runner-contract.mjs +32 -0
- package/dist/test-helpers/runner-contract.mjs.map +1 -0
- package/dist/test-helpers/sql-chunks.mjs +138 -0
- package/dist/test-helpers/sql-chunks.mjs.map +1 -0
- package/dist/test-helpers/storage-contract.d.mts +11 -0
- package/dist/test-helpers/storage-contract.mjs +87 -0
- package/dist/test-helpers/storage-contract.mjs.map +1 -0
- package/dist/test-helpers.d.mts +13 -0
- package/dist/test-helpers.mjs +14 -0
- package/dist/tracing.mjs +63 -0
- package/dist/tracing.mjs.map +1 -0
- package/dist/types.d.mts +38 -5
- package/dist/types.mjs +18 -5
- package/dist/types.mjs.map +1 -1
- package/dist/urls.d.mts +12 -1
- package/dist/urls.mjs +22 -3
- package/dist/urls.mjs.map +1 -1
- package/dist/utils/encrypt.d.mts +48 -0
- package/dist/utils/encrypt.mjs +67 -13
- package/dist/utils/encrypt.mjs.map +1 -1
- package/dist/utils/hash.d.mts +17 -0
- package/dist/utils/hash.mjs +8 -2
- package/dist/utils/hash.mjs.map +1 -1
- package/dist/utils/http.d.mts +58 -0
- package/dist/utils/http.mjs +147 -0
- package/dist/utils/http.mjs.map +1 -0
- package/dist/utils/mime.d.mts +9 -0
- package/dist/utils/mime.mjs +33 -0
- package/dist/utils/mime.mjs.map +1 -0
- package/dist/utils/path-security.d.mts +12 -0
- package/dist/utils/path-security.mjs +24 -0
- package/dist/utils/path-security.mjs.map +1 -0
- package/dist/utils/redact.d.mts +17 -0
- package/dist/utils/redact.mjs +42 -0
- package/dist/utils/redact.mjs.map +1 -0
- package/dist/utils/timing.d.mts +19 -0
- package/dist/utils/timing.mjs +46 -0
- package/dist/utils/timing.mjs.map +1 -0
- package/dist/utils/ulid.d.mts +10 -0
- package/dist/utils/ulid.mjs +8 -8
- package/dist/utils/ulid.mjs.map +1 -1
- package/dist/utils.d.mts +12 -0
- package/dist/utils.mjs +13 -0
- package/package.json +69 -28
- package/dist/adapter/auth.d.mts +0 -50
- package/dist/adapter/auth.mjs +0 -10
- package/dist/adapter/auth.mjs.map +0 -1
- package/dist/adapter/init.d.mts +0 -58
- package/dist/adapter/init.mjs +0 -93
- package/dist/adapter/init.mjs.map +0 -1
- package/dist/adapters/webhook-events.mjs +0 -55
- package/dist/adapters/webhook-events.mjs.map +0 -1
- package/dist/ddl.d.mts +0 -8
- package/dist/ddl.mjs +0 -158
- package/dist/ddl.mjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/middleware/auth-gate.mjs +0 -36
- package/dist/middleware/auth-gate.mjs.map +0 -1
- package/dist/middleware/csrf.mjs +0 -40
- package/dist/middleware/csrf.mjs.map +0 -1
- package/dist/middleware/rate-limit.mjs +0 -39
- package/dist/middleware/rate-limit.mjs.map +0 -1
- package/dist/middleware/request-log.mjs +0 -28
- package/dist/middleware/request-log.mjs.map +0 -1
- package/dist/middleware/store-scope.mjs +0 -29
- package/dist/middleware/store-scope.mjs.map +0 -1
- package/dist/pages/build-detail.mjs +0 -339
- package/dist/pages/build-detail.mjs.map +0 -1
- package/dist/pages/build-diff-comments.mjs +0 -113
- package/dist/pages/build-diff-comments.mjs.map +0 -1
- package/dist/pages/build-diff-header.mjs +0 -163
- package/dist/pages/build-diff-header.mjs.map +0 -1
- package/dist/pages/build-diff-nav.mjs +0 -66
- package/dist/pages/build-diff-nav.mjs.map +0 -1
- package/dist/pages/build-diff-viewer.mjs +0 -197
- package/dist/pages/build-diff-viewer.mjs.map +0 -1
- package/dist/pages/build-diff.mjs +0 -90
- package/dist/pages/build-diff.mjs.map +0 -1
- package/dist/pages/compute-jobs.mjs +0 -198
- package/dist/pages/compute-jobs.mjs.map +0 -1
- package/dist/pages/label-detail.mjs +0 -228
- package/dist/pages/label-detail.mjs.map +0 -1
- package/dist/pages/login.mjs +0 -78
- package/dist/pages/login.mjs.map +0 -1
- package/dist/pages/project-builds.mjs +0 -231
- package/dist/pages/project-builds.mjs.map +0 -1
- package/dist/pages/project-create.mjs +0 -169
- package/dist/pages/project-create.mjs.map +0 -1
- package/dist/pages/project-settings.mjs +0 -102
- package/dist/pages/project-settings.mjs.map +0 -1
- package/dist/pages/projects.mjs +0 -184
- package/dist/pages/projects.mjs.map +0 -1
- package/dist/pages/root.mjs +0 -94
- package/dist/pages/root.mjs.map +0 -1
- package/dist/pages/settings-general.mjs +0 -192
- package/dist/pages/settings-general.mjs.map +0 -1
- package/dist/pages/settings-labels.mjs +0 -150
- package/dist/pages/settings-labels.mjs.map +0 -1
- package/dist/pages/settings-members.mjs +0 -125
- package/dist/pages/settings-members.mjs.map +0 -1
- package/dist/pages/settings-status.mjs +0 -152
- package/dist/pages/settings-status.mjs.map +0 -1
- package/dist/pages/settings-tests.mjs +0 -149
- package/dist/pages/settings-tests.mjs.map +0 -1
- package/dist/pages/settings-tokens.mjs +0 -96
- package/dist/pages/settings-tokens.mjs.map +0 -1
- package/dist/pages/settings-webhooks.mjs +0 -150
- package/dist/pages/settings-webhooks.mjs.map +0 -1
- package/dist/pages/storybook.mjs +0 -96
- package/dist/pages/storybook.mjs.map +0 -1
- package/dist/retention/purge.mjs +0 -70
- package/dist/retention/purge.mjs.map +0 -1
- package/dist/routers/admin.mjs +0 -42
- package/dist/routers/admin.mjs.map +0 -1
- package/dist/routers/assets.mjs +0 -25
- package/dist/routers/assets.mjs.map +0 -1
- package/dist/routers/auth.mjs +0 -78
- package/dist/routers/auth.mjs.map +0 -1
- package/dist/routers/builds.handlers.mjs +0 -184
- package/dist/routers/builds.handlers.mjs.map +0 -1
- package/dist/routers/builds.mjs +0 -185
- package/dist/routers/builds.mjs.map +0 -1
- package/dist/routers/comments.mjs +0 -90
- package/dist/routers/comments.mjs.map +0 -1
- package/dist/routers/health.mjs +0 -137
- package/dist/routers/health.mjs.map +0 -1
- package/dist/routers/helpers.mjs +0 -82
- package/dist/routers/helpers.mjs.map +0 -1
- package/dist/routers/htmx.mjs +0 -20
- package/dist/routers/htmx.mjs.map +0 -1
- package/dist/routers/labels.mjs +0 -110
- package/dist/routers/labels.mjs.map +0 -1
- package/dist/routers/media.mjs +0 -55
- package/dist/routers/media.mjs.map +0 -1
- package/dist/routers/members.mjs +0 -102
- package/dist/routers/members.mjs.map +0 -1
- package/dist/routers/projects.mjs +0 -122
- package/dist/routers/projects.mjs.map +0 -1
- package/dist/routers/schemas.mjs +0 -224
- package/dist/routers/schemas.mjs.map +0 -1
- package/dist/routers/settings-general.mjs +0 -95
- package/dist/routers/settings-general.mjs.map +0 -1
- package/dist/routers/settings-labels.mjs +0 -49
- package/dist/routers/settings-labels.mjs.map +0 -1
- package/dist/routers/settings-members.mjs +0 -30
- package/dist/routers/settings-members.mjs.map +0 -1
- package/dist/routers/settings-status.mjs +0 -73
- package/dist/routers/settings-status.mjs.map +0 -1
- package/dist/routers/settings-tokens.mjs +0 -40
- package/dist/routers/settings-tokens.mjs.map +0 -1
- package/dist/routers/settings-webhooks.mjs +0 -63
- package/dist/routers/settings-webhooks.mjs.map +0 -1
- package/dist/routers/settings.handlers.mjs +0 -93
- package/dist/routers/settings.handlers.mjs.map +0 -1
- package/dist/routers/settings.mjs +0 -23
- package/dist/routers/settings.mjs.map +0 -1
- package/dist/routers/snapshots.mjs +0 -144
- package/dist/routers/snapshots.mjs.map +0 -1
- package/dist/routers/status-configs.mjs +0 -101
- package/dist/routers/status-configs.mjs.map +0 -1
- package/dist/routers/storybook.mjs +0 -120
- package/dist/routers/storybook.mjs.map +0 -1
- package/dist/routers/tokens.mjs +0 -81
- package/dist/routers/tokens.mjs.map +0 -1
- package/dist/routers/ui.mjs +0 -165
- package/dist/routers/ui.mjs.map +0 -1
- package/dist/routers/webhooks.mjs +0 -90
- package/dist/routers/webhooks.mjs.map +0 -1
- package/dist/schema/baseline.mjs +0 -22
- package/dist/schema/baseline.mjs.map +0 -1
- package/dist/schema/build.mjs +0 -29
- package/dist/schema/build.mjs.map +0 -1
- package/dist/schema/comment.mjs +0 -26
- package/dist/schema/comment.mjs.map +0 -1
- package/dist/schema/label.mjs +0 -30
- package/dist/schema/label.mjs.map +0 -1
- package/dist/schema/member.mjs +0 -19
- package/dist/schema/member.mjs.map +0 -1
- package/dist/schema/project.mjs +0 -25
- package/dist/schema/project.mjs.map +0 -1
- package/dist/schema/snapshot.mjs +0 -34
- package/dist/schema/snapshot.mjs.map +0 -1
- package/dist/schema/status-config.mjs +0 -20
- package/dist/schema/status-config.mjs.map +0 -1
- package/dist/schema/token.mjs +0 -19
- package/dist/schema/token.mjs.map +0 -1
- package/dist/schema/user.mjs +0 -19
- package/dist/schema/user.mjs.map +0 -1
- package/dist/schema/webhook.mjs +0 -20
- package/dist/schema/webhook.mjs.map +0 -1
- package/dist/schema.mjs.map +0 -1
- package/dist/store.mjs +0 -20
- package/dist/store.mjs.map +0 -1
- package/dist/ui/document.mjs +0 -348
- package/dist/ui/document.mjs.map +0 -1
- package/dist/ui/feedback.mjs +0 -24
- package/dist/ui/feedback.mjs.map +0 -1
- package/dist/ui/forms.mjs +0 -117
- package/dist/ui/forms.mjs.map +0 -1
- package/dist/ui/styles.mjs +0 -174
- package/dist/ui/styles.mjs.map +0 -1
- package/dist/ui/theme.mjs +0 -44
- package/dist/ui/theme.mjs.map +0 -1
package/dist/paths.mjs
CHANGED
|
@@ -1,25 +1,54 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
+
import { isSafeSegment } from "./utils/path-security.mjs";
|
|
4
5
|
//#region src/utils/paths.ts
|
|
6
|
+
/** Storage path builders. Every segment is validated — a third-party
|
|
7
|
+
* capture runner echoing `story.id = "../../x"` must fail here, not in an
|
|
8
|
+
* adapter with its own key-jailing quirks. */
|
|
9
|
+
/** Throw when any key segment could escape its storage prefix. */
|
|
10
|
+
function assertSegments(segments) {
|
|
11
|
+
const bad = segments.filter((segment) => !isSafeSegment(segment) || segment.length === 0);
|
|
12
|
+
if (bad.length > 0) throw new Error(`Unsafe storage path segment: ${bad.join(",")}`);
|
|
13
|
+
}
|
|
5
14
|
/** Storage path for a captured snapshot screenshot. */
|
|
6
15
|
function screenshotPath(projectId, buildId, storyId, viewport) {
|
|
16
|
+
assertSegments([
|
|
17
|
+
projectId,
|
|
18
|
+
buildId,
|
|
19
|
+
storyId,
|
|
20
|
+
viewport
|
|
21
|
+
]);
|
|
7
22
|
return `${projectId}/builds/${buildId}/screenshots/${storyId}/${viewport}.png`;
|
|
8
23
|
}
|
|
9
24
|
/** Storage path for a snapshot diff overlay image. */
|
|
10
25
|
function diffPath(projectId, buildId, storyId, viewport) {
|
|
26
|
+
assertSegments([
|
|
27
|
+
projectId,
|
|
28
|
+
buildId,
|
|
29
|
+
storyId,
|
|
30
|
+
viewport
|
|
31
|
+
]);
|
|
11
32
|
return `${projectId}/builds/${buildId}/diffs/${storyId}/${viewport}.png`;
|
|
12
33
|
}
|
|
13
34
|
/** Storage path for a branch baseline screenshot. */
|
|
14
35
|
function baselinePath(projectId, branch, storyId, viewport) {
|
|
36
|
+
assertSegments([
|
|
37
|
+
projectId,
|
|
38
|
+
branch,
|
|
39
|
+
storyId,
|
|
40
|
+
viewport
|
|
41
|
+
]);
|
|
15
42
|
return `${projectId}/baselines/${branch}/${storyId}/${viewport}.png`;
|
|
16
43
|
}
|
|
17
44
|
/** Storage prefix for an extracted published Storybook. */
|
|
18
45
|
function storybookDir(projectId, buildId) {
|
|
46
|
+
assertSegments([projectId, buildId]);
|
|
19
47
|
return `${projectId}/builds/${buildId}/storybook`;
|
|
20
48
|
}
|
|
21
49
|
/** Storage path for an uploaded Storybook zip. */
|
|
22
50
|
function storybookZipPath(projectId, buildId) {
|
|
51
|
+
assertSegments([projectId, buildId]);
|
|
23
52
|
return `${projectId}/builds/${buildId}/storybook.zip`;
|
|
24
53
|
}
|
|
25
54
|
//#endregion
|
package/dist/paths.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.mjs","names":[],"sources":["../src/utils/paths.ts"],"sourcesContent":["/** Storage path for a captured snapshot screenshot. */\nexport function screenshotPath(\n projectId: string,\n buildId: string,\n storyId: string,\n viewport: string,\n): string {\n return `${projectId}/builds/${buildId}/screenshots/${storyId}/${viewport}.png`;\n}\n\n/** Storage path for a snapshot diff overlay image. */\nexport function diffPath(\n projectId: string,\n buildId: string,\n storyId: string,\n viewport: string,\n): string {\n return `${projectId}/builds/${buildId}/diffs/${storyId}/${viewport}.png`;\n}\n\n/** Storage path for a branch baseline screenshot. */\nexport function baselinePath(\n projectId: string,\n branch: string,\n storyId: string,\n viewport: string,\n): string {\n return `${projectId}/baselines/${branch}/${storyId}/${viewport}.png`;\n}\n\n/** Storage prefix for an extracted published Storybook. */\nexport function storybookDir(projectId: string, buildId: string): string {\n return `${projectId}/builds/${buildId}/storybook`;\n}\n\n/** Storage path for an uploaded Storybook zip. */\nexport function storybookZipPath(projectId: string, buildId: string): string {\n return `${projectId}/builds/${buildId}/storybook.zip`;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"paths.mjs","names":[],"sources":["../src/utils/paths.ts"],"sourcesContent":["/** Storage path builders. Every segment is validated — a third-party\n * capture runner echoing `story.id = \"../../x\"` must fail here, not in an\n * adapter with its own key-jailing quirks. */\nimport { isSafeSegment } from \"./path-security.ts\";\n\n/** Throw when any key segment could escape its storage prefix. */\nfunction assertSegments(segments: string[]): void {\n const bad = segments.filter((segment) => !isSafeSegment(segment) || segment.length === 0);\n if (bad.length > 0) {\n throw new Error(`Unsafe storage path segment: ${bad.join(\",\")}`);\n }\n}\n/** Storage path for a captured snapshot screenshot. */\nexport function screenshotPath(\n projectId: string,\n buildId: string,\n storyId: string,\n viewport: string,\n): string {\n assertSegments([projectId, buildId, storyId, viewport]);\n return `${projectId}/builds/${buildId}/screenshots/${storyId}/${viewport}.png`;\n}\n\n/** Storage path for a snapshot diff overlay image. */\nexport function diffPath(\n projectId: string,\n buildId: string,\n storyId: string,\n viewport: string,\n): string {\n assertSegments([projectId, buildId, storyId, viewport]);\n return `${projectId}/builds/${buildId}/diffs/${storyId}/${viewport}.png`;\n}\n\n/** Storage path for a branch baseline screenshot. */\nexport function baselinePath(\n projectId: string,\n branch: string,\n storyId: string,\n viewport: string,\n): string {\n assertSegments([projectId, branch, storyId, viewport]);\n return `${projectId}/baselines/${branch}/${storyId}/${viewport}.png`;\n}\n\n/** Storage prefix for an extracted published Storybook. */\nexport function storybookDir(projectId: string, buildId: string): string {\n assertSegments([projectId, buildId]);\n return `${projectId}/builds/${buildId}/storybook`;\n}\n\n/** Storage path for an uploaded Storybook zip. */\nexport function storybookZipPath(projectId: string, buildId: string): string {\n assertSegments([projectId, buildId]);\n return `${projectId}/builds/${buildId}/storybook.zip`;\n}\n"],"mappings":";;;;;;;;;AAMA,SAAS,eAAe,UAA0B;CAChD,MAAM,MAAM,SAAS,QAAQ,YAAY,CAAC,cAAc,OAAO,KAAK,QAAQ,WAAW,CAAC;CACxF,IAAI,IAAI,SAAS,GACf,MAAM,IAAI,MAAM,gCAAgC,IAAI,KAAK,GAAG,GAAG;AAEnE;;AAEA,SAAgB,eACd,WACA,SACA,SACA,UACQ;CACR,eAAe;EAAC;EAAW;EAAS;EAAS;CAAQ,CAAC;CACtD,OAAO,GAAG,UAAU,UAAU,QAAQ,eAAe,QAAQ,GAAG,SAAS;AAC3E;;AAGA,SAAgB,SACd,WACA,SACA,SACA,UACQ;CACR,eAAe;EAAC;EAAW;EAAS;EAAS;CAAQ,CAAC;CACtD,OAAO,GAAG,UAAU,UAAU,QAAQ,SAAS,QAAQ,GAAG,SAAS;AACrE;;AAGA,SAAgB,aACd,WACA,QACA,SACA,UACQ;CACR,eAAe;EAAC;EAAW;EAAQ;EAAS;CAAQ,CAAC;CACrD,OAAO,GAAG,UAAU,aAAa,OAAO,GAAG,QAAQ,GAAG,SAAS;AACjE;;AAGA,SAAgB,aAAa,WAAmB,SAAyB;CACvE,eAAe,CAAC,WAAW,OAAO,CAAC;CACnC,OAAO,GAAG,UAAU,UAAU,QAAQ;AACxC;;AAGA,SAAgB,iBAAiB,WAAmB,SAAyB;CAC3E,eAAe,CAAC,WAAW,OAAO,CAAC;CACnC,OAAO,GAAG,UAAU,UAAU,QAAQ;AACxC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { DatabaseAdapter } from "./adapter/database.mjs";
|
|
4
|
+
import { StorageAdapter } from "./adapter/storage.mjs";
|
|
5
|
+
import { Project } from "./schema/project.mjs";
|
|
6
|
+
import { Logger } from "pino";
|
|
7
|
+
import { Table } from "drizzle-orm";
|
|
8
|
+
//#region src/retention/purge.d.ts
|
|
9
|
+
/** Table handles for retention queries. */
|
|
10
|
+
interface RetentionTables {
|
|
11
|
+
builds: Table;
|
|
12
|
+
buildLabels: Table;
|
|
13
|
+
baselines: Table;
|
|
14
|
+
}
|
|
15
|
+
/** Removes expired transient builds while keeping baselines and persistent builds. */
|
|
16
|
+
declare class Retention {
|
|
17
|
+
private readonly db;
|
|
18
|
+
private readonly storage;
|
|
19
|
+
private readonly tables;
|
|
20
|
+
private readonly logger?;
|
|
21
|
+
constructor(db: DatabaseAdapter, storage: StorageAdapter, tables: RetentionTables, logger?: Logger | undefined);
|
|
22
|
+
purge(project: Project, options: PurgeOptions): Promise<PurgeResult>;
|
|
23
|
+
private removeBuild;
|
|
24
|
+
private latestPerBranch;
|
|
25
|
+
private deleteBuildFiles;
|
|
26
|
+
purgeStaleBranches(project: Project, ttlDays: number): Promise<BranchGcResult>;
|
|
27
|
+
}
|
|
28
|
+
/** Options controlling which builds a retention purge removes. */
|
|
29
|
+
interface PurgeOptions {
|
|
30
|
+
ttlDays: number;
|
|
31
|
+
keepLatestPerBranch: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** Counts of builds and files removed by a retention purge. */
|
|
34
|
+
interface PurgeResult {
|
|
35
|
+
removedBuilds: number;
|
|
36
|
+
removedFiles: number;
|
|
37
|
+
}
|
|
38
|
+
/** Counts of stale branches and baselines removed. */
|
|
39
|
+
interface BranchGcResult {
|
|
40
|
+
removedBranches: number;
|
|
41
|
+
removedBaselines: number;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { BranchGcResult, PurgeOptions, PurgeResult, Retention, RetentionTables };
|
|
45
|
+
//# sourceMappingURL=retention.d.mts.map
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { TERMINAL_BUILD_STATUSES } from "./types.mjs";
|
|
5
|
+
import { BuildModel } from "./models/build.mjs";
|
|
6
|
+
import { BaselineModel } from "./models/baseline.mjs";
|
|
7
|
+
import { LabelModel } from "./models/label.mjs";
|
|
8
|
+
import { and, desc, eq, getTableColumns, inArray, lt } from "drizzle-orm";
|
|
9
|
+
//#region src/retention/purge.ts
|
|
10
|
+
/** Removes expired transient builds while keeping baselines and persistent builds. */
|
|
11
|
+
var Retention = class {
|
|
12
|
+
db;
|
|
13
|
+
storage;
|
|
14
|
+
tables;
|
|
15
|
+
logger;
|
|
16
|
+
constructor(db, storage, tables, logger) {
|
|
17
|
+
this.db = db;
|
|
18
|
+
this.storage = storage;
|
|
19
|
+
this.tables = tables;
|
|
20
|
+
this.logger = logger;
|
|
21
|
+
}
|
|
22
|
+
async purge(project, options) {
|
|
23
|
+
const cutoff = (/* @__PURE__ */ new Date(Date.now() - options.ttlDays * 864e5)).toISOString();
|
|
24
|
+
const candidates = await this.db.list(this.tables.builds, { where: and(eq(getTableColumns(this.tables.builds)["projectId"], project.id), inArray(getTableColumns(this.tables.builds)["status"], [...TERMINAL_BUILD_STATUSES]), lt(getTableColumns(this.tables.builds)["updatedAt"], cutoff)) });
|
|
25
|
+
const keep = options.keepLatestPerBranch ? await this.latestPerBranch(project.id) : /* @__PURE__ */ new Set();
|
|
26
|
+
const labelModel = new LabelModel(this.db, this.tables);
|
|
27
|
+
const buildIds = (await Promise.all(candidates.map(async (build) => {
|
|
28
|
+
const buildId = build.id;
|
|
29
|
+
if (keep.has(buildId) || await labelModel.hasPersistent(project.id, buildId)) return null;
|
|
30
|
+
return buildId;
|
|
31
|
+
}))).filter((id) => id !== null);
|
|
32
|
+
const results = await Promise.all(buildIds.map(async (buildId) => ({
|
|
33
|
+
files: await this.deleteBuildFiles(project.id, buildId),
|
|
34
|
+
removed: await this.removeBuild(buildId)
|
|
35
|
+
})));
|
|
36
|
+
const removedBuilds = results.filter((r) => r.removed).length;
|
|
37
|
+
const removedFiles = results.reduce((sum, r) => sum + r.files, 0);
|
|
38
|
+
this.logger?.info({
|
|
39
|
+
projectId: project.id,
|
|
40
|
+
removedBuilds,
|
|
41
|
+
removedFiles
|
|
42
|
+
}, "build retention purge complete");
|
|
43
|
+
return {
|
|
44
|
+
removedBuilds,
|
|
45
|
+
removedFiles
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async removeBuild(buildId) {
|
|
49
|
+
await new BuildModel(this.db, this.tables).remove(buildId);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
async latestPerBranch(projectId) {
|
|
53
|
+
const rows = await this.db.list(this.tables.builds, {
|
|
54
|
+
where: eq(getTableColumns(this.tables.builds)["projectId"], projectId),
|
|
55
|
+
orderBy: desc(getTableColumns(this.tables.builds)["updatedAt"])
|
|
56
|
+
});
|
|
57
|
+
const latest = /* @__PURE__ */ new Map();
|
|
58
|
+
for (const row of rows) {
|
|
59
|
+
const branch = row.gitBranch;
|
|
60
|
+
if (!latest.get(branch)) latest.set(branch, row.id);
|
|
61
|
+
}
|
|
62
|
+
return new Set(latest.values());
|
|
63
|
+
}
|
|
64
|
+
async deleteBuildFiles(projectId, buildId) {
|
|
65
|
+
const prefix = `${projectId}/builds/${buildId}/`;
|
|
66
|
+
const manifestPath = `${prefix}storybook/manifest.json`;
|
|
67
|
+
let manifestFiles = [];
|
|
68
|
+
try {
|
|
69
|
+
if (await this.storage.exists(manifestPath)) {
|
|
70
|
+
const raw = await this.storage.read(manifestPath);
|
|
71
|
+
const manifest = JSON.parse(raw.toString("utf8"));
|
|
72
|
+
manifestFiles = Object.values(manifest);
|
|
73
|
+
}
|
|
74
|
+
} catch {}
|
|
75
|
+
const files = await this.storage.list(prefix);
|
|
76
|
+
await Promise.all(files.map(async (file) => {
|
|
77
|
+
await this.storage.delete(file);
|
|
78
|
+
}));
|
|
79
|
+
for (const hash of manifestFiles) try {
|
|
80
|
+
const contentRefs = this.db.tables.contentRefs;
|
|
81
|
+
const existing = await this.db.get(contentRefs, hash);
|
|
82
|
+
if (existing) {
|
|
83
|
+
const refCount = existing.refCount;
|
|
84
|
+
if (refCount <= 1) await this.db.update(contentRefs, hash, {
|
|
85
|
+
refCount: 0,
|
|
86
|
+
lastSeenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
87
|
+
});
|
|
88
|
+
else await this.db.update(contentRefs, hash, {
|
|
89
|
+
refCount: refCount - 1,
|
|
90
|
+
lastSeenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
} catch {}
|
|
94
|
+
try {
|
|
95
|
+
const contentRefs = this.db.tables.contentRefs;
|
|
96
|
+
const cutoff = (/* @__PURE__ */ new Date(Date.now() - 6048e5)).toISOString();
|
|
97
|
+
const all = await this.db.list(contentRefs);
|
|
98
|
+
for (const row of all) if (row.refCount === 0 && row.lastSeenAt < cutoff) {
|
|
99
|
+
await this.storage.delete(`content/${row.hash}`).catch(() => {});
|
|
100
|
+
await this.db.remove(contentRefs, row.hash);
|
|
101
|
+
}
|
|
102
|
+
} catch {}
|
|
103
|
+
return files.length;
|
|
104
|
+
}
|
|
105
|
+
async purgeStaleBranches(project, ttlDays) {
|
|
106
|
+
if (ttlDays <= 0) return {
|
|
107
|
+
removedBranches: 0,
|
|
108
|
+
removedBaselines: 0
|
|
109
|
+
};
|
|
110
|
+
const cutoff = (/* @__PURE__ */ new Date(Date.now() - ttlDays * 864e5)).toISOString();
|
|
111
|
+
const stale = collectStaleBranches(await this.db.list(this.tables.builds, { where: eq(getTableColumns(this.tables.builds)["projectId"], project.id) }), project.gitDefaultBranch, cutoff);
|
|
112
|
+
if (stale.size === 0) return {
|
|
113
|
+
removedBranches: 0,
|
|
114
|
+
removedBaselines: 0
|
|
115
|
+
};
|
|
116
|
+
const removedBaselines = await new BaselineModel(this.db, this.tables, this.storage).removeStaleBranches(project.id, stale);
|
|
117
|
+
this.logger?.info({
|
|
118
|
+
projectId: project.id,
|
|
119
|
+
removedBranches: stale.size,
|
|
120
|
+
removedBaselines
|
|
121
|
+
}, "branch GC complete");
|
|
122
|
+
return {
|
|
123
|
+
removedBranches: stale.size,
|
|
124
|
+
removedBaselines
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
function collectStaleBranches(rows, defaultBranch, cutoff) {
|
|
129
|
+
const latestAt = branchLatestAt(rows);
|
|
130
|
+
const stale = /* @__PURE__ */ new Set();
|
|
131
|
+
for (const [branch, updatedAt] of latestAt) if (branch !== defaultBranch && updatedAt < cutoff) stale.add(branch);
|
|
132
|
+
return stale;
|
|
133
|
+
}
|
|
134
|
+
function branchLatestAt(rows) {
|
|
135
|
+
const latestAt = /* @__PURE__ */ new Map();
|
|
136
|
+
for (const row of rows) {
|
|
137
|
+
const current = latestAt.get(row.gitBranch);
|
|
138
|
+
if (!current || row.updatedAt > current) latestAt.set(row.gitBranch, row.updatedAt);
|
|
139
|
+
}
|
|
140
|
+
return latestAt;
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
export { Retention };
|
|
144
|
+
|
|
145
|
+
//# sourceMappingURL=retention.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention.mjs","names":[],"sources":["../src/retention/purge.ts"],"sourcesContent":["import { and, desc, eq, getTableColumns, inArray, lt } from \"drizzle-orm\";\nimport type { SQLWrapper, Table } from \"drizzle-orm\";\nimport type { Logger } from \"pino\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { StorageAdapter } from \"../adapters/storage.ts\";\nimport { BaselineModel } from \"../models/baseline.ts\";\nimport { BuildModel, type BuildTables } from \"../models/build.ts\";\nimport { LabelModel, type LabelTables } from \"../models/label.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport { TERMINAL_BUILD_STATUSES } from \"../types.ts\";\n\n/** Table handles for retention queries. */\nexport interface RetentionTables {\n builds: Table;\n buildLabels: Table;\n baselines: Table;\n}\n\n/** Removes expired transient builds while keeping baselines and persistent builds. */\nexport class Retention {\n constructor(\n private readonly db: DatabaseAdapter,\n private readonly storage: StorageAdapter,\n private readonly tables: RetentionTables,\n private readonly logger?: Logger,\n ) {}\n\n async purge(project: Project, options: PurgeOptions): Promise<PurgeResult> {\n const cutoff = new Date(Date.now() - options.ttlDays * 86_400_000).toISOString();\n const candidates = await this.db.list(this.tables.builds, {\n where: and(\n eq(getTableColumns(this.tables.builds)[\"projectId\"] as unknown as SQLWrapper, project.id),\n inArray(getTableColumns(this.tables.builds)[\"status\"] as unknown as SQLWrapper, [\n ...TERMINAL_BUILD_STATUSES,\n ]),\n lt(getTableColumns(this.tables.builds)[\"updatedAt\"] as unknown as SQLWrapper, cutoff),\n ),\n });\n\n const keep = options.keepLatestPerBranch\n ? await this.latestPerBranch(project.id)\n : new Set<string>();\n const labelModel = new LabelModel(this.db, this.tables as unknown as LabelTables);\n const target = await Promise.all(\n candidates.map(async (build) => {\n const buildId = (build as { id: string }).id;\n if (keep.has(buildId) || (await labelModel.hasPersistent(project.id, buildId))) {\n return null;\n }\n return buildId;\n }),\n );\n\n const buildIds = target.filter((id): id is string => id !== null);\n const results = await Promise.all(\n buildIds.map(async (buildId) => ({\n files: await this.deleteBuildFiles(project.id, buildId),\n removed: await this.removeBuild(buildId),\n })),\n );\n const removedBuilds = results.filter((r: { removed: boolean }) => r.removed).length;\n const removedFiles = results.reduce((sum: number, r: { files: number }) => sum + r.files, 0);\n this.logger?.info(\n { projectId: project.id, removedBuilds, removedFiles },\n \"build retention purge complete\",\n );\n return { removedBuilds, removedFiles };\n }\n\n private async removeBuild(buildId: string): Promise<boolean> {\n await new BuildModel(this.db, this.tables as unknown as BuildTables).remove(buildId);\n return true;\n }\n\n private async latestPerBranch(projectId: string): Promise<Set<string>> {\n const rows = (await this.db.list(this.tables.builds, {\n where: eq(\n getTableColumns(this.tables.builds)[\"projectId\"] as unknown as SQLWrapper,\n projectId,\n ),\n orderBy: desc(getTableColumns(this.tables.builds)[\"updatedAt\"] as unknown as SQLWrapper),\n })) as unknown as { gitBranch: string; id: string }[];\n const latest = new Map<string, string>();\n for (const row of rows) {\n const branch = row.gitBranch;\n const current = latest.get(branch);\n if (!current) {\n latest.set(branch, row.id);\n }\n }\n return new Set(latest.values());\n }\n\n private async deleteBuildFiles(projectId: string, buildId: string): Promise<number> {\n const prefix = `${projectId}/builds/${buildId}/`;\n const manifestPath = `${prefix}storybook/manifest.json`;\n let manifestFiles: string[] = [];\n try {\n if (await this.storage.exists(manifestPath)) {\n const raw = await this.storage.read(manifestPath);\n const manifest = JSON.parse(raw.toString(\"utf8\")) as Record<string, string>;\n manifestFiles = Object.values(manifest);\n }\n } catch {\n // ignore — manifest may not exist for old builds\n }\n const files = await this.storage.list(prefix);\n await Promise.all(\n files.map(async (file) => {\n await this.storage.delete(file);\n }),\n );\n // Decrement content refs for this build's manifest\n for (const hash of manifestFiles) {\n try {\n const contentRefs = this.db.tables.contentRefs;\n const existing = (await this.db.get(contentRefs, hash)) as unknown as {\n refCount: number;\n } | null;\n // oxlint-disable-next-line unicorn/prefer-ternary -- refCount check is clearer as if/else\n if (existing) {\n const refCount = existing.refCount;\n // oxlint-disable-next-line unicorn/prefer-ternary -- grace logic is clearer as if/else\n if (refCount <= 1) {\n // Keep for 7-day grace: set refCount 0 and update lastSeenAt, don't delete yet\n await this.db.update(contentRefs, hash, {\n refCount: 0,\n lastSeenAt: new Date().toISOString(),\n });\n } else {\n await this.db.update(contentRefs, hash, {\n refCount: refCount - 1,\n lastSeenAt: new Date().toISOString(),\n });\n }\n }\n } catch {\n // ignore — content_refs may not exist\n }\n }\n // GC stale content_refs with 7-day grace\n try {\n const contentRefs = this.db.tables.contentRefs;\n const cutoff = new Date(Date.now() - 7 * 86_400_000).toISOString();\n const all = (await this.db.list(contentRefs)) as unknown as {\n hash: string;\n refCount: number;\n lastSeenAt: string;\n }[];\n for (const row of all) {\n if (row.refCount === 0 && row.lastSeenAt < cutoff) {\n await this.storage.delete(`content/${row.hash}`).catch(() => {\n // ignore storage delete failure\n });\n await this.db.remove(contentRefs, row.hash);\n }\n }\n } catch {\n // ignore — content_refs may not exist\n }\n return files.length;\n }\n\n async purgeStaleBranches(project: Project, ttlDays: number): Promise<BranchGcResult> {\n if (ttlDays <= 0) {\n return { removedBranches: 0, removedBaselines: 0 };\n }\n const cutoff = new Date(Date.now() - ttlDays * 86_400_000).toISOString();\n const rows = (await this.db.list(this.tables.builds, {\n where: eq(\n getTableColumns(this.tables.builds)[\"projectId\"] as unknown as SQLWrapper,\n project.id,\n ),\n })) as unknown as { gitBranch: string; updatedAt: string }[];\n const stale = collectStaleBranches(rows, project.gitDefaultBranch, cutoff);\n if (stale.size === 0) {\n return { removedBranches: 0, removedBaselines: 0 };\n }\n const baselines = new BaselineModel(this.db, this.tables, this.storage);\n const removedBaselines = await baselines.removeStaleBranches(project.id, stale);\n this.logger?.info(\n { projectId: project.id, removedBranches: stale.size, removedBaselines },\n \"branch GC complete\",\n );\n return { removedBranches: stale.size, removedBaselines };\n }\n}\n\n/** Options controlling which builds a retention purge removes. */\nexport interface PurgeOptions {\n ttlDays: number;\n keepLatestPerBranch: boolean;\n}\n\n/** Counts of builds and files removed by a retention purge. */\nexport interface PurgeResult {\n removedBuilds: number;\n removedFiles: number;\n}\n\n/** Counts of stale branches and baselines removed. */\nexport interface BranchGcResult {\n removedBranches: number;\n removedBaselines: number;\n}\n\nfunction collectStaleBranches(\n rows: { gitBranch: string; updatedAt: string }[],\n defaultBranch: string,\n cutoff: string,\n): Set<string> {\n const latestAt = branchLatestAt(rows);\n const stale = new Set<string>();\n for (const [branch, updatedAt] of latestAt) {\n if (branch !== defaultBranch && updatedAt < cutoff) {\n stale.add(branch);\n }\n }\n return stale;\n}\n\nfunction branchLatestAt(rows: { gitBranch: string; updatedAt: string }[]): Map<string, string> {\n const latestAt = new Map<string, string>();\n for (const row of rows) {\n const current = latestAt.get(row.gitBranch);\n if (!current || row.updatedAt > current) {\n latestAt.set(row.gitBranch, row.updatedAt);\n }\n }\n return latestAt;\n}\n"],"mappings":"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"}
|
package/dist/schema/build.d.mts
CHANGED
|
@@ -18,6 +18,14 @@ interface Build {
|
|
|
18
18
|
changedCount: number;
|
|
19
19
|
approvedCount: number;
|
|
20
20
|
rejectedCount: number;
|
|
21
|
+
/** Affected capture enabled for this build (default true). */
|
|
22
|
+
affectedOnly: boolean;
|
|
23
|
+
/** Ancestor commit the affected set was computed against, if any. */
|
|
24
|
+
baselineSha: string | null;
|
|
25
|
+
/** JSON array of repo-relative changed files, if computed. */
|
|
26
|
+
changedFiles: string | null;
|
|
27
|
+
/** JSON array of affected story import paths; null means full capture. */
|
|
28
|
+
affectedImportPaths: string | null;
|
|
21
29
|
createdAt: string;
|
|
22
30
|
updatedAt: string;
|
|
23
31
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { JobStatus } from "../adapter/capture-queue.mjs";
|
|
4
|
+
//#region src/schema/capture-attempt.d.ts
|
|
5
|
+
/** A capture attempt row: one queued run of a build's capture pipeline. */
|
|
6
|
+
interface CaptureAttempt {
|
|
7
|
+
id: string;
|
|
8
|
+
projectId: string;
|
|
9
|
+
buildId: string;
|
|
10
|
+
attemptNo: number;
|
|
11
|
+
status: JobStatus;
|
|
12
|
+
error: string | null;
|
|
13
|
+
reqId: string | null;
|
|
14
|
+
storyCount: number;
|
|
15
|
+
failedCount: number;
|
|
16
|
+
queuedAt: string;
|
|
17
|
+
startedAt: string | null;
|
|
18
|
+
finishedAt: string | null;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
updatedAt: string;
|
|
21
|
+
}
|
|
22
|
+
/** Log levels stored per capture attempt. */
|
|
23
|
+
type CaptureLogLevel = "debug" | "info" | "warn" | "error";
|
|
24
|
+
/** A single log line captured for a build attempt. */
|
|
25
|
+
interface CaptureLog {
|
|
26
|
+
id: string;
|
|
27
|
+
projectId: string;
|
|
28
|
+
buildId: string;
|
|
29
|
+
attemptId: string;
|
|
30
|
+
seq: number;
|
|
31
|
+
level: CaptureLogLevel;
|
|
32
|
+
message: string;
|
|
33
|
+
fields: string | null;
|
|
34
|
+
createdAt: string;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { CaptureAttempt, CaptureLog, CaptureLogLevel };
|
|
38
|
+
//# sourceMappingURL=capture-attempt.d.mts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/schema/content-ref.d.ts
|
|
4
|
+
/** Content ref row for deduplicated assets. */
|
|
5
|
+
interface ContentRef {
|
|
6
|
+
hash: string;
|
|
7
|
+
refCount: number;
|
|
8
|
+
lastSeenAt: string;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { ContentRef };
|
|
13
|
+
//# sourceMappingURL=content-ref.d.mts.map
|
package/dist/schema/member.d.mts
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/schema/notification.d.ts
|
|
4
|
+
/** A project (or site-wide) notification channel row. */
|
|
5
|
+
interface NotificationChannelRow {
|
|
6
|
+
id: string;
|
|
7
|
+
/** Owning project, or null for site-wide admin (`sys:*`) channels. */
|
|
8
|
+
projectId: string | null;
|
|
9
|
+
/** Provider kind (e.g. "slack-webhook", "teams-workflow", "email"). */
|
|
10
|
+
provider: string;
|
|
11
|
+
/** JSON-serialized provider config (toggles, addresses; never secrets). */
|
|
12
|
+
config: string;
|
|
13
|
+
/** AES-256-GCM secret (webhook URL / SMTP pass), null when none. */
|
|
14
|
+
secretEncrypted: string | null;
|
|
15
|
+
/** JSON array of subscribed events, or null for all. */
|
|
16
|
+
events: string | null;
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
}
|
|
21
|
+
/** A per-user opt-in row for project notifications. */
|
|
22
|
+
interface NotificationSubscriptionRow {
|
|
23
|
+
id: string;
|
|
24
|
+
projectId: string;
|
|
25
|
+
userId: string;
|
|
26
|
+
/** JSON array of subscribed events, or null for all. */
|
|
27
|
+
events: string | null;
|
|
28
|
+
/** JSON array of channels (e.g. ["email"]); v1 supports email only. */
|
|
29
|
+
via: string | null;
|
|
30
|
+
enabled: boolean;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { NotificationChannelRow, NotificationSubscriptionRow };
|
|
35
|
+
//# sourceMappingURL=notification.d.mts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { ProjectRole } from "../types.mjs";
|
|
4
|
+
//#region src/schema/project-group-mapping.d.ts
|
|
5
|
+
/** An identity-provider group to project-role mapping row. */
|
|
6
|
+
interface ProjectGroupMapping {
|
|
7
|
+
id: string;
|
|
8
|
+
projectId: string;
|
|
9
|
+
groupName: string;
|
|
10
|
+
role: ProjectRole;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { ProjectGroupMapping };
|
|
15
|
+
//# sourceMappingURL=project-group-mapping.d.mts.map
|
|
@@ -14,6 +14,10 @@ interface Project {
|
|
|
14
14
|
storybookMeta: string | null | undefined;
|
|
15
15
|
executePlay: boolean;
|
|
16
16
|
playTimeoutMs: number;
|
|
17
|
+
runA11y?: boolean;
|
|
18
|
+
browser?: string;
|
|
19
|
+
viewports?: string | null;
|
|
20
|
+
automigrate?: boolean;
|
|
17
21
|
createdAt: string;
|
|
18
22
|
updatedAt: string;
|
|
19
23
|
}
|
|
@@ -22,6 +22,13 @@ interface Snapshot {
|
|
|
22
22
|
status: SnapshotStatus;
|
|
23
23
|
reviewedBy: string | null;
|
|
24
24
|
reviewedAt: string | null;
|
|
25
|
+
infraHash: string | null;
|
|
26
|
+
/** True when inherited unchanged from the baseline without rendering. */
|
|
27
|
+
inherited: boolean;
|
|
28
|
+
/** Baseline row the diff was computed against (null: no baseline, or legacy row). */
|
|
29
|
+
baselineId: string | null;
|
|
30
|
+
/** That baseline's `updatedAt` at diff time; compared on approval to detect drift. */
|
|
31
|
+
baselineVersion: string | null;
|
|
25
32
|
createdAt: string;
|
|
26
33
|
updatedAt: string;
|
|
27
34
|
}
|
package/dist/schema/token.d.mts
CHANGED
package/dist/schema/user.d.mts
CHANGED
|
@@ -2,6 +2,8 @@ import __tsdown_shims_path from 'node:path';
|
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
3
|
import { SiteRole } from "../types.mjs";
|
|
4
4
|
//#region src/schema/user.d.ts
|
|
5
|
+
/** How a user authenticates. */
|
|
6
|
+
type AuthProvider = "local" | "oidc" | "shared";
|
|
5
7
|
/** A user row. */
|
|
6
8
|
interface User {
|
|
7
9
|
id: string;
|
|
@@ -11,7 +13,15 @@ interface User {
|
|
|
11
13
|
role: SiteRole;
|
|
12
14
|
lastLoginAt: string | null;
|
|
13
15
|
createdAt: string;
|
|
16
|
+
/** Scrypt password hash for local accounts, null for SSO/shared users. */
|
|
17
|
+
passwordHash?: string | null;
|
|
18
|
+
/** User-edited display name that survives OIDC refresh, null if never edited. */
|
|
19
|
+
displayNameOverride?: string | null;
|
|
20
|
+
/** Which provider minted this identity. */
|
|
21
|
+
authProvider?: AuthProvider;
|
|
22
|
+
/** Whether the account is disabled (login rejected). */
|
|
23
|
+
disabled?: boolean;
|
|
14
24
|
}
|
|
15
25
|
//#endregion
|
|
16
|
-
export { User };
|
|
26
|
+
export { AuthProvider, User };
|
|
17
27
|
//# sourceMappingURL=user.d.mts.map
|
package/dist/schema.d.mts
CHANGED
|
@@ -1,59 +1,22 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { Webhook } from "./schema/webhook.mjs";
|
|
3
4
|
import { Build } from "./schema/build.mjs";
|
|
5
|
+
import { CaptureAttempt, CaptureLog, CaptureLogLevel } from "./schema/capture-attempt.mjs";
|
|
4
6
|
import { Project, StorybookMeta } from "./schema/project.mjs";
|
|
5
7
|
import { Baseline } from "./schema/baseline.mjs";
|
|
8
|
+
import { Snapshot } from "./schema/snapshot.mjs";
|
|
9
|
+
import { ProjectStatusConfig } from "./schema/status-config.mjs";
|
|
6
10
|
import { Comment } from "./schema/comment.mjs";
|
|
7
11
|
import { BuildLabel, LabelType } from "./schema/label.mjs";
|
|
8
12
|
import { ProjectMember } from "./schema/member.mjs";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
13
|
+
import { NotificationChannelRow, NotificationSubscriptionRow } from "./schema/notification.mjs";
|
|
14
|
+
import { ProjectGroupMapping } from "./schema/project-group-mapping.mjs";
|
|
11
15
|
import { Token } from "./schema/token.mjs";
|
|
12
16
|
import { User } from "./schema/user.mjs";
|
|
13
|
-
import { Webhook } from "./schema/webhook.mjs";
|
|
14
|
-
import { AnySQLiteTable } from "drizzle-orm/sqlite-core";
|
|
15
17
|
//#region src/schema/index.d.ts
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
/** Project status-configs table (merge-gate configurations). */
|
|
19
|
-
declare const projectStatusConfigs: AnySQLiteTable;
|
|
20
|
-
/** Builds table (one row per uploaded Storybook build). */
|
|
21
|
-
declare const builds: AnySQLiteTable;
|
|
22
|
-
/** Snapshots table (one row per captured story screenshot). */
|
|
23
|
-
declare const snapshots: AnySQLiteTable;
|
|
24
|
-
/** Baselines table (accepted reference snapshots per branch). */
|
|
25
|
-
declare const baselines: AnySQLiteTable;
|
|
26
|
-
/** Comments table (review comments on snapshots). */
|
|
27
|
-
declare const comments: AnySQLiteTable;
|
|
28
|
-
/** Label-types table (project-defined build label vocabularies). */
|
|
29
|
-
declare const labelTypes: AnySQLiteTable;
|
|
30
|
-
/** Build-labels table (labels attached to builds). */
|
|
31
|
-
declare const buildLabels: AnySQLiteTable;
|
|
32
|
-
/** Tokens table (CI token hashes per project). */
|
|
33
|
-
declare const tokens: AnySQLiteTable;
|
|
34
|
-
/** Webhooks table (outgoing build-event subscriptions). */
|
|
35
|
-
declare const webhooks: AnySQLiteTable;
|
|
36
|
-
/** Users table (dashboard members). */
|
|
37
|
-
declare const users: AnySQLiteTable;
|
|
38
|
-
/** Project-members table (per-project memberships and roles). */
|
|
39
|
-
declare const projectMembers: AnySQLiteTable;
|
|
40
|
-
/** Full Drizzle schema object passed to the database client. */
|
|
41
|
-
declare const schema: {
|
|
42
|
-
projects: AnySQLiteTable;
|
|
43
|
-
projectStatusConfigs: AnySQLiteTable;
|
|
44
|
-
builds: AnySQLiteTable;
|
|
45
|
-
snapshots: AnySQLiteTable;
|
|
46
|
-
baselines: AnySQLiteTable;
|
|
47
|
-
comments: AnySQLiteTable;
|
|
48
|
-
labelTypes: AnySQLiteTable;
|
|
49
|
-
buildLabels: AnySQLiteTable;
|
|
50
|
-
tokens: AnySQLiteTable;
|
|
51
|
-
webhooks: AnySQLiteTable;
|
|
52
|
-
users: AnySQLiteTable;
|
|
53
|
-
projectMembers: AnySQLiteTable;
|
|
54
|
-
};
|
|
55
|
-
/** The full database schema type. */
|
|
56
|
-
type Schema = typeof schema;
|
|
18
|
+
/** Placeholder schema type — Drizzle schema lives in the db adapters. */
|
|
19
|
+
type Schema = Record<string, unknown>;
|
|
57
20
|
//#endregion
|
|
58
|
-
export { type Baseline, type Build, type BuildLabel, type
|
|
21
|
+
export { type Baseline, type Build, type BuildLabel, type CaptureAttempt, type CaptureLog, type CaptureLogLevel, type Comment, type LabelType, type NotificationChannelRow, type NotificationSubscriptionRow, type Project, type ProjectGroupMapping, type ProjectMember, type ProjectStatusConfig, Schema, type Snapshot, type StorybookMeta, type Token, type User, type Webhook };
|
|
59
22
|
//# sourceMappingURL=schema.d.mts.map
|
package/dist/schema.mjs
CHANGED
|
@@ -1,58 +1,4 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
|
|
5
|
-
import { builds as builds$1 } from "./schema/build.mjs";
|
|
6
|
-
import { buildLabels as buildLabels$1, labelTypes as labelTypes$1 } from "./schema/label.mjs";
|
|
7
|
-
import { snapshots as snapshots$1 } from "./schema/snapshot.mjs";
|
|
8
|
-
import { webhooks as webhooks$1 } from "./schema/webhook.mjs";
|
|
9
|
-
import { baselines as baselines$1 } from "./schema/baseline.mjs";
|
|
10
|
-
import { projectStatusConfigs as projectStatusConfigs$1 } from "./schema/status-config.mjs";
|
|
11
|
-
import { users as users$1 } from "./schema/user.mjs";
|
|
12
|
-
import { projectMembers as projectMembers$1 } from "./schema/member.mjs";
|
|
13
|
-
import { tokens as tokens$1 } from "./schema/token.mjs";
|
|
14
|
-
import { comments as comments$1 } from "./schema/comment.mjs";
|
|
15
|
-
//#region src/schema/index.ts
|
|
16
|
-
/** Projects table (one row per Storybook project). */
|
|
17
|
-
const projects = projects$1;
|
|
18
|
-
/** Project status-configs table (merge-gate configurations). */
|
|
19
|
-
const projectStatusConfigs = projectStatusConfigs$1;
|
|
20
|
-
/** Builds table (one row per uploaded Storybook build). */
|
|
21
|
-
const builds = builds$1;
|
|
22
|
-
/** Snapshots table (one row per captured story screenshot). */
|
|
23
|
-
const snapshots = snapshots$1;
|
|
24
|
-
/** Baselines table (accepted reference snapshots per branch). */
|
|
25
|
-
const baselines = baselines$1;
|
|
26
|
-
/** Comments table (review comments on snapshots). */
|
|
27
|
-
const comments = comments$1;
|
|
28
|
-
/** Label-types table (project-defined build label vocabularies). */
|
|
29
|
-
const labelTypes = labelTypes$1;
|
|
30
|
-
/** Build-labels table (labels attached to builds). */
|
|
31
|
-
const buildLabels = buildLabels$1;
|
|
32
|
-
/** Tokens table (CI token hashes per project). */
|
|
33
|
-
const tokens = tokens$1;
|
|
34
|
-
/** Webhooks table (outgoing build-event subscriptions). */
|
|
35
|
-
const webhooks = webhooks$1;
|
|
36
|
-
/** Users table (dashboard members). */
|
|
37
|
-
const users = users$1;
|
|
38
|
-
/** Project-members table (per-project memberships and roles). */
|
|
39
|
-
const projectMembers = projectMembers$1;
|
|
40
|
-
/** Full Drizzle schema object passed to the database client. */
|
|
41
|
-
const schema = {
|
|
42
|
-
projects,
|
|
43
|
-
projectStatusConfigs,
|
|
44
|
-
builds,
|
|
45
|
-
snapshots,
|
|
46
|
-
baselines,
|
|
47
|
-
comments,
|
|
48
|
-
labelTypes,
|
|
49
|
-
buildLabels,
|
|
50
|
-
tokens,
|
|
51
|
-
webhooks,
|
|
52
|
-
users,
|
|
53
|
-
projectMembers
|
|
54
|
-
};
|
|
55
|
-
//#endregion
|
|
56
|
-
export { baselines, buildLabels, builds, comments, labelTypes, projectMembers, projectStatusConfigs, projects, schema, snapshots, tokens, users, webhooks };
|
|
57
|
-
|
|
58
|
-
//# sourceMappingURL=schema.mjs.map
|
|
4
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { DatabaseAdapter } from "../adapter/database.mjs";
|
|
4
|
+
import { Build } from "../schema/build.mjs";
|
|
5
|
+
import { BuildTables } from "../models/build.mjs";
|
|
6
|
+
import { Project } from "../schema/project.mjs";
|
|
7
|
+
import { ProjectTables } from "../models/project.mjs";
|
|
8
|
+
//#region src/test-helpers/create-project.d.ts
|
|
9
|
+
/** Create a test project with owner/repo defaults. */
|
|
10
|
+
declare function createTestProject(db: DatabaseAdapter, tables: ProjectTables, overrides?: Partial<Project>): Promise<Project>;
|
|
11
|
+
/** Create a test build on main with sha-1 defaults. */
|
|
12
|
+
declare function createTestBuild(db: DatabaseAdapter, tables: BuildTables, projectId: string, overrides?: Partial<Build>): Promise<Build>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { createTestBuild, createTestProject };
|
|
15
|
+
//# sourceMappingURL=create-project.d.mts.map
|