@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.
- package/README.md +7 -6
- package/dist/agents/agent-storage.d.ts +7 -4
- package/dist/agents/agent-storage.d.ts.map +1 -1
- package/dist/agents/checkpoints.d.ts +12 -0
- package/dist/agents/checkpoints.d.ts.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/messages.d.ts +2 -1
- package/dist/agents/messages.d.ts.map +1 -1
- package/dist/agents/rows.d.ts +22 -12
- package/dist/agents/rows.d.ts.map +1 -1
- package/dist/agents/runs.d.ts +3 -2
- package/dist/agents/runs.d.ts.map +1 -1
- package/dist/auth-storage/service-accounts.d.ts.map +1 -1
- package/dist/auth-storage/shared.d.ts +0 -4
- package/dist/auth-storage/shared.d.ts.map +1 -1
- package/dist/connector-connection-storage.d.ts +9 -0
- package/dist/connector-connection-storage.d.ts.map +1 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5010 -1837
- package/dist/index.js.map +31 -26
- package/dist/latest-run-query.d.ts.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-session.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-state.d.ts +0 -2
- package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-writer.d.ts.map +1 -1
- package/dist/ontology-storage/materializations.d.ts.map +1 -1
- package/dist/ontology-storage/outbox.d.ts.map +1 -1
- package/dist/ontology-storage/shared.d.ts +3 -6
- package/dist/ontology-storage/shared.d.ts.map +1 -1
- package/dist/pg-action-run-storage.d.ts +3 -2
- package/dist/pg-action-run-storage.d.ts.map +1 -1
- package/dist/pg-ai-cost-storage.d.ts +12 -0
- package/dist/pg-ai-cost-storage.d.ts.map +1 -0
- package/dist/pg-ai-usage-storage.d.ts +16 -0
- package/dist/pg-ai-usage-storage.d.ts.map +1 -0
- package/dist/pg-execution-storage.d.ts +14 -0
- package/dist/pg-execution-storage.d.ts.map +1 -0
- package/dist/pg-pipeline-run-storage.d.ts +5 -2
- package/dist/pg-pipeline-run-storage.d.ts.map +1 -1
- package/dist/pg-projection-run-storage.d.ts +5 -2
- package/dist/pg-projection-run-storage.d.ts.map +1 -1
- package/dist/pg-sync-run-storage.d.ts +5 -2
- package/dist/pg-sync-run-storage.d.ts.map +1 -1
- package/dist/pg-webhook-run-storage.d.ts +5 -2
- package/dist/pg-webhook-run-storage.d.ts.map +1 -1
- package/dist/pg-workflow-run-storage.d.ts +5 -3
- package/dist/pg-workflow-run-storage.d.ts.map +1 -1
- package/dist/run-list-query.d.ts +1 -1
- package/dist/run-list-query.d.ts.map +1 -1
- package/dist/testing.d.ts +6 -0
- package/dist/testing.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/agents/agent-storage.ts +9 -5
- package/src/agents/checkpoints.ts +175 -0
- package/src/agents/index.ts +1 -0
- package/src/agents/messages.ts +71 -13
- package/src/agents/rows.ts +57 -43
- package/src/agents/runs.ts +29 -15
- package/src/auth-storage/service-accounts.ts +14 -15
- package/src/auth-storage/shared.ts +0 -8
- package/src/connector-connection-storage.ts +760 -0
- package/src/index.ts +38 -15
- package/src/latest-run-query.ts +7 -1
- package/src/migrations/004-executions.sql +140 -0
- package/src/migrations/005-workflow-executions.sql +10 -0
- package/src/migrations/006-narrow-ontology-source-root-index.sql +4 -0
- package/src/migrations/007-split-overrides.sql +153 -0
- package/src/migrations/008-action-executions.sql +7 -0
- package/src/migrations/009-agent-executions.sql +21 -0
- package/src/migrations/010-ai-usage-accounting-foundation.sql +76 -0
- package/src/migrations/011-sync-failure-record.sql +23 -0
- package/src/migrations/012-pipeline-failure-record.sql +47 -0
- package/src/migrations/013-workflow-failure-record.sql +45 -0
- package/src/migrations/014-agent-failure-record.sql +56 -0
- package/src/migrations/015-projection-failure-record.sql +20 -0
- package/src/migrations/016-webhook-run-failure-record.sql +19 -0
- package/src/migrations/017-action-failure-record.sql +65 -0
- package/src/migrations/018-ontology-outbox-failure-record.sql +29 -0
- package/src/migrations/019-webhook-delivery-failure-record.sql +27 -0
- package/src/migrations/020-drop-run-usage-projections.sql +8 -0
- package/src/migrations/021-sync-pipeline-executions.sql +50 -0
- package/src/migrations/022-projection-executions.sql +115 -0
- package/src/migrations/023-webhook-executions.sql +30 -0
- package/src/migrations/024-ontology-commit-executions.sql +12 -0
- package/src/migrations/025-connector-connections.sql +231 -0
- package/src/migrations/026-ai-cost-accounting.sql +53 -0
- package/src/migrations/027-agent-context-checkpoints.sql +34 -0
- package/src/migrations/028-object-override-edit-times.sql +3 -0
- package/src/migrations.ts +82 -0
- package/src/ontology-storage/materialization-session.ts +25 -28
- package/src/ontology-storage/materialization-state.ts +161 -43
- package/src/ontology-storage/materialization-writer.ts +149 -76
- package/src/ontology-storage/materializations.ts +3 -1
- package/src/ontology-storage/outbox.ts +9 -2
- package/src/ontology-storage/shared.ts +10 -20
- package/src/pg-action-run-storage.ts +43 -67
- package/src/pg-ai-cost-storage.ts +707 -0
- package/src/pg-ai-usage-storage.ts +290 -0
- package/src/pg-execution-storage.ts +147 -0
- package/src/pg-pipeline-run-storage.ts +107 -41
- package/src/pg-projection-run-storage.ts +159 -91
- package/src/pg-sync-run-storage.ts +100 -28
- package/src/pg-webhook-run-storage.ts +89 -57
- package/src/pg-workflow-run-storage.ts +97 -130
- package/src/run-list-query.ts +9 -4
- package/src/testing.ts +18 -0
- package/dist/pg-webhook-delivery-storage.d.ts +0 -17
- package/dist/pg-webhook-delivery-storage.d.ts.map +0 -1
- package/src/pg-webhook-delivery-storage.ts +0 -180
|
@@ -0,0 +1,760 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ConnectorConnectionPersistence,
|
|
3
|
+
type ConnectorConnectionPersistenceBackend,
|
|
4
|
+
type ConnectorConnectionPersistenceScope,
|
|
5
|
+
DurableConnectorConnectionStorage,
|
|
6
|
+
} from "@sixb/core/internal/connector-connection-storage-provider"
|
|
7
|
+
import type {
|
|
8
|
+
ConnectorAuthorizationAttemptRecord,
|
|
9
|
+
ConnectorAuthorizationRecord,
|
|
10
|
+
ConnectorConnectionRecord,
|
|
11
|
+
ConnectorConnectionRunRecord,
|
|
12
|
+
ConnectorCredentialMutation,
|
|
13
|
+
ConnectorStagedCredentials,
|
|
14
|
+
} from "@sixb/core/storage"
|
|
15
|
+
import type { SQLClient } from "./pg-client"
|
|
16
|
+
import { isUniqueViolation } from "./storage-errors"
|
|
17
|
+
import { lockAdvisoryKeys, type PgStoreClient, runPgTransaction } from "./transactions"
|
|
18
|
+
|
|
19
|
+
export class PgConnectorConnectionStorage extends DurableConnectorConnectionStorage {
|
|
20
|
+
private readonly clock: ConnectorConnectionTestClock
|
|
21
|
+
|
|
22
|
+
constructor(sql: PgStoreClient) {
|
|
23
|
+
const clock = { offsetMs: 0 }
|
|
24
|
+
super(new PgConnectorConnectionPersistenceBackend(sql, clock))
|
|
25
|
+
this.clock = clock
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Internal deterministic clock control used only by the provider contract suite. */
|
|
29
|
+
advanceTimeForTesting(durationMs: number): void {
|
|
30
|
+
this.clock.offsetMs += durationMs
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class PgConnectorConnectionPersistenceBackend implements ConnectorConnectionPersistenceBackend {
|
|
35
|
+
constructor(
|
|
36
|
+
private readonly sql: PgStoreClient,
|
|
37
|
+
private readonly clock: ConnectorConnectionTestClock
|
|
38
|
+
) {}
|
|
39
|
+
|
|
40
|
+
read<T>(
|
|
41
|
+
scope: ConnectorConnectionPersistenceScope,
|
|
42
|
+
run: (persistence: ConnectorConnectionPersistence) => Promise<T>
|
|
43
|
+
): Promise<T> {
|
|
44
|
+
return run(new PgConnectorConnectionPersistence(this.sql, scope, false, this.clock))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
transaction<T>(
|
|
48
|
+
scope: ConnectorConnectionPersistenceScope,
|
|
49
|
+
run: (persistence: ConnectorConnectionPersistence) => Promise<T>
|
|
50
|
+
): Promise<T> {
|
|
51
|
+
return runPgTransaction(this.sql, async (tx) => {
|
|
52
|
+
if (scope.connectorId) {
|
|
53
|
+
await lockAdvisoryKeys(tx, [
|
|
54
|
+
["connector-connections", scope.projectId, scope.connectorId].join(":"),
|
|
55
|
+
])
|
|
56
|
+
}
|
|
57
|
+
return run(new PgConnectorConnectionPersistence(tx, scope, true, this.clock))
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
class PgConnectorConnectionPersistence implements ConnectorConnectionPersistence {
|
|
63
|
+
constructor(
|
|
64
|
+
private readonly sql: PgStoreClient,
|
|
65
|
+
private readonly scope: ConnectorConnectionPersistenceScope,
|
|
66
|
+
private readonly locking: boolean,
|
|
67
|
+
private readonly clock: ConnectorConnectionTestClock
|
|
68
|
+
) {}
|
|
69
|
+
|
|
70
|
+
async now(): Promise<Date> {
|
|
71
|
+
const [row] = await this.sql<{ readonly now: Date | string }[]>`
|
|
72
|
+
SELECT clock_timestamp() AS now
|
|
73
|
+
`
|
|
74
|
+
if (!row) throw new Error("[SixbPg] Database clock returned no row.")
|
|
75
|
+
return new Date(new Date(row.now).getTime() + this.clock.offsetMs)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async insertAuthorizationAttempt(record: ConnectorAuthorizationAttemptRecord): Promise<boolean> {
|
|
79
|
+
try {
|
|
80
|
+
await this.sql`
|
|
81
|
+
INSERT INTO connector_authorization_attempts (
|
|
82
|
+
project_id, connector_id, id, slot, initiated_by_execution_id,
|
|
83
|
+
state_hash, code_verifier, redirect_uri, connection_run_id, return_to,
|
|
84
|
+
callback_binding_hash, reauthorization_id, reauthorization_revision,
|
|
85
|
+
reauthorization_connection_ids, created_at, expires_at
|
|
86
|
+
) VALUES (
|
|
87
|
+
${record.projectId}, ${record.connectorId}, ${record.id}, ${record.slot},
|
|
88
|
+
${record.initiatedByExecutionId}, ${record.stateHash},
|
|
89
|
+
${jsonParameter(this.sql, record.codeVerifier)}, ${record.redirectUri},
|
|
90
|
+
${record.connectionRunId ?? null}, ${record.returnTo ?? null},
|
|
91
|
+
${record.callbackBindingHash ?? null}, ${record.reauthorizationId ?? null},
|
|
92
|
+
${record.reauthorizationRevision ?? null},
|
|
93
|
+
${
|
|
94
|
+
record.reauthorizationConnectionIds
|
|
95
|
+
? jsonParameter(this.sql, record.reauthorizationConnectionIds)
|
|
96
|
+
: null
|
|
97
|
+
},
|
|
98
|
+
${record.createdAt}, ${record.expiresAt}
|
|
99
|
+
)
|
|
100
|
+
`
|
|
101
|
+
return true
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if (isUniqueViolation(error)) return false
|
|
104
|
+
throw error
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async getAuthorizationAttempt(id: string): Promise<ConnectorAuthorizationAttemptRecord | null> {
|
|
109
|
+
const rows = this.scope.connectorId
|
|
110
|
+
? await this.sql<PgAuthorizationAttemptRow[]>`
|
|
111
|
+
SELECT * FROM connector_authorization_attempts
|
|
112
|
+
WHERE project_id = ${this.scope.projectId}
|
|
113
|
+
AND connector_id = ${this.scope.connectorId}
|
|
114
|
+
AND id = ${id}
|
|
115
|
+
${this.lockClause()}
|
|
116
|
+
`
|
|
117
|
+
: await this.sql<PgAuthorizationAttemptRow[]>`
|
|
118
|
+
SELECT * FROM connector_authorization_attempts
|
|
119
|
+
WHERE project_id = ${this.scope.projectId} AND id = ${id}
|
|
120
|
+
${this.lockClause()}
|
|
121
|
+
`
|
|
122
|
+
return rows[0] ? authorizationAttemptFromRow(rows[0]) : null
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async getAuthorizationAttemptByConnectionRunId(
|
|
126
|
+
connectionRunId: string
|
|
127
|
+
): Promise<ConnectorAuthorizationAttemptRecord | null> {
|
|
128
|
+
if (!this.scope.connectorId) return null
|
|
129
|
+
const rows = await this.sql<PgAuthorizationAttemptRow[]>`
|
|
130
|
+
SELECT * FROM connector_authorization_attempts
|
|
131
|
+
WHERE project_id = ${this.scope.projectId}
|
|
132
|
+
AND connector_id = ${this.scope.connectorId}
|
|
133
|
+
AND connection_run_id = ${connectionRunId}
|
|
134
|
+
${this.lockClause()}
|
|
135
|
+
`
|
|
136
|
+
return rows[0] ? authorizationAttemptFromRow(rows[0]) : null
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async deleteAuthorizationAttempt(id: string): Promise<boolean> {
|
|
140
|
+
const rows = this.scope.connectorId
|
|
141
|
+
? await this.sql<{ readonly id: string }[]>`
|
|
142
|
+
DELETE FROM connector_authorization_attempts
|
|
143
|
+
WHERE project_id = ${this.scope.projectId}
|
|
144
|
+
AND connector_id = ${this.scope.connectorId}
|
|
145
|
+
AND id = ${id}
|
|
146
|
+
RETURNING id
|
|
147
|
+
`
|
|
148
|
+
: await this.sql<{ readonly id: string }[]>`
|
|
149
|
+
DELETE FROM connector_authorization_attempts
|
|
150
|
+
WHERE project_id = ${this.scope.projectId} AND id = ${id}
|
|
151
|
+
RETURNING id
|
|
152
|
+
`
|
|
153
|
+
return rows.length === 1
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async insertConnectionRun(record: ConnectorConnectionRunRecord): Promise<boolean> {
|
|
157
|
+
try {
|
|
158
|
+
const values = runValues(record)
|
|
159
|
+
await this.sql`
|
|
160
|
+
INSERT INTO connector_connection_runs (
|
|
161
|
+
project_id, connector_id, id, kind, slot, initiated_by_execution_id,
|
|
162
|
+
status, waiting_for, processing_id, callback_started_at,
|
|
163
|
+
expires_at, authorization_id, cleanup_authorization_id, connections, error,
|
|
164
|
+
created_at, updated_at, finished_at
|
|
165
|
+
) VALUES (
|
|
166
|
+
${record.projectId}, ${record.connectorId}, ${record.id}, ${values.kind},
|
|
167
|
+
${values.slot}, ${values.initiatedByExecutionId}, ${values.status},
|
|
168
|
+
${values.waitingFor}, ${values.processingId},
|
|
169
|
+
${values.callbackStartedAt}, ${values.expiresAt}, ${values.authorizationId},
|
|
170
|
+
${values.cleanupAuthorizationId},
|
|
171
|
+
${values.connections ? jsonParameter(this.sql, values.connections) : null},
|
|
172
|
+
${values.error ? jsonParameter(this.sql, values.error) : null},
|
|
173
|
+
${record.createdAt}, ${record.updatedAt}, ${values.finishedAt}
|
|
174
|
+
)
|
|
175
|
+
`
|
|
176
|
+
return true
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (isUniqueViolation(error)) return false
|
|
179
|
+
throw error
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async getConnectionRun(id: string): Promise<ConnectorConnectionRunRecord | null> {
|
|
184
|
+
const rows = await this.runById(id)
|
|
185
|
+
return rows[0] ? connectionRunFromRow(rows[0]) : null
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async updateConnectionRun(record: ConnectorConnectionRunRecord): Promise<void> {
|
|
189
|
+
const values = runValues(record)
|
|
190
|
+
const rows = await this.sql<{ readonly id: string }[]>`
|
|
191
|
+
UPDATE connector_connection_runs
|
|
192
|
+
SET kind = ${values.kind}, slot = ${values.slot},
|
|
193
|
+
initiated_by_execution_id = ${values.initiatedByExecutionId}, status = ${values.status},
|
|
194
|
+
waiting_for = ${values.waitingFor},
|
|
195
|
+
processing_id = ${values.processingId}, callback_started_at = ${values.callbackStartedAt},
|
|
196
|
+
expires_at = ${values.expiresAt}, authorization_id = ${values.authorizationId},
|
|
197
|
+
cleanup_authorization_id = ${values.cleanupAuthorizationId},
|
|
198
|
+
connections = ${values.connections ? jsonParameter(this.sql, values.connections) : null},
|
|
199
|
+
error = ${values.error ? jsonParameter(this.sql, values.error) : null},
|
|
200
|
+
updated_at = ${record.updatedAt}, finished_at = ${values.finishedAt}
|
|
201
|
+
WHERE project_id = ${record.projectId} AND connector_id = ${record.connectorId}
|
|
202
|
+
AND id = ${record.id}
|
|
203
|
+
RETURNING id
|
|
204
|
+
`
|
|
205
|
+
assertChanged(rows, "connector connection run", record.id)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async insertAuthorization(record: ConnectorAuthorizationRecord): Promise<boolean> {
|
|
209
|
+
try {
|
|
210
|
+
const values = authorizationValues(record)
|
|
211
|
+
await this.sql`
|
|
212
|
+
INSERT INTO connector_authorizations (
|
|
213
|
+
project_id, connector_id, id, authorized_by, credentials, credential_expires_at,
|
|
214
|
+
scopes, accounts, status, selection_expires_at, revision, mutation_id, mutation_kind,
|
|
215
|
+
mutation_phase, mutation_holder_id, mutation_expires_at, mutation_deadline_at,
|
|
216
|
+
mutation_expected_connection_ids, staged_credentials, staged_credential_expires_at,
|
|
217
|
+
staged_scopes, created_at, updated_at
|
|
218
|
+
) VALUES (
|
|
219
|
+
${record.projectId}, ${record.connectorId}, ${record.id},
|
|
220
|
+
${jsonParameter(this.sql, record.authorizedBy)},
|
|
221
|
+
${record.credentials ? jsonParameter(this.sql, record.credentials) : null},
|
|
222
|
+
${record.credentialExpiresAt ?? null}, ${jsonParameter(this.sql, record.scopes)},
|
|
223
|
+
${jsonParameter(this.sql, record.accounts)}, ${record.status},
|
|
224
|
+
${record.selectionExpiresAt ?? null}, ${record.revision}, ${values.mutationId},
|
|
225
|
+
${values.mutationKind}, ${values.mutationPhase}, ${values.mutationHolderId},
|
|
226
|
+
${values.mutationExpiresAt}, ${values.mutationDeadlineAt},
|
|
227
|
+
${
|
|
228
|
+
values.mutationExpectedConnectionIds
|
|
229
|
+
? jsonParameter(this.sql, values.mutationExpectedConnectionIds)
|
|
230
|
+
: null
|
|
231
|
+
},
|
|
232
|
+
${values.stagedCredentials ? jsonParameter(this.sql, values.stagedCredentials) : null},
|
|
233
|
+
${values.stagedCredentialExpiresAt},
|
|
234
|
+
${values.stagedScopes ? jsonParameter(this.sql, values.stagedScopes) : null},
|
|
235
|
+
${record.createdAt}, ${record.updatedAt}
|
|
236
|
+
)
|
|
237
|
+
`
|
|
238
|
+
return true
|
|
239
|
+
} catch (error) {
|
|
240
|
+
if (isUniqueViolation(error)) return false
|
|
241
|
+
throw error
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async getAuthorization(id: string): Promise<ConnectorAuthorizationRecord | null> {
|
|
246
|
+
const rows = await this.authorizationById(id)
|
|
247
|
+
return rows[0] ? authorizationFromRow(rows[0]) : null
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async updateAuthorization(record: ConnectorAuthorizationRecord): Promise<void> {
|
|
251
|
+
const values = authorizationValues(record)
|
|
252
|
+
const rows = await this.sql<{ readonly id: string }[]>`
|
|
253
|
+
UPDATE connector_authorizations
|
|
254
|
+
SET authorized_by = ${jsonParameter(this.sql, record.authorizedBy)},
|
|
255
|
+
credentials = ${record.credentials ? jsonParameter(this.sql, record.credentials) : null},
|
|
256
|
+
credential_expires_at = ${record.credentialExpiresAt ?? null},
|
|
257
|
+
scopes = ${jsonParameter(this.sql, record.scopes)},
|
|
258
|
+
accounts = ${jsonParameter(this.sql, record.accounts)}, status = ${record.status},
|
|
259
|
+
selection_expires_at = ${record.selectionExpiresAt ?? null}, revision = ${record.revision},
|
|
260
|
+
mutation_id = ${values.mutationId}, mutation_kind = ${values.mutationKind},
|
|
261
|
+
mutation_phase = ${values.mutationPhase}, mutation_holder_id = ${values.mutationHolderId},
|
|
262
|
+
mutation_expires_at = ${values.mutationExpiresAt},
|
|
263
|
+
mutation_deadline_at = ${values.mutationDeadlineAt},
|
|
264
|
+
mutation_expected_connection_ids = ${
|
|
265
|
+
values.mutationExpectedConnectionIds
|
|
266
|
+
? jsonParameter(this.sql, values.mutationExpectedConnectionIds)
|
|
267
|
+
: null
|
|
268
|
+
},
|
|
269
|
+
staged_credentials = ${
|
|
270
|
+
values.stagedCredentials ? jsonParameter(this.sql, values.stagedCredentials) : null
|
|
271
|
+
},
|
|
272
|
+
staged_credential_expires_at = ${values.stagedCredentialExpiresAt},
|
|
273
|
+
staged_scopes = ${
|
|
274
|
+
values.stagedScopes ? jsonParameter(this.sql, values.stagedScopes) : null
|
|
275
|
+
},
|
|
276
|
+
updated_at = ${record.updatedAt}
|
|
277
|
+
WHERE project_id = ${record.projectId} AND connector_id = ${record.connectorId}
|
|
278
|
+
AND id = ${record.id}
|
|
279
|
+
RETURNING id
|
|
280
|
+
`
|
|
281
|
+
assertChanged(rows, "connector authorization", record.id)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async insertConnection(record: ConnectorConnectionRecord): Promise<boolean> {
|
|
285
|
+
try {
|
|
286
|
+
await this.sql`
|
|
287
|
+
INSERT INTO connector_connections (
|
|
288
|
+
project_id, connector_id, id, authorization_id, slot, account,
|
|
289
|
+
account_id, status, disconnected_at, created_at, updated_at
|
|
290
|
+
) VALUES (
|
|
291
|
+
${record.projectId}, ${record.connectorId}, ${record.id}, ${record.authorizationId},
|
|
292
|
+
${record.slot}, ${jsonParameter(this.sql, record.account)},
|
|
293
|
+
${record.account.id}, ${record.status}, ${record.disconnectedAt ?? null},
|
|
294
|
+
${record.createdAt}, ${record.updatedAt}
|
|
295
|
+
)
|
|
296
|
+
`
|
|
297
|
+
return true
|
|
298
|
+
} catch (error) {
|
|
299
|
+
if (isUniqueViolation(error)) return false
|
|
300
|
+
throw error
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async getConnectionById(id: string): Promise<ConnectorConnectionRecord | null> {
|
|
305
|
+
const rows = await this.connectionById(id)
|
|
306
|
+
return rows[0] ? connectionFromRow(rows[0]) : null
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async getConnectionBySelector(input: {
|
|
310
|
+
readonly owner: { readonly type: "project" }
|
|
311
|
+
readonly slot: string
|
|
312
|
+
}): Promise<ConnectorConnectionRecord | null> {
|
|
313
|
+
if (!this.scope.connectorId) return null
|
|
314
|
+
const rows = await this.sql<PgConnectionRow[]>`
|
|
315
|
+
SELECT * FROM connector_connections
|
|
316
|
+
WHERE project_id = ${this.scope.projectId} AND connector_id = ${this.scope.connectorId}
|
|
317
|
+
AND slot = ${input.slot}
|
|
318
|
+
${this.lockClause()}
|
|
319
|
+
`
|
|
320
|
+
return rows[0] ? connectionFromRow(rows[0]) : null
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async listConnections(): Promise<readonly ConnectorConnectionRecord[]> {
|
|
324
|
+
if (!this.scope.connectorId) return []
|
|
325
|
+
const rows = await this.sql<PgConnectionRow[]>`
|
|
326
|
+
SELECT * FROM connector_connections
|
|
327
|
+
WHERE project_id = ${this.scope.projectId} AND connector_id = ${this.scope.connectorId}
|
|
328
|
+
ORDER BY id
|
|
329
|
+
${this.lockClause()}
|
|
330
|
+
`
|
|
331
|
+
return rows.map(connectionFromRow)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async listConnectionsByAuthorization(
|
|
335
|
+
authorizationId: string,
|
|
336
|
+
options: { readonly connectedOnly?: boolean } = {}
|
|
337
|
+
): Promise<readonly ConnectorConnectionRecord[]> {
|
|
338
|
+
if (!this.scope.connectorId) return []
|
|
339
|
+
const rows = options.connectedOnly
|
|
340
|
+
? await this.sql<PgConnectionRow[]>`
|
|
341
|
+
SELECT * FROM connector_connections
|
|
342
|
+
WHERE project_id = ${this.scope.projectId} AND connector_id = ${this.scope.connectorId}
|
|
343
|
+
AND authorization_id = ${authorizationId} AND status = 'connected'
|
|
344
|
+
ORDER BY id
|
|
345
|
+
${this.lockClause()}
|
|
346
|
+
`
|
|
347
|
+
: await this.sql<PgConnectionRow[]>`
|
|
348
|
+
SELECT * FROM connector_connections
|
|
349
|
+
WHERE project_id = ${this.scope.projectId} AND connector_id = ${this.scope.connectorId}
|
|
350
|
+
AND authorization_id = ${authorizationId}
|
|
351
|
+
ORDER BY id
|
|
352
|
+
${this.lockClause()}
|
|
353
|
+
`
|
|
354
|
+
return rows.map(connectionFromRow)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
async updateConnection(record: ConnectorConnectionRecord): Promise<void> {
|
|
358
|
+
const rows = await this.sql<{ readonly id: string }[]>`
|
|
359
|
+
UPDATE connector_connections
|
|
360
|
+
SET authorization_id = ${record.authorizationId}, slot = ${record.slot},
|
|
361
|
+
account = ${jsonParameter(this.sql, record.account)},
|
|
362
|
+
account_id = ${record.account.id}, status = ${record.status},
|
|
363
|
+
disconnected_at = ${record.disconnectedAt ?? null}, updated_at = ${record.updatedAt}
|
|
364
|
+
WHERE project_id = ${record.projectId} AND connector_id = ${record.connectorId}
|
|
365
|
+
AND id = ${record.id}
|
|
366
|
+
RETURNING id
|
|
367
|
+
`
|
|
368
|
+
assertChanged(rows, "connector connection", record.id)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private runById(id: string): Promise<PgConnectionRunRow[]> {
|
|
372
|
+
return this.scope.connectorId
|
|
373
|
+
? this.sql<PgConnectionRunRow[]>`
|
|
374
|
+
SELECT * FROM connector_connection_runs
|
|
375
|
+
WHERE project_id = ${this.scope.projectId}
|
|
376
|
+
AND connector_id = ${this.scope.connectorId} AND id = ${id}
|
|
377
|
+
${this.lockClause()}
|
|
378
|
+
`
|
|
379
|
+
: this.sql<PgConnectionRunRow[]>`
|
|
380
|
+
SELECT * FROM connector_connection_runs
|
|
381
|
+
WHERE project_id = ${this.scope.projectId} AND id = ${id}
|
|
382
|
+
${this.lockClause()}
|
|
383
|
+
`
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private authorizationById(id: string): Promise<PgAuthorizationRow[]> {
|
|
387
|
+
return this.scope.connectorId
|
|
388
|
+
? this.sql<PgAuthorizationRow[]>`
|
|
389
|
+
SELECT * FROM connector_authorizations
|
|
390
|
+
WHERE project_id = ${this.scope.projectId}
|
|
391
|
+
AND connector_id = ${this.scope.connectorId} AND id = ${id}
|
|
392
|
+
${this.lockClause()}
|
|
393
|
+
`
|
|
394
|
+
: this.sql<PgAuthorizationRow[]>`
|
|
395
|
+
SELECT * FROM connector_authorizations
|
|
396
|
+
WHERE project_id = ${this.scope.projectId} AND id = ${id}
|
|
397
|
+
${this.lockClause()}
|
|
398
|
+
`
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private connectionById(id: string): Promise<PgConnectionRow[]> {
|
|
402
|
+
return this.scope.connectorId
|
|
403
|
+
? this.sql<PgConnectionRow[]>`
|
|
404
|
+
SELECT * FROM connector_connections
|
|
405
|
+
WHERE project_id = ${this.scope.projectId}
|
|
406
|
+
AND connector_id = ${this.scope.connectorId} AND id = ${id}
|
|
407
|
+
${this.lockClause()}
|
|
408
|
+
`
|
|
409
|
+
: this.sql<PgConnectionRow[]>`
|
|
410
|
+
SELECT * FROM connector_connections
|
|
411
|
+
WHERE project_id = ${this.scope.projectId} AND id = ${id}
|
|
412
|
+
${this.lockClause()}
|
|
413
|
+
`
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
private lockClause() {
|
|
417
|
+
return this.locking ? this.sql`FOR UPDATE` : this.sql``
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function authorizationAttemptFromRow(
|
|
422
|
+
row: PgAuthorizationAttemptRow
|
|
423
|
+
): ConnectorAuthorizationAttemptRecord {
|
|
424
|
+
return {
|
|
425
|
+
id: row.id,
|
|
426
|
+
projectId: row.project_id,
|
|
427
|
+
connectorId: row.connector_id,
|
|
428
|
+
owner: { type: "project" },
|
|
429
|
+
slot: row.slot,
|
|
430
|
+
initiatedByExecutionId: row.initiated_by_execution_id,
|
|
431
|
+
stateHash: row.state_hash,
|
|
432
|
+
codeVerifier: row.code_verifier,
|
|
433
|
+
redirectUri: row.redirect_uri,
|
|
434
|
+
...(row.connection_run_id === null ? {} : { connectionRunId: row.connection_run_id }),
|
|
435
|
+
...(row.return_to === null ? {} : { returnTo: row.return_to }),
|
|
436
|
+
...(row.callback_binding_hash === null
|
|
437
|
+
? {}
|
|
438
|
+
: { callbackBindingHash: row.callback_binding_hash }),
|
|
439
|
+
...(row.reauthorization_id === null ? {} : { reauthorizationId: row.reauthorization_id }),
|
|
440
|
+
...(row.reauthorization_revision === null
|
|
441
|
+
? {}
|
|
442
|
+
: { reauthorizationRevision: row.reauthorization_revision }),
|
|
443
|
+
...(row.reauthorization_connection_ids === null
|
|
444
|
+
? {}
|
|
445
|
+
: { reauthorizationConnectionIds: row.reauthorization_connection_ids }),
|
|
446
|
+
createdAt: date(row.created_at),
|
|
447
|
+
expiresAt: date(row.expires_at),
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function runValues(record: ConnectorConnectionRunRecord) {
|
|
452
|
+
return {
|
|
453
|
+
kind: record.kind,
|
|
454
|
+
slot: record.slot,
|
|
455
|
+
initiatedByExecutionId: record.initiatedByExecutionId,
|
|
456
|
+
status: record.status,
|
|
457
|
+
waitingFor: record.status === "waiting" ? record.waitingFor : null,
|
|
458
|
+
processingId: record.status === "running" ? record.processingId : null,
|
|
459
|
+
callbackStartedAt: record.status === "running" ? record.callbackStartedAt : null,
|
|
460
|
+
expiresAt: record.status === "waiting" || record.status === "running" ? record.expiresAt : null,
|
|
461
|
+
authorizationId: "authorizationId" in record ? (record.authorizationId ?? null) : null,
|
|
462
|
+
cleanupAuthorizationId:
|
|
463
|
+
record.status === "succeeded" ? (record.cleanupAuthorizationId ?? null) : null,
|
|
464
|
+
connections: record.status === "succeeded" ? record.connections : null,
|
|
465
|
+
error: record.status === "failed" ? record.error : null,
|
|
466
|
+
finishedAt:
|
|
467
|
+
record.status === "succeeded" ||
|
|
468
|
+
record.status === "failed" ||
|
|
469
|
+
record.status === "cancelled" ||
|
|
470
|
+
record.status === "expired"
|
|
471
|
+
? record.finishedAt
|
|
472
|
+
: null,
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function connectionRunFromRow(row: PgConnectionRunRow): ConnectorConnectionRunRecord {
|
|
477
|
+
const base = {
|
|
478
|
+
id: row.id,
|
|
479
|
+
projectId: row.project_id,
|
|
480
|
+
connectorId: row.connector_id,
|
|
481
|
+
kind: row.kind,
|
|
482
|
+
owner: { type: "project" as const },
|
|
483
|
+
slot: row.slot,
|
|
484
|
+
initiatedByExecutionId: row.initiated_by_execution_id,
|
|
485
|
+
createdAt: date(row.created_at),
|
|
486
|
+
updatedAt: date(row.updated_at),
|
|
487
|
+
}
|
|
488
|
+
if (row.status === "waiting" && row.waiting_for === "provider_authorization") {
|
|
489
|
+
return {
|
|
490
|
+
...base,
|
|
491
|
+
status: "waiting",
|
|
492
|
+
waitingFor: "provider_authorization",
|
|
493
|
+
expiresAt: date(required(row.expires_at, "run expiry")),
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (row.status === "waiting" && row.waiting_for === "account_selection") {
|
|
497
|
+
return {
|
|
498
|
+
...base,
|
|
499
|
+
status: "waiting",
|
|
500
|
+
waitingFor: "account_selection",
|
|
501
|
+
authorizationId: required(row.authorization_id, "authorization id"),
|
|
502
|
+
expiresAt: date(required(row.expires_at, "run expiry")),
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
if (row.status === "running") {
|
|
506
|
+
return {
|
|
507
|
+
...base,
|
|
508
|
+
status: "running",
|
|
509
|
+
processingId: required(row.processing_id, "processing id"),
|
|
510
|
+
callbackStartedAt: date(required(row.callback_started_at, "callback start")),
|
|
511
|
+
expiresAt: date(required(row.expires_at, "run expiry")),
|
|
512
|
+
...(row.authorization_id === null ? {} : { authorizationId: row.authorization_id }),
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
const finishedAt = date(required(row.finished_at, "run finish"))
|
|
516
|
+
if (row.status === "succeeded") {
|
|
517
|
+
return {
|
|
518
|
+
...base,
|
|
519
|
+
status: "succeeded",
|
|
520
|
+
authorizationId: required(row.authorization_id, "authorization id"),
|
|
521
|
+
...(row.cleanup_authorization_id === null
|
|
522
|
+
? {}
|
|
523
|
+
: { cleanupAuthorizationId: row.cleanup_authorization_id }),
|
|
524
|
+
connections: required(row.connections, "connections").map(connectionFromSerialized),
|
|
525
|
+
finishedAt,
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
if (row.status === "failed") {
|
|
529
|
+
return {
|
|
530
|
+
...base,
|
|
531
|
+
status: "failed",
|
|
532
|
+
error: required(row.error, "run error"),
|
|
533
|
+
...(row.authorization_id === null ? {} : { authorizationId: row.authorization_id }),
|
|
534
|
+
finishedAt,
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (row.status === "cancelled") {
|
|
538
|
+
return {
|
|
539
|
+
...base,
|
|
540
|
+
status: "cancelled",
|
|
541
|
+
...(row.authorization_id === null ? {} : { authorizationId: row.authorization_id }),
|
|
542
|
+
finishedAt,
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
if (row.status === "expired") {
|
|
546
|
+
return {
|
|
547
|
+
...base,
|
|
548
|
+
status: "expired",
|
|
549
|
+
...(row.authorization_id === null ? {} : { authorizationId: row.authorization_id }),
|
|
550
|
+
finishedAt,
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
throw new Error(`[SixbPg] Stored connector connection run status '${row.status}' is invalid.`)
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function authorizationValues(record: ConnectorAuthorizationRecord) {
|
|
557
|
+
const mutation = record.credentialMutation
|
|
558
|
+
return {
|
|
559
|
+
mutationId: mutation?.id ?? null,
|
|
560
|
+
mutationKind: mutation?.kind ?? null,
|
|
561
|
+
mutationPhase: mutation?.phase ?? null,
|
|
562
|
+
mutationHolderId: mutation?.holderId ?? null,
|
|
563
|
+
mutationExpiresAt: mutation?.expiresAt ?? null,
|
|
564
|
+
mutationDeadlineAt: mutation?.deadlineAt ?? null,
|
|
565
|
+
mutationExpectedConnectionIds: mutation?.expectedConnectionIds ?? null,
|
|
566
|
+
stagedCredentials: mutation?.stagedCredentials?.credentials ?? null,
|
|
567
|
+
stagedCredentialExpiresAt: mutation?.stagedCredentials?.credentialExpiresAt ?? null,
|
|
568
|
+
stagedScopes: mutation?.stagedCredentials?.scopes ?? null,
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function authorizationFromRow(row: PgAuthorizationRow): ConnectorAuthorizationRecord {
|
|
573
|
+
const mutation = mutationFromRow(row)
|
|
574
|
+
return {
|
|
575
|
+
id: row.id,
|
|
576
|
+
projectId: row.project_id,
|
|
577
|
+
connectorId: row.connector_id,
|
|
578
|
+
authorizedBy: row.authorized_by,
|
|
579
|
+
...(row.credentials === null ? {} : { credentials: row.credentials }),
|
|
580
|
+
...(row.credential_expires_at === null
|
|
581
|
+
? {}
|
|
582
|
+
: { credentialExpiresAt: date(row.credential_expires_at) }),
|
|
583
|
+
scopes: row.scopes,
|
|
584
|
+
accounts: row.accounts,
|
|
585
|
+
status: row.status,
|
|
586
|
+
...(row.selection_expires_at === null
|
|
587
|
+
? {}
|
|
588
|
+
: { selectionExpiresAt: date(row.selection_expires_at) }),
|
|
589
|
+
revision: row.revision,
|
|
590
|
+
...(mutation === undefined ? {} : { credentialMutation: mutation }),
|
|
591
|
+
createdAt: date(row.created_at),
|
|
592
|
+
updatedAt: date(row.updated_at),
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function mutationFromRow(row: PgAuthorizationRow): ConnectorCredentialMutation | undefined {
|
|
597
|
+
if (row.mutation_id === null) return undefined
|
|
598
|
+
const stagedCredentials: ConnectorStagedCredentials | undefined =
|
|
599
|
+
row.staged_credentials === null
|
|
600
|
+
? undefined
|
|
601
|
+
: {
|
|
602
|
+
credentials: row.staged_credentials,
|
|
603
|
+
...(row.staged_credential_expires_at === null
|
|
604
|
+
? {}
|
|
605
|
+
: { credentialExpiresAt: date(row.staged_credential_expires_at) }),
|
|
606
|
+
scopes: required(row.staged_scopes, "staged credential scopes"),
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
id: row.mutation_id,
|
|
610
|
+
kind: required(row.mutation_kind, "credential mutation kind"),
|
|
611
|
+
phase: required(row.mutation_phase, "credential mutation phase"),
|
|
612
|
+
holderId: required(row.mutation_holder_id, "credential mutation holder"),
|
|
613
|
+
expiresAt: date(required(row.mutation_expires_at, "credential mutation expiry")),
|
|
614
|
+
deadlineAt: date(required(row.mutation_deadline_at, "credential mutation deadline")),
|
|
615
|
+
...(row.mutation_expected_connection_ids === null
|
|
616
|
+
? {}
|
|
617
|
+
: { expectedConnectionIds: row.mutation_expected_connection_ids }),
|
|
618
|
+
...(stagedCredentials === undefined ? {} : { stagedCredentials }),
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function connectionFromRow(row: PgConnectionRow): ConnectorConnectionRecord {
|
|
623
|
+
return {
|
|
624
|
+
id: row.id,
|
|
625
|
+
projectId: row.project_id,
|
|
626
|
+
connectorId: row.connector_id,
|
|
627
|
+
authorizationId: row.authorization_id,
|
|
628
|
+
owner: { type: "project" },
|
|
629
|
+
slot: row.slot,
|
|
630
|
+
account: row.account,
|
|
631
|
+
status: row.status,
|
|
632
|
+
...(row.disconnected_at === null ? {} : { disconnectedAt: date(row.disconnected_at) }),
|
|
633
|
+
createdAt: date(row.created_at),
|
|
634
|
+
updatedAt: date(row.updated_at),
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
type SerializedConnectorConnection = Omit<
|
|
639
|
+
ConnectorConnectionRecord,
|
|
640
|
+
"createdAt" | "updatedAt" | "disconnectedAt"
|
|
641
|
+
> & {
|
|
642
|
+
readonly createdAt: string
|
|
643
|
+
readonly updatedAt: string
|
|
644
|
+
readonly disconnectedAt?: string
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function connectionFromSerialized(
|
|
648
|
+
record: SerializedConnectorConnection
|
|
649
|
+
): ConnectorConnectionRecord {
|
|
650
|
+
const { createdAt, updatedAt, disconnectedAt, ...connection } = record
|
|
651
|
+
return {
|
|
652
|
+
...connection,
|
|
653
|
+
createdAt: new Date(createdAt),
|
|
654
|
+
updatedAt: new Date(updatedAt),
|
|
655
|
+
...(disconnectedAt === undefined ? {} : { disconnectedAt: new Date(disconnectedAt) }),
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
type PgJsonValue = Parameters<SQLClient["json"]>[0]
|
|
660
|
+
|
|
661
|
+
function jsonParameter(sql: PgStoreClient, value: unknown): ReturnType<PgStoreClient["json"]> {
|
|
662
|
+
return sql.json(value as PgJsonValue)
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function date(value: Date | string): Date {
|
|
666
|
+
return new Date(value)
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function required<T>(value: T | null, label: string): T {
|
|
670
|
+
if (value !== null) return value
|
|
671
|
+
throw new Error(`[SixbPg] Stored ${label} is missing.`)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function assertChanged(rows: readonly unknown[], label: string, id: string): void {
|
|
675
|
+
if (rows.length === 1) return
|
|
676
|
+
throw new Error(`[SixbPg] Stored ${label} '${id}' is unavailable.`)
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
interface ConnectorConnectionTestClock {
|
|
680
|
+
offsetMs: number
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
interface PgAuthorizationAttemptRow {
|
|
684
|
+
readonly project_id: string
|
|
685
|
+
readonly connector_id: string
|
|
686
|
+
readonly id: string
|
|
687
|
+
readonly slot: string
|
|
688
|
+
readonly initiated_by_execution_id: string
|
|
689
|
+
readonly state_hash: string
|
|
690
|
+
readonly code_verifier: ConnectorAuthorizationAttemptRecord["codeVerifier"]
|
|
691
|
+
readonly redirect_uri: string
|
|
692
|
+
readonly connection_run_id: string | null
|
|
693
|
+
readonly return_to: string | null
|
|
694
|
+
readonly callback_binding_hash: string | null
|
|
695
|
+
readonly reauthorization_id: string | null
|
|
696
|
+
readonly reauthorization_revision: number | null
|
|
697
|
+
readonly reauthorization_connection_ids: readonly string[] | null
|
|
698
|
+
readonly created_at: Date | string
|
|
699
|
+
readonly expires_at: Date | string
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
interface PgConnectionRunRow {
|
|
703
|
+
readonly project_id: string
|
|
704
|
+
readonly connector_id: string
|
|
705
|
+
readonly id: string
|
|
706
|
+
readonly kind: ConnectorConnectionRunRecord["kind"]
|
|
707
|
+
readonly slot: string
|
|
708
|
+
readonly initiated_by_execution_id: string
|
|
709
|
+
readonly status: ConnectorConnectionRunRecord["status"]
|
|
710
|
+
readonly waiting_for: "provider_authorization" | "account_selection" | null
|
|
711
|
+
readonly processing_id: string | null
|
|
712
|
+
readonly callback_started_at: Date | string | null
|
|
713
|
+
readonly expires_at: Date | string | null
|
|
714
|
+
readonly authorization_id: string | null
|
|
715
|
+
readonly cleanup_authorization_id: string | null
|
|
716
|
+
readonly connections: readonly SerializedConnectorConnection[] | null
|
|
717
|
+
readonly error: Extract<ConnectorConnectionRunRecord, { status: "failed" }>["error"] | null
|
|
718
|
+
readonly created_at: Date | string
|
|
719
|
+
readonly updated_at: Date | string
|
|
720
|
+
readonly finished_at: Date | string | null
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
interface PgAuthorizationRow {
|
|
724
|
+
readonly project_id: string
|
|
725
|
+
readonly connector_id: string
|
|
726
|
+
readonly id: string
|
|
727
|
+
readonly authorized_by: ConnectorAuthorizationRecord["authorizedBy"]
|
|
728
|
+
readonly credentials: ConnectorAuthorizationRecord["credentials"] | null
|
|
729
|
+
readonly credential_expires_at: Date | string | null
|
|
730
|
+
readonly scopes: readonly string[]
|
|
731
|
+
readonly accounts: ConnectorAuthorizationRecord["accounts"]
|
|
732
|
+
readonly status: ConnectorAuthorizationRecord["status"]
|
|
733
|
+
readonly selection_expires_at: Date | string | null
|
|
734
|
+
readonly revision: number
|
|
735
|
+
readonly mutation_id: string | null
|
|
736
|
+
readonly mutation_kind: ConnectorCredentialMutation["kind"] | null
|
|
737
|
+
readonly mutation_phase: ConnectorCredentialMutation["phase"] | null
|
|
738
|
+
readonly mutation_holder_id: string | null
|
|
739
|
+
readonly mutation_expires_at: Date | string | null
|
|
740
|
+
readonly mutation_deadline_at: Date | string | null
|
|
741
|
+
readonly mutation_expected_connection_ids: readonly string[] | null
|
|
742
|
+
readonly staged_credentials: ConnectorStagedCredentials["credentials"] | null
|
|
743
|
+
readonly staged_credential_expires_at: Date | string | null
|
|
744
|
+
readonly staged_scopes: readonly string[] | null
|
|
745
|
+
readonly created_at: Date | string
|
|
746
|
+
readonly updated_at: Date | string
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
interface PgConnectionRow {
|
|
750
|
+
readonly project_id: string
|
|
751
|
+
readonly connector_id: string
|
|
752
|
+
readonly id: string
|
|
753
|
+
readonly authorization_id: string
|
|
754
|
+
readonly slot: string
|
|
755
|
+
readonly account: ConnectorConnectionRecord["account"]
|
|
756
|
+
readonly status: ConnectorConnectionRecord["status"]
|
|
757
|
+
readonly disconnected_at: Date | string | null
|
|
758
|
+
readonly created_at: Date | string
|
|
759
|
+
readonly updated_at: Date | string
|
|
760
|
+
}
|