@tstdl/base 0.93.182 → 0.93.184

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 +6 -1
  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 +10 -1
  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,213 +0,0 @@
1
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from 'vitest';
2
- import { ActorType, Auditor } from '../../audit/index.js';
3
- import { importKey } from '../../cryptography/index.js';
4
- import { generateTotpToken } from '../../cryptography/totp.js';
5
- import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
6
- import { currentTimestampSeconds } from '../../utils/date-time.js';
7
- import { AuthenticationService } from '../server/authentication.service.js';
8
- import { SubjectService } from '../server/subject.service.js';
9
- import { DefaultAuthenticationAncillaryService } from './authentication.test-ancillary-service.js';
10
- describe('TOTP Login', () => {
11
- let injector;
12
- let database;
13
- let authenticationService;
14
- let subjectService;
15
- let auditor;
16
- const schema = 'authentication';
17
- const tenantId = crypto.randomUUID();
18
- const password = crypto.randomUUID();
19
- beforeAll(async () => {
20
- ({ injector, database } = await setupIntegrationTest({
21
- modules: { authentication: true },
22
- authentication: {
23
- ancillaryService: DefaultAuthenticationAncillaryService,
24
- },
25
- }));
26
- authenticationService = await injector.resolveAsync(AuthenticationService);
27
- subjectService = await injector.resolveAsync(SubjectService);
28
- auditor = injector.resolve(Auditor);
29
- });
30
- afterAll(async () => {
31
- await injector?.dispose();
32
- });
33
- beforeEach(async () => {
34
- await clearTenantData(database, schema, ['used_totp_tokens', 'totp_recovery_code', 'totp', 'password', 'session', 'user', 'service_account', 'system_account', 'subject'], tenantId);
35
- });
36
- test('loginVerifyTotp should fail if the same token is used twice (replay attack)', async () => {
37
- const user = await subjectService.createUser({
38
- tenantId,
39
- email: 'replay-totp@example.com',
40
- firstName: 'Replay',
41
- lastName: 'Totp',
42
- });
43
- await authenticationService.setPassword(user, password);
44
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
45
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
46
- const totpEntry = await authenticationService.tryGetTotp(tenantId, user.id);
47
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
48
- const enrollmentToken = await generateTotpToken(secretKey, { ...authenticationService.getTotpOptions(), timestamp: currentTimestampSeconds() - 30 });
49
- await authenticationService.completeEnrollTotp(tenantId, user.id, enrollmentToken, userAuditor);
50
- const loginResult1 = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor);
51
- const loginResult2 = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor);
52
- const challengeToken1 = loginResult1.challengeToken;
53
- const challengeToken2 = loginResult2.challengeToken;
54
- const totpToken = await generateTotpToken(secretKey, authenticationService.getTotpOptions());
55
- // First use: success
56
- const verifyResult1 = await authenticationService.loginVerifyTotp(challengeToken1, totpToken, auditor);
57
- expect(verifyResult1.type).toBe('success');
58
- // Second use (replay): fail
59
- await expect(authenticationService.loginVerifyTotp(challengeToken2, totpToken, auditor)).rejects.toThrow();
60
- });
61
- test('login should return success if TOTP is not enabled', async () => {
62
- const user = await subjectService.createUser({
63
- tenantId,
64
- email: 'no-totp@example.com',
65
- firstName: 'No',
66
- lastName: 'Totp',
67
- });
68
- await authenticationService.setPassword(user, password);
69
- const result = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor);
70
- expect(result.type).toBe('success');
71
- });
72
- test('login should return totp challenge if TOTP is enabled', async () => {
73
- const user = await subjectService.createUser({
74
- tenantId,
75
- email: 'with-totp@example.com',
76
- firstName: 'With',
77
- lastName: 'Totp',
78
- });
79
- await authenticationService.setPassword(user, password);
80
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
81
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
82
- const totpEntry = await authenticationService.tryGetTotp(tenantId, user.id);
83
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
84
- const token = await generateTotpToken(secretKey, { ...authenticationService.getTotpOptions(), timestamp: currentTimestampSeconds() - 30 });
85
- await authenticationService.completeEnrollTotp(tenantId, user.id, token, userAuditor);
86
- const result = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor);
87
- expect(result.type).toBe('totp');
88
- if (result.type !== 'totp') {
89
- throw new Error('Expected TOTP result');
90
- }
91
- expect(result.challengeToken).toBeDefined();
92
- });
93
- test('loginVerifyTotp should return success with valid token', async () => {
94
- const user = await subjectService.createUser({
95
- tenantId,
96
- email: 'verify-totp@example.com',
97
- firstName: 'Verify',
98
- lastName: 'Totp',
99
- });
100
- await authenticationService.setPassword(user, password);
101
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
102
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
103
- const totpEntry = await authenticationService.tryGetTotp(tenantId, user.id);
104
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
105
- const enrollmentToken = await generateTotpToken(secretKey, { ...authenticationService.getTotpOptions(), timestamp: currentTimestampSeconds() - 30 });
106
- await authenticationService.completeEnrollTotp(tenantId, user.id, enrollmentToken, userAuditor);
107
- const loginResult = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor, true);
108
- expect(loginResult.type).toBe('totp');
109
- if (loginResult.type !== 'totp') {
110
- throw new Error('Expected TOTP result');
111
- }
112
- const challengeToken = loginResult.challengeToken;
113
- const totpToken = await generateTotpToken(secretKey, authenticationService.getTotpOptions());
114
- const verifyResult = await authenticationService.loginVerifyTotp(challengeToken, totpToken, auditor);
115
- expect(verifyResult.type).toBe('success');
116
- expect(verifyResult.result.remember).toBe(true);
117
- });
118
- test('loginVerifyTotp should fail with recovery code (decoupled)', async () => {
119
- const user = await subjectService.createUser({
120
- tenantId,
121
- email: 'verify-recovery-fail@example.com',
122
- firstName: 'Verify',
123
- lastName: 'RecoveryFail',
124
- });
125
- await authenticationService.setPassword(user, password);
126
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
127
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
128
- const totpEntry = await authenticationService.tryGetTotp(tenantId, user.id);
129
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
130
- const enrollmentToken = await generateTotpToken(secretKey, { ...authenticationService.getTotpOptions(), timestamp: currentTimestampSeconds() - 30 });
131
- const { recoveryCodes } = await authenticationService.completeEnrollTotp(tenantId, user.id, enrollmentToken, userAuditor);
132
- const loginResult = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor);
133
- expect(loginResult.type).toBe('totp');
134
- if (loginResult.type !== 'totp') {
135
- throw new Error('Expected TOTP result');
136
- }
137
- const challengeToken = loginResult.challengeToken;
138
- await expect(authenticationService.loginVerifyTotp(challengeToken, recoveryCodes[0], auditor)).rejects.toThrow();
139
- });
140
- test('loginRecovery should return success with valid recovery code', async () => {
141
- const user = await subjectService.createUser({
142
- tenantId,
143
- email: 'verify-recovery-success@example.com',
144
- firstName: 'Verify',
145
- lastName: 'RecoverySuccess',
146
- });
147
- await authenticationService.setPassword(user, password);
148
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
149
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
150
- const totpEntry = await authenticationService.tryGetTotp(tenantId, user.id);
151
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
152
- const enrollmentToken = await generateTotpToken(secretKey, { ...authenticationService.getTotpOptions(), timestamp: currentTimestampSeconds() - 30 });
153
- const { recoveryCodes } = await authenticationService.completeEnrollTotp(tenantId, user.id, enrollmentToken, userAuditor);
154
- const loginResult = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor);
155
- expect(loginResult.type).toBe('totp');
156
- if (loginResult.type !== 'totp') {
157
- throw new Error('Expected TOTP result');
158
- }
159
- const challengeToken = loginResult.challengeToken;
160
- const verifyResult = await authenticationService.loginRecovery(challengeToken, recoveryCodes[0], auditor);
161
- expect(verifyResult.type).toBe('success');
162
- expect(verifyResult.lowRecoveryCodesWarning).toBe(false);
163
- });
164
- test('loginRecovery should return success and lowRecoveryCodesWarning when few codes remain', async () => {
165
- const user = await subjectService.createUser({
166
- tenantId,
167
- email: 'verify-recovery-warning@example.com',
168
- firstName: 'Verify',
169
- lastName: 'RecoveryWarning',
170
- });
171
- await authenticationService.setPassword(user, password);
172
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
173
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
174
- const totpEntry = await authenticationService.tryGetTotp(tenantId, user.id);
175
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
176
- const enrollmentToken = await generateTotpToken(secretKey, { ...authenticationService.getTotpOptions(), timestamp: currentTimestampSeconds() - 30 });
177
- const { recoveryCodes } = await authenticationService.completeEnrollTotp(tenantId, user.id, enrollmentToken, userAuditor);
178
- // Use 7 codes to leave 3 unused (assuming 10 total)
179
- for (let i = 0; i < 7; i++) {
180
- const loginResult = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor);
181
- const challengeToken = loginResult.challengeToken;
182
- await authenticationService.loginRecovery(challengeToken, recoveryCodes[i], auditor);
183
- }
184
- // Next use should trigger warning
185
- const loginResult = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor);
186
- const challengeToken = loginResult.challengeToken;
187
- const verifyResult = await authenticationService.loginRecovery(challengeToken, recoveryCodes[7], auditor);
188
- expect(verifyResult.type).toBe('success');
189
- expect(verifyResult.lowRecoveryCodesWarning).toBe(true);
190
- });
191
- test('loginVerifyTotp should fail with invalid token', async () => {
192
- const user = await subjectService.createUser({
193
- tenantId,
194
- email: 'verify-fail@example.com',
195
- firstName: 'Verify',
196
- lastName: 'Fail',
197
- });
198
- await authenticationService.setPassword(user, password);
199
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
200
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
201
- const totpEntry = await authenticationService.tryGetTotp(tenantId, user.id);
202
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
203
- const enrollmentToken = await generateTotpToken(secretKey, { ...authenticationService.getTotpOptions(), timestamp: currentTimestampSeconds() - 30 });
204
- await authenticationService.completeEnrollTotp(tenantId, user.id, enrollmentToken, userAuditor);
205
- const loginResult = await authenticationService.login({ tenantId, subject: user.id }, password, undefined, auditor);
206
- expect(loginResult.type).toBe('totp');
207
- if (loginResult.type !== 'totp') {
208
- throw new Error('Expected TOTP result');
209
- }
210
- const challengeToken = loginResult.challengeToken;
211
- await expect(authenticationService.loginVerifyTotp(challengeToken, '000000', auditor)).rejects.toThrow();
212
- });
213
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,97 +0,0 @@
1
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from 'vitest';
2
- import { ActorType, Auditor } from '../../audit/index.js';
3
- import { importKey } from '../../cryptography/index.js';
4
- import { generateTotpToken } from '../../cryptography/totp.js';
5
- import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
6
- import { currentTimestampSeconds } from '../../utils/date-time.js';
7
- import { AuthenticationService } from '../server/authentication.service.js';
8
- import { SubjectService } from '../server/subject.service.js';
9
- import { DefaultAuthenticationAncillaryService } from './authentication.test-ancillary-service.js';
10
- describe('TOTP Recovery Codes Regeneration', () => {
11
- let injector;
12
- let database;
13
- let authenticationService;
14
- let subjectService;
15
- let auditor;
16
- const schema = 'authentication';
17
- const tenantId = crypto.randomUUID();
18
- beforeAll(async () => {
19
- ({ injector, database } = await setupIntegrationTest({
20
- modules: { authentication: true },
21
- authentication: {
22
- ancillaryService: DefaultAuthenticationAncillaryService,
23
- },
24
- }));
25
- authenticationService = await injector.resolveAsync(AuthenticationService);
26
- subjectService = await injector.resolveAsync(SubjectService);
27
- auditor = injector.resolve(Auditor);
28
- });
29
- afterAll(async () => {
30
- await injector?.dispose();
31
- });
32
- beforeEach(async () => {
33
- await clearTenantData(database, schema, ['used_totp_tokens', 'totp_recovery_code', 'totp', 'password', 'session', 'user', 'service_account', 'system_account', 'subject'], tenantId);
34
- });
35
- test('regenerateRecoveryCodes should replace existing codes after valid TOTP verification', async () => {
36
- const user = await subjectService.createUser({
37
- tenantId,
38
- email: 'regen-totp@example.com',
39
- firstName: 'Regen',
40
- lastName: 'Totp',
41
- });
42
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
43
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
44
- const totpEntry = (await authenticationService.tryGetTotp(tenantId, user.id));
45
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
46
- const token = await generateTotpToken(secretKey, authenticationService.getTotpOptions());
47
- const { recoveryCodes: originalCodes } = await authenticationService.completeEnrollTotp(tenantId, user.id, token, userAuditor);
48
- // Verify original codes work (using disableTotp for now as it uses recovery codes currently)
49
- // Actually we just want to ensure regeneration works.
50
- const regenToken = await generateTotpToken(secretKey, { ...authenticationService.getTotpOptions(), timestamp: currentTimestampSeconds() + 30 });
51
- const { recoveryCodes: newCodes } = await authenticationService.regenerateRecoveryCodes(tenantId, user.id, regenToken, userAuditor);
52
- expect(newCodes).toHaveLength(10);
53
- expect(newCodes).not.toEqual(originalCodes);
54
- // Verify old code fails (should fail standard TOTP verification fallback later, but for now let's just check they are replaced)
55
- // We can't easily check database content directly here without more boilerplate, but the logic should handle it.
56
- });
57
- test('regenerateRecoveryCodes should fail with invalid TOTP token', async () => {
58
- const user = await subjectService.createUser({
59
- tenantId,
60
- email: 'regen-fail@example.com',
61
- firstName: 'Regen',
62
- lastName: 'Fail',
63
- });
64
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
65
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
66
- const totpEntry = (await authenticationService.tryGetTotp(tenantId, user.id));
67
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
68
- const token = await generateTotpToken(secretKey, authenticationService.getTotpOptions());
69
- await authenticationService.completeEnrollTotp(tenantId, user.id, token, userAuditor);
70
- await expect(authenticationService.regenerateRecoveryCodes(tenantId, user.id, '000000', userAuditor)).rejects.toThrow();
71
- });
72
- test('regenerateRecoveryCodes should optionally invalidate other sessions', async () => {
73
- const user = await subjectService.createUser({
74
- tenantId,
75
- email: 'regen-invalidate@example.com',
76
- firstName: 'Regen',
77
- lastName: 'Invalidate',
78
- });
79
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
80
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
81
- const totpEntry = (await authenticationService.tryGetTotp(tenantId, user.id));
82
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
83
- const token = await generateTotpToken(secretKey, authenticationService.getTotpOptions());
84
- await authenticationService.completeEnrollTotp(tenantId, user.id, token, userAuditor);
85
- // Create some sessions
86
- const session1 = await authenticationService.loginAlreadyValidatedSubject(user, undefined, userAuditor, false);
87
- const session2 = await authenticationService.loginAlreadyValidatedSubject(user, undefined, userAuditor, false);
88
- const regenToken = await generateTotpToken(secretKey, { ...authenticationService.getTotpOptions(), timestamp: currentTimestampSeconds() + 30 });
89
- // We need to pass the current session id to NOT invalidate it if we were implementing it for "invalidateOtherSessions"
90
- // But the spec says "invalidateOtherSessions", usually it means all except current.
91
- // In this test context, we don't have a "current" session in the service call yet, unless we fork the auditor or similar.
92
- // Let's see how AuthenticationService handles session invalidation.
93
- await authenticationService.regenerateRecoveryCodes(tenantId, user.id, regenToken, userAuditor, { invalidateOtherSessions: true });
94
- // Check sessions (should be invalidated)
95
- // This part might need adjustment based on how invalidateAllOtherSessions is implemented in the service.
96
- });
97
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,72 +0,0 @@
1
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from 'vitest';
2
- import { ActorType, Auditor } from '../../audit/index.js';
3
- import { importKey } from '../../cryptography/index.js';
4
- import { generateTotpToken } from '../../cryptography/totp.js';
5
- import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
6
- import { AuthenticationService } from '../server/authentication.service.js';
7
- import { SubjectService } from '../server/subject.service.js';
8
- import { DefaultAuthenticationAncillaryService } from './authentication.test-ancillary-service.js';
9
- describe('TOTP Status', () => {
10
- let injector;
11
- let database;
12
- let authenticationService;
13
- let subjectService;
14
- let auditor;
15
- const schema = 'authentication';
16
- const tenantId = crypto.randomUUID();
17
- beforeAll(async () => {
18
- ({ injector, database } = await setupIntegrationTest({
19
- modules: { authentication: true },
20
- authentication: {
21
- ancillaryService: DefaultAuthenticationAncillaryService,
22
- },
23
- }));
24
- authenticationService = await injector.resolveAsync(AuthenticationService);
25
- subjectService = await injector.resolveAsync(SubjectService);
26
- auditor = injector.resolve(Auditor);
27
- });
28
- afterAll(async () => {
29
- await injector?.dispose();
30
- });
31
- beforeEach(async () => {
32
- await clearTenantData(database, schema, ['used_totp_tokens', 'totp_recovery_code', 'totp', 'password', 'session', 'user', 'service_account', 'system_account', 'subject'], tenantId);
33
- });
34
- test('getTotpStatus should return false when TOTP is not enrolled', async () => {
35
- const user = await subjectService.createUser({
36
- tenantId,
37
- email: 'no-totp@example.com',
38
- firstName: 'No',
39
- lastName: 'Totp',
40
- });
41
- const status = await authenticationService.getTotpStatus(tenantId, user.id);
42
- expect(status.active).toBe(false);
43
- });
44
- test('getTotpStatus should return false when TOTP enrollment is pending', async () => {
45
- const user = await subjectService.createUser({
46
- tenantId,
47
- email: 'pending-totp@example.com',
48
- firstName: 'Pending',
49
- lastName: 'Totp',
50
- });
51
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
52
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
53
- const status = await authenticationService.getTotpStatus(tenantId, user.id);
54
- expect(status.active).toBe(false);
55
- });
56
- test('getTotpStatus should return true when TOTP is active', async () => {
57
- const user = await subjectService.createUser({
58
- tenantId,
59
- email: 'active-totp@example.com',
60
- firstName: 'Active',
61
- lastName: 'Totp',
62
- });
63
- const userAuditor = auditor.with({ actor: user.id, actorType: ActorType.Subject });
64
- await authenticationService.initEnrollTotp(tenantId, user.id, userAuditor);
65
- const totpEntry = (await authenticationService.tryGetTotp(tenantId, user.id));
66
- const secretKey = await importKey('raw-secret', totpEntry.secret, { name: 'HMAC', hash: authenticationService.getTotpOptions().codeHashAlgorithm }, false, ['sign']);
67
- const token = await generateTotpToken(secretKey, authenticationService.getTotpOptions());
68
- await authenticationService.completeEnrollTotp(tenantId, user.id, token, userAuditor);
69
- const status = await authenticationService.getTotpStatus(tenantId, user.id);
70
- expect(status.active).toBe(true);
71
- });
72
- });
@@ -1 +0,0 @@
1
- import '../../polyfills.js';
@@ -1,49 +0,0 @@
1
- import '../../polyfills.js';
2
- import { describe, expect, it, vi } from 'vitest';
3
- import * as core from '../../core.js';
4
- import { CancellationToken, sourcesToAbortSignal } from '../token.js';
5
- describe('Cancellation Coverage Extra', () => {
6
- it('should hit dev mode branch (true)', () => {
7
- vi.spyOn(core, 'isDevMode').mockReturnValue(true);
8
- const token = new CancellationToken();
9
- expect(token.isSet).toBe(false);
10
- });
11
- it('should hit dev mode branch (false)', () => {
12
- vi.spyOn(core, 'isDevMode').mockReturnValue(false);
13
- const token = new CancellationToken();
14
- expect(token.isSet).toBe(false);
15
- });
16
- it('should hit throw: true branch in wait', async () => {
17
- const token = new CancellationToken();
18
- token.set('reason');
19
- await expect(token.wait({ throw: true })).rejects.toThrow();
20
- });
21
- it('should hit waitThrow', async () => {
22
- const token = new CancellationToken();
23
- token.set('reason');
24
- await expect(token.waitThrow()).rejects.toThrow();
25
- });
26
- it('should hit signals.length == 1 branch', () => {
27
- const controller = new AbortController();
28
- const signal = sourcesToAbortSignal(controller.signal);
29
- expect(signal).toBe(controller.signal);
30
- });
31
- it('should hit signals.length > 1 branch', () => {
32
- const controller1 = new AbortController();
33
- const controller2 = new AbortController();
34
- const signal = sourcesToAbortSignal([controller1.signal, controller2.signal]);
35
- expect(signal).not.toBe(controller1.signal);
36
- expect(signal).not.toBe(controller2.signal);
37
- });
38
- it('should hit sourcesToAbortSignal error branch', () => {
39
- expect(() => sourcesToAbortSignal([])).toThrow('At least one cancellation source must be provided');
40
- });
41
- it('should hit unsubscribe branch in subscribe', () => {
42
- const token = new CancellationToken();
43
- const next = vi.fn();
44
- const subscription = token.subscribe({ next });
45
- subscription.unsubscribe();
46
- token.set();
47
- expect(next).not.toHaveBeenCalled();
48
- });
49
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,35 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { CancellationSignal, CancellationToken } from '../token.js';
3
- describe('CancellationToken Memory Leak', () => {
4
- it('should not leak when using inherit and disposing', () => {
5
- const parent = new CancellationToken();
6
- for (let i = 0; i < 1000; i++) {
7
- const child = parent.inherit(new CancellationToken());
8
- child.dispose();
9
- }
10
- expect(parent.isSet).toBe(false);
11
- });
12
- it('should follow parent signal', () => {
13
- const parent = new CancellationToken();
14
- const child = new CancellationToken(parent);
15
- expect(child.isSet).toBe(false);
16
- parent.set();
17
- expect(child.isSet).toBe(true);
18
- });
19
- it('should not affect parent when child is set', () => {
20
- const parent = new CancellationToken();
21
- const child = new CancellationToken(parent);
22
- expect(parent.isSet).toBe(false);
23
- child.set();
24
- expect(parent.isSet).toBe(false);
25
- expect(child.isSet).toBe(true);
26
- });
27
- it('should clean up when disposed', () => {
28
- const parent = new CancellationToken();
29
- const signal = CancellationSignal.from(parent);
30
- expect(signal.isSet).toBe(false);
31
- signal.dispose();
32
- expect(signal.isSet).toBe(true);
33
- expect(parent.isSet).toBe(false);
34
- });
35
- });
@@ -1 +0,0 @@
1
- import '../../polyfills.js';
@@ -1,136 +0,0 @@
1
- import '../../polyfills.js';
2
- import { firstValueFrom, from } from 'rxjs';
3
- import { describe, expect, it, vi } from 'vitest';
4
- import { CancellationSignal, CancellationToken } from '../token.js';
5
- describe('CancellationToken', () => {
6
- it('should be unset by default', () => {
7
- const token = new CancellationToken();
8
- expect(token.isSet).toBe(false);
9
- expect(token.isUnset).toBe(true);
10
- });
11
- it('should be set when set() is called', () => {
12
- const token = new CancellationToken();
13
- token.set('reason');
14
- expect(token.isSet).toBe(true);
15
- expect(token.isUnset).toBe(false);
16
- expect(token.reason).toBeInstanceOf(Error);
17
- expect(token.reason.message).toBe('Operation cancelled');
18
- expect(token.reason.cause).toBe('reason');
19
- });
20
- it('should fork a new token', () => {
21
- const parent = new CancellationToken();
22
- const child = parent.fork();
23
- expect(child).toBeInstanceOf(CancellationToken);
24
- expect(child.isSet).toBe(false);
25
- parent.set();
26
- expect(child.isSet).toBe(true);
27
- });
28
- it('should support multiple parents', () => {
29
- const parent1 = new CancellationToken();
30
- const parent2 = new CancellationToken();
31
- const child = new CancellationToken([parent1, parent2]);
32
- expect(child.isSet).toBe(false);
33
- parent2.set();
34
- expect(child.isSet).toBe(true);
35
- });
36
- it('should support single parent', () => {
37
- const parent = new CancellationToken();
38
- const child = new CancellationToken(parent);
39
- expect(child.isSet).toBe(false);
40
- parent.set();
41
- expect(child.isSet).toBe(true);
42
- });
43
- it('should support AbortController as a source', () => {
44
- const controller = new AbortController();
45
- const signal = CancellationSignal.from(controller);
46
- expect(signal.isSet).toBe(false);
47
- controller.abort();
48
- expect(signal.isSet).toBe(true);
49
- });
50
- it('should support AbortSignal as a source', () => {
51
- const controller = new AbortController();
52
- const signal = CancellationSignal.from(controller.signal);
53
- expect(signal.isSet).toBe(false);
54
- controller.abort();
55
- expect(signal.isSet).toBe(true);
56
- });
57
- it('should wait for cancellation (resolve)', async () => {
58
- const token = new CancellationToken();
59
- setTimeout(() => token.set(), 10);
60
- await token.wait();
61
- expect(token.isSet).toBe(true);
62
- });
63
- it('should wait and throw (waitThrow)', async () => {
64
- const token = new CancellationToken();
65
- setTimeout(() => token.set('foo'), 10);
66
- await expect(token.waitThrow()).rejects.toThrow('Operation cancelled');
67
- });
68
- it('should resolve immediately if already set', async () => {
69
- const token = new CancellationToken();
70
- token.set();
71
- await token.wait();
72
- expect(token.isSet).toBe(true);
73
- });
74
- it('should throw immediately if already set with waitThrow', async () => {
75
- const token = new CancellationToken();
76
- token.set();
77
- await expect(token.waitThrow()).rejects.toThrow();
78
- });
79
- it('should throw immediately if already set', async () => {
80
- const token = new CancellationToken();
81
- token.set();
82
- expect(() => token.throwIfSet()).toThrow();
83
- });
84
- it('should not throw if not set', () => {
85
- const token = new CancellationToken();
86
- expect(() => token.throwIfSet()).not.toThrow();
87
- });
88
- it('should support timeouts', async () => {
89
- const token = new CancellationToken();
90
- const timedSignal = token.withTimeout(10);
91
- expect(timedSignal.isSet).toBe(false);
92
- await timedSignal.wait();
93
- expect(timedSignal.isSet).toBe(true);
94
- expect(token.isSet).toBe(false);
95
- });
96
- it('should be observable', async () => {
97
- const token = new CancellationToken();
98
- const promise = firstValueFrom(from(token));
99
- token.set();
100
- await promise;
101
- });
102
- it('should support subscribe', () => {
103
- const token = new CancellationToken();
104
- const next = vi.fn();
105
- const complete = vi.fn();
106
- const subscription = token.subscribe({ next, complete });
107
- token.set();
108
- expect(next).toHaveBeenCalled();
109
- expect(complete).toHaveBeenCalled();
110
- subscription.unsubscribe();
111
- });
112
- it('should support Symbol.observable', () => {
113
- const token = new CancellationToken();
114
- const result = token[Symbol.observable]();
115
- expect(result).toBe(token);
116
- });
117
- it('should return self as signal', () => {
118
- const token = new CancellationToken();
119
- expect(token.signal).toBe(token);
120
- });
121
- it('should handle subscribe when already set', () => {
122
- const token = new CancellationToken();
123
- token.set();
124
- const next = vi.fn();
125
- token.subscribe({ next });
126
- expect(next).toHaveBeenCalled();
127
- });
128
- it('should support unsubscribe', () => {
129
- const token = new CancellationToken();
130
- const next = vi.fn();
131
- const subscription = token.subscribe({ next });
132
- subscription.unsubscribe();
133
- token.set();
134
- expect(next).not.toHaveBeenCalled();
135
- });
136
- });
@@ -1 +0,0 @@
1
- export {};