@oidcraft/kysely 0.1.0 → 0.2.0
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/dist/index.d.mts +1 -0
- package/dist/index.mjs +222 -160
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,146 @@
|
|
|
1
|
+
import { noAccounts } from "@oidcraft/adapter";
|
|
2
|
+
// ../sql/dist/rows.mjs
|
|
3
|
+
/** Never `new Date` on the raw value: a string there is read as a date, not as milliseconds. */
|
|
4
|
+
const at = (millis) => new Date(Number(millis));
|
|
5
|
+
const json = (value) => JSON.stringify(value);
|
|
6
|
+
const parse = (value) => JSON.parse(value);
|
|
7
|
+
const clientRow = (client) => ({
|
|
8
|
+
client_id: client.clientId,
|
|
9
|
+
data: json(client),
|
|
10
|
+
created_at: client.createdAt.getTime(),
|
|
11
|
+
updated_at: client.updatedAt.getTime()
|
|
12
|
+
});
|
|
13
|
+
const toClient = (row) => ({
|
|
14
|
+
...parse(row.data),
|
|
15
|
+
createdAt: at(row.created_at),
|
|
16
|
+
updatedAt: at(row.updated_at)
|
|
17
|
+
});
|
|
18
|
+
/** `user_code` is lifted out of the payload so a device's code is found by index (FR-C7). */
|
|
19
|
+
const artifactRow = (artifact) => ({
|
|
20
|
+
kind: artifact.kind,
|
|
21
|
+
id: artifact.id,
|
|
22
|
+
client_id: artifact.clientId,
|
|
23
|
+
account_id: artifact.accountId ?? null,
|
|
24
|
+
grant_id: artifact.grantId ?? null,
|
|
25
|
+
family_id: artifact.familyId ?? null,
|
|
26
|
+
user_code: artifact.payload.userCode ?? null,
|
|
27
|
+
payload: json(artifact.payload),
|
|
28
|
+
consumed_at: artifact.consumedAt ? artifact.consumedAt.getTime() : null,
|
|
29
|
+
expires_at: artifact.expiresAt.getTime()
|
|
30
|
+
});
|
|
31
|
+
const toArtifact = (row) => ({
|
|
32
|
+
id: row.id,
|
|
33
|
+
kind: row.kind,
|
|
34
|
+
clientId: row.client_id,
|
|
35
|
+
...row.account_id && { accountId: row.account_id },
|
|
36
|
+
...row.grant_id && { grantId: row.grant_id },
|
|
37
|
+
...row.family_id && { familyId: row.family_id },
|
|
38
|
+
payload: parse(row.payload),
|
|
39
|
+
...row.consumed_at && { consumedAt: at(row.consumed_at) },
|
|
40
|
+
expiresAt: at(row.expires_at)
|
|
41
|
+
});
|
|
42
|
+
const sessionRow = (session) => ({
|
|
43
|
+
id: session.id,
|
|
44
|
+
account_id: session.accountId,
|
|
45
|
+
auth_time: session.authTime.getTime(),
|
|
46
|
+
acr: session.acr ?? null,
|
|
47
|
+
amr: session.amr ? json(session.amr) : null,
|
|
48
|
+
idp: session.idp ?? null,
|
|
49
|
+
upstream_session_id: session.upstreamSessionId ?? null,
|
|
50
|
+
clients: json(session.clients),
|
|
51
|
+
expires_at: session.expiresAt.getTime()
|
|
52
|
+
});
|
|
53
|
+
const toSession = (row) => ({
|
|
54
|
+
id: row.id,
|
|
55
|
+
accountId: row.account_id,
|
|
56
|
+
authTime: at(row.auth_time),
|
|
57
|
+
...row.acr && { acr: row.acr },
|
|
58
|
+
...row.amr ? { amr: parse(row.amr) } : {},
|
|
59
|
+
...row.idp && { idp: row.idp },
|
|
60
|
+
...row.upstream_session_id && { upstreamSessionId: row.upstream_session_id },
|
|
61
|
+
clients: parse(row.clients),
|
|
62
|
+
expiresAt: at(row.expires_at)
|
|
63
|
+
});
|
|
64
|
+
const grantRow = (grant) => ({
|
|
65
|
+
id: grant.id,
|
|
66
|
+
account_id: grant.accountId,
|
|
67
|
+
client_id: grant.clientId,
|
|
68
|
+
scopes: json(grant.scopes),
|
|
69
|
+
claims: json(grant.claims),
|
|
70
|
+
resources: json(grant.resources),
|
|
71
|
+
created_at: grant.createdAt.getTime(),
|
|
72
|
+
expires_at: grant.expiresAt ? grant.expiresAt.getTime() : null
|
|
73
|
+
});
|
|
74
|
+
const toGrant = (row) => ({
|
|
75
|
+
id: row.id,
|
|
76
|
+
accountId: row.account_id,
|
|
77
|
+
clientId: row.client_id,
|
|
78
|
+
scopes: parse(row.scopes),
|
|
79
|
+
claims: parse(row.claims),
|
|
80
|
+
resources: parse(row.resources),
|
|
81
|
+
createdAt: at(row.created_at),
|
|
82
|
+
...row.expires_at && { expiresAt: at(row.expires_at) }
|
|
83
|
+
});
|
|
84
|
+
const identityRow = (identity) => ({
|
|
85
|
+
provider: identity.provider,
|
|
86
|
+
subject: identity.subject,
|
|
87
|
+
account_id: identity.accountId,
|
|
88
|
+
email: identity.email ?? null,
|
|
89
|
+
claims: json(identity.claims),
|
|
90
|
+
linked_at: identity.linkedAt.getTime()
|
|
91
|
+
});
|
|
92
|
+
const toIdentity = (row) => ({
|
|
93
|
+
accountId: row.account_id,
|
|
94
|
+
provider: row.provider,
|
|
95
|
+
subject: row.subject,
|
|
96
|
+
...row.email && { email: row.email },
|
|
97
|
+
claims: parse(row.claims),
|
|
98
|
+
linkedAt: at(row.linked_at)
|
|
99
|
+
});
|
|
100
|
+
const credentialRow = (credential) => ({
|
|
101
|
+
account_id: credential.accountId,
|
|
102
|
+
username: credential.username,
|
|
103
|
+
password_hash: credential.passwordHash,
|
|
104
|
+
claims: json(credential.claims),
|
|
105
|
+
totp_secret: credential.totp?.secret ?? null,
|
|
106
|
+
totp_confirmed_at: credential.totp?.confirmedAt?.getTime() ?? null,
|
|
107
|
+
recovery_codes: credential.recoveryCodes ? json(credential.recoveryCodes) : null,
|
|
108
|
+
failed_attempts: credential.failedAttempts,
|
|
109
|
+
locked_until: credential.lockedUntil?.getTime() ?? null,
|
|
110
|
+
created_at: credential.createdAt.getTime(),
|
|
111
|
+
updated_at: credential.updatedAt.getTime()
|
|
112
|
+
});
|
|
113
|
+
const toCredential = (row) => ({
|
|
114
|
+
accountId: row.account_id,
|
|
115
|
+
username: row.username,
|
|
116
|
+
passwordHash: row.password_hash,
|
|
117
|
+
claims: parse(row.claims),
|
|
118
|
+
...row.totp_secret && { totp: {
|
|
119
|
+
secret: row.totp_secret,
|
|
120
|
+
...row.totp_confirmed_at && { confirmedAt: at(row.totp_confirmed_at) }
|
|
121
|
+
} },
|
|
122
|
+
...row.recovery_codes ? { recoveryCodes: parse(row.recovery_codes) } : {},
|
|
123
|
+
failedAttempts: Number(row.failed_attempts),
|
|
124
|
+
...row.locked_until && { lockedUntil: at(row.locked_until) },
|
|
125
|
+
createdAt: at(row.created_at),
|
|
126
|
+
updatedAt: at(row.updated_at)
|
|
127
|
+
});
|
|
128
|
+
const realmRow = (realm) => ({
|
|
129
|
+
id: realm.id,
|
|
130
|
+
display_name: realm.displayName ?? null,
|
|
131
|
+
enabled: realm.enabled ? 1 : 0,
|
|
132
|
+
settings: json(realm.settings),
|
|
133
|
+
created_at: realm.createdAt.getTime(),
|
|
134
|
+
updated_at: realm.updatedAt.getTime()
|
|
135
|
+
});
|
|
136
|
+
const toRealm = (row) => ({
|
|
137
|
+
id: row.id,
|
|
138
|
+
...row.display_name && { displayName: row.display_name },
|
|
139
|
+
enabled: Boolean(Number(row.enabled)),
|
|
140
|
+
settings: parse(row.settings),
|
|
141
|
+
createdAt: at(row.created_at),
|
|
142
|
+
updatedAt: at(row.updated_at)
|
|
143
|
+
});
|
|
1
144
|
// ../sql/dist/postgres.mjs
|
|
2
145
|
/**
|
|
3
146
|
* The same tables as `SQLITE_MIGRATIONS`, with the same ids, for Postgres (FR-A4). Milliseconds are
|
|
@@ -35,6 +178,18 @@ const POSTGRES_MIGRATIONS = [
|
|
|
35
178
|
{
|
|
36
179
|
id: "0003_realms",
|
|
37
180
|
statements: ["create table oidc_realms (id text primary key, display_name text, enabled integer not null, settings text not null, created_at bigint not null, updated_at bigint not null)"]
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
id: "0004_indexes",
|
|
184
|
+
statements: [
|
|
185
|
+
"create index oidc_artifacts_client_idx on oidc_artifacts (client_id)",
|
|
186
|
+
"create index oidc_grants_client_idx on oidc_grants (client_id)",
|
|
187
|
+
"create index oidc_sessions_expiry_idx on oidc_sessions (expires_at)"
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: "0005_families",
|
|
192
|
+
statements: ["alter table oidc_artifacts add column family_id text", "create index oidc_artifacts_family_idx on oidc_artifacts (family_id)"]
|
|
38
193
|
}
|
|
39
194
|
];
|
|
40
195
|
// ../sql/dist/sqlite.mjs
|
|
@@ -73,100 +228,22 @@ const SQLITE_MIGRATIONS = [
|
|
|
73
228
|
{
|
|
74
229
|
id: "0003_realms",
|
|
75
230
|
statements: ["create table oidc_realms (id text primary key, display_name text, enabled integer not null, settings text not null, created_at integer not null, updated_at integer not null)"]
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
id: "0004_indexes",
|
|
234
|
+
statements: [
|
|
235
|
+
"create index oidc_artifacts_client_idx on oidc_artifacts (client_id)",
|
|
236
|
+
"create index oidc_grants_client_idx on oidc_grants (client_id)",
|
|
237
|
+
"create index oidc_sessions_expiry_idx on oidc_sessions (expires_at)"
|
|
238
|
+
]
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
id: "0005_families",
|
|
242
|
+
statements: ["alter table oidc_artifacts add column family_id text", "create index oidc_artifacts_family_idx on oidc_artifacts (family_id)"]
|
|
76
243
|
}
|
|
77
244
|
];
|
|
78
245
|
// src/index.ts
|
|
79
246
|
const now = () => Date.now();
|
|
80
|
-
const at = (millis) => new Date(Number(millis));
|
|
81
|
-
const json = (value) => JSON.stringify(value);
|
|
82
|
-
const parse = (value) => JSON.parse(value);
|
|
83
|
-
const toArtifact = (row) => ({
|
|
84
|
-
id: row.id,
|
|
85
|
-
kind: row.kind,
|
|
86
|
-
clientId: row.client_id,
|
|
87
|
-
...row.account_id && { accountId: row.account_id },
|
|
88
|
-
...row.grant_id && { grantId: row.grant_id },
|
|
89
|
-
payload: parse(row.payload),
|
|
90
|
-
...row.consumed_at && { consumedAt: at(row.consumed_at) },
|
|
91
|
-
expiresAt: at(row.expires_at)
|
|
92
|
-
});
|
|
93
|
-
const toSession = (row) => ({
|
|
94
|
-
id: row.id,
|
|
95
|
-
accountId: row.account_id,
|
|
96
|
-
authTime: at(row.auth_time),
|
|
97
|
-
...row.acr && { acr: row.acr },
|
|
98
|
-
...row.amr ? { amr: parse(row.amr) } : {},
|
|
99
|
-
...row.idp && { idp: row.idp },
|
|
100
|
-
...row.upstream_session_id && { upstreamSessionId: row.upstream_session_id },
|
|
101
|
-
clients: parse(row.clients),
|
|
102
|
-
expiresAt: at(row.expires_at)
|
|
103
|
-
});
|
|
104
|
-
const toGrant = (row) => ({
|
|
105
|
-
id: row.id,
|
|
106
|
-
accountId: row.account_id,
|
|
107
|
-
clientId: row.client_id,
|
|
108
|
-
scopes: parse(row.scopes),
|
|
109
|
-
claims: parse(row.claims),
|
|
110
|
-
resources: parse(row.resources),
|
|
111
|
-
createdAt: at(row.created_at),
|
|
112
|
-
...row.expires_at && { expiresAt: at(row.expires_at) }
|
|
113
|
-
});
|
|
114
|
-
const noAccounts = {
|
|
115
|
-
async find() {},
|
|
116
|
-
async claims() {}
|
|
117
|
-
};
|
|
118
|
-
const credentialRow = (credential) => ({
|
|
119
|
-
account_id: credential.accountId,
|
|
120
|
-
username: credential.username,
|
|
121
|
-
password_hash: credential.passwordHash,
|
|
122
|
-
claims: json(credential.claims),
|
|
123
|
-
totp_secret: credential.totp?.secret ?? null,
|
|
124
|
-
totp_confirmed_at: credential.totp?.confirmedAt?.getTime() ?? null,
|
|
125
|
-
recovery_codes: credential.recoveryCodes ? json(credential.recoveryCodes) : null,
|
|
126
|
-
failed_attempts: credential.failedAttempts,
|
|
127
|
-
locked_until: credential.lockedUntil?.getTime() ?? null,
|
|
128
|
-
created_at: credential.createdAt.getTime(),
|
|
129
|
-
updated_at: credential.updatedAt.getTime()
|
|
130
|
-
});
|
|
131
|
-
const toCredential = (row) => ({
|
|
132
|
-
accountId: row.account_id,
|
|
133
|
-
username: row.username,
|
|
134
|
-
passwordHash: row.password_hash,
|
|
135
|
-
claims: parse(row.claims),
|
|
136
|
-
...row.totp_secret && { totp: {
|
|
137
|
-
secret: row.totp_secret,
|
|
138
|
-
...row.totp_confirmed_at && { confirmedAt: at(row.totp_confirmed_at) }
|
|
139
|
-
} },
|
|
140
|
-
...row.recovery_codes ? { recoveryCodes: parse(row.recovery_codes) } : {},
|
|
141
|
-
failedAttempts: row.failed_attempts,
|
|
142
|
-
...row.locked_until && { lockedUntil: at(row.locked_until) },
|
|
143
|
-
createdAt: at(row.created_at),
|
|
144
|
-
updatedAt: at(row.updated_at)
|
|
145
|
-
});
|
|
146
|
-
const realmRow = (realm) => ({
|
|
147
|
-
id: realm.id,
|
|
148
|
-
display_name: realm.displayName ?? null,
|
|
149
|
-
enabled: realm.enabled ? 1 : 0,
|
|
150
|
-
settings: json(realm.settings),
|
|
151
|
-
created_at: realm.createdAt.getTime(),
|
|
152
|
-
updated_at: realm.updatedAt.getTime()
|
|
153
|
-
});
|
|
154
|
-
const toRealm = (row) => ({
|
|
155
|
-
id: row.id,
|
|
156
|
-
...row.display_name && { displayName: row.display_name },
|
|
157
|
-
enabled: Boolean(row.enabled),
|
|
158
|
-
settings: parse(row.settings),
|
|
159
|
-
createdAt: at(row.created_at),
|
|
160
|
-
updatedAt: at(row.updated_at)
|
|
161
|
-
});
|
|
162
|
-
const toIdentity = (row) => ({
|
|
163
|
-
accountId: row.account_id,
|
|
164
|
-
provider: row.provider,
|
|
165
|
-
subject: row.subject,
|
|
166
|
-
...row.email && { email: row.email },
|
|
167
|
-
claims: parse(row.claims),
|
|
168
|
-
linkedAt: at(row.linked_at)
|
|
169
|
-
});
|
|
170
247
|
/**
|
|
171
248
|
* The same contract as the Drizzle adapter, on a query builder rather than an ORM (FR-A4). Both run
|
|
172
249
|
* the one conformance suite, which is what makes "interchangeable" checkable rather than asserted.
|
|
@@ -175,17 +252,7 @@ const kyselyAdapter = (options) => {
|
|
|
175
252
|
const { db } = options;
|
|
176
253
|
const artifacts = {
|
|
177
254
|
async upsert(artifact) {
|
|
178
|
-
const row =
|
|
179
|
-
kind: artifact.kind,
|
|
180
|
-
id: artifact.id,
|
|
181
|
-
client_id: artifact.clientId,
|
|
182
|
-
account_id: artifact.accountId ?? null,
|
|
183
|
-
grant_id: artifact.grantId ?? null,
|
|
184
|
-
user_code: artifact.payload.userCode ?? null,
|
|
185
|
-
payload: json(artifact.payload),
|
|
186
|
-
consumed_at: artifact.consumedAt ? artifact.consumedAt.getTime() : null,
|
|
187
|
-
expires_at: artifact.expiresAt.getTime()
|
|
188
|
-
};
|
|
255
|
+
const row = artifactRow(artifact);
|
|
189
256
|
await db.insertInto("oidc_artifacts").values(row).onConflict((conflict) => conflict.columns(["kind", "id"]).doUpdateSet({
|
|
190
257
|
...row,
|
|
191
258
|
consumed_at: void 0
|
|
@@ -208,6 +275,12 @@ const kyselyAdapter = (options) => {
|
|
|
208
275
|
async revokeByGrantId(grantId) {
|
|
209
276
|
await db.deleteFrom("oidc_artifacts").where("grant_id", "=", grantId).execute();
|
|
210
277
|
},
|
|
278
|
+
async revokeByFamilyId(familyId) {
|
|
279
|
+
await db.deleteFrom("oidc_artifacts").where("family_id", "=", familyId).execute();
|
|
280
|
+
},
|
|
281
|
+
async revokeByClientId(clientId) {
|
|
282
|
+
await db.deleteFrom("oidc_artifacts").where("client_id", "=", clientId).execute();
|
|
283
|
+
},
|
|
211
284
|
async prune(before, limit) {
|
|
212
285
|
const doomed = await db.selectFrom("oidc_artifacts").select(["kind", "id"]).where("expires_at", "<=", before.getTime()).limit(limit).execute();
|
|
213
286
|
for (const row of doomed) await artifacts.destroy(row.kind, row.id);
|
|
@@ -219,21 +292,12 @@ const kyselyAdapter = (options) => {
|
|
|
219
292
|
async find(clientId) {
|
|
220
293
|
const row = await db.selectFrom("oidc_clients").selectAll().where("client_id", "=", clientId).executeTakeFirst();
|
|
221
294
|
if (!row) return void 0;
|
|
222
|
-
return
|
|
223
|
-
...parse(row.data),
|
|
224
|
-
createdAt: at(row.created_at),
|
|
225
|
-
updatedAt: at(row.updated_at)
|
|
226
|
-
};
|
|
295
|
+
return toClient(row);
|
|
227
296
|
},
|
|
228
297
|
async upsert(client) {
|
|
229
|
-
const
|
|
230
|
-
const updated_at =
|
|
231
|
-
await db.insertInto("oidc_clients").values({
|
|
232
|
-
client_id: client.clientId,
|
|
233
|
-
data,
|
|
234
|
-
created_at: client.createdAt.getTime(),
|
|
235
|
-
updated_at
|
|
236
|
-
}).onConflict((conflict) => conflict.column("client_id").doUpdateSet({
|
|
298
|
+
const row = clientRow(client);
|
|
299
|
+
const { data, updated_at } = row;
|
|
300
|
+
await db.insertInto("oidc_clients").values(row).onConflict((conflict) => conflict.column("client_id").doUpdateSet({
|
|
237
301
|
data,
|
|
238
302
|
updated_at
|
|
239
303
|
})).execute();
|
|
@@ -241,12 +305,16 @@ const kyselyAdapter = (options) => {
|
|
|
241
305
|
async destroy(clientId) {
|
|
242
306
|
await db.deleteFrom("oidc_clients").where("client_id", "=", clientId).execute();
|
|
243
307
|
},
|
|
244
|
-
async list() {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
308
|
+
async list(cursor, limit) {
|
|
309
|
+
let query = db.selectFrom("oidc_clients").selectAll().orderBy("client_id");
|
|
310
|
+
if (cursor !== void 0) query = query.where("client_id", ">", cursor);
|
|
311
|
+
const rows = await (limit === void 0 ? query : query.limit(limit + 1)).execute();
|
|
312
|
+
const more = limit !== void 0 && rows.length > limit;
|
|
313
|
+
const shown = more ? rows.slice(0, limit) : rows;
|
|
314
|
+
return {
|
|
315
|
+
clients: shown.map(toClient),
|
|
316
|
+
...more && { cursor: shown.at(-1)?.client_id }
|
|
317
|
+
};
|
|
250
318
|
}
|
|
251
319
|
},
|
|
252
320
|
artifacts,
|
|
@@ -259,20 +327,10 @@ const kyselyAdapter = (options) => {
|
|
|
259
327
|
return (await db.selectFrom("oidc_sessions").selectAll().where("account_id", "=", accountId).where("expires_at", ">", now()).execute()).map(toSession);
|
|
260
328
|
},
|
|
261
329
|
async findByUpstreamSession(provider, upstreamSessionId) {
|
|
262
|
-
return (await db.selectFrom("oidc_sessions").selectAll().where("idp", "=", provider).where("upstream_session_id", "=", upstreamSessionId).execute()).map(toSession);
|
|
330
|
+
return (await db.selectFrom("oidc_sessions").selectAll().where("idp", "=", provider).where("upstream_session_id", "=", upstreamSessionId).where("expires_at", ">", now()).execute()).map(toSession);
|
|
263
331
|
},
|
|
264
332
|
async upsert(session) {
|
|
265
|
-
const row =
|
|
266
|
-
id: session.id,
|
|
267
|
-
account_id: session.accountId,
|
|
268
|
-
auth_time: session.authTime.getTime(),
|
|
269
|
-
acr: session.acr ?? null,
|
|
270
|
-
amr: session.amr ? json(session.amr) : null,
|
|
271
|
-
idp: session.idp ?? null,
|
|
272
|
-
upstream_session_id: session.upstreamSessionId ?? null,
|
|
273
|
-
clients: json(session.clients),
|
|
274
|
-
expires_at: session.expiresAt.getTime()
|
|
275
|
-
};
|
|
333
|
+
const row = sessionRow(session);
|
|
276
334
|
await db.insertInto("oidc_sessions").values(row).onConflict((conflict) => conflict.column("id").doUpdateSet(row)).execute();
|
|
277
335
|
},
|
|
278
336
|
async addClient(id, clientId) {
|
|
@@ -288,7 +346,12 @@ const kyselyAdapter = (options) => {
|
|
|
288
346
|
},
|
|
289
347
|
async destroy(id) {
|
|
290
348
|
await db.deleteFrom("oidc_sessions").where("id", "=", id).execute();
|
|
291
|
-
}
|
|
349
|
+
},
|
|
350
|
+
prune: { async prune(before, limit) {
|
|
351
|
+
const doomed = await db.selectFrom("oidc_sessions").select("id").where("expires_at", "<=", before.getTime()).limit(limit).execute();
|
|
352
|
+
if (doomed.length) await db.deleteFrom("oidc_sessions").where("id", "in", doomed.map((row) => row.id)).where("expires_at", "<=", before.getTime()).execute();
|
|
353
|
+
return doomed.length;
|
|
354
|
+
} }.prune
|
|
292
355
|
},
|
|
293
356
|
grants: {
|
|
294
357
|
async find(id) {
|
|
@@ -303,20 +366,19 @@ const kyselyAdapter = (options) => {
|
|
|
303
366
|
return (await db.selectFrom("oidc_grants").selectAll().where("account_id", "=", accountId).execute()).map(toGrant);
|
|
304
367
|
},
|
|
305
368
|
async upsert(grant) {
|
|
306
|
-
const row =
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
created_at: grant.createdAt.getTime(),
|
|
314
|
-
expires_at: grant.expiresAt ? grant.expiresAt.getTime() : null
|
|
315
|
-
};
|
|
316
|
-
await db.insertInto("oidc_grants").values(row).onConflict((conflict) => conflict.column("id").doUpdateSet(row)).execute();
|
|
369
|
+
const row = grantRow(grant);
|
|
370
|
+
await db.insertInto("oidc_grants").values(row).onConflict((conflict) => conflict.columns(["account_id", "client_id"]).doUpdateSet({
|
|
371
|
+
scopes: row.scopes,
|
|
372
|
+
claims: row.claims,
|
|
373
|
+
resources: row.resources,
|
|
374
|
+
expires_at: row.expires_at
|
|
375
|
+
})).execute();
|
|
317
376
|
},
|
|
318
377
|
async destroy(id) {
|
|
319
378
|
await db.deleteFrom("oidc_grants").where("id", "=", id).execute();
|
|
379
|
+
},
|
|
380
|
+
async destroyByClientId(clientId) {
|
|
381
|
+
await db.deleteFrom("oidc_grants").where("client_id", "=", clientId).execute();
|
|
320
382
|
}
|
|
321
383
|
},
|
|
322
384
|
accounts: options.accounts ?? noAccounts,
|
|
@@ -360,14 +422,21 @@ const kyselyAdapter = (options) => {
|
|
|
360
422
|
}
|
|
361
423
|
},
|
|
362
424
|
keys: options.keys,
|
|
363
|
-
replay: {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
425
|
+
replay: {
|
|
426
|
+
async claim(namespace, value, ttl) {
|
|
427
|
+
const expires_at = now() + ttl * 1e3;
|
|
428
|
+
return await db.insertInto("oidc_replay").values({
|
|
429
|
+
namespace,
|
|
430
|
+
value,
|
|
431
|
+
expires_at
|
|
432
|
+
}).onConflict((conflict) => conflict.columns(["namespace", "value"]).doUpdateSet({ expires_at }).where("oidc_replay.expires_at", "<=", now())).returning("value").executeTakeFirst() !== void 0;
|
|
433
|
+
},
|
|
434
|
+
prune: { async prune(before, limit) {
|
|
435
|
+
const doomed = await db.selectFrom("oidc_replay").select(["namespace", "value"]).where("expires_at", "<=", before.getTime()).limit(limit).execute();
|
|
436
|
+
for (const row of doomed) await db.deleteFrom("oidc_replay").where("namespace", "=", row.namespace).where("value", "=", row.value).where("expires_at", "<=", before.getTime()).execute();
|
|
437
|
+
return doomed.length;
|
|
438
|
+
} }.prune
|
|
439
|
+
},
|
|
371
440
|
identities: {
|
|
372
441
|
async find(provider, subject) {
|
|
373
442
|
const row = await db.selectFrom("oidc_identities").selectAll().where("provider", "=", provider).where("subject", "=", subject).executeTakeFirst();
|
|
@@ -377,14 +446,7 @@ const kyselyAdapter = (options) => {
|
|
|
377
446
|
return (await db.selectFrom("oidc_identities").selectAll().where("account_id", "=", accountId).execute()).map(toIdentity);
|
|
378
447
|
},
|
|
379
448
|
async upsert(identity) {
|
|
380
|
-
const row =
|
|
381
|
-
provider: identity.provider,
|
|
382
|
-
subject: identity.subject,
|
|
383
|
-
account_id: identity.accountId,
|
|
384
|
-
email: identity.email ?? null,
|
|
385
|
-
claims: json(identity.claims),
|
|
386
|
-
linked_at: identity.linkedAt.getTime()
|
|
387
|
-
};
|
|
449
|
+
const row = identityRow(identity);
|
|
388
450
|
await db.insertInto("oidc_identities").values(row).onConflict((conflict) => conflict.columns(["provider", "subject"]).doUpdateSet(row)).execute();
|
|
389
451
|
},
|
|
390
452
|
async destroy(provider, subject) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oidcraft/kysely",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A Kysely storage adapter for @oidcraft/provider, on Postgres or SQLite.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Fl0r14n <florian.chis@gmail.com>",
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
"verify:entries": "bun run verify-entries.ts"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"@oidcraft/adapter": "^0.
|
|
44
|
+
"@oidcraft/adapter": "^0.2.0",
|
|
45
45
|
"kysely": ">=0.28"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@oidcraft/adapter": "^0.
|
|
48
|
+
"@oidcraft/adapter": "^0.2.0",
|
|
49
49
|
"@oidcraft/sql": "0.0.0",
|
|
50
50
|
"@types/pg": "^8.23.1",
|
|
51
51
|
"kysely": "^0.29.8",
|