@ai-matrx/media 0.5.12 → 0.6.1
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/CHANGELOG.md +31 -0
- package/dist/core.cjs +76 -8
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +7 -1
- package/dist/core.d.ts +7 -1
- package/dist/core.js +76 -8
- package/dist/core.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -3
- package/dist/index.d.ts +90 -3
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +86 -15
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +86 -15
- package/dist/react.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# @ai-matrx/media
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/media/v0.6.0..npm/media/v0.6.1 -- apps/shared/media`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.6.0
|
|
10
|
+
|
|
11
|
+
**The heal ladder — the user is never denied while any lane works, and a
|
|
12
|
+
render that heals itself is logged as loudly as one that dies.**
|
|
13
|
+
|
|
14
|
+
- `MediaClient.healLoadError?(ref, {src, attempts})` (optional): runs AFTER the
|
|
15
|
+
ONE retry policy is exhausted; returns `MediaHealResult` — the lanes tried
|
|
16
|
+
(`MediaHealAttempt[]`: lane, outcome, status, ms, host), the lane that
|
|
17
|
+
healed (`healedBy`), a NAMED root cause (`MediaHealDiagnosis`, e.g.
|
|
18
|
+
`cookie-not-sent-by-browser`, `bearer-rejected`, `primary-host-down-alternate-served`)
|
|
19
|
+
and a plain-English `summary`.
|
|
20
|
+
- `useMediaLoadRecovery` returns `healedSrc` (a `blob:` object URL from the
|
|
21
|
+
bearer lane) — bind it instead of the dead src. `InlineMediaRef` and the
|
|
22
|
+
thumbnails do so already.
|
|
23
|
+
- `MediaFailureInfo` gains `healed`, `healedBy`, `attempts`, `diagnosis` and
|
|
24
|
+
the `"heal"` phase. A healed render captures `terminal: false, healed: true`
|
|
25
|
+
with the full ladder; hosts MUST persist it like a dead one (matrx-frontend
|
|
26
|
+
does: `code = "healed:<diagnosis>"`, `durable: true`).
|
|
27
|
+
- Clients without a ladder keep the pre-0.6 phases/messages exactly, with a
|
|
28
|
+
suffix saying no ladder ran.
|
|
29
|
+
|
|
30
|
+
Why: 2026-09-16, a private image 401'd twice in Arman's Chrome (third-party
|
|
31
|
+
cookies blocked) and rendered "Image unavailable" while the bearer lane would
|
|
32
|
+
have served it the whole time; the DB row said only "failed after retry".
|
|
33
|
+
|
|
3
34
|
## 0.5.12
|
|
4
35
|
|
|
5
36
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
package/dist/core.cjs
CHANGED
|
@@ -207,7 +207,7 @@ function useMediaLoadRecovery(src, options) {
|
|
|
207
207
|
const recoverable = options?.recoverable !== false;
|
|
208
208
|
const onTerminal = options?.onTerminal;
|
|
209
209
|
const failureRef = options?.failureRef;
|
|
210
|
-
const [result, setResult] = (0, import_react4.useState)({ source: src, retryKey: 0, failed: false });
|
|
210
|
+
const [result, setResult] = (0, import_react4.useState)({ source: src, retryKey: 0, failed: false, healedSrc: null });
|
|
211
211
|
const attemptRef = (0, import_react4.useRef)(0);
|
|
212
212
|
const recoveryInFlightRef = (0, import_react4.useRef)(false);
|
|
213
213
|
(0, import_react4.useEffect)(() => {
|
|
@@ -221,7 +221,7 @@ function useMediaLoadRecovery(src, options) {
|
|
|
221
221
|
const onLoadError = (event) => {
|
|
222
222
|
if (recoveryInFlightRef.current) return;
|
|
223
223
|
if (!src || !recoverable) {
|
|
224
|
-
setResult({ source: src, retryKey: 0, failed: true });
|
|
224
|
+
setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
|
|
225
225
|
if (src) {
|
|
226
226
|
capture({
|
|
227
227
|
phase: "element-load",
|
|
@@ -252,23 +252,90 @@ function useMediaLoadRecovery(src, options) {
|
|
|
252
252
|
setResult((current) => ({
|
|
253
253
|
source: src,
|
|
254
254
|
retryKey: current.source === src ? current.retryKey + 1 : 1,
|
|
255
|
-
failed: false
|
|
255
|
+
failed: false,
|
|
256
|
+
healedSrc: null
|
|
256
257
|
}));
|
|
257
|
-
|
|
258
|
-
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const lane1 = {
|
|
261
|
+
lane: "session-refresh-retry",
|
|
262
|
+
outcome: attempt > 1 ? "http-error" : "unavailable",
|
|
263
|
+
ms: 0,
|
|
264
|
+
...report.status !== void 0 ? { status: report.status } : {},
|
|
265
|
+
detail: attempt > 1 ? "cookie re-minted, same durable URL retried in the element, element errored again" : "recovery declined on the first attempt (no usable session)"
|
|
266
|
+
};
|
|
267
|
+
if (!failureRef || !client.healLoadError) {
|
|
268
|
+
setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
|
|
259
269
|
capture({
|
|
260
270
|
phase: attempt > 1 ? "element-load" : "recovery",
|
|
261
271
|
mediaRef: identity(),
|
|
262
272
|
terminal: true,
|
|
263
273
|
retryOutcome: attempt > 1 ? "retried" : "not-attempted",
|
|
264
|
-
message: attempt > 1 ? "media element failed to load after the session-refresh retry" : "media load recovery declined on the first attempt (session refresh did not produce a usable session)",
|
|
274
|
+
message: (attempt > 1 ? "media element failed to load after the session-refresh retry" : "media load recovery declined on the first attempt (session refresh did not produce a usable session)") + (failureRef ? " \u2014 no heal ladder on this client (healLoadError not implemented)" : " \u2014 no durable ref supplied, so no heal lane could run"),
|
|
265
275
|
...report.status !== void 0 ? { status: report.status } : {}
|
|
266
276
|
});
|
|
267
277
|
onTerminal?.(event);
|
|
278
|
+
return;
|
|
268
279
|
}
|
|
280
|
+
const heal = client.healLoadError(failureRef, {
|
|
281
|
+
src: mintDurableSrc(src),
|
|
282
|
+
attempts: [lane1]
|
|
283
|
+
});
|
|
284
|
+
heal.then(
|
|
285
|
+
(verdict) => {
|
|
286
|
+
if (verdict.src) {
|
|
287
|
+
setResult({
|
|
288
|
+
source: src,
|
|
289
|
+
retryKey: 0,
|
|
290
|
+
failed: false,
|
|
291
|
+
healedSrc: verdict.src
|
|
292
|
+
});
|
|
293
|
+
capture({
|
|
294
|
+
phase: "heal",
|
|
295
|
+
mediaRef: identity(),
|
|
296
|
+
terminal: false,
|
|
297
|
+
healed: true,
|
|
298
|
+
healedBy: verdict.healedBy,
|
|
299
|
+
attempts: verdict.attempts,
|
|
300
|
+
diagnosis: verdict.diagnosis,
|
|
301
|
+
retryOutcome: "retried",
|
|
302
|
+
message: `HEALED (${verdict.healedBy ?? "unknown lane"}): ${verdict.summary}`,
|
|
303
|
+
...report.status !== void 0 ? { status: report.status } : {}
|
|
304
|
+
});
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
|
|
308
|
+
capture({
|
|
309
|
+
phase: "heal",
|
|
310
|
+
mediaRef: identity(),
|
|
311
|
+
terminal: true,
|
|
312
|
+
healed: false,
|
|
313
|
+
attempts: verdict.attempts,
|
|
314
|
+
diagnosis: verdict.diagnosis,
|
|
315
|
+
retryOutcome: "retried",
|
|
316
|
+
message: `DEAD after ${verdict.attempts.length} lane(s): ${verdict.summary}`,
|
|
317
|
+
...report.status !== void 0 ? { status: report.status } : {}
|
|
318
|
+
});
|
|
319
|
+
onTerminal?.(event);
|
|
320
|
+
},
|
|
321
|
+
(err) => {
|
|
322
|
+
setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
|
|
323
|
+
capture({
|
|
324
|
+
phase: "heal",
|
|
325
|
+
mediaRef: identity(),
|
|
326
|
+
terminal: true,
|
|
327
|
+
healed: false,
|
|
328
|
+
attempts: [lane1],
|
|
329
|
+
diagnosis: "unknown",
|
|
330
|
+
retryOutcome: "recovery-failed",
|
|
331
|
+
message: `heal ladder threw: ${err instanceof Error ? err.message : String(err ?? "unknown error")}`
|
|
332
|
+
});
|
|
333
|
+
onTerminal?.(event);
|
|
334
|
+
}
|
|
335
|
+
);
|
|
269
336
|
},
|
|
270
337
|
(err) => {
|
|
271
|
-
setResult({ source: src, retryKey: 0, failed: true });
|
|
338
|
+
setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
|
|
272
339
|
capture({
|
|
273
340
|
phase: "session",
|
|
274
341
|
mediaRef: identity(),
|
|
@@ -283,7 +350,8 @@ function useMediaLoadRecovery(src, options) {
|
|
|
283
350
|
return {
|
|
284
351
|
retryKey: result.source === src ? result.retryKey : 0,
|
|
285
352
|
onLoadError,
|
|
286
|
-
failed: result.source === src ? result.failed : false
|
|
353
|
+
failed: result.source === src ? result.failed : false,
|
|
354
|
+
healedSrc: result.source === src ? result.healedSrc : null
|
|
287
355
|
};
|
|
288
356
|
}
|
|
289
357
|
|