@tstdl/base 0.92.166 → 0.92.168

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 (308) hide show
  1. package/api/server/middlewares/content-type.middleware.js +1 -1
  2. package/application/application.d.ts +12 -18
  3. package/application/application.js +48 -69
  4. package/application/index.d.ts +1 -5
  5. package/application/index.js +1 -5
  6. package/application/providers.d.ts +10 -0
  7. package/application/providers.js +54 -0
  8. package/authentication/client/authentication.service.d.ts +1 -3
  9. package/authentication/client/authentication.service.js +4 -5
  10. package/browser/browser-context-controller.d.ts +2 -4
  11. package/browser/browser-context-controller.js +5 -6
  12. package/browser/browser-controller.d.ts +2 -4
  13. package/browser/browser-controller.js +3 -4
  14. package/browser/browser.service.d.ts +1 -3
  15. package/browser/browser.service.js +1 -2
  16. package/browser/page-controller.d.ts +2 -4
  17. package/browser/page-controller.js +7 -8
  18. package/browser/utils.js +3 -3
  19. package/cancellation/token.d.ts +104 -41
  20. package/cancellation/token.js +125 -54
  21. package/core.d.ts +1 -13
  22. package/core.js +1 -46
  23. package/disposable/disposable.d.ts +0 -8
  24. package/disposable/disposable.js +1 -3
  25. package/disposable/index.d.ts +0 -6
  26. package/disposable/index.js +0 -6
  27. package/disposable/using.d.ts +0 -1
  28. package/disposable/using.js +2 -3
  29. package/distributed-loop/distributed-loop.js +2 -2
  30. package/errors/utils.js +4 -1
  31. package/examples/api/authentication.js +11 -5
  32. package/examples/api/basic-overview.js +17 -12
  33. package/examples/api/custom-authentication.js +13 -7
  34. package/examples/api/streaming.js +15 -12
  35. package/examples/browser/basic.js +6 -3
  36. package/examples/document-management/main.js +6 -3
  37. package/examples/http/client.js +7 -3
  38. package/examples/mail/basic.js +9 -7
  39. package/examples/pdf/basic.js +8 -6
  40. package/examples/template/basic.js +7 -5
  41. package/http/client/http-client-request.d.ts +1 -2
  42. package/http/client/http-client-request.js +1 -2
  43. package/http/server/http-server.d.ts +1 -3
  44. package/http/server/http-server.js +0 -1
  45. package/http/server/node/node-http-server.d.ts +1 -2
  46. package/http/server/node/node-http-server.js +1 -2
  47. package/import.js +1 -1
  48. package/injector/injector.d.ts +1 -1
  49. package/injector/types.d.ts +3 -4
  50. package/lock/lock.d.ts +40 -21
  51. package/lock/lock.js +74 -1
  52. package/lock/postgres/drizzle/0000_busy_tattoo.sql +7 -0
  53. package/lock/postgres/drizzle/meta/0000_snapshot.json +65 -0
  54. package/lock/postgres/drizzle/meta/_journal.json +13 -0
  55. package/lock/postgres/drizzle.config.js +11 -0
  56. package/lock/postgres/index.d.ts +2 -0
  57. package/lock/postgres/index.js +2 -0
  58. package/lock/postgres/lock.d.ts +14 -0
  59. package/lock/postgres/lock.js +127 -0
  60. package/lock/postgres/models/index.d.ts +2 -0
  61. package/lock/postgres/models/index.js +2 -0
  62. package/lock/postgres/models/lock.model.d.ts +7 -0
  63. package/{examples/orm/user.model.js → lock/postgres/models/lock.model.js} +22 -30
  64. package/lock/postgres/models/schemas.d.ts +3 -0
  65. package/lock/postgres/models/schemas.js +4 -0
  66. package/lock/postgres/module.d.ts +6 -0
  67. package/lock/postgres/module.js +26 -0
  68. package/lock/postgres/provider.d.ts +6 -0
  69. package/lock/postgres/provider.js +29 -0
  70. package/lock/provider.d.ts +12 -2
  71. package/lock/provider.js +24 -1
  72. package/lock/web/web-lock.d.ts +4 -3
  73. package/lock/web/web-lock.js +49 -42
  74. package/lock/web/web-lock.provider.d.ts +0 -3
  75. package/lock/web/web-lock.provider.js +5 -22
  76. package/logger/formatter.d.ts +13 -0
  77. package/logger/formatter.js +3 -0
  78. package/logger/formatters/index.d.ts +2 -0
  79. package/logger/formatters/index.js +2 -0
  80. package/logger/formatters/json.d.ts +5 -0
  81. package/logger/formatters/json.js +33 -0
  82. package/logger/formatters/pretty-print.d.ts +5 -0
  83. package/logger/formatters/pretty-print.js +55 -0
  84. package/logger/index.d.ts +5 -2
  85. package/logger/index.js +5 -2
  86. package/logger/level.d.ts +10 -8
  87. package/logger/level.js +9 -9
  88. package/logger/logger.d.ts +21 -30
  89. package/logger/logger.js +98 -26
  90. package/logger/manager.d.ts +20 -0
  91. package/logger/manager.js +77 -0
  92. package/logger/tokens.d.ts +1 -1
  93. package/logger/tokens.js +1 -1
  94. package/logger/transport.d.ts +14 -0
  95. package/logger/transport.js +16 -0
  96. package/logger/transports/console.d.ts +14 -0
  97. package/logger/transports/console.js +36 -0
  98. package/logger/transports/index.d.ts +1 -0
  99. package/logger/transports/index.js +1 -0
  100. package/mail/clients/nodemailer.mail-client.d.ts +0 -1
  101. package/mail/clients/nodemailer.mail-client.js +9 -7
  102. package/message-bus/local/local-message-bus.js +2 -2
  103. package/message-bus/message-bus-base.d.ts +2 -3
  104. package/message-bus/message-bus-base.js +5 -6
  105. package/message-bus/message-bus.d.ts +1 -2
  106. package/message-bus/message-bus.js +1 -2
  107. package/module/index.d.ts +0 -2
  108. package/module/index.js +0 -2
  109. package/module/module.d.ts +17 -18
  110. package/module/module.js +47 -12
  111. package/module/modules/function.module.d.ts +6 -6
  112. package/module/modules/function.module.js +25 -9
  113. package/module/modules/web-server.module.d.ts +2 -10
  114. package/module/modules/web-server.module.js +3 -11
  115. package/openid-connect/index.d.ts +0 -2
  116. package/openid-connect/index.js +0 -2
  117. package/openid-connect/oidc-state.model.d.ts +4 -5
  118. package/openid-connect/oidc-state.model.js +51 -1
  119. package/openid-connect/oidc.service-model.d.ts +1 -1
  120. package/openid-connect/oidc.service.d.ts +2 -6
  121. package/openid-connect/oidc.service.js +24 -37
  122. package/orm/decorators.d.ts +10 -1
  123. package/orm/decorators.js +8 -0
  124. package/orm/server/repository.d.ts +3 -1
  125. package/orm/server/repository.js +32 -3
  126. package/package.json +17 -28
  127. package/pdf/pdf.service.js +9 -9
  128. package/pool/pool.d.ts +1 -3
  129. package/pool/pool.js +3 -4
  130. package/queue/postgres/job.model.d.ts +1 -2
  131. package/queue/postgres/job.model.js +1 -2
  132. package/queue/postgres/module.js +1 -1
  133. package/threading/thread-pool.d.ts +1 -3
  134. package/threading/thread-pool.js +7 -8
  135. package/utils/format-error.d.ts +7 -0
  136. package/utils/format-error.js +59 -17
  137. package/utils/index.d.ts +1 -0
  138. package/utils/index.js +1 -0
  139. package/utils/object/dereference.d.ts +51 -19
  140. package/utils/object/dereference.js +52 -43
  141. package/utils/timing.js +2 -2
  142. package/utils/try-chain.d.ts +22 -0
  143. package/utils/try-chain.js +46 -0
  144. package/database/entity-repository.d.ts +0 -50
  145. package/database/entity-repository.js +0 -3
  146. package/database/entity.d.ts +0 -7
  147. package/database/entity.js +0 -1
  148. package/database/id.d.ts +0 -1
  149. package/database/id.js +0 -9
  150. package/database/index.d.ts +0 -11
  151. package/database/index.js +0 -11
  152. package/database/module.d.ts +0 -8
  153. package/database/module.js +0 -11
  154. package/database/mongo/classes.d.ts +0 -21
  155. package/database/mongo/classes.js +0 -26
  156. package/database/mongo/index.d.ts +0 -15
  157. package/database/mongo/index.js +0 -15
  158. package/database/mongo/model/document.d.ts +0 -29
  159. package/database/mongo/model/document.js +0 -63
  160. package/database/mongo/model/index.d.ts +0 -1
  161. package/database/mongo/model/index.js +0 -1
  162. package/database/mongo/module.d.ts +0 -8
  163. package/database/mongo/module.js +0 -68
  164. package/database/mongo/mongo-base.repository.d.ts +0 -103
  165. package/database/mongo/mongo-base.repository.js +0 -263
  166. package/database/mongo/mongo-bulk.d.ts +0 -35
  167. package/database/mongo/mongo-bulk.js +0 -90
  168. package/database/mongo/mongo-entity-repository.d.ts +0 -98
  169. package/database/mongo/mongo-entity-repository.js +0 -278
  170. package/database/mongo/operations.d.ts +0 -10
  171. package/database/mongo/operations.js +0 -54
  172. package/database/mongo/query-converter.d.ts +0 -6
  173. package/database/mongo/query-converter.js +0 -83
  174. package/database/mongo/simple-entity-repository.d.ts +0 -7
  175. package/database/mongo/simple-entity-repository.js +0 -6
  176. package/database/mongo/types.d.ts +0 -50
  177. package/database/mongo/types.js +0 -3
  178. package/database/query.d.ts +0 -121
  179. package/database/query.js +0 -7
  180. package/database/utils.d.ts +0 -2
  181. package/database/utils.js +0 -3
  182. package/disposable/async-disposer.d.ts +0 -35
  183. package/disposable/async-disposer.js +0 -125
  184. package/examples/orm/drizzle.config.js +0 -6
  185. package/examples/orm/schemas.d.ts +0 -3
  186. package/examples/orm/schemas.js +0 -4
  187. package/examples/orm/test.d.ts +0 -1
  188. package/examples/orm/test.js +0 -11
  189. package/examples/orm/user.model.d.ts +0 -13
  190. package/key-value-store/mongo/index.d.ts +0 -6
  191. package/key-value-store/mongo/index.js +0 -6
  192. package/key-value-store/mongo/module.d.ts +0 -8
  193. package/key-value-store/mongo/module.js +0 -18
  194. package/key-value-store/mongo/mongo-key-value-store.provider.d.ts +0 -8
  195. package/key-value-store/mongo/mongo-key-value-store.provider.js +0 -26
  196. package/key-value-store/mongo/mongo-key-value.model.d.ts +0 -7
  197. package/key-value-store/mongo/mongo-key-value.model.js +0 -1
  198. package/key-value-store/mongo/mongo-key-value.repository.d.ts +0 -10
  199. package/key-value-store/mongo/mongo-key-value.repository.js +0 -31
  200. package/key-value-store/mongo/mongo-key-value.store.d.ts +0 -15
  201. package/key-value-store/mongo/mongo-key-value.store.js +0 -82
  202. package/key-value-store/mongo/tokens.d.ts +0 -3
  203. package/key-value-store/mongo/tokens.js +0 -2
  204. package/lock/mongo/index.d.ts +0 -5
  205. package/lock/mongo/index.js +0 -5
  206. package/lock/mongo/lock.d.ts +0 -14
  207. package/lock/mongo/lock.js +0 -125
  208. package/lock/mongo/model.d.ts +0 -6
  209. package/lock/mongo/model.js +0 -1
  210. package/lock/mongo/module.d.ts +0 -12
  211. package/lock/mongo/module.js +0 -20
  212. package/lock/mongo/mongo-lock-repository.d.ts +0 -14
  213. package/lock/mongo/mongo-lock-repository.js +0 -67
  214. package/lock/mongo/provider.d.ts +0 -8
  215. package/lock/mongo/provider.js +0 -36
  216. package/logger/console/index.d.ts +0 -1
  217. package/logger/console/index.js +0 -1
  218. package/logger/console/logger.d.ts +0 -11
  219. package/logger/console/logger.js +0 -64
  220. package/logger/noop/index.d.ts +0 -1
  221. package/logger/noop/index.js +0 -1
  222. package/logger/noop/logger.d.ts +0 -9
  223. package/logger/noop/logger.js +0 -21
  224. package/migration/index.d.ts +0 -9
  225. package/migration/index.js +0 -9
  226. package/migration/migration-state-repository.d.ts +0 -4
  227. package/migration/migration-state-repository.js +0 -3
  228. package/migration/migration-state.d.ts +0 -6
  229. package/migration/migration-state.js +0 -1
  230. package/migration/migrator.d.ts +0 -23
  231. package/migration/migrator.js +0 -76
  232. package/migration/mongo/index.d.ts +0 -2
  233. package/migration/mongo/index.js +0 -2
  234. package/migration/mongo/migration-state-repository.d.ts +0 -11
  235. package/migration/mongo/migration-state-repository.js +0 -32
  236. package/migration/mongo/module.d.ts +0 -12
  237. package/migration/mongo/module.js +0 -17
  238. package/module/module-base.d.ts +0 -18
  239. package/module/module-base.js +0 -40
  240. package/module/module-metric-reporter.d.ts +0 -29
  241. package/module/module-metric-reporter.js +0 -62
  242. package/openid-connect/mongo-oidc-state.repository.d.ts +0 -21
  243. package/openid-connect/mongo-oidc-state.repository.js +0 -52
  244. package/openid-connect/oidc-state.repository.d.ts +0 -4
  245. package/openid-connect/oidc-state.repository.js +0 -3
  246. package/process-shutdown.d.ts +0 -9
  247. package/process-shutdown.js +0 -65
  248. package/queue/mongo/index.d.ts +0 -4
  249. package/queue/mongo/index.js +0 -4
  250. package/queue/mongo/job.d.ts +0 -12
  251. package/queue/mongo/job.js +0 -1
  252. package/queue/mongo/mongo-job.repository.d.ts +0 -13
  253. package/queue/mongo/mongo-job.repository.js +0 -54
  254. package/queue/mongo/queue.d.ts +0 -38
  255. package/queue/mongo/queue.js +0 -266
  256. package/queue/mongo/queue.provider.d.ts +0 -18
  257. package/queue/mongo/queue.provider.js +0 -38
  258. package/search-index/elastic/config.d.ts +0 -8
  259. package/search-index/elastic/config.js +0 -26
  260. package/search-index/elastic/index.d.ts +0 -8
  261. package/search-index/elastic/index.js +0 -8
  262. package/search-index/elastic/keyword-rewriter.d.ts +0 -8
  263. package/search-index/elastic/keyword-rewriter.js +0 -18
  264. package/search-index/elastic/model/elastic-query.d.ts +0 -16
  265. package/search-index/elastic/model/elastic-query.js +0 -1
  266. package/search-index/elastic/model/index-mapping.d.ts +0 -26
  267. package/search-index/elastic/model/index-mapping.js +0 -4
  268. package/search-index/elastic/model/index.d.ts +0 -3
  269. package/search-index/elastic/model/index.js +0 -3
  270. package/search-index/elastic/model/sort.d.ts +0 -8
  271. package/search-index/elastic/model/sort.js +0 -1
  272. package/search-index/elastic/module.d.ts +0 -10
  273. package/search-index/elastic/module.js +0 -49
  274. package/search-index/elastic/query-builder/boolean-query-builder.d.ts +0 -11
  275. package/search-index/elastic/query-builder/boolean-query-builder.js +0 -52
  276. package/search-index/elastic/query-builder/index.d.ts +0 -1
  277. package/search-index/elastic/query-builder/index.js +0 -1
  278. package/search-index/elastic/query-converter.d.ts +0 -9
  279. package/search-index/elastic/query-converter.js +0 -183
  280. package/search-index/elastic/search-index.d.ts +0 -30
  281. package/search-index/elastic/search-index.js +0 -144
  282. package/search-index/elastic/sort-converter.d.ts +0 -4
  283. package/search-index/elastic/sort-converter.js +0 -14
  284. package/search-index/elastic/types.d.ts +0 -5
  285. package/search-index/elastic/types.js +0 -1
  286. package/search-index/error.d.ts +0 -10
  287. package/search-index/error.js +0 -14
  288. package/search-index/index.d.ts +0 -3
  289. package/search-index/index.js +0 -3
  290. package/search-index/memory/index.d.ts +0 -1
  291. package/search-index/memory/index.js +0 -1
  292. package/search-index/memory/memory-search-index.d.ts +0 -19
  293. package/search-index/memory/memory-search-index.js +0 -144
  294. package/search-index/search-index.d.ts +0 -46
  295. package/search-index/search-index.js +0 -31
  296. package/search-index/search-result.d.ts +0 -12
  297. package/search-index/search-result.js +0 -1
  298. package/theme/adapters/css-adapter.d.ts +0 -5
  299. package/theme/adapters/css-adapter.js +0 -29
  300. package/theme/adapters/index.d.ts +0 -2
  301. package/theme/adapters/index.js +0 -2
  302. package/theme/adapters/tailwind-adapter.d.ts +0 -18
  303. package/theme/adapters/tailwind-adapter.js +0 -32
  304. package/theme/index.d.ts +0 -1
  305. package/theme/index.js +0 -1
  306. package/theme/theme-service.d.ts +0 -43
  307. package/theme/theme-service.js +0 -128
  308. /package/{examples/orm → lock/postgres}/drizzle.config.d.ts +0 -0
package/lock/lock.d.ts CHANGED
@@ -1,25 +1,24 @@
1
+ import type { CancellationSignal } from '../cancellation/index.js';
1
2
  import type { Resolvable } from '../injector/index.js';
2
3
  import { resolveArgumentType } from '../injector/index.js';
3
- export type LockedFunction<R> = (controller: LockController) => R | Promise<R>;
4
- export type AcquireResult<Throw extends boolean> = Throw extends true ? LockController : (LockController | false);
5
- export type UsingResult<Throw extends boolean, R> = Throw extends true ? ({
4
+ export type LockedFunction<R> = (controller: UseLockController) => R | Promise<R>;
5
+ export type LockTryUseResult<R> = ({
6
6
  success: true;
7
7
  result: R;
8
- }) : ({
9
- success: true;
10
- result: R;
11
- } | {
8
+ }) | ({
12
9
  success: false;
13
- result: undefined;
10
+ result?: undefined;
14
11
  });
15
- export interface LockController {
12
+ export interface UseLockController {
16
13
  /**
17
- * whether the the lock is lost or not. Can happen for example if it couldn't be renewed
14
+ * Whether the the lock is lost or not. Can happen for example if it couldn't be renewed
18
15
  * because the network connection is lost (depending on implementation)
19
16
  */
20
17
  readonly lost: boolean;
18
+ }
19
+ export interface LockController extends UseLockController {
21
20
  /** manually release lock */
22
- release(): void | Promise<void>;
21
+ release(): Promise<void>;
23
22
  }
24
23
  /** resource */
25
24
  export type LockArgument = string | {
@@ -27,22 +26,42 @@ export type LockArgument = string | {
27
26
  resource: string;
28
27
  };
29
28
  export declare abstract class Lock implements Resolvable<LockArgument> {
29
+ protected readonly cancellationSignal: CancellationSignal;
30
30
  readonly resource: string;
31
31
  readonly [resolveArgumentType]: LockArgument;
32
- constructor(resource: string);
32
+ constructor(resource: string, cancellationSignal: CancellationSignal);
33
+ /**
34
+ * Tries to acquire a lock for the resource, it must be manually released.
35
+ * @param timeout How long to try to get a lock in milliseconds. If undefined, it tries only once.
36
+ * @returns A lock controller if successful, otherwise `false`.
37
+ */
38
+ tryAcquire(timeout?: number): Promise<LockController | false>;
39
+ /**
40
+ * Acquires a lock for the resource, it must be manually released.
41
+ * Throws an error if the lock cannot be acquired within the specified timeout.
42
+ * @param timeout How long to try to get a lock in milliseconds. If undefined, it tries forever.
43
+ */
44
+ acquire(timeout?: number): Promise<LockController>;
45
+ /**
46
+ * Tries to acquire a lock for the resource and releases it automatically after the provided function has returned or thrown.
47
+ * @param timeout How long to try to get a lock in milliseconds. If undefined, it tries only once.
48
+ * @param func Function to run when the lock is acquired.
49
+ * @returns A result object indicating success and containing the return value of the function.
50
+ */
51
+ tryUse<R>(timeout: number | undefined, func: LockedFunction<R>): Promise<LockTryUseResult<R>>;
33
52
  /**
34
- * acquire a lock for the resource, it must be manually released
35
- * @param timeout how long to try to get a lock. If undefined it's tries forever
36
- * @param throwOnFail throw if resource is locked and we couldn't acquire it in the specified timeout
53
+ * Acquires a lock for the resource and releases it automatically after the provided function has returned or thrown.
54
+ * Throws an error if the lock cannot be acquired within the specified timeout.
55
+ * @param timeout How long to try to get a lock in milliseconds. If undefined, it tries forever.
56
+ * @param func Function to run when the lock is acquired.
57
+ * @returns The return value of the function.
37
58
  */
38
- abstract acquire<Throw extends boolean>(timeout: number | undefined, throwOnFail: Throw): Promise<AcquireResult<Throw>>;
59
+ use<R>(timeout: number | undefined, func: LockedFunction<R>): Promise<R>;
39
60
  /**
40
- * acquire a lock for the resource and release it automatically after the provided function has returned or thrown
41
- * @param timeout how long to try to get a lock. If undefined it's tries forever
42
- * @param throwOnFail throw if resource is locked and we couldn't acquire it in the specified timeout
43
- * @param func function to run when lock is acquired
61
+ * try to acquire the lock for the resource, returns a controller if successful
62
+ * returns false if the lock is already held by another process
44
63
  */
45
- abstract use<Throw extends boolean, R>(timeout: number | undefined, throwOnFail: Throw, func: LockedFunction<R>): Promise<UsingResult<Throw, R>>;
64
+ abstract tryAcquireOnce(): Promise<LockController | false>;
46
65
  /** check if resource is locked */
47
66
  abstract exists(): Promise<boolean>;
48
67
  }
package/lock/lock.js CHANGED
@@ -1,7 +1,80 @@
1
1
  import { resolveArgumentType } from '../injector/index.js';
2
+ import { Timer } from '../utils/timer.js';
3
+ import { cancelableTimeout } from '../utils/timing.js';
4
+ import { isUndefined } from '../utils/type-guards.js';
2
5
  export class Lock {
6
+ cancellationSignal;
3
7
  resource;
4
- constructor(resource) {
8
+ constructor(resource, cancellationSignal) {
9
+ this.cancellationSignal = cancellationSignal;
5
10
  this.resource = resource;
6
11
  }
12
+ /**
13
+ * Tries to acquire a lock for the resource, it must be manually released.
14
+ * @param timeout How long to try to get a lock in milliseconds. If undefined, it tries only once.
15
+ * @returns A lock controller if successful, otherwise `false`.
16
+ */
17
+ async tryAcquire(timeout) {
18
+ if (isUndefined(timeout) || (timeout <= 0)) {
19
+ return await this.tryAcquireOnce();
20
+ }
21
+ const delay = Math.max(50, Math.min(1000, timeout / 10));
22
+ const timer = new Timer(true);
23
+ do {
24
+ const result = await this.tryAcquireOnce();
25
+ if (result !== false) {
26
+ return result;
27
+ }
28
+ const delayResult = await cancelableTimeout(delay, this.cancellationSignal);
29
+ if (delayResult == 'canceled') {
30
+ break;
31
+ }
32
+ } while (timer.milliseconds < timeout);
33
+ return false;
34
+ }
35
+ /**
36
+ * Acquires a lock for the resource, it must be manually released.
37
+ * Throws an error if the lock cannot be acquired within the specified timeout.
38
+ * @param timeout How long to try to get a lock in milliseconds. If undefined, it tries forever.
39
+ */
40
+ async acquire(timeout) {
41
+ const result = await this.tryAcquire(timeout);
42
+ if (result === false) {
43
+ throw new Error(`Failed to acquire lock for resource '${this.resource}'.`);
44
+ }
45
+ return result;
46
+ }
47
+ /**
48
+ * Tries to acquire a lock for the resource and releases it automatically after the provided function has returned or thrown.
49
+ * @param timeout How long to try to get a lock in milliseconds. If undefined, it tries only once.
50
+ * @param func Function to run when the lock is acquired.
51
+ * @returns A result object indicating success and containing the return value of the function.
52
+ */
53
+ async tryUse(timeout, func) {
54
+ const controller = await this.tryAcquire(timeout);
55
+ if (controller == false) {
56
+ return { success: false, result: undefined };
57
+ }
58
+ try {
59
+ const result = await func(controller);
60
+ return { success: true, result };
61
+ }
62
+ finally {
63
+ await controller.release();
64
+ }
65
+ }
66
+ /**
67
+ * Acquires a lock for the resource and releases it automatically after the provided function has returned or thrown.
68
+ * Throws an error if the lock cannot be acquired within the specified timeout.
69
+ * @param timeout How long to try to get a lock in milliseconds. If undefined, it tries forever.
70
+ * @param func Function to run when the lock is acquired.
71
+ * @returns The return value of the function.
72
+ */
73
+ async use(timeout, func) {
74
+ const result = await this.tryUse(timeout, func);
75
+ if (!result.success) {
76
+ throw new Error(`Failed to acquire lock for resource '${this.resource}'.`);
77
+ }
78
+ return result.result;
79
+ }
7
80
  }
@@ -0,0 +1,7 @@
1
+ CREATE TABLE "lock"."lock" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "resource" text NOT NULL,
4
+ "key" text NOT NULL,
5
+ "expiration" timestamp with time zone NOT NULL,
6
+ CONSTRAINT "lock_resource_unique" UNIQUE("resource")
7
+ );
@@ -0,0 +1,65 @@
1
+ {
2
+ "id": "2d26f59a-2c92-4d3c-aea3-93aa48a91d5f",
3
+ "prevId": "00000000-0000-0000-0000-000000000000",
4
+ "version": "7",
5
+ "dialect": "postgresql",
6
+ "tables": {
7
+ "lock.lock": {
8
+ "name": "lock",
9
+ "schema": "lock",
10
+ "columns": {
11
+ "id": {
12
+ "name": "id",
13
+ "type": "uuid",
14
+ "primaryKey": true,
15
+ "notNull": true,
16
+ "default": "gen_random_uuid()"
17
+ },
18
+ "resource": {
19
+ "name": "resource",
20
+ "type": "text",
21
+ "primaryKey": false,
22
+ "notNull": true
23
+ },
24
+ "key": {
25
+ "name": "key",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true
29
+ },
30
+ "expiration": {
31
+ "name": "expiration",
32
+ "type": "timestamp with time zone",
33
+ "primaryKey": false,
34
+ "notNull": true
35
+ }
36
+ },
37
+ "indexes": {},
38
+ "foreignKeys": {},
39
+ "compositePrimaryKeys": {},
40
+ "uniqueConstraints": {
41
+ "lock_resource_unique": {
42
+ "name": "lock_resource_unique",
43
+ "nullsNotDistinct": false,
44
+ "columns": [
45
+ "resource"
46
+ ]
47
+ }
48
+ },
49
+ "policies": {},
50
+ "checkConstraints": {},
51
+ "isRLSEnabled": false
52
+ }
53
+ },
54
+ "enums": {},
55
+ "schemas": {},
56
+ "sequences": {},
57
+ "roles": {},
58
+ "policies": {},
59
+ "views": {},
60
+ "_meta": {
61
+ "columns": {},
62
+ "schemas": {},
63
+ "tables": {}
64
+ }
65
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "postgresql",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "7",
8
+ "when": 1756898177209,
9
+ "tag": "0000_busy_tattoo",
10
+ "breakpoints": true
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,11 @@
1
+ import { relative, resolve } from 'node:path';
2
+ import { defineConfig } from 'drizzle-kit';
3
+ export default defineConfig({
4
+ dialect: 'postgresql',
5
+ out: relative('./', resolve(__dirname, './drizzle/').replace('dist', 'source')),
6
+ schema: resolve(__dirname, './models/schemas.js'),
7
+ migrations: {
8
+ schema: 'lock',
9
+ table: '_migrations',
10
+ },
11
+ });
@@ -0,0 +1,2 @@
1
+ export * from './provider.js';
2
+ export * from './module.js';
@@ -0,0 +1,2 @@
1
+ export * from './provider.js';
2
+ export * from './module.js';
@@ -0,0 +1,14 @@
1
+ import { type CancellationSignal } from '../../cancellation/index.js';
2
+ import type { Logger } from '../../logger/logger.js';
3
+ import type { EntityRepository } from '../../orm/server/index.js';
4
+ import { Lock, type LockController } from '../lock.js';
5
+ import type { PostgresLock } from './models/lock.model.js';
6
+ export declare class PostgresLockAdapter extends Lock {
7
+ #private;
8
+ constructor(repository: EntityRepository<PostgresLock>, resource: string, logger: Logger, cancellationSignal: CancellationSignal);
9
+ tryAcquireOnce(): Promise<LockController | false>;
10
+ exists(): Promise<boolean>;
11
+ private executeTryAcquire;
12
+ private tryRefresh;
13
+ private release;
14
+ }
@@ -0,0 +1,127 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { and, eq, lte, sql } from 'drizzle-orm';
11
+ import { CancellationToken } from '../../cancellation/index.js';
12
+ import { Injectable } from '../../injector/decorators.js';
13
+ import { TRANSACTION_TIMESTAMP } from '../../orm/sqls.js';
14
+ import { currentTimestamp } from '../../utils/date-time.js';
15
+ import { cancelableTimeoutUntil } from '../../utils/timing.js';
16
+ import { assertDefined, isDefined, isString, isUndefined } from '../../utils/type-guards.js';
17
+ import { Lock } from '../lock.js';
18
+ import { lock } from './models/schemas.js';
19
+ import { PostgresLockProvider } from './provider.js';
20
+ const expirationTime = 10000;
21
+ const renewBuffer = expirationTime / 2;
22
+ let PostgresLockAdapter = class PostgresLockAdapter extends Lock {
23
+ #lockRepository;
24
+ #logger;
25
+ constructor(repository, resource, logger, cancellationSignal) {
26
+ super(resource, cancellationSignal);
27
+ this.#lockRepository = repository;
28
+ this.#logger = logger;
29
+ }
30
+ async tryAcquireOnce() {
31
+ const key = crypto.randomUUID();
32
+ let result = await this.executeTryAcquire(this.resource, key);
33
+ if (result === false) {
34
+ return false;
35
+ }
36
+ const releaseToken = new CancellationToken();
37
+ let expiration = result;
38
+ const controller = {
39
+ get lost() {
40
+ return currentTimestamp() >= expiration;
41
+ },
42
+ release: async () => {
43
+ releaseToken.set();
44
+ await this.release(this.resource, key);
45
+ },
46
+ };
47
+ void (async () => {
48
+ await cancelableTimeoutUntil(expiration - renewBuffer, releaseToken);
49
+ while (!releaseToken.isSet && !controller.lost) {
50
+ try {
51
+ const refreshResult = await this.tryRefresh(this.resource, key);
52
+ expiration = (refreshResult === false) ? 0 : refreshResult;
53
+ }
54
+ catch (error) {
55
+ this.#logger.error(error);
56
+ }
57
+ finally {
58
+ await cancelableTimeoutUntil(Math.max(currentTimestamp() + 1000, expiration - renewBuffer), releaseToken);
59
+ }
60
+ }
61
+ })();
62
+ return controller;
63
+ }
64
+ async exists() {
65
+ return await this.#lockRepository.hasByQuery({
66
+ resource: this.resource,
67
+ expiration: { $gt: TRANSACTION_TIMESTAMP },
68
+ });
69
+ }
70
+ async executeTryAcquire(resource, key) {
71
+ const upsertQuery = this.#lockRepository.session
72
+ .insert(lock)
73
+ .values({
74
+ resource,
75
+ key,
76
+ expiration: sql `${TRANSACTION_TIMESTAMP} + INTERVAL '${sql.raw(expirationTime.toString())} milliseconds'`,
77
+ })
78
+ .onConflictDoUpdate({
79
+ target: this.#lockRepository.getColumn('resource'),
80
+ set: {
81
+ key: sql.raw(`excluded.${lock.key.name}`),
82
+ expiration: sql.raw(`excluded.${lock.expiration.name}`),
83
+ },
84
+ setWhere: lte(lock.expiration, TRANSACTION_TIMESTAMP),
85
+ })
86
+ .returning({ expiration: lock.expiration });
87
+ console.log(upsertQuery.toSQL());
88
+ const [result] = await upsertQuery;
89
+ if (isUndefined(result)) {
90
+ return false;
91
+ }
92
+ return result.expiration;
93
+ }
94
+ async tryRefresh(resource, key) {
95
+ const [result] = await this.#lockRepository.session
96
+ .update(lock)
97
+ .set({
98
+ expiration: sql `${TRANSACTION_TIMESTAMP} + INTERVAL '${sql.raw(expirationTime.toString())} milliseconds'`,
99
+ })
100
+ .where(and(eq(lock.resource, resource), eq(lock.key, key)))
101
+ .returning({ expiration: lock.expiration });
102
+ if (isUndefined(result)) {
103
+ return false;
104
+ }
105
+ return result.expiration;
106
+ }
107
+ async release(resource, key) {
108
+ const result = await this.#lockRepository.tryDeleteByQuery({ resource, key });
109
+ return isDefined(result);
110
+ }
111
+ };
112
+ PostgresLockAdapter = __decorate([
113
+ Injectable({
114
+ lifecycle: 'transient', provider: {
115
+ useFactory: (argument, context) => {
116
+ assertDefined(argument, 'Missing argument for lock.');
117
+ const argumentIsString = isString(argument);
118
+ const prefix = argumentIsString ? undefined : argument.prefix;
119
+ const resource = argumentIsString ? argument : argument.resource;
120
+ const provider = context.resolve(PostgresLockProvider, prefix);
121
+ return provider.get(resource);
122
+ },
123
+ },
124
+ }),
125
+ __metadata("design:paramtypes", [Function, String, Function, Function])
126
+ ], PostgresLockAdapter);
127
+ export { PostgresLockAdapter };
@@ -0,0 +1,2 @@
1
+ export * from './lock.model.js';
2
+ export * from './schemas.js';
@@ -0,0 +1,2 @@
1
+ export * from './lock.model.js';
2
+ export * from './schemas.js';
@@ -0,0 +1,7 @@
1
+ import { EntityWithoutMetadata } from '../../../orm/entity.js';
2
+ import { Timestamp } from '../../../orm/types.js';
3
+ export declare class PostgresLock extends EntityWithoutMetadata {
4
+ resource: string;
5
+ key: string;
6
+ expiration: Timestamp;
7
+ }
@@ -7,38 +7,30 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { Array, Entity, Integer, Unique } from '../../orm/index.js';
11
- import { BooleanProperty, StringProperty } from '../../schema/index.js';
12
- export var Foo;
13
- (function (Foo) {
14
- Foo[Foo["Bar"] = 0] = "Bar";
15
- Foo[Foo["Baz"] = 1] = "Baz";
16
- })(Foo || (Foo = {}));
17
- export class User extends Entity {
18
- static entityName = 'User';
19
- name;
20
- nickNames;
21
- age;
22
- hasAge;
23
- mail;
24
- }
10
+ import { ExpiresAt, Table } from '../../../orm/decorators.js';
11
+ import { EntityWithoutMetadata } from '../../../orm/entity.js';
12
+ import { Timestamp, Unique } from '../../../orm/types.js';
13
+ import { StringProperty } from '../../../schema/index.js';
14
+ let PostgresLock = class PostgresLock extends EntityWithoutMetadata {
15
+ resource;
16
+ key;
17
+ expiration;
18
+ };
25
19
  __decorate([
20
+ Unique(),
26
21
  StringProperty(),
27
22
  __metadata("design:type", String)
28
- ], User.prototype, "name", void 0);
29
- __decorate([
30
- Array(String),
31
- __metadata("design:type", Array)
32
- ], User.prototype, "nickNames", void 0);
33
- __decorate([
34
- Integer({ nullable: true }),
35
- __metadata("design:type", Object)
36
- ], User.prototype, "age", void 0);
23
+ ], PostgresLock.prototype, "resource", void 0);
37
24
  __decorate([
38
- BooleanProperty(),
39
- __metadata("design:type", Boolean)
40
- ], User.prototype, "hasAge", void 0);
41
- __decorate([
42
- Unique(),
25
+ StringProperty(),
43
26
  __metadata("design:type", String)
44
- ], User.prototype, "mail", void 0);
27
+ ], PostgresLock.prototype, "key", void 0);
28
+ __decorate([
29
+ ExpiresAt(),
30
+ Timestamp(),
31
+ __metadata("design:type", Number)
32
+ ], PostgresLock.prototype, "expiration", void 0);
33
+ PostgresLock = __decorate([
34
+ Table('lock')
35
+ ], PostgresLock);
36
+ export { PostgresLock };
@@ -0,0 +1,3 @@
1
+ import { PostgresLock } from './lock.model.js';
2
+ export declare const lockSchema: import("../../../orm/server/database-schema.js").DatabaseSchema<"lock">;
3
+ export declare const lock: import("../../../orm/server/types.js").PgTableFromType<typeof PostgresLock, "lock">;
@@ -0,0 +1,4 @@
1
+ import { databaseSchema } from '../../../orm/server/database-schema.js';
2
+ import { PostgresLock } from './lock.model.js';
3
+ export const lockSchema = databaseSchema('lock');
4
+ export const lock = lockSchema.getTable(PostgresLock);
@@ -0,0 +1,6 @@
1
+ import { type DatabaseConfig } from '../../orm/server/index.js';
2
+ export declare class PostgresLockModuleConfig {
3
+ database?: DatabaseConfig;
4
+ }
5
+ export declare function configurePostgresLock(config?: PostgresLockModuleConfig): void;
6
+ export declare function migratePostgresLockSchema(): Promise<void>;
@@ -0,0 +1,26 @@
1
+ import { inject, Injector } from '../../injector/index.js';
2
+ import { Database, migrate } from '../../orm/server/index.js';
3
+ import { isDefined } from '../../utils/type-guards.js';
4
+ import { Lock } from '../lock.js';
5
+ import { LockProvider } from '../provider.js';
6
+ import { PostgresLockProvider } from './provider.js';
7
+ import { PostgresLockAdapter } from './lock.js';
8
+ export class PostgresLockModuleConfig {
9
+ database;
10
+ }
11
+ export function configurePostgresLock(config) {
12
+ if (isDefined(config)) {
13
+ Injector.register(PostgresLockModuleConfig, { useValue: config });
14
+ }
15
+ Injector.registerSingleton(LockProvider, { useToken: PostgresLockProvider });
16
+ Injector.registerSingleton(Lock, { useToken: PostgresLockAdapter });
17
+ }
18
+ export async function migratePostgresLockSchema() {
19
+ const connection = inject(PostgresLockModuleConfig, undefined, { optional: true })?.database?.connection;
20
+ const database = inject(Database, connection);
21
+ await migrate(database, {
22
+ migrationsSchema: 'lock',
23
+ migrationsTable: '_migrations',
24
+ migrationsFolder: import.meta.resolve('./drizzle').replace('file://', ''),
25
+ });
26
+ }
@@ -0,0 +1,6 @@
1
+ import type { Lock } from '../lock.js';
2
+ import { LockProvider } from '../provider.js';
3
+ export declare class PostgresLockProvider extends LockProvider {
4
+ #private;
5
+ get(resource: string): Lock;
6
+ }
@@ -0,0 +1,29 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Singleton, provide } from '../../injector/index.js';
8
+ import { DatabaseConfig } from '../../orm/server/index.js';
9
+ import { EntityRepositoryConfig, injectRepository } from '../../orm/server/repository.js';
10
+ import { LockProvider } from '../provider.js';
11
+ import { PostgresLockAdapter } from './lock.js';
12
+ import { PostgresLock } from './models/lock.model.js';
13
+ import { PostgresLockModuleConfig } from './module.js';
14
+ let PostgresLockProvider = class PostgresLockProvider extends LockProvider {
15
+ #lockRepository = injectRepository(PostgresLock);
16
+ get(resource) {
17
+ const resourceString = this.getResourceString(resource, this._prefix);
18
+ return new PostgresLockAdapter(this.#lockRepository, resourceString, this.logger, this.cancellationSignal);
19
+ }
20
+ };
21
+ PostgresLockProvider = __decorate([
22
+ Singleton({
23
+ providers: [
24
+ provide(EntityRepositoryConfig, { useValue: { schema: 'lock' } }),
25
+ { provide: DatabaseConfig, useFactory: (_, context) => context.resolve(PostgresLockModuleConfig).database ?? context.resolve(DatabaseConfig, undefined, { skipSelf: true }) },
26
+ ],
27
+ })
28
+ ], PostgresLockProvider);
29
+ export { PostgresLockProvider };
@@ -1,10 +1,20 @@
1
+ import { CancellationSignal } from '../cancellation/index.js';
1
2
  import type { Resolvable } from '../injector/index.js';
2
- import { resolveArgumentType } from '../injector/index.js';
3
+ import { Injector, resolveArgumentType } from '../injector/index.js';
4
+ import { Logger } from '../logger/logger.js';
3
5
  import type { Lock } from './lock.js';
4
6
  /** prefix */
5
7
  export type LockProviderArgument = string;
6
8
  export declare abstract class LockProvider implements Resolvable<LockProviderArgument> {
9
+ #private;
10
+ protected readonly _prefix: string | undefined;
11
+ protected readonly injector: Injector;
12
+ protected readonly lockInjector: Injector;
13
+ protected readonly logger: Logger;
14
+ protected readonly cancellationSignal: CancellationSignal;
7
15
  readonly [resolveArgumentType]: LockProviderArgument;
8
- abstract prefix(prefix: string): LockProvider;
16
+ constructor();
17
+ prefix(prefix: string): this;
9
18
  abstract get(resource: string): Lock;
19
+ protected getResourceString(resource: string, prefix?: string): string;
10
20
  }
package/lock/provider.js CHANGED
@@ -1,3 +1,26 @@
1
- import { resolveArgumentType } from '../injector/index.js';
1
+ import { CancellationSignal } from '../cancellation/index.js';
2
+ import { inject, injectArgument, Injector, resolveArgumentType } from '../injector/index.js';
3
+ import { Logger } from '../logger/logger.js';
4
+ import { isDefined, isString } from '../utils/type-guards.js';
2
5
  export class LockProvider {
6
+ #type;
7
+ _prefix = injectArgument(this, { optional: true });
8
+ injector = inject(Injector);
9
+ lockInjector = this.injector.fork(`LockInjector${isString(this._prefix) ? `:${this._prefix}` : ''}`);
10
+ logger;
11
+ cancellationSignal = inject(CancellationSignal);
12
+ constructor() {
13
+ this.#type = new.target;
14
+ this.logger = inject(Logger, `${this.#type.name}${isString(this._prefix) ? `:${this._prefix}` : ''}`);
15
+ }
16
+ prefix(prefix) {
17
+ const newPrefixString = this.getResourceString(prefix, this._prefix);
18
+ return this.injector.resolve(this.#type, newPrefixString);
19
+ }
20
+ getResourceString(resource, prefix) {
21
+ if (isDefined(prefix) && (prefix.length > 0)) {
22
+ return `${prefix}:${resource}`;
23
+ }
24
+ return resource;
25
+ }
3
26
  }
@@ -1,7 +1,8 @@
1
- import type { AcquireResult, LockedFunction, UsingResult } from '../lock.js';
1
+ import type { LockController, LockedFunction, LockTryUseResult } from '../lock.js';
2
2
  import { Lock } from '../lock.js';
3
3
  export declare class WebLock extends Lock {
4
- acquire<Throw extends boolean>(timeout: number | undefined, throwOnFail: Throw): Promise<AcquireResult<Throw>>;
5
- use<Throw extends boolean, R>(timeout: number | undefined, throwOnFail: Throw, func: LockedFunction<R>): Promise<UsingResult<Throw, R>>;
4
+ tryAcquireOnce(): Promise<LockController | false>;
5
+ tryAcquire(timeout?: number): Promise<LockController | false>;
6
+ tryUse<R>(timeout: number | undefined, func: LockedFunction<R>): Promise<LockTryUseResult<R>>;
6
7
  exists(): Promise<boolean>;
7
8
  }