@rindle/remote 0.10.0 → 0.10.2
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/dist/mutation-queue.d.ts
CHANGED
|
@@ -13,7 +13,9 @@ export interface QueuedMutationSenderOptions {
|
|
|
13
13
|
/** A policy rejection for one envelope (never retried; the prediction snaps back via the
|
|
14
14
|
* lmid release — this callback is where the reason reaches the app). */
|
|
15
15
|
onRejected?: (envelope: MutationEnvelope, reason: string) => void;
|
|
16
|
-
/** A failed flush attempt, before its retry
|
|
16
|
+
/** A failed flush attempt, before its retry. The ONLY surface for a transport/authority
|
|
17
|
+
* failure: `send` throwing is otherwise absorbed by the retry loop, so a queue built without
|
|
18
|
+
* this hook fails perfectly silently while head-of-line blocking every later mutation. */
|
|
17
19
|
onError?: (err: unknown, attempt: number) => void;
|
|
18
20
|
/** Backoff before retry `attempt` (1-based). Default: 200ms · 2^(attempt-1), capped at 5s. */
|
|
19
21
|
retryDelayMs?: (attempt: number) => number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation-queue.d.ts","sourceRoot":"","sources":["../src/mutation-queue.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C;;uFAEmF;IACnF,IAAI,EAAE,CAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAAC;IACvE;6EACyE;IACzE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClE
|
|
1
|
+
{"version":3,"file":"mutation-queue.d.ts","sourceRoot":"","sources":["../src/mutation-queue.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C;;uFAEmF;IACnF,IAAI,EAAE,CAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAAC;IACvE;6EACyE;IACzE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClE;;+FAE2F;IAC3F,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,8FAA8F;IAC9F,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAwBD;yEACyE;AACzE,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,2BAA2B,GAAG,sBAAsB,CA4CpG"}
|
package/dist/mutation-queue.js
CHANGED
|
@@ -12,6 +12,17 @@
|
|
|
12
12
|
// surfaces here through `onRejected` (the wire itself carries no rejection signal).
|
|
13
13
|
const defaultDelay = (attempt) => Math.min(200 * 2 ** (attempt - 1), 5_000);
|
|
14
14
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
|
+
/** Run an app-supplied observer without letting it break the queue. A throw escaping `flush`
|
|
16
|
+
* would abandon the loop with envelopes still queued and nothing scheduled to drain them —
|
|
17
|
+
* the notification hooks must not be able to wedge the write path they report on. */
|
|
18
|
+
const notify = (what, fn) => {
|
|
19
|
+
try {
|
|
20
|
+
fn();
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
console.error(`[rindle] mutation queue ${what} handler threw:`, err);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
15
26
|
/** A `MutationEnvelopeSender` (the `pushMutation` option of `RemoteOptimisticSource`) that
|
|
16
27
|
* queues envelopes and delivers them as confirmed, in-order batches. */
|
|
17
28
|
export function createQueuedMutationSender(opts) {
|
|
@@ -33,7 +44,7 @@ export function createQueuedMutationSender(opts) {
|
|
|
33
44
|
break;
|
|
34
45
|
}
|
|
35
46
|
catch (err) {
|
|
36
|
-
opts.onError?.(err, attempt);
|
|
47
|
+
notify("onError", () => opts.onError?.(err, attempt));
|
|
37
48
|
await sleep(delay(attempt));
|
|
38
49
|
}
|
|
39
50
|
}
|
|
@@ -41,7 +52,8 @@ export function createQueuedMutationSender(opts) {
|
|
|
41
52
|
batch.forEach((pending, i) => {
|
|
42
53
|
const outcome = Array.isArray(outcomes) ? outcomes[i] : undefined;
|
|
43
54
|
if (outcome && !outcome.accepted) {
|
|
44
|
-
|
|
55
|
+
const reason = outcome.reason ?? "mutation rejected";
|
|
56
|
+
notify("onRejected", () => opts.onRejected?.(pending.envelope, reason));
|
|
45
57
|
}
|
|
46
58
|
pending.resolve();
|
|
47
59
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation-queue.js","sourceRoot":"","sources":["../src/mutation-queue.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,4FAA4F;AAC5F,0FAA0F;AAC1F,0FAA0F;AAC1F,2FAA2F;AAC3F,4FAA4F;AAC5F,EAAE;AACF,0FAA0F;AAC1F,uFAAuF;AACvF,wFAAwF;AACxF,4FAA4F;AAC5F,oFAAoF;
|
|
1
|
+
{"version":3,"file":"mutation-queue.js","sourceRoot":"","sources":["../src/mutation-queue.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rindle/remote",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@rindle/client": "0.10.
|
|
28
|
+
"@rindle/client": "0.10.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^22.10.0",
|
package/src/mutation-queue.ts
CHANGED
|
@@ -29,7 +29,9 @@ export interface QueuedMutationSenderOptions {
|
|
|
29
29
|
/** A policy rejection for one envelope (never retried; the prediction snaps back via the
|
|
30
30
|
* lmid release — this callback is where the reason reaches the app). */
|
|
31
31
|
onRejected?: (envelope: MutationEnvelope, reason: string) => void;
|
|
32
|
-
/** A failed flush attempt, before its retry
|
|
32
|
+
/** A failed flush attempt, before its retry. The ONLY surface for a transport/authority
|
|
33
|
+
* failure: `send` throwing is otherwise absorbed by the retry loop, so a queue built without
|
|
34
|
+
* this hook fails perfectly silently while head-of-line blocking every later mutation. */
|
|
33
35
|
onError?: (err: unknown, attempt: number) => void;
|
|
34
36
|
/** Backoff before retry `attempt` (1-based). Default: 200ms · 2^(attempt-1), capped at 5s. */
|
|
35
37
|
retryDelayMs?: (attempt: number) => number;
|
|
@@ -48,6 +50,17 @@ const defaultDelay = (attempt: number): number => Math.min(200 * 2 ** (attempt -
|
|
|
48
50
|
|
|
49
51
|
const sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));
|
|
50
52
|
|
|
53
|
+
/** Run an app-supplied observer without letting it break the queue. A throw escaping `flush`
|
|
54
|
+
* would abandon the loop with envelopes still queued and nothing scheduled to drain them —
|
|
55
|
+
* the notification hooks must not be able to wedge the write path they report on. */
|
|
56
|
+
const notify = (what: string, fn: () => void): void => {
|
|
57
|
+
try {
|
|
58
|
+
fn();
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error(`[rindle] mutation queue ${what} handler threw:`, err);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
51
64
|
/** A `MutationEnvelopeSender` (the `pushMutation` option of `RemoteOptimisticSource`) that
|
|
52
65
|
* queues envelopes and delivers them as confirmed, in-order batches. */
|
|
53
66
|
export function createQueuedMutationSender(opts: QueuedMutationSenderOptions): MutationEnvelopeSender {
|
|
@@ -68,7 +81,7 @@ export function createQueuedMutationSender(opts: QueuedMutationSenderOptions): M
|
|
|
68
81
|
outcomes = await opts.send(batch.map((p) => p.envelope));
|
|
69
82
|
break;
|
|
70
83
|
} catch (err) {
|
|
71
|
-
opts.onError?.(err, attempt);
|
|
84
|
+
notify("onError", () => opts.onError?.(err, attempt));
|
|
72
85
|
await sleep(delay(attempt));
|
|
73
86
|
}
|
|
74
87
|
}
|
|
@@ -76,7 +89,8 @@ export function createQueuedMutationSender(opts: QueuedMutationSenderOptions): M
|
|
|
76
89
|
batch.forEach((pending, i) => {
|
|
77
90
|
const outcome = Array.isArray(outcomes) ? outcomes[i] : undefined;
|
|
78
91
|
if (outcome && !outcome.accepted) {
|
|
79
|
-
|
|
92
|
+
const reason = outcome.reason ?? "mutation rejected";
|
|
93
|
+
notify("onRejected", () => opts.onRejected?.(pending.envelope, reason));
|
|
80
94
|
}
|
|
81
95
|
pending.resolve();
|
|
82
96
|
});
|