mutts 1.0.1 → 1.0.3

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 (111) hide show
  1. package/README.md +36 -6
  2. package/dist/chunks/_tslib-BgjropY9.js +81 -0
  3. package/dist/chunks/_tslib-BgjropY9.js.map +1 -0
  4. package/dist/chunks/_tslib-Mzh1rNsX.esm.js +75 -0
  5. package/dist/chunks/_tslib-Mzh1rNsX.esm.js.map +1 -0
  6. package/dist/chunks/{decorator-8qjFb7dw.js → decorator-DLvrD0UF.js} +103 -14
  7. package/dist/chunks/decorator-DLvrD0UF.js.map +1 -0
  8. package/dist/chunks/{decorator-AbRkXM5O.esm.js → decorator-DqiszP7i.esm.js} +100 -15
  9. package/dist/chunks/decorator-DqiszP7i.esm.js.map +1 -0
  10. package/dist/chunks/index-DzUDtFc7.esm.js +4841 -0
  11. package/dist/chunks/index-DzUDtFc7.esm.js.map +1 -0
  12. package/dist/chunks/index-HNVqPzjz.js +4891 -0
  13. package/dist/chunks/index-HNVqPzjz.js.map +1 -0
  14. package/dist/decorator.d.ts +57 -0
  15. package/dist/decorator.esm.js +1 -1
  16. package/dist/decorator.js +1 -1
  17. package/dist/destroyable.d.ts +43 -1
  18. package/dist/destroyable.esm.js +19 -1
  19. package/dist/destroyable.esm.js.map +1 -1
  20. package/dist/destroyable.js +19 -1
  21. package/dist/destroyable.js.map +1 -1
  22. package/dist/devtools/devtools.html +9 -0
  23. package/dist/devtools/devtools.js +5 -0
  24. package/dist/devtools/devtools.js.map +1 -0
  25. package/dist/devtools/manifest.json +8 -0
  26. package/dist/devtools/panel.css +72 -0
  27. package/dist/devtools/panel.html +31 -0
  28. package/dist/devtools/panel.js +13048 -0
  29. package/dist/devtools/panel.js.map +1 -0
  30. package/dist/eventful.d.ts +10 -1
  31. package/dist/eventful.esm.js +5 -27
  32. package/dist/eventful.esm.js.map +1 -1
  33. package/dist/eventful.js +15 -37
  34. package/dist/eventful.js.map +1 -1
  35. package/dist/index.d.ts +18 -14
  36. package/dist/index.esm.js +4 -3
  37. package/dist/index.esm.js.map +1 -1
  38. package/dist/index.js +44 -5
  39. package/dist/index.js.map +1 -1
  40. package/dist/indexable.d.ts +213 -1
  41. package/dist/indexable.esm.js +203 -3
  42. package/dist/indexable.esm.js.map +1 -1
  43. package/dist/indexable.js +204 -2
  44. package/dist/indexable.js.map +1 -1
  45. package/dist/mutts.umd.js +1 -1
  46. package/dist/mutts.umd.js.map +1 -1
  47. package/dist/mutts.umd.min.js +1 -1
  48. package/dist/mutts.umd.min.js.map +1 -1
  49. package/dist/promiseChain.d.ts +10 -0
  50. package/dist/promiseChain.esm.js +6 -0
  51. package/dist/promiseChain.esm.js.map +1 -1
  52. package/dist/promiseChain.js +6 -0
  53. package/dist/promiseChain.js.map +1 -1
  54. package/dist/reactive.d.ts +774 -33
  55. package/dist/reactive.esm.js +4 -1458
  56. package/dist/reactive.esm.js.map +1 -1
  57. package/dist/reactive.js +53 -1474
  58. package/dist/reactive.js.map +1 -1
  59. package/dist/std-decorators.d.ts +35 -0
  60. package/dist/std-decorators.esm.js +36 -1
  61. package/dist/std-decorators.esm.js.map +1 -1
  62. package/dist/std-decorators.js +36 -1
  63. package/dist/std-decorators.js.map +1 -1
  64. package/docs/ai/api-reference.md +133 -0
  65. package/docs/ai/manual.md +105 -0
  66. package/docs/iterableWeak.md +646 -0
  67. package/docs/mixin.md +229 -0
  68. package/docs/reactive/advanced.md +1280 -0
  69. package/docs/reactive/collections.md +767 -0
  70. package/docs/reactive/core.md +973 -0
  71. package/docs/reactive.md +21 -2688
  72. package/package.json +18 -5
  73. package/src/decorator.ts +266 -0
  74. package/src/destroyable.ts +199 -0
  75. package/src/eventful.ts +77 -0
  76. package/src/index.d.ts +9 -0
  77. package/src/index.ts +9 -0
  78. package/src/indexable.ts +484 -0
  79. package/src/introspection.ts +59 -0
  80. package/src/iterableWeak.ts +233 -0
  81. package/src/mixins.ts +123 -0
  82. package/src/promiseChain.ts +110 -0
  83. package/src/reactive/array.ts +414 -0
  84. package/src/reactive/change.ts +134 -0
  85. package/src/reactive/debug.ts +517 -0
  86. package/src/reactive/deep-touch.ts +268 -0
  87. package/src/reactive/deep-watch-state.ts +82 -0
  88. package/src/reactive/deep-watch.ts +168 -0
  89. package/src/reactive/effect-context.ts +94 -0
  90. package/src/reactive/effects.ts +1333 -0
  91. package/src/reactive/index.ts +75 -0
  92. package/src/reactive/interface.ts +223 -0
  93. package/src/reactive/map.ts +171 -0
  94. package/src/reactive/mapped.ts +130 -0
  95. package/src/reactive/memoize.ts +107 -0
  96. package/src/reactive/non-reactive-state.ts +49 -0
  97. package/src/reactive/non-reactive.ts +43 -0
  98. package/src/reactive/project.project.md +93 -0
  99. package/src/reactive/project.ts +335 -0
  100. package/src/reactive/proxy-state.ts +27 -0
  101. package/src/reactive/proxy.ts +285 -0
  102. package/src/reactive/record.ts +196 -0
  103. package/src/reactive/register.ts +421 -0
  104. package/src/reactive/set.ts +144 -0
  105. package/src/reactive/tracking.ts +101 -0
  106. package/src/reactive/types.ts +358 -0
  107. package/src/reactive/zone.ts +208 -0
  108. package/src/std-decorators.ts +217 -0
  109. package/src/utils.ts +117 -0
  110. package/dist/chunks/decorator-8qjFb7dw.js.map +0 -1
  111. package/dist/chunks/decorator-AbRkXM5O.esm.js.map +0 -1
@@ -0,0 +1,233 @@
1
+ /// <reference lib="esnext.collection" />
2
+
3
+ /**
4
+ * Uses weak references but still may iterate through them
5
+ * Note: The behavior is highly dependant on the garbage collector - some entries are perhaps deemed to be collected: don't resuscitate them
6
+ */
7
+ export class IterableWeakMap<K extends WeakKey, V> implements Map<K, V> {
8
+ private uuids = new WeakMap<K, string>()
9
+ private refs: Record<string, [WeakRef<K>, any]> = {}
10
+ private readonly registry: FinalizationRegistry<string>
11
+
12
+ constructor(entries?: Iterable<[K, V]>) {
13
+ // Create a FinalizationRegistry to clean up refs when keys are garbage collected
14
+ this.registry = new FinalizationRegistry((uuid: string) => {
15
+ delete this.refs[uuid]
16
+ })
17
+ if (entries) for (const [k, v] of entries) this.set(k, v)
18
+ }
19
+ private createIterator<I>(cb: (key: K, value: V) => I): MapIterator<I> {
20
+ const { refs } = this
21
+ return (function* () {
22
+ for (const uuid of Object.keys(refs)) {
23
+ const [keyRef, value] = refs[uuid]
24
+ const key = keyRef.deref()
25
+ if (key) yield cb(key, value)
26
+ else delete refs[uuid]
27
+ }
28
+ return undefined
29
+ })()
30
+ }
31
+ clear(): void {
32
+ // Unregister all keys from the FinalizationRegistry
33
+ for (const uuid of Object.keys(this.refs)) {
34
+ const key = this.refs[uuid][0].deref()
35
+ if (key) this.registry.unregister(key)
36
+ }
37
+ this.uuids = new WeakMap<K, string>()
38
+ this.refs = {}
39
+ }
40
+ delete(key: K): boolean {
41
+ const uuid = this.uuids.get(key)
42
+ if (!uuid) return false
43
+ delete this.refs[uuid]
44
+ this.uuids.delete(key)
45
+ this.registry.unregister(key)
46
+ return true
47
+ }
48
+ forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void {
49
+ for (const [k, v] of this) callbackfn.call(thisArg ?? this, v, k, thisArg ?? this)
50
+ }
51
+ get(key: K): V | undefined {
52
+ const uuid = this.uuids.get(key)
53
+ if (!uuid) return undefined
54
+ return this.refs[uuid][1]
55
+ }
56
+ has(key: K): boolean {
57
+ return this.uuids.has(key)
58
+ }
59
+ set(key: K, value: V): this {
60
+ let uuid = this.uuids.get(key)
61
+ if (uuid) {
62
+ this.refs[uuid][1] = value
63
+ } else {
64
+ uuid = crypto.randomUUID()
65
+ this.uuids.set(key, uuid)
66
+ this.refs[uuid] = [new WeakRef(key), value]
67
+ // Register key for cleanup when garbage collected
68
+ this.registry.register(key, uuid, key)
69
+ }
70
+ return this
71
+ }
72
+ get size(): number {
73
+ return [...this].length
74
+ }
75
+ entries(): MapIterator<[K, V]> {
76
+ return this.createIterator((key, value) => [key, value] as [K, V])
77
+ }
78
+ keys(): MapIterator<K> {
79
+ return this.createIterator((key, _value) => key)
80
+ }
81
+ values(): MapIterator<V> {
82
+ return this.createIterator((_key, value) => value)
83
+ }
84
+ [Symbol.iterator](): MapIterator<[K, V]> {
85
+ return this.entries()
86
+ }
87
+ readonly [Symbol.toStringTag]: string = 'IterableWeakMap'
88
+ }
89
+
90
+ /**
91
+ * Uses weak references but still may iterate through them
92
+ * Note: The behavior is highly dependant on the garbage collector - some entries are perhaps deemed to be collected: don't resuscitate them
93
+ */
94
+ export class IterableWeakSet<K extends WeakKey> implements Set<K> {
95
+ private uuids = new WeakMap<K, string>()
96
+ private refs: Record<string, WeakRef<K>> = {}
97
+ private readonly registry: FinalizationRegistry<string>
98
+
99
+ constructor(entries?: Iterable<K>) {
100
+ // Create a FinalizationRegistry to clean up refs when values are garbage collected
101
+ this.registry = new FinalizationRegistry((uuid: string) => {
102
+ delete this.refs[uuid]
103
+ })
104
+ if (entries) for (const k of entries) this.add(k)
105
+ }
106
+ private createIterator<I>(cb: (key: K) => I): MapIterator<I> {
107
+ const { refs } = this
108
+ return (function* () {
109
+ for (const uuid of Object.keys(refs)) {
110
+ const key = refs[uuid].deref()
111
+ if (key) yield cb(key)
112
+ else delete refs[uuid]
113
+ }
114
+ return undefined
115
+ })()
116
+ }
117
+
118
+ clear(): void {
119
+ // Unregister all values from the FinalizationRegistry
120
+ for (const uuid of Object.keys(this.refs)) {
121
+ const value = this.refs[uuid].deref()
122
+ if (value) this.registry.unregister(value)
123
+ }
124
+ this.uuids = new WeakMap<K, string>()
125
+ this.refs = {}
126
+ }
127
+
128
+ add(value: K): this {
129
+ let uuid = this.uuids.get(value)
130
+ if (!uuid) {
131
+ uuid = crypto.randomUUID()
132
+ this.uuids.set(value, uuid)
133
+ this.refs[uuid] = new WeakRef(value)
134
+ // Register value for cleanup when garbage collected
135
+ this.registry.register(value, uuid, value)
136
+ }
137
+ return this
138
+ }
139
+ delete(value: K): boolean {
140
+ const uuid = this.uuids.get(value)
141
+ if (!uuid) return false
142
+ delete this.refs[uuid]
143
+ this.uuids.delete(value)
144
+ this.registry.unregister(value)
145
+ return true
146
+ }
147
+
148
+ forEach(callbackfn: (value: K, value2: K, set: Set<K>) => void, thisArg?: any): void {
149
+ for (const value of this) callbackfn.call(thisArg ?? this, value, value, thisArg ?? this)
150
+ }
151
+
152
+ has(value: K): boolean {
153
+ return this.uuids.has(value)
154
+ }
155
+ get size(): number {
156
+ return [...this].length
157
+ }
158
+ entries(): SetIterator<[K, K]> {
159
+ return this.createIterator((key) => [key, key] as [K, K])
160
+ }
161
+ keys(): SetIterator<K> {
162
+ return this.createIterator((key) => key)
163
+ }
164
+ values(): SetIterator<K> {
165
+ return this.createIterator((key) => key)
166
+ }
167
+ [Symbol.iterator](): SetIterator<K> {
168
+ return this.keys()
169
+ }
170
+ readonly [Symbol.toStringTag]: string = 'IterableWeakSet'
171
+
172
+ union<U>(other: ReadonlySetLike<U>): Set<K | U> {
173
+ const others = {
174
+ [Symbol.iterator]() {
175
+ return other.keys()
176
+ },
177
+ }
178
+ const that = this
179
+ return new Set(
180
+ (function* () {
181
+ yield* that
182
+ for (const value of others) if (!that.has(<K>(<unknown>value))) yield value
183
+ })()
184
+ )
185
+ }
186
+ intersection<U /**/>(other: ReadonlySetLike<U>): Set<K & U> {
187
+ const that = this
188
+ return new Set(
189
+ (function* () {
190
+ for (const value of that) if (other.has(<U>(<unknown>value))) yield <K & U>value
191
+ })()
192
+ )
193
+ }
194
+ difference<U>(other: ReadonlySetLike<U>): Set<K> {
195
+ const that = this
196
+ return new Set(
197
+ (function* () {
198
+ for (const value of that) if (!other.has(<U>(<unknown>value))) yield <K>value
199
+ })()
200
+ )
201
+ }
202
+ symmetricDifference<U>(other: ReadonlySetLike<U>): Set<K | U> {
203
+ const others = {
204
+ [Symbol.iterator]() {
205
+ return other.keys()
206
+ },
207
+ }
208
+ const that = this
209
+ return new Set(
210
+ (function* () {
211
+ for (const value of that) if (!other.has(<U>(<unknown>value))) yield <K | U>value
212
+ for (const value of others) if (!that.has(<K>(<unknown>value))) yield <K | U>value
213
+ })()
214
+ )
215
+ }
216
+ isSubsetOf(other: ReadonlySetLike<unknown>): boolean {
217
+ for (const value of this) if (!other.has(value)) return false
218
+ return true
219
+ }
220
+ isSupersetOf(other: ReadonlySetLike<unknown>): boolean {
221
+ const others = {
222
+ [Symbol.iterator]() {
223
+ return other.keys()
224
+ },
225
+ }
226
+ for (const value of others) if (!this.has(<K>value)) return false
227
+ return true
228
+ }
229
+ isDisjointFrom(other: ReadonlySetLike<unknown>): boolean {
230
+ for (const value of this) if (other.has(value)) return false
231
+ return true
232
+ }
233
+ }
package/src/mixins.ts ADDED
@@ -0,0 +1,123 @@
1
+ import { isConstructor, ReflectGet } from './utils'
2
+
3
+ /**
4
+ * A mixin function that takes a base class and returns a new class with mixed-in functionality
5
+ * @template Mixed - The functionality to be mixed in
6
+ */
7
+ export type MixinFunction<Mixed> = <Base>(
8
+ base: new (...args: any[]) => Base
9
+ ) => new (
10
+ ...args: any[]
11
+ ) => Base & Mixed
12
+
13
+ /**
14
+ * A mixin class that can be used both as a base class and as a mixin function
15
+ * @template Mixed - The functionality to be mixed in
16
+ */
17
+ export type MixinClass<Mixed> = new (...args: any[]) => Mixed
18
+
19
+ /**
20
+ * Creates a mixin that can be used both as a class (extends) and as a function (mixin)
21
+ *
22
+ * This function supports:
23
+ * - Using mixins as base classes: `class MyClass extends MyMixin`
24
+ * - Using mixins as functions: `class MyClass extends MyMixin(SomeBase)`
25
+ * - Composing mixins: `const Composed = MixinA(MixinB)`
26
+ * - Type-safe property inference for all patterns
27
+ *
28
+ * @param mixinFunction - The function that creates the mixin
29
+ * @param unwrapFunction - Optional function to unwrap reactive objects for method calls
30
+ * @returns A mixin that can be used both as a class and as a function
31
+ */
32
+ export function mixin<MixinFn extends (base: any) => new (...args: any[]) => any>(
33
+ mixinFunction: MixinFn,
34
+ unwrapFunction?: (obj: any) => any
35
+ ): (new (
36
+ ...args: any[]
37
+ ) => InstanceType<ReturnType<MixinFn>>) &
38
+ (<Base>(
39
+ base: abstract new (...args: any[]) => Base
40
+ ) => new (
41
+ ...args: any[]
42
+ ) => InstanceType<ReturnType<MixinFn>> & Base) {
43
+ /**
44
+ * Cache for mixin results to ensure the same base class always returns the same mixed class
45
+ */
46
+ const mixinCache = new WeakMap<new (...args: any[]) => any, new (...args: any[]) => any>()
47
+
48
+ // Apply the mixin to Object as the base class
49
+ const MixedBase = mixinFunction(Object)
50
+ mixinCache.set(Object, MixedBase)
51
+
52
+ // Create the proxy that handles both constructor and function calls
53
+ return new Proxy(MixedBase, {
54
+ // Handle `MixinClass(SomeBase)` - use as mixin function
55
+ apply(_target, _thisArg, args) {
56
+ if (args.length === 0) {
57
+ throw new Error('Mixin requires a base class')
58
+ }
59
+
60
+ const baseClass = args[0]
61
+ if (typeof baseClass !== 'function') {
62
+ throw new Error('Mixin requires a constructor function')
63
+ }
64
+
65
+ // Check if it's a valid constructor or a mixin
66
+ if (
67
+ !isConstructor(baseClass) &&
68
+ !(baseClass && typeof baseClass === 'function' && baseClass.prototype)
69
+ ) {
70
+ throw new Error('Mixin requires a valid constructor')
71
+ }
72
+
73
+ // Check cache first
74
+ const cached = mixinCache.get(baseClass)
75
+ if (cached) {
76
+ return cached
77
+ }
78
+
79
+ let usedBase = baseClass
80
+ if (unwrapFunction) {
81
+ // Create a proxied base class that handles method unwrapping
82
+ const ProxiedBaseClass = class extends baseClass {}
83
+
84
+ // Proxy the prototype methods to handle unwrapping
85
+ const originalPrototype = baseClass.prototype
86
+ const proxiedPrototype = new Proxy(originalPrototype, {
87
+ get(target, prop, receiver) {
88
+ const value = ReflectGet(target, prop, receiver)
89
+
90
+ // Only wrap methods that are likely to access private fields
91
+ // Skip symbols and special properties that the reactive system needs
92
+ if (
93
+ typeof value === 'function' &&
94
+ typeof prop === 'string' &&
95
+ !['constructor', 'toString', 'valueOf'].includes(prop)
96
+ ) {
97
+ // Return a wrapped version that uses unwrapped context
98
+ return function (this: any, ...args: any[]) {
99
+ // Use the unwrapping function if provided, otherwise use this
100
+ const context = unwrapFunction(this as any)
101
+ return value.apply(context, args)
102
+ }
103
+ }
104
+
105
+ return value
106
+ },
107
+ })
108
+
109
+ // Set the proxied prototype
110
+ Object.setPrototypeOf(ProxiedBaseClass.prototype, proxiedPrototype)
111
+ usedBase = ProxiedBaseClass
112
+ }
113
+
114
+ // Create the mixed class using the proxied base class
115
+ const mixedClass = mixinFunction(usedBase)
116
+
117
+ // Cache the result
118
+ mixinCache.set(baseClass, mixedClass)
119
+
120
+ return mixedClass
121
+ },
122
+ }) as MixinFn & (new (...args: any[]) => InstanceType<ReturnType<MixinFn>>)
123
+ }
@@ -0,0 +1,110 @@
1
+ type Resolved<T> =
2
+ T extends Promise<infer U>
3
+ ? Resolved<U>
4
+ : T extends (...args: infer Args) => infer R
5
+ ? (...args: Args) => Resolved<R>
6
+ : T extends object
7
+ ? {
8
+ [k in keyof T]: k extends 'then' | 'catch' | 'finally' ? T[k] : Resolved<T[k]>
9
+ }
10
+ : T
11
+ type PromiseAnd<T> = Resolved<T> & Promise<Resolved<T>>
12
+ /**
13
+ * Type that transforms promises into chainable objects
14
+ * Allows calling methods directly on promise results without awaiting them first
15
+ */
16
+ export type PromiseChain<T> = T extends (...args: infer Args) => infer R
17
+ ? PromiseAnd<(...args: Args) => PromiseChain<Resolved<R>>>
18
+ : T extends object
19
+ ? PromiseAnd<{
20
+ [k in keyof T]: k extends 'then' | 'catch' | 'finally' ? T[k] : PromiseChain<Resolved<T[k]>>
21
+ }>
22
+ : Promise<Resolved<T>>
23
+
24
+ const forward =
25
+ (name: string, target: any) =>
26
+ (...args: any[]) => {
27
+ return target[name](...args)
28
+ }
29
+
30
+ const alreadyChained = new WeakMap<any, PromiseChain<any>>()
31
+ const originals = new WeakMap<Promise<any>, any>()
32
+
33
+ function cache(target: any, rv: PromiseChain<any>) {
34
+ originals.set(rv, target)
35
+ alreadyChained.set(target, rv)
36
+ }
37
+
38
+ type ChainedFunction<T> = ((...args: any[]) => PromiseChain<T>) & {
39
+ then: Promise<T>['then']
40
+ catch: Promise<T>['catch']
41
+ finally: Promise<T>['finally']
42
+ }
43
+
44
+ const promiseProxyHandler: ProxyHandler<ChainedFunction<any>> = {
45
+ //@ts-expect-error
46
+ [Symbol.toStringTag]: 'MutTs PromiseChain function',
47
+ get(target, prop) {
48
+ if (prop === Symbol.toStringTag) return 'PromiseProxy'
49
+ if (typeof prop === 'string' && ['then', 'catch', 'finally'].includes(prop))
50
+ return target[prop as keyof typeof target]
51
+ return chainPromise(target.then((r) => r[prop as keyof typeof r]))
52
+ },
53
+ }
54
+ const promiseForward = (target: any) => ({
55
+ // biome-ignore lint/suspicious/noThenProperty: This one is the whole point
56
+ then: forward('then', target),
57
+ catch: forward('catch', target),
58
+ finally: forward('finally', target),
59
+ })
60
+ const objectProxyHandler: ProxyHandler<any> = {
61
+ //@ts-expect-error
62
+ [Symbol.toStringTag]: 'MutTs PromiseChain object',
63
+ get(target, prop, receiver) {
64
+ const getter = Object.getOwnPropertyDescriptor(target, prop)?.get
65
+ const rv = getter ? getter.call(receiver) : target[prop]
66
+ // Allows fct.call or fct.apply to bypass the chain system
67
+ if (typeof target === 'function') return rv
68
+ return chainPromise(rv)
69
+ },
70
+ apply(target, thisArg, args) {
71
+ return chainPromise(target.apply(thisArg, args))
72
+ },
73
+ }
74
+ function chainObject<T extends object | Function>(given: T): PromiseChain<T> {
75
+ const rv = new Proxy(given, objectProxyHandler) as PromiseChain<T>
76
+ cache(given, rv)
77
+ return rv
78
+ }
79
+
80
+ function chainable(x: any): x is object | Function {
81
+ return x && ['function', 'object'].includes(typeof x)
82
+ }
83
+ /**
84
+ * Transforms a promise or value into a chainable object
85
+ * Allows calling methods directly on promise results without awaiting them first
86
+ * @param given - The promise or value to make chainable
87
+ * @returns A chainable version of the input
88
+ */
89
+ export function chainPromise<T>(given: Promise<T> | T): PromiseChain<T> {
90
+ if (!chainable(given)) return given as PromiseChain<T>
91
+ if (alreadyChained.has(given)) return alreadyChained.get(given) as PromiseChain<T>
92
+ if (!(given instanceof Promise)) return chainObject(given)
93
+ // @ts-expect-error It's ok as we check if it's an object above
94
+ given = given.then((r) => (chainable(r) ? chainObject(r) : r))
95
+ const target = Object.assign(function (this: any, ...args: any[]) {
96
+ return chainPromise(
97
+ given.then((r) => {
98
+ return this?.then
99
+ ? this.then((t: any) => (r as any).apply(t, args))
100
+ : (r as any).apply(this, args)
101
+ })
102
+ )
103
+ }, promiseForward(given)) as ChainedFunction<T>
104
+ const chained = new Proxy(
105
+ target,
106
+ promiseProxyHandler as ProxyHandler<ChainedFunction<T>>
107
+ ) as PromiseChain<T>
108
+ cache(given, chained as PromiseChain<any>)
109
+ return chained
110
+ }