jrx 0.3.0-alpha.7 → 0.3.0-alpha.9

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.
package/README.md CHANGED
@@ -18,7 +18,6 @@ npm i jrx
18
18
 
19
19
  - Automatic cleanup for all effects and subscriptions
20
20
  - Built on the native `DisposableStack` / `AsyncDisposableStack` API
21
- - Retry logic with exponential backoff and cancellation
22
21
  - Zero dependencies
23
22
  - Composable reactive utilities
24
23
  - Browser and Node.js compatible
@@ -34,8 +33,6 @@ npm i jrx
34
33
  - [`createAnimationFrameLoop(cb)`](#createAnimationFrameloopcb) - Animation frame loops
35
34
  - [`createTimeout(cb, ms)`](#createTimeoutcb-ms) - Timeouts with cleanup
36
35
  - [`createTransition(cb, durationMs)`](#createTransitioncb-durationms) - Progress-based animations
37
- - [`computed(fn, getDeps?)`](#computedfn-getdeps) - Memoized computed values
38
- - [`retry(cb, backoffSec?)`](#retrycb-backoffsec) - Retry with exponential backoff
39
36
  - [`assignDispose(value, disposable)`](#assigndisposevalue-disposable) - Attach a `Symbol.dispose` to any value
40
37
 
41
38
  ## Naming convention
@@ -236,76 +233,6 @@ const handle = createTransition((progress) => {
236
233
  handle[Symbol.dispose]()
237
234
  ```
238
235
 
239
- ### `computed(fn, getDeps?)`
240
-
241
- Creates a memoized computed value with optional dependency tracking.
242
-
243
- ```typescript
244
- import {computed} from 'jrx'
245
-
246
- // Without dependencies - always recomputes
247
- const value1 = computed(() => expensiveCalculation())
248
- console.log(value1.value) // Computed
249
- console.log(value1.value) // Computed again
250
-
251
- // With dependencies - memoizes when deps unchanged
252
- let a = 1, b = 2
253
- const value2 = computed(
254
- () => a + b,
255
- () => [a, b] // Dependencies
256
- )
257
-
258
- console.log(value2.value) // Computed: 3
259
- console.log(value2.value) // Cached: 3
260
-
261
- a = 10
262
- console.log(value2.value) // Recomputed: 12
263
- ```
264
-
265
- ### `retry(cb, backoffSec?)`
266
-
267
- Retries an operation with exponential backoff on failure. Returns `Disposable & Promise<T>`.
268
-
269
- **Default backoff:** `[5, 5, 10, 10, 20, 20, 40, 40, 60, -1]` seconds (where `-1` means retry forever with 60s delay)
270
-
271
- ```typescript
272
- import {retry} from 'jrx'
273
-
274
- // Basic usage - retries with default backoff
275
- const result = await retry(({resetBackoff}) => {
276
- const promise = fetch('/api/data').then((r) => r.json())
277
- return Object.assign(promise, {[Symbol.dispose]() {}})
278
- })
279
-
280
- // Custom backoff schedule (in seconds)
281
- await retry(
282
- () => {
283
- const promise = fetchData()
284
- return Object.assign(promise, {[Symbol.dispose]() {}})
285
- },
286
- [1, 2, 5, 10, -1], // -1 means retry forever with last delay
287
- )
288
-
289
- // Cancellation via Disposable
290
- const r = retry(
291
- ({resetBackoff}) => {
292
- const promise = fetchData()
293
- return Object.assign(promise, {[Symbol.dispose]() { /* cancel */ }})
294
- },
295
- [5, 10, 20, 40, -1],
296
- )
297
-
298
- // Cancel the retry loop
299
- r[Symbol.dispose]()
300
-
301
- // Returns undefined when disposed
302
- const data = await r // undefined
303
- ```
304
-
305
- **Parameters:**
306
- - `cb`: Callback that returns `Disposable & (T | Promise<T>)`. Receives `{ resetBackoff() }` to reset the backoff counter.
307
- - `backoffSec`: Array of retry delays in seconds. Use `-1` for infinite retries with the last delay. Default: `[5, 5, 10, 10, 20, 20, 40, 40, 60, -1]`
308
-
309
236
  ### `assignDispose(value, disposable)`
310
237
 
311
238
  Attaches a `Symbol.dispose` to an existing value (object, function, array, promise, etc.) that delegates to a given `Disposable`. Returns the same value, now also typed as `Disposable`.
@@ -341,6 +268,8 @@ function loadThing() {
341
268
  }
342
269
  ```
343
270
 
271
+ If `value` is itself a `Disposable`, disposing the returned value disposes `value` first, then `disposable`.
272
+
344
273
  ## Cleanup Pattern
345
274
 
346
275
  All effect functions return a `Disposable` object that stops the effect and runs any pending cleanup:
package/index.d.ts CHANGED
@@ -1,6 +1,3 @@
1
- import retry from './retry.js';
2
- import computed from './computed.js';
3
- export { retry, computed };
4
1
  export declare function makeReset(): () => DisposableStack;
5
2
  export declare function makeAsyncReset(): () => Promise<AsyncDisposableStack>;
6
3
  export declare function makeRenderLoop(): {
@@ -28,5 +25,5 @@ export declare function createTransition(cb: (progress: number) => undefined | D
28
25
  [Symbol.dispose](): void;
29
26
  };
30
27
  export declare function assignDispose<T extends object>(value: T, disposable: Disposable): T & {
31
- [Symbol.dispose]: () => void;
28
+ [Symbol.dispose](): void;
32
29
  };
package/index.js CHANGED
@@ -1,6 +1,3 @@
1
- import retry from './retry.js';
2
- import computed from './computed.js';
3
- export { retry, computed };
4
1
  export function makeReset() {
5
2
  let stack = new DisposableStack();
6
3
  return () => {
@@ -129,7 +126,11 @@ export function createTransition(cb, durationMs) {
129
126
  }
130
127
  }
131
128
  export function assignDispose(value, disposable) {
129
+ const valueDispose = value?.[Symbol.dispose]?.bind(value);
132
130
  return Object.assign(value, {
133
- [Symbol.dispose]: disposable[Symbol.dispose].bind(disposable),
131
+ [Symbol.dispose]() {
132
+ valueDispose?.();
133
+ disposable[Symbol.dispose]();
134
+ }
134
135
  });
135
136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jrx",
3
- "version": "0.3.0-alpha.7",
3
+ "version": "0.3.0-alpha.9",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "prepublishOnly": "npx tsc",
@@ -19,11 +19,7 @@
19
19
  },
20
20
  "files": [
21
21
  "index.js",
22
- "index.d.ts",
23
- "retry.js",
24
- "retry.d.ts",
25
- "computed.js",
26
- "computed.d.ts"
22
+ "index.d.ts"
27
23
  ],
28
24
  "devDependencies": {
29
25
  "@types/node": "^25.2.1",
package/computed.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export default function computed<T, Deps extends any[] = unknown[]>(fn: () => T, getDeps?: () => Deps): {
2
- readonly value: T;
3
- };
package/computed.js DELETED
@@ -1,17 +0,0 @@
1
- export default function computed(fn, getDeps) {
2
- let cached;
3
- let lastDeps;
4
- let first = true;
5
- return {
6
- get value() {
7
- if (!getDeps)
8
- return fn();
9
- const deps = getDeps();
10
- if (!first && deps.length === lastDeps.length && deps.every((dep, idx) => Object.is(dep, lastDeps[idx])))
11
- return cached;
12
- first = false;
13
- lastDeps = deps;
14
- return (cached = fn());
15
- },
16
- };
17
- }
package/retry.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export default function retry<T>(cb: (info: {
2
- resetBackoff(): void;
3
- }) => T | Promise<T>, backoffSec?: number[]): Disposable & Promise<T | undefined>;
package/retry.js DELETED
@@ -1,35 +0,0 @@
1
- import { makeReset } from './index.js';
2
- export default function retry(cb, backoffSec = [5, 5, 10, 10, 20, 20, 40, 40, 60, -1]) {
3
- const stack = new DisposableStack();
4
- const reset = makeReset();
5
- stack.defer(reset);
6
- let count = 0;
7
- let loopStack = reset();
8
- return Object.assign((async () => {
9
- while (true) {
10
- if (backoffSec[count] !== -1)
11
- count++;
12
- try {
13
- if (loopStack.disposed)
14
- return;
15
- const value = cb({
16
- resetBackoff() {
17
- count = 1;
18
- },
19
- });
20
- return value?.[Symbol.dispose] ? loopStack.use(value) : value;
21
- }
22
- catch (e) {
23
- if (stack.disposed)
24
- return;
25
- if (count > backoffSec.length) {
26
- console.error('max retries reached:', e);
27
- throw e;
28
- }
29
- console.warn('Retrying due to error:', e);
30
- loopStack = reset();
31
- await new Promise(resolve => setTimeout(resolve, backoffSec[count - 1] * 1000));
32
- }
33
- }
34
- })(), { [Symbol.dispose]: stack[Symbol.dispose].bind(stack) });
35
- }