@sixb/sqlite 0.0.1

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 (152) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -0
  3. package/dist/action-run-storage.d.ts +29 -0
  4. package/dist/action-run-storage.d.ts.map +1 -0
  5. package/dist/agents/agent-storage.d.ts +25 -0
  6. package/dist/agents/agent-storage.d.ts.map +1 -0
  7. package/dist/agents/index.d.ts +6 -0
  8. package/dist/agents/index.d.ts.map +1 -0
  9. package/dist/agents/messages.d.ts +14 -0
  10. package/dist/agents/messages.d.ts.map +1 -0
  11. package/dist/agents/rows.d.ts +77 -0
  12. package/dist/agents/rows.d.ts.map +1 -0
  13. package/dist/agents/runs.d.ts +26 -0
  14. package/dist/agents/runs.d.ts.map +1 -0
  15. package/dist/agents/threads.d.ts +14 -0
  16. package/dist/agents/threads.d.ts.map +1 -0
  17. package/dist/auth-storage/access-tokens.d.ts +33 -0
  18. package/dist/auth-storage/access-tokens.d.ts.map +1 -0
  19. package/dist/auth-storage/auth-storage.d.ts +46 -0
  20. package/dist/auth-storage/auth-storage.d.ts.map +1 -0
  21. package/dist/auth-storage/group-memberships.d.ts +21 -0
  22. package/dist/auth-storage/group-memberships.d.ts.map +1 -0
  23. package/dist/auth-storage/identities.d.ts +17 -0
  24. package/dist/auth-storage/identities.d.ts.map +1 -0
  25. package/dist/auth-storage/index.d.ts +3 -0
  26. package/dist/auth-storage/index.d.ts.map +1 -0
  27. package/dist/auth-storage/invitations.d.ts +28 -0
  28. package/dist/auth-storage/invitations.d.ts.map +1 -0
  29. package/dist/auth-storage/magic-links.d.ts +28 -0
  30. package/dist/auth-storage/magic-links.d.ts.map +1 -0
  31. package/dist/auth-storage/oidc-attempts.d.ts +18 -0
  32. package/dist/auth-storage/oidc-attempts.d.ts.map +1 -0
  33. package/dist/auth-storage/rows.d.ts +134 -0
  34. package/dist/auth-storage/rows.d.ts.map +1 -0
  35. package/dist/auth-storage/service-account-group-memberships.d.ts +17 -0
  36. package/dist/auth-storage/service-account-group-memberships.d.ts.map +1 -0
  37. package/dist/auth-storage/service-accounts.d.ts +14 -0
  38. package/dist/auth-storage/service-accounts.d.ts.map +1 -0
  39. package/dist/auth-storage/sessions.d.ts +55 -0
  40. package/dist/auth-storage/sessions.d.ts.map +1 -0
  41. package/dist/auth-storage/shared.d.ts +131 -0
  42. package/dist/auth-storage/shared.d.ts.map +1 -0
  43. package/dist/auth-storage/users.d.ts +19 -0
  44. package/dist/auth-storage/users.d.ts.map +1 -0
  45. package/dist/index.d.ts +71 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +10204 -0
  48. package/dist/index.js.map +54 -0
  49. package/dist/latest-run-query.d.ts +22 -0
  50. package/dist/latest-run-query.d.ts.map +1 -0
  51. package/dist/migrations.d.ts +18 -0
  52. package/dist/migrations.d.ts.map +1 -0
  53. package/dist/object-query-compiler.d.ts +44 -0
  54. package/dist/object-query-compiler.d.ts.map +1 -0
  55. package/dist/object-storage.d.ts +93 -0
  56. package/dist/object-storage.d.ts.map +1 -0
  57. package/dist/ontology-storage/commits.d.ts +14 -0
  58. package/dist/ontology-storage/commits.d.ts.map +1 -0
  59. package/dist/ontology-storage/index.d.ts +22 -0
  60. package/dist/ontology-storage/index.d.ts.map +1 -0
  61. package/dist/ontology-storage/materialization-session.d.ts +49 -0
  62. package/dist/ontology-storage/materialization-session.d.ts.map +1 -0
  63. package/dist/ontology-storage/materialization-state.d.ts +63 -0
  64. package/dist/ontology-storage/materialization-state.d.ts.map +1 -0
  65. package/dist/ontology-storage/materialization-writer.d.ts +15 -0
  66. package/dist/ontology-storage/materialization-writer.d.ts.map +1 -0
  67. package/dist/ontology-storage/materializations.d.ts +32 -0
  68. package/dist/ontology-storage/materializations.d.ts.map +1 -0
  69. package/dist/ontology-storage/outbox.d.ts +14 -0
  70. package/dist/ontology-storage/outbox.d.ts.map +1 -0
  71. package/dist/ontology-storage/shared.d.ts +91 -0
  72. package/dist/ontology-storage/shared.d.ts.map +1 -0
  73. package/dist/ontology-storage/sources.d.ts +26 -0
  74. package/dist/ontology-storage/sources.d.ts.map +1 -0
  75. package/dist/pipeline-run-storage.d.ts +26 -0
  76. package/dist/pipeline-run-storage.d.ts.map +1 -0
  77. package/dist/projection-run-storage.d.ts +32 -0
  78. package/dist/projection-run-storage.d.ts.map +1 -0
  79. package/dist/rules-storage.d.ts +33 -0
  80. package/dist/rules-storage.d.ts.map +1 -0
  81. package/dist/run-list-query.d.ts +27 -0
  82. package/dist/run-list-query.d.ts.map +1 -0
  83. package/dist/storage-errors.d.ts +2 -0
  84. package/dist/storage-errors.d.ts.map +1 -0
  85. package/dist/sync-run-storage.d.ts +23 -0
  86. package/dist/sync-run-storage.d.ts.map +1 -0
  87. package/dist/timeseries-storage.d.ts +41 -0
  88. package/dist/timeseries-storage.d.ts.map +1 -0
  89. package/dist/transactions.d.ts +15 -0
  90. package/dist/transactions.d.ts.map +1 -0
  91. package/dist/tsconfig.json +5 -0
  92. package/dist/validation.d.ts +5 -0
  93. package/dist/validation.d.ts.map +1 -0
  94. package/dist/webhook-delivery-storage.d.ts +27 -0
  95. package/dist/webhook-delivery-storage.d.ts.map +1 -0
  96. package/dist/webhook-run-storage.d.ts +22 -0
  97. package/dist/webhook-run-storage.d.ts.map +1 -0
  98. package/dist/workflow-intervention-storage.d.ts +26 -0
  99. package/dist/workflow-intervention-storage.d.ts.map +1 -0
  100. package/dist/workflow-run-storage.d.ts +63 -0
  101. package/dist/workflow-run-storage.d.ts.map +1 -0
  102. package/package.json +58 -0
  103. package/src/action-run-storage.ts +761 -0
  104. package/src/agents/agent-storage.ts +46 -0
  105. package/src/agents/index.ts +5 -0
  106. package/src/agents/messages.ts +162 -0
  107. package/src/agents/rows.ts +205 -0
  108. package/src/agents/runs.ts +389 -0
  109. package/src/agents/threads.ts +133 -0
  110. package/src/auth-storage/access-tokens.ts +289 -0
  111. package/src/auth-storage/auth-storage.ts +784 -0
  112. package/src/auth-storage/group-memberships.ts +52 -0
  113. package/src/auth-storage/identities.ts +98 -0
  114. package/src/auth-storage/index.ts +2 -0
  115. package/src/auth-storage/invitations.ts +258 -0
  116. package/src/auth-storage/magic-links.ts +149 -0
  117. package/src/auth-storage/oidc-attempts.ts +109 -0
  118. package/src/auth-storage/rows.ts +338 -0
  119. package/src/auth-storage/service-account-group-memberships.ts +161 -0
  120. package/src/auth-storage/service-accounts.ts +168 -0
  121. package/src/auth-storage/sessions.ts +230 -0
  122. package/src/auth-storage/shared.ts +707 -0
  123. package/src/auth-storage/users.ts +226 -0
  124. package/src/index.ts +292 -0
  125. package/src/latest-run-query.ts +49 -0
  126. package/src/migrations/001-initial-schema.sql +1068 -0
  127. package/src/migrations.ts +245 -0
  128. package/src/object-query-compiler.ts +1198 -0
  129. package/src/object-storage.ts +605 -0
  130. package/src/ontology-storage/commits.ts +127 -0
  131. package/src/ontology-storage/index.ts +35 -0
  132. package/src/ontology-storage/materialization-session.ts +393 -0
  133. package/src/ontology-storage/materialization-state.ts +901 -0
  134. package/src/ontology-storage/materialization-writer.ts +394 -0
  135. package/src/ontology-storage/materializations.ts +838 -0
  136. package/src/ontology-storage/outbox.ts +237 -0
  137. package/src/ontology-storage/shared.ts +269 -0
  138. package/src/ontology-storage/sources.ts +653 -0
  139. package/src/pipeline-run-storage.ts +506 -0
  140. package/src/projection-run-storage.ts +592 -0
  141. package/src/rules-storage.ts +375 -0
  142. package/src/run-list-query.ts +98 -0
  143. package/src/sql.d.ts +4 -0
  144. package/src/storage-errors.ts +3 -0
  145. package/src/sync-run-storage.ts +299 -0
  146. package/src/timeseries-storage.ts +212 -0
  147. package/src/transactions.ts +96 -0
  148. package/src/validation.ts +30 -0
  149. package/src/webhook-delivery-storage.ts +272 -0
  150. package/src/webhook-run-storage.ts +240 -0
  151. package/src/workflow-intervention-storage.ts +398 -0
  152. package/src/workflow-run-storage.ts +1148 -0
@@ -0,0 +1,272 @@
1
+ import type { Database } from "bun:sqlite"
2
+ import type {
3
+ WebhookDeliveryClaimRecord,
4
+ WebhookDeliveryClaimResult,
5
+ WebhookDeliveryKey,
6
+ WebhookDeliveryRecord,
7
+ WebhookDeliveryStorage,
8
+ } from "@sixb/core/storage"
9
+ import { installFreshSqliteSchema } from "./migrations"
10
+ import {
11
+ closeSqliteStoreConnection,
12
+ openSqliteStoreConnection,
13
+ type SqliteStoreConnection,
14
+ } from "./transactions"
15
+
16
+ export interface SqliteWebhookDeliveryStorageOptions {
17
+ /** Path to SQLite database file. Defaults to ':memory:' for in-memory database. */
18
+ path?: string
19
+ /** Internal shared connection used by bundled SqliteStorage. */
20
+ connection?: SqliteStoreConnection
21
+ }
22
+
23
+ export class SqliteWebhookDeliveryStorage implements WebhookDeliveryStorage {
24
+ private readonly connection: SqliteStoreConnection
25
+ private readonly db: Database
26
+
27
+ constructor(options: SqliteWebhookDeliveryStorageOptions = {}) {
28
+ this.connection = openSqliteStoreConnection(options)
29
+ this.db = this.connection.db
30
+
31
+ if (this.connection.installFreshSchema) {
32
+ installFreshSqliteSchema(this.db)
33
+ }
34
+ }
35
+
36
+ async claim(
37
+ input: WebhookDeliveryKey & { receivedAt: string }
38
+ ): Promise<WebhookDeliveryClaimRecord> {
39
+ return this.db.transaction(() => {
40
+ // Atomic first claim: only one request can insert this scoped delivery key.
41
+ const inserted = this.db
42
+ .query(
43
+ `
44
+ INSERT OR IGNORE INTO webhook_deliveries (
45
+ project_id,
46
+ connector_id,
47
+ webhook_id,
48
+ idempotency_key,
49
+ status,
50
+ received_at
51
+ ) VALUES (?, ?, ?, ?, 'in_progress', ?)
52
+ `
53
+ )
54
+ .run(
55
+ input.projectId,
56
+ input.connectorId,
57
+ input.webhookId,
58
+ input.idempotencyKey,
59
+ input.receivedAt
60
+ ) as { changes: number }
61
+
62
+ if (inserted.changes > 0) {
63
+ return toWebhookDeliveryClaimRecord(
64
+ {
65
+ projectId: input.projectId,
66
+ connectorId: input.connectorId,
67
+ webhookId: input.webhookId,
68
+ idempotencyKey: input.idempotencyKey,
69
+ status: "in_progress",
70
+ receivedAt: input.receivedAt,
71
+ },
72
+ "claimed"
73
+ )
74
+ }
75
+
76
+ const existing = this.getDeliveryRecord(input)
77
+
78
+ if (existing?.status === "completed") {
79
+ return toWebhookDeliveryClaimRecord(existing, "duplicate")
80
+ }
81
+
82
+ if (existing?.status === "in_progress") {
83
+ return toWebhookDeliveryClaimRecord(existing, "in_progress")
84
+ }
85
+
86
+ if (existing?.status !== "failed") {
87
+ throw new Error("[SixbSqlite] Webhook delivery row disappeared during claim.")
88
+ }
89
+
90
+ // Failed deliveries are intentionally claimable so provider retries can run again.
91
+ const claimed = this.db
92
+ .query(
93
+ `
94
+ UPDATE webhook_deliveries
95
+ SET status = 'in_progress',
96
+ received_at = ?,
97
+ completed_at = NULL,
98
+ failed_at = NULL,
99
+ error = NULL
100
+ WHERE project_id = ?
101
+ AND connector_id = ?
102
+ AND webhook_id = ?
103
+ AND idempotency_key = ?
104
+ AND status = 'failed'
105
+ `
106
+ )
107
+ .run(
108
+ input.receivedAt,
109
+ input.projectId,
110
+ input.connectorId,
111
+ input.webhookId,
112
+ input.idempotencyKey
113
+ ) as { changes: number }
114
+
115
+ if (claimed.changes > 0) {
116
+ return toWebhookDeliveryClaimRecord(this.requireDeliveryRecord(input, "claim"), "claimed")
117
+ }
118
+
119
+ const current = this.requireDeliveryRecord(input, "claim")
120
+ return toWebhookDeliveryClaimRecord(
121
+ current,
122
+ current.status === "completed" ? "duplicate" : "in_progress"
123
+ )
124
+ })()
125
+ }
126
+
127
+ async complete(
128
+ input: WebhookDeliveryKey & { completedAt: string }
129
+ ): Promise<WebhookDeliveryRecord> {
130
+ this.db
131
+ .query(
132
+ `
133
+ UPDATE webhook_deliveries
134
+ SET status = 'completed',
135
+ completed_at = ?,
136
+ failed_at = NULL,
137
+ error = NULL
138
+ WHERE project_id = ?
139
+ AND connector_id = ?
140
+ AND webhook_id = ?
141
+ AND idempotency_key = ?
142
+ `
143
+ )
144
+ .run(
145
+ input.completedAt,
146
+ input.projectId,
147
+ input.connectorId,
148
+ input.webhookId,
149
+ input.idempotencyKey
150
+ )
151
+
152
+ return this.requireDeliveryRecord(input, "complete")
153
+ }
154
+
155
+ async fail(
156
+ input: WebhookDeliveryKey & { failedAt: string; error: string }
157
+ ): Promise<WebhookDeliveryRecord> {
158
+ this.db
159
+ .query(
160
+ `
161
+ UPDATE webhook_deliveries
162
+ SET status = 'failed',
163
+ failed_at = ?,
164
+ error = ?
165
+ WHERE project_id = ?
166
+ AND connector_id = ?
167
+ AND webhook_id = ?
168
+ AND idempotency_key = ?
169
+ `
170
+ )
171
+ .run(
172
+ input.failedAt,
173
+ input.error,
174
+ input.projectId,
175
+ input.connectorId,
176
+ input.webhookId,
177
+ input.idempotencyKey
178
+ )
179
+
180
+ return this.requireDeliveryRecord(input, "fail")
181
+ }
182
+
183
+ close(): void {
184
+ closeSqliteStoreConnection(this.connection)
185
+ }
186
+
187
+ private getDeliveryRecord(key: WebhookDeliveryKey): WebhookDeliveryRecord | null {
188
+ const row = this.db
189
+ .query(
190
+ `
191
+ SELECT
192
+ project_id,
193
+ connector_id,
194
+ webhook_id,
195
+ idempotency_key,
196
+ status,
197
+ received_at,
198
+ completed_at,
199
+ failed_at,
200
+ error
201
+ FROM webhook_deliveries
202
+ WHERE project_id = ?
203
+ AND connector_id = ?
204
+ AND webhook_id = ?
205
+ AND idempotency_key = ?
206
+ `
207
+ )
208
+ .get(
209
+ key.projectId,
210
+ key.connectorId,
211
+ key.webhookId,
212
+ key.idempotencyKey
213
+ ) as SqliteWebhookDeliveryRow | null
214
+
215
+ return row ? toWebhookDeliveryRecord(row) : null
216
+ }
217
+
218
+ private requireDeliveryRecord(
219
+ key: WebhookDeliveryKey,
220
+ action: "claim" | "complete" | "fail"
221
+ ): WebhookDeliveryRecord {
222
+ const record = this.getDeliveryRecord(key)
223
+
224
+ if (!record) {
225
+ throw new Error(
226
+ `[SixbSqlite] Missing webhook delivery row after ${action} for ${serializeKey(key)}.`
227
+ )
228
+ }
229
+
230
+ return record
231
+ }
232
+ }
233
+
234
+ interface SqliteWebhookDeliveryRow {
235
+ readonly project_id: string
236
+ readonly connector_id: string
237
+ readonly webhook_id: string
238
+ readonly idempotency_key: string
239
+ readonly status: WebhookDeliveryRecord["status"]
240
+ readonly received_at: string
241
+ readonly completed_at: string | null
242
+ readonly failed_at: string | null
243
+ readonly error: string | null
244
+ }
245
+
246
+ function toWebhookDeliveryRecord(row: SqliteWebhookDeliveryRow): WebhookDeliveryRecord {
247
+ return {
248
+ projectId: row.project_id,
249
+ connectorId: row.connector_id,
250
+ webhookId: row.webhook_id,
251
+ idempotencyKey: row.idempotency_key,
252
+ status: row.status,
253
+ receivedAt: row.received_at,
254
+ completedAt: row.completed_at ?? undefined,
255
+ failedAt: row.failed_at ?? undefined,
256
+ error: row.error ?? undefined,
257
+ }
258
+ }
259
+
260
+ function toWebhookDeliveryClaimRecord(
261
+ record: WebhookDeliveryRecord,
262
+ claimResult: WebhookDeliveryClaimResult
263
+ ): WebhookDeliveryClaimRecord {
264
+ return {
265
+ ...record,
266
+ claimResult,
267
+ }
268
+ }
269
+
270
+ function serializeKey(key: WebhookDeliveryKey): string {
271
+ return JSON.stringify([key.projectId, key.connectorId, key.webhookId, key.idempotencyKey])
272
+ }
@@ -0,0 +1,240 @@
1
+ import type { Database } from "bun:sqlite"
2
+ import type {
3
+ FinishWebhookRunInput,
4
+ ListWebhookRunsInput,
5
+ ListWebhookRunsResult,
6
+ StartWebhookRunInput,
7
+ WebhookRunRecord,
8
+ WebhookRunStorage,
9
+ } from "@sixb/core/storage"
10
+ import { WebhookRunError } from "@sixb/core/storage"
11
+ import { installFreshSqliteSchema } from "./migrations"
12
+ import {
13
+ appendRunListFilters,
14
+ hasEmptyStatuses,
15
+ queryRunList,
16
+ type SqliteValue,
17
+ } from "./run-list-query"
18
+ import { isUniqueConstraintError } from "./storage-errors"
19
+ import {
20
+ closeSqliteStoreConnection,
21
+ openSqliteStoreConnection,
22
+ type SqliteStoreConnection,
23
+ } from "./transactions"
24
+
25
+ export interface SqliteWebhookRunStorageOptions {
26
+ /** Path to SQLite database file. Defaults to ':memory:' for in-memory database. */
27
+ path?: string
28
+ /** Internal shared connection used by bundled SqliteStorage. */
29
+ connection?: SqliteStoreConnection
30
+ }
31
+
32
+ export class SqliteWebhookRunStorage implements WebhookRunStorage {
33
+ private readonly connection: SqliteStoreConnection
34
+ private readonly db: Database
35
+
36
+ constructor(options: SqliteWebhookRunStorageOptions = {}) {
37
+ this.connection = openSqliteStoreConnection(options)
38
+ this.db = this.connection.db
39
+
40
+ if (this.connection.installFreshSchema) {
41
+ installFreshSqliteSchema(this.db)
42
+ }
43
+ }
44
+
45
+ async start(input: StartWebhookRunInput): Promise<WebhookRunRecord> {
46
+ const startedAt = input.startedAt ?? new Date()
47
+
48
+ try {
49
+ this.db
50
+ .query(
51
+ `
52
+ INSERT INTO webhook_runs (
53
+ project_id,
54
+ id,
55
+ connector_id,
56
+ webhook_id,
57
+ status,
58
+ method,
59
+ route,
60
+ started_at
61
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
62
+ `
63
+ )
64
+ .run(
65
+ input.projectId,
66
+ input.id,
67
+ input.connectorId,
68
+ input.webhookId,
69
+ "running",
70
+ input.method,
71
+ input.route,
72
+ startedAt.toISOString()
73
+ )
74
+ } catch (error) {
75
+ if (isUniqueConstraintError(error)) {
76
+ throw new WebhookRunError(
77
+ `[SixbSqlite] Webhook run '${input.id}' already exists for project '${input.projectId}'.`
78
+ )
79
+ }
80
+
81
+ throw error
82
+ }
83
+
84
+ const record = await this.getById({ projectId: input.projectId, id: input.id })
85
+ if (!record) {
86
+ throw new WebhookRunError(
87
+ `[SixbSqlite] Failed to load webhook run '${input.id}' for project '${input.projectId}'.`
88
+ )
89
+ }
90
+
91
+ return record
92
+ }
93
+
94
+ async finish(input: FinishWebhookRunInput): Promise<WebhookRunRecord> {
95
+ return this.db.transaction(() => {
96
+ const existing = this.db
97
+ .query("SELECT * FROM webhook_runs WHERE project_id = ? AND id = ?")
98
+ .get(input.projectId, input.id) as WebhookRunDatabaseRow | null
99
+
100
+ if (!existing) {
101
+ throw new WebhookRunError(
102
+ `[SixbSqlite] Webhook run '${input.id}' not found for project '${input.projectId}'.`
103
+ )
104
+ }
105
+
106
+ if (existing.status !== "running") {
107
+ throw new WebhookRunError(
108
+ `[SixbSqlite] Webhook run '${input.id}' for project '${input.projectId}' is already terminal.`
109
+ )
110
+ }
111
+
112
+ this.db
113
+ .query(
114
+ `
115
+ UPDATE webhook_runs
116
+ SET
117
+ status = ?,
118
+ finished_at = ?,
119
+ request_body_bytes = ?,
120
+ response_status = ?,
121
+ idempotency_key = ?,
122
+ delivery_claim_result = ?,
123
+ error = ?
124
+ WHERE project_id = ? AND id = ?
125
+ `
126
+ )
127
+ .run(
128
+ input.status,
129
+ (input.finishedAt ?? new Date()).toISOString(),
130
+ input.requestBodyBytes ?? null,
131
+ input.responseStatus ?? null,
132
+ input.idempotencyKey ?? null,
133
+ input.deliveryClaimResult ?? null,
134
+ input.status === "succeeded" ? null : (input.error ?? null),
135
+ input.projectId,
136
+ input.id
137
+ )
138
+
139
+ const updated = this.db
140
+ .query("SELECT * FROM webhook_runs WHERE project_id = ? AND id = ?")
141
+ .get(input.projectId, input.id) as WebhookRunDatabaseRow
142
+
143
+ return rowToWebhookRunRecord(updated)
144
+ })()
145
+ }
146
+
147
+ async getById(params: { projectId: string; id: string }): Promise<WebhookRunRecord | null> {
148
+ const row = this.db
149
+ .query("SELECT * FROM webhook_runs WHERE project_id = ? AND id = ?")
150
+ .get(params.projectId, params.id) as WebhookRunDatabaseRow | null
151
+
152
+ return row ? rowToWebhookRunRecord(row) : null
153
+ }
154
+
155
+ async list(input: ListWebhookRunsInput): Promise<ListWebhookRunsResult> {
156
+ if (hasEmptyStatuses(input)) {
157
+ return {
158
+ runs: [],
159
+ hasMore: false,
160
+ total: 0,
161
+ }
162
+ }
163
+
164
+ const whereClauses = ["project_id = ?"]
165
+ const args: SqliteValue[] = [input.projectId]
166
+
167
+ if (input.connectorId) {
168
+ whereClauses.push("connector_id = ?")
169
+ args.push(input.connectorId)
170
+ }
171
+
172
+ if (input.webhookId) {
173
+ whereClauses.push("webhook_id = ?")
174
+ args.push(input.webhookId)
175
+ }
176
+
177
+ if (input.idempotencyKey) {
178
+ whereClauses.push("idempotency_key = ?")
179
+ args.push(input.idempotencyKey)
180
+ }
181
+
182
+ appendRunListFilters(whereClauses, args, input)
183
+
184
+ const { rows, total, hasMore } = queryRunList<WebhookRunDatabaseRow>({
185
+ db: this.db,
186
+ tableName: "webhook_runs",
187
+ whereClauses,
188
+ args,
189
+ order: input.order,
190
+ limit: input.limit,
191
+ offset: input.offset,
192
+ })
193
+
194
+ return {
195
+ runs: rows.map(rowToWebhookRunRecord),
196
+ hasMore,
197
+ total,
198
+ }
199
+ }
200
+
201
+ close(): void {
202
+ closeSqliteStoreConnection(this.connection)
203
+ }
204
+ }
205
+
206
+ function rowToWebhookRunRecord(row: WebhookRunDatabaseRow): WebhookRunRecord {
207
+ return {
208
+ id: row.id,
209
+ projectId: row.project_id,
210
+ connectorId: row.connector_id,
211
+ webhookId: row.webhook_id,
212
+ status: row.status,
213
+ method: row.method,
214
+ route: row.route,
215
+ startedAt: new Date(row.started_at),
216
+ finishedAt: row.finished_at ? new Date(row.finished_at) : undefined,
217
+ requestBodyBytes: row.request_body_bytes ?? undefined,
218
+ responseStatus: row.response_status ?? undefined,
219
+ idempotencyKey: row.idempotency_key ?? undefined,
220
+ deliveryClaimResult: row.delivery_claim_result ?? undefined,
221
+ error: row.error ?? undefined,
222
+ }
223
+ }
224
+
225
+ interface WebhookRunDatabaseRow {
226
+ readonly project_id: string
227
+ readonly id: string
228
+ readonly connector_id: string
229
+ readonly webhook_id: string
230
+ readonly status: WebhookRunRecord["status"]
231
+ readonly method: string
232
+ readonly route: string
233
+ readonly started_at: string
234
+ readonly finished_at: string | null
235
+ readonly request_body_bytes: number | null
236
+ readonly response_status: number | null
237
+ readonly idempotency_key: string | null
238
+ readonly delivery_claim_result: WebhookRunRecord["deliveryClaimResult"] | null
239
+ readonly error: string | null
240
+ }