@doenet/doenetml-iframe 0.7.24 → 0.7.25-dev.499

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
@@ -289,6 +289,9 @@ again (parked when off-screen and over budget).
289
289
  Notes:
290
290
 
291
291
  - Eviction is least-recently-visible first.
292
+ - A boot slot is released when the viewer's document initializes *or* when
293
+ its core cannot be started at all, so a failed activity does not hold a
294
+ slot until the wrapper's 90 s boot watchdog expires.
292
295
  - While parked, a viewer emits no reports (its state was flushed at park
293
296
  time). A host `SPLICE.flushState` broadcast is answered by the wrapper on
294
297
  the parked viewer's behalf, so pre-navigation flush round-trips don't
@@ -392,6 +395,33 @@ booted yet) — equally safe to unmount.
392
395
  > safe. Every viewer on the page receives a broadcast request and responds
393
396
  > (correlate by `activity_id`/`doc_id`/`message_id`).
394
397
 
398
+ #### The page going away flushes on its own
399
+
400
+ A host need not send `flushState` for an ordinary departure. The viewer
401
+ flushes whatever the throttle is holding back when the page hides — on
402
+ `pagehide` and on a `visibilitychange` to `hidden` — so closing the tab,
403
+ typing a new URL, following an external link, or backgrounding a tab on a
404
+ phone no longer strands up to a minute of work. The flushed work arrives on
405
+ your window as an ordinary `SPLICE.reportScoreAndState` message, so a host
406
+ that already persists those saves it with no extra code. Nothing is torn
407
+ down on the way, so a page that comes back — a re-foregrounded tab, a
408
+ back/forward-cache restore — carries on with its state already saved.
409
+
410
+ > **Important:** for this to survive a real unload, your listener has to
411
+ > persist **synchronously**. The report is handed over by dispatching the
412
+ > message event directly rather than posting it, because a document being
413
+ > unloaded is destroyed before a posted message is ever delivered — but a
414
+ > listener that defers its own write (a `fetch`, a `setTimeout`, an `await`)
415
+ > is destroyed just the same. Write from the listener itself, with
416
+ > `navigator.sendBeacon` or a synchronous store such as `localStorage`.
417
+ >
418
+ > The `reportScoreAndStateCallback` prop does not get this guarantee here:
419
+ > the viewer runs inside the iframe, so calling your callback crosses the
420
+ > frame boundary as a posted message, which an unloading page will not
421
+ > deliver. Listen for `SPLICE.reportScoreAndState` on your window if
422
+ > surviving an unload matters. (Everything else — routine reports, and
423
+ > flushes you requested yourself — reaches the callback as before.)
424
+
395
425
  ### Loading saved state at boot (`SPLICE.getState`)
396
426
 
397
427
  With `flags: { allowLoadState: true }` and no `initialState` prop, the
@@ -417,10 +447,31 @@ respond:
417
447
  { subject: "SPLICE.getState.response", message_id, state }
418
448
  ```
419
449
 
450
+ Quote the `message_id`: a response carrying state is only read by the viewer
451
+ whose request it names. Replies reach every viewer in the window, and `cid`
452
+ cannot tell two of them apart — it hashes the DoenetML text alone, so a
453
+ second attempt at the same document, or that document opened twice on a
454
+ page, carries the identical `cid`. An unaddressed answer would be restored
455
+ by all of them.
456
+
420
457
  If there is no saved state, no response is needed. To surface a load
421
458
  failure to the student instead, respond with
422
- `{ subject: "SPLICE.getState.response", error: { code, message } }`
423
- (and no `message_id`).
459
+ `{ subject: "SPLICE.getState.response", error: { code, message } }`,
460
+ either quoting the request's `message_id` or leaving it out — an error is
461
+ the one reply the viewer will take unaddressed, since the worst it costs is
462
+ a message the next usable answer clears. Prefer quoting it even so: an
463
+ unaddressed error is taken by whichever request is open when it lands, on
464
+ every viewer on the page, including one a rebuild opened after the error was
465
+ sent. A reply quoting a *different* id is ignored, since that id belongs to
466
+ some other request.
467
+
468
+ A request has a single answer: the **first** response carrying state for
469
+ this `cid` is the one the viewer reboots from, and every response after
470
+ that — errors included — is ignored. A response with no state — or state for a
471
+ different `cid` — does not count as that answer, so a listener with nothing
472
+ saved cannot shut out one still in flight. Answer once, out of durable
473
+ storage: a host that replies from an in-memory cache first and from storage
474
+ afterwards keeps the cache's answer.
424
475
 
425
476
  Passing `initialState` yourself (or `initialState: null` for "start
426
477
  fresh") skips this request entirely.