mutts 1.0.9 → 1.0.11

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 (206) hide show
  1. package/README.md +60 -35
  2. package/dist/browser.cjs +1333 -1760
  3. package/dist/browser.cjs.map +1 -1
  4. package/dist/browser.d.ts +2 -1392
  5. package/dist/browser.dev.cjs +114 -0
  6. package/dist/browser.dev.cjs.map +1 -0
  7. package/dist/browser.dev.d.ts +2 -0
  8. package/dist/browser.dev.esm.js +5 -0
  9. package/dist/browser.dev.esm.js.map +1 -0
  10. package/dist/browser.esm.js +18 -97
  11. package/dist/browser.esm.js.map +1 -1
  12. package/dist/chunks/{async-browser-lvzLOCgk.cjs → async-browser-Dgr5CreQ.cjs} +16 -95
  13. package/dist/chunks/async-browser-Dgr5CreQ.cjs.map +1 -0
  14. package/dist/chunks/{async-node-C3DeIb0y.cjs → async-node-3PrbVAbB.cjs} +3 -1
  15. package/dist/chunks/async-node-3PrbVAbB.cjs.map +1 -0
  16. package/dist/chunks/index-Sf74wXTV.esm.js +2577 -0
  17. package/dist/chunks/index-Sf74wXTV.esm.js.map +1 -0
  18. package/dist/chunks/node-Bo7WU5S2.esm.js +96 -0
  19. package/dist/chunks/node-Bo7WU5S2.esm.js.map +1 -0
  20. package/dist/chunks/{index-VTO-b2vR.cjs → proxy-Cc79Lrzj.cjs} +2593 -3216
  21. package/dist/chunks/proxy-Cc79Lrzj.cjs.map +1 -0
  22. package/dist/chunks/{index-CtA2AWl3.esm.js → proxy-D2C49sXH.esm.js} +2570 -3174
  23. package/dist/chunks/proxy-D2C49sXH.esm.js.map +1 -0
  24. package/dist/debug.cjs +987 -28
  25. package/dist/debug.cjs.map +1 -1
  26. package/dist/debug.d.ts +37 -38
  27. package/dist/debug.esm.js +963 -1
  28. package/dist/debug.esm.js.map +1 -1
  29. package/dist/devtools/manifest.json +1 -1
  30. package/dist/devtools/panel.html +1 -1
  31. package/dist/devtools/panel.js +107 -94
  32. package/dist/devtools/panel.js.map +1 -1
  33. package/dist/index.d.ts +1322 -1
  34. package/dist/mutts.umd.js +6647 -1
  35. package/dist/mutts.umd.js.map +1 -1
  36. package/dist/mutts.umd.min.js +1 -1
  37. package/dist/mutts.umd.min.js.map +1 -1
  38. package/dist/node.cjs +69 -63
  39. package/dist/node.cjs.map +1 -1
  40. package/dist/node.d.ts +2 -2
  41. package/dist/node.dev.cjs +114 -0
  42. package/dist/node.dev.cjs.map +1 -0
  43. package/dist/node.dev.d.ts +2 -0
  44. package/dist/node.dev.esm.js +6 -0
  45. package/dist/node.dev.esm.js.map +1 -0
  46. package/dist/node.esm.js +4 -97
  47. package/dist/node.esm.js.map +1 -1
  48. package/dist/{types-DaHFfhlN.d.ts → types-Bx2PhORg.d.ts} +134 -88
  49. package/docs/ai/api-reference.md +11 -32
  50. package/docs/ai/manual.md +297 -239
  51. package/docs/reactive/advanced.md +318 -9
  52. package/docs/reactive/attend.md +2 -4
  53. package/docs/reactive/collections.md +22 -187
  54. package/docs/reactive/core.md +223 -131
  55. package/docs/reactive/debugging.md +119 -12
  56. package/docs/reactive/error-handling.md +10 -10
  57. package/docs/reactive/resource.md +125 -0
  58. package/docs/reactive.md +3 -4
  59. package/docs/utils.md +70 -0
  60. package/docs/zone.md +1 -1
  61. package/package.json +76 -38
  62. package/dist/chunks/async-browser-lvzLOCgk.cjs.map +0 -1
  63. package/dist/chunks/async-node-C3DeIb0y.cjs.map +0 -1
  64. package/dist/chunks/index-2vea86wD.esm.js +0 -3011
  65. package/dist/chunks/index-2vea86wD.esm.js.map +0 -1
  66. package/dist/chunks/index-CtA2AWl3.esm.js.map +0 -1
  67. package/dist/chunks/index-VTO-b2vR.cjs.map +0 -1
  68. package/dist/debug/debug.d.ts +0 -122
  69. package/dist/debug/debug.d.ts.map +0 -1
  70. package/dist/debug/index.d.ts +0 -4
  71. package/dist/debug/index.d.ts.map +0 -1
  72. package/dist/debug/lineage-panel.d.ts +0 -5
  73. package/dist/debug/lineage-panel.d.ts.map +0 -1
  74. package/dist/debug/lineage.d.ts +0 -79
  75. package/dist/debug/lineage.d.ts.map +0 -1
  76. package/dist/src/async/browser.d.ts +0 -2
  77. package/dist/src/async/browser.d.ts.map +0 -1
  78. package/dist/src/async/index.d.ts +0 -19
  79. package/dist/src/async/index.d.ts.map +0 -1
  80. package/dist/src/async/node.d.ts +0 -2
  81. package/dist/src/async/node.d.ts.map +0 -1
  82. package/dist/src/decorator.d.ts +0 -106
  83. package/dist/src/decorator.d.ts.map +0 -1
  84. package/dist/src/destroyable.d.ts +0 -87
  85. package/dist/src/destroyable.d.ts.map +0 -1
  86. package/dist/src/entry-browser.d.ts +0 -3
  87. package/dist/src/entry-browser.d.ts.map +0 -1
  88. package/dist/src/entry-node.d.ts +0 -3
  89. package/dist/src/entry-node.d.ts.map +0 -1
  90. package/dist/src/eventful.d.ts +0 -20
  91. package/dist/src/eventful.d.ts.map +0 -1
  92. package/dist/src/flavored.d.ts +0 -33
  93. package/dist/src/flavored.d.ts.map +0 -1
  94. package/dist/src/index.d.ts +0 -14
  95. package/dist/src/index.d.ts.map +0 -1
  96. package/dist/src/indexable.d.ts +0 -243
  97. package/dist/src/indexable.d.ts.map +0 -1
  98. package/dist/src/introspection.d.ts +0 -27
  99. package/dist/src/introspection.d.ts.map +0 -1
  100. package/dist/src/iterableWeak.d.ts +0 -53
  101. package/dist/src/iterableWeak.d.ts.map +0 -1
  102. package/dist/src/mixins.d.ts +0 -25
  103. package/dist/src/mixins.d.ts.map +0 -1
  104. package/dist/src/promiseChain.d.ts +0 -20
  105. package/dist/src/promiseChain.d.ts.map +0 -1
  106. package/dist/src/reactive/array.d.ts +0 -48
  107. package/dist/src/reactive/array.d.ts.map +0 -1
  108. package/dist/src/reactive/buffer.d.ts +0 -120
  109. package/dist/src/reactive/buffer.d.ts.map +0 -1
  110. package/dist/src/reactive/change.d.ts +0 -29
  111. package/dist/src/reactive/change.d.ts.map +0 -1
  112. package/dist/src/reactive/deep-touch.d.ts +0 -28
  113. package/dist/src/reactive/deep-touch.d.ts.map +0 -1
  114. package/dist/src/reactive/deep-watch-state.d.ts +0 -25
  115. package/dist/src/reactive/deep-watch-state.d.ts.map +0 -1
  116. package/dist/src/reactive/deep-watch.d.ts +0 -20
  117. package/dist/src/reactive/deep-watch.d.ts.map +0 -1
  118. package/dist/src/reactive/describe.d.ts +0 -12
  119. package/dist/src/reactive/describe.d.ts.map +0 -1
  120. package/dist/src/reactive/effect-context.d.ts +0 -34
  121. package/dist/src/reactive/effect-context.d.ts.map +0 -1
  122. package/dist/src/reactive/effects.d.ts +0 -164
  123. package/dist/src/reactive/effects.d.ts.map +0 -1
  124. package/dist/src/reactive/index.d.ts +0 -19
  125. package/dist/src/reactive/index.d.ts.map +0 -1
  126. package/dist/src/reactive/map.d.ts +0 -28
  127. package/dist/src/reactive/map.d.ts.map +0 -1
  128. package/dist/src/reactive/memoize.d.ts +0 -28
  129. package/dist/src/reactive/memoize.d.ts.map +0 -1
  130. package/dist/src/reactive/non-reactive-state.d.ts +0 -9
  131. package/dist/src/reactive/non-reactive-state.d.ts.map +0 -1
  132. package/dist/src/reactive/non-reactive.d.ts +0 -11
  133. package/dist/src/reactive/non-reactive.d.ts.map +0 -1
  134. package/dist/src/reactive/project.d.ts +0 -40
  135. package/dist/src/reactive/project.d.ts.map +0 -1
  136. package/dist/src/reactive/proxy-state.d.ts +0 -8
  137. package/dist/src/reactive/proxy-state.d.ts.map +0 -1
  138. package/dist/src/reactive/proxy.d.ts +0 -23
  139. package/dist/src/reactive/proxy.d.ts.map +0 -1
  140. package/dist/src/reactive/record.d.ts +0 -115
  141. package/dist/src/reactive/record.d.ts.map +0 -1
  142. package/dist/src/reactive/register.d.ts +0 -125
  143. package/dist/src/reactive/register.d.ts.map +0 -1
  144. package/dist/src/reactive/registry.d.ts +0 -21
  145. package/dist/src/reactive/registry.d.ts.map +0 -1
  146. package/dist/src/reactive/set.d.ts +0 -26
  147. package/dist/src/reactive/set.d.ts.map +0 -1
  148. package/dist/src/reactive/tracking.d.ts +0 -7
  149. package/dist/src/reactive/tracking.d.ts.map +0 -1
  150. package/dist/src/reactive/types.d.ts +0 -424
  151. package/dist/src/reactive/types.d.ts.map +0 -1
  152. package/dist/src/reactive/watch.d.ts +0 -48
  153. package/dist/src/reactive/watch.d.ts.map +0 -1
  154. package/dist/src/std-decorators.d.ts +0 -45
  155. package/dist/src/std-decorators.d.ts.map +0 -1
  156. package/dist/src/utils.d.ts +0 -49
  157. package/dist/src/utils.d.ts.map +0 -1
  158. package/dist/src/zone.d.ts +0 -40
  159. package/dist/src/zone.d.ts.map +0 -1
  160. package/docs/reactive/describe.md +0 -85
  161. package/docs/reactive/project.md +0 -93
  162. package/docs/reactive/scan.md +0 -293
  163. package/src/async/browser.ts +0 -323
  164. package/src/async/index.ts +0 -27
  165. package/src/async/node.ts +0 -92
  166. package/src/decorator.ts +0 -272
  167. package/src/destroyable.ts +0 -199
  168. package/src/entry-browser.ts +0 -5
  169. package/src/entry-node.ts +0 -5
  170. package/src/eventful.ts +0 -110
  171. package/src/flavored.ts +0 -106
  172. package/src/index.d.ts +0 -12
  173. package/src/index.ts +0 -64
  174. package/src/indexable.ts +0 -526
  175. package/src/introspection.ts +0 -59
  176. package/src/iterableWeak.ts +0 -233
  177. package/src/mixins.ts +0 -123
  178. package/src/promiseChain.ts +0 -110
  179. package/src/reactive/array.ts +0 -500
  180. package/src/reactive/buffer.ts +0 -328
  181. package/src/reactive/change.ts +0 -131
  182. package/src/reactive/deep-touch.ts +0 -273
  183. package/src/reactive/deep-watch-state.ts +0 -82
  184. package/src/reactive/deep-watch.ts +0 -171
  185. package/src/reactive/describe.ts +0 -39
  186. package/src/reactive/effect-context.ts +0 -83
  187. package/src/reactive/effects.ts +0 -1434
  188. package/src/reactive/index.ts +0 -72
  189. package/src/reactive/map.ts +0 -142
  190. package/src/reactive/memoize.ts +0 -186
  191. package/src/reactive/non-reactive-state.ts +0 -49
  192. package/src/reactive/non-reactive.ts +0 -43
  193. package/src/reactive/project.md +0 -107
  194. package/src/reactive/project.ts +0 -430
  195. package/src/reactive/proxy-state.ts +0 -27
  196. package/src/reactive/proxy.ts +0 -282
  197. package/src/reactive/record.ts +0 -181
  198. package/src/reactive/register.ts +0 -538
  199. package/src/reactive/registry.ts +0 -72
  200. package/src/reactive/set.ts +0 -117
  201. package/src/reactive/tracking.ts +0 -41
  202. package/src/reactive/types.ts +0 -520
  203. package/src/reactive/watch.ts +0 -180
  204. package/src/std-decorators.ts +0 -256
  205. package/src/utils.ts +0 -300
  206. package/src/zone.ts +0 -142
@@ -1,323 +0,0 @@
1
- import { asyncHooks, hooks, type Restorer } from '.'
2
-
3
- const promiseContexts = new WeakMap<Promise<any>, Set<Restorer>>()
4
-
5
- // [HACK]: Sanitization
6
- // If a Promise is created inside the zone, it carries the "Sticky" zone context.
7
- // If returned to the outer scope, that context leaks. We wrap it in a new Promise
8
- // created here (in the outer scope) to break the chain and sanitize the return value.
9
- // See BROWSER_ASYNC_POLYFILL.md for full details.
10
- asyncHooks.sanitizePromise = (res: any) => {
11
- if (res && typeof (res as any).then === 'function') {
12
- return new Promise((resolve, reject) => {
13
- setTimeout(() => {
14
- ;(res as any).then(resolve, reject)
15
- }, 0)
16
- })
17
- }
18
- return res
19
- }
20
-
21
- function captureRestorers() {
22
- const restorers = new Set<Restorer>()
23
- for (const hook of hooks) {
24
- const restorer = hook()
25
- if (restorer) restorers.add(restorer)
26
- }
27
- return restorers
28
- }
29
-
30
- function wrap<Args extends any[], R>(
31
- fn: ((...args: Args) => R) | null | undefined,
32
- capturedRestorers?: Set<Restorer>
33
- ) {
34
- if (typeof fn !== 'function') return fn
35
- const restorers = capturedRestorers || captureRestorers()
36
- return function (this: any, ...args: Args) {
37
- const undoers: (() => void)[] = []
38
- for (const restore of restorers) undoers.push(restore())
39
- try {
40
- return fn.apply(this, args)
41
- } finally {
42
- if (originals.queueMicrotask) {
43
- // Double microtask ensures we run after the first await resumption microtask
44
- originals.queueMicrotask.call(globalThis, () => {
45
- originals.queueMicrotask.call(globalThis, () => {
46
- originals.queueMicrotask.call(globalThis, () => {
47
- for (let i = undoers.length - 1; i >= 0; i--) undoers[i]()
48
- })
49
- })
50
- })
51
- } else {
52
- for (let i = undoers.length - 1; i >= 0; i--) undoers[i]()
53
- }
54
- }
55
- }
56
- }
57
-
58
- const targetWrappers = new WeakMap<any, Map<string, WeakMap<Function, Function>>>()
59
-
60
- function patchEventTarget(proto: any) {
61
- if (!proto || !proto.addEventListener || !proto.removeEventListener) return
62
- const nativeAdd = proto.addEventListener
63
- const nativeRemove = proto.removeEventListener
64
-
65
- proto.addEventListener = function (this: any, type: string, listener: any, options: any) {
66
- if (typeof listener !== 'function') {
67
- return nativeAdd.call(this, type, listener, options)
68
- }
69
-
70
- let types = targetWrappers.get(this)
71
- if (!types) {
72
- types = new Map()
73
- targetWrappers.set(this, types)
74
- }
75
- let listeners = types.get(type)
76
- if (!listeners) {
77
- listeners = new WeakMap()
78
- types.set(type, listeners)
79
- }
80
-
81
- let wrapped = listeners.get(listener)
82
- if (!wrapped) {
83
- wrapped = wrap(listener)
84
- listeners.set(listener, wrapped)
85
- }
86
-
87
- return nativeAdd.call(this, type, wrapped, options)
88
- }
89
-
90
- proto.removeEventListener = function (this: any, type: string, listener: any, options: any) {
91
- if (typeof listener !== 'function') {
92
- return nativeRemove.call(this, type, listener, options)
93
- }
94
-
95
- const types = targetWrappers.get(this)
96
- if (types) {
97
- const listeners = types.get(type)
98
- if (listeners) {
99
- const wrapped = listeners.get(listener)
100
- if (wrapped) {
101
- return nativeRemove.call(this, type, wrapped, options)
102
- }
103
- }
104
- }
105
-
106
- return nativeRemove.call(this, type, listener, options)
107
- }
108
- }
109
-
110
- function patchOnProperties(proto: any) {
111
- if (!proto) return
112
- for (const prop of Object.getOwnPropertyNames(proto)) {
113
- if (prop.startsWith('on')) {
114
- const desc = Object.getOwnPropertyDescriptor(proto, prop)
115
- if (desc && desc.set && desc.configurable) {
116
- const nativeSet = desc.set
117
- Object.defineProperty(proto, prop, {
118
- ...desc,
119
- set: function (this: any, fn: any) {
120
- nativeSet.call(this, wrap(fn))
121
- },
122
- })
123
- }
124
- }
125
- }
126
- }
127
-
128
- if (typeof EventTarget !== 'undefined') {
129
- patchEventTarget(EventTarget.prototype)
130
- }
131
-
132
- const prototypesToPatch = [
133
- typeof EventTarget !== 'undefined' && EventTarget.prototype,
134
- typeof HTMLElement !== 'undefined' && HTMLElement.prototype,
135
- typeof Window !== 'undefined' && Window.prototype,
136
- typeof Document !== 'undefined' && Document.prototype,
137
- typeof MessagePort !== 'undefined' && MessagePort.prototype,
138
- typeof XMLHttpRequest !== 'undefined' && XMLHttpRequest.prototype,
139
- typeof IDBRequest !== 'undefined' && IDBRequest.prototype,
140
- typeof IDBTransaction !== 'undefined' && IDBTransaction.prototype,
141
- typeof IDBDatabase !== 'undefined' && IDBDatabase.prototype,
142
- typeof FileReader !== 'undefined' && FileReader.prototype,
143
- typeof AbortSignal !== 'undefined' && AbortSignal.prototype,
144
- ]
145
-
146
- for (const proto of prototypesToPatch) {
147
- if (proto) {
148
- patchOnProperties(proto)
149
- }
150
- }
151
-
152
- const GLOBAL_ORIGINALS = Symbol.for('mutts.originals')
153
- const GLOBAL_PROMISE = Symbol.for('mutts.OriginalPromise')
154
-
155
- let originals: any
156
- let OriginalPromise: any
157
-
158
- if ((globalThis as any)[GLOBAL_ORIGINALS]) {
159
- originals = (globalThis as any)[GLOBAL_ORIGINALS]
160
- OriginalPromise = (globalThis as any)[GLOBAL_PROMISE]
161
- } else {
162
- OriginalPromise = globalThis.Promise
163
- originals = {
164
- then: OriginalPromise.prototype.then,
165
- catch: OriginalPromise.prototype.catch,
166
- finally: OriginalPromise.prototype.finally,
167
- resolve: OriginalPromise.resolve,
168
- reject: OriginalPromise.reject,
169
- all: OriginalPromise.all,
170
- allSettled: (OriginalPromise as any).allSettled,
171
- race: OriginalPromise.race,
172
- any: (OriginalPromise as any).any,
173
- setTimeout: globalThis.setTimeout,
174
- setInterval: globalThis.setInterval,
175
- setImmediate: (globalThis as any).setImmediate,
176
- requestAnimationFrame: (globalThis as any).requestAnimationFrame,
177
- queueMicrotask: globalThis.queueMicrotask,
178
- }
179
- ;(globalThis as any)[GLOBAL_ORIGINALS] = originals
180
- ;(globalThis as any)[GLOBAL_PROMISE] = OriginalPromise
181
- }
182
-
183
- // Ensure modern statics are captured even if originals was cached from an older version
184
- if (!originals.allSettled) originals.allSettled = (OriginalPromise as any).allSettled
185
- if (!originals.any) originals.any = (OriginalPromise as any).any
186
- if (!originals.race) originals.race = OriginalPromise.race
187
-
188
- function patchedThen(this: any, onFulfilled: any, onRejected: any) {
189
- const context = promiseContexts.get(this) || captureRestorers()
190
- const nextPromise = originals.then.call(
191
- this,
192
- wrap(onFulfilled, context),
193
- wrap(onRejected, context)
194
- )
195
- if (context.size > 0) promiseContexts.set(nextPromise, context)
196
- return nextPromise
197
- }
198
-
199
- function patchedCatch(this: any, onRejected: any) {
200
- const context = promiseContexts.get(this) || captureRestorers()
201
- const nextPromise = originals.catch.call(this, wrap(onRejected, context))
202
- if (context.size > 0) promiseContexts.set(nextPromise, context)
203
- return nextPromise
204
- }
205
-
206
- function patchedFinally(this: any, onFinally: any) {
207
- const context = promiseContexts.get(this) || captureRestorers()
208
- const nextPromise = originals.finally.call(this, wrap(onFinally, context))
209
- if (context.size > 0) promiseContexts.set(nextPromise, context)
210
- return nextPromise
211
- }
212
-
213
- function PatchedPromise<T>(
214
- this: any,
215
- executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void
216
- ) {
217
- if (typeof executor === 'function') {
218
- const p = new OriginalPromise((resolve, reject) => {
219
- const wrappedResolve = wrap(resolve)
220
- const wrappedReject = wrap(reject)
221
- executor(wrappedResolve, wrappedReject)
222
- })
223
- const context = captureRestorers()
224
- promiseContexts.set(p, context) // Always set, even if empty (Sticky Root)
225
- return p
226
- }
227
- return new OriginalPromise(executor)
228
- }
229
-
230
- // Copy statics
231
- Object.assign(PatchedPromise, OriginalPromise as any)
232
-
233
- // Inherit prototype for instanceof checks
234
- PatchedPromise.prototype = OriginalPromise.prototype
235
-
236
- PatchedPromise.resolve = (<T>(value?: T | PromiseLike<T>): Promise<T> => {
237
- const p = originals.resolve.call(OriginalPromise, value) as Promise<T>
238
- const context = captureRestorers()
239
- // Ensure we don't overwrite if it already has context (e.g. from constructor)
240
- if (context.size > 0 && !promiseContexts.has(p)) promiseContexts.set(p, context)
241
- return p
242
- }) as any
243
-
244
- PatchedPromise.reject = (<T = never>(reason?: any): Promise<T> => {
245
- const p = originals.reject.call(OriginalPromise, reason) as Promise<T>
246
- const context = captureRestorers()
247
- if (context.size > 0) promiseContexts.set(p, context)
248
- return p
249
- }) as any
250
-
251
- PatchedPromise.all = (<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]> => {
252
- const p = originals.all.call(OriginalPromise, values) as Promise<Awaited<T>[]>
253
- const context = captureRestorers()
254
- if (context.size > 0) promiseContexts.set(p, context)
255
- return p
256
- }) as any
257
-
258
- PatchedPromise.allSettled = (<T>(
259
- values: Iterable<T | PromiseLike<T>>
260
- ): Promise<PromiseSettledResult<Awaited<T>>[]> => {
261
- const p = (originals.allSettled as any).call(OriginalPromise, values)
262
- const context = captureRestorers()
263
- if (context.size > 0) promiseContexts.set(p, context)
264
- return p
265
- }) as any
266
-
267
- PatchedPromise.race = (<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>> => {
268
- const p = originals.race.call(OriginalPromise, values) as Promise<Awaited<T>>
269
- const context = captureRestorers()
270
- if (context.size > 0) promiseContexts.set(p, context)
271
- return p
272
- }) as any
273
-
274
- PatchedPromise.any = (<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>> => {
275
- const p = (originals.any as any).call(OriginalPromise, values)
276
- const context = captureRestorers()
277
- if (context.size > 0) promiseContexts.set(p, context)
278
- return p
279
- }) as any
280
-
281
- // Only apply patches if not already applied (or re-apply safely)
282
- // Note: OriginalPromise.prototype might be shared if we used the global one.
283
- // We must ensure we don't patch it twice if it's the SAME object.
284
- if (OriginalPromise.prototype.then !== patchedThen) {
285
- OriginalPromise.prototype.then = patchedThen as any
286
- OriginalPromise.prototype.catch = patchedCatch as any
287
- OriginalPromise.prototype.finally = patchedFinally as any
288
- }
289
-
290
- try {
291
- Object.defineProperty(OriginalPromise, Symbol.species, {
292
- get: () => PatchedPromise,
293
- configurable: true,
294
- })
295
- } catch (e) {}
296
-
297
- ;(globalThis as any).Promise = PatchedPromise
298
-
299
- globalThis.setTimeout = ((callback: Function, ...args: any[]) => {
300
- return originals.setTimeout.call(globalThis, wrap(callback as any), ...args)
301
- }) as any
302
-
303
- globalThis.setInterval = ((callback: Function, ...args: any[]) => {
304
- return originals.setInterval.call(globalThis, wrap(callback as any), ...args)
305
- }) as any
306
-
307
- if (originals.setImmediate) {
308
- ;(globalThis as any).setImmediate = ((callback: Function, ...args: any[]) => {
309
- return originals.setImmediate.call(globalThis, wrap(callback as any), ...args)
310
- }) as any
311
- }
312
-
313
- if (originals.requestAnimationFrame) {
314
- globalThis.requestAnimationFrame = (callback: FrameRequestCallback) => {
315
- return originals.requestAnimationFrame.call(globalThis, wrap(callback))
316
- }
317
- }
318
-
319
- if (originals.queueMicrotask) {
320
- globalThis.queueMicrotask = (callback: VoidFunction): void => {
321
- originals.queueMicrotask.call(globalThis, wrap(callback))
322
- }
323
- }
@@ -1,27 +0,0 @@
1
- export type Restorer = () => () => void
2
- export type Hook = () => Restorer
3
-
4
- // Queue for hooks registered before the environment is ready (circular dependency fix)
5
- export const hooks = new Set<Hook>()
6
-
7
- export const asyncHooks = {
8
- addHook(hook: Hook): () => void {
9
- hooks.add(hook)
10
- return () => hooks.delete(hook)
11
- },
12
- /**
13
- * [Hack] Sanitize a promise (or value) to prevent context leaks.
14
- * Default: Identity function.
15
- * Browser: Uses Macrotask wrapping to break microtask chains.
16
- */
17
- sanitizePromise(p: any): any {
18
- return p
19
- },
20
- }
21
-
22
- /**
23
- * Register a hook that will be called whenever an asynchronous operation is initiated.
24
- * The hook should return a restorer function which will be called just before the async callback runs.
25
- * That restorer should in turn return an undoer function which will be called just after the async callback finishes.
26
- */
27
- export const asyncHook = (hook: Hook) => asyncHooks.addHook(hook)
package/src/async/node.ts DELETED
@@ -1,92 +0,0 @@
1
- import { createHook } from 'node:async_hooks'
2
- import { hooks, type Restorer } from '.'
3
-
4
- // 1. Generic async_hooks implementation for Hooks
5
- // This maintains support for 'asyncHooks.addHook' for generic use cases.
6
-
7
- const contexts = new Map<number, Restorer[]>()
8
- const activeUndoers = new Map<number, (() => void)[]>()
9
-
10
- // Helper to capture current hooks state
11
- function captureRestorers() {
12
- if (hooks.size === 0) return []
13
- const restorers: Restorer[] = []
14
- for (const h of hooks) {
15
- const r = h()
16
- if (r) restorers.push(r)
17
- }
18
- return restorers
19
- }
20
-
21
- // Manual Wrap function to handle Promise callbacks
22
- function wrap<Args extends any[], R>(fn: ((...args: Args) => R) | null | undefined) {
23
- if (typeof fn !== 'function') return fn
24
- const restorers = captureRestorers()
25
- if (restorers.length === 0) return fn
26
-
27
- return function (this: any, ...args: Args) {
28
- const undoers: (() => void)[] = []
29
- for (const restore of restorers) {
30
- const u = restore()
31
- if (u) undoers.push(u)
32
- }
33
- try {
34
- return fn.apply(this, args)
35
- } finally {
36
- for (let i = undoers.length - 1; i >= 0; i--) undoers[i]()
37
- }
38
- }
39
- }
40
-
41
- const hook = createHook({
42
- init(asyncId, _type, _triggerId, _resource) {
43
- // Used for native resources like Timers
44
- const restorers = captureRestorers()
45
- if (restorers.length > 0) contexts.set(asyncId, restorers)
46
- },
47
- before(asyncId) {
48
- const restorers = contexts.get(asyncId)
49
- if (!restorers) return
50
- const undoers: (() => void)[] = []
51
- for (const restore of restorers) {
52
- const u = restore()
53
- if (u) undoers.push(u)
54
- }
55
- if (undoers.length > 0) activeUndoers.set(asyncId, undoers)
56
- },
57
- after(asyncId) {
58
- const undoers = activeUndoers.get(asyncId)
59
- if (!undoers) return
60
- for (let i = undoers.length - 1; i >= 0; i--) undoers[i]()
61
- activeUndoers.delete(asyncId)
62
- },
63
- destroy(asyncId) {
64
- contexts.delete(asyncId)
65
- activeUndoers.delete(asyncId)
66
- },
67
- })
68
- hook.enable()
69
-
70
- // 2. Shadow Promise Implementation
71
- // Ensures V8 await resumptions are visible as .then callbacks, wrapping them to restore context.
72
-
73
- const OriginalPromise = globalThis.Promise
74
- const originalMethods = {
75
- then: OriginalPromise.prototype.then,
76
- catch: OriginalPromise.prototype.catch,
77
- finally: OriginalPromise.prototype.finally,
78
- resolve: OriginalPromise.resolve,
79
- reject: OriginalPromise.reject,
80
- all: OriginalPromise.all,
81
- }
82
-
83
- // Patch prototype
84
- OriginalPromise.prototype.then = function (onFulfilled, onRejected) {
85
- return originalMethods.then.call(this, wrap(onFulfilled), wrap(onRejected))
86
- } as any
87
- OriginalPromise.prototype.catch = function (onRejected) {
88
- return originalMethods.catch.call(this, wrap(onRejected))
89
- } as any
90
- OriginalPromise.prototype.finally = function (onFinally) {
91
- return originalMethods.finally.call(this, wrap(onFinally))
92
- } as any