@storyshelf/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/README.md +127 -0
  2. package/dist/adapter/auth.d.mts +50 -0
  3. package/dist/adapter/auth.mjs +10 -0
  4. package/dist/adapter/auth.mjs.map +1 -0
  5. package/dist/adapter/capture-runner.d.mts +70 -0
  6. package/dist/adapter/capture-runner.mjs +4 -0
  7. package/dist/adapter/database.d.mts +43 -0
  8. package/dist/adapter/database.mjs +4 -0
  9. package/dist/adapter/git-host/helpers.d.mts +12 -0
  10. package/dist/adapter/git-host/helpers.mjs +29 -0
  11. package/dist/adapter/git-host/helpers.mjs.map +1 -0
  12. package/dist/adapter/git-host.d.mts +46 -0
  13. package/dist/adapter/git-host.mjs +4 -0
  14. package/dist/adapter/storage.d.mts +22 -0
  15. package/dist/adapter/storage.mjs +4 -0
  16. package/dist/adapters/capture-queue.d.mts +49 -0
  17. package/dist/adapters/metadata.d.mts +24 -0
  18. package/dist/adapters/webhook-events.mjs +39 -0
  19. package/dist/adapters/webhook-events.mjs.map +1 -0
  20. package/dist/capture/adapter.d.mts +29 -0
  21. package/dist/capture/adapter.mjs +13 -0
  22. package/dist/capture/adapter.mjs.map +1 -0
  23. package/dist/capture/orchestrator.d.mts +23 -0
  24. package/dist/capture/orchestrator.mjs +103 -0
  25. package/dist/capture/orchestrator.mjs.map +1 -0
  26. package/dist/capture/pipeline.d.mts +41 -0
  27. package/dist/capture/pipeline.mjs +119 -0
  28. package/dist/capture/pipeline.mjs.map +1 -0
  29. package/dist/capture/queue.d.mts +35 -0
  30. package/dist/capture/queue.mjs +96 -0
  31. package/dist/capture/queue.mjs.map +1 -0
  32. package/dist/capture/status-fanout.mjs +66 -0
  33. package/dist/capture/status-fanout.mjs.map +1 -0
  34. package/dist/capture/storybook.d.mts +14 -0
  35. package/dist/capture/storybook.mjs +40 -0
  36. package/dist/capture/storybook.mjs.map +1 -0
  37. package/dist/config.d.mts +68 -0
  38. package/dist/config.mjs +69 -0
  39. package/dist/config.mjs.map +1 -0
  40. package/dist/ddl.d.mts +7 -0
  41. package/dist/ddl.mjs +155 -0
  42. package/dist/ddl.mjs.map +1 -0
  43. package/dist/diff/engine.d.mts +8 -0
  44. package/dist/diff/engine.mjs +79 -0
  45. package/dist/diff/engine.mjs.map +1 -0
  46. package/dist/diff/options.d.mts +40 -0
  47. package/dist/diff/options.mjs +15 -0
  48. package/dist/diff/options.mjs.map +1 -0
  49. package/dist/index.d.mts +48 -0
  50. package/dist/index.mjs +327 -0
  51. package/dist/index.mjs.map +1 -0
  52. package/dist/logger.d.mts +39 -0
  53. package/dist/logger.mjs +35 -0
  54. package/dist/logger.mjs.map +1 -0
  55. package/dist/middleware/csrf.mjs +39 -0
  56. package/dist/middleware/csrf.mjs.map +1 -0
  57. package/dist/middleware/rate-limit.mjs +38 -0
  58. package/dist/middleware/rate-limit.mjs.map +1 -0
  59. package/dist/models/baseline.d.mts +20 -0
  60. package/dist/models/baseline.mjs +89 -0
  61. package/dist/models/baseline.mjs.map +1 -0
  62. package/dist/models/build.d.mts +35 -0
  63. package/dist/models/build.mjs +77 -0
  64. package/dist/models/build.mjs.map +1 -0
  65. package/dist/models/comment.d.mts +20 -0
  66. package/dist/models/comment.mjs +42 -0
  67. package/dist/models/comment.mjs.map +1 -0
  68. package/dist/models/label.d.mts +43 -0
  69. package/dist/models/label.mjs +107 -0
  70. package/dist/models/label.mjs.map +1 -0
  71. package/dist/models/member.d.mts +27 -0
  72. package/dist/models/member.mjs +54 -0
  73. package/dist/models/member.mjs.map +1 -0
  74. package/dist/models/project.d.mts +42 -0
  75. package/dist/models/project.mjs +78 -0
  76. package/dist/models/project.mjs.map +1 -0
  77. package/dist/models/snapshot.d.mts +46 -0
  78. package/dist/models/snapshot.mjs +75 -0
  79. package/dist/models/snapshot.mjs.map +1 -0
  80. package/dist/models/status-config.mjs +61 -0
  81. package/dist/models/status-config.mjs.map +1 -0
  82. package/dist/models/token.d.mts +33 -0
  83. package/dist/models/token.mjs +60 -0
  84. package/dist/models/token.mjs.map +1 -0
  85. package/dist/models/webhook.d.mts +37 -0
  86. package/dist/models/webhook.mjs +67 -0
  87. package/dist/models/webhook.mjs.map +1 -0
  88. package/dist/pages/build-detail.mjs +333 -0
  89. package/dist/pages/build-detail.mjs.map +1 -0
  90. package/dist/pages/build-diff.mjs +437 -0
  91. package/dist/pages/build-diff.mjs.map +1 -0
  92. package/dist/pages/compute-jobs.mjs +196 -0
  93. package/dist/pages/compute-jobs.mjs.map +1 -0
  94. package/dist/pages/login.mjs +77 -0
  95. package/dist/pages/login.mjs.map +1 -0
  96. package/dist/pages/project-builds.mjs +228 -0
  97. package/dist/pages/project-builds.mjs.map +1 -0
  98. package/dist/pages/project-create.mjs +168 -0
  99. package/dist/pages/project-create.mjs.map +1 -0
  100. package/dist/pages/project-settings.mjs +111 -0
  101. package/dist/pages/project-settings.mjs.map +1 -0
  102. package/dist/pages/projects.mjs +178 -0
  103. package/dist/pages/projects.mjs.map +1 -0
  104. package/dist/pages/root.mjs +90 -0
  105. package/dist/pages/root.mjs.map +1 -0
  106. package/dist/pages/settings-general.mjs +191 -0
  107. package/dist/pages/settings-general.mjs.map +1 -0
  108. package/dist/pages/settings-labels.mjs +149 -0
  109. package/dist/pages/settings-labels.mjs.map +1 -0
  110. package/dist/pages/settings-members.mjs +124 -0
  111. package/dist/pages/settings-members.mjs.map +1 -0
  112. package/dist/pages/settings-status.mjs +150 -0
  113. package/dist/pages/settings-status.mjs.map +1 -0
  114. package/dist/pages/settings-tokens.mjs +95 -0
  115. package/dist/pages/settings-tokens.mjs.map +1 -0
  116. package/dist/pages/settings-webhooks.mjs +149 -0
  117. package/dist/pages/settings-webhooks.mjs.map +1 -0
  118. package/dist/retention/purge.d.mts +28 -0
  119. package/dist/retention/purge.mjs +66 -0
  120. package/dist/retention/purge.mjs.map +1 -0
  121. package/dist/routers/admin.mjs +41 -0
  122. package/dist/routers/admin.mjs.map +1 -0
  123. package/dist/routers/assets.mjs +24 -0
  124. package/dist/routers/assets.mjs.map +1 -0
  125. package/dist/routers/auth.mjs +77 -0
  126. package/dist/routers/auth.mjs.map +1 -0
  127. package/dist/routers/builds.handlers.mjs +87 -0
  128. package/dist/routers/builds.handlers.mjs.map +1 -0
  129. package/dist/routers/builds.mjs +162 -0
  130. package/dist/routers/builds.mjs.map +1 -0
  131. package/dist/routers/comments.mjs +89 -0
  132. package/dist/routers/comments.mjs.map +1 -0
  133. package/dist/routers/helpers.mjs +76 -0
  134. package/dist/routers/helpers.mjs.map +1 -0
  135. package/dist/routers/htmx.mjs +18 -0
  136. package/dist/routers/htmx.mjs.map +1 -0
  137. package/dist/routers/labels.mjs +77 -0
  138. package/dist/routers/labels.mjs.map +1 -0
  139. package/dist/routers/media.mjs +54 -0
  140. package/dist/routers/media.mjs.map +1 -0
  141. package/dist/routers/members.mjs +101 -0
  142. package/dist/routers/members.mjs.map +1 -0
  143. package/dist/routers/projects.mjs +121 -0
  144. package/dist/routers/projects.mjs.map +1 -0
  145. package/dist/routers/schemas.mjs +188 -0
  146. package/dist/routers/schemas.mjs.map +1 -0
  147. package/dist/routers/settings.mjs +235 -0
  148. package/dist/routers/settings.mjs.map +1 -0
  149. package/dist/routers/snapshots.mjs +143 -0
  150. package/dist/routers/snapshots.mjs.map +1 -0
  151. package/dist/routers/status-configs.mjs +100 -0
  152. package/dist/routers/status-configs.mjs.map +1 -0
  153. package/dist/routers/tokens.mjs +80 -0
  154. package/dist/routers/tokens.mjs.map +1 -0
  155. package/dist/routers/ui.mjs +142 -0
  156. package/dist/routers/ui.mjs.map +1 -0
  157. package/dist/routers/webhooks.mjs +89 -0
  158. package/dist/routers/webhooks.mjs.map +1 -0
  159. package/dist/schema.d.mts +4372 -0
  160. package/dist/schema.mjs +158 -0
  161. package/dist/schema.mjs.map +1 -0
  162. package/dist/store.mjs +18 -0
  163. package/dist/store.mjs.map +1 -0
  164. package/dist/types.d.mts +18 -0
  165. package/dist/types.mjs +49 -0
  166. package/dist/types.mjs.map +1 -0
  167. package/dist/ui/components.mjs +127 -0
  168. package/dist/ui/components.mjs.map +1 -0
  169. package/dist/ui/document.d.mts +8 -0
  170. package/dist/ui/document.mjs +338 -0
  171. package/dist/ui/document.mjs.map +1 -0
  172. package/dist/ui/styles.mjs +173 -0
  173. package/dist/ui/styles.mjs.map +1 -0
  174. package/dist/ui/theme.mjs +42 -0
  175. package/dist/ui/theme.mjs.map +1 -0
  176. package/dist/urls.d.mts +19 -0
  177. package/dist/urls.mjs +23 -0
  178. package/dist/urls.mjs.map +1 -0
  179. package/dist/utils/encrypt.mjs +49 -0
  180. package/dist/utils/encrypt.mjs.map +1 -0
  181. package/dist/utils/hash.mjs +22 -0
  182. package/dist/utils/hash.mjs.map +1 -0
  183. package/dist/utils/paths.d.mts +11 -0
  184. package/dist/utils/paths.mjs +23 -0
  185. package/dist/utils/paths.mjs.map +1 -0
  186. package/dist/utils/ulid.d.mts +8 -0
  187. package/dist/utils/ulid.mjs +41 -0
  188. package/dist/utils/ulid.mjs.map +1 -0
  189. package/package.json +162 -0
package/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # @storyshelf/core
2
+
3
+ The heart of StoryShelf: the Hono router, adapter interfaces, models, capture pipeline, diff engine, and retention logic. Compose pluggable adapters into a complete self-hosted visual testing server.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ nub add @storyshelf/core
9
+ ```
10
+
11
+ or
12
+
13
+ ```sh
14
+ npm install @storyshelf/core
15
+ ```
16
+
17
+ ## Quick start
18
+
19
+ ```ts
20
+ import { createShelfRouter } from "@storyshelf/core";
21
+
22
+ const app = createShelfRouter({
23
+ database, // DatabaseAdapter
24
+ storage, // StorageAdapter
25
+ capture, // CaptureRunner (optional)
26
+ auth, // AuthAdapter (optional)
27
+ status, // StatusAdapter (optional)
28
+ logger, // pino Logger (optional; built internally if omitted)
29
+ ui: { name: "My Shelf" }, // UIConfig (optional)
30
+ config: { captureConcurrency: 2, purgeTtlDays: 30 }, // ShelfConfig (optional)
31
+ });
32
+
33
+ // The returned app is a Hono instance; serve it with any Hono adapter.
34
+ serve({ fetch: app.fetch, port: 3000 });
35
+ ```
36
+
37
+ ## API
38
+
39
+ ### `createShelfRouter(options: ShelfOptions): Hono`
40
+
41
+ Assembles the router from the provided adapters. `ShelfOptions`:
42
+
43
+ | Option | Type | Description |
44
+ | ------ | ---- | ----------- |
45
+ | `database` | `DatabaseAdapter` | **Required.** Data access. |
46
+ | `storage` | `StorageAdapter` | **Required.** Blob storage for screenshots, diffs, storybook archives. |
47
+ | `capture` | `CaptureRunner` | Optional. Enables the async capture queue. |
48
+ | `auth` | `AuthAdapter` | Optional. Enables auth and the login UI. |
49
+ | `status` | `StatusAdapter` | Optional. Reports CI status checks. |
50
+ | `logger` | `Logger` (pino) | Optional. Shared logger. Construct a fallback via `createShelfLogger()`. |
51
+ | `ui` | `UIConfig` | Optional. UI branding. |
52
+ | `config` | `ShelfConfig` | Optional. Server behavior. |
53
+
54
+ ### `ShelfConfig`
55
+
56
+ ```ts
57
+ interface ShelfConfig {
58
+ secret?: string; // session signing secret
59
+ publishedBaseDomain?: string; // for published storybook URLs
60
+ captureConcurrency?: number; // concurrent capture jobs (default 2)
61
+ purgeTtlDays?: number; // purge builds older than N days
62
+ viewports?: Viewport[]; // capture viewports
63
+ }
64
+ ```
65
+
66
+ ### `UIConfig`
67
+
68
+ ```ts
69
+ interface UIConfig {
70
+ name?: string;
71
+ logo?: string;
72
+ favicon?: string;
73
+ lightTheme?: BrandTheme;
74
+ darkTheme?: BrandTheme;
75
+ }
76
+ ```
77
+
78
+ ### Adapter interfaces
79
+
80
+ All adapters are constructor-injected (no AsyncLocalStorage). See `docs/architecture.md` for the entity model and workflow.
81
+
82
+ - `DatabaseAdapter` — `insert`, `update`, `get`, `remove`, `list`, `count`, `all`, `migrate`, `close`. Also exports `ListOptions`.
83
+ - `StorageAdapter` — `read`, `write`, `delete`, `exists`, `list(prefix)`.
84
+ - `AuthAdapter` — `check(request)`, `createSession(user)`, `destroySession(sessionId)`, optional `handleCallback(callback)`. Also exports `AuthUser`, `AuthCallback`, and the shared `SESSION_COOKIE`.
85
+ - `CaptureRunner` — a **pure capture renderer**: `render(input) => RenderResult`, `cancel(buildId)`. Also exports `JobStatus`, `RenderedSnapshot`, `RenderResult`.
86
+ - `StatusAdapter` — `setStatus(context, gitSha, status, url)`. Also exports `CheckStatus`.
87
+
88
+ ### Logging
89
+
90
+ `core` uses **pino** for structured JSON logging. `createShelfLogger({ level, transports, env })` builds a logger writing to stdout by default, with optional extra pino worker transports (Sentry, PostHog, Datadog, GCP, OTEL collector, etc.). Pass the resulting `Logger` to `createShelfRouter({ logger })` (or construct it at your composition root) so request and background logs share one stream. The capture orchestrator derives a `reqId`-scoped child for background capture work, correlating each capture back to the triggering HTTP request. See ADR 0014.
91
+
92
+ ### Capture, diff, and retention
93
+
94
+ - `executeCaptureJob({ buildId, reqId }, deps)` — the capture **orchestrator**: loads the build, marks it `capturing`, extracts the uploaded archive into `scratchDir`, discovers stories, delegates rendering to a pure `CaptureRunner`, and persists. `createShelfRouter` wires it into a `CaptureQueue` when `capture` is supplied (and requires `ShelfConfig.scratchDir`). Also exports `CaptureJobOptions`.
95
+ - `persistCapture(ctx: CaptureContext)` — writes screenshots, diffs against the branch baseline, creates snapshots, and finalizes a build from a pure renderer's `captures`. Also exports `CaptureContext` and the `StorySourceAdapter`/`StoryEntry`/`Viewport` types.
96
+ - `StorybookAdapter` — reads a built Storybook's `index.json`/`stories.json`.
97
+ - `diffImages(baseline: Buffer, current: Buffer, options: DiffOptions): DiffResult` — pixelmatch-based diff. Also exports `DiffOptions`, `DiffResult`.
98
+ - `CaptureQueue` — the **capture queue adapter**: `enqueue({ buildId, reqId? })`, plus `status`, `active`, `recent`. `enqueue` returns once a build is queued (async, "queued"); the job runs in a worker. Default is `InMemoryCaptureQueue` (in-process, concurrency-limited, for long-lived hosts); supply a remote queue with a separate worker for serverless. Also exports `CaptureJob`, `QueueEntry`, `JobStatus`.
99
+ - `Retention` — `new Retention(db, storage, logger?)`, with `purge(project, { ttlDays, keepLatestPerBranch })`.
100
+
101
+ ### Helpers
102
+
103
+ - `createUrlBuilder(baseUrl, publishedBaseDomain?)` — type-safe URL builder. Also exports `UrlBuilder`.
104
+ - `ulid`, `slugify`.
105
+ - Path helpers: `screenshotPath`, `diffPath`, `baselinePath`, `storybookDir`, `storybookZipPath`.
106
+ - `RenderedContent` type for the server-rendered UI.
107
+
108
+ ## How it fits in
109
+
110
+ `core` is the framework everything else plugs into: `createShelfRouter` takes database, storage, capture, and auth adapters (from the `db-*`, `storage-*`, and `auth-*` packages) and produces a complete Hono server. The web UI is server-rendered `hono/jsx` + HTMX, and custom UIs can consume the JSON API under `/api/v1`.
111
+
112
+ See `docs/architecture.md` and the ADRs in `docs/adr/`.
113
+
114
+ ## Deployment targets
115
+
116
+ The core router is runtime-agnostic (Web `Request`/`Response`, `fetch`, `crypto`, `URL`). The only Node-specific code in the stack is `@hono/node-server` in `@storyshelf/node-server`. You can assemble on any platform:
117
+
118
+ | Platform | Database | Storage | Capture queue | Server entry |
119
+ |----------|----------|---------|---------------|--------------|
120
+ | **Vercel** | `@storyshelf/db-turso` | `@storyshelf/storage-s3` (R2/S3) | Remote `CaptureQueue` + worker | Hono + `@hono/vercel-edge` |
121
+ | **Cloudflare Workers** | `@storyshelf/db-turso` | `@storyshelf/storage-s3` (R2) | Workers Queues `CaptureQueue` | Hono + Workers entry |
122
+ | **Azure Functions** | `@storyshelf/db-turso` | `@storyshelf/storage-s3` (Blob) | Azure Queues `CaptureQueue` | Hono + Azure handler |
123
+ | **AWS Lambda** | `@storyshelf/db-turso` | `@storyshelf/storage-s3` | SQS `CaptureQueue` | Hono + Lambda handler |
124
+ | **Deno Deploy** | `@storyshelf/db-turso` | `@storyshelf/storage-s3` | Custom `CaptureQueue` (Deno KV) | Hono + Deno entry |
125
+ | **Bun / Node (VPS, Fly, Railway, Render)** | `db-sqlite` / `db-turso` | `storage-local` / `storage-s3` | `InMemoryCaptureQueue` | `storyshelf-server serve` |
126
+
127
+ All clouds are equal — pick the adapters that match your infrastructure. See the **Deployment** guide for recipes including a minimal Turso + S3 + `InMemoryCaptureQueue` example.
@@ -0,0 +1,50 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { AdapterMetadata } from "../adapters/metadata.mjs";
4
+ import { ProjectRole, SiteRole } from "../types.mjs";
5
+ //#region src/adapters/auth.d.ts
6
+ /** Shared session cookie name used by all auth adapters (ADR 0008). */
7
+ declare const SESSION_COOKIE = "storyshelf_session";
8
+ /** An authenticated user of the platform. */
9
+ interface AuthUser {
10
+ /** User ID. */
11
+ id: string;
12
+ /** User email. */
13
+ email: string;
14
+ /** Display name. */
15
+ name: string;
16
+ /** Optional avatar URL. */
17
+ avatarUrl?: string;
18
+ /** Site-wide role. */
19
+ role: SiteRole;
20
+ }
21
+ /** Data passed to an auth adapter when an OAuth callback is received. */
22
+ interface AuthCallback {
23
+ /** Provider name. */
24
+ provider: string;
25
+ /** Authorization code from the provider. */
26
+ code: string;
27
+ /** Anti-CSRF state value. */
28
+ state: string;
29
+ }
30
+ /** Access controls granted to a user for a specific project. */
31
+ interface ProjectAccess {
32
+ /** Project role. */
33
+ role: ProjectRole;
34
+ }
35
+ /** Pluggable authentication abstraction (ADR 0008). */
36
+ interface AuthAdapter {
37
+ /** Adapter identity. */
38
+ readonly metadata?: AdapterMetadata;
39
+ /** Resolve the current user from a request, or null if unauthenticated. */
40
+ check(request: Request): Promise<AuthUser | null>;
41
+ /** Create a session for a user and return a session token. */
42
+ createSession(user: AuthUser): Promise<string>;
43
+ /** Destroy a session by its id. */
44
+ destroySession(sessionId: string): Promise<void>;
45
+ /** Handle an OAuth callback and return the resolved user, if supported. */
46
+ handleCallback?(callback: AuthCallback): Promise<AuthUser | null>;
47
+ }
48
+ //#endregion
49
+ export { AuthAdapter, AuthCallback, AuthUser, ProjectAccess, SESSION_COOKIE };
50
+ //# sourceMappingURL=auth.d.mts.map
@@ -0,0 +1,10 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ //#region src/adapters/auth.ts
5
+ /** Shared session cookie name used by all auth adapters (ADR 0008). */
6
+ const SESSION_COOKIE = "storyshelf_session";
7
+ //#endregion
8
+ export { SESSION_COOKIE };
9
+
10
+ //# sourceMappingURL=auth.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.mjs","names":[],"sources":["../../src/adapters/auth.ts"],"sourcesContent":["import type { AdapterMetadata } from \"./metadata.ts\";\nimport type { ProjectRole, SiteRole } from \"../types.ts\";\n\n/** Shared session cookie name used by all auth adapters (ADR 0008). */\nexport const SESSION_COOKIE = \"storyshelf_session\";\n\n/** An authenticated user of the platform. */\nexport interface AuthUser {\n /** User ID. */\n id: string;\n /** User email. */\n email: string;\n /** Display name. */\n name: string;\n /** Optional avatar URL. */\n avatarUrl?: string;\n /** Site-wide role. */\n role: SiteRole;\n}\n\n/** Data passed to an auth adapter when an OAuth callback is received. */\nexport interface AuthCallback {\n /** Provider name. */\n provider: string;\n /** Authorization code from the provider. */\n code: string;\n /** Anti-CSRF state value. */\n state: string;\n}\n\n/** Access controls granted to a user for a specific project. */\nexport interface ProjectAccess {\n /** Project role. */\n role: ProjectRole;\n}\n\n/** Pluggable authentication abstraction (ADR 0008). */\nexport interface AuthAdapter {\n /** Adapter identity. */\n readonly metadata?: AdapterMetadata;\n /** Resolve the current user from a request, or null if unauthenticated. */\n check(request: Request): Promise<AuthUser | null>;\n /** Create a session for a user and return a session token. */\n createSession(user: AuthUser): Promise<string>;\n /** Destroy a session by its id. */\n destroySession(sessionId: string): Promise<void>;\n /** Handle an OAuth callback and return the resolved user, if supported. */\n handleCallback?(callback: AuthCallback): Promise<AuthUser | null>;\n}\n"],"mappings":";;;;;AAIA,MAAa,iBAAiB"}
@@ -0,0 +1,70 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { AdapterMetadata } from "../adapters/metadata.mjs";
4
+ import { StoryEntry, Viewport } from "../capture/adapter.mjs";
5
+ import { JobStatus } from "../adapters/capture-queue.mjs";
6
+ import { Logger } from "pino";
7
+ //#region src/adapters/capture-runner.d.ts
8
+ /** A screenshot produced by a capture renderer. */
9
+ interface RenderedSnapshot {
10
+ /** The rendered story (echoed back from the render request). */
11
+ story: StoryEntry;
12
+ /** Viewport name the screenshot was captured at. */
13
+ viewportName: string;
14
+ /** PNG screenshot bytes. */
15
+ screenshot: Buffer;
16
+ }
17
+ /** A story/viewport that a renderer could not capture. */
18
+ interface RenderFailure {
19
+ /** Story that failed to render. */
20
+ storyId: string;
21
+ /** Viewport that failed to render. */
22
+ viewportName: string;
23
+ /** Error message. */
24
+ error: string;
25
+ }
26
+ /** The outcome of a render request. */
27
+ interface RenderResult {
28
+ /** Screenshots the renderer produced successfully. */
29
+ captures: RenderedSnapshot[];
30
+ /** Story/viewport pairs the renderer could not capture. */
31
+ failures: RenderFailure[];
32
+ }
33
+ /**
34
+ * A pure capture renderer.
35
+ *
36
+ * Adapters implementing `CaptureRunner` render screenshots from an
37
+ * already-extracted Storybook directory and return PNG buffers. They are
38
+ * intentionally pure: they perform **no** database, storage, or build-state
39
+ * management. Loading the build, extracting the uploaded archive, persisting
40
+ * snapshots/baselines/diffs, and advancing build status are the capture
41
+ * orchestrator's job (see `capture/orchestrator.ts`), keeping every adapter
42
+ * implementation free of server concerns.
43
+ */
44
+ interface CaptureRunner {
45
+ /** Adapter identity. */
46
+ readonly metadata?: AdapterMetadata;
47
+ /**
48
+ * Render configured viewports for the given stories of an extracted
49
+ * Storybook and return the screenshot buffers.
50
+ *
51
+ * @param input - Render request with the extracted Storybook directory.
52
+ */
53
+ render(input: {
54
+ /** Build being captured, used to correlate cancels with in-flight work. */
55
+ buildId: string;
56
+ /** Root of the already-extracted Storybook build. */
57
+ storybookDir: string;
58
+ /** Stories to render. */
59
+ stories: StoryEntry[];
60
+ /** Viewports to capture. */
61
+ viewports: Viewport[];
62
+ /** Optional logger for render-time diagnostics. */
63
+ logger?: Logger;
64
+ }): Promise<RenderResult>;
65
+ /** Cancel a pending or in-flight render for a build. */
66
+ cancel(buildId: string): Promise<void>;
67
+ }
68
+ //#endregion
69
+ export { CaptureRunner, type JobStatus, RenderFailure, RenderResult, RenderedSnapshot };
70
+ //# sourceMappingURL=capture-runner.d.mts.map
@@ -0,0 +1,4 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ export {};
@@ -0,0 +1,43 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { AdapterMetadata } from "../adapters/metadata.mjs";
4
+ import { SQL } from "drizzle-orm";
5
+ import { AnySQLiteTable } from "drizzle-orm/sqlite-core";
6
+ //#region src/adapters/database.d.ts
7
+ /** Options that narrow and page a list query. */
8
+ interface ListOptions {
9
+ /** SQL WHERE condition. */
10
+ where?: SQL;
11
+ /** SQL ORDER BY condition. */
12
+ orderBy?: SQL;
13
+ /** Maximum number of rows to return. */
14
+ limit?: number;
15
+ /** Number of rows to skip. */
16
+ offset?: number;
17
+ }
18
+ /** Database abstraction over Drizzle tables, agnostic of the underlying driver. */
19
+ interface DatabaseAdapter {
20
+ /** Adapter identity. */
21
+ readonly metadata?: AdapterMetadata;
22
+ /** Insert a row and return the inserted record. */
23
+ insert<T extends AnySQLiteTable>(table: T, values: T["$inferInsert"]): Promise<T["$inferSelect"]>;
24
+ /** Update a row by id and return the updated record. */
25
+ update<T extends AnySQLiteTable>(table: T, id: string, values: Partial<T["$inferInsert"]>): Promise<T["$inferSelect"]>;
26
+ /** Fetch a single row by id, or null if not found. */
27
+ get<T extends AnySQLiteTable>(table: T, id: string): Promise<T["$inferSelect"] | null>;
28
+ /** Delete a row by id. */
29
+ remove(table: AnySQLiteTable, id: string): Promise<void>;
30
+ /** List rows matching the given options. */
31
+ list<T extends AnySQLiteTable>(table: T, opts?: ListOptions): Promise<T["$inferSelect"][]>;
32
+ /** Count rows matching an optional where condition. */
33
+ count(table: AnySQLiteTable, where?: SQL): Promise<number>;
34
+ /** Run an arbitrary SQL query and return typed rows. */
35
+ all<T>(query: SQL): Promise<T[]>;
36
+ /** Apply any pending schema migrations. */
37
+ migrate(): Promise<void>;
38
+ /** Close the underlying database connection. */
39
+ close(): Promise<void>;
40
+ }
41
+ //#endregion
42
+ export { DatabaseAdapter, ListOptions };
43
+ //# sourceMappingURL=database.d.mts.map
@@ -0,0 +1,4 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ export {};
@@ -0,0 +1,12 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { CheckStatus } from "../git-host.mjs";
4
+ //#region src/adapters/git-host/helpers.d.ts
5
+ /** Human description for a check status — shared across GitHub/GitLab. */
6
+ declare function describeStatus(status: CheckStatus): string;
7
+ /** Markdown comment body helpers — single comment per build, idempotent via marker. */
8
+ declare function commentMarker(url: string): string;
9
+ declare function buildCommentMarkdown(status: CheckStatus, url: string, context: string): string;
10
+ //#endregion
11
+ export { buildCommentMarkdown, commentMarker, describeStatus };
12
+ //# sourceMappingURL=helpers.d.mts.map
@@ -0,0 +1,29 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ //#region src/adapters/git-host/helpers.ts
5
+ /** Human description for a check status — shared across GitHub/GitLab. */
6
+ function describeStatus(status) {
7
+ switch (status) {
8
+ case "pending": return "Visual tests pending";
9
+ case "success": return "Visual tests passed";
10
+ case "failure": return "Visual changes detected or tests failed";
11
+ default: return "Visual changes detected or tests failed";
12
+ }
13
+ }
14
+ /** Markdown comment body helpers — single comment per build, idempotent via marker. */
15
+ function commentMarker(url) {
16
+ return `<!-- storyshelf:${url} -->`;
17
+ }
18
+ function buildCommentMarkdown(status, url, context) {
19
+ switch (status) {
20
+ case "pending": return `Visual tests pending for \`${context}\` — [View build](${url})`;
21
+ case "success": return `Visual tests passed for \`${context}\` — [View build](${url})`;
22
+ case "failure": return `Visual changes detected for \`${context}\` — [View build](${url})`;
23
+ default: return `Visual tests \`${status}\` for \`${context}\` — [View build](${url})`;
24
+ }
25
+ }
26
+ //#endregion
27
+ export { buildCommentMarkdown, commentMarker, describeStatus };
28
+
29
+ //# sourceMappingURL=helpers.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.mjs","names":[],"sources":["../../../src/adapters/git-host/helpers.ts"],"sourcesContent":["import type { CheckStatus } from \"./index.ts\";\n\n/** Human description for a check status — shared across GitHub/GitLab. */\nexport function describeStatus(status: CheckStatus): string {\n switch (status) {\n case \"pending\": {\n return \"Visual tests pending\";\n }\n case \"success\": {\n return \"Visual tests passed\";\n }\n case \"failure\": {\n return \"Visual changes detected or tests failed\";\n }\n default: {\n return \"Visual changes detected or tests failed\";\n }\n }\n}\n\n/** Markdown comment body helpers — single comment per build, idempotent via marker. */\nexport function commentMarker(url: string): string {\n return `<!-- storyshelf:${url} -->`;\n}\n\nexport function buildCommentMarkdown(status: CheckStatus, url: string, context: string): string {\n switch (status) {\n case \"pending\": {\n return `Visual tests pending for \\`${context}\\` — [View build](${url})`;\n }\n case \"success\": {\n return `Visual tests passed for \\`${context}\\` — [View build](${url})`;\n }\n case \"failure\": {\n return `Visual changes detected for \\`${context}\\` — [View build](${url})`;\n }\n default: {\n // eslint-disable-next-line restrict-template-expressions -- status is never in default case\n return `Visual tests \\`${status}\\` for \\`${context}\\` — [View build](${url})`;\n }\n }\n}\n"],"mappings":";;;;;AAGA,SAAgB,eAAe,QAA6B;CAC1D,QAAQ,QAAR;EACE,KAAK,WACH,OAAO;EAET,KAAK,WACH,OAAO;EAET,KAAK,WACH,OAAO;EAET,SACE,OAAO;CAEX;AACF;;AAGA,SAAgB,cAAc,KAAqB;CACjD,OAAO,mBAAmB,IAAI;AAChC;AAEA,SAAgB,qBAAqB,QAAqB,KAAa,SAAyB;CAC9F,QAAQ,QAAR;EACE,KAAK,WACH,OAAO,8BAA8B,QAAQ,oBAAoB,IAAI;EAEvE,KAAK,WACH,OAAO,6BAA6B,QAAQ,oBAAoB,IAAI;EAEtE,KAAK,WACH,OAAO,iCAAiC,QAAQ,oBAAoB,IAAI;EAE1E,SAEE,OAAO,kBAAkB,OAAO,WAAW,QAAQ,oBAAoB,IAAI;CAE/E;AACF"}
@@ -0,0 +1,46 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { GitAdapterMetadata } from "../adapters/metadata.mjs";
4
+ import { Logger } from "pino";
5
+ //#region src/adapters/git-host/index.d.ts
6
+ /** Status of a git-host provider check. */
7
+ type CheckStatus = "pending" | "success" | "failure";
8
+ /** Descriptor — registered at startup, validates per-project config. */
9
+ interface GitHostProvider {
10
+ /** Adapter identity (name, version, description, kind="github", logo, schema). */
11
+ readonly metadata: GitAdapterMetadata;
12
+ /** Create a configured instance bound to a project config + decrypted token. */
13
+ create(opts: {
14
+ config: unknown;
15
+ token: string;
16
+ logger?: Logger;
17
+ }): GitHostAdapter;
18
+ }
19
+ /** Runtime — bound to a project config + token, posts statuses/comments. */
20
+ interface GitHostAdapter {
21
+ /** Adapter identity. */
22
+ readonly metadata: GitAdapterMetadata;
23
+ /** Set the status of a commit. */
24
+ setStatus(opts: {
25
+ context: string;
26
+ gitSha: string;
27
+ status: CheckStatus;
28
+ url: string;
29
+ }): Promise<void>;
30
+ /** Whether the branch/sha is already merged — gate to skip capture. */
31
+ isMerged?(opts: {
32
+ sha: string;
33
+ branch: string;
34
+ }): Promise<boolean>;
35
+ /** Create or update a single PR comment per build (idempotent via url marker). */
36
+ upsertComment?(opts: {
37
+ prNumber?: number;
38
+ sha: string;
39
+ url: string;
40
+ status: CheckStatus;
41
+ markdown: string;
42
+ }): Promise<string>;
43
+ }
44
+ //#endregion
45
+ export { CheckStatus, GitHostAdapter, GitHostProvider };
46
+ //# sourceMappingURL=git-host.d.mts.map
@@ -0,0 +1,4 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ export {};
@@ -0,0 +1,22 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { AdapterMetadata } from "../adapters/metadata.mjs";
4
+ //#region src/adapters/storage.d.ts
5
+ /** Blob storage abstraction for screenshots, diffs and Storybook archives. */
6
+ interface StorageAdapter {
7
+ /** Adapter identity. */
8
+ readonly metadata?: AdapterMetadata;
9
+ /** Read the bytes stored at `path`. */
10
+ read(path: string): Promise<Buffer>;
11
+ /** Write `data` to `path`, creating parent directories as needed. */
12
+ write(path: string, data: Buffer): Promise<void>;
13
+ /** Delete the object at `path` if it exists. */
14
+ delete(path: string): Promise<void>;
15
+ /** Return whether an object exists at `path`. */
16
+ exists(path: string): Promise<boolean>;
17
+ /** List object paths under the given key prefix. */
18
+ list(prefix: string): Promise<string[]>;
19
+ }
20
+ //#endregion
21
+ export { StorageAdapter };
22
+ //# sourceMappingURL=storage.d.mts.map
@@ -0,0 +1,4 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ export {};
@@ -0,0 +1,49 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { AdapterMetadata } from "./metadata.mjs";
4
+ //#region src/adapters/capture-queue.d.ts
5
+ type JobStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
6
+ interface QueueEntry {
7
+ buildId: string;
8
+ status: JobStatus;
9
+ queuedAt: string;
10
+ startedAt?: string;
11
+ finishedAt?: string;
12
+ error?: string;
13
+ }
14
+ /** A build submitted for capture. */
15
+ interface CaptureJob {
16
+ buildId: string;
17
+ /** Request id used to correlate the background job with the request that queued it. */
18
+ reqId?: string;
19
+ }
20
+ /**
21
+ * A capture job queue, decoupled from the runtime.
22
+ *
23
+ * `enqueue` submits a build for capture and returns quickly; the build is
24
+ * tracked as "queued". The capture itself runs in a worker:
25
+ *
26
+ * - the in-memory implementation (`InMemoryCaptureQueue`, in
27
+ * `capture/capture-queue.ts`) runs the job in-process on a long-lived
28
+ * Node server;
29
+ * - a remote implementation (e.g. SQS, Cloudflare Queues, Azure Storage
30
+ * Queues) pushes the job and leaves execution to a separately-assembled
31
+ * worker that polls the queue and runs `executeCaptureJob`.
32
+ *
33
+ * `status`/`active`/`recent` back the live queue view regardless of transport.
34
+ */
35
+ interface CaptureQueue {
36
+ /** Adapter identity. */
37
+ readonly metadata?: AdapterMetadata;
38
+ /** Submit a build for capture. Resolves once the build is queued. */
39
+ enqueue(job: CaptureJob): Promise<void>;
40
+ /** Return the current status entry for a build, or null if untracked. */
41
+ status(buildId: string): Promise<QueueEntry | null>;
42
+ /** Queue entries that are queued or running. */
43
+ active(): Promise<QueueEntry[]>;
44
+ /** The most recent queue entries, newest first. */
45
+ recent(limit: number): Promise<QueueEntry[]>;
46
+ }
47
+ //#endregion
48
+ export { CaptureJob, CaptureQueue, JobStatus, QueueEntry };
49
+ //# sourceMappingURL=capture-queue.d.mts.map
@@ -0,0 +1,24 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { z } from "zod";
4
+ //#region src/adapters/metadata.d.ts
5
+ /** Common adapter identity — every adapter instance exposes this. */
6
+ interface AdapterMetadata {
7
+ /** Human label for UI/logs. */
8
+ readonly name: string;
9
+ /** Package version injected at build via __PKG_VERSION__. */
10
+ readonly version: string;
11
+ /** Optional short description. */
12
+ readonly description?: string;
13
+ /** Machine key (e.g. "github", "sqlite", "local", "s3", "password", "oauth", "playwright", "sqs", "memory"). */
14
+ readonly kind: string;
15
+ }
16
+ /** Git-specific metadata extension (adds logo + validation schema). */
17
+ interface GitAdapterMetadata extends AdapterMetadata {
18
+ readonly kind: string;
19
+ readonly logo?: string;
20
+ readonly schema: z.ZodType;
21
+ }
22
+ //#endregion
23
+ export { AdapterMetadata, GitAdapterMetadata };
24
+ //# sourceMappingURL=metadata.d.mts.map
@@ -0,0 +1,39 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { hmacSha256 } from "../utils/hash.mjs";
5
+ import { WebhookModel } from "../models/webhook.mjs";
6
+ //#region src/adapters/webhook-events.ts
7
+ async function sendWebhook(url, secret, event) {
8
+ const body = JSON.stringify(event);
9
+ const signature = hmacSha256(secret, body);
10
+ await fetch(url, {
11
+ method: "POST",
12
+ headers: {
13
+ "Content-Type": "application/json",
14
+ "X-StoryShelf-Event": event.event,
15
+ "X-StoryShelf-Signature": signature
16
+ },
17
+ body
18
+ });
19
+ }
20
+ async function emitWebhookEvent(db, projectId, event, data) {
21
+ const webhooks = await new WebhookModel(db).list(projectId);
22
+ const eventPayload = {
23
+ event,
24
+ projectId,
25
+ data,
26
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
27
+ };
28
+ await Promise.allSettled(webhooks.map(async (webhook) => {
29
+ const events = WebhookModel.eventsOf(webhook);
30
+ if (events.length > 0 && !events.includes(event)) return;
31
+ try {
32
+ await sendWebhook(webhook.url, webhook.secret, eventPayload);
33
+ } catch {}
34
+ }));
35
+ }
36
+ //#endregion
37
+ export { emitWebhookEvent };
38
+
39
+ //# sourceMappingURL=webhook-events.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-events.mjs","names":[],"sources":["../../src/adapters/webhook-events.ts"],"sourcesContent":["import type { DatabaseAdapter } from \"./database.ts\";\nimport { WebhookModel } from \"../models/webhook.ts\";\nimport { hmacSha256 } from \"../utils/hash.ts\";\n\nexport interface WebhookEvent {\n event: string;\n projectId: string;\n data: Record<string, unknown>;\n timestamp: string;\n}\n\nasync function sendWebhook(url: string, secret: string, event: WebhookEvent): Promise<void> {\n const body = JSON.stringify(event);\n const signature = hmacSha256(secret, body);\n await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-StoryShelf-Event\": event.event,\n \"X-StoryShelf-Signature\": signature,\n },\n body,\n });\n}\n\nexport async function emitWebhookEvent(\n db: DatabaseAdapter,\n projectId: string,\n event: string,\n data: Record<string, unknown>,\n): Promise<void> {\n const webhookModel = new WebhookModel(db);\n const webhooks = await webhookModel.list(projectId);\n const eventPayload: WebhookEvent = {\n event,\n projectId,\n data,\n timestamp: new Date().toISOString(),\n };\n\n await Promise.allSettled(\n webhooks.map(async (webhook) => {\n const events = WebhookModel.eventsOf(webhook);\n if (events.length > 0 && !events.includes(event)) {\n return;\n }\n try {\n await sendWebhook(webhook.url, webhook.secret, eventPayload);\n } catch {\n // webhook delivery failures are non-fatal\n }\n }),\n );\n}\n"],"mappings":";;;;;;AAWA,eAAe,YAAY,KAAa,QAAgB,OAAoC;CAC1F,MAAM,OAAO,KAAK,UAAU,KAAK;CACjC,MAAM,YAAY,WAAW,QAAQ,IAAI;CACzC,MAAM,MAAM,KAAK;EACf,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,sBAAsB,MAAM;GAC5B,0BAA0B;EAC5B;EACA;CACF,CAAC;AACH;AAEA,eAAsB,iBACpB,IACA,WACA,OACA,MACe;CAEf,MAAM,WAAW,MAAM,IADE,aAAa,EACJ,CAAC,CAAC,KAAK,SAAS;CAClD,MAAM,eAA6B;EACjC;EACA;EACA;EACA,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;CACpC;CAEA,MAAM,QAAQ,WACZ,SAAS,IAAI,OAAO,YAAY;EAC9B,MAAM,SAAS,aAAa,SAAS,OAAO;EAC5C,IAAI,OAAO,SAAS,KAAK,CAAC,OAAO,SAAS,KAAK,GAC7C;EAEF,IAAI;GACF,MAAM,YAAY,QAAQ,KAAK,QAAQ,QAAQ,YAAY;EAC7D,QAAQ,CAER;CACF,CAAC,CACH;AACF"}
@@ -0,0 +1,29 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ //#region src/capture/adapter.d.ts
4
+ /** A single discoverable story or docs entry within a Storybook. */
5
+ interface StoryEntry {
6
+ id: string;
7
+ title: string;
8
+ name: string;
9
+ importPath?: string;
10
+ tags?: string[];
11
+ type: "story" | "docs";
12
+ }
13
+ /** Adapter that discovers and renders stories from a Storybook build. */
14
+ interface StorySourceAdapter {
15
+ name: string;
16
+ discover(source: string): Promise<StoryEntry[]>;
17
+ buildUrl(baseUrl: string, storyId: string): string;
18
+ screenshotSelector?: string;
19
+ }
20
+ /** A viewport size at which stories are captured. */
21
+ interface Viewport {
22
+ name: string;
23
+ width: number;
24
+ height: number;
25
+ }
26
+ declare const DEFAULT_VIEWPORTS: Viewport[];
27
+ //#endregion
28
+ export { DEFAULT_VIEWPORTS, StoryEntry, StorySourceAdapter, Viewport };
29
+ //# sourceMappingURL=adapter.d.mts.map
@@ -0,0 +1,13 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ //#region src/capture/adapter.ts
5
+ const DEFAULT_VIEWPORTS = [{
6
+ name: "desktop",
7
+ width: 1280,
8
+ height: 720
9
+ }];
10
+ //#endregion
11
+ export { DEFAULT_VIEWPORTS };
12
+
13
+ //# sourceMappingURL=adapter.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.mjs","names":[],"sources":["../../src/capture/adapter.ts"],"sourcesContent":["/** A single discoverable story or docs entry within a Storybook. */\nexport interface StoryEntry {\n id: string;\n title: string;\n name: string;\n importPath?: string;\n tags?: string[];\n type: \"story\" | \"docs\";\n}\n\n/** Adapter that discovers and renders stories from a Storybook build. */\nexport interface StorySourceAdapter {\n name: string;\n discover(source: string): Promise<StoryEntry[]>;\n buildUrl(baseUrl: string, storyId: string): string;\n screenshotSelector?: string;\n}\n\n/** A viewport size at which stories are captured. */\nexport interface Viewport {\n name: string;\n width: number;\n height: number;\n}\n\nexport const DEFAULT_VIEWPORTS: Viewport[] = [{ name: \"desktop\", width: 1280, height: 720 }];\n"],"mappings":";;;;AAyBA,MAAa,oBAAgC,CAAC;CAAE,MAAM;CAAW,OAAO;CAAM,QAAQ;AAAI,CAAC"}
@@ -0,0 +1,23 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { Viewport } from "./adapter.mjs";
4
+ import { CaptureRunner } from "../adapter/capture-runner.mjs";
5
+ import { DatabaseAdapter } from "../adapter/database.mjs";
6
+ import { StorageAdapter } from "../adapter/storage.mjs";
7
+ import { Logger } from "pino";
8
+ //#region src/capture/orchestrator.d.ts
9
+ interface CaptureJobOptions {
10
+ db: DatabaseAdapter;
11
+ storage: StorageAdapter;
12
+ runner: CaptureRunner;
13
+ scratchDir: string;
14
+ viewports?: Viewport[];
15
+ logger?: Logger;
16
+ }
17
+ declare function executeCaptureJob(input: {
18
+ buildId: string;
19
+ reqId?: string;
20
+ }, options: CaptureJobOptions): Promise<void>;
21
+ //#endregion
22
+ export { CaptureJobOptions, executeCaptureJob };
23
+ //# sourceMappingURL=orchestrator.d.mts.map