synstate 0.1.1 → 1.0.0

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 (309) hide show
  1. package/README.md +317 -298
  2. package/dist/core/class/child-observable-class.d.mts.map +1 -1
  3. package/dist/core/class/child-observable-class.mjs +43 -10
  4. package/dist/core/class/child-observable-class.mjs.map +1 -1
  5. package/dist/core/class/observable-base-class.d.mts +4 -4
  6. package/dist/core/class/observable-base-class.d.mts.map +1 -1
  7. package/dist/core/class/observable-base-class.mjs +8 -8
  8. package/dist/core/class/observable-base-class.mjs.map +1 -1
  9. package/dist/core/class/root-observable-class.d.mts +1 -1
  10. package/dist/core/class/root-observable-class.d.mts.map +1 -1
  11. package/dist/core/class/root-observable-class.mjs +9 -9
  12. package/dist/core/class/root-observable-class.mjs.map +1 -1
  13. package/dist/core/combine/combine.d.mts +7 -7
  14. package/dist/core/combine/combine.mjs +13 -14
  15. package/dist/core/combine/combine.mjs.map +1 -1
  16. package/dist/core/combine/merge.d.mts +6 -6
  17. package/dist/core/combine/merge.mjs +9 -9
  18. package/dist/core/combine/merge.mjs.map +1 -1
  19. package/dist/core/combine/zip.d.mts +20 -19
  20. package/dist/core/combine/zip.d.mts.map +1 -1
  21. package/dist/core/combine/zip.mjs +22 -21
  22. package/dist/core/combine/zip.mjs.map +1 -1
  23. package/dist/core/create/{interval.d.mts → counter.d.mts} +14 -12
  24. package/dist/core/create/counter.d.mts.map +1 -0
  25. package/dist/core/create/{interval.mjs → counter.mjs} +21 -23
  26. package/dist/core/create/counter.mjs.map +1 -0
  27. package/dist/core/create/from-abortable-promise.d.mts +29 -0
  28. package/dist/core/create/from-abortable-promise.d.mts.map +1 -0
  29. package/dist/core/create/from-abortable-promise.mjs +70 -0
  30. package/dist/core/create/from-abortable-promise.mjs.map +1 -0
  31. package/dist/core/create/from-promise.d.mts +9 -6
  32. package/dist/core/create/from-promise.d.mts.map +1 -1
  33. package/dist/core/create/from-promise.mjs +8 -5
  34. package/dist/core/create/from-promise.mjs.map +1 -1
  35. package/dist/core/create/from-subscribable.d.mts +4 -4
  36. package/dist/core/create/from-subscribable.mjs +4 -4
  37. package/dist/core/create/index.d.mts +3 -3
  38. package/dist/core/create/index.d.mts.map +1 -1
  39. package/dist/core/create/index.mjs +4 -4
  40. package/dist/core/create/just.d.mts +32 -0
  41. package/dist/core/create/just.d.mts.map +1 -0
  42. package/dist/core/create/just.mjs +44 -0
  43. package/dist/core/create/just.mjs.map +1 -0
  44. package/dist/core/create/source.d.mts +7 -12
  45. package/dist/core/create/source.d.mts.map +1 -1
  46. package/dist/core/create/source.mjs +1 -6
  47. package/dist/core/create/source.mjs.map +1 -1
  48. package/dist/core/create/timer.d.mts +6 -4
  49. package/dist/core/create/timer.d.mts.map +1 -1
  50. package/dist/core/create/timer.mjs +6 -7
  51. package/dist/core/create/timer.mjs.map +1 -1
  52. package/dist/core/index.d.mts +1 -1
  53. package/dist/core/index.d.mts.map +1 -1
  54. package/dist/core/index.mjs +21 -14
  55. package/dist/core/index.mjs.map +1 -1
  56. package/dist/core/operators/audit.d.mts +97 -0
  57. package/dist/core/operators/audit.d.mts.map +1 -0
  58. package/dist/core/operators/audit.mjs +144 -0
  59. package/dist/core/operators/audit.mjs.map +1 -0
  60. package/dist/core/operators/debounce.d.mts +88 -0
  61. package/dist/core/operators/debounce.d.mts.map +1 -0
  62. package/dist/core/operators/debounce.mjs +130 -0
  63. package/dist/core/operators/debounce.mjs.map +1 -0
  64. package/dist/core/operators/filter.d.mts +5 -5
  65. package/dist/core/operators/filter.mjs +3 -3
  66. package/dist/core/operators/filter.mjs.map +1 -1
  67. package/dist/core/operators/index.d.mts +4 -4
  68. package/dist/core/operators/index.d.mts.map +1 -1
  69. package/dist/core/operators/index.mjs +6 -6
  70. package/dist/core/operators/map.d.mts +41 -0
  71. package/dist/core/operators/map.d.mts.map +1 -0
  72. package/dist/core/operators/map.mjs +71 -0
  73. package/dist/core/operators/map.mjs.map +1 -0
  74. package/dist/core/operators/merge-map.d.mts +57 -30
  75. package/dist/core/operators/merge-map.d.mts.map +1 -1
  76. package/dist/core/operators/merge-map.mjs +59 -32
  77. package/dist/core/operators/merge-map.mjs.map +1 -1
  78. package/dist/core/operators/pairwise.d.mts +6 -6
  79. package/dist/core/operators/pairwise.mjs +9 -9
  80. package/dist/core/operators/pairwise.mjs.map +1 -1
  81. package/dist/core/operators/scan.d.mts +6 -6
  82. package/dist/core/operators/scan.mjs +9 -9
  83. package/dist/core/operators/scan.mjs.map +1 -1
  84. package/dist/core/operators/skip-if-no-change.d.mts +21 -9
  85. package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
  86. package/dist/core/operators/skip-if-no-change.mjs +25 -13
  87. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  88. package/dist/core/operators/skip-until.d.mts +5 -5
  89. package/dist/core/operators/skip-until.mjs +8 -8
  90. package/dist/core/operators/skip-until.mjs.map +1 -1
  91. package/dist/core/operators/skip-while.d.mts +18 -9
  92. package/dist/core/operators/skip-while.d.mts.map +1 -1
  93. package/dist/core/operators/skip-while.mjs +28 -16
  94. package/dist/core/operators/skip-while.mjs.map +1 -1
  95. package/dist/core/operators/switch-map.d.mts +57 -26
  96. package/dist/core/operators/switch-map.d.mts.map +1 -1
  97. package/dist/core/operators/switch-map.mjs +59 -28
  98. package/dist/core/operators/switch-map.mjs.map +1 -1
  99. package/dist/core/operators/take-until.d.mts +5 -5
  100. package/dist/core/operators/take-until.mjs +8 -8
  101. package/dist/core/operators/take-until.mjs.map +1 -1
  102. package/dist/core/operators/take-while.d.mts +15 -8
  103. package/dist/core/operators/take-while.d.mts.map +1 -1
  104. package/dist/core/operators/take-while.mjs +19 -13
  105. package/dist/core/operators/take-while.mjs.map +1 -1
  106. package/dist/core/operators/throttle.d.mts +81 -0
  107. package/dist/core/operators/throttle.d.mts.map +1 -0
  108. package/dist/core/operators/throttle.mjs +126 -0
  109. package/dist/core/operators/throttle.mjs.map +1 -0
  110. package/dist/core/operators/with-buffered-from.d.mts +13 -9
  111. package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
  112. package/dist/core/operators/with-buffered-from.mjs +17 -13
  113. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  114. package/dist/core/operators/with-current-value-from.d.mts +14 -9
  115. package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
  116. package/dist/core/operators/with-current-value-from.mjs +18 -13
  117. package/dist/core/operators/with-current-value-from.mjs.map +1 -1
  118. package/dist/core/operators/with-initial-value.d.mts +5 -5
  119. package/dist/core/operators/with-initial-value.mjs +8 -8
  120. package/dist/core/operators/with-initial-value.mjs.map +1 -1
  121. package/dist/core/predefined/index.d.mts +2 -0
  122. package/dist/core/predefined/index.d.mts.map +1 -0
  123. package/dist/core/predefined/index.mjs +12 -0
  124. package/dist/core/predefined/index.mjs.map +1 -0
  125. package/dist/core/predefined/operators/attach-index.d.mts +57 -0
  126. package/dist/core/predefined/operators/attach-index.d.mts.map +1 -0
  127. package/dist/core/predefined/operators/attach-index.mjs +62 -0
  128. package/dist/core/predefined/operators/attach-index.mjs.map +1 -0
  129. package/dist/core/predefined/operators/index.d.mts +12 -0
  130. package/dist/core/predefined/operators/index.d.mts.map +1 -0
  131. package/dist/core/predefined/operators/index.mjs +12 -0
  132. package/dist/core/predefined/operators/index.mjs.map +1 -0
  133. package/dist/core/predefined/operators/map-optional.d.mts +51 -0
  134. package/dist/core/predefined/operators/map-optional.d.mts.map +1 -0
  135. package/dist/core/predefined/operators/map-optional.mjs +55 -0
  136. package/dist/core/predefined/operators/map-optional.mjs.map +1 -0
  137. package/dist/core/predefined/operators/map-result-err.d.mts +51 -0
  138. package/dist/core/predefined/operators/map-result-err.d.mts.map +1 -0
  139. package/dist/core/predefined/operators/map-result-err.mjs +55 -0
  140. package/dist/core/predefined/operators/map-result-err.mjs.map +1 -0
  141. package/dist/core/predefined/operators/map-result-ok.d.mts +51 -0
  142. package/dist/core/predefined/operators/map-result-ok.d.mts.map +1 -0
  143. package/dist/core/predefined/operators/map-result-ok.mjs +55 -0
  144. package/dist/core/predefined/operators/map-result-ok.mjs.map +1 -0
  145. package/dist/core/predefined/operators/map-to.d.mts +43 -0
  146. package/dist/core/predefined/operators/map-to.d.mts.map +1 -0
  147. package/dist/core/predefined/operators/map-to.mjs +48 -0
  148. package/dist/core/predefined/operators/map-to.mjs.map +1 -0
  149. package/dist/core/predefined/operators/pluck.d.mts +47 -0
  150. package/dist/core/predefined/operators/pluck.d.mts.map +1 -0
  151. package/dist/core/predefined/operators/pluck.mjs +52 -0
  152. package/dist/core/predefined/operators/pluck.mjs.map +1 -0
  153. package/dist/core/predefined/operators/skip.d.mts +50 -0
  154. package/dist/core/predefined/operators/skip.d.mts.map +1 -0
  155. package/dist/core/predefined/operators/skip.mjs +56 -0
  156. package/dist/core/predefined/operators/skip.mjs.map +1 -0
  157. package/dist/core/predefined/operators/take.d.mts +44 -0
  158. package/dist/core/predefined/operators/take.d.mts.map +1 -0
  159. package/dist/core/predefined/operators/take.mjs +49 -0
  160. package/dist/core/predefined/operators/take.mjs.map +1 -0
  161. package/dist/core/predefined/operators/unwrap-optional.d.mts +44 -0
  162. package/dist/core/predefined/operators/unwrap-optional.d.mts.map +1 -0
  163. package/dist/core/predefined/operators/unwrap-optional.mjs +50 -0
  164. package/dist/core/predefined/operators/unwrap-optional.mjs.map +1 -0
  165. package/dist/core/predefined/operators/unwrap-result-err.d.mts +44 -0
  166. package/dist/core/predefined/operators/unwrap-result-err.d.mts.map +1 -0
  167. package/dist/core/predefined/operators/unwrap-result-err.mjs +48 -0
  168. package/dist/core/predefined/operators/unwrap-result-err.mjs.map +1 -0
  169. package/dist/core/predefined/operators/unwrap-result-ok.d.mts +44 -0
  170. package/dist/core/predefined/operators/unwrap-result-ok.d.mts.map +1 -0
  171. package/dist/core/predefined/operators/unwrap-result-ok.mjs +50 -0
  172. package/dist/core/predefined/operators/unwrap-result-ok.mjs.map +1 -0
  173. package/dist/core/types/id.d.mts +1 -1
  174. package/dist/core/types/id.d.mts.map +1 -1
  175. package/dist/core/types/index.d.mts +1 -0
  176. package/dist/core/types/index.d.mts.map +1 -1
  177. package/dist/core/types/observable-family.d.mts +8 -14
  178. package/dist/core/types/observable-family.d.mts.map +1 -1
  179. package/dist/core/types/observable.d.mts +3 -3
  180. package/dist/core/types/observable.d.mts.map +1 -1
  181. package/dist/core/types/timer.d.mts +2 -0
  182. package/dist/core/types/timer.d.mts.map +1 -0
  183. package/dist/core/types/timer.mjs +2 -0
  184. package/dist/core/types/timer.mjs.map +1 -0
  185. package/dist/core/utils/id-maker.d.mts +2 -2
  186. package/dist/core/utils/id-maker.d.mts.map +1 -1
  187. package/dist/core/utils/id-maker.mjs +3 -3
  188. package/dist/core/utils/id-maker.mjs.map +1 -1
  189. package/dist/core/utils/index.mjs +1 -1
  190. package/dist/entry-point.mjs +24 -15
  191. package/dist/entry-point.mjs.map +1 -1
  192. package/dist/globals.d.mts +0 -3
  193. package/dist/index.mjs +24 -15
  194. package/dist/index.mjs.map +1 -1
  195. package/dist/utils/collect-to-array.d.mts +3 -0
  196. package/dist/utils/collect-to-array.d.mts.map +1 -0
  197. package/dist/utils/collect-to-array.mjs +11 -0
  198. package/dist/utils/collect-to-array.mjs.map +1 -0
  199. package/dist/utils/create-boolean-state.d.mts +40 -0
  200. package/dist/utils/create-boolean-state.d.mts.map +1 -0
  201. package/dist/utils/create-boolean-state.mjs +53 -0
  202. package/dist/utils/create-boolean-state.mjs.map +1 -0
  203. package/dist/utils/create-event-emitter.d.mts +4 -4
  204. package/dist/utils/create-event-emitter.mjs +4 -4
  205. package/dist/utils/create-reducer.d.mts +10 -7
  206. package/dist/utils/create-reducer.d.mts.map +1 -1
  207. package/dist/utils/create-reducer.mjs +7 -7
  208. package/dist/utils/create-reducer.mjs.map +1 -1
  209. package/dist/utils/create-state.d.mts +8 -48
  210. package/dist/utils/create-state.d.mts.map +1 -1
  211. package/dist/utils/create-state.mjs +10 -60
  212. package/dist/utils/create-state.mjs.map +1 -1
  213. package/dist/utils/index.d.mts +2 -0
  214. package/dist/utils/index.d.mts.map +1 -1
  215. package/dist/utils/index.mjs +3 -1
  216. package/dist/utils/index.mjs.map +1 -1
  217. package/package.json +17 -11
  218. package/src/core/class/child-observable-class.mts +65 -9
  219. package/src/core/class/circular-dependency-comparison.test.mts +142 -0
  220. package/src/core/class/circular-dependency.test.mts +251 -0
  221. package/src/core/class/observable-base-class.mts +9 -9
  222. package/src/core/class/root-observable-class.mts +14 -10
  223. package/src/core/combine/combine.mts +15 -15
  224. package/src/core/combine/merge.mts +13 -14
  225. package/src/core/combine/zip.mts +26 -25
  226. package/src/core/create/{interval.mts → counter.mts} +32 -30
  227. package/src/core/create/from-abortable-promise.mts +83 -0
  228. package/src/core/create/from-promise.mts +10 -7
  229. package/src/core/create/from-subscribable.mts +4 -4
  230. package/src/core/create/index.mts +3 -3
  231. package/src/core/create/just.mts +43 -0
  232. package/src/core/create/source.mts +10 -14
  233. package/src/core/create/timer.mts +12 -11
  234. package/src/core/index.mts +1 -1
  235. package/src/core/operators/audit.mts +172 -0
  236. package/src/core/operators/debounce.mts +154 -0
  237. package/src/core/operators/filter.mts +9 -9
  238. package/src/core/operators/index.mts +4 -4
  239. package/src/core/operators/map.mts +124 -0
  240. package/src/core/operators/merge-map.mts +60 -33
  241. package/src/core/operators/pairwise.mts +10 -10
  242. package/src/core/operators/scan.mts +10 -10
  243. package/src/core/operators/skip-if-no-change.mts +26 -14
  244. package/src/core/operators/skip-until.mts +9 -9
  245. package/src/core/operators/skip-while.mts +30 -28
  246. package/src/core/operators/switch-map.mts +60 -29
  247. package/src/core/operators/take-until.mts +9 -9
  248. package/src/core/operators/take-while.mts +21 -19
  249. package/src/core/operators/{throttle-time.mts → throttle.mts} +58 -38
  250. package/src/core/operators/with-buffered-from.mts +18 -14
  251. package/src/core/operators/with-current-value-from.mts +19 -14
  252. package/src/core/operators/with-initial-value.mts +9 -9
  253. package/src/core/predefined/index.mts +1 -0
  254. package/src/core/predefined/operators/attach-index.mts +62 -0
  255. package/src/core/predefined/operators/index.mts +11 -0
  256. package/src/core/predefined/operators/map-optional.mts +55 -0
  257. package/src/core/predefined/operators/map-result-err.mts +55 -0
  258. package/src/core/predefined/operators/map-result-ok.mts +55 -0
  259. package/src/core/predefined/operators/map-to.mts +45 -0
  260. package/src/core/predefined/operators/pluck.mts +51 -0
  261. package/src/core/predefined/operators/skip.mts +57 -0
  262. package/src/core/predefined/operators/take.mts +47 -0
  263. package/src/core/predefined/operators/unwrap-optional.mts +49 -0
  264. package/src/core/predefined/operators/unwrap-result-err.mts +48 -0
  265. package/src/core/predefined/operators/unwrap-result-ok.mts +49 -0
  266. package/src/core/types/id.mts +1 -1
  267. package/src/core/types/index.mts +1 -0
  268. package/src/core/types/observable-family.mts +8 -24
  269. package/src/core/types/observable.mts +3 -3
  270. package/src/core/types/timer.mts +2 -0
  271. package/src/core/utils/id-maker.mts +4 -4
  272. package/src/globals.d.mts +0 -3
  273. package/src/utils/collect-to-array.mts +17 -0
  274. package/src/utils/create-boolean-state.mts +68 -0
  275. package/src/utils/create-event-emitter.mts +4 -4
  276. package/src/utils/create-reducer.mts +11 -8
  277. package/src/utils/create-state.mts +10 -75
  278. package/src/utils/index.mts +2 -0
  279. package/dist/core/create/from-array.d.mts +0 -39
  280. package/dist/core/create/from-array.d.mts.map +0 -1
  281. package/dist/core/create/from-array.mjs +0 -65
  282. package/dist/core/create/from-array.mjs.map +0 -1
  283. package/dist/core/create/interval.d.mts.map +0 -1
  284. package/dist/core/create/interval.mjs.map +0 -1
  285. package/dist/core/create/of.d.mts +0 -39
  286. package/dist/core/create/of.d.mts.map +0 -1
  287. package/dist/core/create/of.mjs +0 -63
  288. package/dist/core/create/of.mjs.map +0 -1
  289. package/dist/core/operators/audit-time.d.mts +0 -62
  290. package/dist/core/operators/audit-time.d.mts.map +0 -1
  291. package/dist/core/operators/audit-time.mjs +0 -109
  292. package/dist/core/operators/audit-time.mjs.map +0 -1
  293. package/dist/core/operators/debounce-time.d.mts +0 -51
  294. package/dist/core/operators/debounce-time.d.mts.map +0 -1
  295. package/dist/core/operators/debounce-time.mjs +0 -93
  296. package/dist/core/operators/debounce-time.mjs.map +0 -1
  297. package/dist/core/operators/map-with-index.d.mts +0 -54
  298. package/dist/core/operators/map-with-index.d.mts.map +0 -1
  299. package/dist/core/operators/map-with-index.mjs +0 -88
  300. package/dist/core/operators/map-with-index.mjs.map +0 -1
  301. package/dist/core/operators/throttle-time.d.mts +0 -62
  302. package/dist/core/operators/throttle-time.d.mts.map +0 -1
  303. package/dist/core/operators/throttle-time.mjs +0 -107
  304. package/dist/core/operators/throttle-time.mjs.map +0 -1
  305. package/src/core/create/from-array.mts +0 -76
  306. package/src/core/create/of.mts +0 -73
  307. package/src/core/operators/audit-time.mts +0 -136
  308. package/src/core/operators/debounce-time.mts +0 -116
  309. package/src/core/operators/map-with-index.mts +0 -183
@@ -1,12 +1,12 @@
1
1
  import { asSafeUint, Optional, SafeUint } from 'ts-data-forge';
2
2
  import { RootObservableClass } from '../class/index.mjs';
3
- import { type IntervalObservable } from '../types/index.mjs';
3
+ import { type CounterObservable, type TimerId } from '../types/index.mjs';
4
4
 
5
5
  /**
6
6
  * Creates an observable that emits incremental numbers at a specified interval.
7
7
  * Starts with 0 immediately after subscription, then emits 1, 2, 3, ... every interval.
8
8
  *
9
- * @param milliSeconds - The interval duration in milliseconds
9
+ * @param intervalMilliSeconds - The interval duration in milliseconds
10
10
  * @param startManually - If true, waits for manual start (default: false)
11
11
  * @returns An observable that emits sequential numbers
12
12
  *
@@ -18,16 +18,16 @@ import { type IntervalObservable } from '../types/index.mjs';
18
18
  * // tick$ 0 1 2 3 4 5 ...
19
19
  * //
20
20
  * // Explanation:
21
- * // - interval emits incrementing numbers at specified intervals
21
+ * // - counter emits incrementing numbers at specified intervals
22
22
  * // - Starts at 0 and continues indefinitely
23
23
  * // - Useful for periodic tasks or animations
24
24
  *
25
- * const tick$ = interval(100);
25
+ * const tick$ = counter(100);
26
26
  *
27
- * const mut_history: number[] = [];
27
+ * const valueHistory: number[] = [];
28
28
  *
29
29
  * const subscription = tick$.subscribe((count) => {
30
- * mut_history.push(count);
30
+ * valueHistory.push(count);
31
31
  * });
32
32
  *
33
33
  * await new Promise((resolve) => {
@@ -36,35 +36,40 @@ import { type IntervalObservable } from '../types/index.mjs';
36
36
  *
37
37
  * subscription.unsubscribe();
38
38
  *
39
- * assert.isTrue(Arr.isArrayAtLeastLength(mut_history, 3));
39
+ * assert.isTrue(Arr.isArrayAtLeastLength(valueHistory, 3));
40
40
  *
41
- * assert.deepStrictEqual(mut_history[0], 0);
41
+ * assert.deepStrictEqual(valueHistory[0], 0);
42
42
  *
43
- * assert.deepStrictEqual(mut_history[1], 1);
43
+ * assert.deepStrictEqual(valueHistory[1], 1);
44
44
  *
45
- * assert.deepStrictEqual(mut_history[2], 2);
45
+ * assert.deepStrictEqual(valueHistory[2], 2);
46
46
  * ```
47
47
  */
48
- export const interval = (
49
- milliSeconds: number,
50
- startManually?: boolean,
51
- ): IntervalObservable =>
52
- new IntervalObservableClass(milliSeconds, startManually);
53
-
54
- class IntervalObservableClass
48
+ export const counter = (
49
+ intervalMilliSeconds: number,
50
+ options?: Readonly<{
51
+ startManually?: boolean;
52
+ }>,
53
+ ): CounterObservable =>
54
+ new CounterObservableClass(
55
+ intervalMilliSeconds,
56
+ options?.startManually ?? false,
57
+ );
58
+
59
+ class CounterObservableClass
55
60
  extends RootObservableClass<SafeUint>
56
- implements IntervalObservable
61
+ implements CounterObservable
57
62
  {
58
- readonly #milliSeconds: number;
63
+ readonly #intervalMilliSeconds: number;
59
64
  #mut_counter: SafeUint;
60
65
  #mut_timerId0: TimerId | undefined;
61
66
  #mut_timerId: TimerId | undefined;
62
67
  #mut_isStarted: boolean;
63
68
 
64
- constructor(milliSeconds: number, startManually?: boolean) {
69
+ constructor(intervalMilliSeconds: number, startManually: boolean) {
65
70
  super({ initialValue: Optional.none });
66
71
 
67
- this.#milliSeconds = milliSeconds;
72
+ this.#intervalMilliSeconds = intervalMilliSeconds;
68
73
 
69
74
  this.#mut_counter = asSafeUint(0);
70
75
 
@@ -74,27 +79,26 @@ class IntervalObservableClass
74
79
 
75
80
  this.#mut_isStarted = false;
76
81
 
77
- if (startManually !== true) {
82
+ if (!startManually) {
78
83
  this.start();
79
84
  }
80
85
  }
81
86
 
82
- start(): this {
87
+ start(): void {
83
88
  if (this.#mut_isStarted) {
84
89
  console.warn('cannot start twice');
85
90
 
86
- return this;
91
+ return;
87
92
  }
88
93
 
89
94
  this.#mut_isStarted = true;
90
95
 
91
96
  if (this.isCompleted) {
92
- console.warn('cannot restart stopped IntervalObservable');
97
+ console.warn('cannot restart stopped CounterObservable');
93
98
 
94
- return this;
99
+ return;
95
100
  }
96
101
 
97
- // emit zero
98
102
  this.#mut_timerId0 = setTimeout(() => {
99
103
  this.startUpdate(this.#mut_counter);
100
104
  }, 0);
@@ -103,9 +107,7 @@ class IntervalObservableClass
103
107
  this.#mut_counter = SafeUint.add(1, this.#mut_counter);
104
108
 
105
109
  this.startUpdate(this.#mut_counter);
106
- }, this.#milliSeconds);
107
-
108
- return this;
110
+ }, this.#intervalMilliSeconds);
109
111
  }
110
112
 
111
113
  #resetTimer(): void {
@@ -0,0 +1,83 @@
1
+ import { Optional, Result } from 'ts-data-forge';
2
+ import { RootObservableClass } from '../class/index.mjs';
3
+ import { type FromPromiseObservable } from '../types/index.mjs';
4
+
5
+ /**
6
+ * Creates an observable from a Promise factory that receives an `AbortSignal`.
7
+ * When the observable is completed (e.g., by `switchMap` switching to a new
8
+ * inner observable), the `AbortController` is automatically aborted, cancelling
9
+ * the in-flight request.
10
+ *
11
+ * Emits `Result.ok(value)` when the promise resolves, or `Result.err(error)`
12
+ * when it rejects. Rejections caused by abort (`AbortError`) are silently
13
+ * ignored and do not emit.
14
+ *
15
+ * @template A - The type of the resolved value
16
+ * @template E - The type of the error (excluding AbortError)
17
+ * @param factory - A function that receives an `AbortSignal` and returns a Promise
18
+ * @returns An observable that emits the promise result
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const results$ = query.pipe(
23
+ * switchMap((q) =>
24
+ * fromAbortablePromise((signal) =>
25
+ * fetch(`/api/search?q=${q}`, { signal }).then((r) => r.json()),
26
+ * ),
27
+ * ),
28
+ * );
29
+ * ```
30
+ */
31
+ export const fromAbortablePromise = <A, E = unknown>(
32
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
33
+ factory: (signal: AbortSignal) => Promise<A>,
34
+ ): FromPromiseObservable<A, E> =>
35
+ new FromAbortablePromiseObservableClass(factory);
36
+
37
+ class FromAbortablePromiseObservableClass<A, E = unknown>
38
+ extends RootObservableClass<Result<A, E>>
39
+ implements FromPromiseObservable<A, E>
40
+ {
41
+ readonly #abortController: AbortController;
42
+
43
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
44
+ constructor(factory: (signal: AbortSignal) => Promise<A>) {
45
+ super({ initialValue: Optional.none });
46
+
47
+ this.#abortController = new AbortController();
48
+
49
+ const promise = factory(this.#abortController.signal);
50
+
51
+ promise
52
+ .then((value) => {
53
+ if (this.isCompleted) return;
54
+
55
+ this.startUpdate(Result.ok(value));
56
+ })
57
+ .catch((error: unknown) => {
58
+ if (this.isCompleted) return;
59
+
60
+ // Silently ignore AbortError — it means the observable was
61
+ // intentionally completed (e.g., by switchMap).
62
+ if (error instanceof DOMException && error.name === 'AbortError') {
63
+ return;
64
+ }
65
+
66
+ this.startUpdate(
67
+ Result.err(
68
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
69
+ error as E,
70
+ ),
71
+ );
72
+ })
73
+ .finally(() => {
74
+ this.complete();
75
+ });
76
+ }
77
+
78
+ override complete(): void {
79
+ this.#abortController.abort();
80
+
81
+ super.complete();
82
+ }
83
+ }
@@ -16,7 +16,7 @@ import { type FromPromiseObservable } from '../types/index.mjs';
16
16
  * // Timeline:
17
17
  * //
18
18
  * // promise [pending...] -> resolved/rejected
19
- * // data$ Ok(value) or Err(error)
19
+ * // data$ Ok(value) or Err(error)
20
20
  * //
21
21
  * // Explanation:
22
22
  * // - fromPromise converts a Promise into an observable
@@ -24,17 +24,20 @@ import { type FromPromiseObservable } from '../types/index.mjs';
24
24
  * // - Completes after emitting the result
25
25
  * // - Useful for integrating async operations into reactive flows
26
26
  *
27
- * const fetchData = async (): Promise<{ value: number }> => ({ value: 42 });
27
+ * const fetchData = async (): Promise<Readonly<{ value: number }>> =>
28
+ * ({
29
+ * value: 42,
30
+ * }) as const;
28
31
  *
29
32
  * const data$ = fromPromise(fetchData());
30
33
  *
31
- * const mut_history: { value: number }[] = [];
34
+ * const valueHistory: Readonly<{ value: number }>[] = [];
32
35
  *
33
36
  * await new Promise<void>((resolve) => {
34
37
  * data$.subscribe(
35
38
  * (result) => {
36
39
  * if (Result.isOk(result)) {
37
- * mut_history.push(result.value);
40
+ * valueHistory.push(result.value);
38
41
  * }
39
42
  * },
40
43
  * () => {
@@ -43,18 +46,18 @@ import { type FromPromiseObservable } from '../types/index.mjs';
43
46
  * );
44
47
  * });
45
48
  *
46
- * assert.deepStrictEqual(mut_history, [{ value: 42 }]);
49
+ * assert.deepStrictEqual(valueHistory, [{ value: 42 }]);
47
50
  * ```
48
51
  */
49
52
  export const fromPromise = <A, E = unknown>(
50
- promise: Readonly<Promise<A>>,
53
+ promise: Promise<A>,
51
54
  ): FromPromiseObservable<A, E> => new FromPromiseObservableClass(promise);
52
55
 
53
56
  class FromPromiseObservableClass<A, E = unknown>
54
57
  extends RootObservableClass<Result<A, E>>
55
58
  implements FromPromiseObservable<A, E>
56
59
  {
57
- constructor(promise: Readonly<Promise<A>>) {
60
+ constructor(promise: Promise<A>) {
58
61
  super({ initialValue: Optional.none });
59
62
 
60
63
  promise
@@ -41,17 +41,17 @@ import {
41
41
  *
42
42
  * return { unsubscribe: () => {} };
43
43
  * },
44
- * };
44
+ * } as const;
45
45
  *
46
46
  * const observable$ = fromSubscribable<number>(customSubscribable);
47
47
  *
48
- * const mut_history: number[] = [];
48
+ * const valueHistory: number[] = [];
49
49
  *
50
50
  * await new Promise<void>((resolve) => {
51
51
  * observable$.subscribe(
52
52
  * (result) => {
53
53
  * if (Result.isOk(result)) {
54
- * mut_history.push(result.value);
54
+ * valueHistory.push(result.value);
55
55
  * }
56
56
  * },
57
57
  * () => {
@@ -60,7 +60,7 @@ import {
60
60
  * );
61
61
  * });
62
62
  *
63
- * assert.deepStrictEqual(mut_history, [1, 2, 3]);
63
+ * assert.deepStrictEqual(valueHistory, [1, 2, 3]);
64
64
  * ```
65
65
  */
66
66
  export const fromSubscribable = <A, E = unknown>(
@@ -1,7 +1,7 @@
1
- export * from './from-array.mjs';
1
+ export * from './counter.mjs';
2
+ export * from './from-abortable-promise.mjs';
2
3
  export * from './from-promise.mjs';
3
4
  export * from './from-subscribable.mjs';
4
- export * from './interval.mjs';
5
- export * from './of.mjs';
5
+ export * from './just.mjs';
6
6
  export * from './source.mjs';
7
7
  export * from './timer.mjs';
@@ -0,0 +1,43 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { RootObservableClass } from '../class/index.mjs';
3
+ import { type InitializedRootObservable } from '../types/index.mjs';
4
+
5
+ /**
6
+ * Creates an Observable that holds a single static value and immediately
7
+ * completes. Useful inside `switchMap` to emit a fallback value when no
8
+ * asynchronous work is needed.
9
+ *
10
+ * @template A - The type of the value
11
+ * @param value - The value to emit
12
+ * @returns An initialized Observable that holds the value and is already completed
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const greeting$ = just('hello');
17
+ *
18
+ * const valueHistory: string[] = [];
19
+ *
20
+ * greeting$.subscribe(
21
+ * (value) => {
22
+ * valueHistory.push(value);
23
+ * },
24
+ * () => {
25
+ * // onComplete — called immediately since just() completes right away
26
+ * },
27
+ * );
28
+ *
29
+ * assert.deepStrictEqual(valueHistory, ['hello']);
30
+ *
31
+ * assert.strictEqual(greeting$.isCompleted, true);
32
+ * ```
33
+ */
34
+ export const just = <const A,>(value: A): InitializedRootObservable<A> => {
35
+ const obs = new RootObservableClass<A>({
36
+ initialValue: Optional.some(value),
37
+ });
38
+
39
+ obs.complete();
40
+
41
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
42
+ return obs as InitializedRootObservable<A>;
43
+ };
@@ -25,39 +25,35 @@ import {
25
25
  *
26
26
  * const count$ = source<number>();
27
27
  *
28
- * const mut_history: number[] = [];
28
+ * const valueHistory: number[] = [];
29
29
  *
30
30
  * count$.subscribe((value) => {
31
- * mut_history.push(value);
31
+ * valueHistory.push(value);
32
32
  * });
33
33
  *
34
34
  * count$.next(1); // logs: 1
35
35
  *
36
- * assert.deepStrictEqual(mut_history, [1]);
36
+ * assert.deepStrictEqual(valueHistory, [1]);
37
37
  *
38
38
  * count$.next(2); // logs: 2
39
39
  *
40
- * assert.deepStrictEqual(mut_history, [1, 2]);
40
+ * assert.deepStrictEqual(valueHistory, [1, 2]);
41
41
  *
42
42
  * count$.next(3); // logs: 3
43
43
  *
44
- * assert.deepStrictEqual(mut_history, [1, 2, 3]);
44
+ * assert.deepStrictEqual(valueHistory, [1, 2, 3]);
45
45
  * ```
46
46
  */
47
- export function source<A>(initialValue: A): InitializedSourceObservable<A>;
47
+ export function source<const A>(
48
+ initialValue: A,
49
+ ): InitializedSourceObservable<A>;
48
50
 
49
- export function source<A>(): SourceObservable<A>;
51
+ export function source<const A>(): SourceObservable<A>;
50
52
 
51
- export function source<A>(...args: readonly A[]): SourceObservable<A> {
53
+ export function source<const A>(...args: readonly A[]): SourceObservable<A> {
52
54
  return new SourceObservableClass<A>(...args);
53
55
  }
54
56
 
55
- /**
56
- * Alias for `source()`. Creates a new Observable source.
57
- * @see source
58
- */
59
- export const subject = source; // alias
60
-
61
57
  class SourceObservableClass<A>
62
58
  extends RootObservableClass<A>
63
59
  implements SourceObservable<A>
@@ -1,6 +1,6 @@
1
1
  import { Optional } from 'ts-data-forge';
2
2
  import { RootObservableClass } from '../class/index.mjs';
3
- import { type TimerObservable } from '../types/index.mjs';
3
+ import { type TimerId, type TimerObservable } from '../types/index.mjs';
4
4
 
5
5
  /**
6
6
  * Creates an observable that emits 0 after a specified delay and then completes.
@@ -22,12 +22,12 @@ import { type TimerObservable } from '../types/index.mjs';
22
22
  *
23
23
  * const delayed$ = timer(100);
24
24
  *
25
- * const mut_history: number[] = [];
25
+ * const valueHistory: number[] = [];
26
26
  *
27
27
  * await new Promise<void>((resolve) => {
28
28
  * delayed$.subscribe(
29
29
  * () => {
30
- * mut_history.push(1);
30
+ * valueHistory.push(1);
31
31
  * },
32
32
  * () => {
33
33
  * resolve();
@@ -35,13 +35,16 @@ import { type TimerObservable } from '../types/index.mjs';
35
35
  * );
36
36
  * });
37
37
  *
38
- * assert.deepStrictEqual(mut_history, [1]);
38
+ * assert.deepStrictEqual(valueHistory, [1]);
39
39
  * ```
40
40
  */
41
41
  export const timer = (
42
42
  milliSeconds: number,
43
- startManually: boolean = false,
44
- ): TimerObservable => new TimerObservableClass(milliSeconds, startManually);
43
+ options?: Readonly<{
44
+ startManually?: boolean;
45
+ }>,
46
+ ): TimerObservable =>
47
+ new TimerObservableClass(milliSeconds, options?.startManually ?? false);
45
48
 
46
49
  class TimerObservableClass
47
50
  extends RootObservableClass<0>
@@ -65,11 +68,11 @@ class TimerObservableClass
65
68
  }
66
69
  }
67
70
 
68
- start(): this {
71
+ start(): void {
69
72
  if (this.#mut_isStarted) {
70
73
  console.warn('cannot start twice');
71
74
 
72
- return this;
75
+ return;
73
76
  }
74
77
 
75
78
  this.#mut_isStarted = true;
@@ -77,7 +80,7 @@ class TimerObservableClass
77
80
  if (this.isCompleted) {
78
81
  console.warn('cannot restart stopped TimerObservable');
79
82
 
80
- return this;
83
+ return;
81
84
  }
82
85
 
83
86
  this.#mut_timerId = setTimeout(() => {
@@ -85,8 +88,6 @@ class TimerObservableClass
85
88
 
86
89
  this.complete();
87
90
  }, this.#milliSeconds);
88
-
89
- return this;
90
91
  }
91
92
 
92
93
  #resetTimer(): void {
@@ -2,5 +2,5 @@ export * from './class/index.mjs';
2
2
  export * from './combine/index.mjs';
3
3
  export * from './create/index.mjs';
4
4
  export * from './operators/index.mjs';
5
+ export * from './predefined/index.mjs';
5
6
  export * from './types/index.mjs';
6
- export * from './utils/index.mjs';
@@ -0,0 +1,172 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { AsyncChildObservableClass } from '../class/index.mjs';
3
+ import {
4
+ type AuditOperatorObservable,
5
+ type KeepInitialValueOperator,
6
+ type Observable,
7
+ type TimerId,
8
+ type UpdateToken,
9
+ } from '../types/index.mjs';
10
+
11
+ /**
12
+ * Ignores source values for duration milliseconds, then emits the most recent value from the source Observable, then repeats this process.
13
+ *
14
+ * Unlike `throttle` which emits the first value, `audit` emits the last value.
15
+ *
16
+ * @template A - The type of values from the source
17
+ * @param milliSeconds - The audit time window in milliseconds
18
+ * @returns An operator that audits emissions from the observable
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // Timeline (250ms audit):
23
+ * //
24
+ * // Time(x50ms) 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
25
+ * //
26
+ * // input$ 0 2 3 9 10 11 12 13 14
27
+ * // |- 250ms -> |- 250ms -> |- 250ms -> |- 250ms ->
28
+ * // audited$ 2 3 11 14 (emitted at end of window)
29
+ * //
30
+ * // Explanation:
31
+ * // - audit emits the LAST value received during each time window
32
+ * // - Unlike throttle (which emits the FIRST value), audit emits the LAST
33
+ * // - Useful when you want the most recent value after a burst of events
34
+ *
35
+ * const input$ = source<number>();
36
+ *
37
+ * const audited$ = input$.pipe(audit(250));
38
+ *
39
+ * const valueHistory: number[] = [];
40
+ *
41
+ * audited$.subscribe((value) => {
42
+ * valueHistory.push(value);
43
+ * });
44
+ *
45
+ * const sleep = (ms: number): Promise<void> =>
46
+ * new Promise((resolve) => {
47
+ * setTimeout(resolve, ms);
48
+ * });
49
+ *
50
+ * input$.next(0);
51
+ *
52
+ * await sleep(200);
53
+ *
54
+ * input$.next(2);
55
+ *
56
+ * assert.deepStrictEqual(valueHistory, []);
57
+ *
58
+ * await sleep(100);
59
+ *
60
+ * assert.deepStrictEqual(valueHistory, [2]);
61
+ *
62
+ * input$.next(3);
63
+ *
64
+ * await sleep(300);
65
+ *
66
+ * assert.deepStrictEqual(valueHistory, [2, 3]);
67
+ *
68
+ * await sleep(300);
69
+ *
70
+ * input$.next(9);
71
+ *
72
+ * await sleep(100);
73
+ *
74
+ * input$.next(10);
75
+ *
76
+ * await sleep(100);
77
+ *
78
+ * input$.next(11);
79
+ *
80
+ * assert.deepStrictEqual(valueHistory, [2, 3]);
81
+ *
82
+ * await sleep(100);
83
+ *
84
+ * assert.deepStrictEqual(valueHistory, [2, 3, 11]);
85
+ *
86
+ * input$.next(12);
87
+ *
88
+ * await sleep(100);
89
+ *
90
+ * input$.next(13);
91
+ *
92
+ * assert.deepStrictEqual(valueHistory, [2, 3, 11]);
93
+ *
94
+ * await sleep(100);
95
+ *
96
+ * input$.next(14);
97
+ *
98
+ * assert.deepStrictEqual(valueHistory, [2, 3, 11]);
99
+ *
100
+ * await sleep(100);
101
+ *
102
+ * assert.deepStrictEqual(valueHistory, [2, 3, 11, 14]);
103
+ * ```
104
+ */
105
+ export const audit = <A,>(
106
+ milliSeconds: number,
107
+ ): KeepInitialValueOperator<A, A> =>
108
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
109
+ ((parentObservable) =>
110
+ new AuditObservableClass(
111
+ parentObservable,
112
+ milliSeconds,
113
+ )) as KeepInitialValueOperator<A, A>;
114
+
115
+ class AuditObservableClass<A>
116
+ extends AsyncChildObservableClass<A, readonly [A]>
117
+ implements AuditOperatorObservable<A>
118
+ {
119
+ readonly #milliSeconds: number;
120
+ #mut_timerId: TimerId | undefined;
121
+ #mut_isSkipping: boolean;
122
+
123
+ constructor(parentObservable: Observable<A>, milliSeconds: number) {
124
+ super({
125
+ parents: [parentObservable],
126
+ initialValue: parentObservable.getSnapshot(),
127
+ });
128
+
129
+ this.#mut_isSkipping = false;
130
+
131
+ this.#mut_timerId = undefined;
132
+
133
+ this.#milliSeconds = milliSeconds;
134
+ }
135
+
136
+ override tryUpdate(updateToken: UpdateToken): void {
137
+ const par = this.parents[0];
138
+
139
+ if (
140
+ par.updateToken !== updateToken ||
141
+ Optional.isNone(par.getSnapshot()) ||
142
+ this.#mut_isSkipping
143
+ ) {
144
+ return; // skip update
145
+ }
146
+
147
+ // set timer
148
+ this.#mut_isSkipping = true;
149
+
150
+ this.#mut_timerId = setTimeout(() => {
151
+ const sn = par.getSnapshot();
152
+
153
+ if (Optional.isNone(sn)) return;
154
+
155
+ this.startUpdate(sn.value);
156
+
157
+ this.#mut_isSkipping = false;
158
+ }, this.#milliSeconds);
159
+ }
160
+
161
+ #resetTimer(): void {
162
+ if (this.#mut_timerId !== undefined) {
163
+ clearTimeout(this.#mut_timerId);
164
+ }
165
+ }
166
+
167
+ override complete(): void {
168
+ this.#resetTimer();
169
+
170
+ super.complete();
171
+ }
172
+ }