@storyshelf/core 0.3.2 → 0.5.4
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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.mjs","names":[],"sources":["../../src/models/snapshot.ts"],"sourcesContent":["/** Snapshot records for captured stories within a build. */\nimport { eq } from \"drizzle-orm\";\nimport type {
|
|
1
|
+
{"version":3,"file":"snapshot.mjs","names":[],"sources":["../../src/models/snapshot.ts"],"sourcesContent":["/** Snapshot records for captured stories within a build. */\nimport { eq, getTableColumns } from \"drizzle-orm\";\nimport type { SQLWrapper, Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { Snapshot } from \"../schema/snapshot.ts\";\nimport type { SnapshotStatus } from \"../types.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\n\n/** Tables required by {@link SnapshotModel}. */\nexport interface SnapshotTables {\n snapshots: Table;\n}\n\n/** Data operations for snapshot records. */\nexport class SnapshotModel {\n private readonly tables: SnapshotTables;\n /**\n * @param db - Database adapter.\n * @param tables - Table handles.\n */\n constructor(\n private readonly db: DatabaseAdapter,\n tables?: SnapshotTables,\n ) {\n this.tables = tables ?? { snapshots: db.tables.snapshots };\n }\n\n /**\n * Create a snapshot for a story within a build.\n *\n * @param projectId - Project ID.\n * @param buildId - Build ID.\n * @param input - Snapshot creation input.\n * @returns The created snapshot.\n */\n async create(projectId: string, buildId: string, input: SnapshotCreateInput): Promise<Snapshot> {\n const now = new Date().toISOString();\n return (await this.db.insert(this.tables.snapshots, {\n id: ulid(),\n projectId,\n buildId,\n storyId: input.storyId,\n storyName: input.storyName,\n storyTitle: input.storyTitle,\n storyImportPath: input.storyImportPath,\n viewportName: input.viewportName,\n viewportWidth: input.viewportWidth,\n viewportHeight: input.viewportHeight,\n screenshotPath: input.screenshotPath,\n infraHash: input.infraHash ?? null,\n inherited: input.inherited ?? false,\n baselineId: input.baselineId ?? null,\n baselineVersion: input.baselineVersion ?? null,\n status: \"pending\",\n createdAt: now,\n updatedAt: now,\n })) as unknown as Snapshot;\n }\n\n /** List all snapshots belonging to a build. */\n async listByBuild(buildId: string): Promise<Snapshot[]> {\n return (await this.db.list(this.tables.snapshots, {\n where: eq(\n getTableColumns(this.tables.snapshots)[\"buildId\"] as unknown as SQLWrapper,\n buildId,\n ),\n })) as unknown as Snapshot[];\n }\n\n /** Fetch a snapshot by id, or null if not found. */\n async get(id: string): Promise<Snapshot | null> {\n return (await this.db.get(this.tables.snapshots, id)) as unknown as Snapshot | null;\n }\n\n /** Update mutable fields of a snapshot. */\n async update(id: string, patch: Partial<Snapshot>): Promise<Snapshot> {\n return (await this.db.update(this.tables.snapshots, id, {\n ...patch,\n updatedAt: new Date().toISOString(),\n })) as unknown as Snapshot;\n }\n\n /** Set the status of a snapshot. */\n async setStatus(id: string, status: SnapshotStatus): Promise<Snapshot> {\n return await this.update(id, { status });\n }\n\n /** Record a reviewer's decision on a snapshot. */\n async review(id: string, status: SnapshotStatus, userId: string | null): Promise<Snapshot> {\n return await this.update(id, {\n status,\n reviewedBy: userId,\n reviewedAt: new Date().toISOString(),\n });\n }\n}\n\n/** Input for creating a snapshot. */\nexport interface SnapshotCreateInput {\n storyId: string;\n storyName: string;\n storyTitle: string;\n storyImportPath?: string;\n viewportName: string;\n viewportWidth: number;\n viewportHeight: number;\n screenshotPath: string;\n infraHash?: string | null;\n inherited?: boolean;\n baselineId?: string | null;\n baselineVersion?: string | null;\n}\n"],"mappings":";;;;;;;;AAcA,IAAa,gBAAb,MAA2B;CAON;CANnB;;;;;CAKA,YACE,IACA,QACA;EAFiB,KAAA,KAAA;EAGjB,KAAK,SAAS,UAAU,EAAE,WAAW,GAAG,OAAO,UAAU;CAC3D;;;;;;;;;CAUA,MAAM,OAAO,WAAmB,SAAiB,OAA+C;EAC9F,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,WAAW;GAClD,IAAI,KAAK;GACT;GACA;GACA,SAAS,MAAM;GACf,WAAW,MAAM;GACjB,YAAY,MAAM;GAClB,iBAAiB,MAAM;GACvB,cAAc,MAAM;GACpB,eAAe,MAAM;GACrB,gBAAgB,MAAM;GACtB,gBAAgB,MAAM;GACtB,WAAW,MAAM,aAAa;GAC9B,WAAW,MAAM,aAAa;GAC9B,YAAY,MAAM,cAAc;GAChC,iBAAiB,MAAM,mBAAmB;GAC1C,QAAQ;GACR,WAAW;GACX,WAAW;EACb,CAAC;CACH;;CAGA,MAAM,YAAY,SAAsC;EACtD,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,WAAW,EAChD,OAAO,GACL,gBAAgB,KAAK,OAAO,SAAS,CAAC,CAAC,YACvC,OACF,EACF,CAAC;CACH;;CAGA,MAAM,IAAI,IAAsC;EAC9C,OAAQ,MAAM,KAAK,GAAG,IAAI,KAAK,OAAO,WAAW,EAAE;CACrD;;CAGA,MAAM,OAAO,IAAY,OAA6C;EACpE,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,WAAW,IAAI;GACtD,GAAG;GACH,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACpC,CAAC;CACH;;CAGA,MAAM,UAAU,IAAY,QAA2C;EACrE,OAAO,MAAM,KAAK,OAAO,IAAI,EAAE,OAAO,CAAC;CACzC;;CAGA,MAAM,OAAO,IAAY,QAAwB,QAA0C;EACzF,OAAO,MAAM,KAAK,OAAO,IAAI;GAC3B;GACA,YAAY;GACZ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EACrC,CAAC;CACH;AACF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
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 { SecretInput } from "../utils/encrypt.mjs";
|
|
5
|
+
import { ProjectStatusConfig } from "../schema/status-config.mjs";
|
|
6
|
+
import { Table } from "drizzle-orm";
|
|
7
|
+
//#region src/models/status-config.d.ts
|
|
8
|
+
/** Tables required by {@link StatusConfigModel}. */
|
|
9
|
+
interface StatusConfigTables {
|
|
10
|
+
projectStatusConfigs: Table;
|
|
11
|
+
}
|
|
12
|
+
/** Data operations for per-project status provider configs. */
|
|
13
|
+
declare class StatusConfigModel {
|
|
14
|
+
private readonly db;
|
|
15
|
+
private readonly tables;
|
|
16
|
+
private readonly secret;
|
|
17
|
+
constructor(db: DatabaseAdapter, tables?: StatusConfigTables, secret?: SecretInput);
|
|
18
|
+
/** List all status configs for a project. */
|
|
19
|
+
list(projectId: string): Promise<ProjectStatusConfig[]>;
|
|
20
|
+
/** Fetch a config by id scoped to a project, or null. */
|
|
21
|
+
get(projectId: string, id: string): Promise<ProjectStatusConfig | null>;
|
|
22
|
+
/** Decrypt the token for a stored row. */
|
|
23
|
+
decryptToken(row: ProjectStatusConfig): string;
|
|
24
|
+
/** Parse the JSON config column. */
|
|
25
|
+
static parseConfig(row: ProjectStatusConfig): unknown;
|
|
26
|
+
create(projectId: string, input: StatusConfigCreateInput): Promise<ProjectStatusConfig>;
|
|
27
|
+
remove(projectId: string, id: string): Promise<void>;
|
|
28
|
+
removeByProject(projectId: string): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/** Input for creating a git-provider status config. */
|
|
31
|
+
interface StatusConfigCreateInput {
|
|
32
|
+
provider: string;
|
|
33
|
+
config: unknown;
|
|
34
|
+
token: string;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { StatusConfigCreateInput, StatusConfigModel, StatusConfigTables };
|
|
38
|
+
//# sourceMappingURL=status-config.d.mts.map
|
|
@@ -1,35 +1,36 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
+
import { decryptCredential, encrypt } from "../utils/encrypt.mjs";
|
|
4
5
|
import { ulid } from "../utils/ulid.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import { projectStatusConfigs } from "../schema/status-config.mjs";
|
|
7
|
-
import { eq } from "drizzle-orm";
|
|
6
|
+
import { eq, getTableColumns } from "drizzle-orm";
|
|
8
7
|
//#region src/models/status-config.ts
|
|
9
8
|
/** Per-project git-provider status check configurations. */
|
|
10
9
|
/** Data operations for per-project status provider configs. */
|
|
11
10
|
var StatusConfigModel = class {
|
|
12
11
|
db;
|
|
12
|
+
tables;
|
|
13
13
|
secret;
|
|
14
|
-
constructor(db, secret) {
|
|
14
|
+
constructor(db, tables, secret) {
|
|
15
15
|
this.db = db;
|
|
16
|
+
this.tables = tables ?? { projectStatusConfigs: db.tables.projectStatusConfigs };
|
|
16
17
|
this.secret = secret;
|
|
17
18
|
}
|
|
18
19
|
/** List all status configs for a project. */
|
|
19
20
|
async list(projectId) {
|
|
20
|
-
return await this.db.list(projectStatusConfigs, { where: eq(projectStatusConfigs
|
|
21
|
+
return await this.db.list(this.tables.projectStatusConfigs, { where: eq(getTableColumns(this.tables.projectStatusConfigs)["projectId"], projectId) });
|
|
21
22
|
}
|
|
22
23
|
/** Fetch a config by id scoped to a project, or null. */
|
|
23
24
|
async get(projectId, id) {
|
|
24
|
-
const found = (await this.db.list(projectStatusConfigs, {
|
|
25
|
-
where: eq(projectStatusConfigs
|
|
25
|
+
const found = (await this.db.list(this.tables.projectStatusConfigs, {
|
|
26
|
+
where: eq(getTableColumns(this.tables.projectStatusConfigs)["id"], id),
|
|
26
27
|
limit: 1
|
|
27
28
|
}))[0] ?? null;
|
|
28
29
|
return found?.projectId === projectId ? found : null;
|
|
29
30
|
}
|
|
30
31
|
/** Decrypt the token for a stored row. */
|
|
31
32
|
decryptToken(row) {
|
|
32
|
-
return
|
|
33
|
+
return decryptCredential(this.secret, row.tokenEncrypted);
|
|
33
34
|
}
|
|
34
35
|
/** Parse the JSON config column. */
|
|
35
36
|
static parseConfig(row) {
|
|
@@ -37,7 +38,7 @@ var StatusConfigModel = class {
|
|
|
37
38
|
}
|
|
38
39
|
async create(projectId, input) {
|
|
39
40
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
40
|
-
return await this.db.insert(projectStatusConfigs, {
|
|
41
|
+
return await this.db.insert(this.tables.projectStatusConfigs, {
|
|
41
42
|
id: ulid(),
|
|
42
43
|
projectId,
|
|
43
44
|
provider: input.provider,
|
|
@@ -49,11 +50,11 @@ var StatusConfigModel = class {
|
|
|
49
50
|
}
|
|
50
51
|
async remove(projectId, id) {
|
|
51
52
|
const existing = await this.get(projectId, id);
|
|
52
|
-
if (existing) await this.db.remove(projectStatusConfigs, existing.id);
|
|
53
|
+
if (existing) await this.db.remove(this.tables.projectStatusConfigs, existing.id);
|
|
53
54
|
}
|
|
54
55
|
async removeByProject(projectId) {
|
|
55
56
|
const rows = await this.list(projectId);
|
|
56
|
-
for (const row of rows) await this.db.remove(projectStatusConfigs, row.id);
|
|
57
|
+
for (const row of rows) await this.db.remove(this.tables.projectStatusConfigs, row.id);
|
|
57
58
|
}
|
|
58
59
|
};
|
|
59
60
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-config.mjs","names":[],"sources":["../../src/models/status-config.ts"],"sourcesContent":["/* oxlint-disable eslint/no-await-in-loop, typescript/promise-function-async, eslint/require-await */\n/** Per-project git-provider status check configurations. */\nimport { eq } from \"drizzle-orm\";\nimport type {
|
|
1
|
+
{"version":3,"file":"status-config.mjs","names":[],"sources":["../../src/models/status-config.ts"],"sourcesContent":["/* oxlint-disable eslint/no-await-in-loop, typescript/promise-function-async, eslint/require-await */\n/** Per-project git-provider status check configurations. */\nimport { eq, getTableColumns } from \"drizzle-orm\";\nimport type { SQLWrapper, Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { ProjectStatusConfig } from \"../schema/status-config.ts\";\nimport { decryptCredential, encrypt, type SecretInput } from \"../utils/encrypt.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\n\n/** Tables required by {@link StatusConfigModel}. */\nexport interface StatusConfigTables {\n projectStatusConfigs: Table;\n}\n\n/** Data operations for per-project status provider configs. */\nexport class StatusConfigModel {\n private readonly tables: StatusConfigTables;\n private readonly secret: SecretInput;\n constructor(\n private readonly db: DatabaseAdapter,\n tables?: StatusConfigTables,\n secret?: SecretInput,\n ) {\n this.tables = tables ?? { projectStatusConfigs: db.tables.projectStatusConfigs };\n this.secret = secret;\n }\n\n /** List all status configs for a project. */\n async list(projectId: string): Promise<ProjectStatusConfig[]> {\n return (await this.db.list(this.tables.projectStatusConfigs, {\n where: eq(\n getTableColumns(this.tables.projectStatusConfigs)[\"projectId\"] as unknown as SQLWrapper,\n projectId,\n ),\n })) as unknown as ProjectStatusConfig[];\n }\n\n /** Fetch a config by id scoped to a project, or null. */\n async get(projectId: string, id: string): Promise<ProjectStatusConfig | null> {\n const rows = (await this.db.list(this.tables.projectStatusConfigs, {\n where: eq(\n getTableColumns(this.tables.projectStatusConfigs)[\"id\"] as unknown as SQLWrapper,\n id,\n ),\n limit: 1,\n })) as unknown as ProjectStatusConfig[];\n const found = rows[0] ?? null;\n return found?.projectId === projectId ? found : null;\n }\n\n /** Decrypt the token for a stored row. */\n decryptToken(row: ProjectStatusConfig): string {\n return decryptCredential(this.secret, row.tokenEncrypted);\n }\n\n /** Parse the JSON config column. */\n static parseConfig(row: ProjectStatusConfig): unknown {\n return JSON.parse(row.config) as unknown;\n }\n\n async create(projectId: string, input: StatusConfigCreateInput): Promise<ProjectStatusConfig> {\n const now = new Date().toISOString();\n return (await this.db.insert(this.tables.projectStatusConfigs, {\n id: ulid(),\n projectId,\n provider: input.provider,\n config: JSON.stringify(input.config),\n tokenEncrypted: encrypt(this.secret, input.token),\n createdAt: now,\n updatedAt: now,\n })) as unknown as ProjectStatusConfig;\n }\n\n async remove(projectId: string, id: string): Promise<void> {\n const existing = await this.get(projectId, id);\n if (existing) {\n await this.db.remove(this.tables.projectStatusConfigs, existing.id);\n }\n }\n\n async removeByProject(projectId: string): Promise<void> {\n const rows = await this.list(projectId);\n for (const row of rows) {\n await this.db.remove(this.tables.projectStatusConfigs, row.id);\n }\n }\n}\n\n/** Input for creating a git-provider status config. */\nexport interface StatusConfigCreateInput {\n provider: string;\n config: unknown;\n token: string;\n}\n"],"mappings":";;;;;;;;;AAeA,IAAa,oBAAb,MAA+B;CAIV;CAHnB;CACA;CACA,YACE,IACA,QACA,QACA;EAHiB,KAAA,KAAA;EAIjB,KAAK,SAAS,UAAU,EAAE,sBAAsB,GAAG,OAAO,qBAAqB;EAC/E,KAAK,SAAS;CAChB;;CAGA,MAAM,KAAK,WAAmD;EAC5D,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,sBAAsB,EAC3D,OAAO,GACL,gBAAgB,KAAK,OAAO,oBAAoB,CAAC,CAAC,cAClD,SACF,EACF,CAAC;CACH;;CAGA,MAAM,IAAI,WAAmB,IAAiD;EAQ5E,MAAM,SAAQ,MAPM,KAAK,GAAG,KAAK,KAAK,OAAO,sBAAsB;GACjE,OAAO,GACL,gBAAgB,KAAK,OAAO,oBAAoB,CAAC,CAAC,OAClD,EACF;GACA,OAAO;EACT,CAAC,EAAA,CACkB,MAAM;EACzB,OAAO,OAAO,cAAc,YAAY,QAAQ;CAClD;;CAGA,aAAa,KAAkC;EAC7C,OAAO,kBAAkB,KAAK,QAAQ,IAAI,cAAc;CAC1D;;CAGA,OAAO,YAAY,KAAmC;EACpD,OAAO,KAAK,MAAM,IAAI,MAAM;CAC9B;CAEA,MAAM,OAAO,WAAmB,OAA8D;EAC5F,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,sBAAsB;GAC7D,IAAI,KAAK;GACT;GACA,UAAU,MAAM;GAChB,QAAQ,KAAK,UAAU,MAAM,MAAM;GACnC,gBAAgB,QAAQ,KAAK,QAAQ,MAAM,KAAK;GAChD,WAAW;GACX,WAAW;EACb,CAAC;CACH;CAEA,MAAM,OAAO,WAAmB,IAA2B;EACzD,MAAM,WAAW,MAAM,KAAK,IAAI,WAAW,EAAE;EAC7C,IAAI,UACF,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,sBAAsB,SAAS,EAAE;CAEtE;CAEA,MAAM,gBAAgB,WAAkC;EACtD,MAAM,OAAO,MAAM,KAAK,KAAK,SAAS;EACtC,KAAK,MAAM,OAAO,MAChB,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,sBAAsB,IAAI,EAAE;CAEjE;AACF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
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 { Token } from "../schema/token.mjs";
|
|
5
|
+
import { Table } from "drizzle-orm";
|
|
6
|
+
//#region src/models/token.d.ts
|
|
7
|
+
/** Tables required by {@link TokenModel}. */
|
|
8
|
+
interface TokenTables {
|
|
9
|
+
tokens: Table;
|
|
10
|
+
}
|
|
11
|
+
/** Data operations for CI tokens. */
|
|
12
|
+
declare class TokenModel {
|
|
13
|
+
private readonly db;
|
|
14
|
+
private readonly tables;
|
|
15
|
+
/**
|
|
16
|
+
* @param db - Database adapter.
|
|
17
|
+
* @param tables - Table handles.
|
|
18
|
+
*/
|
|
19
|
+
constructor(db: DatabaseAdapter, tables?: TokenTables);
|
|
20
|
+
/**
|
|
21
|
+
* Create a token record storing its hash.
|
|
22
|
+
*
|
|
23
|
+
* @param projectId - Project ID.
|
|
24
|
+
* @param input - Token name, hash, and optional owning user ID (null for
|
|
25
|
+
* legacy/admin-token minting; such tokens resolve as viewer).
|
|
26
|
+
* @returns The created token.
|
|
27
|
+
*/
|
|
28
|
+
create(projectId: string, input: {
|
|
29
|
+
name: string;
|
|
30
|
+
hash: string;
|
|
31
|
+
userId?: string | null;
|
|
32
|
+
}): Promise<Token>;
|
|
33
|
+
/** List all tokens for a project. */
|
|
34
|
+
list(projectId: string): Promise<Token[]>;
|
|
35
|
+
/** Fetch a token by id within a project, or null if not found. */
|
|
36
|
+
get(projectId: string, id: string): Promise<Token | null>;
|
|
37
|
+
/** Fetch a token by its hashed value, or null if not found. */
|
|
38
|
+
findByHash(hash: string): Promise<Token | null>;
|
|
39
|
+
/** Delete a token by id. */
|
|
40
|
+
remove(id: string): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { TokenModel, TokenTables };
|
|
44
|
+
//# sourceMappingURL=token.d.mts.map
|
package/dist/models/token.mjs
CHANGED
|
@@ -2,57 +2,60 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { ulid } from "../utils/ulid.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import { and, eq } from "drizzle-orm";
|
|
5
|
+
import { and, eq, getTableColumns } from "drizzle-orm";
|
|
7
6
|
//#region src/models/token.ts
|
|
8
7
|
/** CI tokens for project-scoped API access. */
|
|
9
8
|
/** Data operations for CI tokens. */
|
|
10
9
|
var TokenModel = class {
|
|
11
10
|
db;
|
|
11
|
+
tables;
|
|
12
12
|
/**
|
|
13
13
|
* @param db - Database adapter.
|
|
14
|
+
* @param tables - Table handles.
|
|
14
15
|
*/
|
|
15
|
-
constructor(db) {
|
|
16
|
+
constructor(db, tables) {
|
|
16
17
|
this.db = db;
|
|
18
|
+
this.tables = tables ?? { tokens: db.tables.tokens };
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Create a token record storing its hash.
|
|
20
22
|
*
|
|
21
23
|
* @param projectId - Project ID.
|
|
22
|
-
* @param
|
|
23
|
-
*
|
|
24
|
+
* @param input - Token name, hash, and optional owning user ID (null for
|
|
25
|
+
* legacy/admin-token minting; such tokens resolve as viewer).
|
|
24
26
|
* @returns The created token.
|
|
25
27
|
*/
|
|
26
|
-
async create(projectId,
|
|
27
|
-
return await this.db.insert(tokens, {
|
|
28
|
+
async create(projectId, input) {
|
|
29
|
+
return await this.db.insert(this.tables.tokens, {
|
|
28
30
|
id: ulid(),
|
|
29
31
|
projectId,
|
|
30
|
-
name,
|
|
31
|
-
hash,
|
|
32
|
+
name: input.name,
|
|
33
|
+
hash: input.hash,
|
|
34
|
+
userId: input.userId ?? null,
|
|
32
35
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
33
36
|
});
|
|
34
37
|
}
|
|
35
38
|
/** List all tokens for a project. */
|
|
36
39
|
async list(projectId) {
|
|
37
|
-
return await this.db.list(tokens, { where: eq(tokens
|
|
40
|
+
return await this.db.list(this.tables.tokens, { where: eq(getTableColumns(this.tables.tokens)["projectId"], projectId) });
|
|
38
41
|
}
|
|
39
42
|
/** Fetch a token by id within a project, or null if not found. */
|
|
40
43
|
async get(projectId, id) {
|
|
41
|
-
return (await this.db.list(tokens, {
|
|
42
|
-
where: and(eq(tokens
|
|
44
|
+
return (await this.db.list(this.tables.tokens, {
|
|
45
|
+
where: and(eq(getTableColumns(this.tables.tokens)["projectId"], projectId), eq(getTableColumns(this.tables.tokens)["id"], id)),
|
|
43
46
|
limit: 1
|
|
44
47
|
}))[0] ?? null;
|
|
45
48
|
}
|
|
46
49
|
/** Fetch a token by its hashed value, or null if not found. */
|
|
47
50
|
async findByHash(hash) {
|
|
48
|
-
return (await this.db.list(tokens, {
|
|
49
|
-
where: eq(tokens
|
|
51
|
+
return (await this.db.list(this.tables.tokens, {
|
|
52
|
+
where: eq(getTableColumns(this.tables.tokens)["hash"], hash),
|
|
50
53
|
limit: 1
|
|
51
54
|
}))[0] ?? null;
|
|
52
55
|
}
|
|
53
56
|
/** Delete a token by id. */
|
|
54
57
|
async remove(id) {
|
|
55
|
-
await this.db.remove(tokens, id);
|
|
58
|
+
await this.db.remove(this.tables.tokens, id);
|
|
56
59
|
}
|
|
57
60
|
};
|
|
58
61
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.mjs","names":[],"sources":["../../src/models/token.ts"],"sourcesContent":["/** CI tokens for project-scoped API access. */\nimport { and, eq } from \"drizzle-orm\";\nimport type {
|
|
1
|
+
{"version":3,"file":"token.mjs","names":[],"sources":["../../src/models/token.ts"],"sourcesContent":["/** CI tokens for project-scoped API access. */\nimport { and, eq, getTableColumns } from \"drizzle-orm\";\nimport type { SQLWrapper, Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { Token } from \"../schema/token.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\n\n/** Tables required by {@link TokenModel}. */\nexport interface TokenTables {\n tokens: Table;\n}\n\n/** Data operations for CI tokens. */\nexport class TokenModel {\n private readonly tables: TokenTables;\n /**\n * @param db - Database adapter.\n * @param tables - Table handles.\n */\n constructor(\n private readonly db: DatabaseAdapter,\n tables?: TokenTables,\n ) {\n this.tables = tables ?? { tokens: db.tables.tokens };\n }\n\n /**\n * Create a token record storing its hash.\n *\n * @param projectId - Project ID.\n * @param input - Token name, hash, and optional owning user ID (null for\n * legacy/admin-token minting; such tokens resolve as viewer).\n * @returns The created token.\n */\n async create(\n projectId: string,\n input: { name: string; hash: string; userId?: string | null },\n ): Promise<Token> {\n return (await this.db.insert(this.tables.tokens, {\n id: ulid(),\n projectId,\n name: input.name,\n hash: input.hash,\n userId: input.userId ?? null,\n createdAt: new Date().toISOString(),\n })) as unknown as Token;\n }\n\n /** List all tokens for a project. */\n async list(projectId: string): Promise<Token[]> {\n return (await this.db.list(this.tables.tokens, {\n where: eq(\n getTableColumns(this.tables.tokens)[\"projectId\"] as unknown as SQLWrapper,\n projectId,\n ),\n })) as unknown as Token[];\n }\n\n /** Fetch a token by id within a project, or null if not found. */\n async get(projectId: string, id: string): Promise<Token | null> {\n const rows = (await this.db.list(this.tables.tokens, {\n where: and(\n eq(getTableColumns(this.tables.tokens)[\"projectId\"] as unknown as SQLWrapper, projectId),\n eq(getTableColumns(this.tables.tokens)[\"id\"] as unknown as SQLWrapper, id),\n ),\n limit: 1,\n })) as unknown as Token[];\n return rows[0] ?? null;\n }\n\n /** Fetch a token by its hashed value, or null if not found. */\n async findByHash(hash: string): Promise<Token | null> {\n const rows = (await this.db.list(this.tables.tokens, {\n where: eq(getTableColumns(this.tables.tokens)[\"hash\"] as unknown as SQLWrapper, hash),\n limit: 1,\n })) as unknown as Token[];\n return rows[0] ?? null;\n }\n\n /** Delete a token by id. */\n async remove(id: string): Promise<void> {\n await this.db.remove(this.tables.tokens, id);\n }\n}\n"],"mappings":";;;;;;;;AAaA,IAAa,aAAb,MAAwB;CAOH;CANnB;;;;;CAKA,YACE,IACA,QACA;EAFiB,KAAA,KAAA;EAGjB,KAAK,SAAS,UAAU,EAAE,QAAQ,GAAG,OAAO,OAAO;CACrD;;;;;;;;;CAUA,MAAM,OACJ,WACA,OACgB;EAChB,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,QAAQ;GAC/C,IAAI,KAAK;GACT;GACA,MAAM,MAAM;GACZ,MAAM,MAAM;GACZ,QAAQ,MAAM,UAAU;GACxB,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACpC,CAAC;CACH;;CAGA,MAAM,KAAK,WAAqC;EAC9C,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,QAAQ,EAC7C,OAAO,GACL,gBAAgB,KAAK,OAAO,MAAM,CAAC,CAAC,cACpC,SACF,EACF,CAAC;CACH;;CAGA,MAAM,IAAI,WAAmB,IAAmC;EAQ9D,QAAO,MAPa,KAAK,GAAG,KAAK,KAAK,OAAO,QAAQ;GACnD,OAAO,IACL,GAAG,gBAAgB,KAAK,OAAO,MAAM,CAAC,CAAC,cAAuC,SAAS,GACvF,GAAG,gBAAgB,KAAK,OAAO,MAAM,CAAC,CAAC,OAAgC,EAAE,CAC3E;GACA,OAAO;EACT,CAAC,EAAA,CACW,MAAM;CACpB;;CAGA,MAAM,WAAW,MAAqC;EAKpD,QAAO,MAJa,KAAK,GAAG,KAAK,KAAK,OAAO,QAAQ;GACnD,OAAO,GAAG,gBAAgB,KAAK,OAAO,MAAM,CAAC,CAAC,SAAkC,IAAI;GACpF,OAAO;EACT,CAAC,EAAA,CACW,MAAM;CACpB;;CAGA,MAAM,OAAO,IAA2B;EACtC,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,QAAQ,EAAE;CAC7C;AACF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
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 { User } from "../schema/user.mjs";
|
|
5
|
+
import { Table } from "drizzle-orm";
|
|
6
|
+
//#region src/models/user.d.ts
|
|
7
|
+
/** Tables required by {@link UserModel}. */
|
|
8
|
+
interface UserTables {
|
|
9
|
+
users: Table;
|
|
10
|
+
}
|
|
11
|
+
/** Data operations for users. */
|
|
12
|
+
declare class UserModel {
|
|
13
|
+
private readonly db;
|
|
14
|
+
private readonly tables;
|
|
15
|
+
/**
|
|
16
|
+
* @param db - Database adapter.
|
|
17
|
+
* @param tables - Table handles.
|
|
18
|
+
*/
|
|
19
|
+
constructor(db: DatabaseAdapter, tables?: UserTables);
|
|
20
|
+
/** Fetch a user by id, or null if not found (e.g. deleted after tokens were minted). */
|
|
21
|
+
get(id: string): Promise<User | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Insert or update a user row from an authenticated identity (login sync).
|
|
24
|
+
* Email, name, avatar, and site role refresh on every login; the row id
|
|
25
|
+
* (the provider `sub`) is stable. Preserves `displayNameOverride` so a
|
|
26
|
+
* user-edited name survives IdP refresh; `passwordHash` and `disabled`
|
|
27
|
+
* are never clobbered by SSO sync.
|
|
28
|
+
*/
|
|
29
|
+
upsert(input: {
|
|
30
|
+
id: string;
|
|
31
|
+
email: string;
|
|
32
|
+
name: string;
|
|
33
|
+
avatarUrl?: string | null;
|
|
34
|
+
role: User["role"];
|
|
35
|
+
authProvider?: User["authProvider"];
|
|
36
|
+
}): Promise<User>;
|
|
37
|
+
/** Update the display name override for a user (profile edit). */
|
|
38
|
+
setDisplayNameOverride(id: string, displayName: string | null): Promise<User>;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { UserModel, UserTables };
|
|
42
|
+
//# sourceMappingURL=user.d.mts.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { eq, getTableColumns } from "drizzle-orm";
|
|
5
|
+
//#region src/models/user.ts
|
|
6
|
+
/** User lookups for token and membership resolution. */
|
|
7
|
+
/** Data operations for users. */
|
|
8
|
+
var UserModel = class {
|
|
9
|
+
db;
|
|
10
|
+
tables;
|
|
11
|
+
/**
|
|
12
|
+
* @param db - Database adapter.
|
|
13
|
+
* @param tables - Table handles.
|
|
14
|
+
*/
|
|
15
|
+
constructor(db, tables) {
|
|
16
|
+
this.db = db;
|
|
17
|
+
this.tables = tables ?? { users: db.tables.users };
|
|
18
|
+
}
|
|
19
|
+
/** Fetch a user by id, or null if not found (e.g. deleted after tokens were minted). */
|
|
20
|
+
async get(id) {
|
|
21
|
+
return (await this.db.list(this.tables.users, {
|
|
22
|
+
where: eq(getTableColumns(this.tables.users)["id"], id),
|
|
23
|
+
limit: 1
|
|
24
|
+
}))[0] ?? null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Insert or update a user row from an authenticated identity (login sync).
|
|
28
|
+
* Email, name, avatar, and site role refresh on every login; the row id
|
|
29
|
+
* (the provider `sub`) is stable. Preserves `displayNameOverride` so a
|
|
30
|
+
* user-edited name survives IdP refresh; `passwordHash` and `disabled`
|
|
31
|
+
* are never clobbered by SSO sync.
|
|
32
|
+
*/
|
|
33
|
+
async upsert(input) {
|
|
34
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
35
|
+
const existing = await this.get(input.id);
|
|
36
|
+
if (!existing) return await this.db.insert(this.tables.users, {
|
|
37
|
+
id: input.id,
|
|
38
|
+
email: input.email,
|
|
39
|
+
name: input.name,
|
|
40
|
+
avatarUrl: input.avatarUrl ?? null,
|
|
41
|
+
role: input.role,
|
|
42
|
+
lastLoginAt: now,
|
|
43
|
+
createdAt: now,
|
|
44
|
+
passwordHash: null,
|
|
45
|
+
displayNameOverride: null,
|
|
46
|
+
authProvider: input.authProvider ?? "oidc",
|
|
47
|
+
disabled: false
|
|
48
|
+
});
|
|
49
|
+
return await this.db.update(this.tables.users, existing.id, {
|
|
50
|
+
email: input.email,
|
|
51
|
+
name: input.name,
|
|
52
|
+
avatarUrl: input.avatarUrl ?? null,
|
|
53
|
+
role: input.role,
|
|
54
|
+
lastLoginAt: now
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Update the display name override for a user (profile edit). */
|
|
58
|
+
async setDisplayNameOverride(id, displayName) {
|
|
59
|
+
return await this.db.update(this.tables.users, id, { displayNameOverride: displayName?.trim() ? displayName.trim() : null });
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
63
|
+
export { UserModel };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=user.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user.mjs","names":[],"sources":["../../src/models/user.ts"],"sourcesContent":["/** User lookups for token and membership resolution. */\nimport { eq, getTableColumns } from \"drizzle-orm\";\nimport type { SQLWrapper, Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { User } from \"../schema/user.ts\";\n\n/** Tables required by {@link UserModel}. */\nexport interface UserTables {\n users: Table;\n}\n\n/** Data operations for users. */\nexport class UserModel {\n private readonly tables: UserTables;\n /**\n * @param db - Database adapter.\n * @param tables - Table handles.\n */\n constructor(\n private readonly db: DatabaseAdapter,\n tables?: UserTables,\n ) {\n this.tables = tables ?? { users: db.tables.users };\n }\n\n /** Fetch a user by id, or null if not found (e.g. deleted after tokens were minted). */\n async get(id: string): Promise<User | null> {\n const rows = (await this.db.list(this.tables.users, {\n where: eq(getTableColumns(this.tables.users)[\"id\"] as unknown as SQLWrapper, id),\n limit: 1,\n })) as unknown as User[];\n return rows[0] ?? null;\n }\n\n /**\n * Insert or update a user row from an authenticated identity (login sync).\n * Email, name, avatar, and site role refresh on every login; the row id\n * (the provider `sub`) is stable. Preserves `displayNameOverride` so a\n * user-edited name survives IdP refresh; `passwordHash` and `disabled`\n * are never clobbered by SSO sync.\n */\n async upsert(input: {\n id: string;\n email: string;\n name: string;\n avatarUrl?: string | null;\n role: User[\"role\"];\n authProvider?: User[\"authProvider\"];\n }): Promise<User> {\n const now = new Date().toISOString();\n const existing = await this.get(input.id);\n if (!existing) {\n return (await this.db.insert(this.tables.users, {\n id: input.id,\n email: input.email,\n name: input.name,\n avatarUrl: input.avatarUrl ?? null,\n role: input.role,\n lastLoginAt: now,\n createdAt: now,\n passwordHash: null,\n displayNameOverride: null,\n authProvider: input.authProvider ?? \"oidc\",\n disabled: false,\n })) as unknown as User;\n }\n return (await this.db.update(this.tables.users, existing.id, {\n email: input.email,\n // Keep a user-edited display name: `name` stays the IdP value,\n // `displayNameOverride` is the source of truth for rendering.\n name: input.name,\n avatarUrl: input.avatarUrl ?? null,\n role: input.role,\n lastLoginAt: now,\n })) as unknown as User;\n }\n\n /** Update the display name override for a user (profile edit). */\n async setDisplayNameOverride(id: string, displayName: string | null): Promise<User> {\n return (await this.db.update(this.tables.users, id, {\n displayNameOverride: displayName?.trim() ? displayName.trim() : null,\n })) as unknown as User;\n }\n}\n"],"mappings":";;;;;;;AAYA,IAAa,YAAb,MAAuB;CAOF;CANnB;;;;;CAKA,YACE,IACA,QACA;EAFiB,KAAA,KAAA;EAGjB,KAAK,SAAS,UAAU,EAAE,OAAO,GAAG,OAAO,MAAM;CACnD;;CAGA,MAAM,IAAI,IAAkC;EAK1C,QAAO,MAJa,KAAK,GAAG,KAAK,KAAK,OAAO,OAAO;GAClD,OAAO,GAAG,gBAAgB,KAAK,OAAO,KAAK,CAAC,CAAC,OAAgC,EAAE;GAC/E,OAAO;EACT,CAAC,EAAA,CACW,MAAM;CACpB;;;;;;;;CASA,MAAM,OAAO,OAOK;EAChB,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC,MAAM,WAAW,MAAM,KAAK,IAAI,MAAM,EAAE;EACxC,IAAI,CAAC,UACH,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,OAAO;GAC9C,IAAI,MAAM;GACV,OAAO,MAAM;GACb,MAAM,MAAM;GACZ,WAAW,MAAM,aAAa;GAC9B,MAAM,MAAM;GACZ,aAAa;GACb,WAAW;GACX,cAAc;GACd,qBAAqB;GACrB,cAAc,MAAM,gBAAgB;GACpC,UAAU;EACZ,CAAC;EAEH,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,OAAO,SAAS,IAAI;GAC3D,OAAO,MAAM;GAGb,MAAM,MAAM;GACZ,WAAW,MAAM,aAAa;GAC9B,MAAM,MAAM;GACZ,aAAa;EACf,CAAC;CACH;;CAGA,MAAM,uBAAuB,IAAY,aAA2C;EAClF,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,OAAO,IAAI,EAClD,qBAAqB,aAAa,KAAK,IAAI,YAAY,KAAK,IAAI,KAClE,CAAC;CACH;AACF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
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 { Webhook } from "../schema/webhook.mjs";
|
|
5
|
+
import { SecretInput } from "../utils/encrypt.mjs";
|
|
6
|
+
import { Table } from "drizzle-orm";
|
|
7
|
+
//#region src/models/webhook.d.ts
|
|
8
|
+
/** Tables required by {@link WebhookModel}. */
|
|
9
|
+
interface WebhookTables {
|
|
10
|
+
webhooks: Table;
|
|
11
|
+
}
|
|
12
|
+
/** Data operations for webhook subscriptions. */
|
|
13
|
+
declare class WebhookModel {
|
|
14
|
+
private readonly db;
|
|
15
|
+
private readonly tables;
|
|
16
|
+
private readonly secret?;
|
|
17
|
+
/**
|
|
18
|
+
* @param db - Database adapter.
|
|
19
|
+
* @param tables - Table handles.
|
|
20
|
+
* @param secret - Server secret for webhook-secret encryption (throws on write/decrypt when unset).
|
|
21
|
+
*/
|
|
22
|
+
constructor(db: DatabaseAdapter, tables?: WebhookTables, secret?: SecretInput);
|
|
23
|
+
/** List all webhooks for a project. */
|
|
24
|
+
list(projectId: string): Promise<Webhook[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Create a webhook subscription for a project.
|
|
27
|
+
*
|
|
28
|
+
* @param projectId - Project ID.
|
|
29
|
+
* @param input - Webhook creation input.
|
|
30
|
+
* @returns The created webhook.
|
|
31
|
+
*/
|
|
32
|
+
create(projectId: string, input: WebhookCreateInput): Promise<Webhook>;
|
|
33
|
+
/** Decrypt the secret for a stored row (in memory only, at send time). */
|
|
34
|
+
decryptSecret(row: Webhook): string;
|
|
35
|
+
/** Fetch a webhook by id scoped to a project, or null if not found. */
|
|
36
|
+
get(projectId: string, id: string): Promise<Webhook | null>;
|
|
37
|
+
/** Remove a webhook if it belongs to the given project. */
|
|
38
|
+
remove(projectId: string, id: string): Promise<void>;
|
|
39
|
+
/** Decode the JSON-serialized event list of a webhook. */
|
|
40
|
+
static eventsOf(webhook: Webhook): string[];
|
|
41
|
+
}
|
|
42
|
+
/** Input for creating a webhook subscription. */
|
|
43
|
+
interface WebhookCreateInput {
|
|
44
|
+
url: string;
|
|
45
|
+
events?: string[];
|
|
46
|
+
secret: string;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { WebhookCreateInput, WebhookModel, WebhookTables };
|
|
50
|
+
//# sourceMappingURL=webhook.d.mts.map
|
package/dist/models/webhook.mjs
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
+
import { decryptCredential, encrypt } from "../utils/encrypt.mjs";
|
|
4
5
|
import { ulid } from "../utils/ulid.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import { decrypt, encrypt } from "../utils/encrypt.mjs";
|
|
7
|
-
import { eq } from "drizzle-orm";
|
|
6
|
+
import { eq, getTableColumns } from "drizzle-orm";
|
|
8
7
|
//#region src/models/webhook.ts
|
|
9
8
|
/** Webhook subscriptions for project events. */
|
|
10
9
|
/** Data operations for webhook subscriptions. */
|
|
11
10
|
var WebhookModel = class {
|
|
12
11
|
db;
|
|
12
|
+
tables;
|
|
13
13
|
secret;
|
|
14
14
|
/**
|
|
15
15
|
* @param db - Database adapter.
|
|
16
|
+
* @param tables - Table handles.
|
|
16
17
|
* @param secret - Server secret for webhook-secret encryption (throws on write/decrypt when unset).
|
|
17
18
|
*/
|
|
18
|
-
constructor(db, secret) {
|
|
19
|
+
constructor(db, tables, secret) {
|
|
19
20
|
this.db = db;
|
|
21
|
+
this.tables = tables ?? { webhooks: db.tables.webhooks };
|
|
20
22
|
this.secret = secret;
|
|
21
23
|
}
|
|
22
24
|
/** List all webhooks for a project. */
|
|
23
25
|
async list(projectId) {
|
|
24
|
-
return await this.db.list(webhooks, { where: eq(webhooks
|
|
26
|
+
return await this.db.list(this.tables.webhooks, { where: eq(getTableColumns(this.tables.webhooks)["projectId"], projectId) });
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
29
|
* Create a webhook subscription for a project.
|
|
@@ -32,7 +34,7 @@ var WebhookModel = class {
|
|
|
32
34
|
*/
|
|
33
35
|
async create(projectId, input) {
|
|
34
36
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
35
|
-
return await this.db.insert(webhooks, {
|
|
37
|
+
return await this.db.insert(this.tables.webhooks, {
|
|
36
38
|
id: ulid(),
|
|
37
39
|
projectId,
|
|
38
40
|
url: input.url,
|
|
@@ -44,12 +46,12 @@ var WebhookModel = class {
|
|
|
44
46
|
}
|
|
45
47
|
/** Decrypt the secret for a stored row (in memory only, at send time). */
|
|
46
48
|
decryptSecret(row) {
|
|
47
|
-
return
|
|
49
|
+
return decryptCredential(this.secret, row.secretEncrypted);
|
|
48
50
|
}
|
|
49
51
|
/** Fetch a webhook by id scoped to a project, or null if not found. */
|
|
50
52
|
async get(projectId, id) {
|
|
51
|
-
const found = (await this.db.list(webhooks, {
|
|
52
|
-
where: eq(webhooks
|
|
53
|
+
const found = (await this.db.list(this.tables.webhooks, {
|
|
54
|
+
where: eq(getTableColumns(this.tables.webhooks)["id"], id),
|
|
53
55
|
limit: 1
|
|
54
56
|
}))[0] ?? null;
|
|
55
57
|
return found?.projectId === projectId ? found : null;
|
|
@@ -57,7 +59,7 @@ var WebhookModel = class {
|
|
|
57
59
|
/** Remove a webhook if it belongs to the given project. */
|
|
58
60
|
async remove(projectId, id) {
|
|
59
61
|
const existing = await this.get(projectId, id);
|
|
60
|
-
if (existing) await this.db.remove(webhooks, existing.id);
|
|
62
|
+
if (existing) await this.db.remove(this.tables.webhooks, existing.id);
|
|
61
63
|
}
|
|
62
64
|
/** Decode the JSON-serialized event list of a webhook. */
|
|
63
65
|
static eventsOf(webhook) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.mjs","names":[],"sources":["../../src/models/webhook.ts"],"sourcesContent":["/** Webhook subscriptions for project events. */\nimport { eq } from \"drizzle-orm\";\nimport type {
|
|
1
|
+
{"version":3,"file":"webhook.mjs","names":[],"sources":["../../src/models/webhook.ts"],"sourcesContent":["/** Webhook subscriptions for project events. */\nimport { eq, getTableColumns } from \"drizzle-orm\";\nimport type { SQLWrapper, Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { Webhook } from \"../schema/webhook.ts\";\nimport { decryptCredential, encrypt, type SecretInput } from \"../utils/encrypt.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\n\n/** Tables required by {@link WebhookModel}. */\nexport interface WebhookTables {\n webhooks: Table;\n}\n\n/** Data operations for webhook subscriptions. */\nexport class WebhookModel {\n private readonly tables: WebhookTables;\n private readonly secret?: SecretInput;\n /**\n * @param db - Database adapter.\n * @param tables - Table handles.\n * @param secret - Server secret for webhook-secret encryption (throws on write/decrypt when unset).\n */\n constructor(\n private readonly db: DatabaseAdapter,\n tables?: WebhookTables,\n secret?: SecretInput,\n ) {\n this.tables = tables ?? { webhooks: db.tables.webhooks };\n this.secret = secret;\n }\n\n /** List all webhooks for a project. */\n async list(projectId: string): Promise<Webhook[]> {\n return (await this.db.list(this.tables.webhooks, {\n where: eq(\n getTableColumns(this.tables.webhooks)[\"projectId\"] as unknown as SQLWrapper,\n projectId,\n ),\n })) as unknown as Webhook[];\n }\n\n /**\n * Create a webhook subscription for a project.\n *\n * @param projectId - Project ID.\n * @param input - Webhook creation input.\n * @returns The created webhook.\n */\n async create(projectId: string, input: WebhookCreateInput): Promise<Webhook> {\n const now = new Date().toISOString();\n return (await this.db.insert(this.tables.webhooks, {\n id: ulid(),\n projectId,\n url: input.url,\n secretEncrypted: encrypt(this.secret, input.secret),\n events: input.events && input.events.length > 0 ? JSON.stringify(input.events) : null,\n createdAt: now,\n updatedAt: now,\n })) as unknown as Webhook;\n }\n\n /** Decrypt the secret for a stored row (in memory only, at send time). */\n decryptSecret(row: Webhook): string {\n return decryptCredential(this.secret, row.secretEncrypted);\n }\n\n /** Fetch a webhook by id scoped to a project, or null if not found. */\n async get(projectId: string, id: string): Promise<Webhook | null> {\n const rows = (await this.db.list(this.tables.webhooks, {\n where: eq(getTableColumns(this.tables.webhooks)[\"id\"] as unknown as SQLWrapper, id),\n limit: 1,\n })) as unknown as Webhook[];\n const found = rows[0] ?? null;\n return found?.projectId === projectId ? found : null;\n }\n\n /** Remove a webhook if it belongs to the given project. */\n async remove(projectId: string, id: string): Promise<void> {\n const existing = await this.get(projectId, id);\n if (existing) {\n await this.db.remove(this.tables.webhooks, existing.id);\n }\n }\n\n /** Decode the JSON-serialized event list of a webhook. */\n static eventsOf(webhook: Webhook): string[] {\n if (!webhook.events) {\n return [];\n }\n try {\n const parsed: unknown = JSON.parse(webhook.events);\n return Array.isArray(parsed)\n ? parsed.filter((event): event is string => typeof event === \"string\")\n : [];\n } catch {\n return [];\n }\n }\n}\n\n/** Input for creating a webhook subscription. */\nexport interface WebhookCreateInput {\n url: string;\n events?: string[];\n secret: string;\n}\n"],"mappings":";;;;;;;;;AAcA,IAAa,eAAb,MAA0B;CASL;CARnB;CACA;;;;;;CAMA,YACE,IACA,QACA,QACA;EAHiB,KAAA,KAAA;EAIjB,KAAK,SAAS,UAAU,EAAE,UAAU,GAAG,OAAO,SAAS;EACvD,KAAK,SAAS;CAChB;;CAGA,MAAM,KAAK,WAAuC;EAChD,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,UAAU,EAC/C,OAAO,GACL,gBAAgB,KAAK,OAAO,QAAQ,CAAC,CAAC,cACtC,SACF,EACF,CAAC;CACH;;;;;;;;CASA,MAAM,OAAO,WAAmB,OAA6C;EAC3E,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU;GACjD,IAAI,KAAK;GACT;GACA,KAAK,MAAM;GACX,iBAAiB,QAAQ,KAAK,QAAQ,MAAM,MAAM;GAClD,QAAQ,MAAM,UAAU,MAAM,OAAO,SAAS,IAAI,KAAK,UAAU,MAAM,MAAM,IAAI;GACjF,WAAW;GACX,WAAW;EACb,CAAC;CACH;;CAGA,cAAc,KAAsB;EAClC,OAAO,kBAAkB,KAAK,QAAQ,IAAI,eAAe;CAC3D;;CAGA,MAAM,IAAI,WAAmB,IAAqC;EAKhE,MAAM,SAAQ,MAJM,KAAK,GAAG,KAAK,KAAK,OAAO,UAAU;GACrD,OAAO,GAAG,gBAAgB,KAAK,OAAO,QAAQ,CAAC,CAAC,OAAgC,EAAE;GAClF,OAAO;EACT,CAAC,EAAA,CACkB,MAAM;EACzB,OAAO,OAAO,cAAc,YAAY,QAAQ;CAClD;;CAGA,MAAM,OAAO,WAAmB,IAA2B;EACzD,MAAM,WAAW,MAAM,KAAK,IAAI,WAAW,EAAE;EAC7C,IAAI,UACF,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU,SAAS,EAAE;CAE1D;;CAGA,OAAO,SAAS,SAA4B;EAC1C,IAAI,CAAC,QAAQ,QACX,OAAO,CAAC;EAEV,IAAI;GACF,MAAM,SAAkB,KAAK,MAAM,QAAQ,MAAM;GACjD,OAAO,MAAM,QAAQ,MAAM,IACvB,OAAO,QAAQ,UAA2B,OAAO,UAAU,QAAQ,IACnE,CAAC;EACP,QAAQ;GACN,OAAO,CAAC;EACV;CACF;AACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
import { WebhookCreateInput, WebhookModel } from "./models/webhook.mjs";
|
|
4
|
+
import { BuildCreateInput, BuildListFilter, BuildModel, isPublicBuild } from "./models/build.mjs";
|
|
5
|
+
import { AttemptLogRecorder, CaptureAttemptModel, CaptureAttemptTables, emitAttemptLog } from "./models/capture-attempt.mjs";
|
|
6
|
+
import { CaptureLogModel, CaptureLogTables } from "./models/capture-log.mjs";
|
|
7
|
+
import { ProjectCreateInput, ProjectModel } from "./models/project.mjs";
|
|
8
|
+
import { BaselineModel } from "./models/baseline.mjs";
|
|
9
|
+
import { SnapshotCreateInput, SnapshotModel } from "./models/snapshot.mjs";
|
|
10
|
+
import { StatusConfigCreateInput, StatusConfigModel } from "./models/status-config.mjs";
|
|
11
|
+
import { BaselineStatus, NO_BASELINE, baselineStatus, isBaselineDrifted } from "./models/baseline-status.mjs";
|
|
12
|
+
import { CommentCreateInput, CommentModel } from "./models/comment.mjs";
|
|
13
|
+
import { LabelModel } from "./models/label.mjs";
|
|
14
|
+
import { MemberModel } from "./models/member.mjs";
|
|
15
|
+
import { NotificationChannelCreateInput, NotificationChannelModel, NotificationChannelTables } from "./models/notification-channel.mjs";
|
|
16
|
+
import { NotificationSubscriptionInput, NotificationSubscriptionModel, NotificationSubscriptionTables } from "./models/notification-subscription.mjs";
|
|
17
|
+
import { ProjectGroupMappingModel } from "./models/project-group-mapping.mjs";
|
|
18
|
+
import { TokenModel } from "./models/token.mjs";
|
|
19
|
+
import { UserModel } from "./models/user.mjs";
|
|
20
|
+
import { ContentRefModel } from "./models/content-ref.mjs";
|
|
21
|
+
import { CredentialProbe, ReencryptResult, UnreadableCredential, probeCredentials, reencryptCredentials } from "./models/credentials.mjs";
|
|
22
|
+
export { type AttemptLogRecorder, BaselineModel, type BaselineStatus, type BuildCreateInput, type BuildListFilter, BuildModel, CaptureAttemptModel, type CaptureAttemptTables, CaptureLogModel, type CaptureLogTables, type CommentCreateInput, CommentModel, ContentRefModel, type CredentialProbe, LabelModel, MemberModel, NO_BASELINE, type NotificationChannelCreateInput, NotificationChannelModel, type NotificationChannelTables, type NotificationSubscriptionInput, NotificationSubscriptionModel, type NotificationSubscriptionTables, type ProjectCreateInput, ProjectGroupMappingModel, ProjectModel, type ReencryptResult, type SnapshotCreateInput, SnapshotModel, type StatusConfigCreateInput, StatusConfigModel, TokenModel, type UnreadableCredential, UserModel, type WebhookCreateInput, WebhookModel, baselineStatus, emitAttemptLog, isBaselineDrifted, isPublicBuild, probeCredentials, reencryptCredentials };
|
package/dist/models.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { WebhookModel } from "./models/webhook.mjs";
|
|
5
|
+
import { BuildModel, isPublicBuild } from "./models/build.mjs";
|
|
6
|
+
import { CaptureAttemptModel, emitAttemptLog } from "./models/capture-attempt.mjs";
|
|
7
|
+
import { ProjectModel } from "./models/project.mjs";
|
|
8
|
+
import { BaselineModel } from "./models/baseline.mjs";
|
|
9
|
+
import { NO_BASELINE, baselineStatus, isBaselineDrifted } from "./models/baseline-status.mjs";
|
|
10
|
+
import { SnapshotModel } from "./models/snapshot.mjs";
|
|
11
|
+
import { StatusConfigModel } from "./models/status-config.mjs";
|
|
12
|
+
import { CaptureLogModel } from "./models/capture-log.mjs";
|
|
13
|
+
import { CommentModel } from "./models/comment.mjs";
|
|
14
|
+
import { LabelModel } from "./models/label.mjs";
|
|
15
|
+
import { MemberModel } from "./models/member.mjs";
|
|
16
|
+
import { NotificationChannelModel } from "./models/notification-channel.mjs";
|
|
17
|
+
import { NotificationSubscriptionModel } from "./models/notification-subscription.mjs";
|
|
18
|
+
import { ProjectGroupMappingModel } from "./models/project-group-mapping.mjs";
|
|
19
|
+
import { TokenModel } from "./models/token.mjs";
|
|
20
|
+
import { UserModel } from "./models/user.mjs";
|
|
21
|
+
import { ContentRefModel } from "./models/content-ref.mjs";
|
|
22
|
+
import { probeCredentials, reencryptCredentials } from "./models/credentials.mjs";
|
|
23
|
+
export { BaselineModel, BuildModel, CaptureAttemptModel, CaptureLogModel, CommentModel, ContentRefModel, LabelModel, MemberModel, NO_BASELINE, NotificationChannelModel, NotificationSubscriptionModel, ProjectGroupMappingModel, ProjectModel, SnapshotModel, StatusConfigModel, TokenModel, UserModel, WebhookModel, baselineStatus, emitAttemptLog, isBaselineDrifted, isPublicBuild, probeCredentials, reencryptCredentials };
|