@tstdl/base 0.92.141 → 0.92.143

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 (224) hide show
  1. package/ai/ai-file.service.js +1 -1
  2. package/ai/ai.service.js +3 -3
  3. package/ai/types.d.ts +1 -1
  4. package/api/client/client.d.ts +1 -1
  5. package/api/client/client.js +10 -4
  6. package/api/server/middlewares/content-type.middleware.js +8 -7
  7. package/api/types.js +1 -1
  8. package/authentication/client/authentication.service.js +3 -3
  9. package/authentication/server/authentication-ancillary.service.d.ts +11 -1
  10. package/authentication/server/authentication-ancillary.service.js +1 -1
  11. package/authentication/server/authentication-secret-requirements.validator.js +1 -1
  12. package/authentication/server/authentication.api-controller.js +22 -10
  13. package/authentication/server/authentication.service.d.ts +11 -5
  14. package/authentication/server/authentication.service.js +97 -49
  15. package/authentication/server/drizzle.config.js +2 -2
  16. package/authentication/server/module.js +1 -1
  17. package/cancellation/token.d.ts +2 -2
  18. package/cancellation/token.js +4 -4
  19. package/cookie/cookie.js +2 -2
  20. package/css/css-variables.js +1 -1
  21. package/document-management/api/document-management.api.d.ts +122 -24
  22. package/document-management/api/document-management.api.js +17 -0
  23. package/document-management/{server/services → authorization}/document-management-authorization.service.d.ts +7 -7
  24. package/document-management/authorization/document-management-authorization.service.js +2 -0
  25. package/document-management/authorization/index.d.ts +2 -0
  26. package/document-management/authorization/index.js +2 -0
  27. package/document-management/authorization/policies.d.ts +38 -0
  28. package/document-management/authorization/policies.js +2 -0
  29. package/document-management/index.d.ts +1 -0
  30. package/document-management/index.js +1 -0
  31. package/document-management/models/document-assignment-scope.model.d.ts +1 -0
  32. package/document-management/models/document-assignment-scope.model.js +10 -3
  33. package/document-management/models/document-assignment-task.model.d.ts +1 -0
  34. package/document-management/models/document-assignment-task.model.js +8 -2
  35. package/document-management/models/document-category.model.d.ts +1 -0
  36. package/document-management/models/document-category.model.js +7 -1
  37. package/document-management/models/document-collection-assignment.model.d.ts +1 -0
  38. package/document-management/models/document-collection-assignment.model.js +12 -4
  39. package/document-management/models/document-collection.model.d.ts +2 -0
  40. package/document-management/models/document-collection.model.js +8 -2
  41. package/document-management/models/document-management-table.d.ts +3 -1
  42. package/document-management/models/document-management-table.js +2 -2
  43. package/document-management/models/document-property-value.model.d.ts +1 -0
  44. package/document-management/models/document-property-value.model.js +9 -3
  45. package/document-management/models/document-property.model.d.ts +1 -0
  46. package/document-management/models/document-property.model.js +8 -2
  47. package/document-management/models/document-request-collection-assignment.model.d.ts +1 -0
  48. package/document-management/models/document-request-collection-assignment.model.js +12 -4
  49. package/document-management/models/document-request-template.d.ts +1 -0
  50. package/document-management/models/document-request-template.js +6 -1
  51. package/document-management/models/document-request.model.d.ts +1 -0
  52. package/document-management/models/document-request.model.js +10 -1
  53. package/document-management/models/document-requests-template.d.ts +1 -0
  54. package/document-management/models/document-requests-template.js +7 -3
  55. package/document-management/models/document-tag-assignment.model.d.ts +8 -0
  56. package/document-management/models/document-tag-assignment.model.js +40 -0
  57. package/document-management/models/document-tag.model.d.ts +6 -0
  58. package/document-management/models/{document-request-submission.model.js → document-tag.model.js} +14 -18
  59. package/document-management/models/document-type-property.model.d.ts +1 -0
  60. package/document-management/models/document-type-property.model.js +7 -2
  61. package/document-management/models/document-type-validation.model.d.ts +1 -0
  62. package/document-management/models/document-type-validation.model.js +8 -2
  63. package/document-management/models/document-type.model.d.ts +1 -0
  64. package/document-management/models/document-type.model.js +7 -2
  65. package/document-management/models/document-validation-definition.model.d.ts +1 -0
  66. package/document-management/models/document-validation-definition.model.js +7 -2
  67. package/document-management/models/document-validation-execution-related-document.model.d.ts +1 -0
  68. package/document-management/models/document-validation-execution-related-document.model.js +10 -3
  69. package/document-management/models/document-validation-execution.model.d.ts +1 -0
  70. package/document-management/models/document-validation-execution.model.js +9 -3
  71. package/document-management/models/document-workflow.model.d.ts +4 -1
  72. package/document-management/models/document-workflow.model.js +16 -4
  73. package/document-management/models/document.model.d.ts +2 -2
  74. package/document-management/models/document.model.js +9 -8
  75. package/document-management/models/index.d.ts +2 -1
  76. package/document-management/models/index.js +2 -1
  77. package/document-management/server/api/document-management.api.d.ts +4 -1
  78. package/document-management/server/api/document-management.api.js +113 -22
  79. package/document-management/server/configure.d.ts +2 -2
  80. package/document-management/server/configure.js +7 -7
  81. package/document-management/server/drizzle/0000_parallel_mantis.sql +359 -0
  82. package/document-management/server/drizzle/meta/0000_snapshot.json +784 -260
  83. package/document-management/server/drizzle/meta/_journal.json +2 -2
  84. package/document-management/server/module.d.ts +2 -2
  85. package/document-management/server/module.js +2 -2
  86. package/document-management/server/schemas.d.ts +6 -5
  87. package/document-management/server/schemas.js +12 -11
  88. package/document-management/server/services/document-category-type.service.d.ts +19 -10
  89. package/document-management/server/services/document-category-type.service.js +34 -27
  90. package/document-management/server/services/document-collection.service.d.ts +13 -6
  91. package/document-management/server/services/document-collection.service.js +36 -12
  92. package/document-management/server/services/document-file.service.d.ts +8 -7
  93. package/document-management/server/services/document-file.service.js +28 -33
  94. package/document-management/server/services/document-management-ai.service.d.ts +5 -4
  95. package/document-management/server/services/document-management-ai.service.js +51 -28
  96. package/document-management/server/services/document-management-ancillary.service.d.ts +3 -21
  97. package/document-management/server/services/document-management-ancillary.service.js +0 -24
  98. package/document-management/server/services/document-management-observation.service.d.ts +15 -0
  99. package/document-management/server/services/document-management-observation.service.js +160 -0
  100. package/document-management/server/services/document-management.service.d.ts +6 -5
  101. package/document-management/server/services/document-management.service.js +112 -86
  102. package/document-management/server/services/document-property.service.d.ts +15 -7
  103. package/document-management/server/services/document-property.service.js +52 -20
  104. package/document-management/server/services/document-request.service.d.ts +13 -24
  105. package/document-management/server/services/document-request.service.js +39 -62
  106. package/document-management/server/services/document-tag.service.d.ts +10 -0
  107. package/document-management/server/services/document-tag.service.js +59 -0
  108. package/document-management/server/services/document-validation.service.d.ts +8 -8
  109. package/document-management/server/services/document-validation.service.js +41 -40
  110. package/document-management/server/services/document-workflow.service.d.ts +6 -5
  111. package/document-management/server/services/document-workflow.service.js +54 -43
  112. package/document-management/server/services/document.service.d.ts +12 -11
  113. package/document-management/server/services/document.service.js +64 -40
  114. package/document-management/server/services/index.d.ts +2 -1
  115. package/document-management/server/services/index.js +2 -1
  116. package/document-management/server/services/singleton.js +2 -2
  117. package/document-management/server/validators/ai-validation-executor.js +4 -4
  118. package/document-management/service-models/document-collection-metadata.service-model.d.ts +14 -0
  119. package/document-management/service-models/document-collection-metadata.service-model.js +1 -0
  120. package/document-management/service-models/document-folders.view-model.d.ts +1 -7
  121. package/document-management/service-models/document-folders.view-model.js +3 -15
  122. package/document-management/service-models/document-management.view-model.d.ts +20 -6
  123. package/document-management/service-models/document-management.view-model.js +62 -8
  124. package/document-management/service-models/document.service-model.d.ts +14 -11
  125. package/document-management/service-models/document.service-model.js +11 -2
  126. package/document-management/service-models/enriched/enriched-document-assignment.view.d.ts +1 -1
  127. package/document-management/service-models/enriched/enriched-document-assignment.view.js +0 -2
  128. package/document-management/service-models/enriched/enriched-document-category.view.d.ts +11 -1
  129. package/document-management/service-models/enriched/enriched-document-category.view.js +44 -1
  130. package/document-management/service-models/enriched/enriched-document-collection.view.d.ts +4 -2
  131. package/document-management/service-models/enriched/enriched-document-collection.view.js +13 -3
  132. package/document-management/service-models/enriched/enriched-document-management-data.view.d.ts +2 -0
  133. package/document-management/service-models/enriched/enriched-document-management-data.view.js +4 -2
  134. package/document-management/service-models/enriched/enriched-document-request.view.d.ts +1 -0
  135. package/document-management/service-models/enriched/enriched-document-request.view.js +2 -0
  136. package/document-management/service-models/enriched/enriched-document-type.view.d.ts +9 -1
  137. package/document-management/service-models/enriched/enriched-document-type.view.js +28 -1
  138. package/document-management/service-models/enriched/enriched-document.view.d.ts +7 -6
  139. package/document-management/service-models/enriched/enriched-document.view.js +29 -6
  140. package/document-management/service-models/{normalized-requests-template-data.model.d.ts → enriched/enriched-requests-template-data.model.d.ts} +6 -6
  141. package/document-management/service-models/{normalized-requests-template-data.model.js → enriched/enriched-requests-template-data.model.js} +1 -1
  142. package/document-management/service-models/enriched/index.d.ts +1 -0
  143. package/document-management/service-models/enriched/index.js +1 -0
  144. package/document-management/service-models/index.d.ts +2 -2
  145. package/document-management/service-models/index.js +2 -2
  146. package/examples/document-management/categories-and-types.d.ts +33 -31
  147. package/examples/document-management/categories-and-types.js +33 -0
  148. package/examples/document-management/main.d.ts +5 -4
  149. package/examples/document-management/main.js +13 -7
  150. package/function/log.js +2 -2
  151. package/http/server/node/module.d.ts +4 -1
  152. package/http/server/node/module.js +10 -1
  153. package/http/server/node/node-http-server.d.ts +3 -6
  154. package/http/server/node/node-http-server.js +68 -67
  155. package/injector/inject.js +6 -6
  156. package/injector/injector.js +3 -3
  157. package/jsx/is-component-class.js +1 -1
  158. package/key-value-store/key-value.store.d.ts +38 -7
  159. package/key-value-store/key-value.store.js +2 -1
  160. package/key-value-store/mongo/mongo-key-value.store.d.ts +1 -0
  161. package/key-value-store/mongo/mongo-key-value.store.js +14 -5
  162. package/key-value-store/postgres/drizzle/0000_shocking_slipstream.sql +12 -0
  163. package/key-value-store/postgres/drizzle/meta/0000_snapshot.json +97 -0
  164. package/key-value-store/postgres/drizzle/meta/_journal.json +13 -0
  165. package/key-value-store/postgres/drizzle.config.d.ts +2 -0
  166. package/key-value-store/postgres/drizzle.config.js +11 -0
  167. package/key-value-store/postgres/index.d.ts +2 -0
  168. package/key-value-store/postgres/index.js +2 -0
  169. package/key-value-store/postgres/key-value-store.service.d.ts +17 -0
  170. package/key-value-store/postgres/key-value-store.service.js +65 -0
  171. package/key-value-store/postgres/models/index.d.ts +2 -0
  172. package/key-value-store/postgres/models/index.js +2 -0
  173. package/key-value-store/postgres/models/key-value.model.d.ts +7 -0
  174. package/key-value-store/postgres/models/key-value.model.js +35 -0
  175. package/key-value-store/postgres/models/schemas.d.ts +3 -0
  176. package/key-value-store/postgres/models/schemas.js +4 -0
  177. package/key-value-store/postgres/module.d.ts +6 -0
  178. package/key-value-store/postgres/module.js +23 -0
  179. package/lock/web/web-lock.d.ts +0 -1
  180. package/lock/web/web-lock.js +6 -13
  181. package/orm/data-types/timestamp.js +1 -1
  182. package/orm/decorators.d.ts +37 -29
  183. package/orm/decorators.js +44 -24
  184. package/orm/entity.d.ts +1 -0
  185. package/orm/query.d.ts +10 -2
  186. package/orm/repository.types.d.ts +2 -1
  187. package/orm/schemas/json.d.ts +12 -6
  188. package/orm/schemas/json.js +12 -5
  189. package/orm/server/database.js +5 -2
  190. package/orm/server/drizzle/schema-converter.js +40 -11
  191. package/orm/server/query-converter.d.ts +2 -1
  192. package/orm/server/query-converter.js +57 -34
  193. package/orm/server/repository.d.ts +26 -43
  194. package/orm/server/repository.js +106 -39
  195. package/orm/server/transaction.d.ts +2 -1
  196. package/orm/server/transaction.js +3 -0
  197. package/orm/server/transactional.d.ts +5 -1
  198. package/orm/server/transactional.js +34 -4
  199. package/package.json +14 -11
  200. package/process/spawn.js +0 -1
  201. package/promise/deferred-promise.d.ts +4 -3
  202. package/promise/deferred-promise.js +13 -5
  203. package/queue/postgres/queue.js +8 -8
  204. package/reflection/utils.js +3 -3
  205. package/schema/decorators/class.js +0 -1
  206. package/schema/decorators/schema.js +1 -1
  207. package/schema/schemas/boolean.d.ts +1 -1
  208. package/schema/schemas/boolean.js +2 -2
  209. package/schema/schemas/number.js +3 -3
  210. package/schema/schemas/object.js +5 -6
  211. package/sse/server-sent-events-source.js +4 -1
  212. package/utils/compression.js +9 -9
  213. package/utils/date-time.d.ts +1 -0
  214. package/utils/date-time.js +18 -4
  215. package/utils/equals.d.ts +7 -0
  216. package/utils/equals.js +17 -2
  217. package/utils/function/memoize.js +10 -2
  218. package/utils/jwt.js +3 -3
  219. package/utils/object/property-name.d.ts +2 -2
  220. package/utils/timing.d.ts +2 -2
  221. package/utils/timing.js +12 -12
  222. package/document-management/models/document-request-submission.model.d.ts +0 -7
  223. package/document-management/server/drizzle/0000_moaning_luckman.sql +0 -305
  224. package/document-management/server/services/document-management-authorization.service.js +0 -28
@@ -62,7 +62,7 @@ let AiFileService = class AiFileService {
62
62
  }
63
63
  async getFiles(fileInputs) {
64
64
  const ids = createArray(fileInputs.length, () => crypto.randomUUID());
65
- const files = await AsyncEnumerable.from(fileInputs).parallelMap(5, true, async (file, index) => this.uploadFile(file, ids[index])).toArray();
65
+ const files = await AsyncEnumerable.from(fileInputs).parallelMap(5, true, async (file, index) => await this.uploadFile(file, ids[index])).toArray();
66
66
  this.#logger.verbose(`Processing ${fileInputs.length} files...`);
67
67
  await this.waitForFilesActive(files);
68
68
  return files;
package/ai/ai.service.js CHANGED
@@ -53,7 +53,7 @@ let AiService = AiService_1 = class AiService {
53
53
  apiKey: isUndefined(this.#options.vertex?.project) ? assertDefinedPass(this.#options.apiKey, 'Api key not defined') : undefined,
54
54
  });
55
55
  #maxOutputTokensCache = new Map();
56
- defaultModel = this.#options.defaultModel ?? 'gemini-2.0-flash';
56
+ defaultModel = this.#options.defaultModel ?? 'gemini-2.5-flash-preview-05-20';
57
57
  createSession() {
58
58
  return new AiSession(this);
59
59
  }
@@ -157,8 +157,8 @@ let AiService = AiService_1 = class AiService {
157
157
  catch (error) {
158
158
  if ((i < 20) && isError(error) && (error.message.includes('429 Too Many Requests') || (error.message.includes('503 Service Unavailable')))) {
159
159
  this.#logger.verbose('429 Too Many Requests - trying again in 15 seconds');
160
- const canceled = await cancelableTimeout(15 * millisecondsPerSecond, getShutdownSignal());
161
- if (!canceled) {
160
+ const timeoutResult = await cancelableTimeout(15 * millisecondsPerSecond, getShutdownSignal());
161
+ if (timeoutResult == 'timeout') {
162
162
  continue;
163
163
  }
164
164
  }
package/ai/types.d.ts CHANGED
@@ -53,7 +53,7 @@ export type Content = {
53
53
  };
54
54
  export type FunctionCallingMode = 'auto' | 'force' | 'none';
55
55
  export type FinishReason = 'stop' | 'maxTokens' | 'unknown';
56
- export type AiModel = LiteralUnion<'gemini-2.5-pro-exp-03-25' | 'gemini-2.5-flash-exp-04-17' | 'gemini-2.0-flash' | 'gemini-2.0-flash-lite', string>;
56
+ export type AiModel = LiteralUnion<'gemini-2.5-pro-preview-05-06' | 'gemini-2.5-flash-preview-05-20', string>;
57
57
  export type GenerationOptions = {
58
58
  maxOutputTokens?: number;
59
59
  temperature?: number;
@@ -2,7 +2,7 @@ import { HttpClient, type HttpClientOptions } from '../../http/client/index.js';
2
2
  import { type Resolvable } from '../../injector/interfaces.js';
3
3
  import type { Type } from '../../types.js';
4
4
  import { type ApiClientImplementation, type ApiDefinition, type ApiEndpointDefinition } from '../types.js';
5
- export type ApiClient<T extends ApiDefinition> = Type<ApiClientImplementation<T> & Resolvable<HttpClient | HttpClientOptions>, [httpClientOrOptions?: HttpClient | HttpClientOptions]>;
5
+ export type ApiClient<T extends ApiDefinition> = Type<ApiClientImplementation<T> & Resolvable<HttpClient | HttpClientOptions>, [httpClientOrOptions?: HttpClient | HttpClientOptions]> & Pick<ApiClientImplementation<T>, 'getEndpointResource' | 'getEndpointUrl'>;
6
6
  export type ClientOptions = {
7
7
  /**
8
8
  * Url prefix
@@ -19,7 +19,6 @@ export const defaultOptions = {};
19
19
  export function setDefaultApiClientOptions(options) {
20
20
  copyObjectProperties(options, defaultOptions);
21
21
  }
22
- // eslint-disable-next-line max-lines-per-function
23
22
  export function compileClient(definition, options = defaultOptions) {
24
23
  const { resource: path, endpoints } = definition;
25
24
  const constructedApiName = toTitleCase(path[0] ?? '');
@@ -32,17 +31,24 @@ export function compileClient(definition, options = defaultOptions) {
32
31
  this[httpClientSymbol] = (httpClientOrOptions instanceof HttpClient) ? httpClientOrOptions : inject(HttpClient, httpClientOrOptions);
33
32
  this[apiDefinitionSymbol] = definition;
34
33
  }
35
- getEndpointResource(endpoint, parameters) {
34
+ static getEndpointResource(endpoint, parameters) {
36
35
  const resource = getFullApiEndpointResource({ api: definition, endpoint: resolveValueOrProvider(definition.endpoints[endpoint]), defaultPrefix: options.prefix });
37
36
  if (isUndefined(parameters)) {
38
37
  return resource;
39
38
  }
40
39
  return buildUrl(resource, parameters).parsedUrl;
41
40
  }
42
- getEndpointUrl(endpoint, parameters) {
41
+ static getEndpointUrl(endpoint, parameters) {
43
42
  const url = this.getEndpointResource(endpoint, parameters);
43
+ return new URL(url, 'http://baseurl/');
44
+ }
45
+ getEndpointUrl(endpoint, parameters) {
46
+ const url = api.getEndpointResource(endpoint, parameters);
44
47
  return new URL(url, this[httpClientSymbol].options.baseUrl);
45
48
  }
49
+ getEndpointResource(endpoint, parameters) {
50
+ return api.getEndpointResource(endpoint, parameters);
51
+ }
46
52
  },
47
53
  }[apiName];
48
54
  Injector.registerSingleton(api, {
@@ -77,7 +83,7 @@ export function compileClient(definition, options = defaultOptions) {
77
83
  context,
78
84
  });
79
85
  const response = await this[httpClientSymbol].rawRequest(request);
80
- return getResponseBody(response, endpoint.result);
86
+ return await getResponseBody(response, endpoint.result);
81
87
  },
82
88
  }[name];
83
89
  Object.defineProperty(api.prototype, name, {
@@ -1,3 +1,4 @@
1
+ import { match, P } from 'ts-pattern';
1
2
  import { isDefined } from '../../../utils/type-guards.js';
2
3
  export async function contentTypeMiddleware(context, next) {
3
4
  await next();
@@ -5,11 +6,11 @@ export async function contentTypeMiddleware(context, next) {
5
6
  if (isDefined(response.headers.contentType)) {
6
7
  return;
7
8
  }
8
- response.headers.contentType =
9
- (isDefined(response.body?.json)) ? 'application/json; charset=utf-8'
10
- : (isDefined(response.body?.text)) ? 'text/plain; charset=utf-8'
11
- : (isDefined(response.body?.buffer)) ? 'application/octet-stream'
12
- : (isDefined(response.body?.stream)) ? 'application/octet-stream'
13
- : (isDefined(response.body?.events)) ? 'text/event-stream'
14
- : undefined;
9
+ response.headers.contentType = match(response.body)
10
+ .with({ json: P.select(P.nonNullable) }, () => 'application/json; charset=utf-8')
11
+ .with({ text: P.select(P.nonNullable) }, () => 'text/plain; charset=utf-8')
12
+ .with({ buffer: P.select(P.nonNullable) }, () => 'application/octet-stream')
13
+ .with({ stream: P.select(P.nonNullable) }, () => 'application/octet-stream')
14
+ .with({ events: P.select(P.nonNullable) }, () => 'text/event-stream')
15
+ .otherwise(() => undefined);
15
16
  }
package/api/types.js CHANGED
@@ -6,7 +6,7 @@ export function defineApi(definition) {
6
6
  }
7
7
  export async function resolveApiEndpointDataProvider(request, context, provider) {
8
8
  if (isFunction(provider)) {
9
- return provider(request, context);
9
+ return await provider(request, context);
10
10
  }
11
11
  return provider;
12
12
  }
@@ -134,7 +134,7 @@ let AuthenticationClientService = class AuthenticationClientService {
134
134
  try {
135
135
  await Promise.race([
136
136
  this.client.endSession(),
137
- timeout(150)
137
+ timeout(150),
138
138
  ]).catch((error) => this.logger.error(error));
139
139
  }
140
140
  finally {
@@ -197,7 +197,7 @@ let AuthenticationClientService = class AuthenticationClientService {
197
197
  await this.client.resetSecret({ token, newSecret });
198
198
  }
199
199
  async checkSecret(secret) {
200
- return this.client.checkSecret({ secret });
200
+ return await this.client.checkSecret({ secret });
201
201
  }
202
202
  saveToken(token) {
203
203
  if (isNullOrUndefined(token)) {
@@ -223,7 +223,7 @@ let AuthenticationClientService = class AuthenticationClientService {
223
223
  async refreshLoop() {
224
224
  while (this.disposeToken.isUnset) {
225
225
  try {
226
- await this.lock.use(0, false, async () => this.refreshLoopIteration());
226
+ await this.lock.use(0, false, async () => await this.refreshLoopIteration());
227
227
  await firstValueFrom(race([timer(2500), this.disposeToken, this.forceRefreshToken]));
228
228
  }
229
229
  catch {
@@ -10,12 +10,22 @@ export type GetTokenPayloadContextAction = EnumType<typeof GetTokenPayloadContex
10
10
  export type GetTokenPayloadContext = {
11
11
  action: GetTokenPayloadContextAction;
12
12
  };
13
+ export type ResolveSubjectResult = {
14
+ success: true;
15
+ subject: string;
16
+ } | {
17
+ success: false;
18
+ subject?: undefined;
19
+ };
13
20
  export declare abstract class AuthenticationAncillaryService<AdditionalTokenPayload extends Record = Record<never>, AuthenticationData = void, AdditionalInitSecretResetData = void> {
14
21
  /**
15
22
  * Resolve a provided subject to the actual subject used for authentication.
16
23
  * Useful for example if you want to be able to login via mail but actual subject is the user id.
24
+ * @param providedSubject The subject provided by the user, e.g. an email address.
25
+ * @returns An object with success flag and the resolved subject if successful.
26
+ * If the subject cannot be resolved, return an object with success set to false.
17
27
  */
18
- abstract resolveSubject(providedSubject: string): string | Promise<string>;
28
+ abstract resolveSubject(providedSubject: string): ResolveSubjectResult | Promise<ResolveSubjectResult>;
19
29
  abstract getTokenPayload(subject: string, authenticationData: AuthenticationData, context: GetTokenPayloadContext): AdditionalTokenPayload | Promise<AdditionalTokenPayload>;
20
30
  abstract handleInitSecretReset(data: InitSecretResetData & AdditionalInitSecretResetData): void | Promise<void>;
21
31
  /**
@@ -1,7 +1,7 @@
1
1
  import { defineEnum } from '../../enumeration/enumeration.js';
2
2
  export const GetTokenPayloadContextAction = defineEnum('GetTokenPayloadContextAction', {
3
3
  GetToken: 'get-token',
4
- Refresh: 'refresh'
4
+ Refresh: 'refresh',
5
5
  });
6
6
  export class AuthenticationAncillaryService {
7
7
  }
@@ -13,7 +13,7 @@ export class AuthenticationSecretRequirementsValidator {
13
13
  }
14
14
  let DefaultAuthenticationSecretRequirementsValidator = class DefaultAuthenticationSecretRequirementsValidator extends AuthenticationSecretRequirementsValidator {
15
15
  async checkSecretRequirements(secret) {
16
- return checkPassword(secret, { checkForPwned: true });
16
+ return await checkPassword(secret, { checkForPwned: true });
17
17
  }
18
18
  async testSecretRequirements(secret) {
19
19
  const result = await this.checkSecretRequirements(secret);
@@ -16,7 +16,7 @@ import { authenticationApiDefinition, getAuthenticationApiDefinition } from '../
16
16
  import { AuthenticationService } from './authentication.service.js';
17
17
  import { tryGetAuthorizationTokenStringFromRequest } from './helper.js';
18
18
  const cookieBaseOptions = { path: '/', httpOnly: true, secure: true, sameSite: 'strict' };
19
- const deleteCookie = { value: '', ...cookieBaseOptions, expires: -1 };
19
+ const deleteCookie = { value: '', ...cookieBaseOptions, maxAge: -1 };
20
20
  let AuthenticationApiController = class AuthenticationApiController {
21
21
  authenticationService;
22
22
  constructor(authenticationService) {
@@ -69,11 +69,11 @@ let AuthenticationApiController = class AuthenticationApiController {
69
69
  cookies: {
70
70
  authorization: deleteCookie,
71
71
  refreshToken: deleteCookie,
72
- impersonatorRefreshToken: deleteCookie
72
+ impersonatorRefreshToken: deleteCookie,
73
73
  },
74
74
  body: {
75
- json: result
76
- }
75
+ json: result,
76
+ },
77
77
  });
78
78
  }
79
79
  async initSecretReset({ parameters }) {
@@ -85,7 +85,7 @@ let AuthenticationApiController = class AuthenticationApiController {
85
85
  return 'ok';
86
86
  }
87
87
  async checkSecret({ parameters }) {
88
- return this.authenticationService.checkSecret(parameters.secret);
88
+ return await this.authenticationService.checkSecret(parameters.secret);
89
89
  }
90
90
  timestamp() {
91
91
  return currentTimestamp();
@@ -94,15 +94,27 @@ let AuthenticationApiController = class AuthenticationApiController {
94
94
  const result = jsonToken.payload;
95
95
  const options = {
96
96
  cookies: {
97
- authorization: { value: `Bearer ${token}`, ...cookieBaseOptions, expires: jsonToken.payload.exp * 1000 },
98
- refreshToken: { value: `Bearer ${refreshToken}`, ...cookieBaseOptions, expires: jsonToken.payload.refreshTokenExp * 1000 }
97
+ authorization: {
98
+ value: `Bearer ${token}`,
99
+ ...cookieBaseOptions,
100
+ expires: jsonToken.payload.exp * 1000,
101
+ },
102
+ refreshToken: {
103
+ value: `Bearer ${refreshToken}`,
104
+ ...cookieBaseOptions,
105
+ expires: jsonToken.payload.refreshTokenExp * 1000,
106
+ },
99
107
  },
100
108
  body: {
101
- json: result
102
- }
109
+ json: result,
110
+ },
103
111
  };
104
112
  if (isDefined(impersonatorRefreshToken)) {
105
- options.cookies['impersonatorRefreshToken'] = { value: `Bearer ${impersonatorRefreshToken}`, ...cookieBaseOptions, expires: assertDefinedPass(impersonatorRefreshTokenExpiration) * 1000 };
113
+ options.cookies['impersonatorRefreshToken'] = {
114
+ value: `Bearer ${impersonatorRefreshToken}`,
115
+ ...cookieBaseOptions,
116
+ expires: assertDefinedPass(impersonatorRefreshTokenExpiration) * 1000,
117
+ };
106
118
  }
107
119
  if (omitImpersonatorRefreshToken == true) {
108
120
  options.cookies['impersonatorRefreshToken'] = deleteCookie;
@@ -51,6 +51,8 @@ export type TokenResult<AdditionalTokenPayload extends Record> = {
51
51
  export type SetCredentialsOptions = {
52
52
  /** skip validation for password strength */
53
53
  skipValidation?: boolean;
54
+ /** skip session invalidation */
55
+ skipSessionInvalidation?: boolean;
54
56
  };
55
57
  type CreateTokenResult<AdditionalTokenPayload extends Record> = {
56
58
  token: string;
@@ -63,11 +65,7 @@ type CreateRefreshTokenResult = {
63
65
  hash: Uint8Array;
64
66
  };
65
67
  export declare class AuthenticationService<AdditionalTokenPayload extends Record = Record<never>, AuthenticationData = void, AdditionalInitSecretResetData = void> implements AfterResolve {
66
- private readonly credentialsRepository;
67
- private readonly sessionRepository;
68
- private readonly authenticationSecretRequirementsValidator;
69
- private readonly authenticationAncillaryService;
70
- private readonly options;
68
+ #private;
71
69
  private readonly tokenVersion;
72
70
  private readonly tokenTimeToLive;
73
71
  private readonly refreshTokenTimeToLive;
@@ -96,6 +94,14 @@ export declare class AuthenticationService<AdditionalTokenPayload extends Record
96
94
  validateToken(token: string): Promise<Token<AdditionalTokenPayload>>;
97
95
  validateRefreshToken(token: string): Promise<RefreshToken>;
98
96
  validateSecretResetToken(token: string): Promise<SecretResetToken>;
97
+ tryResolveSubject(subject: string): Promise<string | undefined>;
98
+ /**
99
+ * Resolves the subject to the actual subject used for authentication.
100
+ * This should *not* be used for public facing APIs, as it throws an error if the subject is not found that leaks if the subjects exists or not.
101
+ * Instead use {@link tryResolveSubject} to check if the subject exists without leaking information.
102
+ * @param subject The subject to resolve.
103
+ * @returns The resolved subject or the original subject if not found.
104
+ */
99
105
  resolveSubject(subject: string): Promise<string>;
100
106
  /** Creates a token without session or refresh token and is not saved in database */
101
107
  createToken({ tokenVersion, jwtId, issuedAt, expiration, additionalTokenPayload, subject, sessionId, refreshTokenExpiration, impersonator: impersonatedBy, timestamp }: CreateTokenData<AdditionalTokenPayload>): Promise<CreateTokenResult<AdditionalTokenPayload>>;
@@ -6,14 +6,18 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { ForbiddenError } from '../../errors/forbidden.error.js';
8
8
  import { InvalidTokenError } from '../../errors/invalid-token.error.js';
9
+ import { NotFoundError } from '../../errors/not-found.error.js';
9
10
  import { NotImplementedError } from '../../errors/not-implemented.error.js';
10
11
  import { Singleton, afterResolve, inject, provide } from '../../injector/index.js';
12
+ import { KeyValueStore } from '../../key-value-store/key-value.store.js';
13
+ import { Logger } from '../../logger/logger.js';
11
14
  import { DatabaseConfig } from '../../orm/server/index.js';
12
15
  import { EntityRepositoryConfig, injectRepository } from '../../orm/server/repository.js';
13
16
  import { Alphabet } from '../../utils/alphabet.js';
17
+ import { decodeBase64, encodeBase64 } from '../../utils/base64.js';
14
18
  import { deriveBytesMultiple, importPbkdf2Key } from '../../utils/cryptography.js';
15
19
  import { currentTimestamp, timestampToTimestampSeconds } from '../../utils/date-time.js';
16
- import { binaryEquals } from '../../utils/equals.js';
20
+ import { timingSafeBinaryEquals } from '../../utils/equals.js';
17
21
  import { createJwtTokenString } from '../../utils/jwt.js';
18
22
  import { getRandomBytes, getRandomString } from '../../utils/random.js';
19
23
  import { isBinaryData, isString, isUndefined } from '../../utils/type-guards.js';
@@ -40,15 +44,17 @@ export class AuthenticationServiceOptions {
40
44
  }
41
45
  const SIGNING_SECRETS_LENGTH = 64;
42
46
  let AuthenticationService = class AuthenticationService {
43
- credentialsRepository = injectRepository(AuthenticationCredentials);
44
- sessionRepository = injectRepository(AuthenticationSession);
45
- authenticationSecretRequirementsValidator = inject(AuthenticationSecretRequirementsValidator);
46
- authenticationAncillaryService = inject(AuthenticationAncillaryService, undefined, { optional: true });
47
- options = inject(AuthenticationServiceOptions);
48
- tokenVersion = this.options.version ?? 1;
49
- tokenTimeToLive = this.options.tokenTimeToLive ?? (5 * millisecondsPerMinute);
50
- refreshTokenTimeToLive = this.options.refreshTokenTimeToLive ?? (5 * millisecondsPerDay);
51
- secretResetTokenTimeToLive = this.options.secretResetTokenTimeToLive ?? (10 * millisecondsPerMinute);
47
+ #credentialsRepository = injectRepository(AuthenticationCredentials);
48
+ #sessionRepository = injectRepository(AuthenticationSession);
49
+ #authenticationSecretRequirementsValidator = inject(AuthenticationSecretRequirementsValidator);
50
+ #authenticationAncillaryService = inject(AuthenticationAncillaryService, undefined, { optional: true });
51
+ #keyValueStore = inject((KeyValueStore), 'authentication');
52
+ #options = inject(AuthenticationServiceOptions);
53
+ #logger = inject(Logger, 'authentication');
54
+ tokenVersion = this.#options.version ?? 1;
55
+ tokenTimeToLive = this.#options.tokenTimeToLive ?? (5 * millisecondsPerMinute);
56
+ refreshTokenTimeToLive = this.#options.refreshTokenTimeToLive ?? (5 * millisecondsPerDay);
57
+ secretResetTokenTimeToLive = this.#options.secretResetTokenTimeToLive ?? (10 * millisecondsPerMinute);
52
58
  derivedTokenSigningSecret;
53
59
  derivedRefreshTokenSigningSecret;
54
60
  derivedSecretResetTokenSigningSecret;
@@ -56,37 +62,44 @@ let AuthenticationService = class AuthenticationService {
56
62
  await this.initialize();
57
63
  }
58
64
  async initialize() {
59
- if (isString(this.options.secret) || isBinaryData(this.options.secret)) {
60
- await this.deriveSigningSecrets(this.options.secret);
65
+ if (isString(this.#options.secret) || isBinaryData(this.#options.secret)) {
66
+ await this.deriveSigningSecrets(this.#options.secret);
61
67
  }
62
68
  else {
63
- this.derivedTokenSigningSecret = this.options.secret.tokenSigningSecret;
64
- this.derivedRefreshTokenSigningSecret = this.options.secret.refreshTokenSigningSecret;
65
- this.derivedSecretResetTokenSigningSecret = this.options.secret.secretResetTokenSigningSecret;
69
+ this.derivedTokenSigningSecret = this.#options.secret.tokenSigningSecret;
70
+ this.derivedRefreshTokenSigningSecret = this.#options.secret.refreshTokenSigningSecret;
71
+ this.derivedSecretResetTokenSigningSecret = this.#options.secret.secretResetTokenSigningSecret;
66
72
  }
67
73
  }
68
74
  async setCredentials(subject, secret, options) {
75
+ // We do not need to avoid information leakage here, as this is a non-public method that is only called by a public api if the secret reset token is valid.
69
76
  const actualSubject = await this.resolveSubject(subject);
70
77
  if (options?.skipValidation != true) {
71
- await this.authenticationSecretRequirementsValidator.validateSecretRequirements(secret);
78
+ await this.#authenticationSecretRequirementsValidator.validateSecretRequirements(secret);
72
79
  }
73
80
  const salt = getRandomBytes(32);
74
81
  const hash = await this.getHash(secret, salt);
75
- await this.credentialsRepository.upsert('subject', {
76
- subject: actualSubject,
77
- hashVersion: 1,
78
- salt,
79
- hash,
82
+ await this.#credentialsRepository.transaction(async (tx) => {
83
+ await this.#credentialsRepository.withTransaction(tx).upsert('subject', {
84
+ subject: actualSubject,
85
+ hashVersion: 1,
86
+ salt,
87
+ hash,
88
+ });
89
+ if (options?.skipSessionInvalidation != true) {
90
+ await this.#sessionRepository.withTransaction(tx).updateManyByQuery({ subject: actualSubject }, { end: currentTimestamp() });
91
+ }
80
92
  });
81
93
  }
82
94
  async authenticate(subject, secret) {
83
- const actualSubject = await this.resolveSubject(subject);
84
- const credentials = await this.credentialsRepository.tryLoadByQuery({ subject: actualSubject });
85
- if (isUndefined(credentials)) {
86
- return { success: false };
87
- }
95
+ const actualSubject = await this.tryResolveSubject(subject) ?? subject;
96
+ // Always try to load credentials, even if the subject is not resolved, to avoid information leakage.
97
+ // If the subject is not resolved, we will create a new credentials entry with an empty salt and hash.
98
+ // This way, we do not leak if the subject exists or not via timing attacks.
99
+ const credentials = await this.#credentialsRepository.tryLoadByQuery({ subject: actualSubject })
100
+ ?? { subject: actualSubject, salt: new Uint8Array(), hash: new Uint8Array() };
88
101
  const hash = await this.getHash(secret, credentials.salt);
89
- const valid = binaryEquals(hash, credentials.hash);
102
+ const valid = timingSafeBinaryEquals(hash, credentials.hash);
90
103
  if (valid) {
91
104
  return { success: true, subject: credentials.subject };
92
105
  }
@@ -96,8 +109,8 @@ let AuthenticationService = class AuthenticationService {
96
109
  const actualSubject = await this.resolveSubject(subject);
97
110
  const now = currentTimestamp();
98
111
  const end = now + this.refreshTokenTimeToLive;
99
- return this.sessionRepository.transaction(async (tx) => {
100
- const session = await this.sessionRepository.withTransaction(tx).insert({
112
+ return await this.#sessionRepository.transaction(async (tx) => {
113
+ const session = await this.#sessionRepository.withTransaction(tx).insert({
101
114
  subject: actualSubject,
102
115
  begin: now,
103
116
  end,
@@ -105,10 +118,10 @@ let AuthenticationService = class AuthenticationService {
105
118
  refreshTokenSalt: new Uint8Array(),
106
119
  refreshTokenHash: new Uint8Array(),
107
120
  });
108
- const tokenPayload = await this.authenticationAncillaryService?.getTokenPayload(actualSubject, authenticationData, { action: GetTokenPayloadContextAction.GetToken });
121
+ const tokenPayload = await this.#authenticationAncillaryService?.getTokenPayload(actualSubject, authenticationData, { action: GetTokenPayloadContextAction.GetToken });
109
122
  const { token, jsonToken } = await this.createToken({ additionalTokenPayload: tokenPayload, subject: actualSubject, impersonator, sessionId: session.id, refreshTokenExpiration: end, timestamp: now });
110
123
  const refreshToken = await this.createRefreshToken(actualSubject, session.id, end, { impersonator });
111
- await this.sessionRepository.withTransaction(tx).update(session.id, {
124
+ await this.#sessionRepository.withTransaction(tx).update(session.id, {
112
125
  end,
113
126
  refreshTokenHashVersion: 1,
114
127
  refreshTokenSalt: refreshToken.salt,
@@ -119,26 +132,26 @@ let AuthenticationService = class AuthenticationService {
119
132
  }
120
133
  async endSession(sessionId) {
121
134
  const now = currentTimestamp();
122
- await this.sessionRepository.update(sessionId, { end: now });
135
+ await this.#sessionRepository.update(sessionId, { end: now });
123
136
  }
124
137
  async refresh(refreshToken, authenticationData, { omitImpersonator = false } = {}) {
125
138
  const validatedRefreshToken = await this.validateRefreshToken(refreshToken);
126
139
  const sessionId = validatedRefreshToken.payload.sessionId;
127
- const session = await this.sessionRepository.load(sessionId);
140
+ const session = await this.#sessionRepository.load(sessionId);
128
141
  const hash = await this.getHash(validatedRefreshToken.payload.secret, session.refreshTokenSalt);
129
142
  if (session.end <= currentTimestamp()) {
130
143
  throw new InvalidTokenError('Session is expired.');
131
144
  }
132
- if (!binaryEquals(hash, session.refreshTokenHash)) {
145
+ if (!timingSafeBinaryEquals(hash, session.refreshTokenHash)) {
133
146
  throw new InvalidTokenError('Invalid refresh token.');
134
147
  }
135
148
  const now = currentTimestamp();
136
149
  const impersonator = omitImpersonator ? undefined : validatedRefreshToken.payload.impersonator;
137
150
  const newEnd = now + this.refreshTokenTimeToLive;
138
- const tokenPayload = await this.authenticationAncillaryService?.getTokenPayload(session.subject, authenticationData, { action: GetTokenPayloadContextAction.Refresh });
151
+ const tokenPayload = await this.#authenticationAncillaryService?.getTokenPayload(session.subject, authenticationData, { action: GetTokenPayloadContextAction.Refresh });
139
152
  const { token, jsonToken } = await this.createToken({ additionalTokenPayload: tokenPayload, subject: session.subject, sessionId, refreshTokenExpiration: newEnd, impersonator, timestamp: now });
140
153
  const newRefreshToken = await this.createRefreshToken(validatedRefreshToken.payload.subject, sessionId, newEnd, { impersonator });
141
- await this.sessionRepository.update(sessionId, {
154
+ await this.#sessionRepository.update(sessionId, {
142
155
  end: newEnd,
143
156
  refreshTokenHashVersion: 1,
144
157
  refreshTokenSalt: newRefreshToken.salt,
@@ -149,7 +162,7 @@ let AuthenticationService = class AuthenticationService {
149
162
  async impersonate(impersonatorRoken, impersonatorRefreshToken, subject, authenticationData) {
150
163
  const validatedImpersonatorRoken = await this.validateToken(impersonatorRoken);
151
164
  const validatedImpersonatorRefreshToken = await this.validateRefreshToken(impersonatorRefreshToken);
152
- const allowed = await this.authenticationAncillaryService?.canImpersonate(validatedImpersonatorRoken.payload, subject, authenticationData) ?? false;
165
+ const allowed = await this.#authenticationAncillaryService?.canImpersonate(validatedImpersonatorRoken.payload, subject, authenticationData) ?? false;
153
166
  if (!allowed) {
154
167
  throw new ForbiddenError('Impersonation forbidden.');
155
168
  }
@@ -161,45 +174,78 @@ let AuthenticationService = class AuthenticationService {
161
174
  };
162
175
  }
163
176
  async unimpersonate(impersonatorRefreshToken, authenticationData) {
164
- return this.refresh(impersonatorRefreshToken, authenticationData, { omitImpersonator: true });
177
+ return await this.refresh(impersonatorRefreshToken, authenticationData, { omitImpersonator: true });
165
178
  }
166
179
  async initSecretReset(subject, data) {
167
- if (isUndefined(this.authenticationAncillaryService)) {
180
+ if (isUndefined(this.#authenticationAncillaryService)) {
168
181
  throw new NotImplementedError();
169
182
  }
170
- const actualSubject = await this.resolveSubject(subject);
183
+ const actualSubject = await this.tryResolveSubject(subject);
184
+ if (isUndefined(actualSubject)) {
185
+ this.#logger.warn(`Subject "${subject}" not found for secret reset.`);
186
+ /**
187
+ * If the subject cannot be resolved, we do not throw an error here to avoid information leakage.
188
+ * This is to prevent attackers from discovering valid subjects by trying to reset secrets.
189
+ * Instead, we simply log the attempt and return without performing any action.
190
+ */
191
+ return;
192
+ }
171
193
  const secretResetToken = await this.createSecretResetToken(actualSubject, currentTimestamp() + this.secretResetTokenTimeToLive);
172
194
  const initSecretResetData = {
173
195
  subject: actualSubject,
174
196
  token: secretResetToken.token,
175
197
  ...data,
176
198
  };
177
- await this.authenticationAncillaryService.handleInitSecretReset(initSecretResetData);
199
+ await this.#authenticationAncillaryService.handleInitSecretReset(initSecretResetData);
178
200
  }
179
201
  async resetSecret(tokenString, newSecret) {
180
202
  const token = await this.validateSecretResetToken(tokenString);
181
203
  await this.setCredentials(token.payload.subject, newSecret);
182
204
  }
183
205
  async checkSecret(secret) {
184
- return this.authenticationSecretRequirementsValidator.checkSecretRequirements(secret);
206
+ return await this.#authenticationSecretRequirementsValidator.checkSecretRequirements(secret);
185
207
  }
186
208
  async testSecret(secret) {
187
- return this.authenticationSecretRequirementsValidator.testSecretRequirements(secret);
209
+ return await this.#authenticationSecretRequirementsValidator.testSecretRequirements(secret);
188
210
  }
189
211
  async validateSecret(secret) {
190
- return this.authenticationSecretRequirementsValidator.validateSecretRequirements(secret);
212
+ await this.#authenticationSecretRequirementsValidator.validateSecretRequirements(secret);
191
213
  }
192
214
  async validateToken(token) {
193
- return getTokenFromString(token, this.tokenVersion, this.derivedTokenSigningSecret);
215
+ return await getTokenFromString(token, this.tokenVersion, this.derivedTokenSigningSecret);
194
216
  }
195
217
  async validateRefreshToken(token) {
196
- return getRefreshTokenFromString(token, this.derivedRefreshTokenSigningSecret);
218
+ return await getRefreshTokenFromString(token, this.derivedRefreshTokenSigningSecret);
197
219
  }
198
220
  async validateSecretResetToken(token) {
199
- return getSecretResetTokenFromString(token, this.derivedSecretResetTokenSigningSecret);
221
+ return await getSecretResetTokenFromString(token, this.derivedSecretResetTokenSigningSecret);
200
222
  }
223
+ async tryResolveSubject(subject) {
224
+ if (isUndefined(this.#authenticationAncillaryService)) {
225
+ return subject;
226
+ }
227
+ const result = await this.#authenticationAncillaryService.resolveSubject(subject);
228
+ if (result.success) {
229
+ return result.subject;
230
+ }
231
+ return undefined;
232
+ }
233
+ /**
234
+ * Resolves the subject to the actual subject used for authentication.
235
+ * This should *not* be used for public facing APIs, as it throws an error if the subject is not found that leaks if the subjects exists or not.
236
+ * Instead use {@link tryResolveSubject} to check if the subject exists without leaking information.
237
+ * @param subject The subject to resolve.
238
+ * @returns The resolved subject or the original subject if not found.
239
+ */
201
240
  async resolveSubject(subject) {
202
- return this.authenticationAncillaryService?.resolveSubject(subject) ?? subject;
241
+ if (isUndefined(this.#authenticationAncillaryService)) {
242
+ return subject;
243
+ }
244
+ const result = await this.#authenticationAncillaryService.resolveSubject(subject);
245
+ if (result.success) {
246
+ return result.subject;
247
+ }
248
+ throw new NotFoundError(`Subject not found.`);
203
249
  }
204
250
  /** Creates a token without session or refresh token and is not saved in database */
205
251
  async createToken({ tokenVersion, jwtId, issuedAt, expiration, additionalTokenPayload, subject, sessionId, refreshTokenExpiration, impersonator: impersonatedBy, timestamp = currentTimestamp() }) {
@@ -262,7 +308,9 @@ let AuthenticationService = class AuthenticationService {
262
308
  }
263
309
  async deriveSigningSecrets(secret) {
264
310
  const key = await importPbkdf2Key(secret);
265
- const algorithm = { name: 'PBKDF2', hash: 'SHA-512', iterations: 500000, salt: new Uint8Array() };
311
+ const saltBase64 = await this.#keyValueStore.getOrSet('derivationSalt', encodeBase64(getRandomBytes(32)));
312
+ const salt = decodeBase64(saltBase64);
313
+ const algorithm = { name: 'PBKDF2', hash: 'SHA-512', iterations: 500000, salt };
266
314
  const [derivedTokenSigningSecret, derivedRefreshTokenSigningSecret, derivedSecretResetTokenSigningSecret] = await deriveBytesMultiple(algorithm, key, 3, SIGNING_SECRETS_LENGTH);
267
315
  this.derivedTokenSigningSecret = derivedTokenSigningSecret;
268
316
  this.derivedRefreshTokenSigningSecret = derivedRefreshTokenSigningSecret;
@@ -6,6 +6,6 @@ export default defineConfig({
6
6
  schema: resolve(__dirname, '../models/schemas.js'),
7
7
  migrations: {
8
8
  schema: 'authentication',
9
- table: '_migrations'
10
- }
9
+ table: '_migrations',
10
+ },
11
11
  });
@@ -33,6 +33,6 @@ export async function migrateAuthenticationSchema() {
33
33
  await migrate(database, {
34
34
  migrationsSchema: 'authentication',
35
35
  migrationsTable: '_migrations',
36
- migrationsFolder: import.meta.resolve('./drizzle').replace('file://', '')
36
+ migrationsFolder: import.meta.resolve('./drizzle').replace('file://', ''),
37
37
  });
38
38
  }
@@ -40,11 +40,11 @@ export declare class CancellationSignal implements PromiseLike<void>, Subscribab
40
40
  /**
41
41
  * Observable which emits when this token is set.
42
42
  */
43
- readonly set$: Observable<undefined>;
43
+ readonly set$: Observable<void>;
44
44
  /**
45
45
  * Observable which emits when this token is unset.
46
46
  */
47
- readonly unset$: Observable<undefined>;
47
+ readonly unset$: Observable<void>;
48
48
  /**
49
49
  * Returns a promise which is resolved when this token changes its state.
50
50
  */