Writer.select ​

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 Writer · inherited by Tx, Session, testing.FakeSession · stable · since 2.0.0 · called as session.select

ts
select(group: string, material: string, options?: RecordedOptions<C> & SignalOption): Promise<Report>;

Selects material (a MaterialNode nodeId) in the global-material GroupNode group (its nodeId): recorded, priced and saved. Merging and in the write queue: never superseded, so it commits as its own undo step even while a sync loads. The parts it changes crossfade over the document's materials.fadeMs as its layers resolve it (420 ms when no layer sets it), after the commit point. Outcome: 'committed' at its commit point, after its loads; through a tx, 'staged' once the assets it names have loaded (asset failures: problems). Behind an open transaction it settles only when that transaction closes (a stalled one at its timeoutMs (10 s by default), one holding the display within 14 s of its hold, later while it still loads): show the value you wrote. 'rolled-back' with reason 'internal-error' when applying it failed inside the runtime (through a tx, it then rejects AbortError and the transaction resolves 'rolled-back'; spec section 6.4). Errors: rejects HoloInputError 'unknown-id' when group is not a global-material GroupNode (a variant GroupNode's nodeId included) or material is not one of its MaterialNodes at the call. One that was there at the call and is gone at its turn in the queue (a rollback or an earlier commit removed it) refuses with reason 'conflict' and changes nothing (spec section 6.4). A select whose group dresses no mesh still commits: it reports matched 1 and no Problem, and the price and the recorded choice change while the look does not. The cause is the scene model's: a globalMaterialList meshName close to one of its model's mesh names (a typo) was recorded once, when that model was placed, as 'target-unmatched' in info().problems with didYouMean; a group no placed model names records nothing, as 1.x. A page that must know checks the meshes itself: session.find({ node, name: meshName }).list().length. Not for: a look-only preview, which is a rule: find(q).set({ material: { materialNodeId } }); a variant GroupNode's selected child, which is applyPatch replacing /model/node/{id}/defaultNodeId, or setSceneModel.

Options ​

Through Session:

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

Through Tx:

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

Refused here (typed never, so passing one fails to compile): actor, checkpoint, dryRun, expectGroup, expectRevision, origin, supersede, undo.

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

ts
import type { Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
declare const fabricGroup: string;                         // the GroupNode's nodeId
declare const label: { text: string };
export async function pickFabric(materialNodeId: string, name: string): Promise<void> {
  const before = label.text;
  label.text = name;                                       // show the value you wrote, at once
  try {
    // May be queued behind a transaction: never read it back before this settles.
    const r = await session.select(fabricGroup, materialNodeId, {
      actor: 'shopper', origin: 'swatch',
    });
    if (r.outcome === 'refused') label.text = before;      // gone at its turn: 'conflict'
  } catch (error) {
    label.text = before;                                   // invalid input or abort: nothing ran
    throw error;
  }
}

From ViewerDocumentJson.materials.fadeMs:

The crossfade of a selection change (select, undo, redo, setSceneModel), ms, as 1.x's viewer.transition: the outgoing and incoming base colours (baseColor times its map, or baseColor alone without one) blend in linear colour space, and so do the roughness maps, metallic, roughness, normalScale and the environment intensity, each map sampled at its own placement (uv, scale or sizeM, offset, rotationDeg); other fields switch at the swap. Each changed part fades from what it drew, and a part outside the change keeps its look, also when it already wears the incoming material. A part's first material and a part the same commit loads never fade. select still resolves at its commit point; idle() waits for the fade, and a capture draws its target (spec section 6.8); through a tx it starts when the commit is shown. 0 swaps in one frame. Counts as 0 under reduced motion (spec section 6.2). A change during the fade takes over as PartWriteOptions.fadeMs says (spec section 6.3).

Generic-API test (spec 3.1) ​

Rule Result
1. Neutral name pass: select names no product
2. A precedent pass: a correctness rule (rows X1)
3. Two apps, or labs pass: 28 apps (ledger: app-4fd23bc869, app-822bb9d6aa, app-8675b3225c, app-b362a81c85, app-bcb7ef21da, app-c1384707fc, app-e3b47169bc, app-e61a0b42ad and 7 more; fleet cross-check: app-04c2774145, app-0c773a4ee3, app-37356bf09f, app-378d190f1b, app-4762caacdc, app-4f16d2f6da, app-4fd23bc869, app-510d750508 and 20 more)
4. The cheaper fix first decided per need in Appendix B: rows X1 at tier stable (a member only where no rule, data, asset or app code serves the need)