@econ-v1/ports 7.0.45 → 7.0.47

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.
@@ -10,8 +10,44 @@ export type ShellCacheResetPort = {
10
10
  * healthy the node is. Told apart, the two cases need opposite advice: an offline node is
11
11
  * fixed by reconnecting and retrying, an uncontrolled page never is — retrying re-runs the
12
12
  * identical failure, and only re-establishing a worker recovers it.
13
+ *
14
+ * `activateWaitingUpdate` is the recovery for the OTHER stale-worker failure: a page that IS
15
+ * controlled, by a worker one build behind the node. Its precached shell chunk statically
16
+ * references a content-hashed chunk that is deliberately NOT precached
17
+ * (`LIVE_ONLY_STAGE_ASSET_RE`), so after the node is redeployed that reference 404s and the
18
+ * stage can never open — Retry re-runs the identical fetch. Re-checking the worker script and
19
+ * handing over to whatever a fresh `update()` finds is the only recovery.
20
+ *
21
+ * The worker does NOT wait for the user to accept an update — `service-worker-runtime.js`'s
22
+ * `install` handler calls `skipWaiting()` UNCONDITIONALLY at the end of every install. What
23
+ * actually leaves a page stale is that nothing on the long-lived tab ever calls
24
+ * `registration.update()` in reaction to a stage failing to import: the old shell simply sits on
25
+ * screen, still fully functional for everything it already has cached, until the next real
26
+ * navigation. Combined with `skipWaiting()`'s immediacy, a fresh `update()` call can land and
27
+ * self-activate a new worker (`installing` -> `activating` -> `activated` ->
28
+ * `clients.claim()`) between one microtask and the next — so by the time this function can look,
29
+ * `registration.waiting` may already be `null` again, consumed rather than never populated.
30
+ * Reporting `false` in that case would be treating "didn't catch it in `waiting`" as "nothing
31
+ * happened", so this also succeeds when `update()` demonstrably found something even though
32
+ * nothing was left sitting in `waiting`: the page's controller already changed, a new worker is
33
+ * still `installing`, or a new worker already reached `active` without (yet) being this page's
34
+ * controller. Resolves `true` in any of those cases; the reload itself is left to the existing
35
+ * `controllerchange` handler.
36
+ *
37
+ * That reload is a GUARANTEE only for the first two of the four `true`-resolving cases above (a
38
+ * worker was actually messaged, or the controller had already changed) — both are proof a
39
+ * handoff already happened or was just requested directly. The other two are PREDICTIONS that a
40
+ * `controllerchange` is coming, not proof of it: a worker `installing` can still have its install
41
+ * rejected (never reaching waiting/active), and a worker that reached `active` can still fail
42
+ * inside its own `activate` cleanup in a way that stops `clients.claim()` from ever running,
43
+ * per spec, without preventing the worker from being considered "activated". A caller that shows
44
+ * a blocking "reload is coming" panel on `true` cannot treat the reload as certain — it needs its
45
+ * own bounded fallback for the two predicted cases (`client/ui/src/shell/app-shell.js`'s
46
+ * `#armStaleShellHandoverFallback`, 2026-09-06 review) rather than trusting this method's
47
+ * `true` to always end in a page navigation.
13
48
  */
14
49
  export type ShellWorkerControlPort = {
15
50
  isControlled(): boolean;
51
+ activateWaitingUpdate(): Promise<boolean>;
16
52
  };
17
53
  //# sourceMappingURL=shell-cache-reset.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shell-cache-reset.d.ts","sourceRoot":"","sources":["../src/shell-cache-reset.js"],"names":[],"mappings":"kCACc;IAAE,KAAK,IAAI,IAAI,CAAA;CAAE;;;;;;;;;;;qCAWlB;IAAE,YAAY,IAAI,OAAO,CAAA;CAAE"}
1
+ {"version":3,"file":"shell-cache-reset.d.ts","sourceRoot":"","sources":["../src/shell-cache-reset.js"],"names":[],"mappings":"kCACc;IAAE,KAAK,IAAI,IAAI,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qCA8ClB;IACR,YAAY,IAAI,OAAO,CAAC;IACxB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@econ-v1/ports",
3
- "version": "7.0.45",
3
+ "version": "7.0.47",
4
4
  "description": "Platform-neutral ports for Node client applications",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "author": "Node contributors",
@@ -10,6 +10,44 @@
10
10
  * fixed by reconnecting and retrying, an uncontrolled page never is — retrying re-runs the
11
11
  * identical failure, and only re-establishing a worker recovers it.
12
12
  *
13
- * @typedef {{ isControlled(): boolean }} ShellWorkerControlPort
13
+ * `activateWaitingUpdate` is the recovery for the OTHER stale-worker failure: a page that IS
14
+ * controlled, by a worker one build behind the node. Its precached shell chunk statically
15
+ * references a content-hashed chunk that is deliberately NOT precached
16
+ * (`LIVE_ONLY_STAGE_ASSET_RE`), so after the node is redeployed that reference 404s and the
17
+ * stage can never open — Retry re-runs the identical fetch. Re-checking the worker script and
18
+ * handing over to whatever a fresh `update()` finds is the only recovery.
19
+ *
20
+ * The worker does NOT wait for the user to accept an update — `service-worker-runtime.js`'s
21
+ * `install` handler calls `skipWaiting()` UNCONDITIONALLY at the end of every install. What
22
+ * actually leaves a page stale is that nothing on the long-lived tab ever calls
23
+ * `registration.update()` in reaction to a stage failing to import: the old shell simply sits on
24
+ * screen, still fully functional for everything it already has cached, until the next real
25
+ * navigation. Combined with `skipWaiting()`'s immediacy, a fresh `update()` call can land and
26
+ * self-activate a new worker (`installing` -> `activating` -> `activated` ->
27
+ * `clients.claim()`) between one microtask and the next — so by the time this function can look,
28
+ * `registration.waiting` may already be `null` again, consumed rather than never populated.
29
+ * Reporting `false` in that case would be treating "didn't catch it in `waiting`" as "nothing
30
+ * happened", so this also succeeds when `update()` demonstrably found something even though
31
+ * nothing was left sitting in `waiting`: the page's controller already changed, a new worker is
32
+ * still `installing`, or a new worker already reached `active` without (yet) being this page's
33
+ * controller. Resolves `true` in any of those cases; the reload itself is left to the existing
34
+ * `controllerchange` handler.
35
+ *
36
+ * That reload is a GUARANTEE only for the first two of the four `true`-resolving cases above (a
37
+ * worker was actually messaged, or the controller had already changed) — both are proof a
38
+ * handoff already happened or was just requested directly. The other two are PREDICTIONS that a
39
+ * `controllerchange` is coming, not proof of it: a worker `installing` can still have its install
40
+ * rejected (never reaching waiting/active), and a worker that reached `active` can still fail
41
+ * inside its own `activate` cleanup in a way that stops `clients.claim()` from ever running,
42
+ * per spec, without preventing the worker from being considered "activated". A caller that shows
43
+ * a blocking "reload is coming" panel on `true` cannot treat the reload as certain — it needs its
44
+ * own bounded fallback for the two predicted cases (`client/ui/src/shell/app-shell.js`'s
45
+ * `#armStaleShellHandoverFallback`, 2026-09-06 review) rather than trusting this method's
46
+ * `true` to always end in a page navigation.
47
+ *
48
+ * @typedef {{
49
+ * isControlled(): boolean,
50
+ * activateWaitingUpdate(): Promise<boolean>,
51
+ * }} ShellWorkerControlPort
14
52
  */
15
53
  export {};