@tstdl/base 0.92.144 → 0.92.147

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 (269) hide show
  1. package/ai/ai-file.service.d.ts +29 -1
  2. package/ai/ai-file.service.js +66 -23
  3. package/ai/ai-session.d.ts +28 -1
  4. package/ai/ai-session.js +27 -0
  5. package/ai/ai.service.d.ts +89 -5
  6. package/ai/ai.service.js +130 -27
  7. package/ai/functions.d.ts +7 -1
  8. package/ai/functions.js +7 -1
  9. package/ai/module.d.ts +8 -0
  10. package/ai/module.js +4 -0
  11. package/ai/types.d.ts +115 -2
  12. package/ai/types.js +16 -0
  13. package/api/client/client.d.ts +1 -1
  14. package/api/client/client.js +1 -1
  15. package/api/default-error-handlers.d.ts +1 -1
  16. package/api/index.d.ts +1 -9
  17. package/api/index.js +1 -9
  18. package/api/response.d.ts +1 -1
  19. package/api/server/api-controller.d.ts +1 -1
  20. package/api/server/error-handler.d.ts +1 -1
  21. package/api/server/gateway.d.ts +1 -5
  22. package/api/server/gateway.js +0 -4
  23. package/api/server/middlewares/catch-error.middleware.d.ts +1 -1
  24. package/api/server/module.d.ts +1 -1
  25. package/api/types.d.ts +1 -1
  26. package/application/application.d.ts +1 -1
  27. package/authentication/authentication.api.d.ts +36 -1
  28. package/authentication/authentication.api.js +28 -0
  29. package/authentication/client/api.client.d.ts +14 -1
  30. package/authentication/client/api.client.js +13 -0
  31. package/authentication/client/authentication.service.d.ts +104 -1
  32. package/authentication/client/authentication.service.js +103 -0
  33. package/authentication/client/http-client.middleware.d.ts +5 -0
  34. package/authentication/client/http-client.middleware.js +6 -2
  35. package/authentication/client/module.d.ts +20 -1
  36. package/authentication/client/module.js +6 -1
  37. package/authentication/client/tokens.d.ts +6 -0
  38. package/authentication/client/tokens.js +6 -0
  39. package/authentication/models/authentication-credentials.model.d.ts +6 -0
  40. package/authentication/models/authentication-credentials.model.js +6 -0
  41. package/authentication/models/authentication-session.model.d.ts +6 -0
  42. package/authentication/models/authentication-session.model.js +6 -0
  43. package/authentication/models/init-secret-reset-data.model.d.ts +10 -1
  44. package/authentication/models/init-secret-reset-data.model.js +10 -1
  45. package/authentication/models/token-payload-base.model.d.ts +24 -4
  46. package/authentication/models/token-payload-base.model.js +24 -4
  47. package/authentication/models/token.model.d.ts +33 -2
  48. package/authentication/server/authentication-ancillary.service.d.ts +27 -4
  49. package/authentication/server/authentication-ancillary.service.js +7 -0
  50. package/authentication/server/authentication-api-request-token.provider.d.ts +3 -0
  51. package/authentication/server/authentication-api-request-token.provider.js +3 -0
  52. package/authentication/server/authentication-secret-requirements.validator.d.ts +37 -0
  53. package/authentication/server/authentication-secret-requirements.validator.js +22 -0
  54. package/authentication/server/authentication.api-controller.d.ts +66 -1
  55. package/authentication/server/authentication.api-controller.js +65 -0
  56. package/authentication/server/authentication.service.d.ts +191 -11
  57. package/authentication/server/authentication.service.js +157 -8
  58. package/authentication/server/helper.d.ts +44 -5
  59. package/authentication/server/helper.js +43 -4
  60. package/authentication/server/module.d.ts +23 -1
  61. package/authentication/server/module.js +23 -1
  62. package/browser/browser-context-controller.d.ts +1 -1
  63. package/browser/browser-controller.d.ts +1 -1
  64. package/browser/browser-controller.js +1 -1
  65. package/browser/element-controller.d.ts +1 -1
  66. package/browser/locator-controller.d.ts +1 -1
  67. package/context/context.d.ts +1 -1
  68. package/data-structures/context-data-map.d.ts +1 -1
  69. package/database/mongo/mongo-base.repository.d.ts +1 -1
  70. package/database/mongo/types.d.ts +1 -1
  71. package/database/query.d.ts +1 -1
  72. package/document-management/models/document-assignment-task.model.js +1 -0
  73. package/document-management/models/document-management-table.d.ts +1 -1
  74. package/document-management/models/document-validation-definition.model.d.ts +1 -1
  75. package/document-management/models/document-validation-execution.model.js +1 -0
  76. package/document-management/models/document-workflow.model.js +3 -2
  77. package/document-management/server/api/document-management.api.d.ts +1 -1
  78. package/document-management/server/api/document-management.api.js +3 -3
  79. package/document-management/server/drizzle/{0000_parallel_mantis.sql → 0000_ordinary_pretty_boy.sql} +6 -3
  80. package/document-management/server/drizzle/meta/0000_snapshot.json +27 -2
  81. package/document-management/server/drizzle/meta/_journal.json +2 -2
  82. package/document-management/server/schemas.d.ts +1 -1
  83. package/document-management/server/services/document-collection.service.d.ts +2 -2
  84. package/document-management/server/services/document-management-ai.service.js +7 -5
  85. package/document-management/server/services/document-management-ancillary.service.d.ts +1 -1
  86. package/document-management/server/services/document-management-observation.service.d.ts +1 -1
  87. package/document-management/server/services/document-management.service.d.ts +1 -1
  88. package/document-management/server/services/document-management.service.js +1 -1
  89. package/document-management/server/services/document-property.service.d.ts +3 -3
  90. package/document-management/server/services/document-request.service.d.ts +2 -2
  91. package/document-management/server/services/document-request.service.js +1 -1
  92. package/document-management/server/services/document-tag.service.js +1 -1
  93. package/document-management/server/services/document-validation.service.d.ts +2 -2
  94. package/document-management/server/services/document-validation.service.js +2 -2
  95. package/document-management/server/services/document-workflow.service.d.ts +2 -2
  96. package/document-management/server/services/document-workflow.service.js +4 -4
  97. package/document-management/server/services/document.service.d.ts +1 -1
  98. package/document-management/server/services/singleton.d.ts +1 -1
  99. package/document-management/server/validators/ai-validation-executor.js +4 -4
  100. package/document-management/server/validators/single-document-validation-executor.js +1 -1
  101. package/document-management/server/validators/validator.d.ts +1 -1
  102. package/document-management/service-models/document-management.view-model.d.ts +1 -1
  103. package/document-management/service-models/enriched/enriched-document-assignment.view.d.ts +1 -1
  104. package/document-management/service-models/enriched/enriched-document-category.view.d.ts +1 -1
  105. package/document-management/service-models/enriched/enriched-document-collection.view.d.ts +1 -1
  106. package/document-management/service-models/enriched/enriched-document-request.view.d.ts +1 -1
  107. package/document-management/service-models/enriched/enriched-document-type.view.d.ts +1 -1
  108. package/document-management/service-models/enriched/enriched-document.view.d.ts +1 -1
  109. package/document-management/service-models/enriched/enriched-requests-template-data.model.d.ts +1 -1
  110. package/dom/file-select-dialog.d.ts +1 -1
  111. package/enumeration/enumeration.d.ts +1 -1
  112. package/errors/custom.error.d.ts +3 -0
  113. package/errors/custom.error.js +0 -1
  114. package/errors/errors.localization.d.ts +1 -1
  115. package/errors/not-supported.error.d.ts +1 -1
  116. package/{formats.js → formats/formats.js} +3 -3
  117. package/formats/index.d.ts +1 -0
  118. package/formats/index.js +1 -0
  119. package/http/client/http-client-request.d.ts +1 -1
  120. package/http/client/http-client-response.d.ts +1 -1
  121. package/http/client/http-client.d.ts +1 -1
  122. package/http/client/module.d.ts +1 -1
  123. package/http/http-body.d.ts +1 -1
  124. package/http/http-value-map.d.ts +1 -1
  125. package/http/http.error.d.ts +1 -1
  126. package/http/server/http-server-request.d.ts +1 -1
  127. package/http/server/http-server-response.d.ts +1 -1
  128. package/http/types.d.ts +1 -1
  129. package/http/utils.d.ts +1 -1
  130. package/injector/decorators.d.ts +4 -4
  131. package/injector/index.d.ts +1 -1
  132. package/injector/index.js +1 -1
  133. package/injector/injector.d.ts +10 -1
  134. package/injector/injector.js +6 -0
  135. package/injector/interfaces.d.ts +1 -1
  136. package/injector/provider.d.ts +1 -1
  137. package/injector/resolution.d.ts +10 -5
  138. package/injector/resolve-chain.d.ts +2 -2
  139. package/injector/resolve-chain.js +1 -1
  140. package/injector/resolve.error.js +1 -1
  141. package/injector/token.d.ts +8 -1
  142. package/injector/token.js +7 -0
  143. package/injector/types.d.ts +1 -1
  144. package/key-value-store/key-value-store.provider.d.ts +2 -2
  145. package/key-value-store/key-value.store.d.ts +2 -2
  146. package/key-value-store/mongo/mongo-key-value-store.provider.d.ts +1 -1
  147. package/key-value-store/mongo/mongo-key-value.store.d.ts +1 -1
  148. package/key-value-store/postgres/key-value-store.service.d.ts +1 -1
  149. package/mail/mail.service.d.ts +1 -1
  150. package/mail/models/mail-data.model.d.ts +1 -1
  151. package/mail/models/mail-template.model.d.ts +1 -1
  152. package/mail/module.d.ts +1 -1
  153. package/module/index.d.ts +0 -1
  154. package/module/index.js +0 -1
  155. package/module/module-base.d.ts +1 -1
  156. package/module/module-metric-reporter.js +1 -1
  157. package/module/module.d.ts +1 -1
  158. package/module/modules/function.module.js +1 -1
  159. package/object-storage/object.d.ts +1 -1
  160. package/openid-connect/mongo-oidc-state.repository.d.ts +1 -1
  161. package/openid-connect/oidc.service.d.ts +1 -1
  162. package/orm/decorators.d.ts +2 -2
  163. package/orm/entity.d.ts +1 -1
  164. package/orm/index.d.ts +3 -3
  165. package/orm/index.js +3 -3
  166. package/orm/query.d.ts +1 -1
  167. package/orm/repository.types.d.ts +1 -1
  168. package/orm/schemas/json.d.ts +1 -1
  169. package/orm/server/database-schema.d.ts +1 -1
  170. package/orm/server/drizzle/schema-converter.d.ts +1 -1
  171. package/orm/server/repository.d.ts +1 -1
  172. package/orm/server/transaction.d.ts +1 -1
  173. package/orm/server/transactional.d.ts +3 -3
  174. package/orm/server/types.d.ts +1 -1
  175. package/orm/types.d.ts +1 -1
  176. package/package.json +24 -21
  177. package/queue/mongo/job.d.ts +1 -1
  178. package/queue/mongo/queue.js +31 -31
  179. package/queue/postgres/job.model.d.ts +1 -1
  180. package/queue/postgres/queue.d.ts +1 -1
  181. package/queue/postgres/queue.provider.d.ts +1 -1
  182. package/queue/provider.d.ts +1 -1
  183. package/reflection/decorators.d.ts +1 -1
  184. package/reflection/registry.d.ts +1 -1
  185. package/reflection/types.d.ts +1 -1
  186. package/reflection/utils.d.ts +1 -1
  187. package/rpc/model.d.ts +1 -1
  188. package/rxjs-utils/retry-backoff.js +2 -2
  189. package/schema/converters/openapi-converter.d.ts +1 -1
  190. package/schema/decorators/schema.d.ts +1 -1
  191. package/schema/decorators/utils.d.ts +1 -1
  192. package/schema/schema.d.ts +1 -1
  193. package/schema/schema.error.d.ts +1 -1
  194. package/schema/schemas/array.d.ts +1 -1
  195. package/schema/schemas/enumeration.d.ts +1 -1
  196. package/schema/schemas/function.d.ts +1 -1
  197. package/schema/schemas/instance.d.ts +1 -1
  198. package/schema/schemas/nullable.d.ts +1 -1
  199. package/schema/schemas/number.d.ts +1 -1
  200. package/schema/schemas/object.d.ts +1 -1
  201. package/schema/schemas/one-or-many.d.ts +1 -1
  202. package/schema/schemas/optional.d.ts +1 -1
  203. package/schema/schemas/simple.d.ts +1 -1
  204. package/search-index/elastic/model/index-mapping.d.ts +1 -1
  205. package/search-index/elastic/search-index.js +3 -4
  206. package/search-index/memory/memory-search-index.d.ts +1 -1
  207. package/search-index/memory/memory-search-index.js +1 -1
  208. package/serializer/handlers/binary.d.ts +1 -1
  209. package/serializer/serializable.d.ts +1 -1
  210. package/serializer/types.d.ts +1 -1
  211. package/templates/module.d.ts +1 -1
  212. package/templates/renderers/handlebars.template-renderer.d.ts +1 -1
  213. package/templates/renderers/jsx.template-renderer.d.ts +1 -1
  214. package/templates/renderers/mjml.template-renderer.d.ts +1 -1
  215. package/templates/renderers/string.template-renderer.d.ts +1 -1
  216. package/templates/resolvers/file.template-resolver.d.ts +1 -1
  217. package/templates/resolvers/jsx.template-resolver.d.ts +1 -1
  218. package/templates/resolvers/string.template-resolver.d.ts +1 -1
  219. package/templates/template.model.d.ts +1 -1
  220. package/templates/template.renderer.d.ts +1 -1
  221. package/templates/template.service.d.ts +1 -1
  222. package/text/dynamic-text.model.d.ts +1 -1
  223. package/text/localization.service.d.ts +1 -1
  224. package/types/geo-json.d.ts +1 -1
  225. package/types/index.d.ts +2 -0
  226. package/types/tagged.d.ts +1 -1
  227. package/{types.d.ts → types/types.d.ts} +2 -1
  228. package/utils/async-hook/async-hook.d.ts +109 -0
  229. package/utils/async-hook/async-hook.js +77 -3
  230. package/utils/backoff.d.ts +125 -43
  231. package/utils/backoff.js +140 -65
  232. package/utils/base64.d.ts +1 -1
  233. package/utils/base64.js +1 -2
  234. package/utils/binary.d.ts +1 -1
  235. package/utils/comparison.d.ts +5 -5
  236. package/utils/comparison.js +5 -3
  237. package/utils/cryptography.d.ts +1 -1
  238. package/utils/encoding.d.ts +1 -1
  239. package/utils/enum.d.ts +1 -1
  240. package/utils/equals.d.ts +1 -1
  241. package/utils/format-error.d.ts +1 -1
  242. package/utils/function/class.d.ts +1 -1
  243. package/utils/function/memoize.d.ts +1 -1
  244. package/utils/helpers.d.ts +1 -1
  245. package/utils/helpers.js +2 -2
  246. package/utils/jwt.d.ts +3 -3
  247. package/utils/merge.d.ts +1 -1
  248. package/utils/middleware.js +3 -3
  249. package/utils/object/decycle.d.ts +1 -1
  250. package/utils/object/forward-ref.d.ts +1 -1
  251. package/utils/object/lazy-property.d.ts +1 -1
  252. package/utils/object/object.d.ts +1 -1
  253. package/utils/object/property-name.d.ts +1 -1
  254. package/utils/patch-worker.d.ts +1 -1
  255. package/utils/reactive-value-to-signal.d.ts +1 -1
  256. package/utils/reflection.d.ts +1 -1
  257. package/utils/repl.d.ts +1 -1
  258. package/utils/singleton.d.ts +1 -1
  259. package/utils/stream/size-limited-stream.d.ts +1 -1
  260. package/utils/type/extends.d.ts +1 -1
  261. package/utils/type-guards.d.ts +1 -1
  262. package/utils/url-builder.d.ts +1 -1
  263. package/utils/z-base32.d.ts +1 -1
  264. package/module/utils.d.ts +0 -4
  265. package/module/utils.js +0 -21
  266. /package/{formats.d.ts → formats/formats.d.ts} +0 -0
  267. /package/{types.js → types/types.js} +0 -0
  268. /package/{web-types.d.ts → types/web-types.d.ts} +0 -0
  269. /package/{web-types.js → types/web-types.js} +0 -0
@@ -1,3 +1,70 @@
1
+ /**
2
+ * Creates a new asynchronous hook.
3
+ *
4
+ * An async hook is a system that allows you to register multiple "handler" functions
5
+ * that will be executed in sequence when a "trigger" event occurs. This is useful
6
+ * for creating extensible, plugin-like architectures. Handlers can be synchronous
7
+ * or asynchronous.
8
+ *
9
+ * @template T The type of the primary value that the hook is triggered with.
10
+ * @template C The type of the optional context object passed to the hook's trigger and handlers. Defaults to `never`.
11
+ * @template R The return type of an individual handler. The `trigger` method will resolve with an array of these values (`R[]`). Defaults to `unknown`.
12
+ * @returns {AsyncHook<T, C, R>} An object with `register` and `trigger` methods.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * // Simple hook without context
17
+ * async function runSimpleExample() {
18
+ * const onTaskStart = asyncHook<string>();
19
+ *
20
+ * onTaskStart.register(taskName => {
21
+ * console.log(`[Logger] Task started: ${taskName}`);
22
+ * });
23
+ *
24
+ * const registration = onTaskStart.register(async taskName => {
25
+ * await new Promise(resolve => setTimeout(resolve, 50));
26
+ * console.log(`[Notifier] Notifying that task started: ${taskName}`);
27
+ * });
28
+ *
29
+ * await onTaskStart.trigger('Process Data');
30
+ * // [Logger] Task started: Process Data
31
+ * // [Notifier] Notifying that task started: Process Data
32
+ *
33
+ * registration.unregister();
34
+ * console.log('Notifier unregistered.');
35
+ *
36
+ * await onTaskStart.trigger('Finalize Report');
37
+ * // [Logger] Task started: Finalize Report
38
+ * }
39
+ * ```
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * // Hook with a context object
44
+ * async function runContextExample() {
45
+ * type TaskContext = { userId: number; transactionId: string };
46
+ *
47
+ * const onTaskComplete = asyncHook<string, TaskContext, boolean>();
48
+ *
49
+ * onTaskComplete.register((taskName, context) => {
50
+ * console.log(`[Audit] Task '${taskName}' completed by user ${context.userId}.`);
51
+ * return true; // Audit successful
52
+ * });
53
+ *
54
+ * onTaskComplete.register(async (taskName, context) => {
55
+ * console.log(`[DB] Logging completion of '${taskName}' for transaction ${context.transactionId}.`);
56
+ * return true; // DB update successful
57
+ * });
58
+ *
59
+ * const results = await onTaskComplete.trigger(
60
+ * 'SubmitOrder',
61
+ * { userId: 123, transactionId: 'abc-456' }
62
+ * );
63
+ *
64
+ * console.log('Handler results:', results); // [true, true]
65
+ * }
66
+ * ```
67
+ */
1
68
  export function asyncHook() {
2
69
  const handlers = [];
3
70
  return {
@@ -5,13 +72,20 @@ export function asyncHook() {
5
72
  handlers.push(handler);
6
73
  return {
7
74
  unregister() {
8
- handlers.splice(handlers.indexOf(handler));
75
+ const index = handlers.indexOf(handler);
76
+ if (index > -1) {
77
+ handlers.splice(index, 1);
78
+ }
9
79
  },
10
80
  };
11
81
  },
82
+ // The implementation uses a single function body, but the public type signature
83
+ // is conditional, ensuring type safety for callers.
12
84
  trigger: async (value, context) => {
13
- let returnValues = [];
14
- for (const handler of handlers) {
85
+ const returnValues = [];
86
+ // Create a snapshot of handlers in case one of them unregisters another during its execution.
87
+ for (const handler of [...handlers]) {
88
+ // The non-null assertion `context!` is safe due to the conditional public type of `trigger`.
15
89
  const returnValue = await handler(value, context);
16
90
  returnValues.push(returnValue);
17
91
  }
@@ -1,77 +1,159 @@
1
1
  import type { CancellationSignal } from '../cancellation/token.js';
2
- import { CancellationToken } from '../cancellation/token.js';
3
2
  export type BackoffStrategy = 'linear' | 'exponential';
3
+ /**
4
+ * Configuration for the backoff behavior.
5
+ */
4
6
  export type BackoffOptions = {
5
7
  /**
6
- * how to increase delay
8
+ * The strategy to use for increasing the delay.
9
+ * - `linear`: Adds the `increase` value to the delay in each step.
10
+ * - `exponential`: Multiplies the delay by the `increase` value in each step.
11
+ * @default 'exponential'
7
12
  */
8
- strategy: BackoffStrategy;
13
+ strategy?: BackoffStrategy;
9
14
  /**
10
- * delay to start with
15
+ * The initial delay in milliseconds. Must be non-negative.
16
+ * @default 1000
11
17
  */
12
- initialDelay: number;
18
+ initialDelay?: number;
13
19
  /**
14
- * amount to increase/multiply delay by/with
20
+ * The value to increase the delay with.
21
+ * - For `linear` strategy, this is the number of milliseconds to add.
22
+ * - For `exponential` strategy, this is the multiplication factor.
23
+ * Must be non-negative. For exponential, should be > 1 to ensure growth.
24
+ * @default 2
15
25
  */
16
- increase: number;
26
+ increase?: number;
17
27
  /**
18
- * miaxmum time to back off
28
+ * The maximum delay in milliseconds. The backoff delay will not exceed this value.
29
+ * @default 30000
19
30
  */
20
31
  maximumDelay?: number;
32
+ /**
33
+ * A factor to randomize the delay, e.g., 0.1 for 10% jitter.
34
+ * This helps prevent the "thundering herd" problem in distributed systems.
35
+ * The actual delay will be `delay ± delay * jitter`.
36
+ * Must be a value between 0 and 1.
37
+ * @default 0.15
38
+ */
39
+ jitter?: number;
40
+ };
41
+ export type AutoBackoffLoopOptions = BackoffOptions & {
42
+ cancellationSignal?: CancellationSignal;
43
+ errorHandler?: (error: Error) => void;
44
+ };
45
+ export type BackoffLoopOptions = BackoffOptions & {
46
+ cancellationSignal?: CancellationSignal;
47
+ };
48
+ export type BackoffGeneratorOptions = BackoffOptions & {
49
+ /**
50
+ * An optional signal to terminate the generator.
51
+ * The generator can also be terminated by breaking the `for-await-of` loop.
52
+ */
53
+ cancellationSignal?: CancellationSignal;
21
54
  };
55
+ /**
56
+ * Provides controls for the `backoffLoop`.
57
+ */
22
58
  export type BackoffLoopController = {
23
59
  /**
24
- * backoff before next iteration
60
+ * Schedules a backoff delay before the next iteration of the loop.
61
+ * If this is not called, the backoff delay is reset for the next attempt.
25
62
  */
26
63
  backoff: () => void;
27
64
  /**
28
- * break out of loop
65
+ * Immediately breaks out of the loop.
29
66
  */
30
67
  break: () => void;
31
68
  };
32
- export type BackoffLoopFunction = (controller: BackoffLoopController) => void | Promise<void>;
69
+ export type BackoffLoopFunction = (controller: BackoffLoopController, cancellationSignal: CancellationSignal) => unknown;
70
+ /**
71
+ * A function yielded by `backoffGenerator` to control the next iteration.
72
+ */
73
+ export type BackoffGeneratorCallback = (options?: {
74
+ /**
75
+ * An optional signal that, when set, cancels the current backoff delay and proceeds
76
+ * to the next iteration immediately. This is useful for "continue early" scenarios.
77
+ */
78
+ continueToken?: CancellationSignal;
79
+ }) => void;
80
+ /**
81
+ * Default options for a robust backoff strategy.
82
+ */
83
+ export declare const DEFAULT_BACKOFF_OPTIONS: {
84
+ readonly strategy: "exponential";
85
+ readonly initialDelay: 1000;
86
+ readonly increase: 2;
87
+ readonly maximumDelay: 30000;
88
+ readonly jitter: 0.15;
89
+ };
33
90
  /**
34
- * @param continueToken token to continue loop immediately
91
+ * A helper class to manage the state of a backoff strategy.
35
92
  */
36
- export type BackoffGeneratorYield = (continueToken?: CancellationToken) => void;
37
93
  export declare class BackoffHelper {
38
- private readonly strategy;
39
- private readonly initialDelay;
40
- private readonly increase;
41
- private readonly maximumDelay;
42
- private delay;
43
- constructor({ strategy, initialDelay, increase, maximumDelay }: BackoffOptions);
94
+ private readonly options;
95
+ private currentDelay;
96
+ /**
97
+ * Creates a new BackoffHelper.
98
+ * @param options Partial backoff options, which will be merged with sane defaults.
99
+ */
100
+ constructor(options?: BackoffOptions);
101
+ /**
102
+ * Resets the current delay to the initial delay.
103
+ */
44
104
  reset(): void;
45
- backoff(): number;
105
+ /**
106
+ * Calculates and returns the next backoff delay based on the configured strategy.
107
+ * This also updates the internal state for the subsequent call.
108
+ * @returns The next delay in milliseconds.
109
+ */
110
+ getNextDelay(): number;
46
111
  }
47
112
  /**
48
- * runs a function until token is set or controller returns and automatically backsoff if function throws. Warning: swallows errors
49
- * @param options backoff options
50
- * @param cancellationToken token to cancel loop
51
- * @param loopFunction function to call
113
+ * Runs a function in a loop, automatically backing off on errors.
114
+ *
115
+ * This function is a convenient wrapper that catches any errors from `loopFunction`,
116
+ * triggers a backoff, and continues the loop.
117
+ *
118
+ * @param loopFunction The asynchronous function to execute in each iteration.
119
+ * @param options Additional options for backoff configuration, cancellation, and error handling.
52
120
  */
53
- export declare function autoBackoffLoop(options: BackoffOptions, loopFunction: BackoffLoopFunction, extras?: {
54
- cancellationSignal?: CancellationSignal;
55
- errorHandler?: (error: Error) => void;
56
- }): Promise<void>;
121
+ export declare function autoBackoffLoop(loopFunction: BackoffLoopFunction, options?: AutoBackoffLoopOptions): Promise<void>;
57
122
  /**
58
- * runs a function until token is set or controller returns.
59
- * @param options backoff options
60
- * @param cancellationToken signal to cancel loop
61
- * @param loopFunction function to call
123
+ * Runs a function in a loop, allowing manual control over backoff and breaking.
124
+ * The loop continues until it is explicitly broken via the controller or the cancellation signal is set.
125
+ * If `controller.backoff()` is not called in an iteration, the delay is reset for the next backoff.
126
+ *
127
+ * @param loopFunction The function to execute, receiving a controller to manage the loop.
128
+ * @param options Additional options for backoff configuration and cancellation.
62
129
  */
63
- export declare function backoffLoop(options: BackoffOptions, loopFunction: BackoffLoopFunction, extras?: {
64
- cancellationSignal?: CancellationSignal;
65
- }): Promise<void>;
130
+ export declare function backoffLoop(loopFunction: BackoffLoopFunction, options?: BackoffLoopOptions): Promise<void>;
66
131
  /**
67
- * generates endless function which, when called, backs off next iteration
68
- * @param options backoff options
69
- * @param cancellationSignal signal to cancel loop
132
+ * Creates an async generator that yields a callback to trigger a backoff.
133
+ * This is useful for `for-await-of` loops where you need fine-grained control.
134
+ * The generator terminates when the `cancellationSignal` is set or the loop is terminated by break.
135
+ *
136
+ * @param options Options for backoff configuration and an optional cancellation signal.
70
137
  * @example
71
- * for await (const backoff of backoffGenerator(options, token)) {
72
- * if (iWantToBackoff) {
73
- * backoff();
74
- * }
138
+ * ```ts
139
+ * const token = new CancellationToken();
140
+ *
141
+ * // with a cancellation signal
142
+ * for await (const backoff of backoffGenerator({ cancellationSignal: token.signal })) {
143
+ * const success = await doSomeWork();
144
+ * if (!success) {
145
+ * backoff(); // Schedule a backoff before the next iteration.
146
+ * }
147
+ * }
148
+ *
149
+ * // without a cancellation signal (loop is broken manually)
150
+ * for await (const backoff of backoffGenerator()) {
151
+ * const success = await doSomeWork();
152
+ * if (success) {
153
+ * break; // Exit the loop
154
+ * }
155
+ * backoff();
75
156
  * }
157
+ * ```
76
158
  */
77
- export declare function backoffGenerator(options: BackoffOptions, cancellationSignal: CancellationSignal): AsyncIterableIterator<BackoffGeneratorYield>;
159
+ export declare function backoffGenerator(options?: BackoffGeneratorOptions): AsyncIterableIterator<BackoffGeneratorCallback>;
package/utils/backoff.js CHANGED
@@ -1,101 +1,177 @@
1
1
  import { CancellationToken } from '../cancellation/token.js';
2
- import { noop } from './noop.js';
2
+ import { NEVER } from 'rxjs';
3
+ import { randomFloat } from './math.js';
3
4
  import { cancelableTimeout } from './timing.js';
4
5
  import { isDefined } from './type-guards.js';
6
+ /**
7
+ * Default options for a robust backoff strategy.
8
+ */
9
+ export const DEFAULT_BACKOFF_OPTIONS = {
10
+ strategy: 'exponential',
11
+ initialDelay: 1000,
12
+ increase: 2,
13
+ maximumDelay: 30_000, // 30 seconds
14
+ jitter: 0.15,
15
+ };
16
+ /**
17
+ * A helper class to manage the state of a backoff strategy.
18
+ */
5
19
  export class BackoffHelper {
6
- strategy;
7
- initialDelay;
8
- increase;
9
- maximumDelay;
10
- delay;
11
- constructor({ strategy, initialDelay, increase, maximumDelay }) {
12
- this.strategy = strategy;
13
- this.initialDelay = initialDelay;
14
- this.increase = increase;
15
- this.maximumDelay = maximumDelay ?? Number.MAX_SAFE_INTEGER;
16
- this.reset();
20
+ options;
21
+ currentDelay;
22
+ /**
23
+ * Creates a new BackoffHelper.
24
+ * @param options Partial backoff options, which will be merged with sane defaults.
25
+ */
26
+ constructor(options) {
27
+ this.options = { ...DEFAULT_BACKOFF_OPTIONS, ...options };
28
+ const { initialDelay, increase, jitter, strategy } = this.options;
29
+ if (initialDelay < 0) {
30
+ throw new Error('initialDelay must be non-negative.');
31
+ }
32
+ if (increase < 0) {
33
+ throw new Error('increase must be non-negative.');
34
+ }
35
+ if ((jitter < 0) || (jitter > 1)) {
36
+ throw new Error('jitter must be between 0 and 1.');
37
+ }
38
+ if (strategy == 'exponential' && increase <= 1) {
39
+ console.warn('Using an exponential backoff with an increase factor <= 1 is not recommended as the delay will not grow.');
40
+ }
41
+ this.currentDelay = this.options.initialDelay;
17
42
  }
43
+ /**
44
+ * Resets the current delay to the initial delay.
45
+ */
18
46
  reset() {
19
- this.delay = this.initialDelay;
47
+ this.currentDelay = this.options.initialDelay;
20
48
  }
21
- backoff() {
22
- this.delay = getNewDelay(this.strategy, this.delay, this.increase, this.maximumDelay);
23
- return this.delay;
49
+ /**
50
+ * Calculates and returns the next backoff delay based on the configured strategy.
51
+ * This also updates the internal state for the subsequent call.
52
+ * @returns The next delay in milliseconds.
53
+ */
54
+ getNextDelay() {
55
+ const newDelay = getNewDelay(this.options.strategy, this.currentDelay, this.options.increase, this.options.maximumDelay);
56
+ this.currentDelay = newDelay;
57
+ if (this.options.jitter > 0) {
58
+ const jitterAmount = newDelay * randomFloat(-this.options.jitter, this.options.jitter); // ±jitter
59
+ return Math.max(0, newDelay + jitterAmount);
60
+ }
61
+ return newDelay;
24
62
  }
25
63
  }
26
64
  /**
27
- * runs a function until token is set or controller returns and automatically backsoff if function throws. Warning: swallows errors
28
- * @param options backoff options
29
- * @param cancellationToken token to cancel loop
30
- * @param loopFunction function to call
65
+ * Runs a function in a loop, automatically backing off on errors.
66
+ *
67
+ * This function is a convenient wrapper that catches any errors from `loopFunction`,
68
+ * triggers a backoff, and continues the loop.
69
+ *
70
+ * @param loopFunction The asynchronous function to execute in each iteration.
71
+ * @param options Additional options for backoff configuration, cancellation, and error handling.
31
72
  */
32
- export async function autoBackoffLoop(options, loopFunction, extras) {
33
- const errorHandler = extras?.errorHandler ?? noop;
34
- return backoffLoop(options, async (controller) => {
73
+ export async function autoBackoffLoop(loopFunction, options = {}) {
74
+ const { errorHandler, ...loopOptions } = options;
75
+ await backoffLoop(async (controller, signal) => {
35
76
  try {
36
- await loopFunction(controller);
77
+ await loopFunction(controller, signal);
37
78
  }
38
79
  catch (error) {
39
- errorHandler(error);
80
+ errorHandler?.(error);
40
81
  controller.backoff();
41
82
  }
42
- }, { cancellationSignal: extras?.cancellationSignal });
83
+ }, loopOptions);
43
84
  }
44
85
  /**
45
- * runs a function until token is set or controller returns.
46
- * @param options backoff options
47
- * @param cancellationToken signal to cancel loop
48
- * @param loopFunction function to call
86
+ * Runs a function in a loop, allowing manual control over backoff and breaking.
87
+ * The loop continues until it is explicitly broken via the controller or the cancellation signal is set.
88
+ * If `controller.backoff()` is not called in an iteration, the delay is reset for the next backoff.
89
+ *
90
+ * @param loopFunction The function to execute, receiving a controller to manage the loop.
91
+ * @param options Additional options for backoff configuration and cancellation.
49
92
  */
50
- export async function backoffLoop(options, loopFunction, extras) {
51
- const backoffHelper = new BackoffHelper(options);
52
- const loopCancellationToken = extras?.cancellationSignal?.createChild({ unset: false, complete: false }) ?? new CancellationToken();
53
- let backoff = false;
93
+ export async function backoffLoop(loopFunction, options = {}) {
94
+ const { cancellationSignal, ...backoffOptions } = options;
95
+ const backoffHelper = new BackoffHelper(backoffOptions);
96
+ const loopToken = new CancellationToken();
97
+ let shouldBackoff = false;
98
+ if (isDefined(cancellationSignal)) {
99
+ loopToken.inherit(cancellationSignal, { set: true, unset: false, complete: false, error: false });
100
+ }
54
101
  const controller = {
55
- backoff: () => backoff = true,
56
- break: () => loopCancellationToken.set()
102
+ backoff: () => shouldBackoff = true,
103
+ break: () => loopToken.set(),
57
104
  };
58
- while (!loopCancellationToken.isSet) {
59
- await loopFunction(controller);
60
- if (loopCancellationToken.isSet) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
105
+ while (loopToken.isUnset) {
106
+ await loopFunction(controller, loopToken.signal);
107
+ // Exit immediately if the loop function requested a break.
108
+ if (loopToken.isSet) {
61
109
  return;
62
110
  }
63
- if (backoff) {
64
- backoff = false;
65
- const milliseconds = backoffHelper.backoff();
66
- await cancelableTimeout(milliseconds, loopCancellationToken);
111
+ if (shouldBackoff) {
112
+ shouldBackoff = false;
113
+ const delay = backoffHelper.getNextDelay();
114
+ await cancelableTimeout(delay, loopToken.signal);
67
115
  }
68
116
  else {
117
+ // If an iteration completes successfully without a backoff request, reset the delay.
69
118
  backoffHelper.reset();
70
119
  }
71
120
  }
72
121
  }
73
122
  /**
74
- * generates endless function which, when called, backs off next iteration
75
- * @param options backoff options
76
- * @param cancellationSignal signal to cancel loop
123
+ * Creates an async generator that yields a callback to trigger a backoff.
124
+ * This is useful for `for-await-of` loops where you need fine-grained control.
125
+ * The generator terminates when the `cancellationSignal` is set or the loop is terminated by break.
126
+ *
127
+ * @param options Options for backoff configuration and an optional cancellation signal.
77
128
  * @example
78
- * for await (const backoff of backoffGenerator(options, token)) {
79
- * if (iWantToBackoff) {
80
- * backoff();
81
- * }
129
+ * ```ts
130
+ * const token = new CancellationToken();
131
+ *
132
+ * // with a cancellation signal
133
+ * for await (const backoff of backoffGenerator({ cancellationSignal: token.signal })) {
134
+ * const success = await doSomeWork();
135
+ * if (!success) {
136
+ * backoff(); // Schedule a backoff before the next iteration.
137
+ * }
82
138
  * }
139
+ *
140
+ * // without a cancellation signal (loop is broken manually)
141
+ * for await (const backoff of backoffGenerator()) {
142
+ * const success = await doSomeWork();
143
+ * if (success) {
144
+ * break; // Exit the loop
145
+ * }
146
+ * backoff();
147
+ * }
148
+ * ```
83
149
  */
84
- export async function* backoffGenerator(options, cancellationSignal) {
85
- const backoffHelper = new BackoffHelper(options);
86
- while (cancellationSignal.isUnset) {
87
- let backoff = false;
88
- let timeoutToken = cancellationSignal;
89
- const backoffFunction = (continueToken) => {
90
- backoff = true;
150
+ export async function* backoffGenerator(options = {}) {
151
+ const { cancellationSignal, ...backoffOptions } = options;
152
+ const backoffHelper = new BackoffHelper(backoffOptions);
153
+ // Loop indefinitely if no cancellation signal is provided.
154
+ // The consumer is responsible for breaking the loop.
155
+ while (cancellationSignal?.isUnset ?? true) {
156
+ let backoffTriggered = false;
157
+ let timeoutSignal = cancellationSignal;
158
+ const backoffCallback = (backoffOptions) => {
159
+ backoffTriggered = true;
160
+ const continueToken = backoffOptions?.continueToken;
91
161
  if (isDefined(continueToken)) {
92
- timeoutToken = cancellationSignal.createChild().inherit(continueToken);
162
+ timeoutSignal = isDefined(cancellationSignal)
163
+ ? cancellationSignal.createChild().inherit(continueToken)
164
+ : continueToken;
93
165
  }
94
166
  };
95
- yield backoffFunction;
96
- if (backoff) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
97
- const milliseconds = backoffHelper.backoff();
98
- await cancelableTimeout(milliseconds, timeoutToken);
167
+ yield backoffCallback;
168
+ // Break immediately if the cancellation signal (if provided) is set.
169
+ if (cancellationSignal?.isSet == true) {
170
+ break;
171
+ }
172
+ if (backoffTriggered) {
173
+ const delay = backoffHelper.getNextDelay();
174
+ await cancelableTimeout(delay, timeoutSignal ?? NEVER);
99
175
  }
100
176
  else {
101
177
  backoffHelper.reset();
@@ -112,8 +188,7 @@ function getNewDelay(strategy, currentDelay, increase, maximumDelay) {
112
188
  newDelay = currentDelay * increase;
113
189
  break;
114
190
  default:
115
- throw new Error('unknown backoff-strategy');
191
+ throw new Error(`Unknown backoff strategy: ${strategy}`);
116
192
  }
117
- newDelay = Math.min(newDelay, maximumDelay);
118
- return newDelay;
193
+ return Math.min(newDelay, maximumDelay);
119
194
  }
package/utils/base64.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { BinaryData } from '../types.js';
1
+ import type { BinaryData } from '../types/index.js';
2
2
  export declare function encodeBase64(array: BinaryData, bytesOffset?: number, bytesLength?: number): string;
3
3
  export declare function decodeBase64(base64: string): Uint8Array;
4
4
  export declare function encodeBase64Url(array: BinaryData, bytesOffset?: number, length?: number): string;
package/utils/base64.js CHANGED
@@ -36,7 +36,7 @@ export function decodeBase64Url(base64Url) {
36
36
  }
37
37
  export function base64ToBase64Url(input) {
38
38
  return input
39
- .replace(/=/ug, '') // eslint-disable-line no-div-regex
39
+ .replace(/=/ug, '')
40
40
  .replace(/\+/ug, '-')
41
41
  .replace(/\//ug, '_');
42
42
  }
@@ -98,7 +98,6 @@ export function utf8ArrayToString(bytes) {
98
98
  }
99
99
  return string;
100
100
  }
101
- // eslint-disable-next-line max-lines-per-function, max-statements
102
101
  export function stringToUtf8Array(string) {
103
102
  let bytesLength = 0;
104
103
  for (let i = 0; i < string.length; i++) {
package/utils/binary.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { BinaryData, Type } from '../types.js';
1
+ import type { BinaryData, Type } from '../types/index.js';
2
2
  /**
3
3
  * Get ArrayBuffer from binary data
4
4
  * @param data data to get ArrayBuffer from
@@ -1,8 +1,8 @@
1
- export declare function compareByValueSelection<T>(...selectors: ((item: T) => unknown)[]): (a: T, b: T) => number;
2
- export declare function compareByValueSelectionDescending<T>(...selectors: ((item: T) => unknown)[]): (a: T, b: T) => number;
3
- export declare function compareByValueSelectionOrdered<T>(...selectors: (readonly [(item: T) => unknown, 1 | -1])[]): (a: T, b: T) => number;
1
+ export declare function compareByValueSelection<T, C extends string | number>(...selectors: ((item: T) => C)[]): (a: T, b: T) => number;
2
+ export declare function compareByValueSelectionDescending<T, C extends string | number>(...selectors: ((item: T) => C)[]): (a: T, b: T) => number;
3
+ export declare function compareByValueSelectionOrdered<T, C extends string | number>(...selectors: (readonly [(item: T) => C, 1 | -1])[]): (a: T, b: T) => number;
4
4
  export declare function compareByValueToOrder<T>(order: T[]): (a: T, b: T) => number;
5
5
  export declare const orderRest: unique symbol;
6
6
  export declare function compareByValueSelectionToOrder<T, TSelect>(order: (TSelect | typeof orderRest)[], selector: (item: T) => TSelect): (a: T, b: T) => number;
7
- export declare function compareByValue<T>(a: T, b: T, strict?: boolean): number;
8
- export declare function compareByValueDescending<T>(a: T, b: T, strict?: boolean): number;
7
+ export declare function compareByValue<T>(a: T, b: NoInfer<T>, strict?: boolean): number;
8
+ export declare function compareByValueDescending<T>(a: T, b: NoInfer<T>, strict?: boolean): number;
@@ -1,3 +1,5 @@
1
+ import { isNullOrUndefined } from './type-guards.js';
2
+ import { typeOf } from './type-of.js';
1
3
  export function compareByValueSelection(...selectors) {
2
4
  return (a, b) => {
3
5
  for (const selector of selectors) {
@@ -51,7 +53,7 @@ export function compareByValueSelectionToOrder(order, selector) {
51
53
  const selectedB = selector(b);
52
54
  const indexA = indexMap.get(selectedA) ?? indexMap.get(orderRest);
53
55
  const indexB = indexMap.get(selectedB) ?? indexMap.get(orderRest);
54
- if (indexA == undefined || indexB == undefined) {
56
+ if (isNullOrUndefined(indexA) || isNullOrUndefined(indexB)) {
55
57
  throw new Error('Value not defined in order.');
56
58
  }
57
59
  return compareByValue(indexA, indexB);
@@ -70,7 +72,7 @@ export function compareByValue(a, b, strict = true) {
70
72
  if (!strict) {
71
73
  return 0;
72
74
  }
73
- throw new Error('Objects not comparable');
75
+ throw new Error(`Values of type ${typeOf(a)} and ${typeOf(b)} are not comparable.`);
74
76
  }
75
77
  export function compareByValueDescending(a, b, strict = true) {
76
78
  if (a === b) {
@@ -85,5 +87,5 @@ export function compareByValueDescending(a, b, strict = true) {
85
87
  if (!strict) {
86
88
  return 0;
87
89
  }
88
- throw new Error('Objects not comparable');
90
+ throw new Error(`Values of type ${typeOf(a)} and ${typeOf(b)} are not comparable.`);
89
91
  }
@@ -1,4 +1,4 @@
1
- import type { BinaryData, TypedExtract } from '../types.js';
1
+ import type { BinaryData, TypedExtract } from '../types/index.js';
2
2
  import type { ReadonlyTuple } from 'type-fest';
3
3
  export type AesMode = 'CBC' | 'CTR' | 'GCM' | 'KW';
4
4
  export type EcdsaCurve = 'P-256' | 'P-384' | 'P-521';
@@ -1,4 +1,4 @@
1
- import type { BinaryData } from '../types.js';
1
+ import type { BinaryData } from '../types/index.js';
2
2
  /**
3
3
  * Encodes text to utf8
4
4
  * @param text text to encode
package/utils/enum.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { EnumerationEntries, EnumerationKey, EnumerationObject, EnumerationValue } from '../types.js';
1
+ import type { EnumerationEntries, EnumerationKey, EnumerationObject, EnumerationValue } from '../types/index.js';
2
2
  export declare function enumValueName<T extends EnumerationObject>(enumeration: T, value: T[keyof T]): EnumerationKey<T>;
3
3
  export declare function enumEntries<T extends EnumerationObject>(enumeration: T): EnumerationEntries<T>;
4
4
  export declare function enumKeys<T extends EnumerationObject>(enumeration: T): EnumerationKey<T>[];
package/utils/equals.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { BinaryData } from '../types.js';
1
+ import type { BinaryData } from '../types/index.js';
2
2
  import type { Comparator } from './sort.js';
3
3
  export interface Equals<T = unknown> {
4
4
  [Equals.symbol](other: T): boolean;