@ttoss/auth-postgresdb 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024, Terezinha Tech Operations (ttoss)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # @ttoss/auth-postgresdb
2
+
3
+ Durable Postgres persistence for the OAuth 2.1 authorization server in [`@ttoss/auth-core`](https://ttoss.dev/docs/modules/packages/auth-core): the Sequelize models for the RFC data model, plus the store adapters `createOAuthHandlers`, `createRefreshRotation`, and `createRedirectConsentOnAuthorize` expect.
4
+
5
+ `@ttoss/auth-core` ships `Map`-backed stores for tests and local development; this package is what production swaps in behind the same interfaces, without reaching around your ORM to inject a raw `pg` query runner.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pnpm add @ttoss/auth-postgresdb @ttoss/auth-core @ttoss/postgresdb
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Register `oauthModels` alongside your own models so `ttoss-postgresdb sync` and `erd` manage these tables like any other, then build the stores from the `db` handle:
16
+
17
+ ```typescript
18
+ import {
19
+ createPostgresdbOAuthStores,
20
+ oauthModels,
21
+ } from '@ttoss/auth-postgresdb';
22
+ import { initialize } from '@ttoss/postgresdb';
23
+
24
+ import { User } from './models/User';
25
+
26
+ export const db = await initialize({ models: { ...oauthModels, User } });
27
+
28
+ export const { clientStore, authCodeStore, consentStore, refreshTokenStore } =
29
+ createPostgresdbOAuthStores({ db });
30
+ ```
31
+
32
+ The stores drop straight into the OAuth server:
33
+
34
+ ```typescript
35
+ import { createRefreshRotation } from '@ttoss/auth-core';
36
+ import { oauthServer } from '@ttoss/http-server-auth';
37
+
38
+ const refresh = createRefreshRotation({ store: refreshTokenStore });
39
+
40
+ const authServer = oauthServer({
41
+ issuer: 'https://api.example.com',
42
+ clientStore,
43
+ authCodeStore,
44
+ onRefreshToken: refresh.onRefreshToken,
45
+ // …issueTokens, onAuthorize…
46
+ });
47
+ ```
48
+
49
+ Each store is also exported on its own (`createClientStore`, `createAuthCodeStore`, `createConsentStore`, `createRefreshTokenStore`) for apps that register only some of the models.
50
+
51
+ ## Schema
52
+
53
+ | Model | Table | Primary key |
54
+ | ------------------- | ---------------------- | ---------------- |
55
+ | `OAuthClient` | `oauth_clients` | `client_id` |
56
+ | `OAuthAuthCode` | `oauth_auth_codes` | `code_hash` |
57
+ | `OAuthConsent` | `oauth_consents` | `code_challenge` |
58
+ | `OAuthRefreshToken` | `oauth_refresh_tokens` | `token_hash` |
59
+
60
+ Credentials are stored by SHA-256 hash, never in plaintext, so a database dump yields nothing replayable. `OAuthClient` keeps the registered RFC 7591 fields in their own columns and any additional submitted metadata in a `metadata` JSONB column, so a registration document round-trips unchanged.
61
+
62
+ ## Two traps these adapters absorb
63
+
64
+ **Authorization codes are hashed at rest.** `AuthCodeStore.get` is handed the plaintext code, but a code travels through a browser redirect and a client's URL bar. The engine never compares the returned `code` against anything — it reads only `clientId`, `redirectUri`, `codeChallenge`, `scopes`, `subject`, and `expiresAt` — so the adapter hashes to find the row and echoes the presented value back.
65
+
66
+ **A live refresh token reports no `consumedAt` at all.** `createRefreshRotation` treats `stored.consumedAt !== undefined` as reuse. A nullable timestamp column reads back as `null`, which is `!== undefined`, so a naive adapter makes every live token look consumed: the first refresh is treated as a replay and revokes the owner's entire token set — "refresh works once, then the client must re-authorize forever". The adapter omits the key instead of setting it to `null`.
67
+
68
+ ## Consent
69
+
70
+ `consentStore` satisfies the `ConsentGrantStore` that `createRedirectConsentOnAuthorize` consumes, and adds `saveConsentGrant` for the write your consent page performs on approval. It is the single-use handoff keyed by the PKCE `code_challenge` — not a durable "user X trusts client Y" record, which is an app-level authorization decision and belongs in your own schema.
71
+
72
+ ## Related
73
+
74
+ - [OAuth Authorization Server](https://ttoss.dev/docs/engineering/guidelines/oauth-authorization-server) — the full server setup and the ttoss-vs-app responsibility split
75
+ - [MCP Server with OAuth](https://ttoss.dev/docs/engineering/guidelines/mcp-server-oauth) — the MCP application of these primitives
76
+ - [`@ttoss/postgresdb`](https://ttoss.dev/docs/modules/packages/postgresdb) — `initialize`, and the `sync` / `erd` CLI
package/dist/index.cjs ADDED
@@ -0,0 +1,507 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ Object.defineProperty(exports, Symbol.toStringTag, {
3
+ value: 'Module'
4
+ });
5
+ let _ttoss_auth_core = require("@ttoss/auth-core");
6
+ let _ttoss_postgresdb = require("@ttoss/postgresdb");
7
+
8
+ //#region src/stores/createAuthCodeStore.ts
9
+ /**
10
+ * Creates an {@link AuthCodeStore} backed by the `oauth_auth_codes` table,
11
+ * storing codes by SHA-256 hash.
12
+ *
13
+ * The engine hands the store the plaintext code on every call and never compares
14
+ * the returned `code` against anything — it reads only `clientId`,
15
+ * `redirectUri`, `codeChallenge`, `scopes`, `subject`, and `expiresAt`. So the
16
+ * adapter hashes to find the row and echoes the presented value back, and a
17
+ * database dump yields no replayable codes.
18
+ */
19
+ var createAuthCodeStore = ({
20
+ model
21
+ }) => {
22
+ return {
23
+ save: async code => {
24
+ await model.upsert({
25
+ codeHash: (0, _ttoss_auth_core.hashAuthorizationCode)({
26
+ code: code.code
27
+ }),
28
+ clientId: code.clientId,
29
+ redirectUri: code.redirectUri,
30
+ codeChallenge: code.codeChallenge,
31
+ scopes: code.scopes,
32
+ subject: code.subject,
33
+ expiresAt: new Date(code.expiresAt)
34
+ });
35
+ },
36
+ get: async code => {
37
+ const row = await model.findByPk((0, _ttoss_auth_core.hashAuthorizationCode)({
38
+ code
39
+ }));
40
+ if (!row) return;
41
+ return {
42
+ code,
43
+ clientId: row.clientId,
44
+ redirectUri: row.redirectUri,
45
+ codeChallenge: row.codeChallenge,
46
+ scopes: row.scopes,
47
+ subject: row.subject,
48
+ expiresAt: row.expiresAt.getTime()
49
+ };
50
+ },
51
+ delete: async code => {
52
+ await model.destroy({
53
+ where: {
54
+ codeHash: (0, _ttoss_auth_core.hashAuthorizationCode)({
55
+ code
56
+ })
57
+ }
58
+ });
59
+ }
60
+ };
61
+ };
62
+
63
+ //#endregion
64
+ //#region src/stores/createClientStore.ts
65
+ /**
66
+ * Registration fields that have their own column. Everything else a client
67
+ * submits goes to `metadata`, so the document round-trips unchanged.
68
+ */
69
+ var COLUMN_FIELDS = ["client_id", "client_secret", "client_name", "redirect_uris", "grant_types", "response_types", "token_endpoint_auth_method", "scope", "client_id_issued_at"];
70
+ var toRecord = row => {
71
+ return {
72
+ ...row.metadata,
73
+ client_id: row.clientId,
74
+ redirect_uris: row.redirectUris,
75
+ ...(row.clientSecret !== null && {
76
+ client_secret: row.clientSecret
77
+ }),
78
+ ...(row.clientName !== null && {
79
+ client_name: row.clientName
80
+ }),
81
+ ...(row.grantTypes !== null && {
82
+ grant_types: row.grantTypes
83
+ }),
84
+ ...(row.responseTypes !== null && {
85
+ response_types: row.responseTypes
86
+ }),
87
+ ...(row.tokenEndpointAuthMethod !== null && {
88
+ token_endpoint_auth_method: row.tokenEndpointAuthMethod
89
+ }),
90
+ ...(row.scope !== null && {
91
+ scope: row.scope
92
+ }),
93
+ ...(row.clientIdIssuedAt !== null && {
94
+ client_id_issued_at: Number(row.clientIdIssuedAt)
95
+ })
96
+ };
97
+ };
98
+ var toMetadata = client => {
99
+ const metadata = {};
100
+ for (const [key, value] of Object.entries(client)) if (!COLUMN_FIELDS.includes(key)) metadata[key] = value;
101
+ return metadata;
102
+ };
103
+ /**
104
+ * Creates a {@link ClientStore} backed by the `oauth_clients` table.
105
+ *
106
+ * `register` upserts, so re-registering an existing `client_id` replaces the
107
+ * stored document rather than failing on the primary key.
108
+ */
109
+ var createClientStore = ({
110
+ model
111
+ }) => {
112
+ return {
113
+ get: async clientId => {
114
+ const row = await model.findByPk(clientId);
115
+ return row ? toRecord(row) : void 0;
116
+ },
117
+ register: async client => {
118
+ await model.upsert({
119
+ clientId: client.client_id,
120
+ clientSecret: client.client_secret ?? null,
121
+ clientName: client.client_name ?? null,
122
+ redirectUris: client.redirect_uris,
123
+ grantTypes: client.grant_types ?? null,
124
+ responseTypes: client.response_types ?? null,
125
+ tokenEndpointAuthMethod: client.token_endpoint_auth_method ?? null,
126
+ scope: client.scope ?? null,
127
+ clientIdIssuedAt: client.client_id_issued_at ?? null,
128
+ metadata: toMetadata(client)
129
+ });
130
+ }
131
+ };
132
+ };
133
+
134
+ //#endregion
135
+ //#region src/stores/createConsentStore.ts
136
+ /**
137
+ * Creates a consent store backed by the `oauth_consents` table, for use with
138
+ * `createRedirectConsentOnAuthorize`.
139
+ *
140
+ * Reads and deletes satisfy `ConsentGrantStore`; `saveConsentGrant` covers the
141
+ * write the consent page performs. Grants are single-use — the `onAuthorize`
142
+ * hook deletes each one as it consumes it.
143
+ */
144
+ var createConsentStore = ({
145
+ model
146
+ }) => {
147
+ return {
148
+ saveConsentGrant: async ({
149
+ codeChallenge,
150
+ subject,
151
+ scopes,
152
+ expiresAt
153
+ }) => {
154
+ await model.upsert({
155
+ codeChallenge,
156
+ subject,
157
+ scopes,
158
+ expiresAt: new Date(expiresAt)
159
+ });
160
+ },
161
+ getConsentGrant: async ({
162
+ codeChallenge
163
+ }) => {
164
+ const row = await model.findByPk(codeChallenge);
165
+ if (!row) return;
166
+ return {
167
+ subject: row.subject,
168
+ scopes: row.scopes,
169
+ expiresAt: row.expiresAt.getTime()
170
+ };
171
+ },
172
+ deleteConsentGrant: async ({
173
+ codeChallenge
174
+ }) => {
175
+ await model.destroy({
176
+ where: {
177
+ codeChallenge
178
+ }
179
+ });
180
+ }
181
+ };
182
+ };
183
+
184
+ //#endregion
185
+ //#region src/stores/createRefreshTokenStore.ts
186
+ /**
187
+ * Creates a {@link RefreshTokenStore} backed by the `oauth_refresh_tokens`
188
+ * table, keyed by token hash and by the `(clientId, subject)` owner that
189
+ * `deleteByOwner` revokes on reuse detection.
190
+ */
191
+ var createRefreshTokenStore = ({
192
+ model
193
+ }) => {
194
+ return {
195
+ save: async token => {
196
+ await model.upsert({
197
+ tokenHash: token.tokenHash,
198
+ clientId: token.clientId,
199
+ subject: token.subject,
200
+ scopes: token.scopes,
201
+ expiresAt: new Date(token.expiresAt),
202
+ consumedAt: token.consumedAt === void 0 ? null : new Date(token.consumedAt)
203
+ });
204
+ },
205
+ get: async tokenHash => {
206
+ const row = await model.findByPk(tokenHash);
207
+ if (!row) return;
208
+ return {
209
+ tokenHash: row.tokenHash,
210
+ clientId: row.clientId,
211
+ subject: row.subject,
212
+ scopes: row.scopes,
213
+ expiresAt: row.expiresAt.getTime(),
214
+ /**
215
+ * The key is omitted, not set to `null`. Rotation tests
216
+ * `stored.consumedAt !== undefined` to detect reuse, and a nullable
217
+ * timestamp column reads back as `null` — which would make every live
218
+ * token look consumed, so the first refresh would be treated as a
219
+ * replay and revoke the owner's entire token set.
220
+ */
221
+ ...(row.consumedAt !== null && {
222
+ consumedAt: row.consumedAt.getTime()
223
+ })
224
+ };
225
+ },
226
+ delete: async tokenHash => {
227
+ await model.destroy({
228
+ where: {
229
+ tokenHash
230
+ }
231
+ });
232
+ },
233
+ deleteByOwner: async ({
234
+ clientId,
235
+ subject
236
+ }) => {
237
+ await model.destroy({
238
+ where: {
239
+ clientId,
240
+ subject
241
+ }
242
+ });
243
+ }
244
+ };
245
+ };
246
+
247
+ //#endregion
248
+ //#region src/createPostgresdbOAuthStores.ts
249
+ /**
250
+ * Creates every durable OAuth store from a `@ttoss/postgresdb` `db` handle.
251
+ *
252
+ * The stores are mechanical adapters between the `@ttoss/auth-core` store
253
+ * contracts and Sequelize, so an app that already uses `@ttoss/postgresdb` does
254
+ * not have to write them — nor reach around its own ORM to inject a raw `pg`
255
+ * query runner.
256
+ *
257
+ * @example
258
+ * ```typescript
259
+ * import { createPostgresdbOAuthStores, oauthModels } from '@ttoss/auth-postgresdb';
260
+ * import { initialize } from '@ttoss/postgresdb';
261
+ *
262
+ * const db = await initialize({ models: { ...oauthModels, User } });
263
+ *
264
+ * const { clientStore, authCodeStore, consentStore, refreshTokenStore } =
265
+ * createPostgresdbOAuthStores({ db });
266
+ * ```
267
+ */
268
+ var createPostgresdbOAuthStores = ({
269
+ db
270
+ }) => {
271
+ return {
272
+ clientStore: createClientStore({
273
+ model: db.OAuthClient
274
+ }),
275
+ authCodeStore: createAuthCodeStore({
276
+ model: db.OAuthAuthCode
277
+ }),
278
+ consentStore: createConsentStore({
279
+ model: db.OAuthConsent
280
+ }),
281
+ refreshTokenStore: createRefreshTokenStore({
282
+ model: db.OAuthRefreshToken
283
+ })
284
+ };
285
+ };
286
+
287
+ //#endregion
288
+ //#region \0@oxc-project+runtime@0.134.0/helpers/esm/decorateMetadata.js
289
+ function __decorateMetadata(k, v) {
290
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
291
+ }
292
+
293
+ //#endregion
294
+ //#region \0@oxc-project+runtime@0.134.0/helpers/esm/decorate.js
295
+ function __decorate(decorators, target, key, desc) {
296
+ var c = arguments.length,
297
+ r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
298
+ d;
299
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
300
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
301
+ }
302
+
303
+ //#endregion
304
+ //#region src/models/OAuthAuthCode.ts
305
+ var OAuthAuthCode = class OAuthAuthCode extends _ttoss_postgresdb.Model {};
306
+ __decorate([_ttoss_postgresdb.PrimaryKey, (0, _ttoss_postgresdb.Column)({
307
+ type: _ttoss_postgresdb.DataType.STRING,
308
+ allowNull: false
309
+ }), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "codeHash", void 0);
310
+ __decorate([(0, _ttoss_postgresdb.Column)({
311
+ type: _ttoss_postgresdb.DataType.STRING,
312
+ allowNull: false
313
+ }), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "clientId", void 0);
314
+ __decorate([(0, _ttoss_postgresdb.Column)({
315
+ type: _ttoss_postgresdb.DataType.TEXT,
316
+ allowNull: false
317
+ }), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "redirectUri", void 0);
318
+ __decorate([(0, _ttoss_postgresdb.Column)({
319
+ type: _ttoss_postgresdb.DataType.STRING,
320
+ allowNull: false
321
+ }), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "codeChallenge", void 0);
322
+ __decorate([(0, _ttoss_postgresdb.Column)({
323
+ type: _ttoss_postgresdb.DataType.JSONB,
324
+ allowNull: false
325
+ }), __decorateMetadata("design:type", Array)], OAuthAuthCode.prototype, "scopes", void 0);
326
+ __decorate([(0, _ttoss_postgresdb.Column)({
327
+ type: _ttoss_postgresdb.DataType.STRING,
328
+ allowNull: false
329
+ }), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "subject", void 0);
330
+ __decorate([(0, _ttoss_postgresdb.Column)({
331
+ type: _ttoss_postgresdb.DataType.DATE,
332
+ allowNull: false
333
+ }), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date)], OAuthAuthCode.prototype, "expiresAt", void 0);
334
+ OAuthAuthCode = __decorate([(0, _ttoss_postgresdb.Table)({
335
+ tableName: "oauth_auth_codes",
336
+ modelName: "oauthAuthCode",
337
+ indexes: [{
338
+ fields: ["expires_at"]
339
+ }]
340
+ })], OAuthAuthCode);
341
+
342
+ //#endregion
343
+ //#region src/models/OAuthClient.ts
344
+ var OAuthClient = class OAuthClient extends _ttoss_postgresdb.Model {};
345
+ __decorate([_ttoss_postgresdb.PrimaryKey, (0, _ttoss_postgresdb.Column)({
346
+ type: _ttoss_postgresdb.DataType.STRING,
347
+ allowNull: false
348
+ }), __decorateMetadata("design:type", String)], OAuthClient.prototype, "clientId", void 0);
349
+ __decorate([(0, _ttoss_postgresdb.Column)({
350
+ type: _ttoss_postgresdb.DataType.STRING,
351
+ allowNull: true
352
+ }), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "clientSecret", void 0);
353
+ __decorate([(0, _ttoss_postgresdb.Column)({
354
+ type: _ttoss_postgresdb.DataType.STRING,
355
+ allowNull: true
356
+ }), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "clientName", void 0);
357
+ __decorate([(0, _ttoss_postgresdb.Column)({
358
+ type: _ttoss_postgresdb.DataType.JSONB,
359
+ allowNull: false
360
+ }), __decorateMetadata("design:type", Array)], OAuthClient.prototype, "redirectUris", void 0);
361
+ __decorate([(0, _ttoss_postgresdb.Column)({
362
+ type: _ttoss_postgresdb.DataType.JSONB,
363
+ allowNull: true
364
+ }), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "grantTypes", void 0);
365
+ __decorate([(0, _ttoss_postgresdb.Column)({
366
+ type: _ttoss_postgresdb.DataType.JSONB,
367
+ allowNull: true
368
+ }), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "responseTypes", void 0);
369
+ __decorate([(0, _ttoss_postgresdb.Column)({
370
+ type: _ttoss_postgresdb.DataType.STRING,
371
+ allowNull: true
372
+ }), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "tokenEndpointAuthMethod", void 0);
373
+ __decorate([(0, _ttoss_postgresdb.Column)({
374
+ type: _ttoss_postgresdb.DataType.STRING,
375
+ allowNull: true
376
+ }), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "scope", void 0);
377
+ __decorate([(0, _ttoss_postgresdb.Column)({
378
+ type: _ttoss_postgresdb.DataType.BIGINT,
379
+ allowNull: true
380
+ }), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "clientIdIssuedAt", void 0);
381
+ __decorate([(0, _ttoss_postgresdb.Column)({
382
+ type: _ttoss_postgresdb.DataType.JSONB,
383
+ allowNull: false,
384
+ defaultValue: {}
385
+ }), __decorateMetadata("design:type", typeof Record === "undefined" ? Object : Record)], OAuthClient.prototype, "metadata", void 0);
386
+ OAuthClient = __decorate([(0, _ttoss_postgresdb.Table)({
387
+ tableName: "oauth_clients",
388
+ modelName: "oauthClient"
389
+ })], OAuthClient);
390
+
391
+ //#endregion
392
+ //#region src/models/OAuthConsent.ts
393
+ var OAuthConsent = class OAuthConsent extends _ttoss_postgresdb.Model {};
394
+ __decorate([_ttoss_postgresdb.PrimaryKey, (0, _ttoss_postgresdb.Column)({
395
+ type: _ttoss_postgresdb.DataType.STRING,
396
+ allowNull: false
397
+ }), __decorateMetadata("design:type", String)], OAuthConsent.prototype, "codeChallenge", void 0);
398
+ __decorate([(0, _ttoss_postgresdb.Column)({
399
+ type: _ttoss_postgresdb.DataType.STRING,
400
+ allowNull: false
401
+ }), __decorateMetadata("design:type", String)], OAuthConsent.prototype, "subject", void 0);
402
+ __decorate([(0, _ttoss_postgresdb.Column)({
403
+ type: _ttoss_postgresdb.DataType.JSONB,
404
+ allowNull: false
405
+ }), __decorateMetadata("design:type", Array)], OAuthConsent.prototype, "scopes", void 0);
406
+ __decorate([(0, _ttoss_postgresdb.Column)({
407
+ type: _ttoss_postgresdb.DataType.DATE,
408
+ allowNull: false
409
+ }), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date)], OAuthConsent.prototype, "expiresAt", void 0);
410
+ OAuthConsent = __decorate([(0, _ttoss_postgresdb.Table)({
411
+ tableName: "oauth_consents",
412
+ modelName: "oauthConsent",
413
+ indexes: [{
414
+ fields: ["expires_at"]
415
+ }]
416
+ })], OAuthConsent);
417
+
418
+ //#endregion
419
+ //#region src/models/OAuthRefreshToken.ts
420
+ var OAuthRefreshToken = class OAuthRefreshToken extends _ttoss_postgresdb.Model {};
421
+ __decorate([_ttoss_postgresdb.PrimaryKey, (0, _ttoss_postgresdb.Column)({
422
+ type: _ttoss_postgresdb.DataType.STRING,
423
+ allowNull: false
424
+ }), __decorateMetadata("design:type", String)], OAuthRefreshToken.prototype, "tokenHash", void 0);
425
+ __decorate([(0, _ttoss_postgresdb.Column)({
426
+ type: _ttoss_postgresdb.DataType.STRING,
427
+ allowNull: false
428
+ }), __decorateMetadata("design:type", String)], OAuthRefreshToken.prototype, "clientId", void 0);
429
+ __decorate([(0, _ttoss_postgresdb.Column)({
430
+ type: _ttoss_postgresdb.DataType.STRING,
431
+ allowNull: false
432
+ }), __decorateMetadata("design:type", String)], OAuthRefreshToken.prototype, "subject", void 0);
433
+ __decorate([(0, _ttoss_postgresdb.Column)({
434
+ type: _ttoss_postgresdb.DataType.JSONB,
435
+ allowNull: false
436
+ }), __decorateMetadata("design:type", Array)], OAuthRefreshToken.prototype, "scopes", void 0);
437
+ __decorate([(0, _ttoss_postgresdb.Column)({
438
+ type: _ttoss_postgresdb.DataType.DATE,
439
+ allowNull: false
440
+ }), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date)], OAuthRefreshToken.prototype, "expiresAt", void 0);
441
+ __decorate([(0, _ttoss_postgresdb.Column)({
442
+ type: _ttoss_postgresdb.DataType.DATE,
443
+ allowNull: true
444
+ }), __decorateMetadata("design:type", Object)], OAuthRefreshToken.prototype, "consumedAt", void 0);
445
+ OAuthRefreshToken = __decorate([(0, _ttoss_postgresdb.Table)({
446
+ tableName: "oauth_refresh_tokens",
447
+ modelName: "oauthRefreshToken",
448
+ indexes: [{
449
+ fields: ["client_id", "subject"]
450
+ }, {
451
+ fields: ["expires_at"]
452
+ }]
453
+ })], OAuthRefreshToken);
454
+
455
+ //#endregion
456
+ //#region src/models/index.ts
457
+ /**
458
+ * The OAuth data model, ready to register alongside the application's own
459
+ * models so `ttoss-postgresdb sync` and `erd` cover these tables like any
460
+ * other instead of them being a side-channel schema the CLI cannot see.
461
+ *
462
+ * @example
463
+ * ```typescript
464
+ * import { oauthModels } from '@ttoss/auth-postgresdb';
465
+ * import { initialize } from '@ttoss/postgresdb';
466
+ *
467
+ * export const db = await initialize({ models: { ...oauthModels, User } });
468
+ * ```
469
+ */
470
+ var oauthModels = {
471
+ OAuthAuthCode,
472
+ OAuthClient,
473
+ OAuthConsent,
474
+ OAuthRefreshToken
475
+ };
476
+
477
+ //#endregion
478
+ Object.defineProperty(exports, 'OAuthAuthCode', {
479
+ enumerable: true,
480
+ get: function () {
481
+ return OAuthAuthCode;
482
+ }
483
+ });
484
+ Object.defineProperty(exports, 'OAuthClient', {
485
+ enumerable: true,
486
+ get: function () {
487
+ return OAuthClient;
488
+ }
489
+ });
490
+ Object.defineProperty(exports, 'OAuthConsent', {
491
+ enumerable: true,
492
+ get: function () {
493
+ return OAuthConsent;
494
+ }
495
+ });
496
+ Object.defineProperty(exports, 'OAuthRefreshToken', {
497
+ enumerable: true,
498
+ get: function () {
499
+ return OAuthRefreshToken;
500
+ }
501
+ });
502
+ exports.createAuthCodeStore = createAuthCodeStore;
503
+ exports.createClientStore = createClientStore;
504
+ exports.createConsentStore = createConsentStore;
505
+ exports.createPostgresdbOAuthStores = createPostgresdbOAuthStores;
506
+ exports.createRefreshTokenStore = createRefreshTokenStore;
507
+ exports.oauthModels = oauthModels;