Session.transaction ​

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.transaction

ts
transaction<T>(work: (tx: Tx) => T | Promise<T>, options?: TransactionOptions): Promise<TransactionReport<T>>;

One all-or-nothing change that may await (loads, attach). Only writes through tx and handles obtained from it belong to it; they take member options only. Outside writes made while it is open never join: they are queued (default), supersede it (supersede: true), or are refused 'busy' (expectRevision). A second transaction() while one is open is an outside write: queued transactions run in call order and never coalesce.

Options ​

Option Type Default What it does
actor Actor the expectGroup's actor when one is given, else 'app' Who made the write.
checkpoint JsonValue unchanged Page state stored atomically with this step; returned in state().checkpoint and the feed.
dryRun boolean false Runs and reports, then rolls back by design ('dry-run').
expectGroup HistoryGroup undefined A guard, checked at the call: this write belongs to the undo group you are running.
expectRevision number undefined (no check) If-match on session.revision.
origin string null Your tag, echoed unchanged in Report.origin and cause.origin.
readyTimeoutMs number 4000 After sealing (Session.transaction): decode and compile for at most this long, then show anyway with completed: false.
signal AbortSignal undefined Cancels this call; the member's JSDoc says what an abort does.
supersede boolean false (the write is queued behind the transaction and applies after it closes) While a transaction is open: roll it back (it resolves 'superseded'); the writes queued behind it apply in call order, then this one, which supersedes an…
timeoutMs number 10000 Rolls back after this long without progress (a load receiving data, work making a write).
undo 'rebase' | (string & {}) a recorded-state change gets one step labelled 'Change'; a look-only write gets none; the session's first model (cause 'load') gets none, whatever the label: it is the floor of history An undo label makes this write one undo step.

Abort (signal) ​

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

A write: before the commit point it rolls back and rejects AbortError; after it, no effect, except that a running camera move stops where the last frame drew it (CameraMoveOptions).

Through a tx the commit point is the transaction's: aborting a write still loading rejects AbortError and stages nothing (catch it: unobserved, it rolls the transaction back, spec section 6.1, O6); aborting one already staged unstages it, its paths keeping the latest other write to them as after a failed savepoint (O7), and its Promise stays resolved 'staged'.

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.transaction.ts):

ts
import { HoloAssetError } from '@holostep-configurators/runtime-client';
import type { Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
// All or nothing: if one load fails, nothing appears.
declare const propUrls: readonly string[];
try {
  const r = await session.transaction(async (tx) => {
    // a handle from tx: bound to it
    const props = tx.collection('props', { role: 'scenery' });
    await Promise.all(propUrls.map((url, i) => props.load(url, { key: `prop-${i}` })));
    return propUrls.length;
  }, { undo: 'Add props', origin: 'props-panel', signal });
  if (r.outcome === 'committed') {
    console.log(`${r.value} props shown in one frame`);   // narrowed: no `!`
  } else {
    console.warn(r.outcome, r.reason);   // 'rolled-back' (timeout), 'superseded', 'refused'
  }
} catch (error) {
  if (!(error instanceof HoloAssetError)) throw error;     // work's own error, after the rollback
  console.warn('nothing was added:', error.url);
}

Generic-API test (spec 3.1) ​

Rule Result
1. Neutral name pass: transaction names no product
2. A precedent pass: ProseMirror history (addToHistory) (row K62); Unity Undo (row K62); a correctness rule (rows K36, X1, X4)
3. Two apps, or labs pass: 20 apps (ledger: app-04c2774145, app-4762caacdc, app-4fd23bc869, app-822bb9d6aa, app-8675b3225c, app-b362a81c85, app-bcb7ef21da, app-c1384707fc and 10 more; fleet cross-check: app-04c2774145, app-37356bf09f, app-4762caacdc, app-4fd23bc869, app-510d750508, app-822bb9d6aa, app-8675b3225c, app-bcb7ef21da and 9 more)
4. The cheaper fix first decided per need in Appendix B: rows K36, K62, X1, X4 at tier stable (a member only where no rule, data, asset or app code serves the need)