@plasius/gpu-xr 0.1.0 → 0.1.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/CHANGELOG.md CHANGED
@@ -7,3 +7,61 @@ All notable changes to this project will be documented in this file.
7
7
  - Initial scaffold for `@plasius/gpu-xr`.
8
8
  - Added framework-agnostic WebXR support probing and session lifecycle APIs.
9
9
  - Added unit tests, demo, and ADR documentation.
10
+
11
+ ## [Unreleased]
12
+
13
+ - **Added**
14
+ - (placeholder)
15
+
16
+ - **Changed**
17
+ - (placeholder)
18
+
19
+ - **Fixed**
20
+ - (placeholder)
21
+
22
+ - **Security**
23
+ - (placeholder)
24
+
25
+ ## [0.1.2] - 2026-03-01
26
+
27
+ - **Added**
28
+ - `lint`, `typecheck`, and security audit scripts for local and CI enforcement.
29
+
30
+ - **Changed**
31
+ - CI now fails early on lint/typecheck/runtime dependency audit before build/test.
32
+
33
+ - **Fixed**
34
+ - Pack-check regex cleanup to remove an unnecessary path escape.
35
+
36
+ - **Security**
37
+ - Runtime dependency vulnerability checks are now enforced in CI.
38
+
39
+ ## [0.1.1] - 2026-02-28
40
+
41
+ - **Added**
42
+ - (placeholder)
43
+
44
+ - **Changed**
45
+ - (placeholder)
46
+
47
+ - **Fixed**
48
+ - (placeholder)
49
+
50
+ - **Security**
51
+ - (placeholder)
52
+
53
+ ## [0.1.0] - 2026-02-11
54
+
55
+ - **Added**
56
+ - Initial release.
57
+
58
+ - **Changed**
59
+ - (placeholder)
60
+
61
+ - **Fixed**
62
+ - (placeholder)
63
+
64
+ - **Security**
65
+ - (placeholder)
66
+ [0.1.1]: https://github.com/Plasius-LTD/gpu-xr/releases/tag/v0.1.1
67
+ [0.1.2]: https://github.com/Plasius-LTD/gpu-xr/releases/tag/v0.1.2
package/README.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # @plasius/gpu-xr
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@plasius/gpu-xr)](https://www.npmjs.com/package/@plasius/gpu-xr)
3
+ [![npm version](https://img.shields.io/npm/v/@plasius/gpu-xr.svg)](https://www.npmjs.com/package/@plasius/gpu-xr)
4
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/Plasius-LTD/gpu-xr/ci.yml?branch=main&label=build&style=flat)](https://github.com/Plasius-LTD/gpu-xr/actions/workflows/ci.yml)
5
+ [![coverage](https://img.shields.io/codecov/c/github/Plasius-LTD/gpu-xr)](https://codecov.io/gh/Plasius-LTD/gpu-xr)
6
+ [![License](https://img.shields.io/github/license/Plasius-LTD/gpu-xr)](./LICENSE)
7
+ [![Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-yes-blue.svg)](./CODE_OF_CONDUCT.md)
8
+ [![Security Policy](https://img.shields.io/badge/security%20policy-yes-orange.svg)](./SECURITY.md)
9
+ [![Changelog](https://img.shields.io/badge/changelog-md-blue.svg)](./CHANGELOG.md)
10
+
4
11
  [![license](https://img.shields.io/github/license/Plasius-LTD/gpu-xr)](./LICENSE)
5
12
 
6
13
  Framework-agnostic WebXR session management for Plasius GPU rendering projects.
@@ -52,6 +59,16 @@ npm run demo
52
59
 
53
60
  Then open `http://localhost:8000/gpu-xr/demo/`.
54
61
 
62
+ ## Development Checks
63
+
64
+ ```sh
65
+ npm run lint
66
+ npm run typecheck
67
+ npm run test:coverage
68
+ npm run build
69
+ npm run pack:check
70
+ ```
71
+
55
72
  ## Files
56
73
 
57
74
  - `src/index.js`: XR runtime/session manager and store.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.js"],"sourcesContent":["const DEFAULT_VR_SESSION_INIT = Object.freeze({\n requiredFeatures: [\"local-floor\"],\n optionalFeatures: [\"bounded-floor\", \"hand-tracking\", \"layers\"],\n});\n\nexport const xrSessionModes = Object.freeze([\n \"inline\",\n \"immersive-vr\",\n \"immersive-ar\",\n]);\n\nexport const xrReferenceSpaceTypes = Object.freeze([\n \"viewer\",\n \"local\",\n \"local-floor\",\n \"bounded-floor\",\n \"unbounded\",\n]);\n\nfunction toStringArray(values) {\n if (!Array.isArray(values)) {\n return [];\n }\n return values\n .filter((value) => typeof value === \"string\")\n .map((value) => value.trim())\n .filter(Boolean);\n}\n\nfunction dedupeStrings(values) {\n return [...new Set(toStringArray(values))];\n}\n\nfunction readNavigator(navigatorOverride) {\n const currentNavigator = navigatorOverride ?? globalThis.navigator;\n if (!currentNavigator || typeof currentNavigator !== \"object\") {\n throw new Error(\n \"WebXR navigator unavailable. Provide a browser navigator with navigator.xr.\"\n );\n }\n return currentNavigator;\n}\n\nfunction readXrSystem(navigatorOverride) {\n const currentNavigator = readNavigator(navigatorOverride);\n const xr = currentNavigator.xr;\n if (!xr || typeof xr !== \"object\") {\n throw new Error(\n \"WebXR runtime unavailable. navigator.xr is missing in this environment.\"\n );\n }\n return xr;\n}\n\nfunction assertSessionMode(mode) {\n if (!xrSessionModes.includes(mode)) {\n const available = xrSessionModes.join(\", \");\n throw new Error(\n `Unknown XR session mode \\\"${mode}\\\". Available modes: ${available}.`\n );\n }\n}\n\nexport function mergeXrSessionInit(base = {}, override = {}) {\n const requiredFeatures = dedupeStrings([\n ...toStringArray(base.requiredFeatures),\n ...toStringArray(override.requiredFeatures),\n ]);\n\n const optionalFeatures = dedupeStrings([\n ...toStringArray(base.optionalFeatures),\n ...toStringArray(override.optionalFeatures),\n ]);\n\n const merged = {\n ...base,\n ...override,\n requiredFeatures,\n optionalFeatures,\n };\n\n if (requiredFeatures.length === 0) {\n delete merged.requiredFeatures;\n }\n\n if (optionalFeatures.length === 0) {\n delete merged.optionalFeatures;\n }\n\n return merged;\n}\n\nexport async function isXrModeSupported(\n mode = \"immersive-vr\",\n options = {}\n) {\n assertSessionMode(mode);\n\n const { navigator: navigatorOverride } = options;\n let xr;\n try {\n xr = readXrSystem(navigatorOverride);\n } catch {\n return false;\n }\n\n if (typeof xr.isSessionSupported !== \"function\") {\n return false;\n }\n\n try {\n return Boolean(await xr.isSessionSupported(mode));\n } catch {\n return false;\n }\n}\n\nexport async function requestXrSession(options = {}) {\n const {\n mode = \"immersive-vr\",\n sessionInit = {},\n baseSessionInit = DEFAULT_VR_SESSION_INIT,\n navigator: navigatorOverride,\n } = options;\n\n assertSessionMode(mode);\n\n const xr = readXrSystem(navigatorOverride);\n\n if (typeof xr.requestSession !== \"function\") {\n throw new Error(\"WebXR requestSession API unavailable.\");\n }\n\n const init = mergeXrSessionInit(baseSessionInit, sessionInit);\n return xr.requestSession(mode, init);\n}\n\nexport function createXrStore(initialState = {}) {\n const listeners = new Set();\n let state = {\n activeSession: null,\n mode: null,\n isEntering: false,\n lastError: null,\n supportedModes: {},\n ...initialState,\n };\n\n const notify = () => {\n for (const listener of listeners) {\n listener(state);\n }\n };\n\n return {\n getSnapshot() {\n return state;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n set(partialState) {\n state = {\n ...state,\n ...partialState,\n };\n notify();\n },\n reset() {\n state = {\n activeSession: null,\n mode: null,\n isEntering: false,\n lastError: null,\n supportedModes: {},\n ...initialState,\n };\n notify();\n },\n };\n}\n\nexport function createXrManager(options = {}) {\n const {\n navigator: navigatorOverride,\n defaultMode = \"immersive-vr\",\n baseSessionInit = DEFAULT_VR_SESSION_INIT,\n onSessionStart,\n onSessionEnd,\n } = options;\n\n assertSessionMode(defaultMode);\n\n const store = createXrStore();\n let activeSessionEndHandler = null;\n\n const detachSessionEndHandler = () => {\n const { activeSession } = store.getSnapshot();\n if (\n activeSession &&\n activeSessionEndHandler &&\n typeof activeSession.removeEventListener === \"function\"\n ) {\n activeSession.removeEventListener(\"end\", activeSessionEndHandler);\n }\n activeSessionEndHandler = null;\n };\n\n const handleSessionEnded = () => {\n detachSessionEndHandler();\n store.set({\n activeSession: null,\n mode: null,\n isEntering: false,\n });\n if (typeof onSessionEnd === \"function\") {\n onSessionEnd();\n }\n };\n\n const attachSessionEndHandler = (session) => {\n if (!session || typeof session.addEventListener !== \"function\") {\n return;\n }\n activeSessionEndHandler = handleSessionEnded;\n session.addEventListener(\"end\", activeSessionEndHandler);\n };\n\n const getState = () => store.getSnapshot();\n\n const subscribe = (listener) => store.subscribe(listener);\n\n const probeSupport = async (modes = [defaultMode]) => {\n const supportedModes = {};\n for (const mode of modes) {\n assertSessionMode(mode);\n supportedModes[mode] = await isXrModeSupported(mode, {\n navigator: navigatorOverride,\n });\n }\n store.set({ supportedModes });\n return supportedModes;\n };\n\n const enterSession = async (mode = defaultMode, sessionInit = {}) => {\n assertSessionMode(mode);\n\n const existing = store.getSnapshot().activeSession;\n if (existing) {\n return existing;\n }\n\n store.set({ isEntering: true, lastError: null });\n\n try {\n const session = await requestXrSession({\n mode,\n sessionInit,\n baseSessionInit,\n navigator: navigatorOverride,\n });\n\n attachSessionEndHandler(session);\n\n store.set({\n activeSession: session,\n mode,\n isEntering: false,\n lastError: null,\n });\n\n if (typeof onSessionStart === \"function\") {\n onSessionStart(session, mode);\n }\n\n return session;\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error ?? \"Unknown XR error\");\n store.set({\n isEntering: false,\n lastError: message,\n });\n throw error;\n }\n };\n\n const enterVr = async (sessionInit = {}) => {\n return enterSession(\"immersive-vr\", sessionInit);\n };\n\n const exitSession = async () => {\n const { activeSession } = store.getSnapshot();\n if (!activeSession) {\n return false;\n }\n\n if (typeof activeSession.end === \"function\") {\n await activeSession.end();\n }\n\n // Fallback for test fakes or runtimes that do not emit an end event.\n if (store.getSnapshot().activeSession) {\n handleSessionEnded();\n }\n\n return true;\n };\n\n const dispose = async () => {\n await exitSession();\n detachSessionEndHandler();\n store.reset();\n };\n\n return {\n store,\n getState,\n subscribe,\n probeSupport,\n enterSession,\n enterVr,\n exitSession,\n dispose,\n };\n}\n\nexport const defaultVrSessionInit = DEFAULT_VR_SESSION_INIT;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.js"],"sourcesContent":["const DEFAULT_VR_SESSION_INIT = Object.freeze({\n requiredFeatures: [\"local-floor\"],\n optionalFeatures: [\"bounded-floor\", \"hand-tracking\", \"layers\"],\n});\n\nexport const xrSessionModes = Object.freeze([\n \"inline\",\n \"immersive-vr\",\n \"immersive-ar\",\n]);\n\nexport const xrReferenceSpaceTypes = Object.freeze([\n \"viewer\",\n \"local\",\n \"local-floor\",\n \"bounded-floor\",\n \"unbounded\",\n]);\n\nfunction toStringArray(values) {\n if (!Array.isArray(values)) {\n return [];\n }\n return values\n .filter((value) => typeof value === \"string\")\n .map((value) => value.trim())\n .filter(Boolean);\n}\n\nfunction dedupeStrings(values) {\n return [...new Set(toStringArray(values))];\n}\n\nfunction readNavigator(navigatorOverride) {\n const currentNavigator = navigatorOverride ?? globalThis.navigator;\n if (!currentNavigator || typeof currentNavigator !== \"object\") {\n throw new Error(\n \"WebXR navigator unavailable. Provide a browser navigator with navigator.xr.\"\n );\n }\n return currentNavigator;\n}\n\nfunction readXrSystem(navigatorOverride) {\n const currentNavigator = readNavigator(navigatorOverride);\n const xr = currentNavigator.xr;\n if (!xr || typeof xr !== \"object\") {\n throw new Error(\n \"WebXR runtime unavailable. navigator.xr is missing in this environment.\"\n );\n }\n return xr;\n}\n\nfunction assertSessionMode(mode) {\n if (!xrSessionModes.includes(mode)) {\n const available = xrSessionModes.join(\", \");\n throw new Error(\n `Unknown XR session mode \"${mode}\". Available modes: ${available}.`\n );\n }\n}\n\nexport function mergeXrSessionInit(base = {}, override = {}) {\n const requiredFeatures = dedupeStrings([\n ...toStringArray(base.requiredFeatures),\n ...toStringArray(override.requiredFeatures),\n ]);\n\n const optionalFeatures = dedupeStrings([\n ...toStringArray(base.optionalFeatures),\n ...toStringArray(override.optionalFeatures),\n ]);\n\n const merged = {\n ...base,\n ...override,\n requiredFeatures,\n optionalFeatures,\n };\n\n if (requiredFeatures.length === 0) {\n delete merged.requiredFeatures;\n }\n\n if (optionalFeatures.length === 0) {\n delete merged.optionalFeatures;\n }\n\n return merged;\n}\n\nexport async function isXrModeSupported(\n mode = \"immersive-vr\",\n options = {}\n) {\n assertSessionMode(mode);\n\n const { navigator: navigatorOverride } = options;\n let xr;\n try {\n xr = readXrSystem(navigatorOverride);\n } catch {\n return false;\n }\n\n if (typeof xr.isSessionSupported !== \"function\") {\n return false;\n }\n\n try {\n return Boolean(await xr.isSessionSupported(mode));\n } catch {\n return false;\n }\n}\n\nexport async function requestXrSession(options = {}) {\n const {\n mode = \"immersive-vr\",\n sessionInit = {},\n baseSessionInit = DEFAULT_VR_SESSION_INIT,\n navigator: navigatorOverride,\n } = options;\n\n assertSessionMode(mode);\n\n const xr = readXrSystem(navigatorOverride);\n\n if (typeof xr.requestSession !== \"function\") {\n throw new Error(\"WebXR requestSession API unavailable.\");\n }\n\n const init = mergeXrSessionInit(baseSessionInit, sessionInit);\n return xr.requestSession(mode, init);\n}\n\nexport function createXrStore(initialState = {}) {\n const listeners = new Set();\n let state = {\n activeSession: null,\n mode: null,\n isEntering: false,\n lastError: null,\n supportedModes: {},\n ...initialState,\n };\n\n const notify = () => {\n for (const listener of listeners) {\n listener(state);\n }\n };\n\n return {\n getSnapshot() {\n return state;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n set(partialState) {\n state = {\n ...state,\n ...partialState,\n };\n notify();\n },\n reset() {\n state = {\n activeSession: null,\n mode: null,\n isEntering: false,\n lastError: null,\n supportedModes: {},\n ...initialState,\n };\n notify();\n },\n };\n}\n\nexport function createXrManager(options = {}) {\n const {\n navigator: navigatorOverride,\n defaultMode = \"immersive-vr\",\n baseSessionInit = DEFAULT_VR_SESSION_INIT,\n onSessionStart,\n onSessionEnd,\n } = options;\n\n assertSessionMode(defaultMode);\n\n const store = createXrStore();\n let activeSessionEndHandler = null;\n\n const detachSessionEndHandler = () => {\n const { activeSession } = store.getSnapshot();\n if (\n activeSession &&\n activeSessionEndHandler &&\n typeof activeSession.removeEventListener === \"function\"\n ) {\n activeSession.removeEventListener(\"end\", activeSessionEndHandler);\n }\n activeSessionEndHandler = null;\n };\n\n const handleSessionEnded = () => {\n detachSessionEndHandler();\n store.set({\n activeSession: null,\n mode: null,\n isEntering: false,\n });\n if (typeof onSessionEnd === \"function\") {\n onSessionEnd();\n }\n };\n\n const attachSessionEndHandler = (session) => {\n if (!session || typeof session.addEventListener !== \"function\") {\n return;\n }\n activeSessionEndHandler = handleSessionEnded;\n session.addEventListener(\"end\", activeSessionEndHandler);\n };\n\n const getState = () => store.getSnapshot();\n\n const subscribe = (listener) => store.subscribe(listener);\n\n const probeSupport = async (modes = [defaultMode]) => {\n const supportedModes = {};\n for (const mode of modes) {\n assertSessionMode(mode);\n supportedModes[mode] = await isXrModeSupported(mode, {\n navigator: navigatorOverride,\n });\n }\n store.set({ supportedModes });\n return supportedModes;\n };\n\n const enterSession = async (mode = defaultMode, sessionInit = {}) => {\n assertSessionMode(mode);\n\n const existing = store.getSnapshot().activeSession;\n if (existing) {\n return existing;\n }\n\n store.set({ isEntering: true, lastError: null });\n\n try {\n const session = await requestXrSession({\n mode,\n sessionInit,\n baseSessionInit,\n navigator: navigatorOverride,\n });\n\n attachSessionEndHandler(session);\n\n store.set({\n activeSession: session,\n mode,\n isEntering: false,\n lastError: null,\n });\n\n if (typeof onSessionStart === \"function\") {\n onSessionStart(session, mode);\n }\n\n return session;\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error ?? \"Unknown XR error\");\n store.set({\n isEntering: false,\n lastError: message,\n });\n throw error;\n }\n };\n\n const enterVr = async (sessionInit = {}) => {\n return enterSession(\"immersive-vr\", sessionInit);\n };\n\n const exitSession = async () => {\n const { activeSession } = store.getSnapshot();\n if (!activeSession) {\n return false;\n }\n\n if (typeof activeSession.end === \"function\") {\n await activeSession.end();\n }\n\n // Fallback for test fakes or runtimes that do not emit an end event.\n if (store.getSnapshot().activeSession) {\n handleSessionEnded();\n }\n\n return true;\n };\n\n const dispose = async () => {\n await exitSession();\n detachSessionEndHandler();\n store.reset();\n };\n\n return {\n store,\n getState,\n subscribe,\n probeSupport,\n enterSession,\n enterVr,\n exitSession,\n dispose,\n };\n}\n\nexport const defaultVrSessionInit = DEFAULT_VR_SESSION_INIT;\n"],"mappings":"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","names":[]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.js"],"sourcesContent":["const DEFAULT_VR_SESSION_INIT = Object.freeze({\n requiredFeatures: [\"local-floor\"],\n optionalFeatures: [\"bounded-floor\", \"hand-tracking\", \"layers\"],\n});\n\nexport const xrSessionModes = Object.freeze([\n \"inline\",\n \"immersive-vr\",\n \"immersive-ar\",\n]);\n\nexport const xrReferenceSpaceTypes = Object.freeze([\n \"viewer\",\n \"local\",\n \"local-floor\",\n \"bounded-floor\",\n \"unbounded\",\n]);\n\nfunction toStringArray(values) {\n if (!Array.isArray(values)) {\n return [];\n }\n return values\n .filter((value) => typeof value === \"string\")\n .map((value) => value.trim())\n .filter(Boolean);\n}\n\nfunction dedupeStrings(values) {\n return [...new Set(toStringArray(values))];\n}\n\nfunction readNavigator(navigatorOverride) {\n const currentNavigator = navigatorOverride ?? globalThis.navigator;\n if (!currentNavigator || typeof currentNavigator !== \"object\") {\n throw new Error(\n \"WebXR navigator unavailable. Provide a browser navigator with navigator.xr.\"\n );\n }\n return currentNavigator;\n}\n\nfunction readXrSystem(navigatorOverride) {\n const currentNavigator = readNavigator(navigatorOverride);\n const xr = currentNavigator.xr;\n if (!xr || typeof xr !== \"object\") {\n throw new Error(\n \"WebXR runtime unavailable. navigator.xr is missing in this environment.\"\n );\n }\n return xr;\n}\n\nfunction assertSessionMode(mode) {\n if (!xrSessionModes.includes(mode)) {\n const available = xrSessionModes.join(\", \");\n throw new Error(\n `Unknown XR session mode \\\"${mode}\\\". Available modes: ${available}.`\n );\n }\n}\n\nexport function mergeXrSessionInit(base = {}, override = {}) {\n const requiredFeatures = dedupeStrings([\n ...toStringArray(base.requiredFeatures),\n ...toStringArray(override.requiredFeatures),\n ]);\n\n const optionalFeatures = dedupeStrings([\n ...toStringArray(base.optionalFeatures),\n ...toStringArray(override.optionalFeatures),\n ]);\n\n const merged = {\n ...base,\n ...override,\n requiredFeatures,\n optionalFeatures,\n };\n\n if (requiredFeatures.length === 0) {\n delete merged.requiredFeatures;\n }\n\n if (optionalFeatures.length === 0) {\n delete merged.optionalFeatures;\n }\n\n return merged;\n}\n\nexport async function isXrModeSupported(\n mode = \"immersive-vr\",\n options = {}\n) {\n assertSessionMode(mode);\n\n const { navigator: navigatorOverride } = options;\n let xr;\n try {\n xr = readXrSystem(navigatorOverride);\n } catch {\n return false;\n }\n\n if (typeof xr.isSessionSupported !== \"function\") {\n return false;\n }\n\n try {\n return Boolean(await xr.isSessionSupported(mode));\n } catch {\n return false;\n }\n}\n\nexport async function requestXrSession(options = {}) {\n const {\n mode = \"immersive-vr\",\n sessionInit = {},\n baseSessionInit = DEFAULT_VR_SESSION_INIT,\n navigator: navigatorOverride,\n } = options;\n\n assertSessionMode(mode);\n\n const xr = readXrSystem(navigatorOverride);\n\n if (typeof xr.requestSession !== \"function\") {\n throw new Error(\"WebXR requestSession API unavailable.\");\n }\n\n const init = mergeXrSessionInit(baseSessionInit, sessionInit);\n return xr.requestSession(mode, init);\n}\n\nexport function createXrStore(initialState = {}) {\n const listeners = new Set();\n let state = {\n activeSession: null,\n mode: null,\n isEntering: false,\n lastError: null,\n supportedModes: {},\n ...initialState,\n };\n\n const notify = () => {\n for (const listener of listeners) {\n listener(state);\n }\n };\n\n return {\n getSnapshot() {\n return state;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n set(partialState) {\n state = {\n ...state,\n ...partialState,\n };\n notify();\n },\n reset() {\n state = {\n activeSession: null,\n mode: null,\n isEntering: false,\n lastError: null,\n supportedModes: {},\n ...initialState,\n };\n notify();\n },\n };\n}\n\nexport function createXrManager(options = {}) {\n const {\n navigator: navigatorOverride,\n defaultMode = \"immersive-vr\",\n baseSessionInit = DEFAULT_VR_SESSION_INIT,\n onSessionStart,\n onSessionEnd,\n } = options;\n\n assertSessionMode(defaultMode);\n\n const store = createXrStore();\n let activeSessionEndHandler = null;\n\n const detachSessionEndHandler = () => {\n const { activeSession } = store.getSnapshot();\n if (\n activeSession &&\n activeSessionEndHandler &&\n typeof activeSession.removeEventListener === \"function\"\n ) {\n activeSession.removeEventListener(\"end\", activeSessionEndHandler);\n }\n activeSessionEndHandler = null;\n };\n\n const handleSessionEnded = () => {\n detachSessionEndHandler();\n store.set({\n activeSession: null,\n mode: null,\n isEntering: false,\n });\n if (typeof onSessionEnd === \"function\") {\n onSessionEnd();\n }\n };\n\n const attachSessionEndHandler = (session) => {\n if (!session || typeof session.addEventListener !== \"function\") {\n return;\n }\n activeSessionEndHandler = handleSessionEnded;\n session.addEventListener(\"end\", activeSessionEndHandler);\n };\n\n const getState = () => store.getSnapshot();\n\n const subscribe = (listener) => store.subscribe(listener);\n\n const probeSupport = async (modes = [defaultMode]) => {\n const supportedModes = {};\n for (const mode of modes) {\n assertSessionMode(mode);\n supportedModes[mode] = await isXrModeSupported(mode, {\n navigator: navigatorOverride,\n });\n }\n store.set({ supportedModes });\n return supportedModes;\n };\n\n const enterSession = async (mode = defaultMode, sessionInit = {}) => {\n assertSessionMode(mode);\n\n const existing = store.getSnapshot().activeSession;\n if (existing) {\n return existing;\n }\n\n store.set({ isEntering: true, lastError: null });\n\n try {\n const session = await requestXrSession({\n mode,\n sessionInit,\n baseSessionInit,\n navigator: navigatorOverride,\n });\n\n attachSessionEndHandler(session);\n\n store.set({\n activeSession: session,\n mode,\n isEntering: false,\n lastError: null,\n });\n\n if (typeof onSessionStart === \"function\") {\n onSessionStart(session, mode);\n }\n\n return session;\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error ?? \"Unknown XR error\");\n store.set({\n isEntering: false,\n lastError: message,\n });\n throw error;\n }\n };\n\n const enterVr = async (sessionInit = {}) => {\n return enterSession(\"immersive-vr\", sessionInit);\n };\n\n const exitSession = async () => {\n const { activeSession } = store.getSnapshot();\n if (!activeSession) {\n return false;\n }\n\n if (typeof activeSession.end === \"function\") {\n await activeSession.end();\n }\n\n // Fallback for test fakes or runtimes that do not emit an end event.\n if (store.getSnapshot().activeSession) {\n handleSessionEnded();\n }\n\n return true;\n };\n\n const dispose = async () => {\n await exitSession();\n detachSessionEndHandler();\n store.reset();\n };\n\n return {\n store,\n getState,\n subscribe,\n probeSupport,\n enterSession,\n enterVr,\n exitSession,\n dispose,\n };\n}\n\nexport const defaultVrSessionInit = DEFAULT_VR_SESSION_INIT;\n"],"mappings":";AAAA,IAAM,0BAA0B,OAAO,OAAO;AAAA,EAC5C,kBAAkB,CAAC,aAAa;AAAA,EAChC,kBAAkB,CAAC,iBAAiB,iBAAiB,QAAQ;AAC/D,CAAC;AAEM,IAAM,iBAAiB,OAAO,OAAO;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,wBAAwB,OAAO,OAAO;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,cAAc,QAAQ;AAC7B,MAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;AAC1B,WAAO,CAAC;AAAA,EACV;AACA,SAAO,OACJ,OAAO,CAAC,UAAU,OAAO,UAAU,QAAQ,EAC3C,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,OAAO;AACnB;AAEA,SAAS,cAAc,QAAQ;AAC7B,SAAO,CAAC,GAAG,IAAI,IAAI,cAAc,MAAM,CAAC,CAAC;AAC3C;AAEA,SAAS,cAAc,mBAAmB;AACxC,QAAM,mBAAmB,qBAAqB,WAAW;AACzD,MAAI,CAAC,oBAAoB,OAAO,qBAAqB,UAAU;AAC7D,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,mBAAmB;AACvC,QAAM,mBAAmB,cAAc,iBAAiB;AACxD,QAAM,KAAK,iBAAiB;AAC5B,MAAI,CAAC,MAAM,OAAO,OAAO,UAAU;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,MAAM;AAC/B,MAAI,CAAC,eAAe,SAAS,IAAI,GAAG;AAClC,UAAM,YAAY,eAAe,KAAK,IAAI;AAC1C,UAAM,IAAI;AAAA,MACR,4BAA6B,IAAI,uBAAwB,SAAS;AAAA,IACpE;AAAA,EACF;AACF;AAEO,SAAS,mBAAmB,OAAO,CAAC,GAAG,WAAW,CAAC,GAAG;AAC3D,QAAM,mBAAmB,cAAc;AAAA,IACrC,GAAG,cAAc,KAAK,gBAAgB;AAAA,IACtC,GAAG,cAAc,SAAS,gBAAgB;AAAA,EAC5C,CAAC;AAED,QAAM,mBAAmB,cAAc;AAAA,IACrC,GAAG,cAAc,KAAK,gBAAgB;AAAA,IACtC,GAAG,cAAc,SAAS,gBAAgB;AAAA,EAC5C,CAAC;AAED,QAAM,SAAS;AAAA,IACb,GAAG;AAAA,IACH,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AAEA,MAAI,iBAAiB,WAAW,GAAG;AACjC,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,iBAAiB,WAAW,GAAG;AACjC,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO;AACT;AAEA,eAAsB,kBACpB,OAAO,gBACP,UAAU,CAAC,GACX;AACA,oBAAkB,IAAI;AAEtB,QAAM,EAAE,WAAW,kBAAkB,IAAI;AACzC,MAAI;AACJ,MAAI;AACF,SAAK,aAAa,iBAAiB;AAAA,EACrC,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,GAAG,uBAAuB,YAAY;AAC/C,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,QAAQ,MAAM,GAAG,mBAAmB,IAAI,CAAC;AAAA,EAClD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,iBAAiB,UAAU,CAAC,GAAG;AACnD,QAAM;AAAA,IACJ,OAAO;AAAA,IACP,cAAc,CAAC;AAAA,IACf,kBAAkB;AAAA,IAClB,WAAW;AAAA,EACb,IAAI;AAEJ,oBAAkB,IAAI;AAEtB,QAAM,KAAK,aAAa,iBAAiB;AAEzC,MAAI,OAAO,GAAG,mBAAmB,YAAY;AAC3C,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AAEA,QAAM,OAAO,mBAAmB,iBAAiB,WAAW;AAC5D,SAAO,GAAG,eAAe,MAAM,IAAI;AACrC;AAEO,SAAS,cAAc,eAAe,CAAC,GAAG;AAC/C,QAAM,YAAY,oBAAI,IAAI;AAC1B,MAAI,QAAQ;AAAA,IACV,eAAe;AAAA,IACf,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,gBAAgB,CAAC;AAAA,IACjB,GAAG;AAAA,EACL;AAEA,QAAM,SAAS,MAAM;AACnB,eAAW,YAAY,WAAW;AAChC,eAAS,KAAK;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,cAAc;AACZ,aAAO;AAAA,IACT;AAAA,IACA,UAAU,UAAU;AAClB,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM;AACX,kBAAU,OAAO,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,IAAI,cAAc;AAChB,cAAQ;AAAA,QACN,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AACA,aAAO;AAAA,IACT;AAAA,IACA,QAAQ;AACN,cAAQ;AAAA,QACN,eAAe;AAAA,QACf,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,gBAAgB,CAAC;AAAA,QACjB,GAAG;AAAA,MACL;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,gBAAgB,UAAU,CAAC,GAAG;AAC5C,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,oBAAkB,WAAW;AAE7B,QAAM,QAAQ,cAAc;AAC5B,MAAI,0BAA0B;AAE9B,QAAM,0BAA0B,MAAM;AACpC,UAAM,EAAE,cAAc,IAAI,MAAM,YAAY;AAC5C,QACE,iBACA,2BACA,OAAO,cAAc,wBAAwB,YAC7C;AACA,oBAAc,oBAAoB,OAAO,uBAAuB;AAAA,IAClE;AACA,8BAA0B;AAAA,EAC5B;AAEA,QAAM,qBAAqB,MAAM;AAC/B,4BAAwB;AACxB,UAAM,IAAI;AAAA,MACR,eAAe;AAAA,MACf,MAAM;AAAA,MACN,YAAY;AAAA,IACd,CAAC;AACD,QAAI,OAAO,iBAAiB,YAAY;AACtC,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,QAAM,0BAA0B,CAAC,YAAY;AAC3C,QAAI,CAAC,WAAW,OAAO,QAAQ,qBAAqB,YAAY;AAC9D;AAAA,IACF;AACA,8BAA0B;AAC1B,YAAQ,iBAAiB,OAAO,uBAAuB;AAAA,EACzD;AAEA,QAAM,WAAW,MAAM,MAAM,YAAY;AAEzC,QAAM,YAAY,CAAC,aAAa,MAAM,UAAU,QAAQ;AAExD,QAAM,eAAe,OAAO,QAAQ,CAAC,WAAW,MAAM;AACpD,UAAM,iBAAiB,CAAC;AACxB,eAAW,QAAQ,OAAO;AACxB,wBAAkB,IAAI;AACtB,qBAAe,IAAI,IAAI,MAAM,kBAAkB,MAAM;AAAA,QACnD,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,UAAM,IAAI,EAAE,eAAe,CAAC;AAC5B,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,OAAO,OAAO,aAAa,cAAc,CAAC,MAAM;AACnE,sBAAkB,IAAI;AAEtB,UAAM,WAAW,MAAM,YAAY,EAAE;AACrC,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,EAAE,YAAY,MAAM,WAAW,KAAK,CAAC;AAE/C,QAAI;AACF,YAAM,UAAU,MAAM,iBAAiB;AAAA,QACrC;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACb,CAAC;AAED,8BAAwB,OAAO;AAE/B,YAAM,IAAI;AAAA,QACR,eAAe;AAAA,QACf;AAAA,QACA,YAAY;AAAA,QACZ,WAAW;AAAA,MACb,CAAC;AAED,UAAI,OAAO,mBAAmB,YAAY;AACxC,uBAAe,SAAS,IAAI;AAAA,MAC9B;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,SAAS,kBAAkB;AAC7E,YAAM,IAAI;AAAA,QACR,YAAY;AAAA,QACZ,WAAW;AAAA,MACb,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,cAAc,CAAC,MAAM;AAC1C,WAAO,aAAa,gBAAgB,WAAW;AAAA,EACjD;AAEA,QAAM,cAAc,YAAY;AAC9B,UAAM,EAAE,cAAc,IAAI,MAAM,YAAY;AAC5C,QAAI,CAAC,eAAe;AAClB,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,cAAc,QAAQ,YAAY;AAC3C,YAAM,cAAc,IAAI;AAAA,IAC1B;AAGA,QAAI,MAAM,YAAY,EAAE,eAAe;AACrC,yBAAmB;AAAA,IACrB;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,YAAY;AAC1B,UAAM,YAAY;AAClB,4BAAwB;AACxB,UAAM,MAAM;AAAA,EACd;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,uBAAuB;","names":[]}
1
+ {"version":3,"sources":["../src/index.js"],"sourcesContent":["const DEFAULT_VR_SESSION_INIT = Object.freeze({\n requiredFeatures: [\"local-floor\"],\n optionalFeatures: [\"bounded-floor\", \"hand-tracking\", \"layers\"],\n});\n\nexport const xrSessionModes = Object.freeze([\n \"inline\",\n \"immersive-vr\",\n \"immersive-ar\",\n]);\n\nexport const xrReferenceSpaceTypes = Object.freeze([\n \"viewer\",\n \"local\",\n \"local-floor\",\n \"bounded-floor\",\n \"unbounded\",\n]);\n\nfunction toStringArray(values) {\n if (!Array.isArray(values)) {\n return [];\n }\n return values\n .filter((value) => typeof value === \"string\")\n .map((value) => value.trim())\n .filter(Boolean);\n}\n\nfunction dedupeStrings(values) {\n return [...new Set(toStringArray(values))];\n}\n\nfunction readNavigator(navigatorOverride) {\n const currentNavigator = navigatorOverride ?? globalThis.navigator;\n if (!currentNavigator || typeof currentNavigator !== \"object\") {\n throw new Error(\n \"WebXR navigator unavailable. Provide a browser navigator with navigator.xr.\"\n );\n }\n return currentNavigator;\n}\n\nfunction readXrSystem(navigatorOverride) {\n const currentNavigator = readNavigator(navigatorOverride);\n const xr = currentNavigator.xr;\n if (!xr || typeof xr !== \"object\") {\n throw new Error(\n \"WebXR runtime unavailable. navigator.xr is missing in this environment.\"\n );\n }\n return xr;\n}\n\nfunction assertSessionMode(mode) {\n if (!xrSessionModes.includes(mode)) {\n const available = xrSessionModes.join(\", \");\n throw new Error(\n `Unknown XR session mode \"${mode}\". Available modes: ${available}.`\n );\n }\n}\n\nexport function mergeXrSessionInit(base = {}, override = {}) {\n const requiredFeatures = dedupeStrings([\n ...toStringArray(base.requiredFeatures),\n ...toStringArray(override.requiredFeatures),\n ]);\n\n const optionalFeatures = dedupeStrings([\n ...toStringArray(base.optionalFeatures),\n ...toStringArray(override.optionalFeatures),\n ]);\n\n const merged = {\n ...base,\n ...override,\n requiredFeatures,\n optionalFeatures,\n };\n\n if (requiredFeatures.length === 0) {\n delete merged.requiredFeatures;\n }\n\n if (optionalFeatures.length === 0) {\n delete merged.optionalFeatures;\n }\n\n return merged;\n}\n\nexport async function isXrModeSupported(\n mode = \"immersive-vr\",\n options = {}\n) {\n assertSessionMode(mode);\n\n const { navigator: navigatorOverride } = options;\n let xr;\n try {\n xr = readXrSystem(navigatorOverride);\n } catch {\n return false;\n }\n\n if (typeof xr.isSessionSupported !== \"function\") {\n return false;\n }\n\n try {\n return Boolean(await xr.isSessionSupported(mode));\n } catch {\n return false;\n }\n}\n\nexport async function requestXrSession(options = {}) {\n const {\n mode = \"immersive-vr\",\n sessionInit = {},\n baseSessionInit = DEFAULT_VR_SESSION_INIT,\n navigator: navigatorOverride,\n } = options;\n\n assertSessionMode(mode);\n\n const xr = readXrSystem(navigatorOverride);\n\n if (typeof xr.requestSession !== \"function\") {\n throw new Error(\"WebXR requestSession API unavailable.\");\n }\n\n const init = mergeXrSessionInit(baseSessionInit, sessionInit);\n return xr.requestSession(mode, init);\n}\n\nexport function createXrStore(initialState = {}) {\n const listeners = new Set();\n let state = {\n activeSession: null,\n mode: null,\n isEntering: false,\n lastError: null,\n supportedModes: {},\n ...initialState,\n };\n\n const notify = () => {\n for (const listener of listeners) {\n listener(state);\n }\n };\n\n return {\n getSnapshot() {\n return state;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n set(partialState) {\n state = {\n ...state,\n ...partialState,\n };\n notify();\n },\n reset() {\n state = {\n activeSession: null,\n mode: null,\n isEntering: false,\n lastError: null,\n supportedModes: {},\n ...initialState,\n };\n notify();\n },\n };\n}\n\nexport function createXrManager(options = {}) {\n const {\n navigator: navigatorOverride,\n defaultMode = \"immersive-vr\",\n baseSessionInit = DEFAULT_VR_SESSION_INIT,\n onSessionStart,\n onSessionEnd,\n } = options;\n\n assertSessionMode(defaultMode);\n\n const store = createXrStore();\n let activeSessionEndHandler = null;\n\n const detachSessionEndHandler = () => {\n const { activeSession } = store.getSnapshot();\n if (\n activeSession &&\n activeSessionEndHandler &&\n typeof activeSession.removeEventListener === \"function\"\n ) {\n activeSession.removeEventListener(\"end\", activeSessionEndHandler);\n }\n activeSessionEndHandler = null;\n };\n\n const handleSessionEnded = () => {\n detachSessionEndHandler();\n store.set({\n activeSession: null,\n mode: null,\n isEntering: false,\n });\n if (typeof onSessionEnd === \"function\") {\n onSessionEnd();\n }\n };\n\n const attachSessionEndHandler = (session) => {\n if (!session || typeof session.addEventListener !== \"function\") {\n return;\n }\n activeSessionEndHandler = handleSessionEnded;\n session.addEventListener(\"end\", activeSessionEndHandler);\n };\n\n const getState = () => store.getSnapshot();\n\n const subscribe = (listener) => store.subscribe(listener);\n\n const probeSupport = async (modes = [defaultMode]) => {\n const supportedModes = {};\n for (const mode of modes) {\n assertSessionMode(mode);\n supportedModes[mode] = await isXrModeSupported(mode, {\n navigator: navigatorOverride,\n });\n }\n store.set({ supportedModes });\n return supportedModes;\n };\n\n const enterSession = async (mode = defaultMode, sessionInit = {}) => {\n assertSessionMode(mode);\n\n const existing = store.getSnapshot().activeSession;\n if (existing) {\n return existing;\n }\n\n store.set({ isEntering: true, lastError: null });\n\n try {\n const session = await requestXrSession({\n mode,\n sessionInit,\n baseSessionInit,\n navigator: navigatorOverride,\n });\n\n attachSessionEndHandler(session);\n\n store.set({\n activeSession: session,\n mode,\n isEntering: false,\n lastError: null,\n });\n\n if (typeof onSessionStart === \"function\") {\n onSessionStart(session, mode);\n }\n\n return session;\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error ?? \"Unknown XR error\");\n store.set({\n isEntering: false,\n lastError: message,\n });\n throw error;\n }\n };\n\n const enterVr = async (sessionInit = {}) => {\n return enterSession(\"immersive-vr\", sessionInit);\n };\n\n const exitSession = async () => {\n const { activeSession } = store.getSnapshot();\n if (!activeSession) {\n return false;\n }\n\n if (typeof activeSession.end === \"function\") {\n await activeSession.end();\n }\n\n // Fallback for test fakes or runtimes that do not emit an end event.\n if (store.getSnapshot().activeSession) {\n handleSessionEnded();\n }\n\n return true;\n };\n\n const dispose = async () => {\n await exitSession();\n detachSessionEndHandler();\n store.reset();\n };\n\n return {\n store,\n getState,\n subscribe,\n probeSupport,\n enterSession,\n enterVr,\n exitSession,\n dispose,\n };\n}\n\nexport const defaultVrSessionInit = DEFAULT_VR_SESSION_INIT;\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasius/gpu-xr",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Framework-agnostic WebXR session management for Plasius GPU rendering projects.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -27,9 +27,17 @@
27
27
  "scripts": {
28
28
  "build": "tsup",
29
29
  "demo": "python3 -m http.server --directory ..",
30
+ "typecheck": "node --check src/index.js",
31
+ "audit:eslint": "eslint . --max-warnings=0",
32
+ "audit:deps": "npm ls --all --omit=optional --omit=peer > /dev/null 2>&1 || true",
33
+ "audit:npm": "npm audit --audit-level=high --omit=dev",
34
+ "audit:test": "npm run test:coverage",
35
+ "lint": "eslint . --max-warnings=0",
30
36
  "test": "npm run test:unit",
31
37
  "test:unit": "node --test",
32
- "test:coverage": "c8 --reporter=lcov --reporter=text node --test"
38
+ "test:coverage": "c8 --reporter=lcov --reporter=text node --test",
39
+ "pack:check": "node scripts/verify-public-package.cjs",
40
+ "prepublishOnly": "npm run build && npm run pack:check"
33
41
  },
34
42
  "keywords": [
35
43
  "webxr",
@@ -42,7 +50,10 @@
42
50
  "author": "Plasius LTD <development@plasius.co.uk>",
43
51
  "license": "Apache-2.0",
44
52
  "devDependencies": {
53
+ "@eslint/js": "^9.39.1",
45
54
  "c8": "^10.1.3",
55
+ "eslint": "^9.39.1",
56
+ "globals": "^17.3.0",
46
57
  "tsup": "^8.5.0",
47
58
  "typescript": "^5.9.3"
48
59
  },
@@ -66,5 +77,8 @@
66
77
  "type": "github",
67
78
  "url": "https://github.com/sponsors/Plasius-LTD"
68
79
  }
69
- ]
80
+ ],
81
+ "overrides": {
82
+ "minimatch": "^10.2.1"
83
+ }
70
84
  }
package/src/index.js CHANGED
@@ -56,7 +56,7 @@ function assertSessionMode(mode) {
56
56
  if (!xrSessionModes.includes(mode)) {
57
57
  const available = xrSessionModes.join(", ");
58
58
  throw new Error(
59
- `Unknown XR session mode \"${mode}\". Available modes: ${available}.`
59
+ `Unknown XR session mode "${mode}". Available modes: ${available}.`
60
60
  );
61
61
  }
62
62
  }