@technomoron/api-server-base 2.0.0-beta.2 → 2.0.0-beta.20

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.
Files changed (115) hide show
  1. package/README.txt +81 -28
  2. package/dist/cjs/api-module.cjs +9 -0
  3. package/dist/cjs/api-module.d.ts +7 -4
  4. package/dist/cjs/api-server-base.cjs +607 -99
  5. package/dist/cjs/api-server-base.d.ts +80 -23
  6. package/dist/cjs/auth-api/auth-module.d.ts +23 -3
  7. package/dist/cjs/auth-api/auth-module.js +320 -124
  8. package/dist/cjs/auth-api/compat-auth-storage.d.ts +7 -5
  9. package/dist/cjs/auth-api/compat-auth-storage.js +15 -3
  10. package/dist/cjs/auth-api/mem-auth-store.d.ts +5 -3
  11. package/dist/cjs/auth-api/mem-auth-store.js +14 -28
  12. package/dist/cjs/auth-api/module.d.ts +1 -1
  13. package/dist/cjs/auth-api/sql-auth-store.d.ts +16 -4
  14. package/dist/cjs/auth-api/sql-auth-store.js +43 -30
  15. package/dist/cjs/auth-api/storage.d.ts +6 -4
  16. package/dist/cjs/auth-api/storage.js +15 -5
  17. package/dist/cjs/auth-api/types.d.ts +7 -2
  18. package/dist/cjs/auth-api/user-id.d.ts +5 -0
  19. package/dist/cjs/auth-api/user-id.js +38 -0
  20. package/dist/cjs/auth-cookie-options.d.ts +11 -0
  21. package/dist/cjs/auth-cookie-options.js +66 -0
  22. package/dist/cjs/index.cjs +4 -14
  23. package/dist/cjs/index.d.ts +4 -9
  24. package/dist/cjs/oauth/memory.d.ts +6 -0
  25. package/dist/cjs/oauth/memory.js +44 -11
  26. package/dist/cjs/oauth/models.d.ts +7 -2
  27. package/dist/cjs/oauth/models.js +10 -21
  28. package/dist/cjs/oauth/sequelize.d.ts +10 -48
  29. package/dist/cjs/oauth/sequelize.js +44 -99
  30. package/dist/cjs/oauth/types.d.ts +1 -0
  31. package/dist/cjs/passkey/base.d.ts +2 -0
  32. package/dist/cjs/passkey/config.d.ts +2 -0
  33. package/dist/cjs/passkey/config.js +26 -0
  34. package/dist/cjs/passkey/memory.d.ts +8 -0
  35. package/dist/cjs/passkey/memory.js +57 -16
  36. package/dist/cjs/passkey/models.d.ts +13 -4
  37. package/dist/cjs/passkey/models.js +41 -14
  38. package/dist/cjs/passkey/sequelize.d.ts +13 -25
  39. package/dist/cjs/passkey/sequelize.js +68 -153
  40. package/dist/cjs/passkey/service.d.ts +6 -2
  41. package/dist/cjs/passkey/service.js +205 -27
  42. package/dist/cjs/passkey/types.d.ts +18 -9
  43. package/dist/cjs/sequelize-utils.d.ts +8 -0
  44. package/dist/cjs/sequelize-utils.js +57 -0
  45. package/dist/cjs/token/base.d.ts +2 -1
  46. package/dist/cjs/token/base.js +3 -1
  47. package/dist/cjs/token/memory.d.ts +10 -0
  48. package/dist/cjs/token/memory.js +122 -32
  49. package/dist/cjs/token/sequelize.d.ts +4 -4
  50. package/dist/cjs/token/sequelize.js +67 -85
  51. package/dist/cjs/token/types.d.ts +8 -1
  52. package/dist/cjs/user/base.d.ts +1 -0
  53. package/dist/cjs/user/base.js +11 -4
  54. package/dist/cjs/user/memory.d.ts +2 -0
  55. package/dist/cjs/user/memory.js +9 -10
  56. package/dist/cjs/user/sequelize.d.ts +7 -2
  57. package/dist/cjs/user/sequelize.js +19 -32
  58. package/dist/esm/api-module.d.ts +7 -4
  59. package/dist/esm/api-module.js +9 -0
  60. package/dist/esm/api-server-base.d.ts +80 -23
  61. package/dist/esm/api-server-base.js +608 -100
  62. package/dist/esm/auth-api/auth-module.d.ts +23 -3
  63. package/dist/esm/auth-api/auth-module.js +321 -125
  64. package/dist/esm/auth-api/compat-auth-storage.d.ts +7 -5
  65. package/dist/esm/auth-api/compat-auth-storage.js +13 -1
  66. package/dist/esm/auth-api/mem-auth-store.d.ts +5 -3
  67. package/dist/esm/auth-api/mem-auth-store.js +14 -28
  68. package/dist/esm/auth-api/module.d.ts +1 -1
  69. package/dist/esm/auth-api/sql-auth-store.d.ts +16 -4
  70. package/dist/esm/auth-api/sql-auth-store.js +43 -30
  71. package/dist/esm/auth-api/storage.d.ts +6 -4
  72. package/dist/esm/auth-api/storage.js +13 -3
  73. package/dist/esm/auth-api/types.d.ts +7 -2
  74. package/dist/esm/auth-api/user-id.d.ts +5 -0
  75. package/dist/esm/auth-api/user-id.js +32 -0
  76. package/dist/esm/auth-cookie-options.d.ts +11 -0
  77. package/dist/esm/auth-cookie-options.js +63 -0
  78. package/dist/esm/index.d.ts +4 -9
  79. package/dist/esm/index.js +2 -7
  80. package/dist/esm/oauth/memory.d.ts +6 -0
  81. package/dist/esm/oauth/memory.js +44 -11
  82. package/dist/esm/oauth/models.d.ts +7 -2
  83. package/dist/esm/oauth/models.js +6 -19
  84. package/dist/esm/oauth/sequelize.d.ts +10 -48
  85. package/dist/esm/oauth/sequelize.js +32 -87
  86. package/dist/esm/oauth/types.d.ts +1 -0
  87. package/dist/esm/passkey/base.d.ts +2 -0
  88. package/dist/esm/passkey/config.d.ts +2 -0
  89. package/dist/esm/passkey/config.js +23 -0
  90. package/dist/esm/passkey/memory.d.ts +8 -0
  91. package/dist/esm/passkey/memory.js +57 -16
  92. package/dist/esm/passkey/models.d.ts +13 -4
  93. package/dist/esm/passkey/models.js +39 -12
  94. package/dist/esm/passkey/sequelize.d.ts +13 -25
  95. package/dist/esm/passkey/sequelize.js +69 -154
  96. package/dist/esm/passkey/service.d.ts +6 -2
  97. package/dist/esm/passkey/service.js +173 -28
  98. package/dist/esm/passkey/types.d.ts +18 -9
  99. package/dist/esm/sequelize-utils.d.ts +8 -0
  100. package/dist/esm/sequelize-utils.js +48 -0
  101. package/dist/esm/token/base.d.ts +2 -1
  102. package/dist/esm/token/base.js +3 -1
  103. package/dist/esm/token/memory.d.ts +10 -0
  104. package/dist/esm/token/memory.js +122 -32
  105. package/dist/esm/token/sequelize.d.ts +4 -4
  106. package/dist/esm/token/sequelize.js +67 -85
  107. package/dist/esm/token/types.d.ts +8 -1
  108. package/dist/esm/user/base.d.ts +1 -0
  109. package/dist/esm/user/base.js +11 -4
  110. package/dist/esm/user/memory.d.ts +2 -0
  111. package/dist/esm/user/memory.js +9 -10
  112. package/dist/esm/user/sequelize.d.ts +7 -2
  113. package/dist/esm/user/sequelize.js +19 -32
  114. package/docs/swagger/openapi.json +1876 -0
  115. package/package.json +81 -32
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.SequelizeOAuthStore = exports.MemoryOAuthStore = exports.OAuthStore = exports.SequelizePasskeyStore = exports.MemoryPasskeyStore = exports.PasskeyStore = exports.PasskeyService = exports.SequelizeTokenStore = exports.MemoryTokenStore = exports.TokenStore = exports.SequelizeUserStore = exports.MemoryUserStore = exports.UserStore = exports.AuthModule = exports.SqlAuthStore = exports.MemAuthStore = exports.AuthStorageAdapter = exports.BaseAuthModule = exports.nullAuthModule = exports.BaseAuthStorage = exports.nullAuthStorage = exports.ApiModule = exports.ApiError = exports.ApiServer = void 0;
6
+ exports.MemoryOAuthStore = exports.OAuthStore = exports.MemoryPasskeyStore = exports.PasskeyStore = exports.PasskeyService = exports.MemoryTokenStore = exports.TokenStore = exports.MemoryUserStore = exports.UserStore = exports.AuthModule = exports.MemAuthStore = exports.CompositeAuthAdapter = exports.BaseAuthModule = exports.nullAuthModule = exports.BaseAuthAdapter = exports.nullAuthAdapter = exports.ApiModule = exports.ApiError = exports.ApiServer = void 0;
7
7
  var api_server_base_js_1 = require("./api-server-base.cjs");
8
8
  Object.defineProperty(exports, "ApiServer", { enumerable: true, get: function () { return __importDefault(api_server_base_js_1).default; } });
9
9
  var api_server_base_js_2 = require("./api-server-base.cjs");
@@ -11,42 +11,32 @@ Object.defineProperty(exports, "ApiError", { enumerable: true, get: function ()
11
11
  var api_module_js_1 = require("./api-module.cjs");
12
12
  Object.defineProperty(exports, "ApiModule", { enumerable: true, get: function () { return api_module_js_1.ApiModule; } });
13
13
  var storage_js_1 = require("./auth-api/storage.js");
14
- Object.defineProperty(exports, "nullAuthStorage", { enumerable: true, get: function () { return storage_js_1.nullAuthStorage; } });
15
- Object.defineProperty(exports, "BaseAuthStorage", { enumerable: true, get: function () { return storage_js_1.BaseAuthStorage; } });
14
+ Object.defineProperty(exports, "nullAuthAdapter", { enumerable: true, get: function () { return storage_js_1.nullAuthAdapter; } });
15
+ Object.defineProperty(exports, "BaseAuthAdapter", { enumerable: true, get: function () { return storage_js_1.BaseAuthAdapter; } });
16
16
  var module_js_1 = require("./auth-api/module.js");
17
17
  Object.defineProperty(exports, "nullAuthModule", { enumerable: true, get: function () { return module_js_1.nullAuthModule; } });
18
18
  Object.defineProperty(exports, "BaseAuthModule", { enumerable: true, get: function () { return module_js_1.BaseAuthModule; } });
19
19
  var compat_auth_storage_js_1 = require("./auth-api/compat-auth-storage.js");
20
- Object.defineProperty(exports, "AuthStorageAdapter", { enumerable: true, get: function () { return compat_auth_storage_js_1.AuthStorageAdapter; } });
20
+ Object.defineProperty(exports, "CompositeAuthAdapter", { enumerable: true, get: function () { return compat_auth_storage_js_1.CompositeAuthAdapter; } });
21
21
  var mem_auth_store_js_1 = require("./auth-api/mem-auth-store.js");
22
22
  Object.defineProperty(exports, "MemAuthStore", { enumerable: true, get: function () { return mem_auth_store_js_1.MemAuthStore; } });
23
- var sql_auth_store_js_1 = require("./auth-api/sql-auth-store.js");
24
- Object.defineProperty(exports, "SqlAuthStore", { enumerable: true, get: function () { return sql_auth_store_js_1.SqlAuthStore; } });
25
23
  var auth_module_js_1 = require("./auth-api/auth-module.js");
26
24
  Object.defineProperty(exports, "AuthModule", { enumerable: true, get: function () { return __importDefault(auth_module_js_1).default; } });
27
25
  var base_js_1 = require("./user/base.js");
28
26
  Object.defineProperty(exports, "UserStore", { enumerable: true, get: function () { return base_js_1.UserStore; } });
29
27
  var memory_js_1 = require("./user/memory.js");
30
28
  Object.defineProperty(exports, "MemoryUserStore", { enumerable: true, get: function () { return memory_js_1.MemoryUserStore; } });
31
- var sequelize_js_1 = require("./user/sequelize.js");
32
- Object.defineProperty(exports, "SequelizeUserStore", { enumerable: true, get: function () { return sequelize_js_1.SequelizeUserStore; } });
33
29
  var base_js_2 = require("./token/base.js");
34
30
  Object.defineProperty(exports, "TokenStore", { enumerable: true, get: function () { return base_js_2.TokenStore; } });
35
31
  var memory_js_2 = require("./token/memory.js");
36
32
  Object.defineProperty(exports, "MemoryTokenStore", { enumerable: true, get: function () { return memory_js_2.MemoryTokenStore; } });
37
- var sequelize_js_2 = require("./token/sequelize.js");
38
- Object.defineProperty(exports, "SequelizeTokenStore", { enumerable: true, get: function () { return sequelize_js_2.SequelizeTokenStore; } });
39
33
  var service_js_1 = require("./passkey/service.js");
40
34
  Object.defineProperty(exports, "PasskeyService", { enumerable: true, get: function () { return service_js_1.PasskeyService; } });
41
35
  var base_js_3 = require("./passkey/base.js");
42
36
  Object.defineProperty(exports, "PasskeyStore", { enumerable: true, get: function () { return base_js_3.PasskeyStore; } });
43
37
  var memory_js_3 = require("./passkey/memory.js");
44
38
  Object.defineProperty(exports, "MemoryPasskeyStore", { enumerable: true, get: function () { return memory_js_3.MemoryPasskeyStore; } });
45
- var sequelize_js_3 = require("./passkey/sequelize.js");
46
- Object.defineProperty(exports, "SequelizePasskeyStore", { enumerable: true, get: function () { return sequelize_js_3.SequelizePasskeyStore; } });
47
39
  var base_js_4 = require("./oauth/base.js");
48
40
  Object.defineProperty(exports, "OAuthStore", { enumerable: true, get: function () { return base_js_4.OAuthStore; } });
49
41
  var memory_js_4 = require("./oauth/memory.js");
50
42
  Object.defineProperty(exports, "MemoryOAuthStore", { enumerable: true, get: function () { return memory_js_4.MemoryOAuthStore; } });
51
- var sequelize_js_4 = require("./oauth/sequelize.js");
52
- Object.defineProperty(exports, "SequelizeOAuthStore", { enumerable: true, get: function () { return sequelize_js_4.SequelizeOAuthStore; } });
@@ -1,32 +1,27 @@
1
1
  export { default as ApiServer } from './api-server-base.js';
2
2
  export { ApiError } from './api-server-base.js';
3
3
  export { ApiModule } from './api-module.js';
4
- export type { ApiErrorParams, ApiHandler, ApiKey, ApiServerConf, ApiRequest, ApiRoute, ApiAuthType, ApiAuthClass, ApiTokenData, ExtendedReq } from './api-server-base.js';
5
- export type { AuthIdentifier, AuthStorage } from './auth-api/types.js';
4
+ export type { ApiErrorParams, ApiHandler, ApiKey, ApiServerConf, ApiRequest, ApiRoute, ApiAuthType, ApiAuthClass, ApiTokenData, ExtendedReq, ExpressApiRequest, ExpressApiLocals } from './api-server-base.js';
5
+ export type { AuthIdentifier } from './auth-api/types.js';
6
6
  export type { Token, TokenPair, TokenStatus } from './token/types.js';
7
7
  export type { JwtSignResult, JwtVerifyResult, JwtDecodeResult } from './token/base.js';
8
8
  export type { OAuthClient, AuthCodeData, AuthCodeRequest } from './oauth/types.js';
9
9
  export type { AuthProviderModule } from './auth-api/module.js';
10
- export { nullAuthStorage, BaseAuthStorage } from './auth-api/storage.js';
10
+ export { nullAuthAdapter, BaseAuthAdapter } from './auth-api/storage.js';
11
11
  export { nullAuthModule, BaseAuthModule } from './auth-api/module.js';
12
- export { AuthStorageAdapter } from './auth-api/compat-auth-storage.js';
12
+ export { CompositeAuthAdapter } from './auth-api/compat-auth-storage.js';
13
13
  export { MemAuthStore } from './auth-api/mem-auth-store.js';
14
- export { SqlAuthStore } from './auth-api/sql-auth-store.js';
15
14
  export { default as AuthModule } from './auth-api/auth-module.js';
16
15
  export type { OAuthStartParams, OAuthStartResult, OAuthCallbackParams, OAuthCallbackResult } from './oauth/types.js';
17
16
  export type { BcryptHasherOptions, CreateUserInput, UpdateUserInput, PublicUserMapper } from './user/types.js';
18
17
  export { UserStore } from './user/base.js';
19
18
  export { MemoryUserStore } from './user/memory.js';
20
- export { SequelizeUserStore } from './user/sequelize.js';
21
19
  export type { MemoryUserAttributes, MemoryUserStoreOptions } from './user/memory.js';
22
20
  export { TokenStore } from './token/base.js';
23
21
  export { MemoryTokenStore } from './token/memory.js';
24
- export { SequelizeTokenStore } from './token/sequelize.js';
25
22
  export { PasskeyService } from './passkey/service.js';
26
23
  export { PasskeyStore } from './passkey/base.js';
27
24
  export { MemoryPasskeyStore } from './passkey/memory.js';
28
- export { SequelizePasskeyStore } from './passkey/sequelize.js';
29
25
  export type { PasskeyServiceConfig, PasskeyChallengeRecord, PasskeyUserDescriptor, StoredPasskeyCredential, PasskeyChallenge, PasskeyChallengeParams, PasskeyVerificationParams, PasskeyVerificationResult } from './passkey/types.js';
30
26
  export { OAuthStore } from './oauth/base.js';
31
27
  export { MemoryOAuthStore } from './oauth/memory.js';
32
- export { SequelizeOAuthStore } from './oauth/sequelize.js';
@@ -1,11 +1,15 @@
1
1
  import { OAuthStore, type AuthCode, type OAuthClient } from './base.js';
2
2
  export interface MemoryOAuthStoreOptions {
3
3
  bcryptRounds?: number;
4
+ maxClients?: number;
5
+ maxAuthCodes?: number;
4
6
  }
5
7
  export declare class MemoryOAuthStore extends OAuthStore {
6
8
  private readonly clients;
7
9
  private readonly codes;
8
10
  private readonly bcryptRounds;
11
+ private readonly maxClients?;
12
+ private readonly maxAuthCodes?;
9
13
  constructor(options?: MemoryOAuthStoreOptions);
10
14
  getClient(clientId: string): Promise<OAuthClient | null>;
11
15
  createClient(input: OAuthClient): Promise<OAuthClient>;
@@ -13,4 +17,6 @@ export declare class MemoryOAuthStore extends OAuthStore {
13
17
  createAuthCode(code: AuthCode): Promise<void>;
14
18
  consumeAuthCode(code: string): Promise<AuthCode | null>;
15
19
  close(): Promise<void>;
20
+ private enforceClientCapacity;
21
+ private enforceCodeCapacity;
16
22
  }
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.MemoryOAuthStore = void 0;
7
7
  const bcryptjs_1 = __importDefault(require("bcryptjs"));
8
+ const user_id_js_1 = require("../auth-api/user-id.js");
8
9
  const base_js_1 = require("./base.js");
9
10
  function cloneClient(client) {
10
11
  if (!client) {
@@ -12,7 +13,7 @@ function cloneClient(client) {
12
13
  }
13
14
  return {
14
15
  clientId: client.clientId,
15
- clientSecret: client.clientSecret,
16
+ hasSecret: Boolean(client.clientSecret),
16
17
  name: client.name,
17
18
  redirectUris: [...client.redirectUris],
18
19
  scope: client.scope ? [...client.scope] : undefined,
@@ -23,26 +24,28 @@ function cloneClient(client) {
23
24
  function cloneCode(code) {
24
25
  return {
25
26
  ...code,
27
+ userId: (0, user_id_js_1.normalizeComparableUserId)(code.userId),
26
28
  scope: code.scope ? [...code.scope] : undefined,
27
29
  expiresAt: new Date(code.expiresAt),
28
30
  metadata: code.metadata ? { ...code.metadata } : undefined
29
31
  };
30
32
  }
31
- function normalizeUserId(identifier) {
32
- if (typeof identifier === 'number' && Number.isFinite(identifier)) {
33
- return identifier;
34
- }
35
- if (typeof identifier === 'string' && /^\d+$/.test(identifier)) {
36
- return Number(identifier);
37
- }
38
- throw new Error(`Unable to normalise user identifier: ${identifier}`);
39
- }
40
33
  class MemoryOAuthStore extends base_js_1.OAuthStore {
41
34
  constructor(options = {}) {
42
35
  super();
43
36
  this.clients = new Map();
44
37
  this.codes = new Map();
45
38
  this.bcryptRounds = options.bcryptRounds ?? 12;
39
+ this.maxClients =
40
+ typeof options.maxClients === 'number' && Number.isFinite(options.maxClients) && options.maxClients > 0
41
+ ? Math.floor(options.maxClients)
42
+ : undefined;
43
+ this.maxAuthCodes =
44
+ typeof options.maxAuthCodes === 'number' &&
45
+ Number.isFinite(options.maxAuthCodes) &&
46
+ options.maxAuthCodes > 0
47
+ ? Math.floor(options.maxAuthCodes)
48
+ : undefined;
46
49
  }
47
50
  async getClient(clientId) {
48
51
  return cloneClient(this.clients.get(clientId));
@@ -59,6 +62,7 @@ class MemoryOAuthStore extends base_js_1.OAuthStore {
59
62
  firstParty: input.firstParty
60
63
  };
61
64
  this.clients.set(stored.clientId, stored);
65
+ this.enforceClientCapacity();
62
66
  return cloneClient(stored);
63
67
  }
64
68
  async verifyClientSecret(clientId, secret) {
@@ -77,23 +81,52 @@ class MemoryOAuthStore extends base_js_1.OAuthStore {
77
81
  async createAuthCode(code) {
78
82
  const record = {
79
83
  ...code,
80
- userId: normalizeUserId(code.userId),
84
+ userId: (0, user_id_js_1.normalizeComparableUserId)(code.userId),
81
85
  scope: code.scope ? [...code.scope] : undefined,
82
86
  expiresAt: code.expiresAt,
83
87
  metadata: code.metadata ? { ...code.metadata } : undefined
84
88
  };
85
89
  this.codes.set(record.code, record);
90
+ this.enforceCodeCapacity();
86
91
  }
87
92
  async consumeAuthCode(code) {
88
93
  const record = this.codes.get(code);
89
94
  if (!record) {
90
95
  return null;
91
96
  }
97
+ if (record.expiresAt.getTime() <= Date.now()) {
98
+ this.codes.delete(code);
99
+ return null;
100
+ }
92
101
  this.codes.delete(code);
93
102
  return cloneCode(record);
94
103
  }
95
104
  async close() {
96
105
  return;
97
106
  }
107
+ enforceClientCapacity() {
108
+ if (!this.maxClients) {
109
+ return;
110
+ }
111
+ while (this.clients.size > this.maxClients) {
112
+ const oldest = this.clients.keys().next().value;
113
+ if (!oldest) {
114
+ return;
115
+ }
116
+ this.clients.delete(oldest);
117
+ }
118
+ }
119
+ enforceCodeCapacity() {
120
+ if (!this.maxAuthCodes) {
121
+ return;
122
+ }
123
+ while (this.codes.size > this.maxAuthCodes) {
124
+ const oldest = this.codes.keys().next().value;
125
+ if (!oldest) {
126
+ return;
127
+ }
128
+ this.codes.delete(oldest);
129
+ }
130
+ }
98
131
  }
99
132
  exports.MemoryOAuthStore = MemoryOAuthStore;
@@ -1,4 +1,5 @@
1
1
  import { Model, type Optional, type Sequelize } from 'sequelize';
2
+ export { integerIdType, tableOptions } from '../sequelize-utils.js';
2
3
  export interface OAuthClientAttributes {
3
4
  client_id: string;
4
5
  client_secret: string;
@@ -18,7 +19,9 @@ export declare class OAuthClientModel extends Model<OAuthClientAttributes, OAuth
18
19
  metadata: string | null;
19
20
  first_party: boolean;
20
21
  }
21
- export declare function initOAuthClientModel(sequelize: Sequelize): typeof OAuthClientModel;
22
+ export declare function initOAuthClientModel(sequelize: Sequelize, options?: {
23
+ tablePrefix?: string;
24
+ }): typeof OAuthClientModel;
22
25
  export interface OAuthCodeAttributes {
23
26
  code: string;
24
27
  client_id: string;
@@ -42,4 +45,6 @@ export declare class OAuthCodeModel extends Model<OAuthCodeAttributes, OAuthCode
42
45
  expires: Date;
43
46
  metadata: string | null;
44
47
  }
45
- export declare function initOAuthCodeModel(sequelize: Sequelize): typeof OAuthCodeModel;
48
+ export declare function initOAuthCodeModel(sequelize: Sequelize, options?: {
49
+ tablePrefix?: string;
50
+ }): typeof OAuthCodeModel;
@@ -1,28 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OAuthCodeModel = exports.OAuthClientModel = void 0;
3
+ exports.OAuthCodeModel = exports.OAuthClientModel = exports.tableOptions = exports.integerIdType = void 0;
4
4
  exports.initOAuthClientModel = initOAuthClientModel;
5
5
  exports.initOAuthCodeModel = initOAuthCodeModel;
6
6
  const sequelize_1 = require("sequelize");
7
- const DIALECTS_SUPPORTING_UNSIGNED = new Set(['mysql', 'mariadb']);
8
- function integerIdType(sequelize) {
9
- return DIALECTS_SUPPORTING_UNSIGNED.has(sequelize.getDialect()) ? sequelize_1.DataTypes.INTEGER.UNSIGNED : sequelize_1.DataTypes.INTEGER;
10
- }
11
- function tableOptions(sequelize, tableName, extra) {
12
- const opts = { sequelize, tableName };
13
- if (extra) {
14
- Object.assign(opts, extra);
15
- }
16
- if (DIALECTS_SUPPORTING_UNSIGNED.has(sequelize.getDialect())) {
17
- opts.charset = 'utf8mb4';
18
- opts.collate = 'utf8mb4_unicode_ci';
19
- }
20
- return opts;
21
- }
7
+ const sequelize_utils_js_1 = require("../sequelize-utils.js");
8
+ var sequelize_utils_js_2 = require("../sequelize-utils.js");
9
+ Object.defineProperty(exports, "integerIdType", { enumerable: true, get: function () { return sequelize_utils_js_2.integerIdType; } });
10
+ Object.defineProperty(exports, "tableOptions", { enumerable: true, get: function () { return sequelize_utils_js_2.tableOptions; } });
22
11
  class OAuthClientModel extends sequelize_1.Model {
23
12
  }
24
13
  exports.OAuthClientModel = OAuthClientModel;
25
- function initOAuthClientModel(sequelize) {
14
+ function initOAuthClientModel(sequelize, options = {}) {
26
15
  OAuthClientModel.init({
27
16
  client_id: { type: sequelize_1.DataTypes.STRING(128), allowNull: false, primaryKey: true },
28
17
  client_secret: { type: sequelize_1.DataTypes.STRING(255), allowNull: false, defaultValue: '' },
@@ -32,15 +21,15 @@ function initOAuthClientModel(sequelize) {
32
21
  metadata: { type: sequelize_1.DataTypes.TEXT, allowNull: true, defaultValue: null },
33
22
  first_party: { type: sequelize_1.DataTypes.BOOLEAN, allowNull: false, defaultValue: false }
34
23
  }, {
35
- ...tableOptions(sequelize, 'oauth_clients', { timestamps: false })
24
+ ...(0, sequelize_utils_js_1.tableOptions)(sequelize, 'oauth_clients', options.tablePrefix, { timestamps: false })
36
25
  });
37
26
  return OAuthClientModel;
38
27
  }
39
28
  class OAuthCodeModel extends sequelize_1.Model {
40
29
  }
41
30
  exports.OAuthCodeModel = OAuthCodeModel;
42
- function initOAuthCodeModel(sequelize) {
43
- const idType = integerIdType(sequelize);
31
+ function initOAuthCodeModel(sequelize, options = {}) {
32
+ const idType = (0, sequelize_utils_js_1.integerIdType)(sequelize);
44
33
  OAuthCodeModel.init({
45
34
  code: { type: sequelize_1.DataTypes.STRING(128), allowNull: false, primaryKey: true },
46
35
  client_id: { type: sequelize_1.DataTypes.STRING(128), allowNull: false },
@@ -52,7 +41,7 @@ function initOAuthCodeModel(sequelize) {
52
41
  expires: { type: sequelize_1.DataTypes.DATE, allowNull: false },
53
42
  metadata: { type: sequelize_1.DataTypes.TEXT, allowNull: true, defaultValue: null }
54
43
  }, {
55
- ...tableOptions(sequelize, 'oauth_codes', { timestamps: false })
44
+ ...(0, sequelize_utils_js_1.tableOptions)(sequelize, 'oauth_codes', options.tablePrefix, { timestamps: false })
56
45
  });
57
46
  return OAuthCodeModel;
58
47
  }
@@ -1,57 +1,19 @@
1
- import { Model, type Optional, type Sequelize } from 'sequelize';
2
1
  import { OAuthStore, type AuthCode, type OAuthClient } from './base.js';
3
- export interface OAuthClientAttributes {
4
- client_id: string;
5
- client_secret: string;
6
- name: string | null;
7
- redirect_uris: string;
8
- scope: string;
9
- metadata: string | null;
10
- first_party: boolean;
11
- }
12
- export type OAuthClientCreationAttributes = Optional<OAuthClientAttributes, 'client_secret' | 'name' | 'scope' | 'metadata' | 'first_party'>;
13
- export declare class OAuthClientModel extends Model<OAuthClientAttributes, OAuthClientCreationAttributes> implements OAuthClientAttributes {
14
- client_id: string;
15
- client_secret: string;
16
- name: string | null;
17
- redirect_uris: string;
18
- scope: string;
19
- metadata: string | null;
20
- first_party: boolean;
21
- }
22
- export declare function initOAuthClientModel(sequelize: Sequelize): typeof OAuthClientModel;
23
- export interface OAuthCodeAttributes {
24
- code: string;
25
- client_id: string;
26
- user_id: number;
27
- redirect_uri: string;
28
- scope: string;
29
- code_challenge: string | null;
30
- code_challenge_method: 'plain' | 'S256' | null;
31
- expires: Date;
32
- metadata: string | null;
33
- }
34
- export type OAuthCodeCreationAttributes = Optional<OAuthCodeAttributes, 'code_challenge' | 'code_challenge_method' | 'metadata'>;
35
- export declare class OAuthCodeModel extends Model<OAuthCodeAttributes, OAuthCodeCreationAttributes> implements OAuthCodeAttributes {
36
- code: string;
37
- client_id: string;
38
- user_id: number;
39
- redirect_uri: string;
40
- scope: string;
41
- code_challenge: string | null;
42
- code_challenge_method: 'plain' | 'S256' | null;
43
- expires: Date;
44
- metadata: string | null;
45
- }
46
- export declare function initOAuthCodeModel(sequelize: Sequelize): typeof OAuthCodeModel;
2
+ import { OAuthClientModel, OAuthCodeModel } from './models.js';
47
3
  export interface SequelizeOAuthStoreOptions {
48
- sequelize: Sequelize;
4
+ sequelize: import('sequelize').Sequelize;
5
+ tablePrefix?: string;
49
6
  clientModel?: typeof OAuthClientModel;
50
7
  codeModel?: typeof OAuthCodeModel;
51
- clientModelFactory?: (sequelize: Sequelize) => typeof OAuthClientModel;
52
- codeModelFactory?: (sequelize: Sequelize) => typeof OAuthCodeModel;
8
+ clientModelFactory?: (sequelize: import('sequelize').Sequelize, options?: {
9
+ tablePrefix?: string;
10
+ }) => typeof OAuthClientModel;
11
+ codeModelFactory?: (sequelize: import('sequelize').Sequelize, options?: {
12
+ tablePrefix?: string;
13
+ }) => typeof OAuthCodeModel;
53
14
  bcryptRounds?: number;
54
15
  }
16
+ export { OAuthClientModel, OAuthCodeModel, initOAuthClientModel, initOAuthCodeModel, type OAuthClientAttributes, type OAuthClientCreationAttributes, type OAuthCodeAttributes, type OAuthCodeCreationAttributes } from './models.js';
55
17
  export declare class SequelizeOAuthStore extends OAuthStore {
56
18
  private readonly clients;
57
19
  private readonly codes;
@@ -3,81 +3,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.SequelizeOAuthStore = exports.OAuthCodeModel = exports.OAuthClientModel = void 0;
7
- exports.initOAuthClientModel = initOAuthClientModel;
8
- exports.initOAuthCodeModel = initOAuthCodeModel;
6
+ exports.SequelizeOAuthStore = exports.initOAuthCodeModel = exports.initOAuthClientModel = exports.OAuthCodeModel = exports.OAuthClientModel = void 0;
9
7
  const bcryptjs_1 = __importDefault(require("bcryptjs"));
10
8
  const sequelize_1 = require("sequelize");
9
+ const user_id_js_1 = require("../auth-api/user-id.js");
10
+ const sequelize_utils_js_1 = require("../sequelize-utils.js");
11
11
  const base_js_1 = require("./base.js");
12
- const DIALECTS_SUPPORTING_UNSIGNED = new Set(['mysql', 'mariadb']);
13
- function integerIdType(sequelize) {
14
- return DIALECTS_SUPPORTING_UNSIGNED.has(sequelize.getDialect()) ? sequelize_1.DataTypes.INTEGER.UNSIGNED : sequelize_1.DataTypes.INTEGER;
15
- }
16
- function tableOptions(sequelize, tableName, extra) {
17
- const opts = { sequelize, tableName };
18
- if (extra) {
19
- Object.assign(opts, extra);
20
- }
21
- if (DIALECTS_SUPPORTING_UNSIGNED.has(sequelize.getDialect())) {
22
- opts.charset = 'utf8mb4';
23
- opts.collate = 'utf8mb4_unicode_ci';
24
- }
25
- return opts;
26
- }
27
- class OAuthClientModel extends sequelize_1.Model {
28
- }
29
- exports.OAuthClientModel = OAuthClientModel;
30
- function initOAuthClientModel(sequelize) {
31
- OAuthClientModel.init({
32
- client_id: { type: sequelize_1.DataTypes.STRING(128), allowNull: false, primaryKey: true },
33
- client_secret: { type: sequelize_1.DataTypes.STRING(255), allowNull: false, defaultValue: '' },
34
- name: { type: sequelize_1.DataTypes.STRING(128), allowNull: true, defaultValue: null },
35
- redirect_uris: { type: sequelize_1.DataTypes.TEXT, allowNull: false, defaultValue: '[]' },
36
- scope: { type: sequelize_1.DataTypes.TEXT, allowNull: false, defaultValue: '[]' },
37
- metadata: { type: sequelize_1.DataTypes.TEXT, allowNull: true, defaultValue: null },
38
- first_party: { type: sequelize_1.DataTypes.BOOLEAN, allowNull: false, defaultValue: false }
39
- }, tableOptions(sequelize, 'oauth_clients', { timestamps: false }));
40
- return OAuthClientModel;
41
- }
42
- class OAuthCodeModel extends sequelize_1.Model {
43
- }
44
- exports.OAuthCodeModel = OAuthCodeModel;
45
- function initOAuthCodeModel(sequelize) {
46
- const idType = integerIdType(sequelize);
47
- OAuthCodeModel.init({
48
- code: { type: sequelize_1.DataTypes.STRING(128), allowNull: false, primaryKey: true },
49
- client_id: { type: sequelize_1.DataTypes.STRING(128), allowNull: false },
50
- user_id: { type: idType, allowNull: false },
51
- redirect_uri: { type: sequelize_1.DataTypes.TEXT, allowNull: false },
52
- scope: { type: sequelize_1.DataTypes.TEXT, allowNull: false, defaultValue: '[]' },
53
- code_challenge: { type: sequelize_1.DataTypes.STRING(255), allowNull: true, defaultValue: null },
54
- code_challenge_method: { type: sequelize_1.DataTypes.STRING(10), allowNull: true, defaultValue: null },
55
- expires: { type: sequelize_1.DataTypes.DATE, allowNull: false },
56
- metadata: { type: sequelize_1.DataTypes.TEXT, allowNull: true, defaultValue: null }
57
- }, tableOptions(sequelize, 'oauth_codes', { timestamps: false }));
58
- return OAuthCodeModel;
59
- }
60
- function encodeStringArray(values) {
61
- return JSON.stringify(values ?? []);
62
- }
63
- function decodeStringArray(raw) {
64
- if (!raw) {
65
- return [];
66
- }
67
- try {
68
- const parsed = JSON.parse(raw);
69
- if (Array.isArray(parsed)) {
70
- return parsed.filter((entry) => typeof entry === 'string' && entry.length > 0);
71
- }
72
- }
73
- catch {
74
- // ignore malformed values
75
- }
76
- return raw
77
- .split(/\s+/)
78
- .map((entry) => entry.trim())
79
- .filter((entry) => entry.length > 0);
80
- }
12
+ const models_js_1 = require("./models.js");
13
+ var models_js_2 = require("./models.js");
14
+ Object.defineProperty(exports, "OAuthClientModel", { enumerable: true, get: function () { return models_js_2.OAuthClientModel; } });
15
+ Object.defineProperty(exports, "OAuthCodeModel", { enumerable: true, get: function () { return models_js_2.OAuthCodeModel; } });
16
+ Object.defineProperty(exports, "initOAuthClientModel", { enumerable: true, get: function () { return models_js_2.initOAuthClientModel; } });
17
+ Object.defineProperty(exports, "initOAuthCodeModel", { enumerable: true, get: function () { return models_js_2.initOAuthCodeModel; } });
81
18
  function serializeMetadata(metadata) {
82
19
  if (!metadata) {
83
20
  return null;
@@ -99,23 +36,22 @@ function parseMetadata(raw) {
99
36
  }
100
37
  return undefined;
101
38
  }
102
- function normalizeUserId(identifier) {
103
- if (typeof identifier === 'number' && Number.isFinite(identifier)) {
104
- return identifier;
105
- }
106
- if (typeof identifier === 'string' && /^\d+$/.test(identifier)) {
107
- return Number(identifier);
108
- }
109
- throw new Error(`Unable to normalise user identifier: ${identifier}`);
110
- }
111
39
  class SequelizeOAuthStore extends base_js_1.OAuthStore {
112
40
  constructor(options) {
113
41
  super();
114
42
  if (!options?.sequelize) {
115
43
  throw new Error('SequelizeOAuthStore requires an initialised Sequelize instance');
116
44
  }
117
- this.clients = options.clientModel ?? (options.clientModelFactory ?? initOAuthClientModel)(options.sequelize);
118
- this.codes = options.codeModel ?? (options.codeModelFactory ?? initOAuthCodeModel)(options.sequelize);
45
+ this.clients =
46
+ options.clientModel ??
47
+ (options.clientModelFactory ?? models_js_1.initOAuthClientModel)(options.sequelize, {
48
+ tablePrefix: options.tablePrefix
49
+ });
50
+ this.codes =
51
+ options.codeModel ??
52
+ (options.codeModelFactory ?? models_js_1.initOAuthCodeModel)(options.sequelize, {
53
+ tablePrefix: options.tablePrefix
54
+ });
119
55
  this.bcryptRounds = options.bcryptRounds ?? 12;
120
56
  }
121
57
  async getClient(clientId) {
@@ -127,15 +63,15 @@ class SequelizeOAuthStore extends base_js_1.OAuthStore {
127
63
  const hashedSecret = input.clientSecret !== undefined && input.clientSecret !== null
128
64
  ? await bcryptjs_1.default.hash(input.clientSecret, this.bcryptRounds)
129
65
  : (existing?.client_secret ?? '');
130
- const redirectUris = input.redirectUris ?? (existing ? decodeStringArray(existing.redirect_uris) : undefined);
131
- const scope = input.scope ?? (existing ? decodeStringArray(existing.scope) : undefined);
66
+ const redirectUris = input.redirectUris ?? (existing ? (0, sequelize_utils_js_1.decodeStringArray)(existing.redirect_uris) : undefined);
67
+ const scope = input.scope ?? (existing ? (0, sequelize_utils_js_1.decodeStringArray)(existing.scope) : undefined);
132
68
  const metadata = input.metadata ?? (existing ? parseMetadata(existing.metadata) : undefined);
133
69
  await this.clients.upsert({
134
70
  client_id: input.clientId,
135
71
  client_secret: hashedSecret,
136
72
  name: input.name ?? existing?.name ?? null,
137
- redirect_uris: encodeStringArray(redirectUris),
138
- scope: encodeStringArray(scope),
73
+ redirect_uris: (0, sequelize_utils_js_1.encodeStringArray)(redirectUris),
74
+ scope: (0, sequelize_utils_js_1.encodeStringArray)(scope),
139
75
  metadata: serializeMetadata(metadata),
140
76
  first_party: input.firstParty ?? existing?.first_party ?? false
141
77
  });
@@ -162,9 +98,9 @@ class SequelizeOAuthStore extends base_js_1.OAuthStore {
162
98
  await this.codes.create({
163
99
  code: code.code,
164
100
  client_id: code.clientId,
165
- user_id: normalizeUserId(code.userId),
101
+ user_id: (0, user_id_js_1.normalizeNumericUserId)(code.userId),
166
102
  redirect_uri: code.redirectUri ?? '',
167
- scope: encodeStringArray(code.scope),
103
+ scope: (0, sequelize_utils_js_1.encodeStringArray)(code.scope),
168
104
  code_challenge: code.codeChallenge ?? null,
169
105
  code_challenge_method: code.codeChallengeMethod ?? null,
170
106
  expires: code.expiresAt,
@@ -172,12 +108,21 @@ class SequelizeOAuthStore extends base_js_1.OAuthStore {
172
108
  });
173
109
  }
174
110
  async consumeAuthCode(code) {
175
- const model = await this.codes.findByPk(code);
176
- if (!model) {
177
- return null;
111
+ const sequelize = this.codes.sequelize;
112
+ if (!sequelize) {
113
+ throw new Error('Code model is not bound to a Sequelize instance');
178
114
  }
179
- await model.destroy();
180
- return this.toAuthCode(model);
115
+ return sequelize.transaction({ isolationLevel: sequelize_1.Transaction.ISOLATION_LEVELS.READ_COMMITTED }, async (transaction) => {
116
+ const model = await this.codes.findByPk(code, { transaction, lock: true });
117
+ if (!model) {
118
+ return null;
119
+ }
120
+ await model.destroy({ transaction });
121
+ if (model.expires.getTime() <= Date.now()) {
122
+ return null;
123
+ }
124
+ return this.toAuthCode(model);
125
+ });
181
126
  }
182
127
  async close() {
183
128
  return;
@@ -185,10 +130,10 @@ class SequelizeOAuthStore extends base_js_1.OAuthStore {
185
130
  toOAuthClient(model) {
186
131
  return {
187
132
  clientId: model.client_id,
188
- clientSecret: model.client_secret,
133
+ hasSecret: Boolean(model.client_secret),
189
134
  name: model.name ?? undefined,
190
- redirectUris: decodeStringArray(model.redirect_uris),
191
- scope: decodeStringArray(model.scope),
135
+ redirectUris: (0, sequelize_utils_js_1.decodeStringArray)(model.redirect_uris),
136
+ scope: (0, sequelize_utils_js_1.decodeStringArray)(model.scope),
192
137
  metadata: parseMetadata(model.metadata),
193
138
  firstParty: model.first_party ?? false
194
139
  };
@@ -197,9 +142,9 @@ class SequelizeOAuthStore extends base_js_1.OAuthStore {
197
142
  return {
198
143
  code: model.code,
199
144
  clientId: model.client_id,
200
- userId: model.user_id,
145
+ userId: String(model.user_id),
201
146
  redirectUri: model.redirect_uri,
202
- scope: decodeStringArray(model.scope),
147
+ scope: (0, sequelize_utils_js_1.decodeStringArray)(model.scope),
203
148
  codeChallenge: model.code_challenge ?? undefined,
204
149
  codeChallengeMethod: model.code_challenge_method ?? undefined,
205
150
  expiresAt: model.expires,
@@ -2,6 +2,7 @@ import type { AuthIdentifier } from '../auth-api/types.js';
2
2
  export interface OAuthClient {
3
3
  clientId: string;
4
4
  clientSecret?: string;
5
+ hasSecret?: boolean;
5
6
  firstParty?: boolean;
6
7
  metadata?: Record<string, unknown>;
7
8
  name?: string;
@@ -6,10 +6,12 @@ export declare abstract class PasskeyStore implements PasskeyStorageAdapter {
6
6
  login?: string;
7
7
  }): Promise<PasskeyUserDescriptor | null>;
8
8
  abstract listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
9
+ abstract deleteCredential(credentialId: Buffer | string): Promise<boolean>;
9
10
  abstract findCredentialById(credentialId: Buffer): Promise<StoredPasskeyCredential | null>;
10
11
  abstract saveCredential(record: StoredPasskeyCredential): Promise<void>;
11
12
  abstract updateCredentialCounter(credentialId: Buffer, counter: number): Promise<void>;
12
13
  abstract saveChallenge(record: PasskeyChallengeRecord): Promise<void>;
14
+ abstract getChallenge(challenge: string): Promise<PasskeyChallengeRecord | null>;
13
15
  abstract consumeChallenge(challenge: string): Promise<PasskeyChallengeRecord | null>;
14
16
  abstract cleanupChallenges(now: Date): Promise<void>;
15
17
  }
@@ -0,0 +1,2 @@
1
+ import type { PasskeyServiceConfig } from './types.js';
2
+ export declare function normalizePasskeyConfig(config?: Partial<PasskeyServiceConfig>): PasskeyServiceConfig;