@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.
Files changed (170) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +1 -0
  3. package/README.md +33 -2
  4. package/lib/build/callbacks.d.ts +998 -0
  5. package/lib/build/callbacks.js +32 -0
  6. package/lib/build/context-merge.d.ts +59 -0
  7. package/lib/build/context-merge.js +118 -0
  8. package/lib/build/document.d.ts +36 -0
  9. package/lib/build/document.js +8 -0
  10. package/lib/build/encoding.d.ts +26 -0
  11. package/lib/build/encoding.js +78 -0
  12. package/lib/build/endpoints.d.ts +421 -0
  13. package/lib/build/endpoints.js +46 -0
  14. package/lib/build/hooks.d.ts +74 -0
  15. package/lib/build/hooks.js +1 -0
  16. package/lib/build/index.d.ts +18 -0
  17. package/lib/build/index.js +16 -0
  18. package/lib/build/llm.d.ts +166 -0
  19. package/lib/build/llm.js +17 -0
  20. package/lib/build/resource-schema.d.ts +1048 -0
  21. package/lib/build/resource-schema.js +7 -0
  22. package/lib/build/scheduling.d.ts +112 -0
  23. package/lib/build/scheduling.js +217 -0
  24. package/lib/build/seed.d.ts +51 -0
  25. package/lib/build/seed.js +89 -0
  26. package/lib/build/signatures.d.ts +372 -0
  27. package/lib/build/signatures.js +1 -0
  28. package/lib/build/speech.d.ts +102 -0
  29. package/lib/build/speech.js +11 -0
  30. package/lib/build/tick-validation.d.ts +23 -0
  31. package/lib/build/tick-validation.js +96 -0
  32. package/lib/build/timer.d.ts +74 -0
  33. package/lib/build/timer.js +1 -0
  34. package/lib/build/validators.d.ts +116 -0
  35. package/lib/build/validators.js +1 -0
  36. package/lib/commands.d.ts +357 -0
  37. package/lib/commands.js +14 -0
  38. package/lib/e2e.d.ts +238 -0
  39. package/lib/e2e.js +248 -0
  40. package/lib/projection.d.ts +266 -0
  41. package/lib/projection.js +23 -0
  42. package/lib/testing/index.d.ts +13 -0
  43. package/lib/testing/index.js +13 -0
  44. package/lib/testing/logic-args.d.ts +177 -0
  45. package/lib/testing/logic-args.js +229 -0
  46. package/lib/testing/stub-services.d.ts +41 -0
  47. package/lib/testing/stub-services.js +176 -0
  48. package/lib/ui/CrossTeamDataContext.d.ts +36 -0
  49. package/lib/ui/CrossTeamDataContext.js +32 -0
  50. package/lib/ui/PresentationContext.d.ts +72 -0
  51. package/lib/ui/PresentationContext.js +13 -0
  52. package/lib/ui/PresentationWrapper.d.ts +12 -0
  53. package/lib/ui/PresentationWrapper.js +78 -0
  54. package/lib/ui/SessionUserInterfaceCallbacksContext.d.ts +3 -0
  55. package/lib/ui/SessionUserInterfaceCallbacksContext.js +7 -0
  56. package/lib/ui/SessionUserInterfaceDataContext.d.ts +103 -0
  57. package/lib/ui/SessionUserInterfaceDataContext.js +17 -0
  58. package/lib/ui/SessionUserInterfaceHookFailuresContext.d.ts +44 -0
  59. package/lib/ui/SessionUserInterfaceHookFailuresContext.js +15 -0
  60. package/lib/ui/SessionUserInterfaceHostOverlaysContext.d.ts +23 -0
  61. package/lib/ui/SessionUserInterfaceHostOverlaysContext.js +23 -0
  62. package/lib/ui/SessionUserInterfaceLocaleContext.d.ts +11 -0
  63. package/lib/ui/SessionUserInterfaceLocaleContext.js +13 -0
  64. package/lib/ui/SessionUserInterfaceMetaContext.d.ts +39 -0
  65. package/lib/ui/SessionUserInterfaceMetaContext.js +13 -0
  66. package/lib/ui/SessionUserInterfaceParticipantsContext.d.ts +12 -0
  67. package/lib/ui/SessionUserInterfaceParticipantsContext.js +16 -0
  68. package/lib/ui/SessionUserInterfaceTeamConfigurationContext.d.ts +53 -0
  69. package/lib/ui/SessionUserInterfaceTeamConfigurationContext.js +23 -0
  70. package/lib/ui/SessionUserInterfaceTeamLinksContext.d.ts +56 -0
  71. package/lib/ui/SessionUserInterfaceTeamLinksContext.js +12 -0
  72. package/lib/ui/SessionUserInterfaceTeamsContext.d.ts +13 -0
  73. package/lib/ui/SessionUserInterfaceTeamsContext.js +13 -0
  74. package/lib/ui/SessionUserInterfaceThemeContext.d.ts +9 -0
  75. package/lib/ui/SessionUserInterfaceThemeContext.js +7 -0
  76. package/lib/ui/SessionUserInterfaceThemePreferenceContext.d.ts +3 -0
  77. package/lib/ui/SessionUserInterfaceThemePreferenceContext.js +7 -0
  78. package/lib/ui/SessionUserInterfaceWalkthroughLinkContext.d.ts +42 -0
  79. package/lib/ui/SessionUserInterfaceWalkthroughLinkContext.js +26 -0
  80. package/lib/ui/SessionUserInterfaceWrapper.d.ts +8 -0
  81. package/lib/ui/SessionUserInterfaceWrapper.js +321 -0
  82. package/lib/ui/SettingsEditorCallbacksContext.d.ts +3 -0
  83. package/lib/ui/SettingsEditorCallbacksContext.js +7 -0
  84. package/lib/ui/SettingsEditorContext.d.ts +33 -0
  85. package/lib/ui/SettingsEditorContext.js +16 -0
  86. package/lib/ui/SettingsEditorLocaleContext.d.ts +13 -0
  87. package/lib/ui/SettingsEditorLocaleContext.js +15 -0
  88. package/lib/ui/SettingsEditorThemeContext.d.ts +9 -0
  89. package/lib/ui/SettingsEditorThemeContext.js +7 -0
  90. package/lib/ui/SettingsEditorThemePreferenceContext.d.ts +3 -0
  91. package/lib/ui/SettingsEditorThemePreferenceContext.js +7 -0
  92. package/lib/ui/SettingsEditorWrapper.d.ts +13 -0
  93. package/lib/ui/SettingsEditorWrapper.js +74 -0
  94. package/lib/ui/UserInterfaceCallbacksContext.d.ts +3 -0
  95. package/lib/ui/UserInterfaceCallbacksContext.js +7 -0
  96. package/lib/ui/UserInterfaceDataContext.d.ts +78 -0
  97. package/lib/ui/UserInterfaceDataContext.js +11 -0
  98. package/lib/ui/UserInterfaceLocaleContext.d.ts +13 -0
  99. package/lib/ui/UserInterfaceLocaleContext.js +15 -0
  100. package/lib/ui/UserInterfaceOwnTeamContext.d.ts +25 -0
  101. package/lib/ui/UserInterfaceOwnTeamContext.js +26 -0
  102. package/lib/ui/UserInterfaceOwnTeamJoinLinkContext.d.ts +52 -0
  103. package/lib/ui/UserInterfaceOwnTeamJoinLinkContext.js +13 -0
  104. package/lib/ui/UserInterfaceParticipantContext.d.ts +16 -0
  105. package/lib/ui/UserInterfaceParticipantContext.js +24 -0
  106. package/lib/ui/UserInterfaceParticipantsContext.d.ts +12 -0
  107. package/lib/ui/UserInterfaceParticipantsContext.js +13 -0
  108. package/lib/ui/UserInterfaceRunKindContext.d.ts +31 -0
  109. package/lib/ui/UserInterfaceRunKindContext.js +31 -0
  110. package/lib/ui/UserInterfaceTeamsContext.d.ts +12 -0
  111. package/lib/ui/UserInterfaceTeamsContext.js +13 -0
  112. package/lib/ui/UserInterfaceThemeContext.d.ts +9 -0
  113. package/lib/ui/UserInterfaceThemeContext.js +7 -0
  114. package/lib/ui/UserInterfaceThemePreferenceContext.d.ts +3 -0
  115. package/lib/ui/UserInterfaceThemePreferenceContext.js +7 -0
  116. package/lib/ui/UserInterfaceTimerContext.d.ts +10 -0
  117. package/lib/ui/UserInterfaceTimerContext.js +12 -0
  118. package/lib/ui/UserInterfaceValidationContext.d.ts +25 -0
  119. package/lib/ui/UserInterfaceValidationContext.js +14 -0
  120. package/lib/ui/UserInterfaceViewerRoleContext.d.ts +14 -0
  121. package/lib/ui/UserInterfaceViewerRoleContext.js +17 -0
  122. package/lib/ui/UserInterfaceWrapper.d.ts +8 -0
  123. package/lib/ui/UserInterfaceWrapper.js +219 -0
  124. package/lib/ui/expectedParentOrigin.d.ts +10 -0
  125. package/lib/ui/expectedParentOrigin.js +32 -0
  126. package/lib/ui/index.d.ts +50 -0
  127. package/lib/ui/index.js +52 -0
  128. package/lib/ui/internal/SurfaceGate.d.ts +19 -0
  129. package/lib/ui/internal/SurfaceGate.js +17 -0
  130. package/lib/ui/internal/SurfaceScope.d.ts +17 -0
  131. package/lib/ui/internal/SurfaceScope.js +16 -0
  132. package/lib/ui/internal/createContexts.d.ts +50 -0
  133. package/lib/ui/internal/createContexts.js +32 -0
  134. package/lib/ui/internal/document-attributes.d.ts +9 -0
  135. package/lib/ui/internal/document-attributes.js +87 -0
  136. package/lib/ui/internal/surface-timer.d.ts +3 -0
  137. package/lib/ui/internal/surface-timer.js +11 -0
  138. package/lib/ui/internal/useLatestRef.d.ts +7 -0
  139. package/lib/ui/internal/useLatestRef.js +11 -0
  140. package/lib/ui/internal/useOptimisticMerge.d.ts +19 -0
  141. package/lib/ui/internal/useOptimisticMerge.js +28 -0
  142. package/lib/ui/internal/useSurfaceControls.d.ts +52 -0
  143. package/lib/ui/internal/useSurfaceControls.js +19 -0
  144. package/lib/ui/internal/useTypedPastState.d.ts +17 -0
  145. package/lib/ui/internal/useTypedPastState.js +17 -0
  146. package/lib/ui/mutation-commit.d.ts +32 -0
  147. package/lib/ui/mutation-commit.js +1 -0
  148. package/lib/ui/mutation-outcome.d.ts +66 -0
  149. package/lib/ui/mutation-outcome.js +49 -0
  150. package/lib/ui/request-id.d.ts +18 -0
  151. package/lib/ui/request-id.js +44 -0
  152. package/lib/ui/testing.d.ts +365 -0
  153. package/lib/ui/testing.js +572 -0
  154. package/lib/ui/tick-snapshot.d.ts +28 -0
  155. package/lib/ui/tick-snapshot.js +34 -0
  156. package/lib/ui/ui-protocol.d.ts +799 -0
  157. package/lib/ui/ui-protocol.js +50 -0
  158. package/lib/ui/useAsset.d.ts +80 -0
  159. package/lib/ui/useAsset.js +139 -0
  160. package/lib/ui/useEndpointCallbacks.d.ts +31 -0
  161. package/lib/ui/useEndpointCallbacks.js +68 -0
  162. package/lib/ui/useHostChannel.d.ts +90 -0
  163. package/lib/ui/useHostChannel.js +338 -0
  164. package/lib/ui/useMutationReporter.d.ts +100 -0
  165. package/lib/ui/useMutationReporter.js +97 -0
  166. package/lib/ui/usePastState.d.ts +39 -0
  167. package/lib/ui/usePastState.js +63 -0
  168. package/lib/ui/useViewerStorage.d.ts +54 -0
  169. package/lib/ui/useViewerStorage.js +141 -0
  170. package/package.json +89 -3
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Which surface a wrapper renders, as far as storage is concerned.
3
+ *
4
+ * By wrapper rather than by slot: a game UI and its waiting room are both a
5
+ * player's, so a choice made in one is there in the other, and the two
6
+ * settings editors share a wrapper that is never told which slot it fills
7
+ * (§6.5). They never share a key, because the scenario editor is shown
8
+ * outside any session.
9
+ */
10
+ export type ViewerStorageSurface = 'player' | 'session' | 'settings-editor' | 'presentation';
11
+ /** What a wrapper tells {@link useViewerStorage} about where it is. */
12
+ export interface ViewerStorageScope {
13
+ /**
14
+ * The `sessionKey` the host sent on `init` (§12.2). Undefined on a host
15
+ * that sends none, which keeps every value in memory rather than risk
16
+ * sharing it with another session on the same origin.
17
+ */
18
+ sessionKey: string | undefined;
19
+ surface: ViewerStorageSurface;
20
+ /** The participant's id, or the viewer's role where there is no participant. */
21
+ viewer: string;
22
+ }
23
+ /**
24
+ * Provided by every surface wrapper. Exported for the test helpers, which
25
+ * provide it without a host; game code reads it through {@link useViewerStorage}.
26
+ */
27
+ export declare const ViewerStorageContext: import("react").Context<ViewerStorageScope | undefined>;
28
+ /**
29
+ * State that this browser remembers for this viewer, like `useState` but kept
30
+ * across a reload.
31
+ *
32
+ * Namespaced by the run's `sessionKey`, the surface, and the viewer (the
33
+ * participant, or the viewer's role where there is none), so a value never
34
+ * leaks into another session that happens to give a team the same id, or to
35
+ * another participant sharing the device. A walkthrough has its own key, so
36
+ * a demonstration never touches the real session's values.
37
+ *
38
+ * Per browser, never shared: use it for a viewer's own preferences, such as a
39
+ * collapsed panel or a chosen tab, and context for anything the game needs.
40
+ * Every access is guarded, so a browser that blocks storage falls back to
41
+ * memory for the life of the page rather than throwing. Values are stored as
42
+ * JSON. Other tabs on the same surface follow a change.
43
+ *
44
+ * ```tsx
45
+ * const [collapsed, setCollapsed] = useViewerStorage('help-collapsed', false);
46
+ * ```
47
+ *
48
+ * @param key Names the value within this surface and viewer
49
+ * @param initial The value until one is stored, or a function returning it
50
+ * @returns The value and a setter, as `useState` returns them
51
+ */
52
+ export declare function useViewerStorage<T>(key: string, initial: T | (() => T)): [T, (value: T | ((previous: T) => T)) => void];
53
+ /** Drop every value held in memory. For tests. */
54
+ export declare function clearViewerStorageMemory(): void;
@@ -0,0 +1,141 @@
1
+ import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
2
+ /**
3
+ * Provided by every surface wrapper. Exported for the test helpers, which
4
+ * provide it without a host; game code reads it through {@link useViewerStorage}.
5
+ */
6
+ export const ViewerStorageContext = createContext(undefined);
7
+ /** Values whose browser storage was unavailable, by namespaced key. */
8
+ const memory = new Map();
9
+ /** Every mounted hook, by namespaced key, so one write reaches the rest in the tab. */
10
+ const subscribers = new Map();
11
+ function storage() {
12
+ try {
13
+ return typeof window === 'undefined' ? null : window.localStorage;
14
+ }
15
+ catch {
16
+ // Reading the property itself throws where storage is blocked.
17
+ return null;
18
+ }
19
+ }
20
+ /** The browser storage key for one value: every part encoded, so none can forge another. */
21
+ function namespaced(scope, key) {
22
+ const parts = [scope.sessionKey ?? '', scope.surface, scope.viewer, key];
23
+ return `sg:${parts.map(encodeURIComponent).join(':')}`;
24
+ }
25
+ function readRaw(name, persistent) {
26
+ if (memory.has(name))
27
+ return memory.get(name) ?? null;
28
+ if (!persistent)
29
+ return null;
30
+ try {
31
+ return storage()?.getItem(name) ?? null;
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ function writeRaw(name, raw, persistent) {
38
+ if (persistent) {
39
+ try {
40
+ const store = storage();
41
+ if (store) {
42
+ store.setItem(name, raw);
43
+ memory.delete(name);
44
+ return;
45
+ }
46
+ }
47
+ catch {
48
+ // Quota, private mode, or a blocked origin: kept in memory instead.
49
+ }
50
+ }
51
+ memory.set(name, raw);
52
+ }
53
+ function parse(raw, fallback) {
54
+ if (raw === null)
55
+ return fallback;
56
+ try {
57
+ return JSON.parse(raw);
58
+ }
59
+ catch {
60
+ return fallback;
61
+ }
62
+ }
63
+ function notify(name) {
64
+ subscribers.get(name)?.forEach((listener) => listener());
65
+ }
66
+ /**
67
+ * State that this browser remembers for this viewer, like `useState` but kept
68
+ * across a reload.
69
+ *
70
+ * Namespaced by the run's `sessionKey`, the surface, and the viewer (the
71
+ * participant, or the viewer's role where there is none), so a value never
72
+ * leaks into another session that happens to give a team the same id, or to
73
+ * another participant sharing the device. A walkthrough has its own key, so
74
+ * a demonstration never touches the real session's values.
75
+ *
76
+ * Per browser, never shared: use it for a viewer's own preferences, such as a
77
+ * collapsed panel or a chosen tab, and context for anything the game needs.
78
+ * Every access is guarded, so a browser that blocks storage falls back to
79
+ * memory for the life of the page rather than throwing. Values are stored as
80
+ * JSON. Other tabs on the same surface follow a change.
81
+ *
82
+ * ```tsx
83
+ * const [collapsed, setCollapsed] = useViewerStorage('help-collapsed', false);
84
+ * ```
85
+ *
86
+ * @param key Names the value within this surface and viewer
87
+ * @param initial The value until one is stored, or a function returning it
88
+ * @returns The value and a setter, as `useState` returns them
89
+ */
90
+ export function useViewerStorage(key, initial) {
91
+ const scope = useContext(ViewerStorageContext);
92
+ if (scope === undefined) {
93
+ throw new Error('useViewerStorage must be used inside a surface wrapper');
94
+ }
95
+ const name = namespaced(scope, key);
96
+ const persistent = scope.sessionKey !== undefined;
97
+ const fallback = useMemo(() => (typeof initial === 'function' ? initial() : initial),
98
+ // The initial value is read once per key, as useState reads it once.
99
+ // eslint-disable-next-line react-hooks/exhaustive-deps
100
+ [name]);
101
+ const [value, setValue] = useState(() => parse(readRaw(name, persistent), fallback));
102
+ useEffect(() => {
103
+ const refresh = () => setValue(parse(readRaw(name, persistent), fallback));
104
+ refresh();
105
+ let listeners = subscribers.get(name);
106
+ if (!listeners) {
107
+ listeners = new Set();
108
+ subscribers.set(name, listeners);
109
+ }
110
+ listeners.add(refresh);
111
+ const onStorage = (event) => {
112
+ if (event.key === name || event.key === null)
113
+ refresh();
114
+ };
115
+ window.addEventListener('storage', onStorage);
116
+ return () => {
117
+ listeners.delete(refresh);
118
+ if (listeners.size === 0)
119
+ subscribers.delete(name);
120
+ window.removeEventListener('storage', onStorage);
121
+ };
122
+ }, [name, persistent, fallback]);
123
+ const set = useCallback((next) => {
124
+ const current = parse(readRaw(name, persistent), fallback);
125
+ const resolved = typeof next === 'function' ? next(current) : next;
126
+ let raw;
127
+ try {
128
+ raw = JSON.stringify(resolved) ?? 'null';
129
+ }
130
+ catch {
131
+ return;
132
+ }
133
+ writeRaw(name, raw, persistent);
134
+ notify(name);
135
+ }, [name, persistent, fallback]);
136
+ return [value, set];
137
+ }
138
+ /** Drop every value held in memory. For tests. */
139
+ export function clearViewerStorageMemory() {
140
+ memory.clear();
141
+ }
package/package.json CHANGED
@@ -1,6 +1,92 @@
1
1
  {
2
2
  "name": "@seriousgaming/sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0-alpha.2",
4
+ "description": "SDK for building Serious Gaming games",
5
+ "homepage": "https://sdk.seriousgaming.com/",
6
+ "license": "Apache-2.0",
7
+ "author": "Redburn Technology Ltd",
8
+ "files": [
9
+ "lib",
10
+ "README.md",
11
+ "LICENSE",
12
+ "NOTICE"
13
+ ],
14
+ "type": "module",
15
+ "main": "lib/build/index.js",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/build/index.d.ts",
19
+ "import": "./lib/build/index.js"
20
+ },
21
+ "./ui": {
22
+ "types": "./lib/ui/index.d.ts",
23
+ "import": "./lib/ui/index.js"
24
+ },
25
+ "./ui/testing": {
26
+ "types": "./lib/ui/testing.d.ts",
27
+ "import": "./lib/ui/testing.js"
28
+ },
29
+ "./testing": {
30
+ "types": "./lib/testing/index.d.ts",
31
+ "import": "./lib/testing/index.js"
32
+ },
33
+ "./projection": {
34
+ "types": "./lib/projection.d.ts",
35
+ "import": "./lib/projection.js"
36
+ },
37
+ "./commands": {
38
+ "types": "./lib/commands.d.ts",
39
+ "import": "./lib/commands.js"
40
+ },
41
+ "./e2e": {
42
+ "types": "./lib/e2e.d.ts",
43
+ "import": "./lib/e2e.js"
44
+ }
45
+ },
46
+ "devDependencies": {
47
+ "@testing-library/jest-dom": "^7.0.1",
48
+ "@testing-library/react": "^16.3.3",
49
+ "@types/node": "^24.19.1",
50
+ "@types/react": "^19.3.0",
51
+ "@types/react-dom": "^19.3.0",
52
+ "@vitejs/plugin-react": "^6.1.2",
53
+ "@vitest/coverage-v8": "^5.0.3",
54
+ "ajv": "^8.20.0",
55
+ "jsdom": "^30.1.2",
56
+ "json-schema-to-typescript": "^16.0.0",
57
+ "react": "^19.3.0",
58
+ "react-dom": "^19.3.0",
59
+ "vite": "^8.3.4",
60
+ "vitest": "^5.0.3"
61
+ },
62
+ "peerDependencies": {
63
+ "@testing-library/react": "^16.3.3",
64
+ "react": "^19.2.6",
65
+ "react-dom": "^19.2.6"
66
+ },
67
+ "peerDependenciesMeta": {
68
+ "@testing-library/react": {
69
+ "optional": true
70
+ },
71
+ "react": {
72
+ "optional": true
73
+ },
74
+ "react-dom": {
75
+ "optional": true
76
+ }
77
+ },
78
+ "engines": {
79
+ "node": ">=24"
80
+ },
81
+ "scripts": {
82
+ "build": "rm -rf lib && tsc -p tsconfig.build.json",
83
+ "generate": "json2ts -i ../schema.json -o build/resource-schema.ts --declareExternallyReferenced --style singleQuote",
84
+ "lint": "oxlint --max-warnings=0",
85
+ "lint:fix": "oxlint --fix",
86
+ "format": "oxfmt",
87
+ "format:check": "oxfmt --check",
88
+ "typecheck": "tsc --noEmit",
89
+ "test": "vitest",
90
+ "test:run": "vitest run"
91
+ }
6
92
  }