@oidcraft/typeorm 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 +15 -10
- package/dist/index.mjs +263 -176
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DataSource, EntitySchema, QueryRunner } from "typeorm";
|
|
2
1
|
import { AccountStore, FullAdapter, KeyStore } from "@oidcraft/adapter";
|
|
2
|
+
import { DataSource, EntitySchema, QueryRunner } from "typeorm";
|
|
3
3
|
type Migration = {
|
|
4
4
|
id: string;
|
|
5
5
|
statements: string[];
|
|
@@ -17,24 +17,29 @@ export declare const POSTGRES_MIGRATIONS: Migration[];
|
|
|
17
17
|
* deploy, from several processes at once (ARCHITECTURE.md §4.2, FR-A4).
|
|
18
18
|
*/
|
|
19
19
|
export declare const SQLITE_MIGRATIONS: Migration[];
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* The rows of the shared schema as Kysely and TypeORM read and write them: JSON as text, times as
|
|
22
|
+
* epoch milliseconds. Drizzle declares its columns as JSON and timestamps and maps them itself.
|
|
23
|
+
*/
|
|
24
|
+
type ClientRow = {
|
|
21
25
|
client_id: string;
|
|
22
26
|
data: string;
|
|
23
27
|
created_at: number;
|
|
24
28
|
updated_at: number;
|
|
25
29
|
};
|
|
26
|
-
|
|
30
|
+
type ArtifactRow = {
|
|
27
31
|
kind: string;
|
|
28
32
|
id: string;
|
|
29
33
|
client_id: string;
|
|
30
34
|
account_id: string | null;
|
|
31
35
|
grant_id: string | null;
|
|
36
|
+
family_id: string | null;
|
|
32
37
|
user_code: string | null;
|
|
33
38
|
payload: string;
|
|
34
39
|
consumed_at: number | null;
|
|
35
40
|
expires_at: number;
|
|
36
41
|
};
|
|
37
|
-
|
|
42
|
+
type SessionRow = {
|
|
38
43
|
id: string;
|
|
39
44
|
account_id: string;
|
|
40
45
|
auth_time: number;
|
|
@@ -45,7 +50,7 @@ export type SessionRow = {
|
|
|
45
50
|
clients: string;
|
|
46
51
|
expires_at: number;
|
|
47
52
|
};
|
|
48
|
-
|
|
53
|
+
type GrantRow = {
|
|
49
54
|
id: string;
|
|
50
55
|
account_id: string;
|
|
51
56
|
client_id: string;
|
|
@@ -55,7 +60,7 @@ export type GrantRow = {
|
|
|
55
60
|
created_at: number;
|
|
56
61
|
expires_at: number | null;
|
|
57
62
|
};
|
|
58
|
-
|
|
63
|
+
type IdentityRow = {
|
|
59
64
|
provider: string;
|
|
60
65
|
subject: string;
|
|
61
66
|
account_id: string;
|
|
@@ -63,7 +68,7 @@ export type IdentityRow = {
|
|
|
63
68
|
claims: string;
|
|
64
69
|
linked_at: number;
|
|
65
70
|
};
|
|
66
|
-
|
|
71
|
+
type RealmRow = {
|
|
67
72
|
id: string;
|
|
68
73
|
display_name: string | null;
|
|
69
74
|
enabled: number;
|
|
@@ -71,12 +76,12 @@ export type RealmRow = {
|
|
|
71
76
|
created_at: number;
|
|
72
77
|
updated_at: number;
|
|
73
78
|
};
|
|
74
|
-
|
|
79
|
+
type ReplayRow = {
|
|
75
80
|
namespace: string;
|
|
76
81
|
value: string;
|
|
77
82
|
expires_at: number;
|
|
78
83
|
};
|
|
79
|
-
|
|
84
|
+
type CredentialRow = {
|
|
80
85
|
account_id: string;
|
|
81
86
|
username: string;
|
|
82
87
|
password_hash: string;
|
|
@@ -127,4 +132,4 @@ export type TypeormAdapterOptions = {
|
|
|
127
132
|
* The queries are dialect-agnostic; the schema shipped and tested is SQLite's, as for the others.
|
|
128
133
|
*/
|
|
129
134
|
export declare const typeormAdapter: (options: TypeormAdapterOptions) => FullAdapter;
|
|
130
|
-
export type { Migration };
|
|
135
|
+
export type { ArtifactRow, ClientRow, CredentialRow, GrantRow, IdentityRow, Migration, RealmRow, ReplayRow, SessionRow };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,147 @@
|
|
|
1
|
+
import { noAccounts } from "@oidcraft/adapter";
|
|
1
2
|
import { EntitySchema, QueryFailedError } from "typeorm";
|
|
3
|
+
// ../sql/dist/rows.mjs
|
|
4
|
+
/** Never `new Date` on the raw value: a string there is read as a date, not as milliseconds. */
|
|
5
|
+
const at = (millis) => new Date(Number(millis));
|
|
6
|
+
const json = (value) => JSON.stringify(value);
|
|
7
|
+
const parse = (value) => JSON.parse(value);
|
|
8
|
+
const clientRow = (client) => ({
|
|
9
|
+
client_id: client.clientId,
|
|
10
|
+
data: json(client),
|
|
11
|
+
created_at: client.createdAt.getTime(),
|
|
12
|
+
updated_at: client.updatedAt.getTime()
|
|
13
|
+
});
|
|
14
|
+
const toClient = (row) => ({
|
|
15
|
+
...parse(row.data),
|
|
16
|
+
createdAt: at(row.created_at),
|
|
17
|
+
updatedAt: at(row.updated_at)
|
|
18
|
+
});
|
|
19
|
+
/** `user_code` is lifted out of the payload so a device's code is found by index (FR-C7). */
|
|
20
|
+
const artifactRow = (artifact) => ({
|
|
21
|
+
kind: artifact.kind,
|
|
22
|
+
id: artifact.id,
|
|
23
|
+
client_id: artifact.clientId,
|
|
24
|
+
account_id: artifact.accountId ?? null,
|
|
25
|
+
grant_id: artifact.grantId ?? null,
|
|
26
|
+
family_id: artifact.familyId ?? null,
|
|
27
|
+
user_code: artifact.payload.userCode ?? null,
|
|
28
|
+
payload: json(artifact.payload),
|
|
29
|
+
consumed_at: artifact.consumedAt ? artifact.consumedAt.getTime() : null,
|
|
30
|
+
expires_at: artifact.expiresAt.getTime()
|
|
31
|
+
});
|
|
32
|
+
const toArtifact = (row) => ({
|
|
33
|
+
id: row.id,
|
|
34
|
+
kind: row.kind,
|
|
35
|
+
clientId: row.client_id,
|
|
36
|
+
...row.account_id && { accountId: row.account_id },
|
|
37
|
+
...row.grant_id && { grantId: row.grant_id },
|
|
38
|
+
...row.family_id && { familyId: row.family_id },
|
|
39
|
+
payload: parse(row.payload),
|
|
40
|
+
...row.consumed_at && { consumedAt: at(row.consumed_at) },
|
|
41
|
+
expiresAt: at(row.expires_at)
|
|
42
|
+
});
|
|
43
|
+
const sessionRow = (session) => ({
|
|
44
|
+
id: session.id,
|
|
45
|
+
account_id: session.accountId,
|
|
46
|
+
auth_time: session.authTime.getTime(),
|
|
47
|
+
acr: session.acr ?? null,
|
|
48
|
+
amr: session.amr ? json(session.amr) : null,
|
|
49
|
+
idp: session.idp ?? null,
|
|
50
|
+
upstream_session_id: session.upstreamSessionId ?? null,
|
|
51
|
+
clients: json(session.clients),
|
|
52
|
+
expires_at: session.expiresAt.getTime()
|
|
53
|
+
});
|
|
54
|
+
const toSession = (row) => ({
|
|
55
|
+
id: row.id,
|
|
56
|
+
accountId: row.account_id,
|
|
57
|
+
authTime: at(row.auth_time),
|
|
58
|
+
...row.acr && { acr: row.acr },
|
|
59
|
+
...row.amr ? { amr: parse(row.amr) } : {},
|
|
60
|
+
...row.idp && { idp: row.idp },
|
|
61
|
+
...row.upstream_session_id && { upstreamSessionId: row.upstream_session_id },
|
|
62
|
+
clients: parse(row.clients),
|
|
63
|
+
expiresAt: at(row.expires_at)
|
|
64
|
+
});
|
|
65
|
+
const grantRow = (grant) => ({
|
|
66
|
+
id: grant.id,
|
|
67
|
+
account_id: grant.accountId,
|
|
68
|
+
client_id: grant.clientId,
|
|
69
|
+
scopes: json(grant.scopes),
|
|
70
|
+
claims: json(grant.claims),
|
|
71
|
+
resources: json(grant.resources),
|
|
72
|
+
created_at: grant.createdAt.getTime(),
|
|
73
|
+
expires_at: grant.expiresAt ? grant.expiresAt.getTime() : null
|
|
74
|
+
});
|
|
75
|
+
const toGrant = (row) => ({
|
|
76
|
+
id: row.id,
|
|
77
|
+
accountId: row.account_id,
|
|
78
|
+
clientId: row.client_id,
|
|
79
|
+
scopes: parse(row.scopes),
|
|
80
|
+
claims: parse(row.claims),
|
|
81
|
+
resources: parse(row.resources),
|
|
82
|
+
createdAt: at(row.created_at),
|
|
83
|
+
...row.expires_at && { expiresAt: at(row.expires_at) }
|
|
84
|
+
});
|
|
85
|
+
const identityRow = (identity) => ({
|
|
86
|
+
provider: identity.provider,
|
|
87
|
+
subject: identity.subject,
|
|
88
|
+
account_id: identity.accountId,
|
|
89
|
+
email: identity.email ?? null,
|
|
90
|
+
claims: json(identity.claims),
|
|
91
|
+
linked_at: identity.linkedAt.getTime()
|
|
92
|
+
});
|
|
93
|
+
const toIdentity = (row) => ({
|
|
94
|
+
accountId: row.account_id,
|
|
95
|
+
provider: row.provider,
|
|
96
|
+
subject: row.subject,
|
|
97
|
+
...row.email && { email: row.email },
|
|
98
|
+
claims: parse(row.claims),
|
|
99
|
+
linkedAt: at(row.linked_at)
|
|
100
|
+
});
|
|
101
|
+
const credentialRow = (credential) => ({
|
|
102
|
+
account_id: credential.accountId,
|
|
103
|
+
username: credential.username,
|
|
104
|
+
password_hash: credential.passwordHash,
|
|
105
|
+
claims: json(credential.claims),
|
|
106
|
+
totp_secret: credential.totp?.secret ?? null,
|
|
107
|
+
totp_confirmed_at: credential.totp?.confirmedAt?.getTime() ?? null,
|
|
108
|
+
recovery_codes: credential.recoveryCodes ? json(credential.recoveryCodes) : null,
|
|
109
|
+
failed_attempts: credential.failedAttempts,
|
|
110
|
+
locked_until: credential.lockedUntil?.getTime() ?? null,
|
|
111
|
+
created_at: credential.createdAt.getTime(),
|
|
112
|
+
updated_at: credential.updatedAt.getTime()
|
|
113
|
+
});
|
|
114
|
+
const toCredential = (row) => ({
|
|
115
|
+
accountId: row.account_id,
|
|
116
|
+
username: row.username,
|
|
117
|
+
passwordHash: row.password_hash,
|
|
118
|
+
claims: parse(row.claims),
|
|
119
|
+
...row.totp_secret && { totp: {
|
|
120
|
+
secret: row.totp_secret,
|
|
121
|
+
...row.totp_confirmed_at && { confirmedAt: at(row.totp_confirmed_at) }
|
|
122
|
+
} },
|
|
123
|
+
...row.recovery_codes ? { recoveryCodes: parse(row.recovery_codes) } : {},
|
|
124
|
+
failedAttempts: Number(row.failed_attempts),
|
|
125
|
+
...row.locked_until && { lockedUntil: at(row.locked_until) },
|
|
126
|
+
createdAt: at(row.created_at),
|
|
127
|
+
updatedAt: at(row.updated_at)
|
|
128
|
+
});
|
|
129
|
+
const realmRow = (realm) => ({
|
|
130
|
+
id: realm.id,
|
|
131
|
+
display_name: realm.displayName ?? null,
|
|
132
|
+
enabled: realm.enabled ? 1 : 0,
|
|
133
|
+
settings: json(realm.settings),
|
|
134
|
+
created_at: realm.createdAt.getTime(),
|
|
135
|
+
updated_at: realm.updatedAt.getTime()
|
|
136
|
+
});
|
|
137
|
+
const toRealm = (row) => ({
|
|
138
|
+
id: row.id,
|
|
139
|
+
...row.display_name && { displayName: row.display_name },
|
|
140
|
+
enabled: Boolean(Number(row.enabled)),
|
|
141
|
+
settings: parse(row.settings),
|
|
142
|
+
createdAt: at(row.created_at),
|
|
143
|
+
updatedAt: at(row.updated_at)
|
|
144
|
+
});
|
|
2
145
|
// ../sql/dist/postgres.mjs
|
|
3
146
|
/**
|
|
4
147
|
* The same tables as `SQLITE_MIGRATIONS`, with the same ids, for Postgres (FR-A4). Milliseconds are
|
|
@@ -36,6 +179,18 @@ const POSTGRES_MIGRATIONS = [
|
|
|
36
179
|
{
|
|
37
180
|
id: "0003_realms",
|
|
38
181
|
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)"]
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: "0004_indexes",
|
|
185
|
+
statements: [
|
|
186
|
+
"create index oidc_artifacts_client_idx on oidc_artifacts (client_id)",
|
|
187
|
+
"create index oidc_grants_client_idx on oidc_grants (client_id)",
|
|
188
|
+
"create index oidc_sessions_expiry_idx on oidc_sessions (expires_at)"
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: "0005_families",
|
|
193
|
+
statements: ["alter table oidc_artifacts add column family_id text", "create index oidc_artifacts_family_idx on oidc_artifacts (family_id)"]
|
|
39
194
|
}
|
|
40
195
|
];
|
|
41
196
|
// ../sql/dist/sqlite.mjs
|
|
@@ -74,6 +229,18 @@ const SQLITE_MIGRATIONS = [
|
|
|
74
229
|
{
|
|
75
230
|
id: "0003_realms",
|
|
76
231
|
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)"]
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: "0004_indexes",
|
|
235
|
+
statements: [
|
|
236
|
+
"create index oidc_artifacts_client_idx on oidc_artifacts (client_id)",
|
|
237
|
+
"create index oidc_grants_client_idx on oidc_grants (client_id)",
|
|
238
|
+
"create index oidc_sessions_expiry_idx on oidc_sessions (expires_at)"
|
|
239
|
+
]
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: "0005_families",
|
|
243
|
+
statements: ["alter table oidc_artifacts add column family_id text", "create index oidc_artifacts_family_idx on oidc_artifacts (family_id)"]
|
|
77
244
|
}
|
|
78
245
|
];
|
|
79
246
|
// src/schema.ts
|
|
@@ -109,6 +276,7 @@ const ArtifactEntity = new EntitySchema({
|
|
|
109
276
|
client_id: text(),
|
|
110
277
|
account_id: text({ nullable: true }),
|
|
111
278
|
grant_id: text({ nullable: true }),
|
|
279
|
+
family_id: text({ nullable: true }),
|
|
112
280
|
user_code: text({ nullable: true }),
|
|
113
281
|
payload: text(),
|
|
114
282
|
consumed_at: millis({ nullable: true }),
|
|
@@ -126,6 +294,14 @@ const ArtifactEntity = new EntitySchema({
|
|
|
126
294
|
{
|
|
127
295
|
name: "oidc_artifacts_expiry_idx",
|
|
128
296
|
columns: ["expires_at"]
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
name: "oidc_artifacts_client_idx",
|
|
300
|
+
columns: ["client_id"]
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: "oidc_artifacts_family_idx",
|
|
304
|
+
columns: ["family_id"]
|
|
129
305
|
}
|
|
130
306
|
]
|
|
131
307
|
});
|
|
@@ -143,13 +319,20 @@ const SessionEntity = new EntitySchema({
|
|
|
143
319
|
clients: text(),
|
|
144
320
|
expires_at: millis()
|
|
145
321
|
},
|
|
146
|
-
indices: [
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
322
|
+
indices: [
|
|
323
|
+
{
|
|
324
|
+
name: "oidc_sessions_account_idx",
|
|
325
|
+
columns: ["account_id"]
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: "oidc_sessions_upstream_idx",
|
|
329
|
+
columns: ["idp", "upstream_session_id"]
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
name: "oidc_sessions_expiry_idx",
|
|
333
|
+
columns: ["expires_at"]
|
|
334
|
+
}
|
|
335
|
+
]
|
|
153
336
|
});
|
|
154
337
|
const GrantEntity = new EntitySchema({
|
|
155
338
|
name: "oidc_grants",
|
|
@@ -168,6 +351,9 @@ const GrantEntity = new EntitySchema({
|
|
|
168
351
|
name: "oidc_grants_account_client_idx",
|
|
169
352
|
columns: ["account_id", "client_id"],
|
|
170
353
|
unique: true
|
|
354
|
+
}, {
|
|
355
|
+
name: "oidc_grants_client_idx",
|
|
356
|
+
columns: ["client_id"]
|
|
171
357
|
}]
|
|
172
358
|
});
|
|
173
359
|
const IdentityEntity = new EntitySchema({
|
|
@@ -271,95 +457,6 @@ const TYPEORM_SQLITE_MIGRATIONS = SQLITE_MIGRATIONS.map(asTypeormMigration);
|
|
|
271
457
|
const TYPEORM_POSTGRES_MIGRATIONS = POSTGRES_MIGRATIONS.map(asTypeormMigration);
|
|
272
458
|
// src/index.ts
|
|
273
459
|
const now = () => Date.now();
|
|
274
|
-
const json = (value) => JSON.stringify(value);
|
|
275
|
-
const parse = (value) => JSON.parse(value);
|
|
276
|
-
const toArtifact = (row) => ({
|
|
277
|
-
id: row.id,
|
|
278
|
-
kind: row.kind,
|
|
279
|
-
clientId: row.client_id,
|
|
280
|
-
...row.account_id && { accountId: row.account_id },
|
|
281
|
-
...row.grant_id && { grantId: row.grant_id },
|
|
282
|
-
payload: parse(row.payload),
|
|
283
|
-
...row.consumed_at && { consumedAt: new Date(row.consumed_at) },
|
|
284
|
-
expiresAt: new Date(row.expires_at)
|
|
285
|
-
});
|
|
286
|
-
const toSession = (row) => ({
|
|
287
|
-
id: row.id,
|
|
288
|
-
accountId: row.account_id,
|
|
289
|
-
authTime: new Date(row.auth_time),
|
|
290
|
-
...row.acr && { acr: row.acr },
|
|
291
|
-
...row.amr ? { amr: parse(row.amr) } : {},
|
|
292
|
-
...row.idp && { idp: row.idp },
|
|
293
|
-
...row.upstream_session_id && { upstreamSessionId: row.upstream_session_id },
|
|
294
|
-
clients: parse(row.clients),
|
|
295
|
-
expiresAt: new Date(row.expires_at)
|
|
296
|
-
});
|
|
297
|
-
const toGrant = (row) => ({
|
|
298
|
-
id: row.id,
|
|
299
|
-
accountId: row.account_id,
|
|
300
|
-
clientId: row.client_id,
|
|
301
|
-
scopes: parse(row.scopes),
|
|
302
|
-
claims: parse(row.claims),
|
|
303
|
-
resources: parse(row.resources),
|
|
304
|
-
createdAt: new Date(row.created_at),
|
|
305
|
-
...row.expires_at && { expiresAt: new Date(row.expires_at) }
|
|
306
|
-
});
|
|
307
|
-
const credentialRow = (credential) => ({
|
|
308
|
-
account_id: credential.accountId,
|
|
309
|
-
username: credential.username,
|
|
310
|
-
password_hash: credential.passwordHash,
|
|
311
|
-
claims: json(credential.claims),
|
|
312
|
-
totp_secret: credential.totp?.secret ?? null,
|
|
313
|
-
totp_confirmed_at: credential.totp?.confirmedAt?.getTime() ?? null,
|
|
314
|
-
recovery_codes: credential.recoveryCodes ? json(credential.recoveryCodes) : null,
|
|
315
|
-
failed_attempts: credential.failedAttempts,
|
|
316
|
-
locked_until: credential.lockedUntil?.getTime() ?? null,
|
|
317
|
-
created_at: credential.createdAt.getTime(),
|
|
318
|
-
updated_at: credential.updatedAt.getTime()
|
|
319
|
-
});
|
|
320
|
-
const toCredential = (row) => ({
|
|
321
|
-
accountId: row.account_id,
|
|
322
|
-
username: row.username,
|
|
323
|
-
passwordHash: row.password_hash,
|
|
324
|
-
claims: parse(row.claims),
|
|
325
|
-
...row.totp_secret && { totp: {
|
|
326
|
-
secret: row.totp_secret,
|
|
327
|
-
...row.totp_confirmed_at && { confirmedAt: new Date(row.totp_confirmed_at) }
|
|
328
|
-
} },
|
|
329
|
-
...row.recovery_codes ? { recoveryCodes: parse(row.recovery_codes) } : {},
|
|
330
|
-
failedAttempts: row.failed_attempts,
|
|
331
|
-
...row.locked_until && { lockedUntil: new Date(row.locked_until) },
|
|
332
|
-
createdAt: new Date(row.created_at),
|
|
333
|
-
updatedAt: new Date(row.updated_at)
|
|
334
|
-
});
|
|
335
|
-
const toIdentity = (row) => ({
|
|
336
|
-
accountId: row.account_id,
|
|
337
|
-
provider: row.provider,
|
|
338
|
-
subject: row.subject,
|
|
339
|
-
...row.email && { email: row.email },
|
|
340
|
-
claims: parse(row.claims),
|
|
341
|
-
linkedAt: new Date(row.linked_at)
|
|
342
|
-
});
|
|
343
|
-
const realmRow = (realm) => ({
|
|
344
|
-
id: realm.id,
|
|
345
|
-
display_name: realm.displayName ?? null,
|
|
346
|
-
enabled: realm.enabled ? 1 : 0,
|
|
347
|
-
settings: json(realm.settings),
|
|
348
|
-
created_at: realm.createdAt.getTime(),
|
|
349
|
-
updated_at: realm.updatedAt.getTime()
|
|
350
|
-
});
|
|
351
|
-
const toRealm = (row) => ({
|
|
352
|
-
id: row.id,
|
|
353
|
-
...row.display_name && { displayName: row.display_name },
|
|
354
|
-
enabled: Boolean(row.enabled),
|
|
355
|
-
settings: parse(row.settings),
|
|
356
|
-
createdAt: new Date(row.created_at),
|
|
357
|
-
updatedAt: new Date(row.updated_at)
|
|
358
|
-
});
|
|
359
|
-
const noAccounts = {
|
|
360
|
-
async find() {},
|
|
361
|
-
async claims() {}
|
|
362
|
-
};
|
|
363
460
|
const upsert = async (repository, row, conflict, overwrite) => {
|
|
364
461
|
const columns = overwrite ?? Object.keys(row).filter((column) => !conflict.includes(column));
|
|
365
462
|
await repository.createQueryBuilder().insert().values(row).orUpdate(columns, conflict).execute();
|
|
@@ -396,21 +493,12 @@ const typeormAdapter = (options) => {
|
|
|
396
493
|
const realms = dataSource.getRepository(RealmEntity);
|
|
397
494
|
const artifacts = {
|
|
398
495
|
async upsert(artifact) {
|
|
399
|
-
const row =
|
|
400
|
-
kind: artifact.kind,
|
|
401
|
-
id: artifact.id,
|
|
402
|
-
client_id: artifact.clientId,
|
|
403
|
-
account_id: artifact.accountId ?? null,
|
|
404
|
-
grant_id: artifact.grantId ?? null,
|
|
405
|
-
user_code: artifact.payload.userCode ?? null,
|
|
406
|
-
payload: json(artifact.payload),
|
|
407
|
-
consumed_at: artifact.consumedAt ? artifact.consumedAt.getTime() : null,
|
|
408
|
-
expires_at: artifact.expiresAt.getTime()
|
|
409
|
-
};
|
|
496
|
+
const row = artifactRow(artifact);
|
|
410
497
|
await upsert(artifactRows, row, ["kind", "id"], [
|
|
411
498
|
"client_id",
|
|
412
499
|
"account_id",
|
|
413
500
|
"grant_id",
|
|
501
|
+
"family_id",
|
|
414
502
|
"user_code",
|
|
415
503
|
"payload",
|
|
416
504
|
"expires_at"
|
|
@@ -447,6 +535,12 @@ const typeormAdapter = (options) => {
|
|
|
447
535
|
async revokeByGrantId(grantId) {
|
|
448
536
|
await artifactRows.delete({ grant_id: grantId });
|
|
449
537
|
},
|
|
538
|
+
async revokeByFamilyId(familyId) {
|
|
539
|
+
await artifactRows.delete({ family_id: familyId });
|
|
540
|
+
},
|
|
541
|
+
async revokeByClientId(clientId) {
|
|
542
|
+
await artifactRows.delete({ client_id: clientId });
|
|
543
|
+
},
|
|
450
544
|
async prune(before, limit) {
|
|
451
545
|
const doomed = await artifactRows.createQueryBuilder("a").select(["a.kind", "a.id"]).where("a.expires_at <= :before", { before: before.getTime() }).limit(limit).getMany();
|
|
452
546
|
for (const row of doomed) await artifacts.destroy(row.kind, row.id);
|
|
@@ -458,30 +552,25 @@ const typeormAdapter = (options) => {
|
|
|
458
552
|
async find(clientId) {
|
|
459
553
|
const row = await clients.findOneBy({ client_id: clientId });
|
|
460
554
|
if (!row) return void 0;
|
|
461
|
-
return
|
|
462
|
-
...parse(row.data),
|
|
463
|
-
createdAt: new Date(row.created_at),
|
|
464
|
-
updatedAt: new Date(row.updated_at)
|
|
465
|
-
};
|
|
555
|
+
return toClient(row);
|
|
466
556
|
},
|
|
467
557
|
async upsert(client) {
|
|
468
|
-
|
|
469
|
-
client_id: client.clientId,
|
|
470
|
-
data: json(client),
|
|
471
|
-
created_at: client.createdAt.getTime(),
|
|
472
|
-
updated_at: client.updatedAt.getTime()
|
|
473
|
-
};
|
|
474
|
-
await upsert(clients, row, ["client_id"], ["data", "updated_at"]);
|
|
558
|
+
await upsert(clients, clientRow(client), ["client_id"], ["data", "updated_at"]);
|
|
475
559
|
},
|
|
476
560
|
async destroy(clientId) {
|
|
477
561
|
await clients.delete({ client_id: clientId });
|
|
478
562
|
},
|
|
479
|
-
async list() {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
563
|
+
async list(cursor, limit) {
|
|
564
|
+
const query = clients.createQueryBuilder("c").orderBy("c.client_id");
|
|
565
|
+
if (cursor !== void 0) query.where("c.client_id > :cursor", { cursor });
|
|
566
|
+
if (limit !== void 0) query.limit(limit + 1);
|
|
567
|
+
const rows = await query.getMany();
|
|
568
|
+
const more = limit !== void 0 && rows.length > limit;
|
|
569
|
+
const shown = more ? rows.slice(0, limit) : rows;
|
|
570
|
+
return {
|
|
571
|
+
clients: shown.map(toClient),
|
|
572
|
+
...more && { cursor: shown.at(-1)?.client_id }
|
|
573
|
+
};
|
|
485
574
|
}
|
|
486
575
|
},
|
|
487
576
|
artifacts,
|
|
@@ -500,24 +589,14 @@ const typeormAdapter = (options) => {
|
|
|
500
589
|
}).getMany()).map(toSession);
|
|
501
590
|
},
|
|
502
591
|
async findByUpstreamSession(provider, upstreamSessionId) {
|
|
503
|
-
return (await sessions.
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
592
|
+
return (await sessions.createQueryBuilder("s").where("s.idp = :provider and s.upstream_session_id = :upstreamSessionId and s.expires_at > :now", {
|
|
593
|
+
provider,
|
|
594
|
+
upstreamSessionId,
|
|
595
|
+
now: now()
|
|
596
|
+
}).getMany()).map(toSession);
|
|
507
597
|
},
|
|
508
598
|
async upsert(session) {
|
|
509
|
-
|
|
510
|
-
id: session.id,
|
|
511
|
-
account_id: session.accountId,
|
|
512
|
-
auth_time: session.authTime.getTime(),
|
|
513
|
-
acr: session.acr ?? null,
|
|
514
|
-
amr: session.amr ? json(session.amr) : null,
|
|
515
|
-
idp: session.idp ?? null,
|
|
516
|
-
upstream_session_id: session.upstreamSessionId ?? null,
|
|
517
|
-
clients: json(session.clients),
|
|
518
|
-
expires_at: session.expiresAt.getTime()
|
|
519
|
-
};
|
|
520
|
-
await upsert(sessions, row, ["id"]);
|
|
599
|
+
await upsert(sessions, sessionRow(session), ["id"]);
|
|
521
600
|
},
|
|
522
601
|
async addClient(id, clientId) {
|
|
523
602
|
for (let attempt = 0; attempt < 64; attempt++) {
|
|
@@ -537,6 +616,14 @@ const typeormAdapter = (options) => {
|
|
|
537
616
|
},
|
|
538
617
|
async destroy(id) {
|
|
539
618
|
await sessions.delete({ id });
|
|
619
|
+
},
|
|
620
|
+
async prune(before, limit) {
|
|
621
|
+
const doomed = await sessions.createQueryBuilder("s").select(["s.id"]).where("s.expires_at <= :before", { before: before.getTime() }).limit(limit).getMany();
|
|
622
|
+
for (const row of doomed) await sessions.createQueryBuilder().delete().where("id = :id and expires_at <= :before", {
|
|
623
|
+
id: row.id,
|
|
624
|
+
before: before.getTime()
|
|
625
|
+
}).execute();
|
|
626
|
+
return doomed.length;
|
|
540
627
|
}
|
|
541
628
|
},
|
|
542
629
|
grants: {
|
|
@@ -555,20 +642,18 @@ const typeormAdapter = (options) => {
|
|
|
555
642
|
return (await grants.findBy({ account_id: accountId })).map(toGrant);
|
|
556
643
|
},
|
|
557
644
|
async upsert(grant) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
resources: json(grant.resources),
|
|
565
|
-
created_at: grant.createdAt.getTime(),
|
|
566
|
-
expires_at: grant.expiresAt ? grant.expiresAt.getTime() : null
|
|
567
|
-
};
|
|
568
|
-
await upsert(grants, row, ["id"]);
|
|
645
|
+
await upsert(grants, grantRow(grant), ["account_id", "client_id"], [
|
|
646
|
+
"scopes",
|
|
647
|
+
"claims",
|
|
648
|
+
"resources",
|
|
649
|
+
"expires_at"
|
|
650
|
+
]);
|
|
569
651
|
},
|
|
570
652
|
async destroy(id) {
|
|
571
653
|
await grants.delete({ id });
|
|
654
|
+
},
|
|
655
|
+
async destroyByClientId(clientId) {
|
|
656
|
+
await grants.delete({ client_id: clientId });
|
|
572
657
|
}
|
|
573
658
|
},
|
|
574
659
|
accounts: options.accounts ?? noAccounts,
|
|
@@ -610,21 +695,31 @@ const typeormAdapter = (options) => {
|
|
|
610
695
|
}
|
|
611
696
|
},
|
|
612
697
|
keys: options.keys,
|
|
613
|
-
replay: {
|
|
614
|
-
|
|
615
|
-
namespace,
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
698
|
+
replay: {
|
|
699
|
+
async claim(namespace, value, ttl) {
|
|
700
|
+
await replay.createQueryBuilder().delete().where("namespace = :namespace and value = :value and expires_at <= :now", {
|
|
701
|
+
namespace,
|
|
702
|
+
value,
|
|
703
|
+
now: now()
|
|
704
|
+
}).execute();
|
|
705
|
+
return insertIfAbsent(replay, {
|
|
706
|
+
namespace,
|
|
707
|
+
value,
|
|
708
|
+
expires_at: now() + ttl * 1e3
|
|
709
|
+
}, async () => replay.existsBy({
|
|
710
|
+
namespace,
|
|
711
|
+
value
|
|
712
|
+
}));
|
|
713
|
+
},
|
|
714
|
+
async prune(before, limit) {
|
|
715
|
+
const doomed = await replay.createQueryBuilder("r").select(["r.namespace", "r.value"]).where("r.expires_at <= :before", { before: before.getTime() }).limit(limit).getMany();
|
|
716
|
+
for (const row of doomed) await replay.createQueryBuilder().delete().where("namespace = :namespace and value = :value and expires_at <= :before", {
|
|
717
|
+
...row,
|
|
718
|
+
before: before.getTime()
|
|
719
|
+
}).execute();
|
|
720
|
+
return doomed.length;
|
|
721
|
+
}
|
|
722
|
+
},
|
|
628
723
|
identities: {
|
|
629
724
|
async find(provider, subject) {
|
|
630
725
|
const row = await identities.findOneBy({
|
|
@@ -637,15 +732,7 @@ const typeormAdapter = (options) => {
|
|
|
637
732
|
return (await identities.findBy({ account_id: accountId })).map(toIdentity);
|
|
638
733
|
},
|
|
639
734
|
async upsert(identity) {
|
|
640
|
-
|
|
641
|
-
provider: identity.provider,
|
|
642
|
-
subject: identity.subject,
|
|
643
|
-
account_id: identity.accountId,
|
|
644
|
-
email: identity.email ?? null,
|
|
645
|
-
claims: json(identity.claims),
|
|
646
|
-
linked_at: identity.linkedAt.getTime()
|
|
647
|
-
};
|
|
648
|
-
await upsert(identities, row, ["provider", "subject"]);
|
|
735
|
+
await upsert(identities, identityRow(identity), ["provider", "subject"]);
|
|
649
736
|
},
|
|
650
737
|
async destroy(provider, subject) {
|
|
651
738
|
await identities.delete({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oidcraft/typeorm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A TypeORM storage adapter for @oidcraft/provider, over a DataSource 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
|
"typeorm": ">=1.1"
|
|
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
|
"pg": "^8.23.1",
|