@sixb/sqlite 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +18 -13
  2. package/dist/action-run-storage.d.ts +5 -2
  3. package/dist/action-run-storage.d.ts.map +1 -1
  4. package/dist/agents/agent-storage.d.ts +9 -5
  5. package/dist/agents/agent-storage.d.ts.map +1 -1
  6. package/dist/agents/checkpoints.d.ts +14 -0
  7. package/dist/agents/checkpoints.d.ts.map +1 -0
  8. package/dist/agents/index.d.ts +1 -0
  9. package/dist/agents/index.d.ts.map +1 -1
  10. package/dist/agents/messages.d.ts +2 -1
  11. package/dist/agents/messages.d.ts.map +1 -1
  12. package/dist/agents/rows.d.ts +21 -11
  13. package/dist/agents/rows.d.ts.map +1 -1
  14. package/dist/agents/runs.d.ts +3 -2
  15. package/dist/agents/runs.d.ts.map +1 -1
  16. package/dist/ai-cost-storage.d.ts +15 -0
  17. package/dist/ai-cost-storage.d.ts.map +1 -0
  18. package/dist/ai-usage-storage.d.ts +22 -0
  19. package/dist/ai-usage-storage.d.ts.map +1 -0
  20. package/dist/auth-storage/service-accounts.d.ts.map +1 -1
  21. package/dist/auth-storage/shared.d.ts +1 -10
  22. package/dist/auth-storage/shared.d.ts.map +1 -1
  23. package/dist/connector-connection-storage.d.ts +9 -0
  24. package/dist/connector-connection-storage.d.ts.map +1 -0
  25. package/dist/execution-storage.d.ts +14 -0
  26. package/dist/execution-storage.d.ts.map +1 -0
  27. package/dist/index.d.ts +14 -9
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +4633 -1066
  30. package/dist/index.js.map +33 -28
  31. package/dist/latest-run-query.d.ts.map +1 -1
  32. package/dist/migrations.d.ts +0 -1
  33. package/dist/migrations.d.ts.map +1 -1
  34. package/dist/ontology-storage/materialization-session.d.ts +50 -8
  35. package/dist/ontology-storage/materialization-session.d.ts.map +1 -1
  36. package/dist/ontology-storage/materialization-state.d.ts +4 -5
  37. package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
  38. package/dist/ontology-storage/materialization-writer.d.ts.map +1 -1
  39. package/dist/ontology-storage/materializations.d.ts +0 -2
  40. package/dist/ontology-storage/materializations.d.ts.map +1 -1
  41. package/dist/ontology-storage/outbox.d.ts.map +1 -1
  42. package/dist/ontology-storage/shared.d.ts +3 -3
  43. package/dist/ontology-storage/shared.d.ts.map +1 -1
  44. package/dist/ontology-storage/sources.d.ts.map +1 -1
  45. package/dist/pipeline-run-storage.d.ts +7 -2
  46. package/dist/pipeline-run-storage.d.ts.map +1 -1
  47. package/dist/projection-run-storage.d.ts +9 -2
  48. package/dist/projection-run-storage.d.ts.map +1 -1
  49. package/dist/run-list-query.d.ts +1 -1
  50. package/dist/run-list-query.d.ts.map +1 -1
  51. package/dist/sync-run-storage.d.ts +7 -2
  52. package/dist/sync-run-storage.d.ts.map +1 -1
  53. package/dist/testing.d.ts +6 -0
  54. package/dist/testing.d.ts.map +1 -0
  55. package/dist/transactions.d.ts +3 -0
  56. package/dist/transactions.d.ts.map +1 -1
  57. package/dist/webhook-run-storage.d.ts +9 -2
  58. package/dist/webhook-run-storage.d.ts.map +1 -1
  59. package/dist/workflow-run-storage.d.ts +7 -3
  60. package/dist/workflow-run-storage.d.ts.map +1 -1
  61. package/package.json +3 -3
  62. package/src/action-run-storage.ts +51 -74
  63. package/src/agents/agent-storage.ts +11 -6
  64. package/src/agents/checkpoints.ts +175 -0
  65. package/src/agents/index.ts +1 -0
  66. package/src/agents/messages.ts +59 -0
  67. package/src/agents/rows.ts +52 -40
  68. package/src/agents/runs.ts +27 -21
  69. package/src/ai-cost-storage.ts +744 -0
  70. package/src/ai-usage-storage.ts +324 -0
  71. package/src/auth-storage/service-accounts.ts +14 -21
  72. package/src/auth-storage/shared.ts +0 -22
  73. package/src/connector-connection-storage.ts +784 -0
  74. package/src/execution-storage.ts +158 -0
  75. package/src/index.ts +69 -22
  76. package/src/latest-run-query.ts +7 -1
  77. package/src/migrations/004-executions.sql +142 -0
  78. package/src/migrations/005-workflow-executions.sql +7 -0
  79. package/src/migrations/006-narrow-ontology-source-root-index.sql +4 -0
  80. package/src/migrations/007-split-overrides.sql +154 -0
  81. package/src/migrations/008-action-executions.sql +4 -0
  82. package/src/migrations/009-agent-executions.sql +115 -0
  83. package/src/migrations/010-ai-usage-accounting-foundation.sql +74 -0
  84. package/src/migrations/011-sync-failure-record.sql +22 -0
  85. package/src/migrations/012-pipeline-failure-record.sql +45 -0
  86. package/src/migrations/013-workflow-failure-record.sql +45 -0
  87. package/src/migrations/014-agent-failure-record.sql +59 -0
  88. package/src/migrations/015-projection-failure-record.sql +20 -0
  89. package/src/migrations/016-webhook-run-failure-record.sql +19 -0
  90. package/src/migrations/017-action-failure-record.sql +65 -0
  91. package/src/migrations/018-ontology-outbox-failure-record.sql +80 -0
  92. package/src/migrations/019-webhook-delivery-failure-record.sql +62 -0
  93. package/src/migrations/020-drop-run-usage-projections.sql +7 -0
  94. package/src/migrations/021-sync-pipeline-executions.sql +101 -0
  95. package/src/migrations/022-projection-executions.sql +244 -0
  96. package/src/migrations/023-webhook-executions.sql +51 -0
  97. package/src/migrations/024-ontology-commit-executions.sql +58 -0
  98. package/src/migrations/025-connector-connections.sql +257 -0
  99. package/src/migrations/026-ai-cost-accounting.sql +57 -0
  100. package/src/migrations/027-agent-context-checkpoints.sql +28 -0
  101. package/src/migrations/028-object-override-edit-times.sql +3 -0
  102. package/src/migrations.ts +129 -4
  103. package/src/ontology-storage/materialization-session.ts +317 -143
  104. package/src/ontology-storage/materialization-state.ts +323 -112
  105. package/src/ontology-storage/materialization-writer.ts +145 -67
  106. package/src/ontology-storage/materializations.ts +67 -141
  107. package/src/ontology-storage/outbox.ts +10 -3
  108. package/src/ontology-storage/shared.ts +10 -4
  109. package/src/ontology-storage/sources.ts +4 -1
  110. package/src/pipeline-run-storage.ts +128 -43
  111. package/src/projection-run-storage.ts +209 -97
  112. package/src/run-list-query.ts +9 -4
  113. package/src/sync-run-storage.ts +118 -32
  114. package/src/testing.ts +20 -0
  115. package/src/transactions.ts +10 -3
  116. package/src/webhook-run-storage.ts +118 -74
  117. package/src/workflow-run-storage.ts +117 -131
  118. package/dist/validation.d.ts +0 -5
  119. package/dist/validation.d.ts.map +0 -1
  120. package/dist/webhook-delivery-storage.d.ts +0 -27
  121. package/dist/webhook-delivery-storage.d.ts.map +0 -1
  122. package/src/validation.ts +0 -30
  123. package/src/webhook-delivery-storage.ts +0 -272
@@ -0,0 +1,158 @@
1
+ import type { Database } from "bun:sqlite"
2
+ import {
3
+ type ExecutionStorageRow,
4
+ executionRecordFromStorageRow,
5
+ executionRecordToStorageRow,
6
+ normalizeExecutionRecord,
7
+ validateExecutionRecordReferences,
8
+ } from "@sixb/core/internal/execution-storage"
9
+ import type { CreateExecutionInput, ExecutionRecord, ExecutionStorage } from "@sixb/core/storage"
10
+ import { ExecutionStorageError } from "@sixb/core/storage"
11
+ import type { SqliteAuthStorage } from "./auth-storage"
12
+
13
+ export class SqliteExecutionStorage implements ExecutionStorage {
14
+ constructor(
15
+ private readonly db: Database,
16
+ private readonly auth: SqliteAuthStorage
17
+ ) {}
18
+
19
+ async create(input: CreateExecutionInput): Promise<ExecutionRecord> {
20
+ const record = normalizeExecutionRecord(input)
21
+ await validateExecutionRecordReferences(record, {
22
+ auth: this.auth,
23
+ getExecution: (params) => this.getById(params),
24
+ })
25
+ const row = executionRecordToStorageRow(record)
26
+
27
+ try {
28
+ this.db
29
+ .query(
30
+ `
31
+ INSERT INTO executions (
32
+ project_id,
33
+ id,
34
+ executor_kind,
35
+ executor_id,
36
+ source_kind,
37
+ source_id,
38
+ requested_by_user_id,
39
+ requested_by_service_account_id,
40
+ correlation_id,
41
+ parent_execution_id,
42
+ authority_kind,
43
+ authority_user_id,
44
+ authority_service_account_id,
45
+ authority_session_id,
46
+ authority_access_token_id,
47
+ authority_primitive_kind,
48
+ authority_primitive_id,
49
+ authority_kernel_operation,
50
+ created_at
51
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
52
+ `
53
+ )
54
+ .run(
55
+ row.projectId,
56
+ row.id,
57
+ row.executorKind,
58
+ row.executorId,
59
+ row.sourceKind,
60
+ row.sourceId,
61
+ row.requestedByUserId,
62
+ row.requestedByServiceAccountId,
63
+ row.correlationId,
64
+ row.parentExecutionId,
65
+ row.authorityKind,
66
+ row.authorityUserId,
67
+ row.authorityServiceAccountId,
68
+ row.authoritySessionId,
69
+ row.authorityAccessTokenId,
70
+ row.authorityPrimitiveKind,
71
+ row.authorityPrimitiveId,
72
+ row.authorityKernelOperation,
73
+ row.createdAt.toISOString()
74
+ )
75
+ } catch (error) {
76
+ if (isDuplicateExecutionError(error)) {
77
+ throw new ExecutionStorageError(
78
+ "duplicate_execution",
79
+ `[SixbSqlite] Execution '${record.id}' already exists in project '${record.projectId}'.`,
80
+ { cause: error }
81
+ )
82
+ }
83
+ throw error
84
+ }
85
+
86
+ return executionRecordFromStorageRow(row)
87
+ }
88
+
89
+ async getById(params: {
90
+ readonly projectId: string
91
+ readonly id: string
92
+ }): Promise<ExecutionRecord | null> {
93
+ const row = this.db
94
+ .query(
95
+ `
96
+ SELECT *
97
+ FROM executions
98
+ WHERE project_id = ? AND id = ?
99
+ `
100
+ )
101
+ .get(params.projectId, params.id) as SqliteExecutionRow | null
102
+
103
+ return row ? executionRecordFromStorageRow(toStorageRow(row)) : null
104
+ }
105
+ }
106
+
107
+ function toStorageRow(row: SqliteExecutionRow): ExecutionStorageRow {
108
+ return {
109
+ projectId: row.project_id,
110
+ id: row.id,
111
+ executorKind: row.executor_kind,
112
+ executorId: row.executor_id,
113
+ sourceKind: row.source_kind,
114
+ sourceId: row.source_id,
115
+ requestedByUserId: row.requested_by_user_id,
116
+ requestedByServiceAccountId: row.requested_by_service_account_id,
117
+ correlationId: row.correlation_id,
118
+ parentExecutionId: row.parent_execution_id,
119
+ authorityKind: row.authority_kind,
120
+ authorityUserId: row.authority_user_id,
121
+ authorityServiceAccountId: row.authority_service_account_id,
122
+ authoritySessionId: row.authority_session_id,
123
+ authorityAccessTokenId: row.authority_access_token_id,
124
+ authorityPrimitiveKind: row.authority_primitive_kind,
125
+ authorityPrimitiveId: row.authority_primitive_id,
126
+ authorityKernelOperation: row.authority_kernel_operation,
127
+ createdAt: new Date(row.created_at),
128
+ }
129
+ }
130
+
131
+ function isDuplicateExecutionError(error: unknown): boolean {
132
+ return (
133
+ error instanceof Error &&
134
+ error.message.includes("UNIQUE constraint failed: executions.project_id, executions.id")
135
+ )
136
+ }
137
+
138
+ interface SqliteExecutionRow {
139
+ readonly project_id: string
140
+ readonly id: string
141
+ readonly executor_kind: ExecutionStorageRow["executorKind"]
142
+ readonly executor_id: string
143
+ readonly source_kind: ExecutionStorageRow["sourceKind"]
144
+ readonly source_id: string
145
+ readonly requested_by_user_id: string | null
146
+ readonly requested_by_service_account_id: string | null
147
+ readonly correlation_id: string
148
+ readonly parent_execution_id: string | null
149
+ readonly authority_kind: ExecutionStorageRow["authorityKind"]
150
+ readonly authority_user_id: string | null
151
+ readonly authority_service_account_id: string | null
152
+ readonly authority_session_id: string | null
153
+ readonly authority_access_token_id: string | null
154
+ readonly authority_primitive_kind: ExecutionStorageRow["authorityPrimitiveKind"]
155
+ readonly authority_primitive_id: string | null
156
+ readonly authority_kernel_operation: ExecutionStorageRow["authorityKernelOperation"]
157
+ readonly created_at: string
158
+ }
package/src/index.ts CHANGED
@@ -19,13 +19,19 @@ import {
19
19
  createWorkflowRunOperationScope,
20
20
  } from "@sixb/core/internal/storage-operation-scope"
21
21
  import {
22
+ type AiCostStorage,
23
+ type AiUsageStorage,
22
24
  createTransactionStorageProxy,
23
25
  StorageTransactionError,
24
26
  throwNestedStorageTransaction,
25
27
  } from "@sixb/core/storage"
26
28
  import { SqliteActionRunStorage } from "./action-run-storage"
27
29
  import { SqliteAgentStorage } from "./agents"
30
+ import { SqliteAiCostStorage } from "./ai-cost-storage"
31
+ import { SqliteAiUsageStorage } from "./ai-usage-storage"
28
32
  import { SqliteAuthStorage } from "./auth-storage"
33
+ import { SqliteConnectorConnectionStorage } from "./connector-connection-storage"
34
+ import { SqliteExecutionStorage } from "./execution-storage"
29
35
  import {
30
36
  createSqliteStorageMigrators,
31
37
  installFreshSqliteSchema,
@@ -37,6 +43,7 @@ import { SqlitePipelineRunStorage } from "./pipeline-run-storage"
37
43
  import { SqliteProjectionRunStorage } from "./projection-run-storage"
38
44
  import { SqliteRulesStorage } from "./rules-storage"
39
45
  import { SqliteSyncRunStorage } from "./sync-run-storage"
46
+ import { registerSqliteStorageTestingAdapter } from "./testing"
40
47
  import { SqliteTimeseriesStorage } from "./timeseries-storage"
41
48
  import {
42
49
  closeSqliteStoreConnection,
@@ -44,7 +51,6 @@ import {
44
51
  runImmediateTransactionAsync,
45
52
  type SqliteStoreConnection,
46
53
  } from "./transactions"
47
- import { SqliteWebhookDeliveryStorage } from "./webhook-delivery-storage"
48
54
  import { SqliteWebhookRunStorage } from "./webhook-run-storage"
49
55
  import { SqliteWorkflowInterventionStorage } from "./workflow-intervention-storage"
50
56
  import { SqliteWorkflowRunStorage } from "./workflow-run-storage"
@@ -57,8 +63,8 @@ export interface SqliteStorageOptions {
57
63
  /**
58
64
  * SQLite storage provider for Sixb.
59
65
  *
60
- * Bundles object, timeseries, auth, sync run, pipeline run, projection run, workflow run, webhook
61
- * run, and webhook delivery storage backed by SQLite.
66
+ * Bundles object, timeseries, auth, execution, AI accounting, sync run, pipeline run, projection
67
+ * run, workflow run, webhook run, and connector connection storage backed by SQLite.
62
68
  *
63
69
  * Usage:
64
70
  * ```ts
@@ -74,7 +80,10 @@ export class SqliteStorage implements MigrationCapableStorage {
74
80
  readonly objects: Storage["objects"]
75
81
  readonly ontology: SqliteOntologyStorage
76
82
  readonly auth: SqliteAuthStorage
83
+ readonly executions: SqliteExecutionStorage
77
84
  readonly agents: SqliteAgentStorage
85
+ readonly aiUsage: AiUsageStorage
86
+ readonly aiCosts: AiCostStorage
78
87
  readonly actionRuns: SqliteActionRunStorage
79
88
  readonly pipelineRuns: SqlitePipelineRunStorage
80
89
  readonly syncRuns: SqliteSyncRunStorage
@@ -82,18 +91,25 @@ export class SqliteStorage implements MigrationCapableStorage {
82
91
  readonly workflowRuns: SqliteWorkflowRunStorage
83
92
  readonly workflowInterventions: SqliteWorkflowInterventionStorage
84
93
  readonly timeseries: Storage["timeseries"]
85
- readonly webhookDeliveries: SqliteWebhookDeliveryStorage
86
94
  readonly webhookRuns: SqliteWebhookRunStorage
87
95
  readonly rules: SqliteRulesStorage
96
+ readonly connectorConnections: SqliteConnectorConnectionStorage
88
97
  readonly migrators: readonly StorageMigrator[]
89
98
 
90
99
  private readonly connection: SqliteStoreConnection
100
+ private readonly readConnection: SqliteStoreConnection
91
101
  private readonly transactionScope = new AsyncLocalStorage<{ active: boolean }>()
92
102
  private transactionTail: Promise<void> = Promise.resolve()
93
103
 
94
104
  constructor(options: SqliteStorageOptions = {}) {
95
105
  const path = options.path ? sqliteStoragePath(options.path) : undefined
96
106
  this.connection = openSqliteStoreConnection({ path })
107
+ if (path) {
108
+ this.connection.db.run("PRAGMA journal_mode = WAL")
109
+ this.readConnection = openSqliteStoreConnection({ path, readonly: true })
110
+ } else {
111
+ this.readConnection = this.connection
112
+ }
97
113
 
98
114
  if (this.connection.installFreshSchema) {
99
115
  installFreshSqliteSchema(this.connection.db)
@@ -112,35 +128,57 @@ export class SqliteStorage implements MigrationCapableStorage {
112
128
  (run) => this.runRootOntologyOperation(run),
113
129
  assertRootOperationAvailable
114
130
  )
115
- this.objects = createOperationScopedFacade(stores.objects, scope)
131
+ const readScope = path
132
+ ? createStorageOperationScope(async (run) => {
133
+ this.assertRootOperationAvailable()
134
+ return run()
135
+ }, assertRootOperationAvailable)
136
+ : scope
137
+ const readObjects = path
138
+ ? new SqliteObjectStorage({ connection: this.readConnection })
139
+ : stores.objects
140
+ const readTimeseries = path
141
+ ? new SqliteTimeseriesStorage({ connection: this.readConnection })
142
+ : stores.timeseries
143
+ this.objects = createOperationScopedFacade(readObjects, readScope)
116
144
  this.ontology = createOntologyOperationScope(stores.ontology, ontologyScope)
117
145
  this.auth = createAuthOperationScope(stores.auth, scope)
146
+ this.executions = createOperationScopedFacade(stores.executions, scope)
118
147
  this.agents = createAgentOperationScope(stores.agents, scope)
148
+ this.aiUsage = createOperationScopedFacade(stores.aiUsage, scope)
149
+ this.aiCosts = createOperationScopedFacade(stores.aiCosts, scope)
119
150
  this.actionRuns = createOperationScopedFacade(stores.actionRuns, scope)
120
151
  this.pipelineRuns = createOperationScopedFacade(stores.pipelineRuns, scope)
121
- this.timeseries = createOperationScopedFacade(stores.timeseries, scope)
152
+ this.timeseries = createOperationScopedFacade(readTimeseries, readScope)
122
153
  this.syncRuns = createOperationScopedFacade(stores.syncRuns, scope)
123
154
  this.projectionRuns = createOperationScopedFacade(stores.projectionRuns, scope)
124
155
  this.workflowRuns = createWorkflowRunOperationScope(stores.workflowRuns, scope)
125
156
  this.workflowInterventions = createOperationScopedFacade(stores.workflowInterventions, scope)
126
- this.webhookDeliveries = createOperationScopedFacade(stores.webhookDeliveries, scope)
127
157
  this.webhookRuns = createOperationScopedFacade(stores.webhookRuns, scope)
128
158
  this.rules = createOperationScopedFacade(stores.rules, scope)
159
+ this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope)
129
160
  this.migrators = options.path ? createSqliteStorageMigrators(options.path) : []
161
+ registerSqliteStorageTestingAdapter(this, (durationMs) =>
162
+ stores.connectorConnections.advanceTimeForTesting(durationMs)
163
+ )
130
164
  }
131
165
 
132
166
  async ping(): Promise<void> {
167
+ this.assertRootOperationAvailable()
168
+ if (this.readConnection !== this.connection) {
169
+ this.readConnection.db.query("SELECT 1").get()
170
+ return
171
+ }
133
172
  await this.runRootStorageOperation(() => {
134
173
  this.connection.db.query("SELECT 1").get()
135
174
  })
136
175
  }
137
176
 
138
177
  /**
139
- * The `isolation` option is intentionally ignored. SQLite runs every transaction through one
140
- * shared connection serialized by {@link withTransactionLock} and a `BEGIN IMMEDIATE`, so there is
141
- * no concurrent transaction to isolate against — the lock already provides serializable semantics
142
- * for transaction-vs-transaction races. Postgres, which has true concurrent connections, is where
143
- * `isolation: "serializable"` translates to a real isolation level.
178
+ * The `isolation` option is intentionally ignored. SQLite runs every write transaction through
179
+ * one connection serialized by {@link withTransactionLock} and a `BEGIN IMMEDIATE`, so there is no
180
+ * concurrent writer to isolate against. File-backed object and timeseries reads use a separate WAL
181
+ * snapshot connection; Postgres is where `isolation: "serializable"` maps to a real isolation level.
144
182
  */
145
183
  async transaction<T>(
146
184
  run: (tx: Storage) => Promise<T> | T,
@@ -183,6 +221,7 @@ export class SqliteStorage implements MigrationCapableStorage {
183
221
  }
184
222
 
185
223
  close(): void {
224
+ if (this.readConnection !== this.connection) closeSqliteStoreConnection(this.readConnection)
186
225
  closeSqliteStoreConnection(this.connection)
187
226
  }
188
227
 
@@ -250,6 +289,8 @@ function createSqliteStores(
250
289
  readonly transactionContext: SqliteOntologyTransactionContext | null
251
290
  }
252
291
  ): SqliteStoreSet {
292
+ const auth = new SqliteAuthStorage({ connection })
293
+ const executions = new SqliteExecutionStorage(connection.db, auth)
253
294
  return {
254
295
  objects: new SqliteObjectStorage({ connection }),
255
296
  ontology: new SqliteOntologyStorage({
@@ -257,18 +298,21 @@ function createSqliteStores(
257
298
  runRootOperation: options.runOntologyOperation,
258
299
  transactionContext: options.transactionContext,
259
300
  }),
260
- auth: new SqliteAuthStorage({ connection }),
261
- agents: new SqliteAgentStorage({ connection }),
262
- actionRuns: new SqliteActionRunStorage({ connection }),
263
- pipelineRuns: new SqlitePipelineRunStorage({ connection }),
301
+ auth,
302
+ executions,
303
+ agents: new SqliteAgentStorage({ connection, executions }),
304
+ aiUsage: new SqliteAiUsageStorage({ connection }),
305
+ aiCosts: new SqliteAiCostStorage(connection),
306
+ actionRuns: new SqliteActionRunStorage({ connection, executions }),
307
+ pipelineRuns: new SqlitePipelineRunStorage({ connection, executions }),
264
308
  timeseries: new SqliteTimeseriesStorage({ connection }),
265
- syncRuns: new SqliteSyncRunStorage({ connection }),
266
- projectionRuns: new SqliteProjectionRunStorage({ connection }),
267
- workflowRuns: new SqliteWorkflowRunStorage({ connection }),
309
+ syncRuns: new SqliteSyncRunStorage({ connection, executions }),
310
+ projectionRuns: new SqliteProjectionRunStorage({ connection, executions }),
311
+ workflowRuns: new SqliteWorkflowRunStorage({ connection, executions }),
268
312
  workflowInterventions: new SqliteWorkflowInterventionStorage({ connection }),
269
- webhookDeliveries: new SqliteWebhookDeliveryStorage({ connection }),
270
- webhookRuns: new SqliteWebhookRunStorage({ connection }),
313
+ webhookRuns: new SqliteWebhookRunStorage({ connection, executions }),
271
314
  rules: new SqliteRulesStorage({ connection }),
315
+ connectorConnections: new SqliteConnectorConnectionStorage(connection),
272
316
  }
273
317
  }
274
318
 
@@ -276,7 +320,10 @@ interface SqliteStoreSet {
276
320
  readonly objects: SqliteObjectStorage
277
321
  readonly ontology: SqliteOntologyStorage
278
322
  readonly auth: SqliteAuthStorage
323
+ readonly executions: SqliteExecutionStorage
279
324
  readonly agents: SqliteAgentStorage
325
+ readonly aiUsage: SqliteAiUsageStorage
326
+ readonly aiCosts: SqliteAiCostStorage
280
327
  readonly actionRuns: SqliteActionRunStorage
281
328
  readonly pipelineRuns: SqlitePipelineRunStorage
282
329
  readonly syncRuns: SqliteSyncRunStorage
@@ -284,9 +331,9 @@ interface SqliteStoreSet {
284
331
  readonly workflowRuns: SqliteWorkflowRunStorage
285
332
  readonly workflowInterventions: SqliteWorkflowInterventionStorage
286
333
  readonly timeseries: SqliteTimeseriesStorage
287
- readonly webhookDeliveries: SqliteWebhookDeliveryStorage
288
334
  readonly webhookRuns: SqliteWebhookRunStorage
289
335
  readonly rules: SqliteRulesStorage
336
+ readonly connectorConnections: SqliteConnectorConnectionStorage
290
337
  }
291
338
 
292
339
  export { migrateSqliteStorage } from "./migrations"
@@ -21,6 +21,12 @@ export function queryLatestRunsByOwnerId<TRow>(
21
21
  }
22
22
 
23
23
  const placeholders = ownerIds.map(() => "?").join(", ")
24
+ const orderColumn =
25
+ input.tableName === "sync_runs" ||
26
+ input.tableName === "pipeline_runs" ||
27
+ input.tableName === "projection_runs"
28
+ ? "COALESCE(started_at, queued_at)"
29
+ : "started_at"
24
30
  const rows = input.db
25
31
  .query(
26
32
  `
@@ -30,7 +36,7 @@ export function queryLatestRunsByOwnerId<TRow>(
30
36
  *,
31
37
  ROW_NUMBER() OVER (
32
38
  PARTITION BY ${input.ownerColumn}
33
- ORDER BY started_at DESC, id DESC
39
+ ORDER BY ${orderColumn} DESC, id DESC
34
40
  ) AS sixb_latest_rank
35
41
  FROM ${input.tableName}
36
42
  WHERE project_id = ? AND ${input.ownerColumn} IN (${placeholders})
@@ -0,0 +1,142 @@
1
+ CREATE TABLE executions (
2
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
3
+ id TEXT NOT NULL CHECK (length(trim(id)) > 0),
4
+
5
+ executor_kind TEXT NOT NULL CHECK (
6
+ executor_kind IN (
7
+ 'request', 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow',
8
+ 'agent', 'kernel'
9
+ )
10
+ ),
11
+ executor_id TEXT NOT NULL CHECK (length(trim(executor_id)) > 0),
12
+ source_kind TEXT NOT NULL CHECK (
13
+ source_kind IN ('http', 'webhook', 'schedule', 'event', 'execution')
14
+ ),
15
+ source_id TEXT NOT NULL CHECK (length(trim(source_id)) > 0),
16
+
17
+ requested_by_user_id TEXT,
18
+ requested_by_service_account_id TEXT,
19
+ correlation_id TEXT NOT NULL CHECK (length(trim(correlation_id)) > 0),
20
+ parent_execution_id TEXT,
21
+
22
+ authority_kind TEXT NOT NULL CHECK (
23
+ authority_kind IN ('principal', 'trustedPrimitive', 'kernel', 'disabled')
24
+ ),
25
+ authority_user_id TEXT,
26
+ authority_service_account_id TEXT,
27
+ authority_session_id TEXT,
28
+ authority_access_token_id TEXT,
29
+ authority_primitive_kind TEXT CHECK (
30
+ authority_primitive_kind IS NULL
31
+ OR authority_primitive_kind IN (
32
+ 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow'
33
+ )
34
+ ),
35
+ authority_primitive_id TEXT,
36
+ authority_kernel_operation TEXT CHECK (
37
+ authority_kernel_operation IS NULL OR authority_kernel_operation = 'ontology.recover'
38
+ ),
39
+
40
+ created_at TEXT NOT NULL,
41
+
42
+ PRIMARY KEY (project_id, id),
43
+ FOREIGN KEY (project_id, parent_execution_id)
44
+ REFERENCES executions (project_id, id),
45
+ FOREIGN KEY (project_id, requested_by_user_id)
46
+ REFERENCES auth_users (project_id, id),
47
+ FOREIGN KEY (project_id, requested_by_service_account_id)
48
+ REFERENCES auth_service_accounts (project_id, id),
49
+ FOREIGN KEY (project_id, authority_user_id)
50
+ REFERENCES auth_users (project_id, id),
51
+ FOREIGN KEY (project_id, authority_service_account_id)
52
+ REFERENCES auth_service_accounts (project_id, id),
53
+ FOREIGN KEY (project_id, authority_session_id)
54
+ REFERENCES auth_sessions (project_id, id),
55
+ FOREIGN KEY (project_id, authority_access_token_id)
56
+ REFERENCES auth_access_tokens (project_id, id),
57
+
58
+ CHECK (
59
+ (requested_by_user_id IS NOT NULL) + (requested_by_service_account_id IS NOT NULL) <= 1
60
+ ),
61
+ CHECK (
62
+ (source_kind = 'execution' AND parent_execution_id = source_id)
63
+ OR (source_kind <> 'execution' AND parent_execution_id IS NULL)
64
+ ),
65
+ CHECK (
66
+ (
67
+ authority_kind = 'principal'
68
+ AND (authority_user_id IS NOT NULL) + (authority_service_account_id IS NOT NULL) = 1
69
+ AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) <= 1
70
+ AND (authority_session_id IS NULL OR authority_user_id IS NOT NULL)
71
+ AND authority_primitive_kind IS NULL
72
+ AND authority_primitive_id IS NULL
73
+ AND authority_kernel_operation IS NULL
74
+ )
75
+ OR (
76
+ authority_kind = 'trustedPrimitive'
77
+ AND authority_user_id IS NULL
78
+ AND authority_service_account_id IS NULL
79
+ AND authority_session_id IS NULL
80
+ AND authority_access_token_id IS NULL
81
+ AND authority_primitive_kind IS NOT NULL
82
+ AND authority_primitive_id IS NOT NULL
83
+ AND length(trim(authority_primitive_id)) > 0
84
+ AND authority_kernel_operation IS NULL
85
+ )
86
+ OR (
87
+ authority_kind = 'kernel'
88
+ AND authority_user_id IS NULL
89
+ AND authority_service_account_id IS NULL
90
+ AND authority_session_id IS NULL
91
+ AND authority_access_token_id IS NULL
92
+ AND authority_primitive_kind IS NULL
93
+ AND authority_primitive_id IS NULL
94
+ AND authority_kernel_operation IS NOT NULL
95
+ )
96
+ OR (
97
+ authority_kind = 'disabled'
98
+ AND authority_user_id IS NULL
99
+ AND authority_service_account_id IS NULL
100
+ AND authority_session_id IS NULL
101
+ AND authority_access_token_id IS NULL
102
+ AND authority_primitive_kind IS NULL
103
+ AND authority_primitive_id IS NULL
104
+ AND authority_kernel_operation IS NULL
105
+ )
106
+ ),
107
+ CHECK (
108
+ (
109
+ executor_kind = 'request'
110
+ AND source_kind = 'http'
111
+ AND executor_id = source_id
112
+ AND (
113
+ (
114
+ authority_kind = 'principal'
115
+ AND requested_by_user_id IS authority_user_id
116
+ AND requested_by_service_account_id IS authority_service_account_id
117
+ )
118
+ OR (
119
+ authority_kind = 'disabled'
120
+ AND requested_by_user_id IS NULL
121
+ AND requested_by_service_account_id IS NULL
122
+ )
123
+ )
124
+ )
125
+ OR (
126
+ executor_kind IN ('action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow')
127
+ AND authority_kind = 'trustedPrimitive'
128
+ AND executor_kind = authority_primitive_kind
129
+ )
130
+ OR (
131
+ executor_kind = 'agent'
132
+ AND authority_kind = 'principal'
133
+ AND authority_service_account_id IS NOT NULL
134
+ AND authority_session_id IS NULL
135
+ AND authority_access_token_id IS NULL
136
+ )
137
+ OR (
138
+ executor_kind = 'kernel'
139
+ AND authority_kind = 'kernel'
140
+ )
141
+ )
142
+ );
@@ -0,0 +1,7 @@
1
+ ALTER TABLE workflow_runs ADD COLUMN execution_id TEXT NOT NULL;
2
+ ALTER TABLE workflow_runs DROP COLUMN source;
3
+ ALTER TABLE workflow_runs DROP COLUMN requested_by_principal_type;
4
+ ALTER TABLE workflow_runs DROP COLUMN requested_by_principal_id;
5
+
6
+ CREATE UNIQUE INDEX idx_workflow_runs_project_execution
7
+ ON workflow_runs(project_id, execution_id);
@@ -0,0 +1,4 @@
1
+ DROP INDEX idx_ontology_source_rows_root;
2
+
3
+ CREATE INDEX idx_ontology_source_rows_root
4
+ ON ontology_source_rows(project_id, source_id, materialization_id, root_sort_key);