@seriousgaming/sdk 0.0.0-stage → 1.0.0-alpha.2
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 +33 -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 +89 -3
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one documented shape of a session's observable state.
|
|
3
|
+
*
|
|
4
|
+
* Served three ways and declared once: `sdk view --json`, `GET /api/state`, and
|
|
5
|
+
* the payload the console renders. It is a projection, not any runtime's
|
|
6
|
+
* internal state, so internals can change without breaking an agent that
|
|
7
|
+
* learned to read it, and it is versioned so one that has learned can tell when
|
|
8
|
+
* they have not.
|
|
9
|
+
*
|
|
10
|
+
* Everything a runtime exposes about a session belongs here, because a check
|
|
11
|
+
* made from outside a runtime can only read what the runtime exposes.
|
|
12
|
+
*
|
|
13
|
+
* Published from the SDK rather than declared inside a runtime, because a
|
|
14
|
+
* second runtime implementing it needs the shape, and a type it has to copy is
|
|
15
|
+
* a type the two halves are free to drift apart on.
|
|
16
|
+
*/
|
|
17
|
+
import type { Participant, TeamInfo } from './build/callbacks.js';
|
|
18
|
+
import type { EndpointCallerRole } from './build/endpoints.js';
|
|
19
|
+
import type { RunKind, SessionMode } from './build/signatures.js';
|
|
20
|
+
import type { TimerState } from './build/timer.js';
|
|
21
|
+
import type { MutationOutcome } from './ui/mutation-outcome.js';
|
|
22
|
+
export type { Participant, TeamInfo, TimerState };
|
|
23
|
+
/**
|
|
24
|
+
* Bumped when a field changes meaning or leaves.
|
|
25
|
+
*
|
|
26
|
+
* Adding a field is not a bump: a reader that ignores what it does not know
|
|
27
|
+
* keeps working. Renaming or removing one is.
|
|
28
|
+
*/
|
|
29
|
+
export declare const PROJECTION_VERSION = 4;
|
|
30
|
+
/**
|
|
31
|
+
* A failure a runtime can produce that another otherwise cannot (§9.7, §12.5.1).
|
|
32
|
+
*
|
|
33
|
+
* Armed by name rather than provoked, so an author can verify a game's error
|
|
34
|
+
* handling without manufacturing the race that would otherwise be the only way
|
|
35
|
+
* to reach the state.
|
|
36
|
+
*
|
|
37
|
+
* @internal The SDK dev server's fault injection. Another runtime need not
|
|
38
|
+
* offer it, and the set may change without a major release.
|
|
39
|
+
*/
|
|
40
|
+
export type FaultKind =
|
|
41
|
+
/** The next UI mutation settles `{ kind: 'conflict' }` (§12.5.1). */
|
|
42
|
+
'conflict'
|
|
43
|
+
/** The next UI mutation settles `{ kind: 'denied' }` (§12.5.1). */
|
|
44
|
+
| 'denied'
|
|
45
|
+
/** The next platform service call (`generateText`, `extractText`, `generateSpeech`) rejects (§17). */
|
|
46
|
+
| 'llm-failure'
|
|
47
|
+
/** The next hook chain throws (§14.5). */
|
|
48
|
+
| 'hook-throw'
|
|
49
|
+
/** The next `callEndpoint` exceeds its bound (§6.12). */
|
|
50
|
+
| 'endpoint-timeout'
|
|
51
|
+
/** The next tick fails, atomically (§9.7). */
|
|
52
|
+
| 'tick-failure';
|
|
53
|
+
/**
|
|
54
|
+
* One armed fault, as the state projection reports it.
|
|
55
|
+
*
|
|
56
|
+
* @internal See {@link FaultKind}.
|
|
57
|
+
*/
|
|
58
|
+
export interface ArmedFault {
|
|
59
|
+
kind: FaultKind;
|
|
60
|
+
/** How many more times it will fire. */
|
|
61
|
+
remaining: number;
|
|
62
|
+
/** Operator-supplied note, echoed back so a log says why. */
|
|
63
|
+
reason?: string;
|
|
64
|
+
}
|
|
65
|
+
/** Resolved settings, keyed by settings identifier (§8). */
|
|
66
|
+
export type ResolvedSettings = Record<string, Record<string, unknown>>;
|
|
67
|
+
/** The scenario editor's draft of one scenario (§6.5), resolved. */
|
|
68
|
+
export interface ScenarioDraft {
|
|
69
|
+
/** The scenario being edited, or null for one started from the package's own settings. */
|
|
70
|
+
scenarioId: string | null;
|
|
71
|
+
/** The defaults, then that scenario's `settings`, then the unsaved edits. */
|
|
72
|
+
settings: ResolvedSettings;
|
|
73
|
+
}
|
|
74
|
+
export type { SessionMode };
|
|
75
|
+
/** One team's observable state. */
|
|
76
|
+
export interface ProjectedTeam extends TeamInfo {
|
|
77
|
+
/** Ticks this team has completed. Equal to the session's outside independent mode. */
|
|
78
|
+
completedTicks: number;
|
|
79
|
+
complete: boolean;
|
|
80
|
+
canUndo: boolean;
|
|
81
|
+
/** The composed view: the team's own context plus the shared store (§7.5). */
|
|
82
|
+
context: Record<string, Record<string, unknown>>;
|
|
83
|
+
/** §13.2: absence is reported (`connected: false`), never erased. */
|
|
84
|
+
participants: Participant[];
|
|
85
|
+
/**
|
|
86
|
+
* The timer this team's surfaces are sent (§12.3, `TimerState`). In
|
|
87
|
+
* independent mode each team has its own; otherwise every team carries the
|
|
88
|
+
* cohort's. Absent from a runtime that reports none.
|
|
89
|
+
*/
|
|
90
|
+
timer?: TimerState;
|
|
91
|
+
/**
|
|
92
|
+
* The engine's private memory for this team (§10.2), absent until the
|
|
93
|
+
* engine first returns one. No surface is ever sent it; it is here for the
|
|
94
|
+
* operator's tools and for tests.
|
|
95
|
+
*/
|
|
96
|
+
state?: unknown;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* What changed on disk that a running session applies only when it next
|
|
100
|
+
* initialises. Each list is empty when nothing of its kind is waiting.
|
|
101
|
+
*/
|
|
102
|
+
export interface PendingChanges {
|
|
103
|
+
/** Settings resources whose resolved values differ from the session's. */
|
|
104
|
+
settings: string[];
|
|
105
|
+
/**
|
|
106
|
+
* Manifest fields read only at initialisation: `identifier`, `teams.mode`,
|
|
107
|
+
* and `setup` for the configuration step. The game's tick limit, team
|
|
108
|
+
* bounds and `openOnStart` are the `game` settings, listed in `settings`.
|
|
109
|
+
*/
|
|
110
|
+
manifest: string[];
|
|
111
|
+
/** Capabilities removed from the package, or whose scope changed. */
|
|
112
|
+
capabilities: string[];
|
|
113
|
+
}
|
|
114
|
+
export interface StateProjection {
|
|
115
|
+
projectionVersion: number;
|
|
116
|
+
game: {
|
|
117
|
+
identifier: string;
|
|
118
|
+
/** The game's name in the session locale, which surfaces render. */
|
|
119
|
+
name: string;
|
|
120
|
+
/** The active scenario, or null when the game declares none. */
|
|
121
|
+
scenarioId: string | null;
|
|
122
|
+
};
|
|
123
|
+
session: {
|
|
124
|
+
/** Ticks the session has completed: the shared clock, or the furthest team's. */
|
|
125
|
+
completedTicks: number;
|
|
126
|
+
mode: SessionMode;
|
|
127
|
+
waitingRoomOpen: boolean;
|
|
128
|
+
/** True only once every team is complete (§12.4). */
|
|
129
|
+
complete: boolean;
|
|
130
|
+
/** Stable for the session, unchanged by a re-run of one tick (§10). */
|
|
131
|
+
seed: string;
|
|
132
|
+
/**
|
|
133
|
+
* What every surface of this run is sent on `init` to namespace its
|
|
134
|
+
* own storage by (§12.2): opaque, unique to the run, and not the
|
|
135
|
+
* session's address. Beyond §20.1's shape, as §20.1 permits: the
|
|
136
|
+
* console needs it to hand the frames it mounts.
|
|
137
|
+
*/
|
|
138
|
+
sessionKey: string;
|
|
139
|
+
locale: string;
|
|
140
|
+
/**
|
|
141
|
+
* Whether this is the game being played or a walkthrough beside it
|
|
142
|
+
* (§5.7). The same value logic reads as `meta.runKind`.
|
|
143
|
+
*/
|
|
144
|
+
runKind: RunKind;
|
|
145
|
+
/**
|
|
146
|
+
* The tick limit: the resolved `game` settings' `maxTicks`, or null when
|
|
147
|
+
* completion is the engine's or the tick controller's to decide.
|
|
148
|
+
*/
|
|
149
|
+
maxTicks: number | null;
|
|
150
|
+
/**
|
|
151
|
+
* The team bounds a surface gates its controls on (§5.4).
|
|
152
|
+
*
|
|
153
|
+
* `max` is the **effective** maximum, already resolved as the lower of
|
|
154
|
+
* the game's declared maximum and this host's own ceiling. A surface
|
|
155
|
+
* that read the manifest value instead would disable its add-team
|
|
156
|
+
* control at the wrong point.
|
|
157
|
+
*/
|
|
158
|
+
teamBounds: {
|
|
159
|
+
min?: number;
|
|
160
|
+
max: number;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* True while the session is in its setup state (§8.3, §9.0): the game has a
|
|
164
|
+
* `setup` slot and nobody has started play yet.
|
|
165
|
+
*
|
|
166
|
+
* On the projection rather than only on a separate route because it
|
|
167
|
+
* decides what a client may render: a console that read it from a
|
|
168
|
+
* second request showed the setup UI for a frame after somebody
|
|
169
|
+
* pressed Play, and the player surfaces for a frame after somebody
|
|
170
|
+
* sent the session back to its setup state.
|
|
171
|
+
*/
|
|
172
|
+
inSetup: boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Edits on disk this session has not applied, because they take
|
|
175
|
+
* effect only when a session initialises. Absent when there are none.
|
|
176
|
+
*
|
|
177
|
+
* A local authoring host's own field, beyond §20.1's shape as §20.1
|
|
178
|
+
* permits: a host that reloads a package while it runs must say when
|
|
179
|
+
* the session no longer matches what is on disk, rather than run on
|
|
180
|
+
* a mixture of the two.
|
|
181
|
+
*/
|
|
182
|
+
pending?: PendingChanges;
|
|
183
|
+
};
|
|
184
|
+
teams: ProjectedTeam[];
|
|
185
|
+
/** The canonical shared store (§7.5), empty outside shared-state mode. */
|
|
186
|
+
shared: Record<string, Record<string, unknown>>;
|
|
187
|
+
/**
|
|
188
|
+
* The engine's session-wide private memory (§10.2), absent until an
|
|
189
|
+
* aggregate function first returns one under `shared.state`.
|
|
190
|
+
*/
|
|
191
|
+
sharedState?: unknown;
|
|
192
|
+
/**
|
|
193
|
+
* The cohort's automatic tick timer (§11.4), the same `TimerState` a
|
|
194
|
+
* surface is sent. Null in independent mode, where each team has its own
|
|
195
|
+
* on its entry.
|
|
196
|
+
*/
|
|
197
|
+
timer: TimerState | null;
|
|
198
|
+
/**
|
|
199
|
+
* Every settings resource's resolved values (§8): defaults, the active
|
|
200
|
+
* scenario, then the session's overrides. Keyed by settings identifier.
|
|
201
|
+
*/
|
|
202
|
+
settings: ResolvedSettings;
|
|
203
|
+
/**
|
|
204
|
+
* The same, without the session layer: defaults then the active scenario.
|
|
205
|
+
* What a surface shown outside the session reads, such as a presentation
|
|
206
|
+
* previewed with no session (§6.15.1).
|
|
207
|
+
*/
|
|
208
|
+
settingsWithoutSession: ResolvedSettings;
|
|
209
|
+
/**
|
|
210
|
+
* Each scenario a scenario editor is open on, with its draft resolved:
|
|
211
|
+
* the defaults, that scenario, then the editor's unsaved edits (§6.5).
|
|
212
|
+
* What the editor is sent as `setSettings`. Absent while none is open.
|
|
213
|
+
*/
|
|
214
|
+
scenarioDrafts?: ScenarioDraft[];
|
|
215
|
+
/**
|
|
216
|
+
* Faults armed for this session. Empty in a session nobody has armed one in.
|
|
217
|
+
*
|
|
218
|
+
* @internal See {@link FaultKind}.
|
|
219
|
+
*/
|
|
220
|
+
faults: ArmedFault[];
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* One endpoint call that changed something (§6.12): who made it, and what it
|
|
224
|
+
* changed. Names only, never values, so the log does not become a second copy
|
|
225
|
+
* of the boards.
|
|
226
|
+
*/
|
|
227
|
+
export interface EndpointAuditEntry {
|
|
228
|
+
/** Epoch milliseconds, on the session's clock. */
|
|
229
|
+
at: number;
|
|
230
|
+
endpoint: string;
|
|
231
|
+
/** The caller's role, as the endpoint was told it. */
|
|
232
|
+
role: EndpointCallerRole;
|
|
233
|
+
/** Who was behind an external call, where the host said. */
|
|
234
|
+
principal?: {
|
|
235
|
+
kind: string;
|
|
236
|
+
id: string;
|
|
237
|
+
name?: string;
|
|
238
|
+
};
|
|
239
|
+
/** The team a team-scoped call ran for. */
|
|
240
|
+
teamId?: string;
|
|
241
|
+
/** Capabilities its own patch wrote. */
|
|
242
|
+
wrote: string[];
|
|
243
|
+
/** A session-scoped call's per-team writes: team id to capabilities. */
|
|
244
|
+
teams?: Record<string, string[]>;
|
|
245
|
+
/** The session actions it returned, in order. */
|
|
246
|
+
actions: string[];
|
|
247
|
+
/**
|
|
248
|
+
* Where the call stopped, when a step failed after earlier ones had
|
|
249
|
+
* landed: those stay applied, and everything from here on did not.
|
|
250
|
+
*/
|
|
251
|
+
stoppedAt?: string;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* What a mutation settled as (§12.5.1).
|
|
255
|
+
*
|
|
256
|
+
* The failure half is the SDK's own {@link MutationOutcome}, not a restatement
|
|
257
|
+
* of it: a projection that re-declared the vocabulary it reports would be free
|
|
258
|
+
* to drift from it.
|
|
259
|
+
*/
|
|
260
|
+
export type MutationResult = {
|
|
261
|
+
ok: true;
|
|
262
|
+
committedAtTick?: number;
|
|
263
|
+
} | {
|
|
264
|
+
ok: false;
|
|
265
|
+
outcome: MutationOutcome;
|
|
266
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one documented shape of a session's observable state.
|
|
3
|
+
*
|
|
4
|
+
* Served three ways and declared once: `sdk view --json`, `GET /api/state`, and
|
|
5
|
+
* the payload the console renders. It is a projection, not any runtime's
|
|
6
|
+
* internal state, so internals can change without breaking an agent that
|
|
7
|
+
* learned to read it, and it is versioned so one that has learned can tell when
|
|
8
|
+
* they have not.
|
|
9
|
+
*
|
|
10
|
+
* Everything a runtime exposes about a session belongs here, because a check
|
|
11
|
+
* made from outside a runtime can only read what the runtime exposes.
|
|
12
|
+
*
|
|
13
|
+
* Published from the SDK rather than declared inside a runtime, because a
|
|
14
|
+
* second runtime implementing it needs the shape, and a type it has to copy is
|
|
15
|
+
* a type the two halves are free to drift apart on.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Bumped when a field changes meaning or leaves.
|
|
19
|
+
*
|
|
20
|
+
* Adding a field is not a bump: a reader that ignores what it does not know
|
|
21
|
+
* keeps working. Renaming or removing one is.
|
|
22
|
+
*/
|
|
23
|
+
export const PROJECTION_VERSION = 4;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for unit-testing a game's logic without a runtime.
|
|
3
|
+
*
|
|
4
|
+
* `logicArgs` builds the arguments object a logic function takes, filling
|
|
5
|
+
* everything the test does not name. `createStubCallbacks` is the offline,
|
|
6
|
+
* deterministic set of callbacks it uses, and the stubs behind it are the ones
|
|
7
|
+
* `createTestSession` answers service callbacks with.
|
|
8
|
+
*
|
|
9
|
+
* To test a game as a whole (hooks, validators, endpoints, undo, timers), use
|
|
10
|
+
* `createTestSession` from `@seriousgaming/sdk-tools/client`.
|
|
11
|
+
*/
|
|
12
|
+
export { logicArgs, TEST_NOW, TEST_SEED, type AggregateArgsInput, type EndpointArgsInput, type EngineArgsInput, type HookArgsInput, type RequestTickArgsInput, type TickControllerArgsInput, type ValidatorArgsInput, } from './logic-args.js';
|
|
13
|
+
export { createStubCallbacks, STUB_SPEECH_DURATION_MS, stubExtractText, stubGenerateText, stubSpeechAudio, } from './stub-services.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for unit-testing a game's logic without a runtime.
|
|
3
|
+
*
|
|
4
|
+
* `logicArgs` builds the arguments object a logic function takes, filling
|
|
5
|
+
* everything the test does not name. `createStubCallbacks` is the offline,
|
|
6
|
+
* deterministic set of callbacks it uses, and the stubs behind it are the ones
|
|
7
|
+
* `createTestSession` answers service callbacks with.
|
|
8
|
+
*
|
|
9
|
+
* To test a game as a whole (hooks, validators, endpoints, undo, timers), use
|
|
10
|
+
* `createTestSession` from `@seriousgaming/sdk-tools/client`.
|
|
11
|
+
*/
|
|
12
|
+
export { logicArgs, TEST_NOW, TEST_SEED, } from './logic-args.js';
|
|
13
|
+
export { createStubCallbacks, STUB_SPEECH_DURATION_MS, stubExtractText, stubGenerateText, stubSpeechAudio, } from './stub-services.js';
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arguments for calling a logic function directly in a unit test.
|
|
3
|
+
*
|
|
4
|
+
* Every logic function takes one arguments object, and most of it is the
|
|
5
|
+
* runtime's to supply: `meta`, the roster, the callbacks, a session summary.
|
|
6
|
+
* A test cares about the context and perhaps one setting. Each builder here
|
|
7
|
+
* takes what the test cares about and fills the rest with fixed, deterministic
|
|
8
|
+
* values, typed so the result passes straight to the function with no cast.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { logicArgs } from '@seriousgaming/sdk/testing';
|
|
12
|
+
* import { defaultContext, defaultSettings } from './defaults';
|
|
13
|
+
* import { Run } from './logic';
|
|
14
|
+
*
|
|
15
|
+
* const result = await Run(
|
|
16
|
+
* logicArgs.run({ context: defaultContext, settings: defaultSettings, meta: { tick: 3 } })
|
|
17
|
+
* );
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Settings are not read from disk: there is no runtime here. Pass the
|
|
21
|
+
* resource's generated `defaultSettings`, spread with any value the test
|
|
22
|
+
* changes. A resource that declares no settings may leave `settings` out.
|
|
23
|
+
*/
|
|
24
|
+
import type { AggregateFunctionShared, AggregateFunctionTeam, EndpointCaller, EndpointHandlerArgs, EndpointScope, EndpointSession, EndpointTeamEntry, EngineFunctionArgs, HookFunctionArgs, HookPayloadMap, LogicMeta, Participant, RequestTickFunctionArgs, RunAggregateFunctionArgs, RunMeta, SignatureCallbacks, TeamInfo, TeamRunMeta, TickControllerFunctionArgs, ValidatorActor, ValidatorFunctionArgs } from '../build/index.js';
|
|
25
|
+
import type { HookSignal } from '../build/resource-schema.js';
|
|
26
|
+
/** The `meta.seed` every builder uses unless told otherwise. */
|
|
27
|
+
export declare const TEST_SEED = "test-seed";
|
|
28
|
+
/** The `meta.now` every builder uses unless told otherwise: 2026-01-01T00:00:00Z. */
|
|
29
|
+
export declare const TEST_NOW: number;
|
|
30
|
+
/** A type with no members, which an empty object satisfies. */
|
|
31
|
+
type Empty = Record<never, never>;
|
|
32
|
+
/** The settings a resource that declares none receives. */
|
|
33
|
+
type NoSettings = Record<string, never>;
|
|
34
|
+
/** The callbacks of any logic-bearing resource: some subset of {@link SignatureCallbacks}. */
|
|
35
|
+
type AnyCallbacks = Partial<SignatureCallbacks>;
|
|
36
|
+
/**
|
|
37
|
+
* `settings`, optional only where the type has nothing a test could leave
|
|
38
|
+
* out: a resource that declares no settings resources. Anything else needs its
|
|
39
|
+
* values, since a builder cannot read the schema defaults from disk.
|
|
40
|
+
*/
|
|
41
|
+
type SettingsInput<TSettings> = Empty extends TSettings ? {
|
|
42
|
+
settings?: TSettings;
|
|
43
|
+
} : {
|
|
44
|
+
settings: TSettings;
|
|
45
|
+
};
|
|
46
|
+
/** What every team-scoped builder takes beyond its own arguments. */
|
|
47
|
+
interface CommonInput<TCallbacks> {
|
|
48
|
+
/**
|
|
49
|
+
* The roster the call sees. Defaults to one connected participant on the
|
|
50
|
+
* call's team (two teams' worth for a builder with several teams).
|
|
51
|
+
*/
|
|
52
|
+
participants?: readonly Readonly<Participant>[];
|
|
53
|
+
/**
|
|
54
|
+
* Callbacks to use instead of the stubs. Anything not named keeps its stub
|
|
55
|
+
* (see `createStubCallbacks`).
|
|
56
|
+
*/
|
|
57
|
+
callbacks?: NoInfer<Partial<TCallbacks>>;
|
|
58
|
+
}
|
|
59
|
+
/** Input to {@link logicArgs.init} and {@link logicArgs.run}. */
|
|
60
|
+
export type EngineArgsInput<TContext, TSettings, TCallbacks, TState> = CommonInput<TCallbacks> & SettingsInput<TSettings> & {
|
|
61
|
+
context: TContext;
|
|
62
|
+
/** Any of `meta`; the rest is filled. `teamId` follows `index` when only `index` is given. */
|
|
63
|
+
meta?: Partial<TeamRunMeta>;
|
|
64
|
+
state?: TState;
|
|
65
|
+
};
|
|
66
|
+
/** Input to {@link logicArgs.aggregate}. */
|
|
67
|
+
export type AggregateArgsInput<TTeamContext, TSharedContext, TSettings, TCallbacks, TTeamState, TSharedState> = CommonInput<TCallbacks> & SettingsInput<TSettings> & (Empty extends TSharedContext ? {
|
|
68
|
+
shared?: AggregateFunctionShared<TSharedContext, TSharedState>;
|
|
69
|
+
} : {
|
|
70
|
+
shared: AggregateFunctionShared<TSharedContext, TSharedState>;
|
|
71
|
+
}) & {
|
|
72
|
+
/** Every team the call covers. A team's `teamId` follows its `index` when left out. */
|
|
73
|
+
teams: (Omit<AggregateFunctionTeam<TTeamContext, TTeamState>, 'teamId'> & {
|
|
74
|
+
teamId?: string;
|
|
75
|
+
})[];
|
|
76
|
+
meta?: Partial<RunMeta>;
|
|
77
|
+
};
|
|
78
|
+
/** Input to {@link logicArgs.hook}. */
|
|
79
|
+
export type HookArgsInput<S extends HookSignal, TContext, TSettings, TCallbacks> = CommonInput<TCallbacks> & SettingsInput<TSettings> & HookPayloadMap[S] & {
|
|
80
|
+
/**
|
|
81
|
+
* The signal the hook subscribes to, which decides the payload it
|
|
82
|
+
* needs. Defaults to `participantJoin`; name it for any other.
|
|
83
|
+
*/
|
|
84
|
+
signal?: S;
|
|
85
|
+
context: TContext;
|
|
86
|
+
meta?: Partial<LogicMeta>;
|
|
87
|
+
};
|
|
88
|
+
/** Input to {@link logicArgs.endpoint}. */
|
|
89
|
+
export type EndpointArgsInput<TRequest, TContext, TCallbacks, TTeamContext, TSettings> = CommonInput<TCallbacks> & SettingsInput<TSettings> & {
|
|
90
|
+
request: TRequest;
|
|
91
|
+
context: TContext;
|
|
92
|
+
/**
|
|
93
|
+
* Who is calling. `role` defaults to `participant`; the rest follows the
|
|
94
|
+
* role: a participant is the first on the roster, through `ui`; a
|
|
95
|
+
* facilitator calls from `session`; an author calls from `scenario_editor`
|
|
96
|
+
* with no session; an external caller names no surface.
|
|
97
|
+
*/
|
|
98
|
+
caller?: Partial<EndpointCaller>;
|
|
99
|
+
/** The team a team-scoped call acts on. Defaults to `team-1`, index 0. */
|
|
100
|
+
team?: Partial<TeamInfo>;
|
|
101
|
+
/** A session-scoped call's per-team values. */
|
|
102
|
+
teams?: EndpointTeamEntry<TTeamContext>[];
|
|
103
|
+
/** Where the session stands. Defaults to an independent session with no ticks completed. */
|
|
104
|
+
session?: Partial<EndpointSession>;
|
|
105
|
+
meta?: Partial<LogicMeta>;
|
|
106
|
+
};
|
|
107
|
+
/** Input to {@link logicArgs.tickController}. */
|
|
108
|
+
export type TickControllerArgsInput<TContext, TSettings, TCallbacks> = CommonInput<TCallbacks> & SettingsInput<TSettings> & {
|
|
109
|
+
context: TContext;
|
|
110
|
+
meta?: Partial<TeamRunMeta>;
|
|
111
|
+
/** Defaults to the one team `meta` names, with `context`. */
|
|
112
|
+
teams?: AggregateFunctionTeam<TContext>[];
|
|
113
|
+
waitingRoomOpen?: boolean;
|
|
114
|
+
};
|
|
115
|
+
/** Input to {@link logicArgs.validator}. */
|
|
116
|
+
export type ValidatorArgsInput<TContext, TSettings> = SettingsInput<TSettings> & {
|
|
117
|
+
previous: TContext;
|
|
118
|
+
next: TContext;
|
|
119
|
+
/** Defaults to the first participant on the roster. */
|
|
120
|
+
actor?: ValidatorActor;
|
|
121
|
+
meta?: Partial<LogicMeta>;
|
|
122
|
+
participants?: readonly Readonly<Participant>[];
|
|
123
|
+
};
|
|
124
|
+
/** Input to {@link logicArgs.requestTick}. */
|
|
125
|
+
export type RequestTickArgsInput<TContext, TSettings> = SettingsInput<TSettings> & {
|
|
126
|
+
context: TContext;
|
|
127
|
+
/** Defaults to 1, a team's first request. */
|
|
128
|
+
requestedTick?: number;
|
|
129
|
+
/** Defaults to the first participant on the roster. */
|
|
130
|
+
actor?: ValidatorActor;
|
|
131
|
+
meta?: Partial<LogicMeta>;
|
|
132
|
+
participants?: readonly Readonly<Participant>[];
|
|
133
|
+
};
|
|
134
|
+
declare function init<TContext, TSettings = NoSettings, TCallbacks extends AnyCallbacks = Required<SignatureCallbacks>, TState = never>(input: EngineArgsInput<TContext, TSettings, TCallbacks, TState>): EngineFunctionArgs<TContext, TSettings, TCallbacks, TState>;
|
|
135
|
+
declare function run<TContext, TSettings = NoSettings, TCallbacks extends AnyCallbacks = Required<SignatureCallbacks>, TState = never>(input: EngineArgsInput<TContext, TSettings, TCallbacks, TState>): EngineFunctionArgs<TContext, TSettings, TCallbacks, TState>;
|
|
136
|
+
declare function aggregate<TTeamContext, TSharedContext = NoSettings, TSettings = NoSettings, TCallbacks extends AnyCallbacks = Required<SignatureCallbacks>, TTeamState = never, TSharedState = never>(input: AggregateArgsInput<TTeamContext, TSharedContext, TSettings, TCallbacks, TTeamState, TSharedState>): RunAggregateFunctionArgs<TTeamContext, TSharedContext, TSettings, TCallbacks, TTeamState, TSharedState>;
|
|
137
|
+
declare function hook<S extends HookSignal = 'participantJoin', TContext = unknown, TSettings = NoSettings, TCallbacks extends AnyCallbacks = Required<SignatureCallbacks>>(input: HookArgsInput<S, TContext, TSettings, TCallbacks>): HookFunctionArgs<S, TContext, TSettings, TCallbacks>;
|
|
138
|
+
declare function endpoint<TRequest, TContext, TCallbacks extends AnyCallbacks = Required<SignatureCallbacks>, TTeamContext = never, TScope extends EndpointScope = 'team', TSettings = NoSettings>(input: EndpointArgsInput<TRequest, TContext, TCallbacks, TTeamContext, TSettings>): EndpointHandlerArgs<TRequest, TContext, TCallbacks, TTeamContext, TScope, TSettings>;
|
|
139
|
+
declare function tickController<TContext, TSettings = NoSettings, TCallbacks extends AnyCallbacks = Required<SignatureCallbacks>>(input: TickControllerArgsInput<TContext, TSettings, TCallbacks>): TickControllerFunctionArgs<TContext, TSettings, TCallbacks>;
|
|
140
|
+
declare function validator<TContext, TSettings = NoSettings>(input: ValidatorArgsInput<TContext, TSettings>): ValidatorFunctionArgs<TContext, TSettings>;
|
|
141
|
+
declare function requestTick<TContext, TSettings = NoSettings>(input: RequestTickArgsInput<TContext, TSettings>): RequestTickFunctionArgs<TContext, TSettings>;
|
|
142
|
+
/**
|
|
143
|
+
* Builders for each logic function's arguments. Each takes what the test
|
|
144
|
+
* names and fills the rest:
|
|
145
|
+
*
|
|
146
|
+
* - `meta`: `locale: 'en'`, `seed: 'test-seed'`, `runKind: 'session'`,
|
|
147
|
+
* `now` 2026-01-01T00:00:00Z, and where the function runs for a team,
|
|
148
|
+
* `index: 0` and `teamId: 'team-1'`. `tick` is 0 for `init` and 1 for the
|
|
149
|
+
* rest; `InitAggregate` passes `meta: { tick: 0 }`
|
|
150
|
+
* - `participants`: one connected participant on each team the call covers
|
|
151
|
+
* - `callbacks`: the offline stubs of `createStubCallbacks`, with any the
|
|
152
|
+
* test passes in their place
|
|
153
|
+
* - `settings`: required unless the resource declares none, since there is no
|
|
154
|
+
* runtime to resolve them. Pass the generated `defaultSettings`
|
|
155
|
+
*
|
|
156
|
+
* | Builder | For |
|
|
157
|
+
* | ---------------- | ----------------------------------------------- |
|
|
158
|
+
* | `init` | the engine's `Init` |
|
|
159
|
+
* | `run` | the engine's `Run`, and the steps it calls |
|
|
160
|
+
* | `aggregate` | `RunAggregate` and `InitAggregate` |
|
|
161
|
+
* | `hook` | a hook's `Run` |
|
|
162
|
+
* | `endpoint` | an endpoint's `Handle` or `Plan` |
|
|
163
|
+
* | `tickController` | `GetTickController` |
|
|
164
|
+
* | `validator` | a validator's `UpdateData` |
|
|
165
|
+
* | `requestTick` | a validator's `RequestTick` |
|
|
166
|
+
*/
|
|
167
|
+
export declare const logicArgs: {
|
|
168
|
+
init: typeof init;
|
|
169
|
+
run: typeof run;
|
|
170
|
+
aggregate: typeof aggregate;
|
|
171
|
+
hook: typeof hook;
|
|
172
|
+
endpoint: typeof endpoint;
|
|
173
|
+
tickController: typeof tickController;
|
|
174
|
+
validator: typeof validator;
|
|
175
|
+
requestTick: typeof requestTick;
|
|
176
|
+
};
|
|
177
|
+
export {};
|