@sixb/pg 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/agents/agent-storage.d.ts +20 -0
- package/dist/agents/agent-storage.d.ts.map +1 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/messages.d.ts +13 -0
- package/dist/agents/messages.d.ts.map +1 -0
- package/dist/agents/rows.d.ts +77 -0
- package/dist/agents/rows.d.ts.map +1 -0
- package/dist/agents/runs.d.ts +25 -0
- package/dist/agents/runs.d.ts.map +1 -0
- package/dist/agents/threads.d.ts +13 -0
- package/dist/agents/threads.d.ts.map +1 -0
- package/dist/auth-storage/access-tokens.d.ts +33 -0
- package/dist/auth-storage/access-tokens.d.ts.map +1 -0
- package/dist/auth-storage/auth-storage.d.ts +41 -0
- package/dist/auth-storage/auth-storage.d.ts.map +1 -0
- package/dist/auth-storage/group-memberships.d.ts +21 -0
- package/dist/auth-storage/group-memberships.d.ts.map +1 -0
- package/dist/auth-storage/identities.d.ts +17 -0
- package/dist/auth-storage/identities.d.ts.map +1 -0
- package/dist/auth-storage/index.d.ts +3 -0
- package/dist/auth-storage/index.d.ts.map +1 -0
- package/dist/auth-storage/invitations.d.ts +29 -0
- package/dist/auth-storage/invitations.d.ts.map +1 -0
- package/dist/auth-storage/magic-links.d.ts +28 -0
- package/dist/auth-storage/magic-links.d.ts.map +1 -0
- package/dist/auth-storage/oidc-attempts.d.ts +18 -0
- package/dist/auth-storage/oidc-attempts.d.ts.map +1 -0
- package/dist/auth-storage/rows.d.ts +138 -0
- package/dist/auth-storage/rows.d.ts.map +1 -0
- package/dist/auth-storage/service-account-group-memberships.d.ts +17 -0
- package/dist/auth-storage/service-account-group-memberships.d.ts.map +1 -0
- package/dist/auth-storage/service-accounts.d.ts +14 -0
- package/dist/auth-storage/service-accounts.d.ts.map +1 -0
- package/dist/auth-storage/sessions.d.ts +55 -0
- package/dist/auth-storage/sessions.d.ts.map +1 -0
- package/dist/auth-storage/shared.d.ts +159 -0
- package/dist/auth-storage/shared.d.ts.map +1 -0
- package/dist/auth-storage/users.d.ts +19 -0
- package/dist/auth-storage/users.d.ts.map +1 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11957 -0
- package/dist/index.js.map +55 -0
- package/dist/latest-run-query.d.ts +24 -0
- package/dist/latest-run-query.d.ts.map +1 -0
- package/dist/migrations.d.ts +20 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/ontology-storage/commits.d.ts +11 -0
- package/dist/ontology-storage/commits.d.ts.map +1 -0
- package/dist/ontology-storage/index.d.ts +22 -0
- package/dist/ontology-storage/index.d.ts.map +1 -0
- package/dist/ontology-storage/materialization-session.d.ts +63 -0
- package/dist/ontology-storage/materialization-session.d.ts.map +1 -0
- package/dist/ontology-storage/materialization-state.d.ts +69 -0
- package/dist/ontology-storage/materialization-state.d.ts.map +1 -0
- package/dist/ontology-storage/materialization-writer.d.ts +15 -0
- package/dist/ontology-storage/materialization-writer.d.ts.map +1 -0
- package/dist/ontology-storage/materializations.d.ts +33 -0
- package/dist/ontology-storage/materializations.d.ts.map +1 -0
- package/dist/ontology-storage/outbox.d.ts +12 -0
- package/dist/ontology-storage/outbox.d.ts.map +1 -0
- package/dist/ontology-storage/shared.d.ts +95 -0
- package/dist/ontology-storage/shared.d.ts.map +1 -0
- package/dist/ontology-storage/sources.d.ts +25 -0
- package/dist/ontology-storage/sources.d.ts.map +1 -0
- package/dist/pg-action-run-storage.d.ts +21 -0
- package/dist/pg-action-run-storage.d.ts.map +1 -0
- package/dist/pg-client.d.ts +58 -0
- package/dist/pg-client.d.ts.map +1 -0
- package/dist/pg-object-query-compiler.d.ts +55 -0
- package/dist/pg-object-query-compiler.d.ts.map +1 -0
- package/dist/pg-object-storage.d.ts +90 -0
- package/dist/pg-object-storage.d.ts.map +1 -0
- package/dist/pg-pipeline-run-storage.d.ts +18 -0
- package/dist/pg-pipeline-run-storage.d.ts.map +1 -0
- package/dist/pg-projection-run-storage.d.ts +19 -0
- package/dist/pg-projection-run-storage.d.ts.map +1 -0
- package/dist/pg-rules-storage.d.ts +25 -0
- package/dist/pg-rules-storage.d.ts.map +1 -0
- package/dist/pg-sync-run-storage.d.ts +15 -0
- package/dist/pg-sync-run-storage.d.ts.map +1 -0
- package/dist/pg-timeseries-storage.d.ts +32 -0
- package/dist/pg-timeseries-storage.d.ts.map +1 -0
- package/dist/pg-webhook-delivery-storage.d.ts +17 -0
- package/dist/pg-webhook-delivery-storage.d.ts.map +1 -0
- package/dist/pg-webhook-run-storage.d.ts +14 -0
- package/dist/pg-webhook-run-storage.d.ts.map +1 -0
- package/dist/pg-workflow-intervention-storage.d.ts +16 -0
- package/dist/pg-workflow-intervention-storage.d.ts.map +1 -0
- package/dist/pg-workflow-run-storage.d.ts +49 -0
- package/dist/pg-workflow-run-storage.d.ts.map +1 -0
- package/dist/run-list-query.d.ts +30 -0
- package/dist/run-list-query.d.ts.map +1 -0
- package/dist/storage-errors.d.ts +16 -0
- package/dist/storage-errors.d.ts.map +1 -0
- package/dist/transactions.d.ts +10 -0
- package/dist/transactions.d.ts.map +1 -0
- package/dist/tsconfig.json +5 -0
- package/package.json +60 -0
- package/src/agents/agent-storage.ts +26 -0
- package/src/agents/index.ts +5 -0
- package/src/agents/messages.ts +144 -0
- package/src/agents/rows.ts +227 -0
- package/src/agents/runs.ts +330 -0
- package/src/agents/threads.ts +116 -0
- package/src/auth-storage/access-tokens.ts +254 -0
- package/src/auth-storage/auth-storage.ts +798 -0
- package/src/auth-storage/group-memberships.ts +47 -0
- package/src/auth-storage/identities.ts +85 -0
- package/src/auth-storage/index.ts +2 -0
- package/src/auth-storage/invitations.ts +280 -0
- package/src/auth-storage/magic-links.ts +140 -0
- package/src/auth-storage/oidc-attempts.ts +93 -0
- package/src/auth-storage/rows.ts +352 -0
- package/src/auth-storage/service-account-group-memberships.ts +150 -0
- package/src/auth-storage/service-accounts.ts +154 -0
- package/src/auth-storage/sessions.ts +193 -0
- package/src/auth-storage/shared.ts +799 -0
- package/src/auth-storage/users.ts +196 -0
- package/src/index.ts +367 -0
- package/src/latest-run-query.ts +42 -0
- package/src/migrations/001-initial-schema.sql +1195 -0
- package/src/migrations.ts +280 -0
- package/src/ontology-storage/commits.ts +115 -0
- package/src/ontology-storage/index.ts +35 -0
- package/src/ontology-storage/materialization-session.ts +426 -0
- package/src/ontology-storage/materialization-state.ts +1109 -0
- package/src/ontology-storage/materialization-writer.ts +509 -0
- package/src/ontology-storage/materializations.ts +939 -0
- package/src/ontology-storage/outbox.ts +216 -0
- package/src/ontology-storage/shared.ts +293 -0
- package/src/ontology-storage/sources.ts +658 -0
- package/src/pg-action-run-storage.ts +657 -0
- package/src/pg-client.ts +124 -0
- package/src/pg-object-query-compiler.ts +1545 -0
- package/src/pg-object-storage.ts +638 -0
- package/src/pg-pipeline-run-storage.ts +457 -0
- package/src/pg-projection-run-storage.ts +526 -0
- package/src/pg-rules-storage.ts +308 -0
- package/src/pg-sync-run-storage.ts +263 -0
- package/src/pg-timeseries-storage.ts +180 -0
- package/src/pg-webhook-delivery-storage.ts +180 -0
- package/src/pg-webhook-run-storage.ts +185 -0
- package/src/pg-workflow-intervention-storage.ts +339 -0
- package/src/pg-workflow-run-storage.ts +1065 -0
- package/src/run-list-query.ts +108 -0
- package/src/sql.d.ts +4 -0
- package/src/storage-errors.ts +72 -0
- package/src/transactions.ts +58 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import type { Principal } from "@sixb/core"
|
|
2
|
+
import type {
|
|
3
|
+
AccessTokenRecord,
|
|
4
|
+
GroupMembershipRecord,
|
|
5
|
+
GroupMembershipSource,
|
|
6
|
+
InvitationRecord,
|
|
7
|
+
InvitationStatus,
|
|
8
|
+
MagicLinkRecord,
|
|
9
|
+
OidcAuthorizationAttemptRecord,
|
|
10
|
+
ServiceAccountGroupMembershipRecord,
|
|
11
|
+
ServiceAccountRecord,
|
|
12
|
+
ServiceAccountStatus,
|
|
13
|
+
SessionRecord,
|
|
14
|
+
UserIdentityRecord,
|
|
15
|
+
UserRecord,
|
|
16
|
+
UserStatus,
|
|
17
|
+
} from "@sixb/core/storage"
|
|
18
|
+
|
|
19
|
+
type PgDate = Date | string
|
|
20
|
+
|
|
21
|
+
export interface PgAuthUserRow {
|
|
22
|
+
readonly project_id: string
|
|
23
|
+
readonly id: string
|
|
24
|
+
readonly email: string
|
|
25
|
+
readonly display_name: string | null
|
|
26
|
+
readonly avatar_url: string | null
|
|
27
|
+
readonly status: UserStatus
|
|
28
|
+
readonly created_at: PgDate
|
|
29
|
+
readonly updated_at: PgDate
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PgAuthUserIdentityRow {
|
|
33
|
+
readonly project_id: string
|
|
34
|
+
readonly strategy_id: string
|
|
35
|
+
readonly subject: string
|
|
36
|
+
readonly user_id: string
|
|
37
|
+
readonly claims: Readonly<Record<string, unknown>> | string | null
|
|
38
|
+
readonly created_at: PgDate
|
|
39
|
+
readonly updated_at: PgDate
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface PgAuthServiceAccountRow {
|
|
43
|
+
readonly project_id: string
|
|
44
|
+
readonly id: string
|
|
45
|
+
readonly name: string
|
|
46
|
+
readonly description: string | null
|
|
47
|
+
readonly status: ServiceAccountStatus
|
|
48
|
+
readonly created_by_user_id: string | null
|
|
49
|
+
readonly created_by_service_account_id: string | null
|
|
50
|
+
readonly created_by_system_id: string | null
|
|
51
|
+
readonly created_by_session_id: string | null
|
|
52
|
+
readonly created_at: PgDate
|
|
53
|
+
readonly updated_at: PgDate
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface PgAuthServiceAccountGroupMembershipRow {
|
|
57
|
+
readonly project_id: string
|
|
58
|
+
readonly service_account_id: string
|
|
59
|
+
readonly group_id: string
|
|
60
|
+
readonly source: GroupMembershipSource
|
|
61
|
+
readonly created_at: PgDate
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface PgAuthSessionRow {
|
|
65
|
+
readonly project_id: string
|
|
66
|
+
readonly id: string
|
|
67
|
+
readonly user_id: string
|
|
68
|
+
readonly strategy_id: string
|
|
69
|
+
readonly audience: SessionRecord["audience"]
|
|
70
|
+
readonly token_hash: string
|
|
71
|
+
readonly created_at: PgDate
|
|
72
|
+
readonly expires_at: PgDate
|
|
73
|
+
readonly absolute_expires_at: PgDate | null
|
|
74
|
+
readonly revoked_at: PgDate | null
|
|
75
|
+
readonly last_seen_at: PgDate | null
|
|
76
|
+
readonly user_agent: string | null
|
|
77
|
+
readonly ip_address: string | null
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface PgAuthAccessTokenRow {
|
|
81
|
+
readonly project_id: string
|
|
82
|
+
readonly id: string
|
|
83
|
+
readonly name: string
|
|
84
|
+
readonly kind: AccessTokenRecord["kind"]
|
|
85
|
+
readonly subject_type: AccessTokenRecord["subjectType"]
|
|
86
|
+
readonly subject_id: string
|
|
87
|
+
readonly token_hash: string
|
|
88
|
+
readonly group_ids: readonly string[] | string | null
|
|
89
|
+
readonly created_by_user_id: string | null
|
|
90
|
+
readonly created_by_service_account_id: string | null
|
|
91
|
+
readonly created_by_system_id: string | null
|
|
92
|
+
readonly created_by_session_id: string | null
|
|
93
|
+
readonly created_at: PgDate
|
|
94
|
+
readonly expires_at: PgDate
|
|
95
|
+
readonly revoked_at: PgDate | null
|
|
96
|
+
readonly last_used_at: PgDate | null
|
|
97
|
+
readonly last_used_user_agent: string | null
|
|
98
|
+
readonly last_used_ip_address: string | null
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface PgAuthInvitationRow {
|
|
102
|
+
readonly project_id: string
|
|
103
|
+
readonly id: string
|
|
104
|
+
readonly email: string
|
|
105
|
+
readonly status: InvitationStatus
|
|
106
|
+
readonly created_by_user_id: string | null
|
|
107
|
+
readonly created_by_service_account_id: string | null
|
|
108
|
+
readonly created_by_system_id: string | null
|
|
109
|
+
readonly created_by_session_id: string | null
|
|
110
|
+
readonly created_at: PgDate
|
|
111
|
+
readonly updated_at: PgDate
|
|
112
|
+
readonly expires_at: PgDate
|
|
113
|
+
readonly accepted_at: PgDate | null
|
|
114
|
+
readonly revoked_at: PgDate | null
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface PgAuthGroupMembershipRow {
|
|
118
|
+
readonly project_id: string
|
|
119
|
+
readonly user_id: string
|
|
120
|
+
readonly group_id: string
|
|
121
|
+
readonly source: GroupMembershipSource
|
|
122
|
+
readonly created_at: PgDate
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface PgAuthMagicLinkRow {
|
|
126
|
+
readonly project_id: string
|
|
127
|
+
readonly id: string
|
|
128
|
+
readonly strategy_id: string
|
|
129
|
+
readonly audience: MagicLinkRecord["audience"]
|
|
130
|
+
readonly email: string
|
|
131
|
+
readonly token_hash: string
|
|
132
|
+
readonly return_to: string | null
|
|
133
|
+
readonly created_at: PgDate
|
|
134
|
+
readonly expires_at: PgDate
|
|
135
|
+
readonly consumed_at: PgDate | null
|
|
136
|
+
readonly revoked_at: PgDate | null
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface PgAuthOidcAttemptRow {
|
|
140
|
+
readonly project_id: string
|
|
141
|
+
readonly id: string
|
|
142
|
+
readonly strategy_id: string
|
|
143
|
+
readonly audience: OidcAuthorizationAttemptRecord["audience"]
|
|
144
|
+
readonly state_hash: string
|
|
145
|
+
readonly nonce_hash: string
|
|
146
|
+
readonly code_verifier: string
|
|
147
|
+
readonly return_to: string | null
|
|
148
|
+
readonly created_at: PgDate
|
|
149
|
+
readonly expires_at: PgDate
|
|
150
|
+
readonly consumed_at: PgDate | null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function rowToUserRecord(row: PgAuthUserRow): UserRecord {
|
|
154
|
+
return {
|
|
155
|
+
id: row.id,
|
|
156
|
+
projectId: row.project_id,
|
|
157
|
+
email: row.email,
|
|
158
|
+
displayName: row.display_name ?? undefined,
|
|
159
|
+
avatarUrl: row.avatar_url ?? undefined,
|
|
160
|
+
status: row.status,
|
|
161
|
+
createdAt: toDate(row.created_at),
|
|
162
|
+
updatedAt: toDate(row.updated_at),
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function rowToIdentityRecord(row: PgAuthUserIdentityRow): UserIdentityRecord {
|
|
167
|
+
return {
|
|
168
|
+
projectId: row.project_id,
|
|
169
|
+
strategyId: row.strategy_id,
|
|
170
|
+
subject: row.subject,
|
|
171
|
+
userId: row.user_id,
|
|
172
|
+
claims: parseOptionalRecord(row.claims),
|
|
173
|
+
createdAt: toDate(row.created_at),
|
|
174
|
+
updatedAt: toDate(row.updated_at),
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function rowToServiceAccountRecord(row: PgAuthServiceAccountRow): ServiceAccountRecord {
|
|
179
|
+
return {
|
|
180
|
+
id: row.id,
|
|
181
|
+
projectId: row.project_id,
|
|
182
|
+
name: row.name,
|
|
183
|
+
description: row.description ?? undefined,
|
|
184
|
+
status: row.status,
|
|
185
|
+
createdByPrincipal: principalFromColumns(row),
|
|
186
|
+
createdBySessionId: row.created_by_session_id ?? undefined,
|
|
187
|
+
createdAt: toDate(row.created_at),
|
|
188
|
+
updatedAt: toDate(row.updated_at),
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function rowToServiceAccountGroupMembershipRecord(
|
|
193
|
+
row: PgAuthServiceAccountGroupMembershipRow
|
|
194
|
+
): ServiceAccountGroupMembershipRecord {
|
|
195
|
+
return {
|
|
196
|
+
projectId: row.project_id,
|
|
197
|
+
serviceAccountId: row.service_account_id,
|
|
198
|
+
groupId: row.group_id,
|
|
199
|
+
source: row.source,
|
|
200
|
+
createdAt: toDate(row.created_at),
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function rowToSessionRecord(row: PgAuthSessionRow): SessionRecord {
|
|
205
|
+
return {
|
|
206
|
+
id: row.id,
|
|
207
|
+
projectId: row.project_id,
|
|
208
|
+
userId: row.user_id,
|
|
209
|
+
strategyId: row.strategy_id,
|
|
210
|
+
audience: row.audience,
|
|
211
|
+
tokenHash: row.token_hash,
|
|
212
|
+
createdAt: toDate(row.created_at),
|
|
213
|
+
expiresAt: toDate(row.expires_at),
|
|
214
|
+
absoluteExpiresAt: row.absolute_expires_at ? toDate(row.absolute_expires_at) : undefined,
|
|
215
|
+
revokedAt: row.revoked_at ? toDate(row.revoked_at) : undefined,
|
|
216
|
+
lastSeenAt: row.last_seen_at ? toDate(row.last_seen_at) : undefined,
|
|
217
|
+
userAgent: row.user_agent ?? undefined,
|
|
218
|
+
ipAddress: row.ip_address ?? undefined,
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function rowToAccessTokenRecord(row: PgAuthAccessTokenRow): AccessTokenRecord {
|
|
223
|
+
return {
|
|
224
|
+
id: row.id,
|
|
225
|
+
projectId: row.project_id,
|
|
226
|
+
name: row.name,
|
|
227
|
+
kind: row.kind,
|
|
228
|
+
subjectType: row.subject_type,
|
|
229
|
+
subjectId: row.subject_id,
|
|
230
|
+
tokenHash: row.token_hash,
|
|
231
|
+
groupIds: parseOptionalStringArray(row.group_ids),
|
|
232
|
+
createdByPrincipal: principalFromColumns(row),
|
|
233
|
+
createdBySessionId: row.created_by_session_id ?? undefined,
|
|
234
|
+
createdAt: toDate(row.created_at),
|
|
235
|
+
expiresAt: toDate(row.expires_at),
|
|
236
|
+
revokedAt: row.revoked_at ? toDate(row.revoked_at) : undefined,
|
|
237
|
+
lastUsedAt: row.last_used_at ? toDate(row.last_used_at) : undefined,
|
|
238
|
+
lastUsedUserAgent: row.last_used_user_agent ?? undefined,
|
|
239
|
+
lastUsedIpAddress: row.last_used_ip_address ?? undefined,
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function rowToInvitationRecord(
|
|
244
|
+
row: PgAuthInvitationRow,
|
|
245
|
+
groupIds: readonly string[]
|
|
246
|
+
): InvitationRecord {
|
|
247
|
+
return {
|
|
248
|
+
id: row.id,
|
|
249
|
+
projectId: row.project_id,
|
|
250
|
+
email: row.email,
|
|
251
|
+
groupIds,
|
|
252
|
+
status: row.status,
|
|
253
|
+
createdByPrincipal: invitationCreatorFromRow(row),
|
|
254
|
+
createdBySessionId: row.created_by_session_id ?? undefined,
|
|
255
|
+
createdAt: toDate(row.created_at),
|
|
256
|
+
updatedAt: toDate(row.updated_at),
|
|
257
|
+
expiresAt: toDate(row.expires_at),
|
|
258
|
+
acceptedAt: row.accepted_at ? toDate(row.accepted_at) : undefined,
|
|
259
|
+
revokedAt: row.revoked_at ? toDate(row.revoked_at) : undefined,
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function rowToGroupMembershipRecord(row: PgAuthGroupMembershipRow): GroupMembershipRecord {
|
|
264
|
+
return {
|
|
265
|
+
projectId: row.project_id,
|
|
266
|
+
userId: row.user_id,
|
|
267
|
+
groupId: row.group_id,
|
|
268
|
+
source: row.source,
|
|
269
|
+
createdAt: toDate(row.created_at),
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export function rowToMagicLinkRecord(row: PgAuthMagicLinkRow): MagicLinkRecord {
|
|
274
|
+
return {
|
|
275
|
+
id: row.id,
|
|
276
|
+
projectId: row.project_id,
|
|
277
|
+
strategyId: row.strategy_id,
|
|
278
|
+
audience: row.audience,
|
|
279
|
+
email: row.email,
|
|
280
|
+
tokenHash: row.token_hash,
|
|
281
|
+
returnTo: row.return_to ?? undefined,
|
|
282
|
+
createdAt: toDate(row.created_at),
|
|
283
|
+
expiresAt: toDate(row.expires_at),
|
|
284
|
+
consumedAt: row.consumed_at ? toDate(row.consumed_at) : undefined,
|
|
285
|
+
revokedAt: row.revoked_at ? toDate(row.revoked_at) : undefined,
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function rowToOidcAuthorizationAttemptRecord(
|
|
290
|
+
row: PgAuthOidcAttemptRow
|
|
291
|
+
): OidcAuthorizationAttemptRecord {
|
|
292
|
+
return {
|
|
293
|
+
id: row.id,
|
|
294
|
+
projectId: row.project_id,
|
|
295
|
+
strategyId: row.strategy_id,
|
|
296
|
+
audience: row.audience,
|
|
297
|
+
stateHash: row.state_hash,
|
|
298
|
+
nonceHash: row.nonce_hash,
|
|
299
|
+
codeVerifier: row.code_verifier,
|
|
300
|
+
returnTo: row.return_to ?? undefined,
|
|
301
|
+
createdAt: toDate(row.created_at),
|
|
302
|
+
expiresAt: toDate(row.expires_at),
|
|
303
|
+
consumedAt: row.consumed_at ? toDate(row.consumed_at) : undefined,
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export function serializeOptionalRecord(
|
|
308
|
+
value: Readonly<Record<string, unknown>> | undefined
|
|
309
|
+
): string | null {
|
|
310
|
+
return value ? JSON.stringify(value) : null
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export function serializeOptionalStringArray(value: readonly string[] | undefined): string | null {
|
|
314
|
+
return value === undefined ? null : JSON.stringify(value)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function principalFromColumns(row: {
|
|
318
|
+
readonly created_by_user_id: string | null
|
|
319
|
+
readonly created_by_service_account_id: string | null
|
|
320
|
+
readonly created_by_system_id: string | null
|
|
321
|
+
}): Principal | undefined {
|
|
322
|
+
if (row.created_by_user_id) return { type: "user", id: row.created_by_user_id }
|
|
323
|
+
if (row.created_by_service_account_id) {
|
|
324
|
+
return { type: "serviceAccount", id: row.created_by_service_account_id }
|
|
325
|
+
}
|
|
326
|
+
if (row.created_by_system_id) return { type: "system", id: row.created_by_system_id }
|
|
327
|
+
return undefined
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function invitationCreatorFromRow(row: PgAuthInvitationRow): Principal | undefined {
|
|
331
|
+
return principalFromColumns(row)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function parseOptionalRecord(
|
|
335
|
+
value: Readonly<Record<string, unknown>> | string | null
|
|
336
|
+
): Readonly<Record<string, unknown>> | undefined {
|
|
337
|
+
if (!value) return undefined
|
|
338
|
+
if (typeof value === "string") return JSON.parse(value) as Readonly<Record<string, unknown>>
|
|
339
|
+
return structuredClone(value)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function parseOptionalStringArray(
|
|
343
|
+
value: readonly string[] | string | null
|
|
344
|
+
): readonly string[] | undefined {
|
|
345
|
+
if (value === null) return undefined
|
|
346
|
+
if (typeof value === "string") return JSON.parse(value) as readonly string[]
|
|
347
|
+
return [...value]
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function toDate(value: PgDate): Date {
|
|
351
|
+
return value instanceof Date ? new Date(value) : new Date(value)
|
|
352
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuthServiceAccountGroupMembershipStore,
|
|
3
|
+
ReconcileAuthServiceAccountGroupMembershipsInput,
|
|
4
|
+
ServiceAccountGroupMembershipRecord,
|
|
5
|
+
UpsertAuthServiceAccountGroupMembershipInput,
|
|
6
|
+
} from "@sixb/core/storage"
|
|
7
|
+
import { AuthStorageError } from "@sixb/core/storage"
|
|
8
|
+
import type { PgStoreClient } from "../transactions"
|
|
9
|
+
import type { PgAuthServiceAccountGroupMembershipRow, PgAuthServiceAccountRow } from "./rows"
|
|
10
|
+
import { rowToServiceAccountGroupMembershipRecord } from "./rows"
|
|
11
|
+
import { assertNonEmpty, dateOrNow } from "./shared"
|
|
12
|
+
|
|
13
|
+
export class PgAuthServiceAccountGroupMembershipStore
|
|
14
|
+
implements AuthServiceAccountGroupMembershipStore
|
|
15
|
+
{
|
|
16
|
+
constructor(private readonly sql: PgStoreClient) {}
|
|
17
|
+
|
|
18
|
+
async upsert(
|
|
19
|
+
input: UpsertAuthServiceAccountGroupMembershipInput
|
|
20
|
+
): Promise<ServiceAccountGroupMembershipRecord> {
|
|
21
|
+
const projectId = assertNonEmpty(input.projectId, "Project id")
|
|
22
|
+
const serviceAccountId = assertNonEmpty(input.serviceAccountId, "Service account id")
|
|
23
|
+
const groupId = assertNonEmpty(input.groupId, "Group id")
|
|
24
|
+
const [serviceAccount] = await this.sql<PgAuthServiceAccountRow[]>`
|
|
25
|
+
SELECT *
|
|
26
|
+
FROM auth_service_accounts
|
|
27
|
+
WHERE project_id = ${projectId}
|
|
28
|
+
AND id = ${serviceAccountId}
|
|
29
|
+
`
|
|
30
|
+
if (!serviceAccount) {
|
|
31
|
+
throw new AuthStorageError(
|
|
32
|
+
"missing_service_account",
|
|
33
|
+
`[Sixb] Service account '${serviceAccountId}' not found for project '${projectId}'.`
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const [row] = await this.sql<PgAuthServiceAccountGroupMembershipRow[]>`
|
|
38
|
+
INSERT INTO auth_service_account_group_memberships (
|
|
39
|
+
project_id,
|
|
40
|
+
service_account_id,
|
|
41
|
+
group_id,
|
|
42
|
+
source,
|
|
43
|
+
created_at
|
|
44
|
+
) VALUES (
|
|
45
|
+
${projectId},
|
|
46
|
+
${serviceAccountId},
|
|
47
|
+
${groupId},
|
|
48
|
+
${input.source},
|
|
49
|
+
${dateOrNow(input.createdAt)}
|
|
50
|
+
)
|
|
51
|
+
ON CONFLICT (project_id, service_account_id, group_id) DO UPDATE
|
|
52
|
+
SET source = auth_service_account_group_memberships.source
|
|
53
|
+
RETURNING *
|
|
54
|
+
`
|
|
55
|
+
|
|
56
|
+
return rowToServiceAccountGroupMembershipRecord(row)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async reconcileForServiceAccount(
|
|
60
|
+
input: ReconcileAuthServiceAccountGroupMembershipsInput
|
|
61
|
+
): Promise<readonly ServiceAccountGroupMembershipRecord[]> {
|
|
62
|
+
const projectId = assertNonEmpty(input.projectId, "Project id")
|
|
63
|
+
const serviceAccountId = assertNonEmpty(input.serviceAccountId, "Service account id")
|
|
64
|
+
const groupIds = [
|
|
65
|
+
...new Set(input.groupIds.map((groupId) => assertNonEmpty(groupId, "Group id"))),
|
|
66
|
+
]
|
|
67
|
+
const [serviceAccount] = await this.sql<PgAuthServiceAccountRow[]>`
|
|
68
|
+
SELECT *
|
|
69
|
+
FROM auth_service_accounts
|
|
70
|
+
WHERE project_id = ${projectId}
|
|
71
|
+
AND id = ${serviceAccountId}
|
|
72
|
+
`
|
|
73
|
+
if (!serviceAccount) {
|
|
74
|
+
throw new AuthStorageError(
|
|
75
|
+
"missing_service_account",
|
|
76
|
+
`[Sixb] Service account '${serviceAccountId}' not found for project '${projectId}'.`
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (groupIds.length === 0) {
|
|
81
|
+
await this.sql`
|
|
82
|
+
DELETE FROM auth_service_account_group_memberships
|
|
83
|
+
WHERE project_id = ${projectId}
|
|
84
|
+
AND service_account_id = ${serviceAccountId}
|
|
85
|
+
AND source = ${input.source}
|
|
86
|
+
`
|
|
87
|
+
} else {
|
|
88
|
+
await this.sql`
|
|
89
|
+
DELETE FROM auth_service_account_group_memberships
|
|
90
|
+
WHERE project_id = ${projectId}
|
|
91
|
+
AND service_account_id = ${serviceAccountId}
|
|
92
|
+
AND source = ${input.source}
|
|
93
|
+
AND group_id NOT IN ${this.sql(groupIds)}
|
|
94
|
+
`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const updatedAt = dateOrNow(input.updatedAt)
|
|
98
|
+
for (const groupId of groupIds) {
|
|
99
|
+
await this.sql<PgAuthServiceAccountGroupMembershipRow[]>`
|
|
100
|
+
INSERT INTO auth_service_account_group_memberships (
|
|
101
|
+
project_id,
|
|
102
|
+
service_account_id,
|
|
103
|
+
group_id,
|
|
104
|
+
source,
|
|
105
|
+
created_at
|
|
106
|
+
) VALUES (
|
|
107
|
+
${projectId},
|
|
108
|
+
${serviceAccountId},
|
|
109
|
+
${groupId},
|
|
110
|
+
${input.source},
|
|
111
|
+
${updatedAt}
|
|
112
|
+
)
|
|
113
|
+
ON CONFLICT (project_id, service_account_id, group_id) DO UPDATE
|
|
114
|
+
SET source = EXCLUDED.source
|
|
115
|
+
`
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return this.listForServiceAccount({ projectId, serviceAccountId })
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async listForServiceAccount(params: {
|
|
122
|
+
readonly projectId: string
|
|
123
|
+
readonly serviceAccountId: string
|
|
124
|
+
}): Promise<readonly ServiceAccountGroupMembershipRecord[]> {
|
|
125
|
+
const rows = await this.sql<PgAuthServiceAccountGroupMembershipRow[]>`
|
|
126
|
+
SELECT *
|
|
127
|
+
FROM auth_service_account_group_memberships
|
|
128
|
+
WHERE project_id = ${params.projectId}
|
|
129
|
+
AND service_account_id = ${params.serviceAccountId}
|
|
130
|
+
ORDER BY group_id ASC
|
|
131
|
+
`
|
|
132
|
+
|
|
133
|
+
return rows.map(rowToServiceAccountGroupMembershipRecord)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async listForGroup(params: {
|
|
137
|
+
readonly projectId: string
|
|
138
|
+
readonly groupId: string
|
|
139
|
+
}): Promise<readonly ServiceAccountGroupMembershipRecord[]> {
|
|
140
|
+
const rows = await this.sql<PgAuthServiceAccountGroupMembershipRow[]>`
|
|
141
|
+
SELECT *
|
|
142
|
+
FROM auth_service_account_group_memberships
|
|
143
|
+
WHERE project_id = ${params.projectId}
|
|
144
|
+
AND group_id = ${params.groupId}
|
|
145
|
+
ORDER BY service_account_id ASC
|
|
146
|
+
`
|
|
147
|
+
|
|
148
|
+
return rows.map(rowToServiceAccountGroupMembershipRecord)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuthServiceAccountStore,
|
|
3
|
+
CreateAuthServiceAccountInput,
|
|
4
|
+
ListAuthServiceAccountsInput,
|
|
5
|
+
ListAuthServiceAccountsResult,
|
|
6
|
+
ServiceAccountRecord,
|
|
7
|
+
UpdateAuthServiceAccountInput,
|
|
8
|
+
} from "@sixb/core/storage"
|
|
9
|
+
import { AuthStorageError } from "@sixb/core/storage"
|
|
10
|
+
import type { PgStoreClient } from "../transactions"
|
|
11
|
+
import type { PgAuthServiceAccountRow } from "./rows"
|
|
12
|
+
import { rowToServiceAccountRecord } from "./rows"
|
|
13
|
+
import {
|
|
14
|
+
appendPagination,
|
|
15
|
+
assertNonEmpty,
|
|
16
|
+
dateOrNow,
|
|
17
|
+
hasEmptyFilter,
|
|
18
|
+
mapUniqueConstraintError,
|
|
19
|
+
type PgValue,
|
|
20
|
+
} from "./shared"
|
|
21
|
+
|
|
22
|
+
export class PgAuthServiceAccountStore implements AuthServiceAccountStore {
|
|
23
|
+
constructor(private readonly sql: PgStoreClient) {}
|
|
24
|
+
|
|
25
|
+
async create(input: CreateAuthServiceAccountInput): Promise<ServiceAccountRecord> {
|
|
26
|
+
const id = assertNonEmpty(input.id, "Service account id")
|
|
27
|
+
const projectId = assertNonEmpty(input.projectId, "Project id")
|
|
28
|
+
const name = assertNonEmpty(input.name, "Service account name")
|
|
29
|
+
const createdAt = dateOrNow(input.createdAt)
|
|
30
|
+
const updatedAt = input.updatedAt ? new Date(input.updatedAt) : createdAt
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const [row] = await this.sql<PgAuthServiceAccountRow[]>`
|
|
34
|
+
INSERT INTO auth_service_accounts (
|
|
35
|
+
project_id,
|
|
36
|
+
id,
|
|
37
|
+
name,
|
|
38
|
+
description,
|
|
39
|
+
status,
|
|
40
|
+
created_by_user_id,
|
|
41
|
+
created_by_service_account_id,
|
|
42
|
+
created_by_system_id,
|
|
43
|
+
created_by_session_id,
|
|
44
|
+
created_at,
|
|
45
|
+
updated_at
|
|
46
|
+
) VALUES (
|
|
47
|
+
${projectId},
|
|
48
|
+
${id},
|
|
49
|
+
${name},
|
|
50
|
+
${input.description ?? null},
|
|
51
|
+
${input.status ?? "active"},
|
|
52
|
+
${input.createdByPrincipal?.type === "user" ? input.createdByPrincipal.id : null},
|
|
53
|
+
${
|
|
54
|
+
input.createdByPrincipal?.type === "serviceAccount" ? input.createdByPrincipal.id : null
|
|
55
|
+
},
|
|
56
|
+
${input.createdByPrincipal?.type === "system" ? input.createdByPrincipal.id : null},
|
|
57
|
+
${input.createdBySessionId ?? null},
|
|
58
|
+
${createdAt},
|
|
59
|
+
${updatedAt}
|
|
60
|
+
)
|
|
61
|
+
RETURNING *
|
|
62
|
+
`
|
|
63
|
+
|
|
64
|
+
return rowToServiceAccountRecord(row)
|
|
65
|
+
} catch (error) {
|
|
66
|
+
mapUniqueConstraintError(
|
|
67
|
+
error,
|
|
68
|
+
"duplicate_service_account",
|
|
69
|
+
`[Sixb] Service account '${id}' already exists for project '${projectId}'.`
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async getById(params: {
|
|
75
|
+
readonly projectId: string
|
|
76
|
+
readonly id: string
|
|
77
|
+
}): Promise<ServiceAccountRecord | null> {
|
|
78
|
+
const [row] = await this.sql<PgAuthServiceAccountRow[]>`
|
|
79
|
+
SELECT *
|
|
80
|
+
FROM auth_service_accounts
|
|
81
|
+
WHERE project_id = ${params.projectId}
|
|
82
|
+
AND id = ${params.id}
|
|
83
|
+
`
|
|
84
|
+
return row ? rowToServiceAccountRecord(row) : null
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async update(input: UpdateAuthServiceAccountInput): Promise<ServiceAccountRecord> {
|
|
88
|
+
const existing = await this.getById(input)
|
|
89
|
+
if (!existing) {
|
|
90
|
+
throw new AuthStorageError(
|
|
91
|
+
"missing_service_account",
|
|
92
|
+
`[Sixb] Service account '${input.id}' not found for project '${input.projectId}'.`
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const updatedAt = dateOrNow(input.updatedAt)
|
|
97
|
+
const name =
|
|
98
|
+
input.name === undefined ? existing.name : assertNonEmpty(input.name, "Service account name")
|
|
99
|
+
const description = input.description === undefined ? existing.description : input.description
|
|
100
|
+
const [row] = await this.sql<PgAuthServiceAccountRow[]>`
|
|
101
|
+
UPDATE auth_service_accounts
|
|
102
|
+
SET name = ${name},
|
|
103
|
+
description = ${description ?? null},
|
|
104
|
+
status = ${input.status ?? existing.status},
|
|
105
|
+
updated_at = ${updatedAt}
|
|
106
|
+
WHERE project_id = ${input.projectId}
|
|
107
|
+
AND id = ${input.id}
|
|
108
|
+
RETURNING *
|
|
109
|
+
`
|
|
110
|
+
|
|
111
|
+
return rowToServiceAccountRecord(row)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async list(input: ListAuthServiceAccountsInput): Promise<ListAuthServiceAccountsResult> {
|
|
115
|
+
if (hasEmptyFilter(input.statuses)) {
|
|
116
|
+
return { serviceAccounts: [], hasMore: false, total: 0 }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const whereClauses = ["project_id = $1"]
|
|
120
|
+
const params: PgValue[] = [input.projectId]
|
|
121
|
+
let nextIndex = 2
|
|
122
|
+
if (input.statuses) {
|
|
123
|
+
whereClauses.push(`status IN (${input.statuses.map(() => `$${nextIndex++}`).join(", ")})`)
|
|
124
|
+
params.push(...input.statuses)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const where = `WHERE ${whereClauses.join(" AND ")}`
|
|
128
|
+
const order = input.order === "desc" ? "DESC" : "ASC"
|
|
129
|
+
const [totalRow] = await this.sql.unsafe<{ readonly count: string | number }[]>(
|
|
130
|
+
`SELECT COUNT(*)::bigint AS count FROM auth_service_accounts ${where}`,
|
|
131
|
+
[...params]
|
|
132
|
+
)
|
|
133
|
+
const queryParams = [...params]
|
|
134
|
+
const query = appendPagination(
|
|
135
|
+
`
|
|
136
|
+
SELECT *
|
|
137
|
+
FROM auth_service_accounts
|
|
138
|
+
${where}
|
|
139
|
+
ORDER BY created_at ${order}, id ${order}
|
|
140
|
+
`,
|
|
141
|
+
queryParams,
|
|
142
|
+
nextIndex,
|
|
143
|
+
input
|
|
144
|
+
)
|
|
145
|
+
const rows = await this.sql.unsafe<PgAuthServiceAccountRow[]>(query, queryParams)
|
|
146
|
+
const total = Number(totalRow?.count ?? 0)
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
serviceAccounts: rows.map(rowToServiceAccountRecord),
|
|
150
|
+
hasMore: input.limit === undefined ? false : (input.offset ?? 0) + input.limit < total,
|
|
151
|
+
total,
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|