@tstdl/base 0.93.181 → 0.93.183

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 (353) hide show
  1. package/api/server/api-request-token.provider.js +1 -1
  2. package/api/server/gateway.js +8 -3
  3. package/authentication/authentication.api.d.ts +13 -40
  4. package/authentication/authentication.api.js +5 -14
  5. package/authentication/client/authentication.service.d.ts +6 -14
  6. package/authentication/client/authentication.service.js +22 -4
  7. package/authentication/client/module.d.ts +1 -1
  8. package/authentication/client/module.js +4 -4
  9. package/authentication/models/index.d.ts +1 -0
  10. package/authentication/models/index.js +1 -0
  11. package/authentication/models/totp-results.model.d.ts +11 -0
  12. package/authentication/models/totp-results.model.js +37 -0
  13. package/authentication/server/authentication.api-controller.d.ts +3 -3
  14. package/authentication/server/authentication.api-controller.js +31 -4
  15. package/authentication/server/authentication.service.d.ts +5 -14
  16. package/authentication/server/authentication.service.js +6 -4
  17. package/core.d.ts +0 -5
  18. package/core.js +0 -8
  19. package/document-management/api/document-management.api.d.ts +2 -2
  20. package/document-management/service-models/document.service-model.d.ts +1 -1
  21. package/examples/config.d.ts +25 -0
  22. package/examples/config.js +26 -0
  23. package/notification/server/module.d.ts +1 -1
  24. package/notification/server/module.js +1 -1
  25. package/package.json +5 -5
  26. package/signals/api.d.ts +5 -1
  27. package/signals/api.js +3 -1
  28. package/signals/implementation/api.d.ts +13 -5
  29. package/signals/implementation/api.js +7 -1
  30. package/signals/implementation/asserts.d.ts +2 -2
  31. package/signals/implementation/asserts.js +3 -3
  32. package/signals/implementation/computed.d.ts +7 -34
  33. package/signals/implementation/computed.js +14 -83
  34. package/signals/implementation/configure.js +6 -2
  35. package/signals/implementation/effect.d.ts +65 -46
  36. package/signals/implementation/effect.js +97 -62
  37. package/signals/implementation/index.d.ts +2 -4
  38. package/signals/implementation/index.js +2 -4
  39. package/signals/implementation/linked_signal.d.ts +36 -0
  40. package/signals/implementation/linked_signal.js +34 -0
  41. package/signals/implementation/primitive/computed.d.ts +55 -0
  42. package/signals/implementation/primitive/computed.js +107 -0
  43. package/signals/implementation/primitive/effect.d.ts +26 -0
  44. package/signals/implementation/primitive/effect.js +31 -0
  45. package/signals/implementation/{equality.d.ts → primitive/equality.d.ts} +1 -1
  46. package/signals/implementation/{equality.js → primitive/equality.js} +1 -1
  47. package/signals/implementation/primitive/errors.d.ts +10 -0
  48. package/signals/implementation/{errors.js → primitive/errors.js} +3 -4
  49. package/signals/implementation/primitive/formatter.d.ts +19 -0
  50. package/signals/implementation/primitive/formatter.js +136 -0
  51. package/signals/implementation/{graph.d.ts → primitive/graph.d.ts} +68 -36
  52. package/signals/implementation/primitive/graph.js +386 -0
  53. package/signals/implementation/primitive/linked_signal.d.ts +46 -0
  54. package/signals/implementation/primitive/linked_signal.js +110 -0
  55. package/signals/implementation/primitive/signal.d.ts +31 -0
  56. package/signals/implementation/primitive/signal.js +80 -0
  57. package/signals/implementation/primitive/untracked.d.ts +12 -0
  58. package/signals/implementation/primitive/untracked.js +23 -0
  59. package/signals/implementation/{watch.d.ts → primitive/watch.d.ts} +1 -2
  60. package/signals/implementation/{watch.js → primitive/watch.js} +22 -16
  61. package/signals/implementation/resource/api.d.ts +275 -0
  62. package/signals/implementation/resource/api.js +26 -0
  63. package/signals/implementation/resource/debounce.d.ts +13 -0
  64. package/signals/implementation/resource/debounce.js +113 -0
  65. package/signals/implementation/resource/from_snapshots.d.ts +16 -0
  66. package/signals/implementation/resource/from_snapshots.js +44 -0
  67. package/signals/implementation/resource/index.d.ts +11 -0
  68. package/signals/implementation/resource/index.js +11 -0
  69. package/signals/implementation/resource/resource.d.ts +110 -0
  70. package/signals/implementation/resource/resource.js +402 -0
  71. package/signals/implementation/root_effect_scheduler.d.ts +50 -0
  72. package/signals/implementation/root_effect_scheduler.js +66 -0
  73. package/signals/implementation/signal.d.ts +42 -18
  74. package/signals/implementation/signal.js +29 -49
  75. package/signals/implementation/to-observable.d.ts +12 -5
  76. package/signals/implementation/to-observable.js +12 -2
  77. package/signals/implementation/to-signal.d.ts +9 -18
  78. package/signals/implementation/to-signal.js +46 -13
  79. package/signals/implementation/untracked.d.ts +1 -1
  80. package/signals/implementation/untracked.js +3 -11
  81. package/signals/operators/debounce.d.ts +8 -0
  82. package/signals/operators/debounce.js +19 -0
  83. package/signals/operators/derive-async.js +43 -15
  84. package/signals/operators/index.d.ts +2 -0
  85. package/signals/operators/index.js +2 -0
  86. package/signals/operators/throttle.d.ts +8 -0
  87. package/signals/operators/throttle.js +31 -0
  88. package/ai/genkit/tests/multi-region.test.d.ts +0 -2
  89. package/ai/genkit/tests/multi-region.test.js +0 -179
  90. package/ai/genkit/tests/token-limit-fallback.test.d.ts +0 -2
  91. package/ai/genkit/tests/token-limit-fallback.test.js +0 -209
  92. package/ai/prompts/tests/prompt-builder.test.d.ts +0 -1
  93. package/ai/prompts/tests/prompt-builder.test.js +0 -22
  94. package/ai/tests/instructions-formatter.test.d.ts +0 -1
  95. package/ai/tests/instructions-formatter.test.js +0 -116
  96. package/ai/tests/steering.test.d.ts +0 -1
  97. package/ai/tests/steering.test.js +0 -37
  98. package/api/client/tests/api-client.test.d.ts +0 -1
  99. package/api/client/tests/api-client.test.js +0 -194
  100. package/api/server/tests/csrf.middleware.test.d.ts +0 -1
  101. package/api/server/tests/csrf.middleware.test.js +0 -91
  102. package/authentication/tests/authentication-password-requirements.validator.test.d.ts +0 -1
  103. package/authentication/tests/authentication-password-requirements.validator.test.js +0 -29
  104. package/authentication/tests/authentication.api-controller.test.d.ts +0 -1
  105. package/authentication/tests/authentication.api-controller.test.js +0 -156
  106. package/authentication/tests/authentication.api-request-token.provider.test.d.ts +0 -1
  107. package/authentication/tests/authentication.api-request-token.provider.test.js +0 -48
  108. package/authentication/tests/authentication.client-error-handling.test.d.ts +0 -1
  109. package/authentication/tests/authentication.client-error-handling.test.js +0 -123
  110. package/authentication/tests/authentication.client-middleware.test.d.ts +0 -1
  111. package/authentication/tests/authentication.client-middleware.test.js +0 -118
  112. package/authentication/tests/authentication.client-service-methods.test.d.ts +0 -1
  113. package/authentication/tests/authentication.client-service-methods.test.js +0 -177
  114. package/authentication/tests/authentication.client-service-refresh.test.d.ts +0 -1
  115. package/authentication/tests/authentication.client-service-refresh.test.js +0 -153
  116. package/authentication/tests/authentication.client-service.test.d.ts +0 -1
  117. package/authentication/tests/authentication.client-service.test.js +0 -76
  118. package/authentication/tests/authentication.refresh-busy-loop.test.d.ts +0 -1
  119. package/authentication/tests/authentication.refresh-busy-loop.test.js +0 -84
  120. package/authentication/tests/authentication.service.test.d.ts +0 -1
  121. package/authentication/tests/authentication.service.test.js +0 -167
  122. package/authentication/tests/authentication.test-ancillary-service.d.ts +0 -9
  123. package/authentication/tests/authentication.test-ancillary-service.js +0 -27
  124. package/authentication/tests/brute-force-protection.test.d.ts +0 -1
  125. package/authentication/tests/brute-force-protection.test.js +0 -211
  126. package/authentication/tests/helper.test.d.ts +0 -1
  127. package/authentication/tests/helper.test.js +0 -122
  128. package/authentication/tests/password-requirements.error.test.d.ts +0 -1
  129. package/authentication/tests/password-requirements.error.test.js +0 -14
  130. package/authentication/tests/remember.api.test.d.ts +0 -1
  131. package/authentication/tests/remember.api.test.js +0 -117
  132. package/authentication/tests/remember.service.test.d.ts +0 -1
  133. package/authentication/tests/remember.service.test.js +0 -83
  134. package/authentication/tests/subject.service.test.d.ts +0 -1
  135. package/authentication/tests/subject.service.test.js +0 -140
  136. package/authentication/tests/suspended-subject.test.d.ts +0 -1
  137. package/authentication/tests/suspended-subject.test.js +0 -120
  138. package/authentication/tests/totp.enrollment.test.d.ts +0 -1
  139. package/authentication/tests/totp.enrollment.test.js +0 -123
  140. package/authentication/tests/totp.login.test.d.ts +0 -1
  141. package/authentication/tests/totp.login.test.js +0 -213
  142. package/authentication/tests/totp.recovery-codes.test.d.ts +0 -1
  143. package/authentication/tests/totp.recovery-codes.test.js +0 -97
  144. package/authentication/tests/totp.status.test.d.ts +0 -1
  145. package/authentication/tests/totp.status.test.js +0 -72
  146. package/cancellation/tests/coverage.test.d.ts +0 -1
  147. package/cancellation/tests/coverage.test.js +0 -49
  148. package/cancellation/tests/leak.test.d.ts +0 -1
  149. package/cancellation/tests/leak.test.js +0 -35
  150. package/cancellation/tests/token.test.d.ts +0 -1
  151. package/cancellation/tests/token.test.js +0 -136
  152. package/circuit-breaker/tests/circuit-breaker.test.d.ts +0 -1
  153. package/circuit-breaker/tests/circuit-breaker.test.js +0 -116
  154. package/cryptography/tests/cryptography.test.d.ts +0 -1
  155. package/cryptography/tests/cryptography.test.js +0 -175
  156. package/cryptography/tests/jwt.test.d.ts +0 -1
  157. package/cryptography/tests/jwt.test.js +0 -54
  158. package/cryptography/tests/modern.test.d.ts +0 -1
  159. package/cryptography/tests/modern.test.js +0 -105
  160. package/cryptography/tests/module.test.d.ts +0 -1
  161. package/cryptography/tests/module.test.js +0 -100
  162. package/cryptography/tests/totp.test.d.ts +0 -1
  163. package/cryptography/tests/totp.test.js +0 -108
  164. package/document-management/tests/ai-config-hierarchy.test.d.ts +0 -1
  165. package/document-management/tests/ai-config-hierarchy.test.js +0 -59
  166. package/document-management/tests/ai-config-integration.test.d.ts +0 -1
  167. package/document-management/tests/ai-config-integration.test.js +0 -125
  168. package/document-management/tests/ai-config-merge.test.d.ts +0 -1
  169. package/document-management/tests/ai-config-merge.test.js +0 -46
  170. package/document-management/tests/document-management-ai-overrides.test.d.ts +0 -1
  171. package/document-management/tests/document-management-ai-overrides.test.js +0 -63
  172. package/document-management/tests/document-management-core.test.d.ts +0 -1
  173. package/document-management/tests/document-management-core.test.js +0 -157
  174. package/document-management/tests/document-management.api.test.d.ts +0 -1
  175. package/document-management/tests/document-management.api.test.js +0 -101
  176. package/document-management/tests/document-statistics.service.test.d.ts +0 -1
  177. package/document-management/tests/document-statistics.service.test.js +0 -498
  178. package/document-management/tests/document-validation-ai-overrides.test.d.ts +0 -1
  179. package/document-management/tests/document-validation-ai-overrides.test.js +0 -87
  180. package/document-management/tests/document.service.test.d.ts +0 -1
  181. package/document-management/tests/document.service.test.js +0 -143
  182. package/document-management/tests/enum-helpers.test.d.ts +0 -1
  183. package/document-management/tests/enum-helpers.test.js +0 -452
  184. package/document-management/tests/helper.d.ts +0 -24
  185. package/document-management/tests/helper.js +0 -39
  186. package/errors/tests/format.test.d.ts +0 -1
  187. package/errors/tests/format.test.js +0 -84
  188. package/http/tests/server-timing.test.d.ts +0 -1
  189. package/http/tests/server-timing.test.js +0 -42
  190. package/injector/tests/advanced.test.d.ts +0 -1
  191. package/injector/tests/advanced.test.js +0 -116
  192. package/injector/tests/async-init.test.d.ts +0 -1
  193. package/injector/tests/async-init.test.js +0 -77
  194. package/injector/tests/basic.test.d.ts +0 -1
  195. package/injector/tests/basic.test.js +0 -114
  196. package/injector/tests/hierarchical.test.d.ts +0 -1
  197. package/injector/tests/hierarchical.test.js +0 -59
  198. package/injector/tests/leak.test.d.ts +0 -1
  199. package/injector/tests/leak.test.js +0 -45
  200. package/injector/tests/lifecycles.test.d.ts +0 -1
  201. package/injector/tests/lifecycles.test.js +0 -109
  202. package/logger/tests/pretty-print.test.d.ts +0 -1
  203. package/logger/tests/pretty-print.test.js +0 -60
  204. package/notification/tests/notification-api.test.d.ts +0 -1
  205. package/notification/tests/notification-api.test.js +0 -124
  206. package/notification/tests/notification-client.test.d.ts +0 -1
  207. package/notification/tests/notification-client.test.js +0 -101
  208. package/notification/tests/notification-flow.test.d.ts +0 -1
  209. package/notification/tests/notification-flow.test.js +0 -296
  210. package/notification/tests/notification-sse.service.test.d.ts +0 -1
  211. package/notification/tests/notification-sse.service.test.js +0 -43
  212. package/notification/tests/notification-type.service.test.d.ts +0 -1
  213. package/notification/tests/notification-type.service.test.js +0 -41
  214. package/object-storage/s3/tests/s3.object-storage.integration.test.d.ts +0 -1
  215. package/object-storage/s3/tests/s3.object-storage.integration.test.js +0 -303
  216. package/orm/tests/build-jsonb.test.d.ts +0 -1
  217. package/orm/tests/build-jsonb.test.js +0 -39
  218. package/orm/tests/data-types.test.d.ts +0 -1
  219. package/orm/tests/data-types.test.js +0 -39
  220. package/orm/tests/database-extension.test.d.ts +0 -1
  221. package/orm/tests/database-extension.test.js +0 -63
  222. package/orm/tests/database-migration.test.d.ts +0 -1
  223. package/orm/tests/database-migration.test.js +0 -83
  224. package/orm/tests/decorators.test.d.ts +0 -1
  225. package/orm/tests/decorators.test.js +0 -77
  226. package/orm/tests/encryption.test.d.ts +0 -1
  227. package/orm/tests/encryption.test.js +0 -31
  228. package/orm/tests/query-complex.test.d.ts +0 -1
  229. package/orm/tests/query-complex.test.js +0 -172
  230. package/orm/tests/query-converter-complex.test.d.ts +0 -1
  231. package/orm/tests/query-converter-complex.test.js +0 -131
  232. package/orm/tests/query-converter.test.d.ts +0 -1
  233. package/orm/tests/query-converter.test.js +0 -123
  234. package/orm/tests/repository-advanced.test.d.ts +0 -1
  235. package/orm/tests/repository-advanced.test.js +0 -189
  236. package/orm/tests/repository-attributes.test.d.ts +0 -1
  237. package/orm/tests/repository-attributes.test.js +0 -83
  238. package/orm/tests/repository-compound-primary-key.test.d.ts +0 -2
  239. package/orm/tests/repository-compound-primary-key.test.js +0 -226
  240. package/orm/tests/repository-comprehensive.test.d.ts +0 -1
  241. package/orm/tests/repository-comprehensive.test.js +0 -162
  242. package/orm/tests/repository-coverage.test.d.ts +0 -2
  243. package/orm/tests/repository-coverage.test.js +0 -242
  244. package/orm/tests/repository-cti-complex.test.d.ts +0 -1
  245. package/orm/tests/repository-cti-complex.test.js +0 -151
  246. package/orm/tests/repository-cti-embedded.test.d.ts +0 -1
  247. package/orm/tests/repository-cti-embedded.test.js +0 -178
  248. package/orm/tests/repository-cti-extensive.test.d.ts +0 -2
  249. package/orm/tests/repository-cti-extensive.test.js +0 -279
  250. package/orm/tests/repository-cti-mapping.test.d.ts +0 -2
  251. package/orm/tests/repository-cti-mapping.test.js +0 -108
  252. package/orm/tests/repository-cti-search.test.d.ts +0 -1
  253. package/orm/tests/repository-cti-search.test.js +0 -141
  254. package/orm/tests/repository-cti-soft-delete.test.d.ts +0 -2
  255. package/orm/tests/repository-cti-soft-delete.test.js +0 -103
  256. package/orm/tests/repository-cti-transactions.test.d.ts +0 -1
  257. package/orm/tests/repository-cti-transactions.test.js +0 -112
  258. package/orm/tests/repository-cti-upsert-many.test.d.ts +0 -2
  259. package/orm/tests/repository-cti-upsert-many.test.js +0 -115
  260. package/orm/tests/repository-cti.test.d.ts +0 -2
  261. package/orm/tests/repository-cti.test.js +0 -390
  262. package/orm/tests/repository-edge-cases.test.d.ts +0 -1
  263. package/orm/tests/repository-edge-cases.test.js +0 -178
  264. package/orm/tests/repository-expiration.test.d.ts +0 -2
  265. package/orm/tests/repository-expiration.test.js +0 -140
  266. package/orm/tests/repository-extra-coverage.test.d.ts +0 -2
  267. package/orm/tests/repository-extra-coverage.test.js +0 -402
  268. package/orm/tests/repository-mapping.test.d.ts +0 -2
  269. package/orm/tests/repository-mapping.test.js +0 -65
  270. package/orm/tests/repository-regression.test.d.ts +0 -1
  271. package/orm/tests/repository-regression.test.js +0 -288
  272. package/orm/tests/repository-search-coverage.test.d.ts +0 -1
  273. package/orm/tests/repository-search-coverage.test.js +0 -107
  274. package/orm/tests/repository-search.test.d.ts +0 -1
  275. package/orm/tests/repository-search.test.js +0 -105
  276. package/orm/tests/repository-soft-delete.test.d.ts +0 -1
  277. package/orm/tests/repository-soft-delete.test.js +0 -118
  278. package/orm/tests/repository-transactions-nested.test.d.ts +0 -1
  279. package/orm/tests/repository-transactions-nested.test.js +0 -178
  280. package/orm/tests/repository-types.test.d.ts +0 -1
  281. package/orm/tests/repository-types.test.js +0 -184
  282. package/orm/tests/repository-undelete.test.d.ts +0 -2
  283. package/orm/tests/repository-undelete.test.js +0 -201
  284. package/orm/tests/schema-converter.test.d.ts +0 -1
  285. package/orm/tests/schema-converter.test.js +0 -82
  286. package/orm/tests/schema-generation.test.d.ts +0 -2
  287. package/orm/tests/schema-generation.test.js +0 -174
  288. package/orm/tests/sql-helpers.test.d.ts +0 -1
  289. package/orm/tests/sql-helpers.test.js +0 -67
  290. package/orm/tests/transaction-safety.test.d.ts +0 -1
  291. package/orm/tests/transaction-safety.test.js +0 -81
  292. package/orm/tests/transactional.test.d.ts +0 -1
  293. package/orm/tests/transactional.test.js +0 -215
  294. package/orm/tests/utils.test.d.ts +0 -1
  295. package/orm/tests/utils.test.js +0 -70
  296. package/pdf/tests/utils.test.d.ts +0 -1
  297. package/pdf/tests/utils.test.js +0 -187
  298. package/process/tests/spawn.test.d.ts +0 -1
  299. package/process/tests/spawn.test.js +0 -182
  300. package/rate-limit/tests/postgres-rate-limiter.test.d.ts +0 -1
  301. package/rate-limit/tests/postgres-rate-limiter.test.js +0 -84
  302. package/renderer/tests/renderer.test.d.ts +0 -1
  303. package/renderer/tests/renderer.test.js +0 -88
  304. package/rpc/tests/rpc.integration.test.d.ts +0 -1
  305. package/rpc/tests/rpc.integration.test.js +0 -615
  306. package/signals/implementation/errors.d.ts +0 -2
  307. package/signals/implementation/graph.js +0 -312
  308. package/signals/implementation/writable-signal.d.ts +0 -48
  309. package/signals/implementation/writable-signal.js +0 -32
  310. package/task-queue/tests/coverage-branch.test.d.ts +0 -1
  311. package/task-queue/tests/coverage-branch.test.js +0 -395
  312. package/task-queue/tests/coverage-enhancement.test.d.ts +0 -1
  313. package/task-queue/tests/coverage-enhancement.test.js +0 -150
  314. package/task-queue/tests/dag.test.d.ts +0 -1
  315. package/task-queue/tests/dag.test.js +0 -188
  316. package/task-queue/tests/dependencies.test.d.ts +0 -1
  317. package/task-queue/tests/dependencies.test.js +0 -296
  318. package/task-queue/tests/enqueue-batch.test.d.ts +0 -1
  319. package/task-queue/tests/enqueue-batch.test.js +0 -125
  320. package/task-queue/tests/enqueue-item.test.d.ts +0 -1
  321. package/task-queue/tests/enqueue-item.test.js +0 -12
  322. package/task-queue/tests/fan-out-spawning.test.d.ts +0 -1
  323. package/task-queue/tests/fan-out-spawning.test.js +0 -94
  324. package/task-queue/tests/idempotent-replacement.test.d.ts +0 -1
  325. package/task-queue/tests/idempotent-replacement.test.js +0 -114
  326. package/task-queue/tests/missing-idempotent-tasks.test.d.ts +0 -1
  327. package/task-queue/tests/missing-idempotent-tasks.test.js +0 -39
  328. package/task-queue/tests/optimization-edge-cases.test.d.ts +0 -1
  329. package/task-queue/tests/optimization-edge-cases.test.js +0 -124
  330. package/task-queue/tests/queue-generic.test.d.ts +0 -1
  331. package/task-queue/tests/queue-generic.test.js +0 -8
  332. package/task-queue/tests/queue.test.d.ts +0 -1
  333. package/task-queue/tests/queue.test.js +0 -756
  334. package/task-queue/tests/shutdown.test.d.ts +0 -1
  335. package/task-queue/tests/shutdown.test.js +0 -41
  336. package/task-queue/tests/task-context.test.d.ts +0 -1
  337. package/task-queue/tests/task-context.test.js +0 -7
  338. package/task-queue/tests/task-union.test.d.ts +0 -1
  339. package/task-queue/tests/task-union.test.js +0 -18
  340. package/task-queue/tests/transactions.test.d.ts +0 -1
  341. package/task-queue/tests/transactions.test.js +0 -47
  342. package/task-queue/tests/typing.test.d.ts +0 -1
  343. package/task-queue/tests/typing.test.js +0 -9
  344. package/task-queue/tests/worker.test.d.ts +0 -1
  345. package/task-queue/tests/worker.test.js +0 -258
  346. package/task-queue/tests/zombie-parent.test.d.ts +0 -1
  347. package/task-queue/tests/zombie-parent.test.js +0 -45
  348. package/task-queue/tests/zombie-recovery.test.d.ts +0 -1
  349. package/task-queue/tests/zombie-recovery.test.js +0 -51
  350. package/utils/tests/backoff.test.d.ts +0 -1
  351. package/utils/tests/backoff.test.js +0 -41
  352. package/utils/tests/retry-with-backoff.test.d.ts +0 -1
  353. package/utils/tests/retry-with-backoff.test.js +0 -49
@@ -1,177 +0,0 @@
1
- import { Subject } from 'rxjs';
2
- import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
3
- import { AuthenticationClientService } from '../../authentication/client/authentication.service.js';
4
- import { AUTHENTICATION_API_CLIENT } from '../../authentication/client/tokens.js';
5
- import { CancellationSignal, CancellationToken } from '../../cancellation/token.js';
6
- import { Injector } from '../../injector/index.js';
7
- import { Lock } from '../../lock/index.js';
8
- import { Logger } from '../../logger/index.js';
9
- import { MessageBus } from '../../message-bus/index.js';
10
- import { configureDefaultSignalsImplementation } from '../../signals/implementation/configure.js';
11
- import { currentTimestampSeconds } from '../../utils/date-time.js';
12
- describe('AuthenticationClientService Methods', () => {
13
- let injector;
14
- let service;
15
- let mockApiClient;
16
- let mockLock;
17
- let mockTokenUpdateBus;
18
- let mockLoggedOutBus;
19
- let mockLogger;
20
- beforeEach(() => {
21
- const storage = new Map();
22
- globalThis.localStorage = {
23
- getItem: vi.fn((key) => storage.get(key) ?? null),
24
- setItem: vi.fn((key, value) => storage.set(key, value)),
25
- removeItem: vi.fn((key) => storage.delete(key)),
26
- clear: vi.fn(() => storage.clear()),
27
- };
28
- configureDefaultSignalsImplementation();
29
- injector = new Injector('TestInjector');
30
- mockApiClient = {
31
- login: vi.fn(),
32
- refresh: vi.fn(),
33
- impersonate: vi.fn(),
34
- unimpersonate: vi.fn(),
35
- changePassword: vi.fn(),
36
- initPasswordReset: vi.fn(),
37
- resetPassword: vi.fn(),
38
- checkPassword: vi.fn(),
39
- listSessions: vi.fn(),
40
- invalidateAllOtherSessions: vi.fn(),
41
- timestamp: vi.fn().mockResolvedValue(currentTimestampSeconds()),
42
- endSession: vi.fn().mockResolvedValue(undefined),
43
- };
44
- mockLock = {
45
- tryUse: vi.fn(async (_timeout, callback) => {
46
- const result = await callback({ lost: false });
47
- return { success: true, result };
48
- }),
49
- use: vi.fn(async (_timeout, callback) => {
50
- return await callback({ lost: false });
51
- }),
52
- };
53
- mockTokenUpdateBus = {
54
- publishAndForget: vi.fn(),
55
- messages$: new Subject(),
56
- allMessages$: new Subject(),
57
- dispose: vi.fn(),
58
- };
59
- mockLoggedOutBus = {
60
- publishAndForget: vi.fn(),
61
- messages$: new Subject(),
62
- allMessages$: new Subject(),
63
- dispose: vi.fn(),
64
- };
65
- mockLogger = {
66
- error: vi.fn(),
67
- warn: vi.fn(),
68
- info: vi.fn(),
69
- debug: vi.fn(),
70
- };
71
- injector.register(AUTHENTICATION_API_CLIENT, { useValue: mockApiClient });
72
- injector.register(Lock, { useValue: mockLock });
73
- injector.register(MessageBus, {
74
- useFactory: (argument) => {
75
- if (argument === 'AuthenticationService:tokenUpdate')
76
- return mockTokenUpdateBus;
77
- if (argument === 'AuthenticationService:loggedOut')
78
- return mockLoggedOutBus;
79
- return undefined;
80
- },
81
- });
82
- injector.register(Logger, { useValue: mockLogger });
83
- const disposeToken = new CancellationToken();
84
- injector.register(CancellationSignal, { useValue: disposeToken.signal });
85
- service = injector.resolve(AuthenticationClientService);
86
- });
87
- afterEach(async () => {
88
- await service.dispose();
89
- });
90
- test('impersonate should acquire lock and call api', async () => {
91
- const token = { exp: Date.now() + 3600, jti: 'impersonated-token', subject: 'sub', impersonator: 'admin' };
92
- mockApiClient.impersonate.mockResolvedValue(token);
93
- await service.impersonate('target-subject');
94
- expect(mockLock.use).toHaveBeenCalled();
95
- expect(mockApiClient.impersonate).toHaveBeenCalledWith({ subject: 'target-subject', data: undefined });
96
- expect(service.token()).toEqual(token);
97
- expect(service.impersonated()).toBe(true);
98
- });
99
- test('impersonate should fail if already impersonating', async () => {
100
- const token = { exp: Date.now() + 3600, jti: 'impersonated-token', subject: 'sub', impersonator: 'admin' };
101
- service.setNewToken(token); // Force state
102
- await expect(service.impersonate('another-target')).rejects.toThrow('Already impersonating');
103
- });
104
- test('unimpersonate should acquire lock and call api', async () => {
105
- const token = { exp: Date.now() + 3600, jti: 'original-token', subject: 'admin' };
106
- mockApiClient.unimpersonate.mockResolvedValue(token);
107
- await service.unimpersonate();
108
- expect(mockLock.use).toHaveBeenCalled();
109
- expect(mockApiClient.unimpersonate).toHaveBeenCalled();
110
- expect(service.token()).toEqual(token);
111
- });
112
- test('changePassword should call api', async () => {
113
- await service.changePassword('old', 'new');
114
- expect(mockApiClient.changePassword).toHaveBeenCalledWith({ currentPassword: 'old', newPassword: 'new' });
115
- });
116
- test('initPasswordReset should call api', async () => {
117
- await service.initPasswordReset({ tenantId: 't', subject: 's' }, { some: 'data' });
118
- expect(mockApiClient.initPasswordReset).toHaveBeenCalledWith({ tenantId: 't', subject: 's', data: { some: 'data' } });
119
- });
120
- test('resetPassword should call api', async () => {
121
- await service.resetPassword('token', 'new-password');
122
- expect(mockApiClient.resetPassword).toHaveBeenCalledWith({ token: 'token', newPassword: 'new-password' });
123
- });
124
- test('updateRawTokens should update signals and storage', async () => {
125
- service.updateRawTokens('raw', 'refresh', 'impersonator');
126
- expect(service.rawToken()).toBe('raw');
127
- expect(service.rawRefreshToken()).toBe('refresh');
128
- expect(service.rawImpersonatorRefreshToken()).toBe('impersonator');
129
- expect(globalThis.localStorage.setItem).toHaveBeenCalledWith('AuthenticationService:raw-token', JSON.stringify('raw'));
130
- });
131
- test('impersonate should rollback data on failure', async () => {
132
- service.setAdditionalData({ role: 'admin' });
133
- const originalData = service.authenticationData;
134
- mockApiClient.impersonate.mockRejectedValue(new Error('Impersonation failed'));
135
- await expect(service.impersonate('target')).rejects.toThrow('Impersonation failed');
136
- // Should have restored original data
137
- expect(service.authenticationData).toEqual(originalData);
138
- expect(service.impersonatorAuthenticationData).toBeUndefined();
139
- });
140
- test('unimpersonate should handle failure', async () => {
141
- mockApiClient.unimpersonate.mockRejectedValue(new Error('Unimpersonation failed'));
142
- await expect(service.unimpersonate()).rejects.toThrow('Unimpersonation failed');
143
- });
144
- test('logout should handle concurrent calls and avoid multiple api requests', async () => {
145
- let resolveEndSession;
146
- const endSessionPromise = new Promise((resolve) => {
147
- resolveEndSession = resolve;
148
- });
149
- mockApiClient.endSession.mockReturnValue(endSessionPromise);
150
- const logout1 = service.logout();
151
- const logout2 = service.logout();
152
- // logout1 and logout2 will be different promises because the method is async
153
- expect(mockApiClient.endSession).toHaveBeenCalledTimes(1);
154
- resolveEndSession(undefined);
155
- await Promise.all([logout1, logout2]);
156
- expect(service.isLoggedIn()).toBe(false);
157
- expect(mockTokenUpdateBus.publishAndForget).toHaveBeenCalledWith(undefined);
158
- expect(mockLoggedOutBus.publishAndForget).toHaveBeenCalled();
159
- });
160
- test('syncClock should handle errors gracefully', async () => {
161
- mockApiClient.timestamp.mockRejectedValue(new Error('Time sync failed'));
162
- await service.syncClock();
163
- expect(mockLogger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to synchronize clock'));
164
- expect(service.clockOffset).toBe(0);
165
- });
166
- test('listSessions should call api', async () => {
167
- const sessions = [{ id: '1', begin: 100, end: 200 }];
168
- mockApiClient.listSessions.mockResolvedValue(sessions);
169
- const result = await service.listSessions();
170
- expect(mockApiClient.listSessions).toHaveBeenCalled();
171
- expect(result).toEqual(sessions);
172
- });
173
- test('invalidateAllOtherSessions should call api', async () => {
174
- await service.invalidateAllOtherSessions();
175
- expect(mockApiClient.invalidateAllOtherSessions).toHaveBeenCalled();
176
- });
177
- });
@@ -1,153 +0,0 @@
1
- import { Subject } from 'rxjs';
2
- import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
3
- import { AuthenticationClientService } from '../../authentication/client/authentication.service.js';
4
- import { AUTHENTICATION_API_CLIENT } from '../../authentication/client/tokens.js';
5
- import { CancellationSignal, CancellationToken } from '../../cancellation/token.js';
6
- import { Injector } from '../../injector/index.js';
7
- import { Lock } from '../../lock/index.js';
8
- import { Logger } from '../../logger/index.js';
9
- import { MessageBus } from '../../message-bus/index.js';
10
- import { configureDefaultSignalsImplementation } from '../../signals/implementation/configure.js';
11
- import { currentTimestampSeconds } from '../../utils/date-time.js';
12
- import { timeout } from '../../utils/timing.js';
13
- describe('AuthenticationClientService Refresh Loop Reproduction', () => {
14
- let injector;
15
- let service;
16
- let mockApiClient;
17
- let mockLock;
18
- let mockMessageBus;
19
- let mockLogger;
20
- let disposeToken;
21
- beforeEach(() => {
22
- const storage = new Map();
23
- globalThis.localStorage = {
24
- getItem: vi.fn((key) => storage.get(key) ?? null),
25
- setItem: vi.fn((key, value) => storage.set(key, value)),
26
- removeItem: vi.fn((key) => storage.delete(key)),
27
- clear: vi.fn(() => storage.clear()),
28
- };
29
- configureDefaultSignalsImplementation();
30
- injector = new Injector('Test');
31
- mockApiClient = {
32
- login: vi.fn(),
33
- refresh: vi.fn(),
34
- timestamp: vi.fn().mockResolvedValue(currentTimestampSeconds()),
35
- endSession: vi.fn().mockResolvedValue(undefined),
36
- };
37
- mockLock = {
38
- tryUse: vi.fn(async (_timeout, callback) => {
39
- const result = await callback({ lost: false });
40
- return { success: true, result };
41
- }),
42
- use: vi.fn(async (_timeout, callback) => {
43
- return await callback({ lost: false });
44
- }),
45
- };
46
- mockMessageBus = {
47
- publishAndForget: vi.fn(),
48
- messages$: new Subject(),
49
- dispose: vi.fn(),
50
- };
51
- mockLogger = {
52
- error: vi.fn(),
53
- warn: vi.fn(),
54
- info: vi.fn(),
55
- debug: vi.fn(),
56
- };
57
- injector.register(AUTHENTICATION_API_CLIENT, { useValue: mockApiClient });
58
- injector.register(Lock, { useValue: mockLock });
59
- injector.register(MessageBus, { useValue: mockMessageBus });
60
- injector.register(Logger, { useValue: mockLogger });
61
- disposeToken = new CancellationToken();
62
- injector.register(CancellationSignal, { useValue: disposeToken.signal });
63
- });
64
- afterEach(async () => {
65
- disposeToken.set();
66
- await injector.dispose();
67
- });
68
- test('Zombie Timer: loop should wake up immediately when token changes', async () => {
69
- // 1. Mock a long expiration
70
- const now = currentTimestampSeconds();
71
- const initialToken = { iat: now - 3600, exp: now + 3600, jti: 'initial' };
72
- // Set in storage so initialize() (called by resolve) loads it
73
- globalThis.localStorage.setItem('AuthenticationService:token', JSON.stringify(initialToken));
74
- service = injector.resolve(AuthenticationClientService);
75
- // Wait for loop to enter the race condition (wait phase)
76
- await timeout(20);
77
- // 2. Change token
78
- const newToken = { iat: now - 1800, exp: now + 3600, jti: 'new' };
79
- mockApiClient.refresh.mockResolvedValue(newToken);
80
- service.requestRefresh(); // This should trigger immediate wake up
81
- // Wait for loop to process
82
- await timeout(20);
83
- expect(mockApiClient.refresh).toHaveBeenCalled();
84
- });
85
- test('Forced Refresh Loss: forceRefreshToken should not be cleared on failure', async () => {
86
- const now = currentTimestampSeconds();
87
- const initialToken = { iat: now - 3600, exp: now + 3600, jti: 'initial' };
88
- globalThis.localStorage.setItem('AuthenticationService:token', JSON.stringify(initialToken));
89
- service = injector.resolve(AuthenticationClientService);
90
- await timeout(20);
91
- // 1. Mock refresh failure
92
- mockApiClient.refresh.mockRejectedValue(new Error('Network Error'));
93
- service.requestRefresh();
94
- // Wait for loop to attempt refresh and fail
95
- await timeout(50);
96
- expect(mockApiClient.refresh).toHaveBeenCalled();
97
- expect(service.forceRefreshRequested()).toBe(true); // Should STILL be set
98
- });
99
- test('Lock Contention Backoff: should wait 5 seconds and not busy-loop', async () => {
100
- const now = currentTimestampSeconds();
101
- const initialToken = { iat: now - 3600, exp: now + 5, jti: 'initial' }; // Expiring soon
102
- globalThis.localStorage.setItem('AuthenticationService:token', JSON.stringify(initialToken));
103
- // 1. Mock lock already held
104
- mockLock.tryUse.mockResolvedValue(undefined); // lockAcquired = false
105
- const startTime = Date.now();
106
- service = injector.resolve(AuthenticationClientService);
107
- // We expect it to try once, fail to get lock, and then wait some time.
108
- await timeout(50);
109
- expect(mockLock.tryUse).toHaveBeenCalledTimes(1);
110
- // Check if it's still waiting (not finished loop)
111
- const duration = Date.now() - startTime;
112
- expect(duration).toBeLessThan(500);
113
- });
114
- test('Busy Loop: should not busy loop when forceRefreshToken is set and lock is held', async () => {
115
- const now = currentTimestampSeconds();
116
- const initialToken = { iat: now - 3600, exp: now + 3600, jti: 'initial' };
117
- globalThis.localStorage.setItem('AuthenticationService:token', JSON.stringify(initialToken));
118
- // Mock lock already held
119
- mockLock.tryUse.mockResolvedValue(undefined);
120
- service = injector.resolve(AuthenticationClientService);
121
- await timeout(20);
122
- service.requestRefresh(); // Set the flag
123
- await timeout(50);
124
- // If it busy loops, this will be much higher than 1.
125
- expect(mockLock.tryUse.mock.calls.length).toBeLessThan(5);
126
- });
127
- test('refresh() should call timestamp() to sync clock', async () => {
128
- service = injector.resolve(AuthenticationClientService);
129
- const newToken = { iat: 1000, exp: 2000, jti: 'new' };
130
- mockApiClient.refresh.mockResolvedValue(newToken);
131
- await service.refresh();
132
- expect(mockApiClient.timestamp).toHaveBeenCalled();
133
- });
134
- test('Cross-tab Sync: should not refresh if another tab already did (simulated via localStorage update)', async () => {
135
- const now = currentTimestampSeconds();
136
- const initialToken = { iat: now - 3600, exp: now + 5, jti: 'initial' }; // Expiring soon
137
- globalThis.localStorage.setItem('AuthenticationService:token', JSON.stringify(initialToken));
138
- // 1. Mock lock behavior to simulate another tab refreshing while we wait for the lock
139
- mockLock.tryUse.mockImplementation(async (_timeout, callback) => {
140
- // Simulate another tab refreshing and updating localStorage
141
- const newToken = { iat: now, exp: now + 3600, jti: 'refreshed-by-other-tab' };
142
- globalThis.localStorage.setItem('AuthenticationService:token', JSON.stringify(newToken));
143
- const result = await callback({ lost: false });
144
- return { success: true, result };
145
- });
146
- service = injector.resolve(AuthenticationClientService);
147
- // Wait for loop to run
148
- await timeout(100);
149
- // Should NOT have called refresh because loadToken() inside the lock updated the token
150
- expect(mockApiClient.refresh).not.toHaveBeenCalled();
151
- expect(service.token()?.jti).toBe('refreshed-by-other-tab');
152
- });
153
- });
@@ -1,76 +0,0 @@
1
- import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
2
- import { AuthenticationClientService } from '../../authentication/client/index.js';
3
- import { AuthenticationService as AuthenticationServerService } from '../../authentication/server/index.js';
4
- import { HttpClientOptions } from '../../http/client/index.js';
5
- import { HttpServer } from '../../http/server/index.js';
6
- import { runInInjectionContext } from '../../injector/index.js';
7
- import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
8
- import { SubjectService } from '../server/subject.service.js';
9
- import { DefaultAuthenticationAncillaryService } from './authentication.test-ancillary-service.js';
10
- describe('AuthenticationClientService Integration', () => {
11
- let injector;
12
- let database;
13
- let service;
14
- let serverService;
15
- let subjectService;
16
- let server;
17
- const schema = 'authentication';
18
- const tenantId = crypto.randomUUID();
19
- beforeAll(async () => {
20
- const storage = new Map();
21
- globalThis.localStorage = {
22
- getItem: vi.fn((key) => storage.get(key) ?? null),
23
- setItem: vi.fn((key, value) => storage.set(key, value)),
24
- removeItem: vi.fn((key) => storage.delete(key)),
25
- clear: vi.fn(() => storage.clear()),
26
- };
27
- ({ injector, database } = await setupIntegrationTest({
28
- modules: { authentication: true, audit: true, keyValueStore: true, signals: true, api: true },
29
- authentication: {
30
- ancillaryService: DefaultAuthenticationAncillaryService,
31
- },
32
- }));
33
- await runInInjectionContext(injector, async () => {
34
- server = injector.resolve(HttpServer);
35
- const httpClientOptions = injector.resolve(HttpClientOptions);
36
- httpClientOptions.baseUrl = `http://localhost:${server.port}`;
37
- serverService = await injector.resolveAsync(AuthenticationServerService);
38
- subjectService = await injector.resolveAsync(SubjectService);
39
- service = await injector.resolveAsync(AuthenticationClientService);
40
- service.initialize();
41
- });
42
- });
43
- afterAll(async () => {
44
- await server?.close(1000);
45
- await injector?.dispose();
46
- });
47
- beforeEach(async () => {
48
- globalThis.localStorage?.clear();
49
- await clearTenantData(database, schema, ['password', 'session', 'user', 'service_account', 'system_account', 'subject'], tenantId);
50
- });
51
- test('login and logout should work', async () => {
52
- const user = await subjectService.createUser({ tenantId, email: 'client-test@example.com', firstName: 'C', lastName: 'T' });
53
- await serverService.setPassword(user, 'Strong-Pass-2026!');
54
- expect(service.isLoggedIn()).toBe(false);
55
- await service.login({ tenantId, subject: user.id }, 'Strong-Pass-2026!');
56
- expect(service.isLoggedIn()).toBe(true);
57
- expect(service.subjectId()).toBe(user.id);
58
- await service.logout();
59
- expect(service.isLoggedIn()).toBe(false);
60
- });
61
- test('refresh should work', async () => {
62
- const user = await subjectService.createUser({ tenantId, email: 'refresh-test@example.com', firstName: 'R', lastName: 'T' });
63
- await serverService.setPassword(user, 'Strong-Pass-2026!');
64
- await service.login({ tenantId, subject: user.id }, 'Strong-Pass-2026!');
65
- const initialToken = service.token()?.jti;
66
- await service.refresh();
67
- expect(service.token()?.jti).not.toBe(initialToken);
68
- expect(service.isLoggedIn()).toBe(true);
69
- });
70
- test('checkPassword should work', async () => {
71
- const result = await service.checkPassword('123');
72
- expect(result.strength).toBeLessThan(2);
73
- const strongResult = await service.checkPassword('Very-Strong-Password-2026-!@#$');
74
- expect(strongResult.strength).toBeGreaterThanOrEqual(2);
75
- });
76
- });
@@ -1,84 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
2
- import { AuthenticationClientService } from '../../authentication/client/authentication.service.js';
3
- import { AUTHENTICATION_API_CLIENT } from '../../authentication/client/tokens.js';
4
- import { CancellationSignal, CancellationToken } from '../../cancellation/token.js';
5
- import { Injector } from '../../injector/index.js';
6
- import { Lock } from '../../lock/index.js';
7
- import { Logger } from '../../logger/index.js';
8
- import { MessageBus } from '../../message-bus/index.js';
9
- import { configureDefaultSignalsImplementation } from '../../signals/implementation/configure.js';
10
- import { timeout } from '../../utils/timing.js';
11
- import { Subject } from 'rxjs';
12
- describe('AuthenticationClientService Refresh Busy Loop Prevention', () => {
13
- let injector;
14
- let service;
15
- let mockApiClient;
16
- let mockLock;
17
- let mockMessageBus;
18
- let mockLogger;
19
- let disposeToken;
20
- beforeEach(() => {
21
- const storage = new Map();
22
- globalThis.localStorage = {
23
- getItem: vi.fn((key) => storage.get(key) ?? null),
24
- setItem: vi.fn((key, value) => storage.set(key, value)),
25
- removeItem: vi.fn((key) => storage.delete(key)),
26
- clear: vi.fn(() => storage.clear()),
27
- };
28
- configureDefaultSignalsImplementation();
29
- injector = new Injector('Test');
30
- mockApiClient = {
31
- login: vi.fn(),
32
- refresh: vi.fn(),
33
- timestamp: vi.fn().mockResolvedValue(1000), // Fixed timestamp
34
- endSession: vi.fn().mockResolvedValue(undefined),
35
- };
36
- mockLock = {
37
- tryUse: vi.fn(async (_timeout, callback) => {
38
- const result = await callback({ lost: false });
39
- return { success: true, result };
40
- }),
41
- use: vi.fn(async (_timeout, callback) => {
42
- return await callback({ lost: false });
43
- }),
44
- };
45
- mockMessageBus = {
46
- publishAndForget: vi.fn(),
47
- messages$: new Subject(),
48
- dispose: vi.fn(),
49
- };
50
- mockLogger = {
51
- error: vi.fn(),
52
- warn: vi.fn(),
53
- info: vi.fn(),
54
- debug: vi.fn(),
55
- };
56
- injector.register(AUTHENTICATION_API_CLIENT, { useValue: mockApiClient });
57
- injector.register(Lock, { useValue: mockLock });
58
- injector.register(MessageBus, { useValue: mockMessageBus });
59
- injector.register(Logger, { useValue: mockLogger });
60
- disposeToken = new CancellationToken();
61
- injector.register(CancellationSignal, { useValue: disposeToken.signal });
62
- });
63
- afterEach(async () => {
64
- disposeToken.set();
65
- await injector.dispose();
66
- });
67
- test('should not busy loop when refresh fails to produce a valid token', async () => {
68
- // 1. Mock a token that is ALWAYS expired
69
- // Server time is 1000. Token expires at 500.
70
- const expiredToken = { iat: 0, exp: 500, jti: 'expired', session: 's', tenant: 't', subject: 'sub' };
71
- globalThis.localStorage.setItem('AuthenticationService:token', JSON.stringify(expiredToken));
72
- // refresh() will return the SAME expired token
73
- mockApiClient.refresh.mockResolvedValue(expiredToken);
74
- // 2. Start service
75
- service = injector.resolve(AuthenticationClientService);
76
- // 3. Wait a bit
77
- // With 100ms mandatory yield + minRefreshDelay (1 min) protection, it should only try once or twice in 500ms
78
- // WITHOUT protection, it would try thousands of times.
79
- await timeout(500);
80
- // It should have tried to refresh
81
- expect(mockApiClient.refresh.mock.calls.length).toBeLessThan(5);
82
- expect(mockLogger.warn).toHaveBeenCalledWith(expect.stringContaining('Token still needs refresh after attempt'));
83
- });
84
- });
@@ -1 +0,0 @@
1
- export {};