@sixb/pg 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 (112) hide show
  1. package/README.md +7 -6
  2. package/dist/agents/agent-storage.d.ts +7 -4
  3. package/dist/agents/agent-storage.d.ts.map +1 -1
  4. package/dist/agents/checkpoints.d.ts +12 -0
  5. package/dist/agents/checkpoints.d.ts.map +1 -0
  6. package/dist/agents/index.d.ts +1 -0
  7. package/dist/agents/index.d.ts.map +1 -1
  8. package/dist/agents/messages.d.ts +2 -1
  9. package/dist/agents/messages.d.ts.map +1 -1
  10. package/dist/agents/rows.d.ts +22 -12
  11. package/dist/agents/rows.d.ts.map +1 -1
  12. package/dist/agents/runs.d.ts +3 -2
  13. package/dist/agents/runs.d.ts.map +1 -1
  14. package/dist/auth-storage/service-accounts.d.ts.map +1 -1
  15. package/dist/auth-storage/shared.d.ts +0 -4
  16. package/dist/auth-storage/shared.d.ts.map +1 -1
  17. package/dist/connector-connection-storage.d.ts +9 -0
  18. package/dist/connector-connection-storage.d.ts.map +1 -0
  19. package/dist/index.d.ts +9 -5
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +5010 -1837
  22. package/dist/index.js.map +31 -26
  23. package/dist/latest-run-query.d.ts.map +1 -1
  24. package/dist/migrations.d.ts.map +1 -1
  25. package/dist/ontology-storage/materialization-session.d.ts.map +1 -1
  26. package/dist/ontology-storage/materialization-state.d.ts +0 -2
  27. package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
  28. package/dist/ontology-storage/materialization-writer.d.ts.map +1 -1
  29. package/dist/ontology-storage/materializations.d.ts.map +1 -1
  30. package/dist/ontology-storage/outbox.d.ts.map +1 -1
  31. package/dist/ontology-storage/shared.d.ts +3 -6
  32. package/dist/ontology-storage/shared.d.ts.map +1 -1
  33. package/dist/pg-action-run-storage.d.ts +3 -2
  34. package/dist/pg-action-run-storage.d.ts.map +1 -1
  35. package/dist/pg-ai-cost-storage.d.ts +12 -0
  36. package/dist/pg-ai-cost-storage.d.ts.map +1 -0
  37. package/dist/pg-ai-usage-storage.d.ts +16 -0
  38. package/dist/pg-ai-usage-storage.d.ts.map +1 -0
  39. package/dist/pg-execution-storage.d.ts +14 -0
  40. package/dist/pg-execution-storage.d.ts.map +1 -0
  41. package/dist/pg-pipeline-run-storage.d.ts +5 -2
  42. package/dist/pg-pipeline-run-storage.d.ts.map +1 -1
  43. package/dist/pg-projection-run-storage.d.ts +5 -2
  44. package/dist/pg-projection-run-storage.d.ts.map +1 -1
  45. package/dist/pg-sync-run-storage.d.ts +5 -2
  46. package/dist/pg-sync-run-storage.d.ts.map +1 -1
  47. package/dist/pg-webhook-run-storage.d.ts +5 -2
  48. package/dist/pg-webhook-run-storage.d.ts.map +1 -1
  49. package/dist/pg-workflow-run-storage.d.ts +5 -3
  50. package/dist/pg-workflow-run-storage.d.ts.map +1 -1
  51. package/dist/run-list-query.d.ts +1 -1
  52. package/dist/run-list-query.d.ts.map +1 -1
  53. package/dist/testing.d.ts +6 -0
  54. package/dist/testing.d.ts.map +1 -0
  55. package/package.json +3 -3
  56. package/src/agents/agent-storage.ts +9 -5
  57. package/src/agents/checkpoints.ts +175 -0
  58. package/src/agents/index.ts +1 -0
  59. package/src/agents/messages.ts +71 -13
  60. package/src/agents/rows.ts +57 -43
  61. package/src/agents/runs.ts +29 -15
  62. package/src/auth-storage/service-accounts.ts +14 -15
  63. package/src/auth-storage/shared.ts +0 -8
  64. package/src/connector-connection-storage.ts +760 -0
  65. package/src/index.ts +38 -15
  66. package/src/latest-run-query.ts +7 -1
  67. package/src/migrations/004-executions.sql +140 -0
  68. package/src/migrations/005-workflow-executions.sql +10 -0
  69. package/src/migrations/006-narrow-ontology-source-root-index.sql +4 -0
  70. package/src/migrations/007-split-overrides.sql +153 -0
  71. package/src/migrations/008-action-executions.sql +7 -0
  72. package/src/migrations/009-agent-executions.sql +21 -0
  73. package/src/migrations/010-ai-usage-accounting-foundation.sql +76 -0
  74. package/src/migrations/011-sync-failure-record.sql +23 -0
  75. package/src/migrations/012-pipeline-failure-record.sql +47 -0
  76. package/src/migrations/013-workflow-failure-record.sql +45 -0
  77. package/src/migrations/014-agent-failure-record.sql +56 -0
  78. package/src/migrations/015-projection-failure-record.sql +20 -0
  79. package/src/migrations/016-webhook-run-failure-record.sql +19 -0
  80. package/src/migrations/017-action-failure-record.sql +65 -0
  81. package/src/migrations/018-ontology-outbox-failure-record.sql +29 -0
  82. package/src/migrations/019-webhook-delivery-failure-record.sql +27 -0
  83. package/src/migrations/020-drop-run-usage-projections.sql +8 -0
  84. package/src/migrations/021-sync-pipeline-executions.sql +50 -0
  85. package/src/migrations/022-projection-executions.sql +115 -0
  86. package/src/migrations/023-webhook-executions.sql +30 -0
  87. package/src/migrations/024-ontology-commit-executions.sql +12 -0
  88. package/src/migrations/025-connector-connections.sql +231 -0
  89. package/src/migrations/026-ai-cost-accounting.sql +53 -0
  90. package/src/migrations/027-agent-context-checkpoints.sql +34 -0
  91. package/src/migrations/028-object-override-edit-times.sql +3 -0
  92. package/src/migrations.ts +82 -0
  93. package/src/ontology-storage/materialization-session.ts +25 -28
  94. package/src/ontology-storage/materialization-state.ts +161 -43
  95. package/src/ontology-storage/materialization-writer.ts +149 -76
  96. package/src/ontology-storage/materializations.ts +3 -1
  97. package/src/ontology-storage/outbox.ts +9 -2
  98. package/src/ontology-storage/shared.ts +10 -20
  99. package/src/pg-action-run-storage.ts +43 -67
  100. package/src/pg-ai-cost-storage.ts +707 -0
  101. package/src/pg-ai-usage-storage.ts +290 -0
  102. package/src/pg-execution-storage.ts +147 -0
  103. package/src/pg-pipeline-run-storage.ts +107 -41
  104. package/src/pg-projection-run-storage.ts +159 -91
  105. package/src/pg-sync-run-storage.ts +100 -28
  106. package/src/pg-webhook-run-storage.ts +89 -57
  107. package/src/pg-workflow-run-storage.ts +97 -130
  108. package/src/run-list-query.ts +9 -4
  109. package/src/testing.ts +18 -0
  110. package/dist/pg-webhook-delivery-storage.d.ts +0 -17
  111. package/dist/pg-webhook-delivery-storage.d.ts.map +0 -1
  112. package/src/pg-webhook-delivery-storage.ts +0 -180
@@ -0,0 +1,290 @@
1
+ import type { ReadonlyJsonObject } from "@sixb/core/storage"
2
+ import {
3
+ type AiModelCallUsageInput,
4
+ type AiModelCallUsageRecord,
5
+ type AiUsageExecutionSummary,
6
+ type AiUsageStorage,
7
+ AiUsageStorageError,
8
+ aggregateAiModelCallUsage,
9
+ assertAiUsageExecutionId,
10
+ normalizeAiModelCallRecord,
11
+ type RecordAiModelCallInput,
12
+ type RecordAiModelCallResult,
13
+ type SummarizeAiUsageExecutionInput,
14
+ type SummarizeAiUsageExecutionsInput,
15
+ } from "@sixb/core/storage"
16
+ import type { SQLClient } from "./pg-client"
17
+ import { type PgStoreClient, runPgTransaction } from "./transactions"
18
+
19
+ /** PostgreSQL-backed append-only model-call usage ledger. */
20
+ export class PgAiUsageStorage implements AiUsageStorage {
21
+ constructor(private readonly sql: PgStoreClient) {}
22
+
23
+ async recordModelCall(input: RecordAiModelCallInput): Promise<RecordAiModelCallResult> {
24
+ const record = normalizeAiModelCallRecord(input)
25
+ return runPgTransaction(this.sql, async (tx) => {
26
+ const existing = await this.findByIdempotencyKey(tx, record)
27
+ if (existing) return { record: existing, created: false }
28
+ await this.assertExecutionExists(tx, record.projectId, record.executionId)
29
+
30
+ const inserted = await tx<{ id: string }[]>`
31
+ INSERT INTO ai_model_call_usage (
32
+ project_id,
33
+ id,
34
+ execution_id,
35
+ attempt,
36
+ call_id,
37
+ provider_id,
38
+ requested_model_id,
39
+ response_model_id,
40
+ response_id,
41
+ input_tokens,
42
+ output_tokens,
43
+ total_tokens,
44
+ uncached_input_tokens,
45
+ cache_read_input_tokens,
46
+ cache_write_input_tokens,
47
+ text_output_tokens,
48
+ reasoning_output_tokens,
49
+ reporting_status,
50
+ raw_usage,
51
+ occurred_at,
52
+ recorded_at
53
+ ) VALUES (
54
+ ${record.projectId},
55
+ ${record.id},
56
+ ${record.executionId},
57
+ ${record.attempt},
58
+ ${record.callId},
59
+ ${record.providerId},
60
+ ${record.requestedModelId},
61
+ ${record.responseModelId ?? null},
62
+ ${record.responseId},
63
+ ${record.usage.inputTokens ?? null},
64
+ ${record.usage.outputTokens ?? null},
65
+ ${record.usage.totalTokens ?? null},
66
+ ${record.usage.uncachedInputTokens ?? null},
67
+ ${record.usage.cacheReadInputTokens ?? null},
68
+ ${record.usage.cacheWriteInputTokens ?? null},
69
+ ${record.usage.textOutputTokens ?? null},
70
+ ${record.usage.reasoningOutputTokens ?? null},
71
+ ${record.usage.reportingStatus},
72
+ ${record.rawUsage === undefined ? null : JSON.stringify(record.rawUsage)}::text::jsonb,
73
+ ${record.occurredAt},
74
+ ${record.recordedAt}
75
+ )
76
+ ON CONFLICT DO NOTHING
77
+ RETURNING id
78
+ `
79
+
80
+ if (inserted.length === 0) {
81
+ const concurrent = await this.findByIdempotencyKey(tx, record)
82
+ if (concurrent) return { record: concurrent, created: false }
83
+ throw new AiUsageStorageError(
84
+ "duplicate_id",
85
+ `[SixbPg] AI usage record '${record.id}' already exists for project '${record.projectId}'.`
86
+ )
87
+ }
88
+
89
+ for (const groupId of record.requesterGroupIds) {
90
+ await tx`
91
+ INSERT INTO ai_model_call_usage_groups (
92
+ project_id, usage_record_id, group_id, occurred_at
93
+ ) VALUES (
94
+ ${record.projectId}, ${record.id}, ${groupId}, ${record.occurredAt}
95
+ )
96
+ `
97
+ }
98
+
99
+ return { record: await this.requireById(tx, record.projectId, record.id), created: true }
100
+ })
101
+ }
102
+
103
+ async summarizeExecution(
104
+ input: SummarizeAiUsageExecutionInput
105
+ ): Promise<AiUsageExecutionSummary> {
106
+ const [summary] = await this.summarizeExecutions({
107
+ projectId: input.projectId,
108
+ executionIds: [input.executionId],
109
+ })
110
+ return summary!
111
+ }
112
+
113
+ async summarizeExecutions(
114
+ input: SummarizeAiUsageExecutionsInput
115
+ ): Promise<readonly AiUsageExecutionSummary[]> {
116
+ assertNonBlankProjectId(input.projectId)
117
+ for (const executionId of input.executionIds) assertAiUsageExecutionId(executionId)
118
+ if (input.executionIds.length === 0) return []
119
+
120
+ const rows = await this.executionRows(this.sql, input)
121
+ return aggregateExecutionRows(input.executionIds, rows)
122
+ }
123
+
124
+ private async findByIdempotencyKey(
125
+ sql: PgStoreClient,
126
+ record: Pick<
127
+ AiModelCallUsageRecord,
128
+ "projectId" | "executionId" | "attempt" | "callId" | "responseId"
129
+ >
130
+ ): Promise<AiModelCallUsageRecord | null> {
131
+ const rows = await sql<AiUsageRow[]>`
132
+ SELECT * FROM ai_model_call_usage
133
+ WHERE project_id = ${record.projectId}
134
+ AND execution_id = ${record.executionId}
135
+ AND attempt = ${record.attempt}
136
+ AND call_id = ${record.callId}
137
+ AND response_id = ${record.responseId}
138
+ `
139
+ return rows[0] ? this.rowToRecord(sql, rows[0]) : null
140
+ }
141
+
142
+ private async requireById(
143
+ sql: SQLClient,
144
+ projectId: string,
145
+ id: string
146
+ ): Promise<AiModelCallUsageRecord> {
147
+ const [row] = await sql<AiUsageRow[]>`
148
+ SELECT * FROM ai_model_call_usage WHERE project_id = ${projectId} AND id = ${id}
149
+ `
150
+ if (!row) throw new Error(`[SixbPg] AI usage record '${id}' disappeared after insert.`)
151
+ return this.rowToRecord(sql, row)
152
+ }
153
+
154
+ private async rowToRecord(sql: PgStoreClient, row: AiUsageRow): Promise<AiModelCallUsageRecord> {
155
+ const groupRows = await sql<Array<{ group_id: string }>>`
156
+ SELECT group_id FROM ai_model_call_usage_groups
157
+ WHERE project_id = ${row.project_id} AND usage_record_id = ${row.id}
158
+ ORDER BY group_id
159
+ `
160
+
161
+ return {
162
+ id: row.id,
163
+ projectId: row.project_id,
164
+ executionId: row.execution_id,
165
+ attempt: Number(row.attempt),
166
+ callId: row.call_id,
167
+ requesterGroupIds: groupRows.map((group) => group.group_id),
168
+ providerId: row.provider_id,
169
+ requestedModelId: row.requested_model_id,
170
+ ...(row.response_model_id === null ? {} : { responseModelId: row.response_model_id }),
171
+ responseId: row.response_id,
172
+ usage: {
173
+ ...usageFromRow(row),
174
+ ...(row.total_tokens === null ? {} : { totalTokens: Number(row.total_tokens) }),
175
+ reportingStatus: row.reporting_status,
176
+ },
177
+ ...(row.raw_usage === null ? {} : { rawUsage: rawUsageFromRow(row.raw_usage) }),
178
+ occurredAt: new Date(row.occurred_at),
179
+ recordedAt: new Date(row.recorded_at),
180
+ }
181
+ }
182
+
183
+ private executionRows(
184
+ sql: PgStoreClient,
185
+ input: SummarizeAiUsageExecutionsInput
186
+ ): Promise<AiUsageRow[]> {
187
+ const executionIds = [...new Set(input.executionIds)]
188
+
189
+ return sql<AiUsageRow[]>`
190
+ WITH requested(execution_id) AS (
191
+ SELECT * FROM unnest(${sql.array(executionIds)}::text[])
192
+ )
193
+ SELECT usage.* FROM requested
194
+ JOIN ai_model_call_usage AS usage
195
+ ON usage.project_id = ${input.projectId}
196
+ AND usage.execution_id = requested.execution_id
197
+ `
198
+ }
199
+
200
+ private async assertExecutionExists(
201
+ sql: PgStoreClient,
202
+ projectId: string,
203
+ executionId: string
204
+ ): Promise<void> {
205
+ const [execution] = await sql<{ exists: boolean }[]>`
206
+ SELECT EXISTS (
207
+ SELECT 1 FROM executions WHERE project_id = ${projectId} AND id = ${executionId}
208
+ ) AS exists
209
+ `
210
+ if (execution?.exists) return
211
+ throw new AiUsageStorageError(
212
+ "missing_execution",
213
+ `[SixbPg] AI usage execution '${executionId}' does not exist in project '${projectId}'.`
214
+ )
215
+ }
216
+ }
217
+
218
+ interface AiUsageRow {
219
+ readonly project_id: string
220
+ readonly id: string
221
+ readonly execution_id: string
222
+ readonly attempt: number | string
223
+ readonly call_id: string
224
+ readonly provider_id: string
225
+ readonly requested_model_id: string
226
+ readonly response_model_id: string | null
227
+ readonly response_id: string
228
+ readonly input_tokens: number | string | null
229
+ readonly output_tokens: number | string | null
230
+ readonly total_tokens: number | string | null
231
+ readonly uncached_input_tokens: number | string | null
232
+ readonly cache_read_input_tokens: number | string | null
233
+ readonly cache_write_input_tokens: number | string | null
234
+ readonly text_output_tokens: number | string | null
235
+ readonly reasoning_output_tokens: number | string | null
236
+ readonly reporting_status: AiModelCallUsageRecord["usage"]["reportingStatus"]
237
+ readonly raw_usage: ReadonlyJsonObject | string | null
238
+ readonly occurred_at: Date | string
239
+ readonly recorded_at: Date | string
240
+ }
241
+
242
+ function aggregateExecutionRows(
243
+ executionIds: readonly string[],
244
+ rows: readonly AiUsageRow[]
245
+ ): readonly AiUsageExecutionSummary[] {
246
+ const usageByExecutionId = new Map<string, AiModelCallUsageInput[]>()
247
+ for (const executionId of executionIds) usageByExecutionId.set(executionId, [])
248
+ for (const row of rows) {
249
+ usageByExecutionId.get(row.execution_id)?.push(usageFromRow(row))
250
+ }
251
+ return executionIds.map((executionId) => {
252
+ const usages = usageByExecutionId.get(executionId) ?? []
253
+ return {
254
+ modelCallCount: usages.length,
255
+ usage: aggregateAiModelCallUsage(usages),
256
+ }
257
+ })
258
+ }
259
+
260
+ function usageFromRow(row: AiUsageRow): AiModelCallUsageInput {
261
+ return {
262
+ ...(row.input_tokens === null ? {} : { inputTokens: Number(row.input_tokens) }),
263
+ ...(row.output_tokens === null ? {} : { outputTokens: Number(row.output_tokens) }),
264
+ ...(row.uncached_input_tokens === null
265
+ ? {}
266
+ : { uncachedInputTokens: Number(row.uncached_input_tokens) }),
267
+ ...(row.cache_read_input_tokens === null
268
+ ? {}
269
+ : { cacheReadInputTokens: Number(row.cache_read_input_tokens) }),
270
+ ...(row.cache_write_input_tokens === null
271
+ ? {}
272
+ : { cacheWriteInputTokens: Number(row.cache_write_input_tokens) }),
273
+ ...(row.text_output_tokens === null
274
+ ? {}
275
+ : { textOutputTokens: Number(row.text_output_tokens) }),
276
+ ...(row.reasoning_output_tokens === null
277
+ ? {}
278
+ : { reasoningOutputTokens: Number(row.reasoning_output_tokens) }),
279
+ }
280
+ }
281
+
282
+ function rawUsageFromRow(value: Exclude<AiUsageRow["raw_usage"], null>): ReadonlyJsonObject {
283
+ return typeof value === "string" ? (JSON.parse(value) as ReadonlyJsonObject) : value
284
+ }
285
+
286
+ function assertNonBlankProjectId(projectId: string): void {
287
+ if (typeof projectId !== "string" || projectId.trim().length === 0) {
288
+ throw new TypeError("[Sixb] AI usage projectId must be nonblank.")
289
+ }
290
+ }
@@ -0,0 +1,147 @@
1
+ import {
2
+ type ExecutionStorageRow,
3
+ executionRecordFromStorageRow,
4
+ executionRecordToStorageRow,
5
+ normalizeExecutionRecord,
6
+ validateExecutionRecordReferences,
7
+ } from "@sixb/core/internal/execution-storage"
8
+ import type { CreateExecutionInput, ExecutionRecord, ExecutionStorage } from "@sixb/core/storage"
9
+ import { ExecutionStorageError } from "@sixb/core/storage"
10
+ import type { PgAuthStorage } from "./auth-storage"
11
+ import { isUniqueViolation } from "./storage-errors"
12
+ import type { PgStoreClient } from "./transactions"
13
+
14
+ export class PgExecutionStorage implements ExecutionStorage {
15
+ constructor(
16
+ private readonly sql: PgStoreClient,
17
+ private readonly auth: PgAuthStorage
18
+ ) {}
19
+
20
+ async create(input: CreateExecutionInput): Promise<ExecutionRecord> {
21
+ const record = normalizeExecutionRecord(input)
22
+ await validateExecutionRecordReferences(record, {
23
+ auth: this.auth,
24
+ getExecution: (params) => this.getById(params),
25
+ })
26
+ const row = executionRecordToStorageRow(record)
27
+
28
+ try {
29
+ const [created] = await this.sql<PgExecutionRow[]>`
30
+ INSERT INTO executions (
31
+ project_id,
32
+ id,
33
+ executor_kind,
34
+ executor_id,
35
+ source_kind,
36
+ source_id,
37
+ requested_by_user_id,
38
+ requested_by_service_account_id,
39
+ correlation_id,
40
+ parent_execution_id,
41
+ authority_kind,
42
+ authority_user_id,
43
+ authority_service_account_id,
44
+ authority_session_id,
45
+ authority_access_token_id,
46
+ authority_primitive_kind,
47
+ authority_primitive_id,
48
+ authority_kernel_operation,
49
+ created_at
50
+ ) VALUES (
51
+ ${row.projectId},
52
+ ${row.id},
53
+ ${row.executorKind},
54
+ ${row.executorId},
55
+ ${row.sourceKind},
56
+ ${row.sourceId},
57
+ ${row.requestedByUserId},
58
+ ${row.requestedByServiceAccountId},
59
+ ${row.correlationId},
60
+ ${row.parentExecutionId},
61
+ ${row.authorityKind},
62
+ ${row.authorityUserId},
63
+ ${row.authorityServiceAccountId},
64
+ ${row.authoritySessionId},
65
+ ${row.authorityAccessTokenId},
66
+ ${row.authorityPrimitiveKind},
67
+ ${row.authorityPrimitiveId},
68
+ ${row.authorityKernelOperation},
69
+ ${row.createdAt}
70
+ )
71
+ RETURNING *
72
+ `
73
+
74
+ if (!created) {
75
+ throw new Error("[SixbPg] Execution insert returned no row.")
76
+ }
77
+ return executionRecordFromStorageRow(toStorageRow(created))
78
+ } catch (error) {
79
+ if (isUniqueViolation(error)) {
80
+ throw new ExecutionStorageError(
81
+ "duplicate_execution",
82
+ `[SixbPg] Execution '${record.id}' already exists in project '${record.projectId}'.`,
83
+ { cause: error }
84
+ )
85
+ }
86
+ throw error
87
+ }
88
+ }
89
+
90
+ async getById(params: {
91
+ readonly projectId: string
92
+ readonly id: string
93
+ }): Promise<ExecutionRecord | null> {
94
+ const [row] = await this.sql<PgExecutionRow[]>`
95
+ SELECT *
96
+ FROM executions
97
+ WHERE project_id = ${params.projectId} AND id = ${params.id}
98
+ `
99
+ return row ? executionRecordFromStorageRow(toStorageRow(row)) : null
100
+ }
101
+ }
102
+
103
+ function toStorageRow(row: PgExecutionRow): ExecutionStorageRow {
104
+ return {
105
+ projectId: row.project_id,
106
+ id: row.id,
107
+ executorKind: row.executor_kind,
108
+ executorId: row.executor_id,
109
+ sourceKind: row.source_kind,
110
+ sourceId: row.source_id,
111
+ requestedByUserId: row.requested_by_user_id,
112
+ requestedByServiceAccountId: row.requested_by_service_account_id,
113
+ correlationId: row.correlation_id,
114
+ parentExecutionId: row.parent_execution_id,
115
+ authorityKind: row.authority_kind,
116
+ authorityUserId: row.authority_user_id,
117
+ authorityServiceAccountId: row.authority_service_account_id,
118
+ authoritySessionId: row.authority_session_id,
119
+ authorityAccessTokenId: row.authority_access_token_id,
120
+ authorityPrimitiveKind: row.authority_primitive_kind,
121
+ authorityPrimitiveId: row.authority_primitive_id,
122
+ authorityKernelOperation: row.authority_kernel_operation,
123
+ createdAt: new Date(row.created_at),
124
+ }
125
+ }
126
+
127
+ interface PgExecutionRow {
128
+ readonly project_id: string
129
+ readonly id: string
130
+ readonly executor_kind: ExecutionStorageRow["executorKind"]
131
+ readonly executor_id: string
132
+ readonly source_kind: ExecutionStorageRow["sourceKind"]
133
+ readonly source_id: string
134
+ readonly requested_by_user_id: string | null
135
+ readonly requested_by_service_account_id: string | null
136
+ readonly correlation_id: string
137
+ readonly parent_execution_id: string | null
138
+ readonly authority_kind: ExecutionStorageRow["authorityKind"]
139
+ readonly authority_user_id: string | null
140
+ readonly authority_service_account_id: string | null
141
+ readonly authority_session_id: string | null
142
+ readonly authority_access_token_id: string | null
143
+ readonly authority_primitive_kind: ExecutionStorageRow["authorityPrimitiveKind"]
144
+ readonly authority_primitive_id: string | null
145
+ readonly authority_kernel_operation: ExecutionStorageRow["authorityKernelOperation"]
146
+ readonly created_at: Date | string
147
+ }