Writer.select ​Contract 2.0.0 · package sha256
a857eca95b35921109faf997094bb4192f12527d9d0fcd4be7e97f06425bad6e· generated fromconfigurator-runtime.d.tsbyservices/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
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.
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.
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
txthe 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'.
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):
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'sviewer.transition: the outgoing and incoming base colours (baseColortimes its map, orbaseColoralone without one) blend in linear colour space, and so do the roughness maps,metallic,roughness,normalScaleand the environment intensity, each map sampled at its own placement (uv,scaleorsizeM,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.selectstill resolves at its commit point;idle()waits for the fade, and a capture draws its target (spec section 6.8); through atxit 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 asPartWriteOptions.fadeMssays (spec section 6.3).
| 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) |