Session.on ​

Contract 2.0.0 · package sha256 a857eca95b35921109faf997094bb4192f12527d9d0fcd4be7e97f06425bad6e · generated from configurator-runtime.d.ts by services/onsite-scripter/scripts/build-contract-docs.mjs; edit the source, not this file.

Method of Session · inherited by testing.FakeSession · stable · since 2.0.0 · called as session.on

ts
on<K extends keyof Events, R>(event: K, handler: (payload: Events[K]) => NotAsync<R>, options?: SignalOption): () => void;

Subscribes. Lifecycle call: immediate; unsubscribe is terminal. Handlers run synchronously, never nested: a state event's after the presented frame, in seq order; 'problem' at once, when the Problem is recorded (spec section 6.11). An async handler is a type error. A handler removed during dispatch is skipped for the rest of that round. A write in a handler is a new commit whose events follow this round. Returns the unsubscribe function; aborting signal unsubscribes the same way, and nothing rejects. Errors: an unknown event records 'unknown-event' and returns a no-op unsubscribe; a handler that throws records 'handler-threw', one that returns a Promise 'handler-async', and that Promise's rejection 'handler-rejected'. A 'problem' handler's own failure is recorded with event 'problem' but fires no further 'problem' event. Not for: layout that must show in the same frame as the commit, which is beforeCommit.

Options ​

Option Type Default What it does
signal AbortSignal undefined Cancels this call; the member's JSDoc says what an abort does.

Abort (signal) ​

This call is a registration (SignalOption.signal, the kinds of call).

A registration (on, beforeCommit): aborting removes it and nothing rejects.

A creator (collection for a new name, materials.create, on, onFrame, beforeCommit, follow, input.drag, labs.lightLinking) given a signal already aborted returns at once, already ended: a Collection or Material reading disposed: true that holds no content and no live name, or a registration that never runs and whose disposer does nothing.

It records no Problem for the abort and throws only what it would throw anyway, as the DOM's addEventListener with an aborted signal adds nothing (spec section 6.5).

Example ​

Imports: values (has, validate, the Holo*Error classes, the pure helpers) from @holostep-configurators/runtime-client, types from @holostep-configurators/runtime-client/contract, /math and /testing names from those entries; boot from the runtime module the root's loadRuntimeAtFloor resolves to. A type your page defines is your app's: declare it there, never import it from the package.

Compiled under the contract's strict settings (examples/declaration/05-Session.on.ts):

ts
import type { Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
declare const analytics: { track(name: string, props: Record<string, string | number>): void };
session.on('committed', ({ cause, label, recorded, patch }) => {
  // skip our own sync and look-only commits
  if (cause.origin === 'store-sync' || !recorded) return;
  analytics.track('configuration-change', {
    actor: cause.actor, label: label ?? '', ops: patch.length,
  });
}, { signal });

Generic-API test (spec 3.1) ​

Rule Result
1. Neutral name pass: on names no product
2. A precedent not recorded: no ledger row (coverage.json) names this member or its owner
3. Two apps, or labs pass: 21 apps (fleet cross-check: app-04c2774145, app-0c773a4ee3, app-37356bf09f, app-378d190f1b, app-4762caacdc, app-4fd23bc869, app-822bb9d6aa, app-8675b3225c and 13 more)
4. The cheaper fix first not recorded per member (Appendix B decides it per need)