@seriousgaming/sdk 0.0.0-stage → 1.0.0-alpha.1
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/LICENSE +202 -0
- package/NOTICE +1 -0
- package/README.md +29 -2
- package/lib/build/callbacks.d.ts +998 -0
- package/lib/build/callbacks.js +32 -0
- package/lib/build/context-merge.d.ts +59 -0
- package/lib/build/context-merge.js +118 -0
- package/lib/build/document.d.ts +36 -0
- package/lib/build/document.js +8 -0
- package/lib/build/encoding.d.ts +26 -0
- package/lib/build/encoding.js +78 -0
- package/lib/build/endpoints.d.ts +421 -0
- package/lib/build/endpoints.js +46 -0
- package/lib/build/hooks.d.ts +74 -0
- package/lib/build/hooks.js +1 -0
- package/lib/build/index.d.ts +18 -0
- package/lib/build/index.js +16 -0
- package/lib/build/llm.d.ts +166 -0
- package/lib/build/llm.js +17 -0
- package/lib/build/resource-schema.d.ts +1048 -0
- package/lib/build/resource-schema.js +7 -0
- package/lib/build/scheduling.d.ts +112 -0
- package/lib/build/scheduling.js +217 -0
- package/lib/build/seed.d.ts +51 -0
- package/lib/build/seed.js +89 -0
- package/lib/build/signatures.d.ts +372 -0
- package/lib/build/signatures.js +1 -0
- package/lib/build/speech.d.ts +102 -0
- package/lib/build/speech.js +11 -0
- package/lib/build/tick-validation.d.ts +23 -0
- package/lib/build/tick-validation.js +96 -0
- package/lib/build/timer.d.ts +74 -0
- package/lib/build/timer.js +1 -0
- package/lib/build/validators.d.ts +116 -0
- package/lib/build/validators.js +1 -0
- package/lib/commands.d.ts +357 -0
- package/lib/commands.js +14 -0
- package/lib/e2e.d.ts +238 -0
- package/lib/e2e.js +248 -0
- package/lib/projection.d.ts +266 -0
- package/lib/projection.js +23 -0
- package/lib/testing/index.d.ts +13 -0
- package/lib/testing/index.js +13 -0
- package/lib/testing/logic-args.d.ts +177 -0
- package/lib/testing/logic-args.js +229 -0
- package/lib/testing/stub-services.d.ts +41 -0
- package/lib/testing/stub-services.js +176 -0
- package/lib/ui/CrossTeamDataContext.d.ts +36 -0
- package/lib/ui/CrossTeamDataContext.js +32 -0
- package/lib/ui/PresentationContext.d.ts +72 -0
- package/lib/ui/PresentationContext.js +13 -0
- package/lib/ui/PresentationWrapper.d.ts +12 -0
- package/lib/ui/PresentationWrapper.js +78 -0
- package/lib/ui/SessionUserInterfaceCallbacksContext.d.ts +3 -0
- package/lib/ui/SessionUserInterfaceCallbacksContext.js +7 -0
- package/lib/ui/SessionUserInterfaceDataContext.d.ts +103 -0
- package/lib/ui/SessionUserInterfaceDataContext.js +17 -0
- package/lib/ui/SessionUserInterfaceHookFailuresContext.d.ts +44 -0
- package/lib/ui/SessionUserInterfaceHookFailuresContext.js +15 -0
- package/lib/ui/SessionUserInterfaceHostOverlaysContext.d.ts +23 -0
- package/lib/ui/SessionUserInterfaceHostOverlaysContext.js +23 -0
- package/lib/ui/SessionUserInterfaceLocaleContext.d.ts +11 -0
- package/lib/ui/SessionUserInterfaceLocaleContext.js +13 -0
- package/lib/ui/SessionUserInterfaceMetaContext.d.ts +39 -0
- package/lib/ui/SessionUserInterfaceMetaContext.js +13 -0
- package/lib/ui/SessionUserInterfaceParticipantsContext.d.ts +12 -0
- package/lib/ui/SessionUserInterfaceParticipantsContext.js +16 -0
- package/lib/ui/SessionUserInterfaceTeamConfigurationContext.d.ts +53 -0
- package/lib/ui/SessionUserInterfaceTeamConfigurationContext.js +23 -0
- package/lib/ui/SessionUserInterfaceTeamLinksContext.d.ts +56 -0
- package/lib/ui/SessionUserInterfaceTeamLinksContext.js +12 -0
- package/lib/ui/SessionUserInterfaceTeamsContext.d.ts +13 -0
- package/lib/ui/SessionUserInterfaceTeamsContext.js +13 -0
- package/lib/ui/SessionUserInterfaceThemeContext.d.ts +9 -0
- package/lib/ui/SessionUserInterfaceThemeContext.js +7 -0
- package/lib/ui/SessionUserInterfaceThemePreferenceContext.d.ts +3 -0
- package/lib/ui/SessionUserInterfaceThemePreferenceContext.js +7 -0
- package/lib/ui/SessionUserInterfaceWalkthroughLinkContext.d.ts +42 -0
- package/lib/ui/SessionUserInterfaceWalkthroughLinkContext.js +26 -0
- package/lib/ui/SessionUserInterfaceWrapper.d.ts +8 -0
- package/lib/ui/SessionUserInterfaceWrapper.js +321 -0
- package/lib/ui/SettingsEditorCallbacksContext.d.ts +3 -0
- package/lib/ui/SettingsEditorCallbacksContext.js +7 -0
- package/lib/ui/SettingsEditorContext.d.ts +33 -0
- package/lib/ui/SettingsEditorContext.js +16 -0
- package/lib/ui/SettingsEditorLocaleContext.d.ts +13 -0
- package/lib/ui/SettingsEditorLocaleContext.js +15 -0
- package/lib/ui/SettingsEditorThemeContext.d.ts +9 -0
- package/lib/ui/SettingsEditorThemeContext.js +7 -0
- package/lib/ui/SettingsEditorThemePreferenceContext.d.ts +3 -0
- package/lib/ui/SettingsEditorThemePreferenceContext.js +7 -0
- package/lib/ui/SettingsEditorWrapper.d.ts +13 -0
- package/lib/ui/SettingsEditorWrapper.js +74 -0
- package/lib/ui/UserInterfaceCallbacksContext.d.ts +3 -0
- package/lib/ui/UserInterfaceCallbacksContext.js +7 -0
- package/lib/ui/UserInterfaceDataContext.d.ts +78 -0
- package/lib/ui/UserInterfaceDataContext.js +11 -0
- package/lib/ui/UserInterfaceLocaleContext.d.ts +13 -0
- package/lib/ui/UserInterfaceLocaleContext.js +15 -0
- package/lib/ui/UserInterfaceOwnTeamContext.d.ts +25 -0
- package/lib/ui/UserInterfaceOwnTeamContext.js +26 -0
- package/lib/ui/UserInterfaceOwnTeamJoinLinkContext.d.ts +52 -0
- package/lib/ui/UserInterfaceOwnTeamJoinLinkContext.js +13 -0
- package/lib/ui/UserInterfaceParticipantContext.d.ts +16 -0
- package/lib/ui/UserInterfaceParticipantContext.js +24 -0
- package/lib/ui/UserInterfaceParticipantsContext.d.ts +12 -0
- package/lib/ui/UserInterfaceParticipantsContext.js +13 -0
- package/lib/ui/UserInterfaceRunKindContext.d.ts +31 -0
- package/lib/ui/UserInterfaceRunKindContext.js +31 -0
- package/lib/ui/UserInterfaceTeamsContext.d.ts +12 -0
- package/lib/ui/UserInterfaceTeamsContext.js +13 -0
- package/lib/ui/UserInterfaceThemeContext.d.ts +9 -0
- package/lib/ui/UserInterfaceThemeContext.js +7 -0
- package/lib/ui/UserInterfaceThemePreferenceContext.d.ts +3 -0
- package/lib/ui/UserInterfaceThemePreferenceContext.js +7 -0
- package/lib/ui/UserInterfaceTimerContext.d.ts +10 -0
- package/lib/ui/UserInterfaceTimerContext.js +12 -0
- package/lib/ui/UserInterfaceValidationContext.d.ts +25 -0
- package/lib/ui/UserInterfaceValidationContext.js +14 -0
- package/lib/ui/UserInterfaceViewerRoleContext.d.ts +14 -0
- package/lib/ui/UserInterfaceViewerRoleContext.js +17 -0
- package/lib/ui/UserInterfaceWrapper.d.ts +8 -0
- package/lib/ui/UserInterfaceWrapper.js +219 -0
- package/lib/ui/expectedParentOrigin.d.ts +10 -0
- package/lib/ui/expectedParentOrigin.js +32 -0
- package/lib/ui/index.d.ts +50 -0
- package/lib/ui/index.js +52 -0
- package/lib/ui/internal/SurfaceGate.d.ts +19 -0
- package/lib/ui/internal/SurfaceGate.js +17 -0
- package/lib/ui/internal/SurfaceScope.d.ts +17 -0
- package/lib/ui/internal/SurfaceScope.js +16 -0
- package/lib/ui/internal/createContexts.d.ts +50 -0
- package/lib/ui/internal/createContexts.js +32 -0
- package/lib/ui/internal/document-attributes.d.ts +9 -0
- package/lib/ui/internal/document-attributes.js +87 -0
- package/lib/ui/internal/surface-timer.d.ts +3 -0
- package/lib/ui/internal/surface-timer.js +11 -0
- package/lib/ui/internal/useLatestRef.d.ts +7 -0
- package/lib/ui/internal/useLatestRef.js +11 -0
- package/lib/ui/internal/useOptimisticMerge.d.ts +19 -0
- package/lib/ui/internal/useOptimisticMerge.js +28 -0
- package/lib/ui/internal/useSurfaceControls.d.ts +52 -0
- package/lib/ui/internal/useSurfaceControls.js +19 -0
- package/lib/ui/internal/useTypedPastState.d.ts +17 -0
- package/lib/ui/internal/useTypedPastState.js +17 -0
- package/lib/ui/mutation-commit.d.ts +32 -0
- package/lib/ui/mutation-commit.js +1 -0
- package/lib/ui/mutation-outcome.d.ts +66 -0
- package/lib/ui/mutation-outcome.js +49 -0
- package/lib/ui/request-id.d.ts +18 -0
- package/lib/ui/request-id.js +44 -0
- package/lib/ui/testing.d.ts +365 -0
- package/lib/ui/testing.js +572 -0
- package/lib/ui/tick-snapshot.d.ts +28 -0
- package/lib/ui/tick-snapshot.js +34 -0
- package/lib/ui/ui-protocol.d.ts +799 -0
- package/lib/ui/ui-protocol.js +50 -0
- package/lib/ui/useAsset.d.ts +80 -0
- package/lib/ui/useAsset.js +139 -0
- package/lib/ui/useEndpointCallbacks.d.ts +31 -0
- package/lib/ui/useEndpointCallbacks.js +68 -0
- package/lib/ui/useHostChannel.d.ts +90 -0
- package/lib/ui/useHostChannel.js +338 -0
- package/lib/ui/useMutationReporter.d.ts +100 -0
- package/lib/ui/useMutationReporter.js +97 -0
- package/lib/ui/usePastState.d.ts +39 -0
- package/lib/ui/usePastState.js +63 -0
- package/lib/ui/useViewerStorage.d.ts +54 -0
- package/lib/ui/useViewerStorage.js +141 -0
- package/package.json +83 -3
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host's automatic tick timer, as every reader sees it (§12.3).
|
|
3
|
+
*
|
|
4
|
+
* One shape wherever a timer appears: the `setTimer` payload a game surface
|
|
5
|
+
* receives, each team's entry in a session surface's `SessionData`, an
|
|
6
|
+
* endpoint's `session.teams[].timer`, and the state projection (§20).
|
|
7
|
+
* Durations are milliseconds and end in `Ms`; timestamps are milliseconds
|
|
8
|
+
* since the epoch and end in `At`.
|
|
9
|
+
*
|
|
10
|
+
* The host pushes a new value whenever the *schedule* changes (a new tick is
|
|
11
|
+
* scheduled, the timer pauses or resumes, the controller disables ticking).
|
|
12
|
+
* It does not push one every second: a surface that wants a live countdown
|
|
13
|
+
* computes it from `nextTickAt` in a local `requestAnimationFrame` (or
|
|
14
|
+
* `setInterval`) loop, which keeps React out of the per-frame path.
|
|
15
|
+
*
|
|
16
|
+
* `nextTickAt` is in the same clock-space as `Date.now()`, so the remaining
|
|
17
|
+
* time is `nextTickAt - Date.now()`. Hosts are responsible for stamping it in
|
|
18
|
+
* a clock the consumer recognises: automatic for a browser on the same machine
|
|
19
|
+
* as the host, NTP-synced clocks across machines. The wrapper does not
|
|
20
|
+
* estimate clock skew, since with only two timestamps it cannot be told apart
|
|
21
|
+
* from message staleness.
|
|
22
|
+
*/
|
|
23
|
+
export interface TimerState {
|
|
24
|
+
/**
|
|
25
|
+
* Whether the tick controller currently has automatic ticking enabled.
|
|
26
|
+
* When false, no countdown should be shown: the game is manual-tick only,
|
|
27
|
+
* or the controller has decided to stop scheduling.
|
|
28
|
+
*/
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
/** Whether the host has paused automatic ticking. */
|
|
31
|
+
paused: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* When the next automatic tick is due (epoch milliseconds, in `Date.now()`
|
|
34
|
+
* space). Null when nothing is scheduled: paused, complete, or `enabled`
|
|
35
|
+
* is false.
|
|
36
|
+
*/
|
|
37
|
+
nextTickAt: number | null;
|
|
38
|
+
/**
|
|
39
|
+
* The full length of the currently scheduled window in milliseconds, within
|
|
40
|
+
* the §11.8 bounds. Useful for progress bars (`elapsed / intervalMs`). Null
|
|
41
|
+
* when nothing is scheduled.
|
|
42
|
+
*/
|
|
43
|
+
intervalMs: number | null;
|
|
44
|
+
/**
|
|
45
|
+
* When the current pause began (epoch milliseconds), or null when the timer
|
|
46
|
+
* is not paused.
|
|
47
|
+
*/
|
|
48
|
+
pausedAt: number | null;
|
|
49
|
+
/**
|
|
50
|
+
* Total paused time in milliseconds since the schedule started, not
|
|
51
|
+
* counting the current pause. Combine with `pausedAt` for a live total:
|
|
52
|
+
*
|
|
53
|
+
* ```ts
|
|
54
|
+
* const livePausedMs = timer.pausedMs + (timer.pausedAt ? Date.now() - timer.pausedAt : 0);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
pausedMs: number;
|
|
58
|
+
/**
|
|
59
|
+
* How far facilitator extensions have moved the *currently scheduled* tick,
|
|
60
|
+
* in milliseconds. Positive when the deadline was pushed out, negative when
|
|
61
|
+
* it was pulled in, and 0 for an unadjusted window. Resets with each newly
|
|
62
|
+
* scheduled tick, so it describes this window rather than the session.
|
|
63
|
+
*
|
|
64
|
+
* Read it to say what happened rather than inferring it from a moved
|
|
65
|
+
* `nextTickAt`: a deadline that jumped could equally be a fresh schedule,
|
|
66
|
+
* and 'extended by 2m' is worth showing the room.
|
|
67
|
+
*/
|
|
68
|
+
extendedMs: number;
|
|
69
|
+
/**
|
|
70
|
+
* When the current schedule first started (epoch milliseconds), or null
|
|
71
|
+
* when no schedule has started yet.
|
|
72
|
+
*/
|
|
73
|
+
scheduleStartedAt: number | null;
|
|
74
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Participant } from './hooks.js';
|
|
2
|
+
import { LogicMeta } from './signatures.js';
|
|
3
|
+
/**
|
|
4
|
+
* Verdict returned by a validator. `ok: true` means the proposed state passes
|
|
5
|
+
* this check; `ok: false` rejects it and the runtime returns the message to
|
|
6
|
+
* the caller. The message is free-form — games encode structured data
|
|
7
|
+
* (locale key, JSON blob, etc.) inside it if they need to.
|
|
8
|
+
*/
|
|
9
|
+
export type ValidationResult = {
|
|
10
|
+
ok: true;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Who submitted the mutation a validator is gating.
|
|
17
|
+
*
|
|
18
|
+
* A union rather than an optional participant, because the two cases are not
|
|
19
|
+
* 'identity, or the absence of it'. They are two different callers, and a rule
|
|
20
|
+
* that means something different for each has to say which it is handling. The
|
|
21
|
+
* shape makes that unavoidable: `participant` is unreachable until `role` has
|
|
22
|
+
* been narrowed, so a validator cannot read an identity it has not first
|
|
23
|
+
* decided it has.
|
|
24
|
+
*
|
|
25
|
+
* An observer is a facilitator watching one team on that team's own play
|
|
26
|
+
* surface (§13.3). They are rendered the same user interface a participant is,
|
|
27
|
+
* with the same controls, so their writes are put to validators on the same
|
|
28
|
+
* terms. A game that wants a facilitator to be able to do what a participant
|
|
29
|
+
* cannot says so here, deliberately, rather than the runtime deciding it for
|
|
30
|
+
* every game at once.
|
|
31
|
+
*/
|
|
32
|
+
export type ValidatorActor = {
|
|
33
|
+
role: 'participant';
|
|
34
|
+
participant: Participant;
|
|
35
|
+
}
|
|
36
|
+
/** An observer holds no participant record, so the team is all there is. */
|
|
37
|
+
| {
|
|
38
|
+
role: 'observer';
|
|
39
|
+
teamId: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Arguments of a validator's `UpdateData` gate, which judges a participant's
|
|
43
|
+
* context write. `previous` is the state before the write; `next` is the
|
|
44
|
+
* proposed state after it. Validators are read-only: they return a verdict,
|
|
45
|
+
* never modify the proposed state.
|
|
46
|
+
*/
|
|
47
|
+
export interface ValidatorFunctionArgs<TContext, TSettings> {
|
|
48
|
+
previous: TContext;
|
|
49
|
+
next: TContext;
|
|
50
|
+
actor: ValidatorActor;
|
|
51
|
+
/**
|
|
52
|
+
* The settings resources this resource declared in `settings`, keyed by
|
|
53
|
+
* identifier: resolved from their defaults, the active scenario and the
|
|
54
|
+
* session's overrides, and fixed when play starts (§8). Read-only.
|
|
55
|
+
*/
|
|
56
|
+
settings: TSettings;
|
|
57
|
+
/**
|
|
58
|
+
* The facts true of the whole run: its locale, its seed, whether it is the
|
|
59
|
+
* game being played or a walkthrough beside it, and when this run of the
|
|
60
|
+
* validators started (`now`).
|
|
61
|
+
*
|
|
62
|
+
* A validator gates a participant's action rather than running as part of
|
|
63
|
+
* a tick, so this is {@link LogicMeta} rather than the `RunMeta` an engine
|
|
64
|
+
* receives. Use `locale` to phrase a rejection in the session's language.
|
|
65
|
+
*/
|
|
66
|
+
meta: LogicMeta;
|
|
67
|
+
/**
|
|
68
|
+
* The participants on the actor's team, taken when the validators started
|
|
69
|
+
* (§15.3). Read-only, and a copy per call.
|
|
70
|
+
*/
|
|
71
|
+
participants: readonly Readonly<Participant>[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A validator's `UpdateData` export: the gate on a participant's context
|
|
75
|
+
* write. Engines, hooks, endpoints and a session surface bypass it
|
|
76
|
+
* (system-trusted).
|
|
77
|
+
*/
|
|
78
|
+
export type ValidatorFunction<TContext = unknown, TSettings = unknown> = (args: ValidatorFunctionArgs<TContext, TSettings>) => Promise<ValidationResult>;
|
|
79
|
+
/** Arguments of a validator's `RequestTick` gate. */
|
|
80
|
+
export interface RequestTickFunctionArgs<TContext, TSettings> {
|
|
81
|
+
/**
|
|
82
|
+
* The requesting team's board as it stands. A request changes nothing
|
|
83
|
+
* until the tick runs, so there is no `previous` and `next`: gate on the
|
|
84
|
+
* board, such as a pacing capability the facilitator sets.
|
|
85
|
+
*/
|
|
86
|
+
context: TContext;
|
|
87
|
+
/**
|
|
88
|
+
* The tick the request would run: the requesting team's head tick plus
|
|
89
|
+
* one, so a first request asks for tick 1.
|
|
90
|
+
*/
|
|
91
|
+
requestedTick: number;
|
|
92
|
+
actor: ValidatorActor;
|
|
93
|
+
/**
|
|
94
|
+
* The settings resources this resource declared in `settings`, keyed by
|
|
95
|
+
* identifier: resolved from their defaults, the active scenario and the
|
|
96
|
+
* session's overrides, and fixed when play starts (§8). Read-only.
|
|
97
|
+
*/
|
|
98
|
+
settings: TSettings;
|
|
99
|
+
meta: LogicMeta;
|
|
100
|
+
/** The participants on the requesting team, as `UpdateData` receives them. */
|
|
101
|
+
participants: readonly Readonly<Participant>[];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* A validator's `RequestTick` export: the gate on a participant's request for
|
|
105
|
+
* the next tick. Only a player surface's request reaches it; the facilitator's
|
|
106
|
+
* ticks, the timer's and every system-trusted caller's pass straight through.
|
|
107
|
+
*/
|
|
108
|
+
export type RequestTickFunction<TContext = unknown, TSettings = unknown> = (args: RequestTickFunctionArgs<TContext, TSettings>) => Promise<ValidationResult>;
|
|
109
|
+
/**
|
|
110
|
+
* A single validator rejection returned to the caller. The runtime collects
|
|
111
|
+
* every rejection (form-style UX) rather than short-circuiting on the first.
|
|
112
|
+
*/
|
|
113
|
+
export interface ValidationRejection {
|
|
114
|
+
validatorIdentifier: string;
|
|
115
|
+
message: string;
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a client may ask a session to do (§20).
|
|
3
|
+
*
|
|
4
|
+
* One closed command set, shared by every client of the dev server: the
|
|
5
|
+
* browser console, the CLI, a Playwright suite through `runCommand`, and an
|
|
6
|
+
* agent posting to `/api/command`. Published from the SDK rather than declared
|
|
7
|
+
* inside the runtime so a test is type-checked against the commands the
|
|
8
|
+
* runtime actually accepts, and a misspelled field fails to compile rather
|
|
9
|
+
* than coming back as a 400.
|
|
10
|
+
*
|
|
11
|
+
* The runtime that validates these at its boundary lives in the tools
|
|
12
|
+
* package. This module is types only.
|
|
13
|
+
*/
|
|
14
|
+
import type { PastStateEntry, PastStateQuery } from './build/callbacks.js';
|
|
15
|
+
import type { EndpointFailure } from './build/endpoints.js';
|
|
16
|
+
import type { ViewerRole } from './build/signatures.js';
|
|
17
|
+
import type { EndpointAuditEntry, FaultKind, StateProjection } from './projection.js';
|
|
18
|
+
/** Addresses one team by its stable index, or the session when absent. */
|
|
19
|
+
export interface TeamScope {
|
|
20
|
+
/** Stable team index (§5.6), not an array position. */
|
|
21
|
+
teamIndex?: number;
|
|
22
|
+
}
|
|
23
|
+
/** Who is asking, where the operation is one a participant can perform. */
|
|
24
|
+
export interface Actor {
|
|
25
|
+
participantId?: string;
|
|
26
|
+
teamId?: string;
|
|
27
|
+
/**
|
|
28
|
+
* What the host holds the sending surface as, where it holds it as
|
|
29
|
+
* anything (§13.3).
|
|
30
|
+
*
|
|
31
|
+
* Absence of `participantId` is not on its own a statement that nobody is
|
|
32
|
+
* asking: the CLI, a session surface and an observer all write without
|
|
33
|
+
* one, and so did a player surface whose slot the console had failed to
|
|
34
|
+
* resolve. The first three are deliberately identity-free and system
|
|
35
|
+
* trusted; the fourth was a participant's write being taken as one. The
|
|
36
|
+
* role separates them, so the session can refuse what it cannot attribute
|
|
37
|
+
* instead of trusting it.
|
|
38
|
+
*
|
|
39
|
+
* Host bookkeeping, never a claim the guest makes: the console resolves it
|
|
40
|
+
* from the route and the roster, exactly as it resolves `participantId`.
|
|
41
|
+
*/
|
|
42
|
+
viewerRole?: ViewerRole;
|
|
43
|
+
}
|
|
44
|
+
export type { ViewerRole };
|
|
45
|
+
/**
|
|
46
|
+
* Every state-changing operation. Each one goes through the session's single
|
|
47
|
+
* queue, in submission order (§9.7).
|
|
48
|
+
*/
|
|
49
|
+
export type MutationCommand =
|
|
50
|
+
/**
|
|
51
|
+
* A tick. `Actor` is present when a participant's or observer's surface
|
|
52
|
+
* asked for it (§15), which puts it to the validators gating
|
|
53
|
+
* `requestTick`; a facilitator's, the CLI's or a timer's carries none.
|
|
54
|
+
*/
|
|
55
|
+
({
|
|
56
|
+
type: 'tick';
|
|
57
|
+
} & TeamScope & Actor) | ({
|
|
58
|
+
type: 'undo';
|
|
59
|
+
} & TeamScope) | ({
|
|
60
|
+
type: 'reset';
|
|
61
|
+
} & TeamScope)
|
|
62
|
+
/** Leave the configuration stage and initialise (§8.3). */
|
|
63
|
+
| {
|
|
64
|
+
type: 'play';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Go back to the configuration stage, for a game that has one.
|
|
68
|
+
*
|
|
69
|
+
* The inverse of `play`, and a reset with it: configuration is resolved
|
|
70
|
+
* when the session initialises (§8.2), so changing it after the fact only
|
|
71
|
+
* means anything if the session starts again on the new values.
|
|
72
|
+
*/
|
|
73
|
+
| {
|
|
74
|
+
type: 'reconfigure';
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Reinitialise the session from the package, as if it had just started.
|
|
78
|
+
*
|
|
79
|
+
* Distinct from `reset`, which returns the session to its own tick 0 with
|
|
80
|
+
* the scenario, team count and locale it has. This re-resolves all three,
|
|
81
|
+
* so an omitted `scenarioId` goes back to the package's default rather than
|
|
82
|
+
* staying on whatever is active.
|
|
83
|
+
*/
|
|
84
|
+
| {
|
|
85
|
+
type: 'reinitialise';
|
|
86
|
+
teams?: number;
|
|
87
|
+
scenarioId?: string | null;
|
|
88
|
+
locale?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Participants to seed each team with: one count for every team, or
|
|
91
|
+
* one per team. Zero is allowed. Kept for later re-initialisations,
|
|
92
|
+
* like `teams`, until a new team count leaves a per-team list behind.
|
|
93
|
+
*/
|
|
94
|
+
participants?: number | number[];
|
|
95
|
+
} | ({
|
|
96
|
+
type: 'updateContext';
|
|
97
|
+
payload: Record<string, unknown>;
|
|
98
|
+
/** Paths to remove after the payload merges (§9.5). */
|
|
99
|
+
deletes?: (string | string[])[];
|
|
100
|
+
/**
|
|
101
|
+
* The player surface the write came from, supplied by the host from
|
|
102
|
+
* what it mounted and never by the page. The write is held to that
|
|
103
|
+
* surface's `writes` (§9.5). Absent for a system-trusted caller: the
|
|
104
|
+
* session surface, the CLI, or logic.
|
|
105
|
+
*/
|
|
106
|
+
uiIdentifier?: string;
|
|
107
|
+
/**
|
|
108
|
+
* The session surface a facilitator's team write came from, supplied
|
|
109
|
+
* by the host like `uiIdentifier`. The payload may change only
|
|
110
|
+
* capabilities that surface declares in `writes`, and may carry
|
|
111
|
+
* another capability unchanged; every path in `deletes` must name a
|
|
112
|
+
* team-scope capability it writes (§9.5.1). Absent for every other
|
|
113
|
+
* caller.
|
|
114
|
+
*/
|
|
115
|
+
sessionUiIdentifier?: string;
|
|
116
|
+
} & TeamScope & Actor)
|
|
117
|
+
/**
|
|
118
|
+
* A shared-store write (§9.5.1). Exactly one of the two identifiers is
|
|
119
|
+
* present, and it names what authorised the write: a session surface's
|
|
120
|
+
* `writes` array for a facilitator write, or a session-scoped endpoint's
|
|
121
|
+
* for one of its patches (§6.12). An endpoint has no surface to borrow an
|
|
122
|
+
* identifier from, and a facilitator agent calling one has no bundle at all.
|
|
123
|
+
*/
|
|
124
|
+
| {
|
|
125
|
+
type: 'updateSharedContext';
|
|
126
|
+
uiIdentifier?: string;
|
|
127
|
+
endpointIdentifier?: string;
|
|
128
|
+
payload: Record<string, unknown>;
|
|
129
|
+
/**
|
|
130
|
+
* Paths to remove from the store after the payload merges (§9.5), each
|
|
131
|
+
* under a shared capability the writer declares. Set by a
|
|
132
|
+
* session-scoped endpoint's `deletes` (§6.12).
|
|
133
|
+
*/
|
|
134
|
+
deletes?: (string | string[])[];
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Write into the session-override layer (§8.2). `uiIdentifier` names the
|
|
138
|
+
* settings editor that sent it, which may change only what it
|
|
139
|
+
* `configures` (§6.5); a caller naming none is system-trusted.
|
|
140
|
+
*/
|
|
141
|
+
| {
|
|
142
|
+
type: 'updateSettings';
|
|
143
|
+
uiIdentifier?: string;
|
|
144
|
+
payload: Record<string, unknown>;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Open the scenario editor's draft of a scenario (§6.5), or of none for
|
|
148
|
+
* one started from the package's own settings. A draft already open on
|
|
149
|
+
* it is kept. The draft belongs to no session: it is resolved from the
|
|
150
|
+
* scenario, never from the session's override layer, and reaches a
|
|
151
|
+
* session only once it is saved as a scenario.
|
|
152
|
+
*/
|
|
153
|
+
| {
|
|
154
|
+
type: 'editScenario';
|
|
155
|
+
scenarioId: string | null;
|
|
156
|
+
}
|
|
157
|
+
/** What the scenario editor sends in `updateSettings`: an edit to its draft (§6.5). */
|
|
158
|
+
| {
|
|
159
|
+
type: 'updateScenarioDraft';
|
|
160
|
+
uiIdentifier?: string;
|
|
161
|
+
scenarioId: string | null;
|
|
162
|
+
payload: Record<string, unknown>;
|
|
163
|
+
} | {
|
|
164
|
+
type: 'addTeam';
|
|
165
|
+
name?: string;
|
|
166
|
+
participants?: number;
|
|
167
|
+
} | {
|
|
168
|
+
type: 'removeTeam';
|
|
169
|
+
teamIndex: number;
|
|
170
|
+
} | {
|
|
171
|
+
type: 'renameTeam';
|
|
172
|
+
teamId: string;
|
|
173
|
+
name: string;
|
|
174
|
+
}
|
|
175
|
+
/** From a player surface; the host resolves the team (§12.5). */
|
|
176
|
+
| ({
|
|
177
|
+
type: 'renameOwnTeam';
|
|
178
|
+
name: string;
|
|
179
|
+
} & Actor) | {
|
|
180
|
+
type: 'addParticipant';
|
|
181
|
+
teamId: string;
|
|
182
|
+
name?: string;
|
|
183
|
+
} | {
|
|
184
|
+
type: 'renameParticipant';
|
|
185
|
+
participantId: string;
|
|
186
|
+
name: string;
|
|
187
|
+
} | {
|
|
188
|
+
type: 'moveParticipant';
|
|
189
|
+
participantId: string;
|
|
190
|
+
teamId: string;
|
|
191
|
+
} | {
|
|
192
|
+
type: 'setWaitingRoom';
|
|
193
|
+
open: boolean;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Throw the walkthrough away and start it again at tick 0 (§5.7).
|
|
197
|
+
*
|
|
198
|
+
* Handled by the host rather than by a session: it replaces the run a
|
|
199
|
+
* command would otherwise be addressed to, so the run cannot settle it.
|
|
200
|
+
*/
|
|
201
|
+
| {
|
|
202
|
+
type: 'resetWalkthrough';
|
|
203
|
+
} | {
|
|
204
|
+
type: 'selectScenario';
|
|
205
|
+
scenarioId: string | null;
|
|
206
|
+
} | {
|
|
207
|
+
type: 'setLocale';
|
|
208
|
+
locale: string;
|
|
209
|
+
} | ({
|
|
210
|
+
type: 'pauseTimer';
|
|
211
|
+
} & TeamScope) | ({
|
|
212
|
+
type: 'resumeTimer';
|
|
213
|
+
} & TeamScope) | ({
|
|
214
|
+
type: 'extendTick';
|
|
215
|
+
byMs: number;
|
|
216
|
+
} & TeamScope)
|
|
217
|
+
/**
|
|
218
|
+
* Move a fake clock forward, running every automatic tick that comes due.
|
|
219
|
+
* Refused on the real clock: only `sdk dev --fake-clock` starts a session
|
|
220
|
+
* whose time can be moved by hand.
|
|
221
|
+
*/
|
|
222
|
+
| {
|
|
223
|
+
type: 'advanceClock';
|
|
224
|
+
byMs: number;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Arm a failure this runtime cannot otherwise produce (§3.3 of the design).
|
|
228
|
+
*
|
|
229
|
+
* @internal The SDK dev server's fault injection; see `FaultKind`.
|
|
230
|
+
*/
|
|
231
|
+
| {
|
|
232
|
+
type: 'armFault';
|
|
233
|
+
fault: FaultKind;
|
|
234
|
+
times?: number;
|
|
235
|
+
reason?: string;
|
|
236
|
+
}
|
|
237
|
+
/** @internal The SDK dev server's fault injection; see `FaultKind`. */
|
|
238
|
+
| {
|
|
239
|
+
type: 'disarmFault';
|
|
240
|
+
fault: FaultKind;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* Every read. None of these enters the queue: a read is never blocked behind a
|
|
244
|
+
* mutation (§9.7), so a tick in flight must not delay one.
|
|
245
|
+
*/
|
|
246
|
+
export type QueryCommand = {
|
|
247
|
+
type: 'getState';
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* `uiIdentifier` names the calling surface, whose `endpoints` allowlist
|
|
251
|
+
* bounds what it may call (§6.12). `external` marks a caller outside the
|
|
252
|
+
* game, such as a facilitator's AI agent, which names no surface and
|
|
253
|
+
* reaches only an endpoint whose `visibility` is `external`.
|
|
254
|
+
*/
|
|
255
|
+
| ({
|
|
256
|
+
type: 'callEndpoint';
|
|
257
|
+
endpointIdentifier: string;
|
|
258
|
+
request: unknown;
|
|
259
|
+
uiIdentifier?: string;
|
|
260
|
+
external?: boolean;
|
|
261
|
+
/**
|
|
262
|
+
* Who is behind an external call, as the host authenticated them.
|
|
263
|
+
* Accepted only with `external`, and passed to the endpoint as
|
|
264
|
+
* `caller.principal`.
|
|
265
|
+
*/
|
|
266
|
+
principal?: {
|
|
267
|
+
kind: string;
|
|
268
|
+
id: string;
|
|
269
|
+
name?: string;
|
|
270
|
+
};
|
|
271
|
+
/**
|
|
272
|
+
* The scenario a call from the scenario editor is editing, whose
|
|
273
|
+
* draft the endpoint's settings resolve from (§6.5, §6.12). Null for
|
|
274
|
+
* an editor opened on no scenario; absent for the one in force.
|
|
275
|
+
*/
|
|
276
|
+
scenarioId?: string | null;
|
|
277
|
+
} & TeamScope & Actor)
|
|
278
|
+
/**
|
|
279
|
+
* `uiIdentifier` names the asking surface, whose declarations bound what
|
|
280
|
+
* it may read (§12.5). Omitted for a caller with no surface, such as the
|
|
281
|
+
* CLI, which is system-trusted.
|
|
282
|
+
*/
|
|
283
|
+
| ({
|
|
284
|
+
type: 'getPastState';
|
|
285
|
+
query: PastStateQuery;
|
|
286
|
+
uiIdentifier?: string;
|
|
287
|
+
} & Actor) | ({
|
|
288
|
+
type: 'getAllTeamsParticipants';
|
|
289
|
+
uiIdentifier?: string;
|
|
290
|
+
} & Actor)
|
|
291
|
+
/** Endpoint calls that changed something, oldest first (§6.12). */
|
|
292
|
+
| {
|
|
293
|
+
type: 'getEndpointAudit';
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* The package's endpoints, as a caller outside the game discovers them:
|
|
297
|
+
* what each is for, what it takes and returns, and what it may change.
|
|
298
|
+
* `external` narrows the list to the ones such a caller may call.
|
|
299
|
+
*/
|
|
300
|
+
| {
|
|
301
|
+
type: 'listEndpoints';
|
|
302
|
+
external?: boolean;
|
|
303
|
+
};
|
|
304
|
+
/** One endpoint, as `listEndpoints` describes it. */
|
|
305
|
+
export interface EndpointListing {
|
|
306
|
+
identifier: string;
|
|
307
|
+
displayName?: string;
|
|
308
|
+
description?: string;
|
|
309
|
+
scope: 'session' | 'team';
|
|
310
|
+
visibility: 'internal' | 'external';
|
|
311
|
+
requestSchema: Record<string, unknown>;
|
|
312
|
+
responseSchema: Record<string, unknown>;
|
|
313
|
+
/**
|
|
314
|
+
* Capabilities it may change, and session actions it may carry out. An
|
|
315
|
+
* agent host deciding whether a call needs a person's approval reads these:
|
|
316
|
+
* an endpoint that only reads is a different request from one that ticks.
|
|
317
|
+
*/
|
|
318
|
+
writes: string[];
|
|
319
|
+
actions: string[];
|
|
320
|
+
}
|
|
321
|
+
export type Command = MutationCommand | QueryCommand;
|
|
322
|
+
/** What a query answered with. */
|
|
323
|
+
export type QueryResult = {
|
|
324
|
+
type: 'state';
|
|
325
|
+
state: StateProjection;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* `blobs` is present on an external call whose response carries `blob:`
|
|
329
|
+
* references: each one resolved to a URL the caller can fetch it from,
|
|
330
|
+
* because a caller outside the game has no `getAssetUrl` of its own.
|
|
331
|
+
*/
|
|
332
|
+
| {
|
|
333
|
+
type: 'endpoint';
|
|
334
|
+
response: unknown;
|
|
335
|
+
blobs?: Record<string, string>;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* A `callEndpoint` that failed (§6.12): why, and which of its effects had
|
|
339
|
+
* already landed. An answer rather than a throw, so every transport
|
|
340
|
+
* carries it unchanged.
|
|
341
|
+
*/
|
|
342
|
+
| {
|
|
343
|
+
type: 'endpointFailure';
|
|
344
|
+
failure: EndpointFailure;
|
|
345
|
+
} | {
|
|
346
|
+
type: 'pastState';
|
|
347
|
+
entries: PastStateEntry[];
|
|
348
|
+
} | {
|
|
349
|
+
type: 'participants';
|
|
350
|
+
participants: unknown[];
|
|
351
|
+
} | {
|
|
352
|
+
type: 'endpointAudit';
|
|
353
|
+
entries: EndpointAuditEntry[];
|
|
354
|
+
} | {
|
|
355
|
+
type: 'endpoints';
|
|
356
|
+
endpoints: EndpointListing[];
|
|
357
|
+
};
|
package/lib/commands.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a client may ask a session to do (§20).
|
|
3
|
+
*
|
|
4
|
+
* One closed command set, shared by every client of the dev server: the
|
|
5
|
+
* browser console, the CLI, a Playwright suite through `runCommand`, and an
|
|
6
|
+
* agent posting to `/api/command`. Published from the SDK rather than declared
|
|
7
|
+
* inside the runtime so a test is type-checked against the commands the
|
|
8
|
+
* runtime actually accepts, and a misspelled field fails to compile rather
|
|
9
|
+
* than coming back as a 400.
|
|
10
|
+
*
|
|
11
|
+
* The runtime that validates these at its boundary lives in the tools
|
|
12
|
+
* package. This module is types only.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|