From b2c739e9c7b8c22987edd0f8e12dc1bb550b50dc Mon Sep 17 00:00:00 2001 From: Marcus Longmuir Date: Fri, 26 Apr 2024 13:42:04 +0100 Subject: [PATCH] Packaging (#126) (#127) * Packaging * allows the user to load a compressed JPG HDR from Tweakpane * fixes depth texture size recomputing issue when toggling SSAO on/off --------- Co-authored-by: Thomas Bergmueller Co-authored-by: TheCodeTherapy --- .nvmrc | 2 +- README.md | 80 +- example/assets/hdr/puresky_2k.jpg | Bin 0 -> 308653 bytes example/assets/models/anim_air.glb | 4 +- example/assets/models/anim_idle.glb | 4 +- example/assets/models/anim_jog.glb | 4 +- example/assets/models/anim_run.glb | 4 +- example/assets/models/bot.glb | 4 +- example/assets/textures/checker.png | Bin 1017 -> 0 bytes example/local-multi-web-client/src/Room.ts | 48 - .../client}/build.ts | 4 +- .../client}/package.json | 7 +- .../client}/public/favicon.svg | 0 .../client}/public/index.html | 6 +- .../client}/public/style.css | 0 .../client}/src/LocalAvatarClient.ts | 62 +- .../client}/src/LocalAvatarServer.ts | 0 .../client}/src/declaration.d.ts | 0 .../client}/src/example-mml.html | 4 +- .../client}/src/index.ts | 0 .../client}/tsconfig.json | 2 +- .../server/build.ts | 2 +- .../server/package.json | 37 + .../server/src/index.ts | 27 + .../server/tsconfig.json | 2 +- .../client}/build.ts | 3 +- .../client}/package.json | 9 +- .../client}/public/favicon.svg | 0 .../client}/public/index.html | 4 - .../client}/src/declaration.d.ts | 0 .../client/src/index.ts | 28 + .../client}/tsconfig.json | 2 +- .../server/build.ts | 44 + .../server/mml-documents/example-mml.html | 3 + .../server/package.json | 16 +- .../server/src/BasicUserAuthenticator.ts | 113 + .../server/src/index.ts | 82 + .../server/src/voice-routes.ts | 67 + .../server/tsconfig.json | 24 + example/server/assets/dice.glb | 3 - example/server/src/auth.ts | 12 - .../local-multi-web-client-app-routes.ts | 51 - .../client}/build.ts | 3 + example/web-avatar-editor/client/package.json | 19 + .../client}/public/favicon.svg | 0 .../client}/public/index.html | 6 +- .../client}/public/style.css | 0 .../client}/src/AvatarEditor.tsx | 8 +- .../client}/src/collection.json | 0 .../client}/src/declaration.d.ts | 0 .../client}/src/index.tsx | 0 .../client}/src/mmlCharacterDescription.ts | 0 .../client}/tsconfig.json | 2 +- example/web-avatar-editor/server/build.ts | 44 + example/web-avatar-editor/server/package.json | 35 + example/web-avatar-editor/server/src/index.ts | 30 + .../web-avatar-editor/server/tsconfig.json | 24 + example/web-client/public/style.css | 45 - package-lock.json | 2890 +++++++++-------- package.json | 29 +- packages/3d-web-avatar-editor-ui/build.ts | 8 +- packages/3d-web-avatar-editor-ui/package.json | 6 +- packages/3d-web-avatar/build.ts | 8 +- packages/3d-web-avatar/package.json | 11 +- .../src/character/MMLCharacter.ts | 121 +- .../src/character/ModelLoader.ts | 133 - .../3d-web-avatar/src/helpers/MathHelpers.ts | 6 - .../src/helpers/SkeletonHelpers.ts | 200 -- .../src/helpers/cloneSkinnedMesh.ts | 6 + packages/3d-web-avatar/src/index.ts | 3 +- packages/3d-web-client-core/package.json | 12 +- .../src/camera/CameraManager.ts | 16 +- .../src/character/Character.ts | 58 +- .../src/character/CharacterManager.ts | 121 +- .../src/character/CharacterMaterial.ts | 30 +- .../src/character/CharacterModel.ts | 82 +- .../src/character/CharacterModelLoader.ts | 79 +- .../src/character/CharacterTooltip.ts | 57 +- .../src/character/LocalController.ts | 112 +- .../src/character/RemoteController.ts | 37 +- .../src/ground-plane/GroundPlane.ts | 33 +- packages/3d-web-client-core/src/index.ts | 3 + .../src/input/KeyInputManager.ts | 21 +- .../src/input/VirtualJoystick.ts | 67 +- .../src/loading-screen}/LoadingScreen.ts | 1 + .../src/mml/MMLCompositionScene.ts | 46 +- .../src/rendering/composer.ts | 36 +- packages/3d-web-client-core/src/sun/Sun.ts | 2 +- .../src/tweakpane/TweakPane.ts | 16 +- .../src/tweakpane/blades/environmentFolder.ts | 4 +- .../src/tweakpane/blades/ssaoFolder.ts | 4 + packages/3d-web-experience-client/build.ts | 3 + .../3d-web-experience-client}/package.json | 18 +- .../src/Networked3dWebExperienceClient.ts | 173 +- .../3d-web-experience-client/src/index.ts | 1 + .../3d-web-experience-client/tsconfig.json | 23 + packages/3d-web-experience-server/build.ts | 3 + .../3d-web-experience-server/package.json | 31 + .../src}/MMLDocumentsServer.ts | 0 .../src/Networked3dWebExperienceServer.ts | 153 + .../3d-web-experience-server/src/index.ts | 2 + .../3d-web-experience-server/tsconfig.json | 23 + .../3d-web-standalone-avatar-editor/build.ts | 8 +- .../package.json | 11 +- .../src/AvatarRenderer.ts | 6 +- .../src/index.ts | 8 +- .../src/screenshot/ModelScreenshotter.ts | 12 +- packages/3d-web-text-chat/build.ts | 8 +- packages/3d-web-text-chat/package.json | 8 +- .../src/chat-ui/TextChatUI.tsx | 4 +- packages/3d-web-user-networking/package.json | 4 +- .../src/UserNetworkingServer.ts | 130 +- packages/3d-web-voice-chat/build.ts | 8 +- packages/3d-web-voice-chat/package.json | 10 +- .../src/chat-ui/components/voice-chat-ui.tsx | 4 +- .../voice-chat-manager/VoiceChatManager.ts | 2 + tsconfig.json | 16 +- utils/build-library.ts | 29 +- utils/websocketDirectoryChangeListener.ts | 25 + 119 files changed, 3336 insertions(+), 2625 deletions(-) create mode 100644 example/assets/hdr/puresky_2k.jpg delete mode 100755 example/assets/textures/checker.png delete mode 100644 example/local-multi-web-client/src/Room.ts rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/build.ts (91%) rename example/{web-client => local-only-multi-user-3d-web-experience/client}/package.json (80%) rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/public/favicon.svg (100%) rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/public/index.html (56%) rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/public/style.css (100%) rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/src/LocalAvatarClient.ts (78%) rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/src/LocalAvatarServer.ts (100%) rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/src/declaration.d.ts (100%) rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/src/example-mml.html (96%) rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/src/index.ts (100%) rename example/{local-multi-web-client => local-only-multi-user-3d-web-experience/client}/tsconfig.json (94%) rename example/{ => local-only-multi-user-3d-web-experience}/server/build.ts (90%) create mode 100644 example/local-only-multi-user-3d-web-experience/server/package.json create mode 100644 example/local-only-multi-user-3d-web-experience/server/src/index.ts rename example/{ => local-only-multi-user-3d-web-experience}/server/tsconfig.json (93%) rename example/{web-client => multi-user-3d-web-experience/client}/build.ts (91%) rename example/{web-avatar-client => multi-user-3d-web-experience/client}/package.json (69%) rename example/{web-avatar-client => multi-user-3d-web-experience/client}/public/favicon.svg (100%) rename example/{web-client => multi-user-3d-web-experience/client}/public/index.html (76%) rename example/{web-avatar-client => multi-user-3d-web-experience/client}/src/declaration.d.ts (100%) create mode 100644 example/multi-user-3d-web-experience/client/src/index.ts rename example/{web-client => multi-user-3d-web-experience/client}/tsconfig.json (94%) create mode 100644 example/multi-user-3d-web-experience/server/build.ts rename example/{ => multi-user-3d-web-experience}/server/mml-documents/example-mml.html (89%) rename example/{ => multi-user-3d-web-experience}/server/package.json (75%) create mode 100644 example/multi-user-3d-web-experience/server/src/BasicUserAuthenticator.ts create mode 100644 example/multi-user-3d-web-experience/server/src/index.ts create mode 100644 example/multi-user-3d-web-experience/server/src/voice-routes.ts create mode 100644 example/multi-user-3d-web-experience/server/tsconfig.json delete mode 100644 example/server/assets/dice.glb delete mode 100644 example/server/src/auth.ts delete mode 100644 example/server/src/router/local-multi-web-client-app-routes.ts rename example/{web-avatar-client => web-avatar-editor/client}/build.ts (89%) create mode 100644 example/web-avatar-editor/client/package.json rename example/{web-client => web-avatar-editor/client}/public/favicon.svg (100%) rename example/{web-avatar-client => web-avatar-editor/client}/public/index.html (59%) rename example/{web-avatar-client => web-avatar-editor/client}/public/style.css (100%) rename example/{web-avatar-client => web-avatar-editor/client}/src/AvatarEditor.tsx (96%) rename example/{web-avatar-client => web-avatar-editor/client}/src/collection.json (100%) rename example/{web-client => web-avatar-editor/client}/src/declaration.d.ts (100%) rename example/{web-avatar-client => web-avatar-editor/client}/src/index.tsx (100%) rename example/{web-avatar-client => web-avatar-editor/client}/src/mmlCharacterDescription.ts (100%) rename example/{web-avatar-client => web-avatar-editor/client}/tsconfig.json (94%) create mode 100644 example/web-avatar-editor/server/build.ts create mode 100644 example/web-avatar-editor/server/package.json create mode 100644 example/web-avatar-editor/server/src/index.ts create mode 100644 example/web-avatar-editor/server/tsconfig.json delete mode 100644 example/web-client/public/style.css delete mode 100644 packages/3d-web-avatar/src/character/ModelLoader.ts delete mode 100644 packages/3d-web-avatar/src/helpers/SkeletonHelpers.ts create mode 100644 packages/3d-web-avatar/src/helpers/cloneSkinnedMesh.ts rename example/web-client/src/Room.ts => packages/3d-web-client-core/src/ground-plane/GroundPlane.ts (51%) rename {example/web-client/src => packages/3d-web-client-core/src/loading-screen}/LoadingScreen.ts (99%) create mode 100644 packages/3d-web-experience-client/build.ts rename {example/local-multi-web-client => packages/3d-web-experience-client}/package.json (66%) rename example/web-client/src/index.ts => packages/3d-web-experience-client/src/Networked3dWebExperienceClient.ts (79%) create mode 100644 packages/3d-web-experience-client/src/index.ts create mode 100644 packages/3d-web-experience-client/tsconfig.json create mode 100644 packages/3d-web-experience-server/build.ts create mode 100644 packages/3d-web-experience-server/package.json rename {example/server/src/router => packages/3d-web-experience-server/src}/MMLDocumentsServer.ts (100%) create mode 100644 packages/3d-web-experience-server/src/Networked3dWebExperienceServer.ts create mode 100644 packages/3d-web-experience-server/src/index.ts create mode 100644 packages/3d-web-experience-server/tsconfig.json create mode 100644 utils/websocketDirectoryChangeListener.ts diff --git a/.nvmrc b/.nvmrc index 8ddbc0c6..ee09fac7 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v18.16.0 +v20.11.1 diff --git a/README.md b/README.md index 953f6462..43bd075a 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,51 @@ # (MML) 3D Web Experience This repository contains packages used to run a web-based, multi-user 3D web experience that -supports [MML (Metaverse Markup Language)](https://mml.io/). This repository includes two published -packages: - -- [`@mml-io/3d-web-client-core`](./packages/3d-web-client-core) - A package that implements the main - components of a 3D web experience. -- [`@mml-io/3d-web-user-networking`](./packages/3d-web-user-networking) - A package that contains - WebSocket server and client implementations that synchronize user positions. - -There is an example implementation of a 3D web experience in the `examples` directory. This example -contains: - -- `web-client` - - A THREE.js 3D experience utilizing the `@mml-io/3d-web-client-core` and - `@mml-io/3d-web-user-networking` packages to create a multi-user 3D web client that connects to - the server. -- `server` - - A server which serves the `web-client` and handles user networking WebSocket connections with - `@mml-io/3d-web-user-networking` - - Additionally, the server runs MML documents in the `mml-documents` directory which are then - connected to by the `web-client`. - - A simple session-based [auth system](#auth) that can be used as a reference to implement arbitrary http-based auth. - -It can be easily deployed to environments that support Node.js and expose ports to the internet. +supports [MML (Metaverse Markup Language)](https://mml.io/). + +It can be easily deployed to environments that support Node.js and can expose ports to the internet. +## Packages + +This repository includes the following published packages: + +- [`@mml-io/3d-web-experience-client`](./packages/3d-web-experience-client) + - Client for a 3D web experience that includes user position networking, MML content composition, + MML-based avatars, and text chat. +- [`@mml-io/3d-web-experience-server`](./packages/3d-web-experience-server) + - Server for a 3D web experience that includes user position networking, MML hosting, and text chat. +- [`@mml-io/3d-web-client-core`](./packages/3d-web-client-core) + - The main components of a 3D web experience (controls, rendering, MML composition etc.) that can be + extended with other packages to create a full 3D web experience. +- [`@mml-io/3d-web-user-networking`](./packages/3d-web-user-networking) + - WebSocket server and client implementations that synchronize user positions. +- [`@mml-io/3d-web-avatar`](./packages/3d-web-avatar) + - Creates and parses MML documents for avatars (using `m-character`). +- [`@mml-io/3d-web-avatar-editor-ui`](./packages/3d-web-avatar-editor-ui) + - UI components (e.g. parts pickers) for creating avatars. +- [`@mml-io/3d-web-standalone-avatar-editor`](./packages/3d-web-standalone-avatar-editor) + - An MML avatar editor (using `m-character`). +- [`@mml-io/3d-web-text-chat`](./packages/3d-web-text-chat) + - Contains WebSocket server and client implementations for text chat. +- [`@mml-io/3d-web-voice-chat`](./packages/3d-web-voice-chat) + - Client implementation for spatial voice chat. + ## Main features - Multiple users can connect to the experience using just a web browser. - - Users can interact simultaneously with the stateful MML documents. - - Easy to deploy and extend with interactive MML content. -## Running locally +### Auth Flow +- When the client page is rendered by the server, the server uses a UserAuthenticator implementation to determine if a session should be generated for the incoming http request and if so includes that session token on the client page. +- The client then sends the session token in the first message to the server when it connects via websocket. +- The server can use the session token to authenticate the user and determine what identity (username, avatar etc) the user should have. +- An example implementation of this is provided in the example server, but the interface is extensible enough that a more complex user authenticator can limit which avatar components should be permitted based on external systems. + + +## Running Examples & Iterating Locally Making sure you have Node.js installed, run the following from the root of the repository: @@ -44,10 +54,14 @@ npm install npm run iterate ``` -Once the example server is running, open `http://localhost:8080` in your browser. - -## Auth -- When the client page is rendered by the server the server uses a UserAuthenticator implementation to determine if a session should be generated for the incoming http request and if so includes that session token on the client page. -- The client then sends the session token in the first message to the server when it connects via websocket. -- The server can use the session token to authenticate the user and determine what identity (username, avatar etc) the user should have. -- An example implementation of this is provided in the example server, but the interface is extensible enough that a more complex user authenticator can limit which avatar components should be permitted based on external systems. +## Examples + +- [`example/multi-user-3d-web-experience`](./example/multi-user-3d-web-experience) + - Once the server is running (see [above](#running-examples--iterating-locally)), open `http://localhost:8080`. + - A client and server pair of packages that uses the `@mml-io/3d-web-experience-client` and `@mml-io/3d-web-experience-server` packages to create a multi-user 3d web experience that includes MML hosting and text chat. +- [`example/local-only-multi-user-3d-web-experience`](./example/local-only-multi-user-3d-web-experience) + - Once the server is running (see [above](#running-examples--iterating-locally)), open `http://localhost:8081`. + - A client that uses the various packages to create a 3d web experience that only works locally. No server is needed, but there is a server to serve the client. +- [`example/web-avatar-editor`](./example/web-avatar-editor) + - Once the server is running (see [above](#running-examples--iterating-locally)), open `http://localhost:8082`. + - An avatar editor that uses the `@mml-io/3d-web-standalone-avatar-editor` to create and edit MML avatars and a simple Express server that hosts the editor. diff --git a/example/assets/hdr/puresky_2k.jpg b/example/assets/hdr/puresky_2k.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1961837548e9a7be0d8aa09353f0b41461ec1f75 GIT binary patch literal 308653 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 z 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 z%0D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 diff --git a/example/local-multi-web-client/src/Room.ts b/example/local-multi-web-client/src/Room.ts deleted file mode 100644 index 6c0e06c8..00000000 --- a/example/local-multi-web-client/src/Room.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { - CircleGeometry, - FrontSide, - Group, - LinearMipMapLinearFilter, - LoadingManager, - Mesh, - MeshStandardMaterial, - NearestFilter, - RepeatWrapping, - Texture, - TextureLoader, -} from "three"; - -import checkerTextureUrl from "../../assets/textures/checker.png"; - -export class Room extends Group { - private readonly floorSize = 210; - private readonly floorTexture: Texture | null = null; - private readonly floorGeometry = new CircleGeometry(this.floorSize, this.floorSize); - private readonly floorMaterial: MeshStandardMaterial; - private readonly floorMesh: Mesh | null = null; - - constructor() { - super(); - - this.floorMaterial = new MeshStandardMaterial({ - color: 0xbcbcbc, - side: FrontSide, - metalness: 0.04, - roughness: 0.49, - }); - this.floorMesh = new Mesh(this.floorGeometry, this.floorMaterial); - this.floorMesh.receiveShadow = true; - this.floorMesh.rotation.x = Math.PI * -0.5; - this.add(this.floorMesh); - - this.floorTexture = new TextureLoader(new LoadingManager()).load(checkerTextureUrl, () => { - this.floorTexture!.wrapS = RepeatWrapping; - this.floorTexture!.wrapT = RepeatWrapping; - this.floorTexture!.magFilter = NearestFilter; - this.floorTexture!.minFilter = LinearMipMapLinearFilter; - this.floorTexture!.repeat.set(this.floorSize / 1.5, this.floorSize / 1.5); - this.floorMaterial.map = this.floorTexture; - this.floorMaterial.needsUpdate = true; - }); - } -} diff --git a/example/local-multi-web-client/build.ts b/example/local-only-multi-user-3d-web-experience/client/build.ts similarity index 91% rename from example/local-multi-web-client/build.ts rename to example/local-only-multi-user-3d-web-experience/client/build.ts index 4adae11c..737b50fa 100644 --- a/example/local-multi-web-client/build.ts +++ b/example/local-only-multi-user-3d-web-experience/client/build.ts @@ -34,9 +34,9 @@ const buildOptions: esbuild.BuildOptions = { ".glb": "file", ".hdr": "file", }, - outbase: "../", + outbase: "../../", // This is targeting the parent of the "assets" directory to avoid generated paths including a traversal sourceRoot: "./src", - publicPath: "/local-multi-web-client/", + publicPath: "/", plugins: [ copy({ resolveFrom: "cwd", diff --git a/example/web-client/package.json b/example/local-only-multi-user-3d-web-experience/client/package.json similarity index 80% rename from example/web-client/package.json rename to example/local-only-multi-user-3d-web-experience/client/package.json index 5ad5573f..6c8364e5 100644 --- a/example/web-client/package.json +++ b/example/local-only-multi-user-3d-web-experience/client/package.json @@ -1,5 +1,5 @@ { - "name": "@example/web-client", + "name": "@example/local-only-multi-user-3d-web-experience-client", "private": true, "version": "0.15.0", "files": [ @@ -18,9 +18,10 @@ "@mml-io/3d-web-text-chat": "^0.15.0", "@mml-io/3d-web-user-networking": "^0.15.0", "@mml-io/3d-web-voice-chat": "^0.15.0", - "three": "0.153.0" + "mml-web-runner": "0.14.0", + "three": "0.163.0" }, "devDependencies": { - "@types/three": "0.153.0" + "@types/three": "0.163.0" } } diff --git a/example/local-multi-web-client/public/favicon.svg b/example/local-only-multi-user-3d-web-experience/client/public/favicon.svg similarity index 100% rename from example/local-multi-web-client/public/favicon.svg rename to example/local-only-multi-user-3d-web-experience/client/public/favicon.svg diff --git a/example/local-multi-web-client/public/index.html b/example/local-only-multi-user-3d-web-experience/client/public/index.html similarity index 56% rename from example/local-multi-web-client/public/index.html rename to example/local-only-multi-user-3d-web-experience/client/public/index.html index 327e8ae9..ca526525 100644 --- a/example/local-multi-web-client/public/index.html +++ b/example/local-only-multi-user-3d-web-experience/client/public/index.html @@ -2,15 +2,15 @@ - + MML 3D Web Experience - +

- + diff --git a/example/local-multi-web-client/public/style.css b/example/local-only-multi-user-3d-web-experience/client/public/style.css similarity index 100% rename from example/local-multi-web-client/public/style.css rename to example/local-only-multi-user-3d-web-experience/client/public/style.css diff --git a/example/local-multi-web-client/src/LocalAvatarClient.ts b/example/local-only-multi-user-3d-web-experience/client/src/LocalAvatarClient.ts similarity index 78% rename from example/local-multi-web-client/src/LocalAvatarClient.ts rename to example/local-only-multi-user-3d-web-experience/client/src/LocalAvatarClient.ts index 3332d99c..f795f23e 100644 --- a/example/local-multi-web-client/src/LocalAvatarClient.ts +++ b/example/local-only-multi-user-3d-web-experience/client/src/LocalAvatarClient.ts @@ -7,6 +7,7 @@ import { CharacterState, CollisionsManager, Composer, + GroundPlane, KeyInputManager, MMLCompositionScene, TimeManager, @@ -15,15 +16,14 @@ import { EditableNetworkedDOM, NetworkedDOM } from "@mml-io/networked-dom-docume import { MMLWebRunnerClient } from "mml-web-runner"; import { AudioListener, Euler, Scene, Vector3 } from "three"; -import hdrUrl from "../../assets/hdr/puresky_2k.hdr"; -import airAnimationFileUrl from "../../assets/models/anim_air.glb"; -import idleAnimationFileUrl from "../../assets/models/anim_idle.glb"; -import jogAnimationFileUrl from "../../assets/models/anim_jog.glb"; -import sprintAnimationFileUrl from "../../assets/models/anim_run.glb"; -import defaultAvatarMeshFileUrl from "../../assets/models/bot.glb"; +import hdrJpgUrl from "../../../assets/hdr/puresky_2k.jpg"; +import airAnimationFileUrl from "../../../assets/models/anim_air.glb"; +import idleAnimationFileUrl from "../../../assets/models/anim_idle.glb"; +import jogAnimationFileUrl from "../../../assets/models/anim_jog.glb"; +import sprintAnimationFileUrl from "../../../assets/models/anim_run.glb"; +import defaultAvatarMeshFileUrl from "../../../assets/models/bot.glb"; import { LocalAvatarServer } from "./LocalAvatarServer"; -import { Room } from "./Room"; const animationConfig: AnimationConfig = { airAnimationFileUrl, @@ -90,7 +90,7 @@ export class LocalAvatarClient { this.cameraManager.camera.add(this.audioListener); this.composer = new Composer(this.scene, this.cameraManager.camera, true); - this.composer.useHDRI(hdrUrl); + this.composer.useHDRJPG(hdrJpgUrl); this.element.appendChild(this.composer.renderer.domElement); this.resizeObserver = new ResizeObserver(() => { @@ -109,40 +109,40 @@ export class LocalAvatarClient { }, ); - this.characterManager = new CharacterManager( - this.composer, - this.characterModelLoader, - this.collisionsManager, - this.cameraManager, - this.timeManager, - this.keyInputManager, - this.remoteUserStates, - (characterState: CharacterState) => { + this.characterManager = new CharacterManager({ + composer: this.composer, + characterModelLoader: this.characterModelLoader, + collisionsManager: this.collisionsManager, + cameraManager: this.cameraManager, + timeManager: this.timeManager, + keyInputManager: this.keyInputManager, + remoteUserStates: this.remoteUserStates, + sendUpdate: (characterState: CharacterState) => { localAvatarServer.send(localClientId, characterState); }, animationConfig, - () => { + characterResolve: () => { return { username: "User", characterDescription }; }, - ); + }); this.scene.add(this.characterManager.group); - this.mmlComposition = new MMLCompositionScene( - this.element, - this.composer.renderer, - this.scene, - this.cameraManager.camera, - this.audioListener, - this.collisionsManager, - () => { + this.mmlComposition = new MMLCompositionScene({ + targetElement: this.element, + renderer: this.composer.renderer, + scene: this.scene, + camera: this.cameraManager.camera, + audioListener: this.audioListener, + collisionsManager: this.collisionsManager, + getUserPositionAndRotation: () => { return this.characterManager.getLocalCharacterPositionAndRotation(); }, - ); + }); this.scene.add(this.mmlComposition.group); - const room = new Room(); - this.collisionsManager.addMeshesGroup(room); - this.scene.add(room); + const groundPlane = new GroundPlane(); + this.collisionsManager.addMeshesGroup(groundPlane); + this.scene.add(groundPlane); this.characterManager.spawnLocalCharacter( localClientId, diff --git a/example/local-multi-web-client/src/LocalAvatarServer.ts b/example/local-only-multi-user-3d-web-experience/client/src/LocalAvatarServer.ts similarity index 100% rename from example/local-multi-web-client/src/LocalAvatarServer.ts rename to example/local-only-multi-user-3d-web-experience/client/src/LocalAvatarServer.ts diff --git a/example/local-multi-web-client/src/declaration.d.ts b/example/local-only-multi-user-3d-web-experience/client/src/declaration.d.ts similarity index 100% rename from example/local-multi-web-client/src/declaration.d.ts rename to example/local-only-multi-user-3d-web-experience/client/src/declaration.d.ts diff --git a/example/local-multi-web-client/src/example-mml.html b/example/local-only-multi-user-3d-web-experience/client/src/example-mml.html similarity index 96% rename from example/local-multi-web-client/src/example-mml.html rename to example/local-only-multi-user-3d-web-experience/client/src/example-mml.html index dc23474d..13d0e591 100644 --- a/example/local-multi-web-client/src/example-mml.html +++ b/example/local-only-multi-user-3d-web-experience/client/src/example-mml.html @@ -1,4 +1,4 @@ - + @@ -41,4 +41,4 @@ }); stairs.append(stair); } - \ No newline at end of file + diff --git a/example/local-multi-web-client/src/index.ts b/example/local-only-multi-user-3d-web-experience/client/src/index.ts similarity index 100% rename from example/local-multi-web-client/src/index.ts rename to example/local-only-multi-user-3d-web-experience/client/src/index.ts diff --git a/example/local-multi-web-client/tsconfig.json b/example/local-only-multi-user-3d-web-experience/client/tsconfig.json similarity index 94% rename from example/local-multi-web-client/tsconfig.json rename to example/local-only-multi-user-3d-web-experience/client/tsconfig.json index 37953b29..c2a69c81 100644 --- a/example/local-multi-web-client/tsconfig.json +++ b/example/local-only-multi-user-3d-web-experience/client/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.json", + "extends": "../../../tsconfig.json", "compilerOptions": { "noImplicitAny": true, "module": "esnext", diff --git a/example/server/build.ts b/example/local-only-multi-user-3d-web-experience/server/build.ts similarity index 90% rename from example/server/build.ts rename to example/local-only-multi-user-3d-web-experience/server/build.ts index 9dc40225..46cac26d 100644 --- a/example/server/build.ts +++ b/example/local-only-multi-user-3d-web-experience/server/build.ts @@ -1,6 +1,6 @@ import * as esbuild from "esbuild"; -import { rebuildOnDependencyChangesPlugin } from "../../utils/rebuildOnDependencyChangesPlugin"; +import { rebuildOnDependencyChangesPlugin } from "../../../utils/rebuildOnDependencyChangesPlugin"; const buildMode = "--build"; const watchMode = "--watch"; diff --git a/example/local-only-multi-user-3d-web-experience/server/package.json b/example/local-only-multi-user-3d-web-experience/server/package.json new file mode 100644 index 00000000..2d4ab8f4 --- /dev/null +++ b/example/local-only-multi-user-3d-web-experience/server/package.json @@ -0,0 +1,37 @@ +{ + "name": "@example/local-only-multi-user-3d-web-experience-server", + "private": true, + "version": "0.15.0", + "engines": { + "node": "20.x" + }, + "main": "./src/index.js", + "type": "module", + "scripts": { + "build": "rimraf ./build && tsx ./build.ts --build", + "iterate": "tsx ./build.ts --watch", + "iterate:start": "node ./build/index.js", + "start": "NODE_ENV=production node build/index.js", + "type-check": "tsc --noEmit", + "lint": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --max-warnings 0", + "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" + }, + "dependencies": { + "@example/local-only-multi-user-3d-web-experience-client": "^0.15.0", + "@mml-io/3d-web-experience-server": "^0.15.0", + "chokidar": "^3.6.0", + "cors": "^2.8.5", + "express": "4.19.2", + "express-ws": "5.0.2", + "http-proxy": "^1.18.1", + "networked-dom-server": "0.14.0", + "ws": "8.16.0" + }, + "devDependencies": { + "@types/cors": "2.8.17", + "@types/express": "^4.17.21", + "@types/express-ws": "^3.0.4", + "@types/http-proxy": "^1.17.14", + "@types/node": "^20.12.7" + } +} diff --git a/example/local-only-multi-user-3d-web-experience/server/src/index.ts b/example/local-only-multi-user-3d-web-experience/server/src/index.ts new file mode 100644 index 00000000..74b2f12a --- /dev/null +++ b/example/local-only-multi-user-3d-web-experience/server/src/index.ts @@ -0,0 +1,27 @@ +import path from "path"; +import url from "url"; + +import express from "express"; +import enableWs from "express-ws"; + +import { websocketDirectoryChangeListener } from "../../../../utils/websocketDirectoryChangeListener"; + +const dirname = url.fileURLToPath(new URL(".", import.meta.url)); +const PORT = process.env.PORT || 8081; + +const { app } = enableWs(express()); +app.enable("trust proxy"); + +const webClientBuildDir = path.join(dirname, "../../client/build/"); +app.use("/", express.static(webClientBuildDir)); + +if (process.env.NODE_ENV !== "production") { + websocketDirectoryChangeListener(app, { + directory: webClientBuildDir, + websocketPath: "/web-avatar-build", + }); +} + +// Start listening +console.log("Listening on port", PORT); +app.listen(PORT); diff --git a/example/server/tsconfig.json b/example/local-only-multi-user-3d-web-experience/server/tsconfig.json similarity index 93% rename from example/server/tsconfig.json rename to example/local-only-multi-user-3d-web-experience/server/tsconfig.json index ac428ff7..bb2b94b3 100644 --- a/example/server/tsconfig.json +++ b/example/local-only-multi-user-3d-web-experience/server/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.json", + "extends": "../../../tsconfig.json", "compilerOptions": { "noImplicitAny": true, "module": "esnext", diff --git a/example/web-client/build.ts b/example/multi-user-3d-web-experience/client/build.ts similarity index 91% rename from example/web-client/build.ts rename to example/multi-user-3d-web-experience/client/build.ts index 25e8b3f9..4e0bab89 100644 --- a/example/web-client/build.ts +++ b/example/multi-user-3d-web-experience/client/build.ts @@ -23,6 +23,7 @@ const buildOptions: esbuild.BuildOptions = { write: true, metafile: true, sourcemap: "linked", + minify: true, outdir: "./build/", assetNames: "[dir]/[name]-[hash]", preserveSymlinks: true, @@ -33,7 +34,7 @@ const buildOptions: esbuild.BuildOptions = { ".glb": "file", ".hdr": "file", }, - outbase: "../", + outbase: "../../", // This is targeting the parent of the "assets" directory to avoid generated paths including a traversal sourceRoot: "./src", publicPath: "/web-client/", plugins: [ diff --git a/example/web-avatar-client/package.json b/example/multi-user-3d-web-experience/client/package.json similarity index 69% rename from example/web-avatar-client/package.json rename to example/multi-user-3d-web-experience/client/package.json index d7015246..bc7b7c72 100644 --- a/example/web-avatar-client/package.json +++ b/example/multi-user-3d-web-experience/client/package.json @@ -1,5 +1,5 @@ { - "name": "@example/web-avatar-client", + "name": "@example/multi-user-3d-web-experience-client", "private": true, "version": "0.15.0", "files": [ @@ -14,11 +14,10 @@ "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" }, "dependencies": { - "@mml-io/3d-web-client-core": "^0.15.0", - "@mml-io/3d-web-standalone-avatar-editor": "^0.15.0", - "three": "0.153.0" + "@mml-io/3d-web-experience-client": "^0.15.0", + "three": "0.163.0" }, "devDependencies": { - "@types/three": "0.153.0" + "@types/three": "0.163.0" } } diff --git a/example/web-avatar-client/public/favicon.svg b/example/multi-user-3d-web-experience/client/public/favicon.svg similarity index 100% rename from example/web-avatar-client/public/favicon.svg rename to example/multi-user-3d-web-experience/client/public/favicon.svg diff --git a/example/web-client/public/index.html b/example/multi-user-3d-web-experience/client/public/index.html similarity index 76% rename from example/web-client/public/index.html rename to example/multi-user-3d-web-experience/client/public/index.html index e7b7516a..390dab10 100644 --- a/example/web-client/public/index.html +++ b/example/multi-user-3d-web-experience/client/public/index.html @@ -5,15 +5,11 @@ MML 3D Web Experience - -
-
-
diff --git a/example/web-avatar-client/src/declaration.d.ts b/example/multi-user-3d-web-experience/client/src/declaration.d.ts similarity index 100% rename from example/web-avatar-client/src/declaration.d.ts rename to example/multi-user-3d-web-experience/client/src/declaration.d.ts diff --git a/example/multi-user-3d-web-experience/client/src/index.ts b/example/multi-user-3d-web-experience/client/src/index.ts new file mode 100644 index 00000000..f2a6dfdf --- /dev/null +++ b/example/multi-user-3d-web-experience/client/src/index.ts @@ -0,0 +1,28 @@ +import { Networked3dWebExperienceClient } from "@mml-io/3d-web-experience-client"; + +import hdrJpgUrl from "../../../assets/hdr/puresky_2k.jpg"; +import airAnimationFileUrl from "../../../assets/models/anim_air.glb"; +import idleAnimationFileUrl from "../../../assets/models/anim_idle.glb"; +import jogAnimationFileUrl from "../../../assets/models/anim_jog.glb"; +import sprintAnimationFileUrl from "../../../assets/models/anim_run.glb"; + +const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; +const host = window.location.host; +const userNetworkAddress = `${protocol}//${host}/network`; +const chatNetworkAddress = `${protocol}//${host}/chat-network`; + +const holder = Networked3dWebExperienceClient.createFullscreenHolder(); +const app = new Networked3dWebExperienceClient(holder, { + sessionToken: (window as any).SESSION_TOKEN, + userNetworkAddress, + chatNetworkAddress, + animationConfig: { + airAnimationFileUrl, + idleAnimationFileUrl, + jogAnimationFileUrl, + sprintAnimationFileUrl, + }, + hdrJpgUrl, + mmlDocumentAddresses: [`${protocol}//${host}/mml-documents/example-mml.html`], +}); +app.update(); diff --git a/example/web-client/tsconfig.json b/example/multi-user-3d-web-experience/client/tsconfig.json similarity index 94% rename from example/web-client/tsconfig.json rename to example/multi-user-3d-web-experience/client/tsconfig.json index 37953b29..c2a69c81 100644 --- a/example/web-client/tsconfig.json +++ b/example/multi-user-3d-web-experience/client/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.json", + "extends": "../../../tsconfig.json", "compilerOptions": { "noImplicitAny": true, "module": "esnext", diff --git a/example/multi-user-3d-web-experience/server/build.ts b/example/multi-user-3d-web-experience/server/build.ts new file mode 100644 index 00000000..46cac26d --- /dev/null +++ b/example/multi-user-3d-web-experience/server/build.ts @@ -0,0 +1,44 @@ +import * as esbuild from "esbuild"; + +import { rebuildOnDependencyChangesPlugin } from "../../../utils/rebuildOnDependencyChangesPlugin"; + +const buildMode = "--build"; +const watchMode = "--watch"; + +const helpString = `Mode must be provided as one of ${buildMode} or ${watchMode}`; + +const args = process.argv.splice(2); + +if (args.length !== 1) { + console.error(helpString); + process.exit(1); +} + +const mode = args[0]; + +const buildOptions: esbuild.BuildOptions = { + entryPoints: ["src/index.ts"], + outdir: "./build", + bundle: true, + metafile: true, + format: "esm", + packages: "external", + sourcemap: true, + platform: "node", + target: "es2020", + plugins: mode === watchMode ? [rebuildOnDependencyChangesPlugin] : [], +}; + +switch (mode) { + case buildMode: + esbuild.build(buildOptions).catch(() => process.exit(1)); + break; + case watchMode: + esbuild + .context({ ...buildOptions }) + .then((context) => context.watch()) + .catch(() => process.exit(1)); + break; + default: + console.error(helpString); +} diff --git a/example/server/mml-documents/example-mml.html b/example/multi-user-3d-web-experience/server/mml-documents/example-mml.html similarity index 89% rename from example/server/mml-documents/example-mml.html rename to example/multi-user-3d-web-experience/server/mml-documents/example-mml.html index 06af5e5f..4dec450b 100644 --- a/example/server/mml-documents/example-mml.html +++ b/example/multi-user-3d-web-experience/server/mml-documents/example-mml.html @@ -1,5 +1,8 @@ + + + + diff --git a/example/web-avatar-client/public/style.css b/example/web-avatar-editor/client/public/style.css similarity index 100% rename from example/web-avatar-client/public/style.css rename to example/web-avatar-editor/client/public/style.css diff --git a/example/web-avatar-client/src/AvatarEditor.tsx b/example/web-avatar-editor/client/src/AvatarEditor.tsx similarity index 96% rename from example/web-avatar-client/src/AvatarEditor.tsx rename to example/web-avatar-editor/client/src/AvatarEditor.tsx index d25e334c..60877113 100644 --- a/example/web-avatar-client/src/AvatarEditor.tsx +++ b/example/web-avatar-editor/client/src/AvatarEditor.tsx @@ -1,5 +1,5 @@ import { - cloneModel, + cloneSkinnedMesh, type LoadingErrors, type MMLCharacterDescription, } from "@mml-io/3d-web-avatar"; @@ -16,8 +16,8 @@ import { import React, { useCallback, useEffect, useState } from "react"; import { Group, Object3D } from "three"; -import idleAnimationURL from "../../assets/avatar/anims/idle.glb"; -import hdrURL from "../../assets/hdr/puresky_2k.hdr"; +import idleAnimationURL from "../../../assets/avatar/anims/idle.glb"; +import hdrURL from "../../../assets/hdr/puresky_2k.hdr"; type BodyPartTypes = "fullBody" | "head" | "upperBody" | "lowerBody" | "feet"; @@ -94,7 +94,7 @@ export function AvatarEditor(props: { }; const takeScreenShot = useCallback(async () => { - const characterClone = cloneModel(characterMesh as Group); + const characterClone = cloneSkinnedMesh(characterMesh as Group); const screenshotData = await screenshotTool.screenshot( characterClone, idleAnimationURL, diff --git a/example/web-avatar-client/src/collection.json b/example/web-avatar-editor/client/src/collection.json similarity index 100% rename from example/web-avatar-client/src/collection.json rename to example/web-avatar-editor/client/src/collection.json diff --git a/example/web-client/src/declaration.d.ts b/example/web-avatar-editor/client/src/declaration.d.ts similarity index 100% rename from example/web-client/src/declaration.d.ts rename to example/web-avatar-editor/client/src/declaration.d.ts diff --git a/example/web-avatar-client/src/index.tsx b/example/web-avatar-editor/client/src/index.tsx similarity index 100% rename from example/web-avatar-client/src/index.tsx rename to example/web-avatar-editor/client/src/index.tsx diff --git a/example/web-avatar-client/src/mmlCharacterDescription.ts b/example/web-avatar-editor/client/src/mmlCharacterDescription.ts similarity index 100% rename from example/web-avatar-client/src/mmlCharacterDescription.ts rename to example/web-avatar-editor/client/src/mmlCharacterDescription.ts diff --git a/example/web-avatar-client/tsconfig.json b/example/web-avatar-editor/client/tsconfig.json similarity index 94% rename from example/web-avatar-client/tsconfig.json rename to example/web-avatar-editor/client/tsconfig.json index 8d7b1a2d..739d8c9e 100644 --- a/example/web-avatar-client/tsconfig.json +++ b/example/web-avatar-editor/client/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.json", + "extends": "../../../tsconfig.json", "compilerOptions": { "noImplicitAny": true, "module": "esnext", diff --git a/example/web-avatar-editor/server/build.ts b/example/web-avatar-editor/server/build.ts new file mode 100644 index 00000000..46cac26d --- /dev/null +++ b/example/web-avatar-editor/server/build.ts @@ -0,0 +1,44 @@ +import * as esbuild from "esbuild"; + +import { rebuildOnDependencyChangesPlugin } from "../../../utils/rebuildOnDependencyChangesPlugin"; + +const buildMode = "--build"; +const watchMode = "--watch"; + +const helpString = `Mode must be provided as one of ${buildMode} or ${watchMode}`; + +const args = process.argv.splice(2); + +if (args.length !== 1) { + console.error(helpString); + process.exit(1); +} + +const mode = args[0]; + +const buildOptions: esbuild.BuildOptions = { + entryPoints: ["src/index.ts"], + outdir: "./build", + bundle: true, + metafile: true, + format: "esm", + packages: "external", + sourcemap: true, + platform: "node", + target: "es2020", + plugins: mode === watchMode ? [rebuildOnDependencyChangesPlugin] : [], +}; + +switch (mode) { + case buildMode: + esbuild.build(buildOptions).catch(() => process.exit(1)); + break; + case watchMode: + esbuild + .context({ ...buildOptions }) + .then((context) => context.watch()) + .catch(() => process.exit(1)); + break; + default: + console.error(helpString); +} diff --git a/example/web-avatar-editor/server/package.json b/example/web-avatar-editor/server/package.json new file mode 100644 index 00000000..e9be586a --- /dev/null +++ b/example/web-avatar-editor/server/package.json @@ -0,0 +1,35 @@ +{ + "name": "@example/web-avatar-editor-server", + "private": true, + "version": "0.15.0", + "engines": { + "node": "20.x" + }, + "main": "./src/index.js", + "type": "module", + "scripts": { + "build": "rimraf ./build && tsx ./build.ts --build", + "iterate": "tsx ./build.ts --watch", + "iterate:start": "node ./build/index.js", + "start": "NODE_ENV=production node build/index.js", + "type-check": "tsc --noEmit", + "lint": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --max-warnings 0", + "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" + }, + "dependencies": { + "@example/web-avatar-editor-client": "0.15.0", + "chokidar": "^3.6.0", + "cors": "^2.8.5", + "express": "4.19.2", + "express-ws": "5.0.2", + "http-proxy": "^1.18.1", + "ws": "8.16.0" + }, + "devDependencies": { + "@types/cors": "2.8.17", + "@types/express": "^4.17.21", + "@types/express-ws": "^3.0.4", + "@types/http-proxy": "^1.17.14", + "@types/node": "^20.12.7" + } +} diff --git a/example/web-avatar-editor/server/src/index.ts b/example/web-avatar-editor/server/src/index.ts new file mode 100644 index 00000000..5388ae4b --- /dev/null +++ b/example/web-avatar-editor/server/src/index.ts @@ -0,0 +1,30 @@ +import path from "path"; +import url from "url"; + +import cors from "cors"; +import express from "express"; +import enableWs from "express-ws"; + +import { websocketDirectoryChangeListener } from "../../../../utils/websocketDirectoryChangeListener"; + +const dirname = url.fileURLToPath(new URL(".", import.meta.url)); +const PORT = process.env.PORT || 8082; + +// Specify the avatar to use here: +const { app } = enableWs(express()); +app.enable("trust proxy"); + +const webAvatarEditorBuildDir = path.join(dirname, "../../client/build/"); +app.use("/", express.static(webAvatarEditorBuildDir)); +if (process.env.NODE_ENV !== "production") { + websocketDirectoryChangeListener(app, { + directory: webAvatarEditorBuildDir, + websocketPath: "/web-avatar-build", + }); +} + +app.use("/assets/", cors(), express.static(path.resolve(dirname, "../../../assets/"))); + +// Start listening +console.log("Listening on port", PORT); +app.listen(PORT); diff --git a/example/web-avatar-editor/server/tsconfig.json b/example/web-avatar-editor/server/tsconfig.json new file mode 100644 index 00000000..bb2b94b3 --- /dev/null +++ b/example/web-avatar-editor/server/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "noImplicitAny": true, + "module": "esnext", + "target": "es2022", + "jsx": "react", + "lib": ["es2022", "dom"], + "sourceMap": true, + "esModuleInterop": true, + "allowJs": true, + "strictNullChecks": true, + "allowSyntheticDefaultImports": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "downlevelIteration": true, + "noEmit": true, + "baseUrl": ".", + "incremental": true, + "skipLibCheck": true + }, + "include": ["src/**/*", "test/**/*", "./build.ts"], + "exclude": ["**/build/*", "types-src"] +} diff --git a/example/web-client/public/style.css b/example/web-client/public/style.css deleted file mode 100644 index 393e7976..00000000 --- a/example/web-client/public/style.css +++ /dev/null @@ -1,45 +0,0 @@ -html, -body, -#app, -#root { - width: 100%; - height: 100%; - touch-action: none; -} - -body { - margin: 0; - overflow: hidden; -} - -#app { - position: relative; - width: 100%; - height: 100%; - overflow: hidden; -} - -.frame-emu { - position: relative; - width: 90% !important; - height: 90% !important; - transform: translate(5%, 5%) !important; - overflow: hidden !important; -} - -#tweakpane-panel { - position: fixed; - width: 400px; - height: 100%; - top: 0px; - right: calc(-50vw); - z-index: 99; - overflow: auto; - background-color: rgba(0, 0, 0, 0.66); - padding-left: 5px; - box-shadow: -7px 0px 12px rgba(0, 0, 0, 0.5); - transition: right cubic-bezier(0.83, 0, 0.17, 1) 0.7s; - - scrollbar-width: auto; - scrollbar-color: #aaaaaa #000000; -} diff --git a/package-lock.json b/package-lock.json index 39afd62b..63042f84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,69 +8,68 @@ "hasInstallScript": true, "workspaces": [ "packages/*", - "example/*" + "example/**" ], "devDependencies": { - "@types/jest": "29.5.11", + "@types/jest": "29.5.12", "@types/jju": "^1.4.5", "@types/tmp": "^0.2.6", - "@typescript-eslint/eslint-plugin": "^6.20.0", - "@typescript-eslint/parser": "^6.20.0", + "@typescript-eslint/eslint-plugin": "^7.7.0", + "@typescript-eslint/parser": "^7.7.0", "concurrently": "^8.2.2", - "esbuild": "0.20.0", + "esbuild": "0.20.2", "esbuild-jest": "0.5.0", "esbuild-plugin-copy": "2.1.1", - "eslint": "^8.56.0", - "eslint-config-airbnb-typescript": "^17.1.0", + "eslint": "^8.57.0", + "eslint-config-airbnb-typescript": "^18.0.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.29.1", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react": "^7.34.1", "eslint-plugin-react-hooks": "^4.6.0", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jju": "^1.4.0", - "lerna": "8.0.2", - "prettier": "^3.2.4", + "lerna": "8.1.2", + "prettier": "^3.2.5", + "rfc6902": "^5.1.1", "rimraf": "^5.0.5", - "tmp": "^0.2.1", + "tmp": "^0.2.3", "ts-node": "^10.9.2", - "tsx": "4.7.0", - "typescript": "^5.3.3" + "tsx": "4.7.2", + "typescript": "^5.4.5" }, "engines": { - "node": "18.x" + "node": "20.x" } }, - "example/local-multi-web-client": { - "name": "@example/local-multi-web-client", + "example/local-only-multi-user-3d-web-experience/client": { + "name": "@example/local-only-multi-user-3d-web-experience-client", "version": "0.15.0", "dependencies": { "@mml-io/3d-web-client-core": "^0.15.0", "@mml-io/3d-web-text-chat": "^0.15.0", "@mml-io/3d-web-user-networking": "^0.15.0", "@mml-io/3d-web-voice-chat": "^0.15.0", - "mml-web-runner": "0.13.0", - "three": "0.153.0" + "mml-web-runner": "0.14.0", + "three": "0.163.0" }, "devDependencies": { - "@types/three": "0.153.0" + "@types/three": "0.163.0" } }, - "example/server": { - "name": "@example/server", + "example/local-only-multi-user-3d-web-experience/server": { + "name": "@example/local-only-multi-user-3d-web-experience-server", "version": "0.15.0", "dependencies": { - "@dolbyio/dolbyio-rest-apis-client": "4.1.0", - "@example/web-client": "^0.15.0", - "@mml-io/3d-web-text-chat": "^0.15.0", - "@mml-io/3d-web-user-networking": "^0.15.0", - "chokidar": "^3.5.3", + "@example/local-only-multi-user-3d-web-experience-client": "^0.15.0", + "@mml-io/3d-web-experience-server": "^0.15.0", + "chokidar": "^3.6.0", "cors": "^2.8.5", - "express": "4.18.2", + "express": "4.19.2", "express-ws": "5.0.2", "http-proxy": "^1.18.1", - "networked-dom-server": "0.13.0", + "networked-dom-server": "0.14.0", "ws": "8.16.0" }, "devDependencies": { @@ -78,170 +77,141 @@ "@types/express": "^4.17.21", "@types/express-ws": "^3.0.4", "@types/http-proxy": "^1.17.14", - "@types/node": "^20.11.13", - "nodemon": "^3.0.3" + "@types/node": "^20.12.7" }, "engines": { - "node": "18.x" + "node": "20.x" } }, - "example/web-avatar-client": { - "name": "@example/web-avatar-client", + "example/multi-user-3d-web-experience/client": { + "name": "@example/multi-user-3d-web-experience-client", "version": "0.15.0", "dependencies": { - "@mml-io/3d-web-client-core": "^0.15.0", - "@mml-io/3d-web-standalone-avatar-editor": "^0.15.0", - "three": "0.153.0" + "@mml-io/3d-web-experience-client": "^0.15.0", + "three": "0.163.0" }, "devDependencies": { - "@types/three": "0.153.0" + "@types/three": "0.163.0" } }, - "example/web-client": { - "name": "@example/web-client", + "example/multi-user-3d-web-experience/server": { + "name": "@example/multi-user-3d-web-experience-server", "version": "0.15.0", "dependencies": { - "@mml-io/3d-web-client-core": "^0.15.0", + "@dolbyio/dolbyio-rest-apis-client": "4.1.0", + "@example/multi-user-3d-web-experience-client": "^0.15.0", + "@mml-io/3d-web-experience-server": "^0.15.0", "@mml-io/3d-web-text-chat": "^0.15.0", "@mml-io/3d-web-user-networking": "^0.15.0", - "@mml-io/3d-web-voice-chat": "^0.15.0", - "three": "0.153.0" + "chokidar": "^3.6.0", + "cors": "^2.8.5", + "express": "4.19.2", + "express-ws": "5.0.2", + "http-proxy": "^1.18.1", + "networked-dom-server": "0.14.0", + "ws": "8.16.0" }, "devDependencies": { - "@types/three": "0.153.0" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@types/cors": "2.8.17", + "@types/express": "^4.17.21", + "@types/express-ws": "^3.0.4", + "@types/http-proxy": "^1.17.14", + "@types/node": "^20.12.7" }, "engines": { - "node": ">=6.0.0" + "node": "20.x" } }, - "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dev": true, + "example/web-avatar-editor/client": { + "name": "@example/web-avatar-editor-client", + "version": "0.15.0", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" + "@mml-io/3d-web-standalone-avatar-editor": "^0.15.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "example/web-avatar-editor/server": { + "name": "@example/web-avatar-editor-server", + "version": "0.15.0", "dependencies": { - "color-convert": "^1.9.0" + "@example/web-avatar-editor-client": "0.15.0", + "chokidar": "^3.6.0", + "cors": "^2.8.5", + "express": "4.19.2", + "express-ws": "5.0.2", + "http-proxy": "^1.18.1", + "ws": "8.16.0" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "devDependencies": { + "@types/cors": "2.8.17", + "@types/express": "^4.17.21", + "@types/express-ws": "^3.0.4", + "@types/http-proxy": "^1.17.14", + "@types/node": "^20.12.7" }, "engines": { - "node": ">=4" + "node": "20.x" } }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=0.10.0" } }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, "engines": { - "node": ">=4" + "node": ">=6.0.0" } }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", - "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.9", - "@babel/parser": "^7.23.9", - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -266,14 +236,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dev": true, "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -340,12 +310,12 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -371,9 +341,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -404,9 +374,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -431,28 +401,29 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", - "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dev": true, "dependencies": { - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -530,9 +501,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -602,12 +573,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -704,12 +675,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -719,13 +690,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", - "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-simple-access": "^7.22.5" }, "engines": { @@ -736,9 +707,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -748,33 +719,33 @@ } }, "node_modules/@babel/template": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", - "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", - "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -783,9 +754,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", - "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -849,9 +820,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.0.tgz", - "integrity": "sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", "cpu": [ "ppc64" ], @@ -865,9 +836,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.0.tgz", - "integrity": "sha512-3bMAfInvByLHfJwYPJRlpTeaQA75n8C/QKpEaiS4HrFWFiJlNI0vzq/zCjBrhAYcPyVPG7Eo9dMrcQXuqmNk5g==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", "cpu": [ "arm" ], @@ -881,9 +852,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.0.tgz", - "integrity": "sha512-aVpnM4lURNkp0D3qPoAzSG92VXStYmoVPOgXveAUoQBWRSuQzt51yvSju29J6AHPmwY1BjH49uR29oyfH1ra8Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", "cpu": [ "arm64" ], @@ -897,9 +868,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.0.tgz", - "integrity": "sha512-uK7wAnlRvjkCPzh8jJ+QejFyrP8ObKuR5cBIsQZ+qbMunwR8sbd8krmMbxTLSrDhiPZaJYKQAU5Y3iMDcZPhyQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", "cpu": [ "x64" ], @@ -913,9 +884,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.0.tgz", - "integrity": "sha512-AjEcivGAlPs3UAcJedMa9qYg9eSfU6FnGHJjT8s346HSKkrcWlYezGE8VaO2xKfvvlZkgAhyvl06OJOxiMgOYQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", "cpu": [ "arm64" ], @@ -929,9 +900,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.0.tgz", - "integrity": "sha512-bsgTPoyYDnPv8ER0HqnJggXK6RyFy4PH4rtsId0V7Efa90u2+EifxytE9pZnsDgExgkARy24WUQGv9irVbTvIw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", "cpu": [ "x64" ], @@ -945,9 +916,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.0.tgz", - "integrity": "sha512-kQ7jYdlKS335mpGbMW5tEe3IrQFIok9r84EM3PXB8qBFJPSc6dpWfrtsC/y1pyrz82xfUIn5ZrnSHQQsd6jebQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", "cpu": [ "arm64" ], @@ -961,9 +932,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.0.tgz", - "integrity": "sha512-uG8B0WSepMRsBNVXAQcHf9+Ko/Tr+XqmK7Ptel9HVmnykupXdS4J7ovSQUIi0tQGIndhbqWLaIL/qO/cWhXKyQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", "cpu": [ "x64" ], @@ -977,9 +948,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.0.tgz", - "integrity": "sha512-2ezuhdiZw8vuHf1HKSf4TIk80naTbP9At7sOqZmdVwvvMyuoDiZB49YZKLsLOfKIr77+I40dWpHVeY5JHpIEIg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", "cpu": [ "arm" ], @@ -993,9 +964,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.0.tgz", - "integrity": "sha512-uTtyYAP5veqi2z9b6Gr0NUoNv9F/rOzI8tOD5jKcCvRUn7T60Bb+42NDBCWNhMjkQzI0qqwXkQGo1SY41G52nw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", "cpu": [ "arm64" ], @@ -1009,9 +980,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.0.tgz", - "integrity": "sha512-c88wwtfs8tTffPaoJ+SQn3y+lKtgTzyjkD8NgsyCtCmtoIC8RDL7PrJU05an/e9VuAke6eJqGkoMhJK1RY6z4w==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", "cpu": [ "ia32" ], @@ -1025,9 +996,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.0.tgz", - "integrity": "sha512-lR2rr/128/6svngnVta6JN4gxSXle/yZEZL3o4XZ6esOqhyR4wsKyfu6qXAL04S4S5CgGfG+GYZnjFd4YiG3Aw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", "cpu": [ "loong64" ], @@ -1041,9 +1012,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.0.tgz", - "integrity": "sha512-9Sycc+1uUsDnJCelDf6ZNqgZQoK1mJvFtqf2MUz4ujTxGhvCWw+4chYfDLPepMEvVL9PDwn6HrXad5yOrNzIsQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", "cpu": [ "mips64el" ], @@ -1057,9 +1028,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.0.tgz", - "integrity": "sha512-CoWSaaAXOZd+CjbUTdXIJE/t7Oz+4g90A3VBCHLbfuc5yUQU/nFDLOzQsN0cdxgXd97lYW/psIIBdjzQIwTBGw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", "cpu": [ "ppc64" ], @@ -1073,9 +1044,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.0.tgz", - "integrity": "sha512-mlb1hg/eYRJUpv8h/x+4ShgoNLL8wgZ64SUr26KwglTYnwAWjkhR2GpoKftDbPOCnodA9t4Y/b68H4J9XmmPzA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", "cpu": [ "riscv64" ], @@ -1089,9 +1060,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.0.tgz", - "integrity": "sha512-fgf9ubb53xSnOBqyvWEY6ukBNRl1mVX1srPNu06B6mNsNK20JfH6xV6jECzrQ69/VMiTLvHMicQR/PgTOgqJUQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", "cpu": [ "s390x" ], @@ -1105,9 +1076,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.0.tgz", - "integrity": "sha512-H9Eu6MGse++204XZcYsse1yFHmRXEWgadk2N58O/xd50P9EvFMLJTQLg+lB4E1cF2xhLZU5luSWtGTb0l9UeSg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", "cpu": [ "x64" ], @@ -1121,9 +1092,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.0.tgz", - "integrity": "sha512-lCT675rTN1v8Fo+RGrE5KjSnfY0x9Og4RN7t7lVrN3vMSjy34/+3na0q7RIfWDAj0e0rCh0OL+P88lu3Rt21MQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", "cpu": [ "x64" ], @@ -1137,9 +1108,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.0.tgz", - "integrity": "sha512-HKoUGXz/TOVXKQ+67NhxyHv+aDSZf44QpWLa3I1lLvAwGq8x1k0T+e2HHSRvxWhfJrFxaaqre1+YyzQ99KixoA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", "cpu": [ "x64" ], @@ -1153,9 +1124,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.0.tgz", - "integrity": "sha512-GDwAqgHQm1mVoPppGsoq4WJwT3vhnz/2N62CzhvApFD1eJyTroob30FPpOZabN+FgCjhG+AgcZyOPIkR8dfD7g==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", "cpu": [ "x64" ], @@ -1169,9 +1140,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.0.tgz", - "integrity": "sha512-0vYsP8aC4TvMlOQYozoksiaxjlvUcQrac+muDqj1Fxy6jh9l9CZJzj7zmh8JGfiV49cYLTorFLxg7593pGldwQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", "cpu": [ "arm64" ], @@ -1185,9 +1156,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.0.tgz", - "integrity": "sha512-p98u4rIgfh4gdpV00IqknBD5pC84LCub+4a3MO+zjqvU5MVXOc3hqR2UgT2jI2nh3h8s9EQxmOsVI3tyzv1iFg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", "cpu": [ "ia32" ], @@ -1201,9 +1172,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.0.tgz", - "integrity": "sha512-NgJnesu1RtWihtTtXGFMU5YSE6JyyHPMxCwBZK7a6/8d31GuSo9l0Ss7w1Jw5QnKUawG6UEehs883kcXf5fYwg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", "cpu": [ "x64" ], @@ -1331,28 +1302,36 @@ } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@example/local-multi-web-client": { - "resolved": "example/local-multi-web-client", + "node_modules/@example/local-only-multi-user-3d-web-experience-client": { + "resolved": "example/local-only-multi-user-3d-web-experience/client", + "link": true + }, + "node_modules/@example/local-only-multi-user-3d-web-experience-server": { + "resolved": "example/local-only-multi-user-3d-web-experience/server", "link": true }, - "node_modules/@example/server": { - "resolved": "example/server", + "node_modules/@example/multi-user-3d-web-experience-client": { + "resolved": "example/multi-user-3d-web-experience/client", "link": true }, - "node_modules/@example/web-avatar-client": { - "resolved": "example/web-avatar-client", + "node_modules/@example/multi-user-3d-web-experience-server": { + "resolved": "example/multi-user-3d-web-experience/server", "link": true }, - "node_modules/@example/web-client": { - "resolved": "example/web-client", + "node_modules/@example/web-avatar-editor-client": { + "resolved": "example/web-avatar-editor/client", + "link": true + }, + "node_modules/@example/web-avatar-editor-server": { + "resolved": "example/web-avatar-editor/server", "link": true }, "node_modules/@humanwhocodes/config-array": { @@ -1405,9 +1384,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@hutson/parse-repository-url": { @@ -2313,14 +2292,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -2336,9 +2315,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" @@ -2351,9 +2330,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2361,13 +2340,13 @@ } }, "node_modules/@lerna/create": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@lerna/create/-/create-8.0.2.tgz", - "integrity": "sha512-AueSlfiYXqEmy9/EIc17mjlaHFuv734dfgVBegyoefIA7hdeoExtsXnACWf8Tw5af6gwyTL3KAp6QQyc1sTuZQ==", + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-8.1.2.tgz", + "integrity": "sha512-GzScCIkAW3tg3+Yn/MKCH9963bzG+zpjGz2NdfYDlYWI7p0f/SH46v1dqpPpYmZ2E/m3JK8HjTNNNL8eIm8/YQ==", "dev": true, "dependencies": { "@npmcli/run-script": "7.0.2", - "@nx/devkit": ">=17.1.2 < 18", + "@nx/devkit": ">=17.1.2 < 19", "@octokit/plugin-enterprise-rest": "6.0.1", "@octokit/rest": "19.0.11", "byte-size": "8.1.1", @@ -2404,7 +2383,7 @@ "npm-packlist": "5.1.1", "npm-registry-fetch": "^14.0.5", "npmlog": "^6.0.2", - "nx": ">=17.1.2 < 18", + "nx": ">=17.1.2 < 19", "p-map": "4.0.0", "p-map-series": "2.1.0", "p-queue": "6.6.2", @@ -2685,6 +2664,14 @@ "resolved": "packages/3d-web-client-core", "link": true }, + "node_modules/@mml-io/3d-web-experience-client": { + "resolved": "packages/3d-web-experience-client", + "link": true + }, + "node_modules/@mml-io/3d-web-experience-server": { + "resolved": "packages/3d-web-experience-server", + "link": true + }, "node_modules/@mml-io/3d-web-standalone-avatar-editor": { "resolved": "packages/3d-web-standalone-avatar-editor", "link": true @@ -2701,114 +2688,176 @@ "resolved": "packages/3d-web-voice-chat", "link": true }, + "node_modules/@mml-io/model-loader": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mml-io/model-loader/-/model-loader-0.14.0.tgz", + "integrity": "sha512-/9oJ155oyElQVBfdaKjBA3QH65yXxx/LG/X1XXv/9E53oIJDPUmyfk4KCyUPe3ZcHfvm7txrQku1cBcqZyjl7Q==", + "dependencies": { + "three": "^0.163.0" + } + }, "node_modules/@mml-io/networked-dom-document": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@mml-io/networked-dom-document/-/networked-dom-document-0.13.0.tgz", - "integrity": "sha512-OuQiWwz8Wh9BL0rUrzxpf6WnOflVMLCrz6vMBdVSIUM+xUT5m5JNDHp4E0dU6EpJdFItmSzy25TwqTsMQZ8CmQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mml-io/networked-dom-document/-/networked-dom-document-0.14.0.tgz", + "integrity": "sha512-fYkyqDencM9c8kX9mo8dIHEnxryoSUqVJKKWJI8LMb4fIXCYAU98tp+E9ZGWfaFtRma3Db8cYbErJ9c8BJNt7Q==", "dependencies": { - "@mml-io/networked-dom-protocol": "^0.13.0", - "@mml-io/observable-dom-common": "^0.13.0", + "@mml-io/networked-dom-protocol": "^0.14.0", + "@mml-io/observable-dom-common": "^0.14.0", "rfc6902": "5.1.1" } }, "node_modules/@mml-io/networked-dom-protocol": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@mml-io/networked-dom-protocol/-/networked-dom-protocol-0.13.0.tgz", - "integrity": "sha512-U+lmufb76DzXfjwPJMsVw4Mw16fs2XvwTH5fsNqQsJYCfkqUXWbrSa6cSKHKCQ5qhKL9yUAmTMhhswtvdCzdBw==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mml-io/networked-dom-protocol/-/networked-dom-protocol-0.14.0.tgz", + "integrity": "sha512-oHO/86OIW3Q0Ax4wPIChcpgG9KsLFJU3X1yi6ecsfNL+Wz7N4tPejvPgWdh8dveIUQCqcEv9A6yc6UC4Po5mjg==" }, "node_modules/@mml-io/networked-dom-web": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@mml-io/networked-dom-web/-/networked-dom-web-0.13.0.tgz", - "integrity": "sha512-ShKTA1zJLclnY+xjGHi3kbhbJ5HYlMEGCubKyjQ9FaI86+ipEpmxh+WSMlbSNHiN3/W87X4He/OmF1R7Tl0q/Q==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mml-io/networked-dom-web/-/networked-dom-web-0.14.0.tgz", + "integrity": "sha512-s1sG4Hnuo/C6NsfsBRtiZEBKgbtaIWdBg6q40sWx4koDjrf5DrGLGc4eiKyBpof9fUf2F32wDLQchMkHWgQnCQ==", "dependencies": { - "@mml-io/networked-dom-protocol": "^0.13.0" + "@mml-io/networked-dom-protocol": "^0.14.0" } }, "node_modules/@mml-io/networked-dom-web-runner": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@mml-io/networked-dom-web-runner/-/networked-dom-web-runner-0.13.0.tgz", - "integrity": "sha512-3YxOka82qkO/KQEaLM6bD/eNK3tXTl0BWpEDOfKWDq/5HrAoZQjtGVfPEkgDamYwLsl/C7sdBtOy3WCvZ53/oQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mml-io/networked-dom-web-runner/-/networked-dom-web-runner-0.14.0.tgz", + "integrity": "sha512-Ibm8kEk0HVe41tdpaA8IJBMK+knHtt4+9w667tT3l/Z2I8yXrMK6eYm8mASiUlm9qm0URiUjoyYuMWzksZZmmg==", "dependencies": { - "@mml-io/networked-dom-web": "^0.13.0", - "@mml-io/observable-dom-common": "^0.13.0" + "@mml-io/networked-dom-web": "^0.14.0", + "@mml-io/observable-dom-common": "^0.14.0" } }, "node_modules/@mml-io/observable-dom": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@mml-io/observable-dom/-/observable-dom-0.13.0.tgz", - "integrity": "sha512-nHz5UzN8rn5hSpmbhnA7TM6F2xYRv3ODM/a8okIkXQ+02EDHcLle59gH9Wk1Lvt+z7Rk9YTx7l5yIMLyGQwRUw==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mml-io/observable-dom/-/observable-dom-0.14.0.tgz", + "integrity": "sha512-snvAs4rxyVXOm+YE69OVK829/pvODbuw/K1uNJ7kB8s3H+ronANPD6gA40Wn0dwqbGDvyWX9P4/aJtPXVsjIoA==", "dependencies": { - "@mml-io/observable-dom-common": "^0.13.0", - "jsdom": "22.1.0", - "node-fetch": "2.6.12" + "@mml-io/observable-dom-common": "^0.14.0", + "jsdom": "24.0.0", + "node-fetch": "3.3.2" } }, "node_modules/@mml-io/observable-dom-common": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@mml-io/observable-dom-common/-/observable-dom-common-0.13.0.tgz", - "integrity": "sha512-HEOCFTudQG6a6xL3uFMiB0k0xe0BUzqk9EZ7iIQ96cCoCSkkzAE2TqozNJiDEdFUGVD9zFcAA4E/NDXf21wNVw==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mml-io/observable-dom-common/-/observable-dom-common-0.14.0.tgz", + "integrity": "sha512-etFtch7qU8cSW9+i5rTDC8SNfFHy4pSHsEecZgmpnyHjXDRGsT6WCXYVKMRI6WSqTpUS3l9IMensGp27vzBH4A==", "dependencies": { - "@mml-io/networked-dom-protocol": "^0.13.0" + "@mml-io/networked-dom-protocol": "^0.14.0" + } + }, + "node_modules/@mml-io/observable-dom/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/@mml-io/observable-dom/node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", + "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", "dependencies": { "rrweb-cssom": "^0.6.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/@mml-io/observable-dom/node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@mml-io/observable-dom/node_modules/html-encoding-sniffer": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" + "whatwg-encoding": "^3.1.1" }, "engines": { - "node": ">=14" + "node": ">=18" + } + }, + "node_modules/@mml-io/observable-dom/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@mml-io/observable-dom/node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@mml-io/observable-dom/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@mml-io/observable-dom/node_modules/jsdom": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", - "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.0.0.tgz", + "integrity": "sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==", "dependencies": { - "abab": "^2.0.6", - "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", "decimal.js": "^10.4.3", - "domexception": "^4.0.0", "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", + "nwsapi": "^2.2.7", "parse5": "^7.1.2", "rrweb-cssom": "^0.6.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", + "tough-cookie": "^4.1.3", + "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.16.0", + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" }, "peerDependencies": { - "canvas": "^2.5.0" + "canvas": "^2.11.2" }, "peerDependenciesMeta": { "canvas": { @@ -2817,64 +2866,92 @@ } }, "node_modules/@mml-io/observable-dom/node_modules/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "dependencies": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, - "node_modules/@mml-io/observable-dom/node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/@mml-io/observable-dom/node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "node_modules/@mml-io/observable-dom/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } }, - "node_modules/@mml-io/observable-dom/node_modules/node-fetch/node_modules/whatwg-url": { + "node_modules/@mml-io/observable-dom/node_modules/w3c-xmlserializer": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@mml-io/observable-dom/node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "node_modules/@mml-io/observable-dom/node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dependencies": { - "punycode": "^2.3.0" + "iconv-lite": "0.6.3" }, "engines": { - "node": ">=14" + "node": ">=18" + } + }, + "node_modules/@mml-io/observable-dom/node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "engines": { + "node": ">=18" } }, "node_modules/@mml-io/observable-dom/node_modules/whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", "dependencies": { - "tr46": "^4.1.1", + "tr46": "^5.0.0", "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" + } + }, + "node_modules/@mml-io/observable-dom/node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@monogrid/gainmap-js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.0.5.tgz", + "integrity": "sha512-53sCTG4FaJBaAq/tcufARtVYDMDGqyBT9i7F453pWGhZ5LqubDHDWtYoHo9VhQqMcHTEexdJqSsR58y+9HVmQA==", + "dependencies": { + "promise-worker-transferable": "^1.0.4" + }, + "peerDependencies": { + "three": ">= 0.159.0" } }, "node_modules/@nodelib/fs.scandir": { @@ -2913,25 +2990,25 @@ } }, "node_modules/@npmcli/agent": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", - "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", "dev": true, "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.1" + "socks-proxy-agent": "^8.0.3" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@npmcli/agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "dependencies": { "debug": "^4.3.4" @@ -2967,9 +3044,9 @@ } }, "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz", + "integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -2988,15 +3065,15 @@ } }, "node_modules/@npmcli/git": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", - "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.6.tgz", + "integrity": "sha512-4x/182sKXmQkf0EtXxT26GEsaOATpD7WVtza5hrYivWZeo6QefC6xq9KAXrnjtFKBZ4rZwR7aX/zClYYXgtwLw==", "dev": true, "dependencies": { "@npmcli/promise-spawn": "^7.0.0", "lru-cache": "^10.0.1", "npm-pick-manifest": "^9.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "promise-inflight": "^1.0.1", "promise-retry": "^2.0.1", "semver": "^7.3.5", @@ -3016,14 +3093,23 @@ } }, "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz", + "integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==", "dev": true, "engines": { "node": "14 || >=16.14" } }, + "node_modules/@npmcli/git/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@npmcli/git/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -3040,16 +3126,16 @@ } }, "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", + "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", "dev": true, "dependencies": { "npm-bundled": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" }, "bin": { - "installed-package-contents": "lib/index.js" + "installed-package-contents": "bin/index.js" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -3121,6 +3207,15 @@ "node": "^16.13.0 || >=18.0.0" } }, + "node_modules/@npmcli/redact": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-1.1.0.tgz", + "integrity": "sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/@npmcli/run-script": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.2.tgz", @@ -3162,21 +3257,21 @@ } }, "node_modules/@nrwl/devkit": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-17.3.2.tgz", - "integrity": "sha512-31wh7dDZPM1YUCfhhk/ioHnUeoPIlKYLFLW0fGdw76Ow2nmTqrmxha2m0CSIR1/9En9GpYut2IdUdNh9CctNlA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-18.3.4.tgz", + "integrity": "sha512-Fty9Huqm12OYueU3uLJl3uvBUl5BvEyPfvw8+rLiNx9iftdEattM8C+268eAbIRRSLSOVXlWsJH4brlc6QZYYw==", "dev": true, "dependencies": { - "@nx/devkit": "17.3.2" + "@nx/devkit": "18.3.4" } }, "node_modules/@nrwl/tao": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-17.3.2.tgz", - "integrity": "sha512-5uvpSmij0J9tteFV/0M/024K+H/o3XAlqtSdU8j03Auj1IleclSLF2yCTuIo7pYXhG3cgx1+nR+3nMs1QVAdUA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-18.3.4.tgz", + "integrity": "sha512-+7KsDYmGj1cvNaXZcjSYOPN1h17hsGFBtVX7MqnpJLLkQTUhKg2rQxqyluzshJ+RoDUVtYPGyHg1AizlB66RIA==", "dev": true, "dependencies": { - "nx": "17.3.2", + "nx": "18.3.4", "tslib": "^2.3.0" }, "bin": { @@ -3184,12 +3279,12 @@ } }, "node_modules/@nx/devkit": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-17.3.2.tgz", - "integrity": "sha512-gbOIhwrZKCSSFFbh6nE6LLCvAU7mhSdBSnRiS14YBwJJMu4CRJ0IcaFz58iXqGWZefMivKtkNFtx+zqwUC4ziw==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-18.3.4.tgz", + "integrity": "sha512-M3htxl5WvlNKK5KNOndCAApbyBCZNTFFs+rtdwvudNZk5+84zAAPaWzSoX9C4XLAW78/f98LzF68/ch05aN12A==", "dev": true, "dependencies": { - "@nrwl/devkit": "17.3.2", + "@nrwl/devkit": "18.3.4", "ejs": "^3.1.7", "enquirer": "~2.3.6", "ignore": "^5.0.4", @@ -3199,13 +3294,13 @@ "yargs-parser": "21.1.1" }, "peerDependencies": { - "nx": ">= 16 <= 18" + "nx": ">= 16 <= 19" } }, "node_modules/@nx/nx-darwin-arm64": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-17.3.2.tgz", - "integrity": "sha512-hn12o/tt26Pf4wG+8rIBgNIEZq5BFlHLv3scNrgKbd5SancHlTbY4RveRGct737UQ/78GCMCgMDRgNdagbCr6w==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.3.4.tgz", + "integrity": "sha512-MOGk9z4fIoOkJB68diH3bwoWrC8X9IzMNsz1mu0cbVfgCRAfIV3b+lMsiwQYzWal3UWW5DE5Rkss4F8whiV5Uw==", "cpu": [ "arm64" ], @@ -3219,9 +3314,9 @@ } }, "node_modules/@nx/nx-darwin-x64": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-17.3.2.tgz", - "integrity": "sha512-5F28wrfE7yU60MzEXGjndy1sPJmNMIaV2W/g82kTXzxAbGHgSjwrGFmrJsrexzLp9oDlWkbc6YmInKV8gmmIaQ==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-18.3.4.tgz", + "integrity": "sha512-tSzPRnNB3QdPM+KYiIuRCUtyCwcuIRC95FfP0ZB3WvfDeNxJChEAChNqmCMDE4iFvZhGuze8WqkJuIVdte+lyQ==", "cpu": [ "x64" ], @@ -3235,9 +3330,9 @@ } }, "node_modules/@nx/nx-freebsd-x64": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-17.3.2.tgz", - "integrity": "sha512-07MMTfsJooONqL1Vrm5L6qk/gzmSrYLazjkiTmJz+9mrAM61RdfSYfO3mSyAoyfgWuQ5yEvfI56P036mK8aoPg==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-18.3.4.tgz", + "integrity": "sha512-bjSPak/d+bcR95/pxHMRhnnpHc6MnrQcG6f5AjX15Esm4JdrdQKPBmG1RybuK0WKSyD5wgVhkAGc/QQUom9l8g==", "cpu": [ "x64" ], @@ -3251,9 +3346,9 @@ } }, "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-17.3.2.tgz", - "integrity": "sha512-gQxMF6U/h18Rz+FZu50DZCtfOdk27hHghNh3d3YTeVsrJTd1SmUQbYublmwU/ia1HhFS8RVI8GvkaKt5ph0HoA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-18.3.4.tgz", + "integrity": "sha512-/1HnUL7jhH0S7PxJqf6R1pk3QlAU22GY89EQV9fd+RDUtp7IyzaTlkebijTIqfxlSjC4OO3bPizaxEaxdd3uKQ==", "cpu": [ "arm" ], @@ -3267,9 +3362,9 @@ } }, "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-17.3.2.tgz", - "integrity": "sha512-X20wiXtXmKlC01bpVEREsRls1uVOM22xDTpqILvVty6+P+ytEYFR3Vs5EjDtzBKF51wjrwf03rEoToZbmgM8MA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-18.3.4.tgz", + "integrity": "sha512-g/2IaB2bZTKaBNPEf9LxtIXb1XHdhh3VO9PnePIrwkkixPMLN0dTxT5Sttt75lvLP3EU1AUR5w3Aaz2Q1mYtWA==", "cpu": [ "arm64" ], @@ -3283,9 +3378,9 @@ } }, "node_modules/@nx/nx-linux-arm64-musl": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-17.3.2.tgz", - "integrity": "sha512-yko3Xsezkn4tjeudZYLjxFl07X/YB84K+DLK7EFyh9elRWV/8VjFcQmBAKUS2r9LfaEMNXq8/vhWMOWYyWBrIA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-18.3.4.tgz", + "integrity": "sha512-MgfKLoEF6I1cCS+0ooFLEjJSSVdCYyCT9Q96IHRJntAEL8u/0GR2OUoBoLC+q1lnbIkJr/uqTJxA2Jh+sJTIbA==", "cpu": [ "arm64" ], @@ -3299,9 +3394,9 @@ } }, "node_modules/@nx/nx-linux-x64-gnu": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-17.3.2.tgz", - "integrity": "sha512-RiPvvQMmlZmDu9HdT6n6sV0+fEkyAqR5VocrD5ZAzEzFIlh4dyVLripFR3+MD+QhIhXyPt/hpri1kq9sgs4wnw==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.3.4.tgz", + "integrity": "sha512-vbHxv7m3gjthBvw50EYCtgyY0Zg5nVTaQtX+wRsmKybV2i7wHbw5zIe1aL4zHUm6TcPGbIQK+utVM+hyCqKHVA==", "cpu": [ "x64" ], @@ -3315,9 +3410,9 @@ } }, "node_modules/@nx/nx-linux-x64-musl": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-17.3.2.tgz", - "integrity": "sha512-PWfVGmFsFJi+N1Nljg/jTKLHdufpGuHlxyfHqhDso/o4Qc0exZKSeZ1C63WkD7eTcT5kInifTQ/PffLiIDE3MA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-18.3.4.tgz", + "integrity": "sha512-qIJKJCYFRLVSALsvg3avjReOjuYk91Q0hFXMJ2KaEM1Y3tdzcFN0fKBiaHexgbFIUk8zJuS4dJObTqSYMXowbg==", "cpu": [ "x64" ], @@ -3331,9 +3426,9 @@ } }, "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-17.3.2.tgz", - "integrity": "sha512-O+4FFPbQz1mqaIj+SVE02ppe7T9ELj7Z5soQct5TbRRhwjGaw5n5xaPPBW7jUuQe2L5htid1E82LJyq3JpVc8A==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-18.3.4.tgz", + "integrity": "sha512-UxC8mRkFTPdZbKFprZkiBqVw8624xU38kI0xyooxKlFpt5lccTBwJ0B7+R8p1RoWyvh2DSyFI9VvfD7lczg1lA==", "cpu": [ "arm64" ], @@ -3347,9 +3442,9 @@ } }, "node_modules/@nx/nx-win32-x64-msvc": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-17.3.2.tgz", - "integrity": "sha512-4hQm+7coy+hBqGY9J709hz/tUPijhf/WS7eML2r2xBmqBew3PMHfeZuaAAYWN690nIsu0WX3wyDsNjulR8HGPQ==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.3.4.tgz", + "integrity": "sha512-/RqEjNU9hxIBxRLafCNKoH3SaB2FShf+1ZnIYCdAoCZBxLJebDpnhiyrVs0lPnMj9248JbizEMdJj1+bs/bXig==", "cpu": [ "x64" ], @@ -3574,9 +3669,9 @@ } }, "node_modules/@sigstore/core": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.0.0.tgz", - "integrity": "sha512-dW2qjbWLRKGu6MIDUTBuJwXCnR8zivcSpf5inUzk7y84zqy/dji0/uahppoIgMoKeR+6pUZucrwHfkQQtiG9Rw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", + "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", "dev": true, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -3629,16 +3724,16 @@ } }, "node_modules/@sigstore/sign/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -3764,38 +3859,38 @@ } }, "node_modules/@sigstore/verify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.1.0.tgz", - "integrity": "sha512-1fTqnqyTBWvV7cftUUFtDcHPdSox0N3Ub7C0lRyReYx4zZUlNTZjCV+HPy4Lre+r45dV7Qx5JLKvqqsgxuyYfg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.0.tgz", + "integrity": "sha512-hQF60nc9yab+Csi4AyoAmilGNfpXT+EXdBgFkP9OgPwIBPwyqVf7JAWPtmqrrrneTmAT6ojv7OlH1f6Ix5BG4Q==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.2.0", - "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.0" + "@sigstore/bundle": "^2.3.1", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@sigstore/verify/node_modules/@sigstore/bundle": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.2.0.tgz", - "integrity": "sha512-5VI58qgNs76RDrwXNhpmyN/jKpq9evV/7f1XrcqcAfvxDl5SeVY/I5Rmfe96ULAV7/FK5dge9RBKGBJPhL1WsQ==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.1.tgz", + "integrity": "sha512-eqV17lO3EIFqCWK3969Rz+J8MYrRZKw9IBHpSo6DEcEX2c+uzDFOgHE9f2MnyDpfs48LFO4hXmk9KhQ74JzU1g==", "dev": true, "dependencies": { - "@sigstore/protobuf-specs": "^0.3.0" + "@sigstore/protobuf-specs": "^0.3.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@sigstore/verify/node_modules/@sigstore/protobuf-specs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.0.tgz", - "integrity": "sha512-zxiQ66JFOjVvP9hbhGj/F/qNdsZfkGb/dVXSanNRNuAzMlr4MC95voPUBX8//ZNnmv3uSYzdfR/JSkrgvZTGxA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.1.tgz", + "integrity": "sha512-aIL8Z9NsMr3C64jyQzE0XlkEyBLpgEJJFDHLVVStkFV5Q3Il/r/YtY6NJWKQ4cy4AE7spP1IX5Jq7VCAxHHMfQ==", "dev": true, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@sinclair/typebox": { @@ -3826,14 +3921,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, "engines": { "node": ">= 10" } }, "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true }, "node_modules/@tsconfig/node12": { @@ -3890,9 +3986,9 @@ } }, "node_modules/@tweenjs/tween.js": { - "version": "18.6.4", - "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-18.6.4.tgz", - "integrity": "sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==", + "version": "23.1.1", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.1.tgz", + "integrity": "sha512-ZpboH7pCPPeyBWKf8c7TJswtCEQObFo3bOBYalm99NzZarATALYCo5OhbCa/n4RQyJyHfhkdx+hNrdL5ByFYDw==", "dev": true }, "node_modules/@types/babel__core": { @@ -3977,9 +4073,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dev": true, "dependencies": { "@types/node": "*", @@ -4048,9 +4144,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.11", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.11.tgz", - "integrity": "sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==", + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -4105,9 +4201,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", - "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -4120,15 +4216,15 @@ "dev": true }, "node_modules/@types/prop-types": { - "version": "15.7.11", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", "dev": true }, "node_modules/@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", "dev": true }, "node_modules/@types/range-parser": { @@ -4138,35 +4234,28 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.2.57", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.57.tgz", - "integrity": "sha512-ZvQsktJgSYrQiMirAN60y4O/LRevIV8hUzSOSNB6gfR3/o3wCBFQx3sPwIYtuDMeiVgsSS3UzCV26tEzgnfvQw==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.0.tgz", + "integrity": "sha512-DiUcKjzE6soLyln8NNZmyhcQjVv+WsUIFSqetMN0p8927OztKT4VTfFTqsbAi5oAGIcgOmOajlfBqyptDDjZRw==", "dev": true, "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.19", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.19.tgz", - "integrity": "sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", "dev": true, "dependencies": { "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "dev": true - }, "node_modules/@types/semver": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", - "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/send": { @@ -4180,14 +4269,14 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, "dependencies": { "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@types/stack-utils": { @@ -4203,16 +4292,16 @@ "dev": true }, "node_modules/@types/three": { - "version": "0.153.0", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.153.0.tgz", - "integrity": "sha512-L9quzIP4lsl6asDCw5zqN5opewCVOKRuB09apw5Acf2AIkoj5gLnUOY5AMB/ntFUt/QfFey0uKZaAd5t+HXSUw==", + "version": "0.163.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.163.0.tgz", + "integrity": "sha512-uIdDhsXRpQiBUkflBS/i1l3JX14fW6Ot9csed60nfbZNXHDTRsnV2xnTVwXcgbvTiboAR4IW+t+lTL5f1rqIqA==", "dev": true, "dependencies": { - "@tweenjs/tween.js": "~18.6.4", + "@tweenjs/tween.js": "~23.1.1", "@types/stats.js": "*", "@types/webxr": "*", - "fflate": "~0.6.9", - "lil-gui": "~0.17.0" + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" } }, "node_modules/@types/tmp": { @@ -4228,9 +4317,9 @@ "dev": true }, "node_modules/@types/webxr": { - "version": "0.5.14", - "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.14.tgz", - "integrity": "sha512-UEMMm/Xn3DtEa+gpzUrOcDj+SJS1tk5YodjwOxcqStNhCfPcwgyC5Srg2ToVKyg2Fhq16Ffpb0UWUQHqoT9AMA==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.15.tgz", + "integrity": "sha512-nC9116Gd4N+CqTxqo6gvCfhAMAzgRcfS8ZsciNodHq8uwW4JCVKwhagw8yN0XmC7mHrLnWqniJpoVEiR+72Drw==", "dev": true }, "node_modules/@types/ws": { @@ -4258,33 +4347,33 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", + "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/type-utils": "7.7.1", + "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -4293,26 +4382,26 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", + "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -4321,16 +4410,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", + "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4338,25 +4427,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", + "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/utils": "7.7.1", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -4365,12 +4454,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", + "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4378,22 +4467,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", + "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4406,41 +4495,41 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", + "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", + "semver": "^7.6.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", + "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.7.1", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4454,15 +4543,15 @@ "dev": true }, "node_modules/@voxeet/voxeet-web-sdk": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@voxeet/voxeet-web-sdk/-/voxeet-web-sdk-3.11.0.tgz", - "integrity": "sha512-ltQ0E8EzHTJxJXl63IFqw6hSs9fzwF9DiV7jtudfKaQxrNDBDEDIE3vUjlxQZlKGfjLoeODfCFezxyjbB0tXNA==", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@voxeet/voxeet-web-sdk/-/voxeet-web-sdk-3.11.1.tgz", + "integrity": "sha512-YzesJMYCwZZB7H4L1qdhL6KFY9z52OnVmf3du7DTmQkbyZGhGZLi6DhIODLQjDkpgsffWay9ZJLq9NZ8YoilOw==", "dependencies": { - "axios": "^0.26.0", + "axios": "^0.28.0", "bowser": "^2.8.1", "browserslist": "^4.5.2", "btoa": "^1.1.2", - "debug": "^4.3.1", + "debug": "^4.3.4", "events": "^1.1.0", "get-float-time-domain-data": "^0.1.0", "global": "^4.4.0", @@ -4475,11 +4564,13 @@ } }, "node_modules/@voxeet/voxeet-web-sdk/node_modules/axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.28.1.tgz", + "integrity": "sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ==", "dependencies": { - "follow-redirects": "^1.14.8" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/@yarnpkg/lockfile": { @@ -4523,7 +4614,8 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead" + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true }, "node_modules/abbrev": { "version": "2.0.0", @@ -4596,6 +4688,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "dependencies": { "debug": "4" }, @@ -4802,15 +4895,16 @@ "dev": true }, "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -4838,17 +4932,18 @@ "node": ">=0.10.0" } }, - "node_modules/array.prototype.filter": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", - "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4858,15 +4953,16 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", - "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", + "es-abstract": "^1.23.2", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" }, "engines": { @@ -4912,6 +5008,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, "node_modules/array.prototype.tosorted": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", @@ -4971,15 +5079,6 @@ "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", "dev": true }, - "node_modules/asynciterator.prototype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", - "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -5013,12 +5112,12 @@ } }, "node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "dev": true, "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -5178,11 +5277,14 @@ "dev": true }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bl": { @@ -5197,12 +5299,12 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -5210,7 +5312,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -5339,9 +5441,9 @@ "dev": true }, "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", + "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", "dev": true, "dependencies": { "semver": "^7.0.0" @@ -5388,16 +5490,16 @@ } }, "node_modules/cacache/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -5410,9 +5512,9 @@ } }, "node_modules/cacache/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz", + "integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -5504,9 +5606,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001588", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz", - "integrity": "sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "funding": [ { "type": "opencollective", @@ -6088,9 +6190,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -6294,6 +6396,14 @@ "node": ">=8" } }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -6308,6 +6418,57 @@ "node": ">=12" } }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -6398,9 +6559,9 @@ } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -6612,6 +6773,7 @@ "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", "deprecated": "Use your platform's native DOMException instead", + "dev": true, "dependencies": { "webidl-conversions": "^7.0.0" }, @@ -6670,9 +6832,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, "dependencies": { "jake": "^10.8.5" @@ -6685,9 +6847,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.677", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.677.tgz", - "integrity": "sha512-erDa3CaDzwJOpyvfKhOiJjBVNnMM0qxHq47RheVVwsSQrgBA9ZSGV9kdaOfZDPXcHzhG7lBxhj6A7KvfLJBd6Q==" + "version": "1.4.749", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.749.tgz", + "integrity": "sha512-LRMMrM9ITOvue0PoBrvNIraVmuDbJV5QC9ierz/z5VilMdPOVMjOtpICNld3PuXuTZ3CHH/UPxX9gHhAPwi+0Q==" }, "node_modules/emittery": { "version": "0.13.1", @@ -6719,6 +6881,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -6728,6 +6891,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -6805,18 +6969,22 @@ } }, "node_modules/es-abstract": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", - "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.6", + "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", @@ -6824,15 +6992,16 @@ "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "hasown": "^2.0.1", + "hasown": "^2.0.2", "internal-slot": "^1.0.7", "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", @@ -6840,17 +7009,17 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.5", "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", + "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.1", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -6859,12 +7028,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -6885,26 +7048,37 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.17.tgz", - "integrity": "sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==", + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", "dev": true, "dependencies": { - "asynciterator.prototype": "^1.0.0", "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.4", + "es-abstract": "^1.23.3", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "globalthis": "^1.0.3", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", "internal-slot": "^1.0.7", "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.0" + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -6951,9 +7125,9 @@ } }, "node_modules/esbuild": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.0.tgz", - "integrity": "sha512-6iwE3Y2RVYCME1jLpBqq7LQWK3MW6vjV2bZy6gt/WrqkY+WE74Spyc0ThAOYpMtITvnjX09CrC6ym7A/m9mebA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", "dev": true, "hasInstallScript": true, "bin": { @@ -6963,29 +7137,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.0", - "@esbuild/android-arm": "0.20.0", - "@esbuild/android-arm64": "0.20.0", - "@esbuild/android-x64": "0.20.0", - "@esbuild/darwin-arm64": "0.20.0", - "@esbuild/darwin-x64": "0.20.0", - "@esbuild/freebsd-arm64": "0.20.0", - "@esbuild/freebsd-x64": "0.20.0", - "@esbuild/linux-arm": "0.20.0", - "@esbuild/linux-arm64": "0.20.0", - "@esbuild/linux-ia32": "0.20.0", - "@esbuild/linux-loong64": "0.20.0", - "@esbuild/linux-mips64el": "0.20.0", - "@esbuild/linux-ppc64": "0.20.0", - "@esbuild/linux-riscv64": "0.20.0", - "@esbuild/linux-s390x": "0.20.0", - "@esbuild/linux-x64": "0.20.0", - "@esbuild/netbsd-x64": "0.20.0", - "@esbuild/openbsd-x64": "0.20.0", - "@esbuild/sunos-x64": "0.20.0", - "@esbuild/win32-arm64": "0.20.0", - "@esbuild/win32-ia32": "0.20.0", - "@esbuild/win32-x64": "0.20.0" + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" } }, "node_modules/esbuild-css-modules-plugin": { @@ -7080,16 +7254,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -7163,18 +7337,17 @@ } }, "node_modules/eslint-config-airbnb-typescript": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", - "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-18.0.0.tgz", + "integrity": "sha512-oc+Lxzgzsu8FQyFVa4QFaVKiitTYiiW3frB9KYW5OWdPrqFc7FzxgB20hP4cHMlr+MBzGcLl3jnCOVOydL9mIg==", "dev": true, "dependencies": { "eslint-config-airbnb-base": "^15.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", - "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3" + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" } }, "node_modules/eslint-config-prettier": { @@ -7210,9 +7383,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -7349,27 +7522,29 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.33.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", - "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", + "es-iterator-helpers": "^1.0.17", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", + "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" + "string.prototype.matchall": "^4.0.10" }, "engines": { "node": ">=4" @@ -7379,9 +7554,9 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.1.tgz", + "integrity": "sha512-Ck77j8hF7l9N4S/rzSLOWEKpn994YH6iwUK8fr9mXIaQvGpQYmOnQLbiue1u5kI5T1y+gdgqosnEAO9NCz0DBg==", "dev": true, "engines": { "node": ">=10" @@ -7879,16 +8054,16 @@ "dev": true }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -8115,10 +8290,32 @@ "bser": "2.1.1" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/fflate": { - "version": "0.6.10", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", - "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", "dev": true }, "node_modules/figures": { @@ -8277,9 +8474,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -8354,6 +8551,17 @@ "node": ">= 6" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -8652,9 +8860,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", - "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -9050,9 +9258,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -9094,6 +9302,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, "dependencies": { "whatwg-encoding": "^2.0.0" }, @@ -9145,6 +9354,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, "dependencies": { "@tootallnate/once": "2", "agent-base": "6", @@ -9158,6 +9368,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -9224,12 +9435,6 @@ "node": ">= 4" } }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, "node_modules/ignore-walk": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", @@ -9254,6 +9459,11 @@ "node": ">=10" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -9606,6 +9816,21 @@ "node": ">= 0.4" } }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -9753,10 +9978,13 @@ "dev": true }, "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9837,6 +10065,11 @@ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -9854,10 +10087,13 @@ } }, "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9974,10 +10210,13 @@ } }, "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9995,13 +10234,16 @@ } }, "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12108,14 +12350,14 @@ } }, "node_modules/lerna": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/lerna/-/lerna-8.0.2.tgz", - "integrity": "sha512-nnOIGI5V5Af9gfraNcMVoV1Fry/y7/h3nCQYk0/CMzBYDD+xbNL3DH8+c82AJkNR5ABslmpXjW4DLJ11/1b3CQ==", + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-8.1.2.tgz", + "integrity": "sha512-RCyBAn3XsqqvHbz3TxLfD7ylqzCi1A2UJnFEZmhURgx589vM3qYWQa/uOMeEEf565q6cAdtmulITciX1wgkAtw==", "dev": true, "dependencies": { - "@lerna/create": "8.0.2", + "@lerna/create": "8.1.2", "@npmcli/run-script": "7.0.2", - "@nx/devkit": ">=17.1.2 < 18", + "@nx/devkit": ">=17.1.2 < 19", "@octokit/plugin-enterprise-rest": "6.0.1", "@octokit/rest": "19.0.11", "byte-size": "8.1.1", @@ -12158,7 +12400,7 @@ "npm-packlist": "5.1.1", "npm-registry-fetch": "^14.0.5", "npmlog": "^6.0.2", - "nx": ">=17.1.2 < 18", + "nx": ">=17.1.2 < 19", "p-map": "4.0.0", "p-map-series": "2.1.0", "p-pipe": "3.1.0", @@ -12586,10 +12828,18 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lightningcss": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.23.0.tgz", - "integrity": "sha512-SEArWKMHhqn/0QzOtclIwH5pXIYQOUEkF8DgICd/105O+GCgd7jxjNod/QPnBCSWvpRHQBGVz5fQ9uScby03zA==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.24.1.tgz", + "integrity": "sha512-kUpHOLiH5GB0ERSv4pxqlL0RYKnOXtgGtVe7shDGfhS0AZ4D1ouKFYAcLcZhql8aMspDNzaUCumGHZ78tb2fTg==", "dev": true, "dependencies": { "detect-libc": "^1.0.3" @@ -12602,21 +12852,21 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-darwin-arm64": "1.23.0", - "lightningcss-darwin-x64": "1.23.0", - "lightningcss-freebsd-x64": "1.23.0", - "lightningcss-linux-arm-gnueabihf": "1.23.0", - "lightningcss-linux-arm64-gnu": "1.23.0", - "lightningcss-linux-arm64-musl": "1.23.0", - "lightningcss-linux-x64-gnu": "1.23.0", - "lightningcss-linux-x64-musl": "1.23.0", - "lightningcss-win32-x64-msvc": "1.23.0" + "lightningcss-darwin-arm64": "1.24.1", + "lightningcss-darwin-x64": "1.24.1", + "lightningcss-freebsd-x64": "1.24.1", + "lightningcss-linux-arm-gnueabihf": "1.24.1", + "lightningcss-linux-arm64-gnu": "1.24.1", + "lightningcss-linux-arm64-musl": "1.24.1", + "lightningcss-linux-x64-gnu": "1.24.1", + "lightningcss-linux-x64-musl": "1.24.1", + "lightningcss-win32-x64-msvc": "1.24.1" } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.23.0.tgz", - "integrity": "sha512-kl4Pk3Q2lnE6AJ7Qaij47KNEfY2/UXRZBT/zqGA24B8qwkgllr/j7rclKOf1axcslNXvvUdztjo4Xqh39Yq1aA==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.24.1.tgz", + "integrity": "sha512-1jQ12jBy+AE/73uGQWGSafK5GoWgmSiIQOGhSEXiFJSZxzV+OXIx+a9h2EYHxdJfX864M+2TAxWPWb0Vv+8y4w==", "cpu": [ "arm64" ], @@ -12634,9 +12884,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.23.0.tgz", - "integrity": "sha512-KeRFCNoYfDdcolcFXvokVw+PXCapd2yHS1Diko1z1BhRz/nQuD5XyZmxjWdhmhN/zj5sH8YvWsp0/lPLVzqKpg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.24.1.tgz", + "integrity": "sha512-R4R1d7VVdq2mG4igMU+Di8GPf0b64ZLnYVkubYnGG0Qxq1KaXQtAzcLI43EkpnoWvB/kUg8JKCWH4S13NfiLcQ==", "cpu": [ "x64" ], @@ -12654,9 +12904,9 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.23.0.tgz", - "integrity": "sha512-xhnhf0bWPuZxcqknvMDRFFo2TInrmQRWZGB0f6YoAsZX8Y+epfjHeeOIGCfAmgF0DgZxHwYc8mIR5tQU9/+ROA==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.24.1.tgz", + "integrity": "sha512-z6NberUUw5ALES6Ixn2shmjRRrM1cmEn1ZQPiM5IrZ6xHHL5a1lPin9pRv+w6eWfcrEo+qGG6R9XfJrpuY3e4g==", "cpu": [ "x64" ], @@ -12674,9 +12924,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.23.0.tgz", - "integrity": "sha512-fBamf/bULvmWft9uuX+bZske236pUZEoUlaHNBjnueaCTJ/xd8eXgb0cEc7S5o0Nn6kxlauMBnqJpF70Bgq3zg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.24.1.tgz", + "integrity": "sha512-NLQLnBQW/0sSg74qLNI8F8QKQXkNg4/ukSTa+XhtkO7v3BnK19TS1MfCbDHt+TTdSgNEBv0tubRuapcKho2EWw==", "cpu": [ "arm" ], @@ -12694,9 +12944,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.23.0.tgz", - "integrity": "sha512-RS7sY77yVLOmZD6xW2uEHByYHhQi5JYWmgVumYY85BfNoVI3DupXSlzbw+b45A9NnVKq45+oXkiN6ouMMtTwfg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.24.1.tgz", + "integrity": "sha512-AQxWU8c9E9JAjAi4Qw9CvX2tDIPjgzCTrZCSXKELfs4mCwzxRkHh2RCxX8sFK19RyJoJAjA/Kw8+LMNRHS5qEg==", "cpu": [ "arm64" ], @@ -12714,9 +12964,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.23.0.tgz", - "integrity": "sha512-cU00LGb6GUXCwof6ACgSMKo3q7XYbsyTj0WsKHLi1nw7pV0NCq8nFTn6ZRBYLoKiV8t+jWl0Hv8KkgymmK5L5g==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.24.1.tgz", + "integrity": "sha512-JCgH/SrNrhqsguUA0uJUM1PvN5+dVuzPIlXcoWDHSv2OU/BWlj2dUYr3XNzEw748SmNZPfl2NjQrAdzaPOn1lA==", "cpu": [ "arm64" ], @@ -12734,9 +12984,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.23.0.tgz", - "integrity": "sha512-q4jdx5+5NfB0/qMbXbOmuC6oo7caPnFghJbIAV90cXZqgV8Am3miZhC4p+sQVdacqxfd+3nrle4C8icR3p1AYw==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.24.1.tgz", + "integrity": "sha512-TYdEsC63bHV0h47aNRGN3RiK7aIeco3/keN4NkoSQ5T8xk09KHuBdySltWAvKLgT8JvR+ayzq8ZHnL1wKWY0rw==", "cpu": [ "x64" ], @@ -12754,9 +13004,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.23.0.tgz", - "integrity": "sha512-G9Ri3qpmF4qef2CV/80dADHKXRAQeQXpQTLx7AiQrBYQHqBjB75oxqj06FCIe5g4hNCqLPnM9fsO4CyiT1sFSQ==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.24.1.tgz", + "integrity": "sha512-HLfzVik3RToot6pQ2Rgc3JhfZkGi01hFetHt40HrUMoeKitLoqUUT5owM6yTZPTytTUW9ukLBJ1pc3XNMSvlLw==", "cpu": [ "x64" ], @@ -12774,9 +13024,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.23.0.tgz", - "integrity": "sha512-1rcBDJLU+obPPJM6qR5fgBUiCdZwZLafZM5f9kwjFLkb/UBNIzmae39uCSmh71nzPCTXZqHbvwu23OWnWEz+eg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.24.1.tgz", + "integrity": "sha512-joEupPjYJ7PjZtDsS5lzALtlAudAbgIBMGJPNeFe5HfdmJXFd13ECmEM+5rXNxYVMRHua2w8132R6ab5Z6K9Ow==", "cpu": [ "x64" ], @@ -12793,12 +13043,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/lil-gui": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.17.0.tgz", - "integrity": "sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ==", - "dev": true - }, "node_modules/lines-and-columns": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", @@ -13156,6 +13400,12 @@ "node": ">= 8" } }, + "node_modules/meshoptimizer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", + "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", + "dev": true + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -13234,9 +13484,9 @@ } }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -13484,22 +13734,22 @@ } }, "node_modules/mml-web": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/mml-web/-/mml-web-0.13.0.tgz", - "integrity": "sha512-kidoJuH9A3BxZvgiMQ85e7VgVaWqyjERjGF7AifE7FhbwaiDwvgtl0/6mkSvV7TLW0Vtsrb3OG6Yvs8ePv0HiQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/mml-web/-/mml-web-0.14.0.tgz", + "integrity": "sha512-1ERRsRvTnYA4Ex/VvrDWn65s0H6DjJyjEfeTbWjSBcSSi8LwZKKzLWHaF4Pxz0TY9WRR45LatHdGKivisHzKRA==", "dependencies": { - "@mml-io/networked-dom-web": "^0.13.0" + "@mml-io/networked-dom-web": "^0.14.0" }, "peerDependencies": { "three": "*" } }, "node_modules/mml-web-runner": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/mml-web-runner/-/mml-web-runner-0.13.0.tgz", - "integrity": "sha512-NDx25oSMjy0lzXeB+yeQUBLbUqMUr32pEDGbjWiYqpChXpicQ4NUbV3sqzqz2SIx9BxXectQook6R80DROYGZg==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/mml-web-runner/-/mml-web-runner-0.14.0.tgz", + "integrity": "sha512-ybR9Y+UamCalfU3UT4GNqpFjesLUz/b7FL4vfTdqSWR9rMFilz6z/RODfSn/fV0VltHC0qsxyUqBLdWYzTVg8g==", "dependencies": { - "@mml-io/networked-dom-web-runner": "^0.13.0" + "@mml-io/networked-dom-web-runner": "^0.14.0" } }, "node_modules/modify-values": { @@ -13623,13 +13873,13 @@ "dev": true }, "node_modules/networked-dom-server": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/networked-dom-server/-/networked-dom-server-0.13.0.tgz", - "integrity": "sha512-o4Re5mnM9P7tRe7osfHxvLGt0thL+T50JwJ4zoC6TQGwm8I2Y2Fh5hlH6BVNy4yTIxlNWjl09erOkVB/Y6H09w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/networked-dom-server/-/networked-dom-server-0.14.0.tgz", + "integrity": "sha512-3bEiRaV/VtX+EwDocSMW7iytnTxSY92svPkZYSNcdFlj8/0JeeJr4eyiEymCf6AgXshq+nv0u2xTNJdi7mUKHw==", "dependencies": { - "@mml-io/networked-dom-document": "^0.13.0", - "@mml-io/observable-dom": "^0.13.0", - "@mml-io/observable-dom-common": "^0.13.0" + "@mml-io/networked-dom-document": "^0.14.0", + "@mml-io/observable-dom": "^0.14.0", + "@mml-io/observable-dom-common": "^0.14.0" } }, "node_modules/nice-try": { @@ -13638,6 +13888,24 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -13681,9 +13949,9 @@ } }, "node_modules/node-gyp": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", - "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", + "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", "dev": true, "dependencies": { "env-paths": "^2.2.0", @@ -13705,16 +13973,16 @@ } }, "node_modules/node-gyp/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -13767,77 +14035,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, - "node_modules/nodemon": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", - "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", - "dev": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nodemon/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/nopt": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", @@ -14039,9 +14236,9 @@ } }, "node_modules/npm-pick-manifest/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz", + "integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -14057,13 +14254,13 @@ } }, "node_modules/npm-pick-manifest/node_modules/npm-package-arg": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", - "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", + "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", "dev": true, "dependencies": { "hosted-git-info": "^7.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^5.0.0" }, @@ -14071,6 +14268,15 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/npm-pick-manifest/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/npm-registry-fetch": { "version": "14.0.5", "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", @@ -14122,25 +14328,34 @@ } }, "node_modules/npm-registry-fetch/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" }, "engines": { "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm-registry-fetch/node_modules/glob/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" } }, "node_modules/npm-registry-fetch/node_modules/hosted-git-info": { @@ -14307,18 +14522,18 @@ } }, "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", + "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==" }, "node_modules/nx": { - "version": "17.3.2", - "resolved": "https://registry.npmjs.org/nx/-/nx-17.3.2.tgz", - "integrity": "sha512-QjF1gnwKebQISvATrSbW7dsmIcLbA0fcyDyxLo5wVHx/MIlcaIb/lLYaPTld73ZZ6svHEZ6n2gOkhMitmkIPQA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/nx/-/nx-18.3.4.tgz", + "integrity": "sha512-7rOHRyxpnZGJ3pHnwmpoAMHt9hNuwibWhOhPBJDhJVcbQJtGfwcWWyV/iSEnVXwKZ2lfHVE3TwE+gXFdT/GFiw==", "dev": true, "hasInstallScript": true, "dependencies": { - "@nrwl/tao": "17.3.2", + "@nrwl/tao": "18.3.4", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "3.0.0-rc.46", "@zkochan/js-yaml": "0.0.6", @@ -14358,19 +14573,19 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "17.3.2", - "@nx/nx-darwin-x64": "17.3.2", - "@nx/nx-freebsd-x64": "17.3.2", - "@nx/nx-linux-arm-gnueabihf": "17.3.2", - "@nx/nx-linux-arm64-gnu": "17.3.2", - "@nx/nx-linux-arm64-musl": "17.3.2", - "@nx/nx-linux-x64-gnu": "17.3.2", - "@nx/nx-linux-x64-musl": "17.3.2", - "@nx/nx-win32-arm64-msvc": "17.3.2", - "@nx/nx-win32-x64-msvc": "17.3.2" + "@nx/nx-darwin-arm64": "18.3.4", + "@nx/nx-darwin-x64": "18.3.4", + "@nx/nx-freebsd-x64": "18.3.4", + "@nx/nx-linux-arm-gnueabihf": "18.3.4", + "@nx/nx-linux-arm64-gnu": "18.3.4", + "@nx/nx-linux-arm64-musl": "18.3.4", + "@nx/nx-linux-x64-gnu": "18.3.4", + "@nx/nx-linux-x64-musl": "18.3.4", + "@nx/nx-win32-arm64-msvc": "18.3.4", + "@nx/nx-win32-x64-msvc": "18.3.4" }, "peerDependencies": { - "@swc-node/register": "^1.6.7", + "@swc-node/register": "^1.8.0", "@swc/core": "^1.3.85" }, "peerDependenciesMeta": { @@ -14414,6 +14629,21 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/nx/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/nx/node_modules/ora": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", @@ -14566,28 +14796,29 @@ } }, "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -14597,26 +14828,31 @@ } }, "node_modules/object.groupby": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", - "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, "dependencies": { - "array.prototype.filter": "^1.0.3", - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0" + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", "dev": true, "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14635,14 +14871,14 @@ } }, "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -14901,9 +15137,9 @@ } }, "node_modules/pacote": { - "version": "17.0.6", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", - "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "version": "17.0.7", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.7.tgz", + "integrity": "sha512-sgvnoUMlkv9xHwDUKjKQFXVyUi8dtJGKp3vg6sYy+TxbDic5RjZCHF3ygv0EJgNRZ2GfRONjlKPUfokJ9lDpwQ==", "dev": true, "dependencies": { "@npmcli/git": "^5.0.0", @@ -14917,7 +15153,7 @@ "npm-packlist": "^8.0.0", "npm-pick-manifest": "^9.0.0", "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "promise-retry": "^2.0.1", "read-package-json": "^7.0.0", "read-package-json-fast": "^3.0.0", @@ -14933,35 +15169,35 @@ } }, "node_modules/pacote/node_modules/@sigstore/bundle": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.2.0.tgz", - "integrity": "sha512-5VI58qgNs76RDrwXNhpmyN/jKpq9evV/7f1XrcqcAfvxDl5SeVY/I5Rmfe96ULAV7/FK5dge9RBKGBJPhL1WsQ==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.1.tgz", + "integrity": "sha512-eqV17lO3EIFqCWK3969Rz+J8MYrRZKw9IBHpSo6DEcEX2c+uzDFOgHE9f2MnyDpfs48LFO4hXmk9KhQ74JzU1g==", "dev": true, "dependencies": { - "@sigstore/protobuf-specs": "^0.3.0" + "@sigstore/protobuf-specs": "^0.3.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/pacote/node_modules/@sigstore/protobuf-specs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.0.tgz", - "integrity": "sha512-zxiQ66JFOjVvP9hbhGj/F/qNdsZfkGb/dVXSanNRNuAzMlr4MC95voPUBX8//ZNnmv3uSYzdfR/JSkrgvZTGxA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.1.tgz", + "integrity": "sha512-aIL8Z9NsMr3C64jyQzE0XlkEyBLpgEJJFDHLVVStkFV5Q3Il/r/YtY6NJWKQ4cy4AE7spP1IX5Jq7VCAxHHMfQ==", "dev": true, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/pacote/node_modules/@sigstore/sign": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.3.tgz", - "integrity": "sha512-LqlA+ffyN02yC7RKszCdMTS6bldZnIodiox+IkT8B2f8oRYXCB3LQ9roXeiEL21m64CVH1wyveYAORfD65WoSw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.0.tgz", + "integrity": "sha512-tsAyV6FC3R3pHmKS880IXcDJuiFJiKITO1jxR1qbplcsBkZLBmjrEw5GbC7ikD6f5RU1hr7WnmxB/2kKc1qUWQ==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.2.0", + "@sigstore/bundle": "^2.3.0", "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.0", + "@sigstore/protobuf-specs": "^0.3.1", "make-fetch-happen": "^13.0.0" }, "engines": { @@ -14969,9 +15205,9 @@ } }, "node_modules/pacote/node_modules/@sigstore/tuf": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.1.tgz", - "integrity": "sha512-9Iv40z652td/QbV0o5n/x25H9w6IYRt2pIGbTX55yFDYlApDQn/6YZomjz6+KBx69rXHLzHcbtTS586mDdFD+Q==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.2.tgz", + "integrity": "sha512-mwbY1VrEGU4CO55t+Kl6I7WZzIl+ysSzEYdA1Nv/FTrl2bkeaPXo5PnWZAVfcY2zSdhOpsUTJW67/M2zHXGn5w==", "dev": true, "dependencies": { "@sigstore/protobuf-specs": "^0.3.0", @@ -15004,16 +15240,16 @@ } }, "node_modules/pacote/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -15059,9 +15295,9 @@ } }, "node_modules/pacote/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz", + "integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -15092,13 +15328,13 @@ } }, "node_modules/pacote/node_modules/npm-package-arg": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", - "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", + "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", "dev": true, "dependencies": { "hosted-git-info": "^7.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^5.0.0" }, @@ -15119,23 +15355,33 @@ } }, "node_modules/pacote/node_modules/npm-registry-fetch": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", - "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz", + "integrity": "sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA==", "dev": true, "dependencies": { + "@npmcli/redact": "^1.1.0", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", "minipass-json-stream": "^1.0.1", "minizlib": "^2.1.2", "npm-package-arg": "^11.0.0", - "proc-log": "^3.0.0" + "proc-log": "^4.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/pacote/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/pacote/node_modules/read-package-json": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", @@ -15152,17 +15398,17 @@ } }, "node_modules/pacote/node_modules/sigstore": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.2.tgz", - "integrity": "sha512-2A3WvXkQurhuMgORgT60r6pOWiCOO5LlEqY2ADxGBDGVYLSo5HN0uLtb68YpVpuL/Vi8mLTe7+0Dx2Fq8lLqEg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.0.tgz", + "integrity": "sha512-q+o8L2ebiWD1AxD17eglf1pFrl9jtW7FHa0ygqY6EKvibK8JHyq9Z26v9MZXeDiw+RbfOJ9j2v70M10Hd6E06A==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.2.0", + "@sigstore/bundle": "^2.3.1", "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.0", - "@sigstore/sign": "^2.2.3", + "@sigstore/protobuf-specs": "^0.3.1", + "@sigstore/sign": "^2.3.0", "@sigstore/tuf": "^2.3.1", - "@sigstore/verify": "^1.1.0" + "@sigstore/verify": "^1.2.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -15310,12 +15556,12 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dev": true, "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -15326,9 +15572,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz", + "integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -15416,14 +15662,14 @@ } }, "node_modules/postprocessing": { - "version": "6.34.1", - "resolved": "https://registry.npmjs.org/postprocessing/-/postprocessing-6.34.1.tgz", - "integrity": "sha512-xae6A2XNs61V3ohGHR+i9sQDvB4dWaoG/AICw0hg8sOYQWAYDlf+esWMRmO4hixMaYo3AJBJ9WAA7JF7OiGakw==", + "version": "6.35.3", + "resolved": "https://registry.npmjs.org/postprocessing/-/postprocessing-6.35.3.tgz", + "integrity": "sha512-PH0/gqVYpp+vZjmSAohG/xH0u9FpbjfCGsFMsmsZVd8XXSmqJUR7b5C9ZFE/iMrWhe+tiTOFN9WvcEdjLI8LYQ==", "engines": { "node": ">= 0.13.2" }, "peerDependencies": { - "three": ">= 0.138.0 < 0.161.0" + "three": ">= 0.152.0 < 0.164.0" } }, "node_modules/prelude-ls": { @@ -15530,6 +15776,15 @@ "node": ">=10" } }, + "node_modules/promise-worker-transferable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", + "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", + "dependencies": { + "is-promise": "^2.1.0", + "lie": "^3.0.2" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -15544,12 +15799,33 @@ } }, "node_modules/promzard": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promzard/-/promzard-1.0.1.tgz", + "integrity": "sha512-ulDF77aULEHUoJkN5XZgRV5loHXBaqd9eorMvLNLvi2gXMuRAtwH6Gh4zsMHQY1kTt7tyv/YZwZW5C2gtj8F2A==", + "dev": true, + "dependencies": { + "read": "^3.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/promzard/node_modules/mute-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-1.0.0.tgz", - "integrity": "sha512-KQVDEubSUHGSt5xLakaToDFrSoZhStB8dXLzk2xvwR67gJktrHFvpR63oZgHyK19WKbHFLXJqCPXdVR3aBP8Ig==", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/promzard/node_modules/read": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/read/-/read-3.0.1.tgz", + "integrity": "sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==", "dev": true, "dependencies": { - "read": "^2.0.0" + "mute-stream": "^1.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -15593,20 +15869,13 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -15626,9 +15895,9 @@ } }, "node_modules/pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -15698,9 +15967,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -15712,9 +15981,9 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.0.tgz", + "integrity": "sha512-RPutkJftSAldDibyrjuku7q11d3oy6wKOyPe5K1HA/HwwrXcEqBdHsLypkC2FFYjP7bPUa6gbzSBhw4sY2JcDg==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -15723,21 +15992,21 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-zaKdLBftQJnvb7FtDIpZtsAIb2MZU087RM8bRDZU8LVCCFYjPTsDZJNFUWPcVz3HFSN1n/caxi0ca4B/aaVQGQ==", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.1" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.0" } }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.0.tgz", + "integrity": "sha512-wRiUsea88TjKDc4FBEn+sLvIDesp6brMbGWnJGjew2waAc9evdhja/2LvePc898HJbHw0L+MTWy7NhpnELAvLQ==", "dev": true }, "node_modules/read": { @@ -15808,16 +16077,16 @@ } }, "node_modules/read-package-json/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -16110,16 +16379,16 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", - "integrity": "sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0", - "get-intrinsic": "^1.2.3", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", "globalthis": "^1.0.3", "which-builtin-type": "^1.1.3" }, @@ -16333,16 +16602,16 @@ } }, "node_modules/rimraf/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -16422,13 +16691,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -16795,9 +17064,9 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.1.tgz", + "integrity": "sha512-5GKS5JGfiah1O38Vfa9srZE4s3wdHbwjlCrvIookrg2FO9aIwKLOJXuJQFlEfNcVSOXuaL2hzDeY20uVXcUtrw==", "dependencies": { "loose-envify": "^1.1.0" } @@ -16902,16 +17171,16 @@ "dev": true }, "node_modules/set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dependencies": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -17028,11 +17297,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -17093,16 +17362,16 @@ } }, "node_modules/sigstore/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -17214,18 +17483,6 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -17391,9 +17648,9 @@ } }, "node_modules/socks": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.3.tgz", - "integrity": "sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "dependencies": { "ip-address": "^9.0.5", @@ -17405,12 +17662,12 @@ } }, "node_modules/socks-proxy-agent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", - "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", "dev": true, "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.1", "debug": "^4.3.4", "socks": "^2.7.1" }, @@ -17419,9 +17676,9 @@ } }, "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "dependencies": { "debug": "^4.3.4" @@ -17708,34 +17965,41 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -17745,28 +18009,31 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -18037,14 +18304,14 @@ "dev": true }, "node_modules/three": { - "version": "0.153.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.153.0.tgz", - "integrity": "sha512-OCP2/uQR6GcDpSLnJt/3a4mdS0kNWcbfUXIwLoEMgLzEUIVIYsSDwskpmOii/AkDM+BBwrl6+CKgrjX9+E2aWg==" + "version": "0.163.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.163.0.tgz", + "integrity": "sha512-HlMgCb2TF/dTLRtknBnjUTsR8FsDqBY43itYop2+Zg822I+Kd0Ua2vs8CvfBVefXkBdNDrLMoRTGCIIpfCuDew==" }, "node_modules/three-mesh-bvh": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.1.tgz", - "integrity": "sha512-63xvjnmK3FpA41klHfVvTMi2JRFdKeu3b4STBcLvGyDMYRpkBIyJ2d77CnNvKBZl9bed4sdEyrqE3AOsGorjUA==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.4.tgz", + "integrity": "sha512-flxe0A4uflTPR6elgq/Y8VrLoljDNS899i422SxQcU3EtMj6o8z4kZRyqZqGWzR0qMf1InTZzY1/0xZl/rnvVw==", "peerDependencies": { "three": ">= 0.151.0" } @@ -18102,30 +18369,12 @@ } }, "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/tmp/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=14.14" } }, "node_modules/tmpl": { @@ -18201,39 +18450,6 @@ "node": ">=0.6" } }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/touch/node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/touch/node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/tough-cookie": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", @@ -18287,9 +18503,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", - "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { "node": ">=16" @@ -18381,9 +18597,9 @@ "dev": true }, "node_modules/tsx": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.0.tgz", - "integrity": "sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.2.tgz", + "integrity": "sha512-BCNd4kz6fz12fyrgCTEdZHGJ9fWTGeUzXmQysh0RVocDY3h4frk05ZNCXSy4kIenF7y/QnrdiVpTsyNRn6vlAw==", "dev": true, "dependencies": { "esbuild": "~0.19.10", @@ -18843,16 +19059,16 @@ } }, "node_modules/tuf-js/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -19071,9 +19287,9 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "dependencies": { "call-bind": "^1.0.7", @@ -19106,9 +19322,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -19146,12 +19362,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -19437,6 +19647,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, "dependencies": { "xml-name-validator": "^4.0.0" }, @@ -19462,6 +19673,14 @@ "defaults": "^1.0.3" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -19487,6 +19706,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -19498,6 +19718,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -19509,6 +19730,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, "engines": { "node": ">=12" } @@ -19584,31 +19806,34 @@ } }, "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-typed-array": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", - "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -19788,6 +20013,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, "engines": { "node": ">=12" } @@ -19873,15 +20099,16 @@ "name": "@mml-io/3d-web-avatar", "version": "0.15.0", "dependencies": { + "@mml-io/model-loader": "0.14.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "three": "0.153.0" + "three": "0.163.0" }, "devDependencies": { - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", - "@types/three": "0.153.0", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", + "@types/three": "0.163.0", "esbuild-css-modules-plugin": "3.1.0" } }, @@ -19893,9 +20120,9 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", "esbuild-css-modules-plugin": "3.1.0" } }, @@ -19904,18 +20131,50 @@ "version": "0.15.0", "dependencies": { "@mml-io/3d-web-avatar": "^0.15.0", + "@mml-io/model-loader": "0.14.0", + "@monogrid/gainmap-js": "^3.0.5", "@tweakpane/core": "2.0.3", "@tweakpane/plugin-essentials": "0.2.1", - "mml-web": "0.13.0", - "postprocessing": "6.34.1", - "three-mesh-bvh": "0.7.1", + "mml-web": "0.14.0", + "postprocessing": "6.35.3", + "three-mesh-bvh": "0.7.4", "tweakpane": "4.0.3" }, "devDependencies": { - "@types/three": "0.153.0" + "@types/three": "0.163.0" }, "peerDependencies": { - "three": ">= 0.153.0" + "three": ">= 0.163.0" + } + }, + "packages/3d-web-experience-client": { + "name": "@mml-io/3d-web-experience-client", + "version": "0.15.0", + "dependencies": { + "@mml-io/3d-web-client-core": "^0.15.0", + "@mml-io/3d-web-text-chat": "^0.15.0", + "@mml-io/3d-web-user-networking": "^0.15.0", + "@mml-io/3d-web-voice-chat": "^0.15.0", + "three": "0.163.0" + }, + "devDependencies": { + "@types/node": "^20.12.7", + "@types/three": "0.163.0" + } + }, + "packages/3d-web-experience-server": { + "name": "@mml-io/3d-web-experience-server", + "version": "0.15.0", + "dependencies": { + "@mml-io/3d-web-client-core": "^0.15.0", + "@mml-io/3d-web-text-chat": "^0.15.0", + "@mml-io/3d-web-user-networking": "^0.15.0", + "@mml-io/3d-web-voice-chat": "^0.15.0", + "three": "0.163.0" + }, + "devDependencies": { + "@types/node": "^20.12.7", + "@types/three": "0.163.0" } }, "packages/3d-web-standalone-avatar-editor": { @@ -19925,15 +20184,16 @@ "@mml-io/3d-web-avatar": "^0.15.0", "@mml-io/3d-web-avatar-editor-ui": "^0.15.0", "@mml-io/3d-web-client-core": "^0.15.0", + "@mml-io/model-loader": "0.14.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "three": "0.153.0" + "three": "0.163.0" }, "devDependencies": { - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", - "@types/three": "0.153.0", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", + "@types/three": "0.163.0", "esbuild-css-modules-plugin": "3.1.0" } }, @@ -19941,7 +20201,7 @@ "name": "@mml-io/3d-web-text-chat", "version": "0.15.0", "dependencies": { - "express": "4.18.2", + "express": "4.19.2", "express-ws": "5.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -19950,9 +20210,9 @@ "devDependencies": { "@types/express": "^4.17.21", "@types/express-ws": "^3.0.4", - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", "@types/ws": "^8.5.10", "esbuild-css-modules-plugin": "3.1.0" } @@ -19966,9 +20226,9 @@ "devDependencies": { "@types/express": "^4.17.21", "@types/express-ws": "^3.0.4", - "@types/node": "^20.11.13", + "@types/node": "^20.12.7", "@types/ws": "^8.5.10", - "express": "4.18.2", + "express": "4.19.2", "express-ws": "5.0.2" } }, @@ -19976,7 +20236,7 @@ "name": "@mml-io/3d-web-voice-chat", "version": "0.15.0", "dependencies": { - "@voxeet/voxeet-web-sdk": "3.11.0", + "@voxeet/voxeet-web-sdk": "3.11.1", "react": "^18.2.0", "react-dom": "^18.2.0", "ws": "^8.16.0" @@ -19984,12 +20244,12 @@ "devDependencies": { "@types/express": "^4.17.21", "@types/express-ws": "^3.0.4", - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", "@types/ws": "^8.5.10", "esbuild-css-modules-plugin": "3.1.0", - "express": "4.18.2", + "express": "4.19.2", "express-ws": "5.0.2" } } diff --git a/package.json b/package.json index f7a8794b..af17c089 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "private": true, "type": "module", "engines": { - "node": "18.x" + "node": "20.x" }, "scripts": { "preinstall": "node check-node-version.js", @@ -20,34 +20,35 @@ }, "workspaces": [ "packages/*", - "example/*" + "example/**" ], "devDependencies": { - "@types/jest": "29.5.11", + "@types/jest": "29.5.12", "@types/jju": "^1.4.5", "@types/tmp": "^0.2.6", - "@typescript-eslint/eslint-plugin": "^6.20.0", - "@typescript-eslint/parser": "^6.20.0", + "@typescript-eslint/eslint-plugin": "^7.7.0", + "@typescript-eslint/parser": "^7.7.0", "concurrently": "^8.2.2", - "esbuild": "0.20.0", + "esbuild": "0.20.2", "esbuild-jest": "0.5.0", "esbuild-plugin-copy": "2.1.1", - "eslint": "^8.56.0", - "eslint-config-airbnb-typescript": "^17.1.0", + "eslint": "^8.57.0", + "eslint-config-airbnb-typescript": "^18.0.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.29.1", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react": "^7.34.1", "eslint-plugin-react-hooks": "^4.6.0", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jju": "^1.4.0", - "lerna": "8.0.2", - "prettier": "^3.2.4", + "lerna": "8.1.2", + "prettier": "^3.2.5", + "rfc6902": "^5.1.1", "rimraf": "^5.0.5", - "tmp": "^0.2.1", + "tmp": "^0.2.3", "ts-node": "^10.9.2", - "tsx": "4.7.0", - "typescript": "^5.3.3" + "tsx": "4.7.2", + "typescript": "^5.4.5" } } diff --git a/packages/3d-web-avatar-editor-ui/build.ts b/packages/3d-web-avatar-editor-ui/build.ts index 17b91697..6e3aa3be 100644 --- a/packages/3d-web-avatar-editor-ui/build.ts +++ b/packages/3d-web-avatar-editor-ui/build.ts @@ -2,14 +2,14 @@ import cssModulesPlugin from "esbuild-css-modules-plugin"; import { handleLibraryBuild } from "../../utils/build-library"; -handleLibraryBuild( - [ +handleLibraryBuild({ + plugins: [ cssModulesPlugin({ inject: true, emitDeclarationFile: true, }), ], - { + loader: { ".svg": "text", }, -); +}); diff --git a/packages/3d-web-avatar-editor-ui/package.json b/packages/3d-web-avatar-editor-ui/package.json index cdb62a1a..07556ce6 100644 --- a/packages/3d-web-avatar-editor-ui/package.json +++ b/packages/3d-web-avatar-editor-ui/package.json @@ -23,9 +23,9 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", "esbuild-css-modules-plugin": "3.1.0" } } diff --git a/packages/3d-web-avatar/build.ts b/packages/3d-web-avatar/build.ts index 17b91697..6e3aa3be 100644 --- a/packages/3d-web-avatar/build.ts +++ b/packages/3d-web-avatar/build.ts @@ -2,14 +2,14 @@ import cssModulesPlugin from "esbuild-css-modules-plugin"; import { handleLibraryBuild } from "../../utils/build-library"; -handleLibraryBuild( - [ +handleLibraryBuild({ + plugins: [ cssModulesPlugin({ inject: true, emitDeclarationFile: true, }), ], - { + loader: { ".svg": "text", }, -); +}); diff --git a/packages/3d-web-avatar/package.json b/packages/3d-web-avatar/package.json index e44f6c4f..595b5b26 100644 --- a/packages/3d-web-avatar/package.json +++ b/packages/3d-web-avatar/package.json @@ -22,13 +22,14 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "three": "0.153.0" + "@mml-io/model-loader": "0.14.0", + "three": "0.163.0" }, "devDependencies": { - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", - "@types/three": "0.153.0", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", + "@types/three": "0.163.0", "esbuild-css-modules-plugin": "3.1.0" } } diff --git a/packages/3d-web-avatar/src/character/MMLCharacter.ts b/packages/3d-web-avatar/src/character/MMLCharacter.ts index a35fb853..e14447a8 100644 --- a/packages/3d-web-avatar/src/character/MMLCharacter.ts +++ b/packages/3d-web-avatar/src/character/MMLCharacter.ts @@ -1,30 +1,14 @@ -import { - Bone, - BufferAttribute, - Euler, - Group, - MathUtils, - Matrix4, - MeshStandardMaterial, - Object3D, - Skeleton, - SkinnedMesh, - Vector3, -} from "three"; -import { GLTF } from "three/examples/jsm/loaders/GLTFLoader.js"; +import { ModelLoadResult } from "@mml-io/model-loader"; +import { Bone, BufferAttribute, Group, MathUtils, Object3D, Skeleton, SkinnedMesh } from "three"; import { MMLCharacterDescriptionPart } from "../helpers/parseMMLDescription"; -import { SkeletonHelpers } from "../helpers/SkeletonHelpers"; -import { ModelLoader } from "./ModelLoader"; +type MMLCharacterModelLoader = { + load: (url: string) => Promise; +}; export class MMLCharacter { - private skeletonHelpers: SkeletonHelpers = new SkeletonHelpers(); - private skinnedMeshesParent: Group | null = null; - private sharedSkeleton: Skeleton | null = null; - private sharedMatrixWorld: Matrix4 | null = null; - - constructor(private modelLoader: ModelLoader) {} + constructor(private modelLoader: MMLCharacterModelLoader) {} private createBoneIndexMap( originSkeleton: Skeleton, @@ -42,8 +26,7 @@ export class MMLCharacter { return boneIndexMap; } - private remapBoneIndices(skinnedMesh: SkinnedMesh): void { - const targetSkeleton = this.sharedSkeleton!; + private remapBoneIndices(skinnedMesh: SkinnedMesh, targetSkeleton: Skeleton): void { const originSkeleton = skinnedMesh.skeleton; const originGeometry = skinnedMesh.geometry; @@ -70,24 +53,26 @@ export class MMLCharacter { fullBodyURL: string, bodyParts: Array, ): Promise { - const fullBodyAsset = await this.modelLoader.load(fullBodyURL); - const fullBodyGLTF = this.skeletonHelpers.cloneGLTF(fullBodyAsset as GLTF, "fullBody"); - const assetPromises: Array> = - bodyParts.map((part) => { - return new Promise((resolve) => { - this.modelLoader.load(part.url).then((asset) => { - resolve({ asset: asset!, part }); - }); + const group = new Group(); + + const fullBodyAssetPromise = this.modelLoader.load(fullBodyURL); + + const assetPromises: Array< + Promise<{ asset: ModelLoadResult; part: MMLCharacterDescriptionPart }> + > = bodyParts.map((part) => { + return new Promise((resolve) => { + this.modelLoader.load(part.url).then((asset) => { + resolve({ asset, part }); }); }); - const assets = await Promise.all(assetPromises); - - const fullBodyModelGroup = fullBodyGLTF.gltf.scene; + }); - this.skinnedMeshesParent = null; + const fullBodyAsset = await fullBodyAssetPromise; + const assets = await Promise.all(assetPromises); + const rawBodyGltf = fullBodyAsset.group; const availableBones = new Map(); - fullBodyModelGroup.traverse((child) => { + rawBodyGltf.traverse((child) => { const asBone = child as Bone; if (asBone.isBone) { availableBones.set(child.name, asBone); @@ -97,18 +82,35 @@ export class MMLCharacter { if (asSkinnedMesh.isSkinnedMesh) { asSkinnedMesh.castShadow = true; asSkinnedMesh.receiveShadow = true; - if (this.skinnedMeshesParent === null) { - this.skinnedMeshesParent = asSkinnedMesh.parent as Group; - } } }); - this.sharedSkeleton = fullBodyGLTF.sharedSkeleton; - this.sharedMatrixWorld = fullBodyGLTF.matrixWorld; + const foundSkinnedMeshes: Array = []; + rawBodyGltf.traverse((child) => { + const asSkinnedMesh = child as SkinnedMesh; + if (asSkinnedMesh.isSkinnedMesh) { + foundSkinnedMeshes.push(asSkinnedMesh); + } + }); + + if (foundSkinnedMeshes.length === 0) { + throw new Error("No skinned mesh in base model file"); + } + if (foundSkinnedMeshes.length > 1) { + console.warn( + "Multiple skinned meshes in base model file. Expected 1. Using first for skeleton.", + ); + } + const skinnedMesh = foundSkinnedMeshes[0]; + group.add(...foundSkinnedMeshes); + const sharedSkeleton = skinnedMesh.skeleton; + group.add(skinnedMesh.skeleton.bones[0]); + const sharedMatrixWorld = skinnedMesh.matrixWorld; for (const loadingAsset of assets) { const part = loadingAsset.part; - const gltf = this.skeletonHelpers.cloneGLTF(loadingAsset.asset, part.url); - const modelGroup = gltf.gltf.scene; + const rawGltf = loadingAsset.asset; + + const modelGroup = rawGltf.group; if (part.socket) { const socketName = part.socket.socket; let bone = availableBones.get("root"); @@ -120,45 +122,40 @@ export class MMLCharacter { ); } if (bone) { - modelGroup.position.set(0, 0, 0); - modelGroup.rotation.set(0, 0, 0); - modelGroup.scale.set(1, 1, 1); - bone.add(modelGroup); - modelGroup.rotateZ(-Math.PI / 2); - - const offsetPosition = new Vector3( + modelGroup.position.set( part.socket.position.x, part.socket.position.y, part.socket.position.z, ); - modelGroup.position.copy(offsetPosition); - const offsetRotation = new Euler( + modelGroup.rotation.set( MathUtils.degToRad(part.socket.rotation.x), MathUtils.degToRad(part.socket.rotation.y), MathUtils.degToRad(part.socket.rotation.z), ); - modelGroup.setRotationFromEuler(offsetRotation); modelGroup.scale.set(part.socket.scale.x, part.socket.scale.y, part.socket.scale.z); } } else { + const skinnedMeshes: Array = []; modelGroup.traverse((child) => { const asSkinnedMesh = child as SkinnedMesh; if (asSkinnedMesh.isSkinnedMesh) { - const skinnedMeshClone = child.clone(true) as SkinnedMesh; - this.remapBoneIndices(skinnedMeshClone); - skinnedMeshClone.castShadow = true; - skinnedMeshClone.receiveShadow = true; - skinnedMeshClone.bind(this.sharedSkeleton!, this.sharedMatrixWorld!); - skinnedMeshClone.children = []; - this.skinnedMeshesParent?.add(skinnedMeshClone); + skinnedMeshes.push(asSkinnedMesh); } }); + for (const skinnedMeshPart of skinnedMeshes) { + this.remapBoneIndices(skinnedMeshPart, sharedSkeleton); + skinnedMeshPart.castShadow = true; + skinnedMeshPart.receiveShadow = true; + skinnedMeshPart.bind(sharedSkeleton, sharedMatrixWorld!); + skinnedMeshPart.children = []; + group.add(skinnedMeshPart); + } } } - return fullBodyGLTF!.gltf.scene as Object3D; + return group; } } diff --git a/packages/3d-web-avatar/src/character/ModelLoader.ts b/packages/3d-web-avatar/src/character/ModelLoader.ts deleted file mode 100644 index 8bc89980..00000000 --- a/packages/3d-web-avatar/src/character/ModelLoader.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { LoadingManager } from "three"; -import { GLTF, GLTFLoader as ThreeGLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; - -class CachedGLTFLoader extends ThreeGLTFLoader { - private blobCache: Map; - - constructor(manager?: LoadingManager) { - super(manager); - this.blobCache = new Map(); - } - - setBlobUrl(originalUrl: string, blobUrl: string) { - this.blobCache.set(originalUrl, blobUrl); - } - - getBlobUrl(originalUrl: string): string | undefined { - return this.blobCache.get(originalUrl); - } - - load( - url: string, - onLoad: (gltf: GLTF) => void, - onProgress?: ((event: ProgressEvent) => void) | undefined, - onError?: ((event: ErrorEvent) => void) | undefined, - ): void { - const blobUrl = this.getBlobUrl(url); - const effectiveUrl = blobUrl || url; - super.load(effectiveUrl, onLoad, onProgress, onError); - } -} - -class LRUCache { - private maxSize: number; - private cache: Map; - - constructor(maxSize: number = 100) { - this.maxSize = maxSize; - this.cache = new Map(); - } - - get(key: K): V | undefined { - const item = this.cache.get(key); - if (item) { - this.cache.delete(key); - this.cache.set(key, item); - } - return item; - } - - set(key: K, value: V): void { - if (this.cache.size >= this.maxSize) { - const oldestKey = this.cache.keys().next().value; - this.cache.delete(oldestKey); - } - this.cache.set(key, value); - } -} - -interface CachedModel { - blob: Blob; -} - -export class ModelLoader { - private static instance: ModelLoader | null = null; - - private readonly loadingManager: LoadingManager; - private readonly gltfLoader: CachedGLTFLoader; - private modelCache: LRUCache; - private ongoingLoads: Map> = new Map(); - - constructor( - maxCacheSize: number = 100, - private debug: boolean = false, - ) { - this.loadingManager = new LoadingManager(); - this.gltfLoader = new CachedGLTFLoader(this.loadingManager); - this.modelCache = new LRUCache(maxCacheSize); - } - - static getInstance(): ModelLoader { - if (!ModelLoader.instance) { - ModelLoader.instance = new ModelLoader(); - } - return ModelLoader.instance; - } - - async load(fileUrl: string): Promise { - const cachedModel = this.modelCache.get(fileUrl); - - if (cachedModel) { - if (this.debug === true) { - console.log(`Loading ${fileUrl.split("/").pop()} from cache`); - } - const blobURL = URL.createObjectURL(cachedModel.blob); - this.gltfLoader.setBlobUrl(fileUrl, blobURL); - return this.loadFromUrl(blobURL); - } else { - if (this.debug === true) { - console.log(`Loading ${fileUrl} from server`); - } - const ongoingLoad = this.ongoingLoads.get(fileUrl); - if (ongoingLoad) return ongoingLoad; - - const loadPromise = fetch(fileUrl) - .then((response) => response.blob()) - .then((blob) => { - this.modelCache.set(fileUrl, { blob }); - const blobURL = URL.createObjectURL(blob); - this.ongoingLoads.delete(fileUrl); - return this.loadFromUrl(blobURL); - }); - - this.ongoingLoads.set(fileUrl, loadPromise); - return loadPromise; - } - } - - private async loadFromUrl(url: string): Promise { - return new Promise((resolve, reject) => { - this.gltfLoader.load( - url, - (object: GLTF) => { - resolve(object); - }, - undefined, - (error) => { - console.error(`Error loading model from ${url}: ${error}`); - reject(error); - }, - ); - }); - } -} diff --git a/packages/3d-web-avatar/src/helpers/MathHelpers.ts b/packages/3d-web-avatar/src/helpers/MathHelpers.ts index 30ccca5c..c4190786 100644 --- a/packages/3d-web-avatar/src/helpers/MathHelpers.ts +++ b/packages/3d-web-avatar/src/helpers/MathHelpers.ts @@ -1,9 +1,3 @@ -import { Quaternion, Vector3, Vector4 } from "three"; - export const round = (n: number, digits: number): number => { return Number(n.toFixed(digits)); }; - -export const ease = (target: number, n: number, factor: number): number => { - return round((target - n) * factor, 5); -}; diff --git a/packages/3d-web-avatar/src/helpers/SkeletonHelpers.ts b/packages/3d-web-avatar/src/helpers/SkeletonHelpers.ts deleted file mode 100644 index 451c36eb..00000000 --- a/packages/3d-web-avatar/src/helpers/SkeletonHelpers.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { Bone, Group, Matrix4, Mesh, Object3D, Skeleton, SkinnedMesh } from "three"; -import { GLTF } from "three/examples/jsm/loaders/GLTFLoader.js"; -import * as SkeletonUtils from "three/examples/jsm/utils/SkeletonUtils.js"; - -type ClonedGLTFParts = { - gltf: GLTF; - sharedSkeleton: Skeleton; - matrixWorld: Matrix4; -}; - -type BoneHierarchyMap = Map; -type DiffResult = { - identical: boolean; - differences: string[]; -}; - -export function cloneModel(model: Group) { - const clone = SkeletonUtils.clone(model); - return clone; -} - -export class SkeletonHelpers { - private debug: boolean = false; - private hierarchies: BoneHierarchyMap[] = []; - private modelNames: string[] = []; - - private extractBoneHierarchy(node: Object3D): BoneHierarchyMap | null { - if (node.type !== "Bone") return null; - const boneMap: BoneHierarchyMap = new Map(); - node.children.forEach((child) => { - const childHierarchy = this.extractBoneHierarchy(child); - if (childHierarchy) boneMap.set(child.name, childHierarchy); - }); - return boneMap; - } - - private areBoneHierarchiesEqual( - a: BoneHierarchyMap, - b: BoneHierarchyMap, - modelNameA: string, - modelNameB: string, - path: string[] = [], - ): DiffResult { - let identical = true; - const differences: string[] = []; - - if (a.size !== b.size) { - differences.push( - `Different number of children at path: ${path.join( - " -> ", - )} in models ${modelNameA} and ${modelNameB}.`, - ); - identical = false; - } - - for (const [key, value] of a) { - if (!b.has(key)) { - differences.push( - `Bone "${key}" was found in model ${modelNameA} but not in model ${modelNameB} at path: ${path.join( - " -> ", - )}.`, - ); - identical = false; - continue; - } - - const newPath = [...path, key]; - const result = this.areBoneHierarchiesEqual( - value, - b.get(key)!, - modelNameA, - modelNameB, - newPath, - ); - - if (!result.identical) { - identical = false; - differences.push(...result.differences); - } - } - - for (const key of b.keys()) { - if (!a.has(key)) { - differences.push( - `Bone "${key}" was found in model ${modelNameB} but not in model ${modelNameA} at path: ${path.join( - " -> ", - )}.`, - ); - identical = false; - } - } - - return { - identical, - differences, - }; - } - - public extractAndStoreBoneHierarchy(node: Object3D, modelName: string) { - const newHierarchy = this.extractBoneHierarchy(node); - - if (!newHierarchy) { - console.log(`No bone hierarchy found in the model: ${modelName}.`); - return; - } - - this.hierarchies.push(newHierarchy); - this.modelNames.push(modelName); - } - - public compareLatestHierarchies() { - if (this.hierarchies.length < 2) return; - - const latestHierarchy = this.hierarchies[this.hierarchies.length - 1]; - const previousHierarchy = this.hierarchies[this.hierarchies.length - 2]; - - const diff = this.areBoneHierarchiesEqual( - previousHierarchy, - latestHierarchy, - this.modelNames[this.modelNames.length - 2], - this.modelNames[this.modelNames.length - 1], - [], - ); - - if (diff.identical) { - if (this.debug) console.log("The skeletons are identical."); - } else { - diff.differences.forEach((difference) => console.log(difference)); - } - } - - public cloneGLTF(gltf: GLTF, modelName: string): ClonedGLTFParts { - const clone: Partial = { - animations: gltf.animations, - scene: cloneModel(gltf.scene) as Group, - }; - - let sharedSkeleton: Skeleton | null = null; - let matrixWorld: Matrix4 | null = null; - - const skinnedMeshes: Record = {}; - - gltf.scene.traverse((node) => { - if (node.type === "SkinnedMesh") { - skinnedMeshes[node.name] = node as SkinnedMesh; - } - }); - - const cloneBones: Record = {}; - const cloneSkinnedMeshes: Record = {}; - - let hierarchyCheck = false; - clone.scene!.traverse((node) => { - if ((node as Mesh).isMesh || (node as SkinnedMesh).isSkinnedMesh) { - node.castShadow = true; - node.receiveShadow = true; - } - if (node.type === "Bone") { - if (hierarchyCheck === false) { - hierarchyCheck = true; - this.extractAndStoreBoneHierarchy(node, modelName); - } - cloneBones[node.name] = node as Bone; - } - - if (node.type === "SkinnedMesh") { - cloneSkinnedMeshes[node.name] = node as SkinnedMesh; - } - }); - - for (const name in skinnedMeshes) { - const skinnedMesh = skinnedMeshes[name]; - const skeleton = skinnedMesh.skeleton; - const cloneSkinnedMesh = cloneSkinnedMeshes[name]; - - const orderedCloneBones = []; - - for (let i = 0; i < skeleton.bones.length; ++i) { - const cloneBone = cloneBones[skeleton.bones[i].name]; - orderedCloneBones.push(cloneBone); - } - - if (sharedSkeleton === null) { - sharedSkeleton = new Skeleton(orderedCloneBones, skeleton.boneInverses); - } - - if (matrixWorld === null) { - matrixWorld = cloneSkinnedMesh.matrixWorld; - } - - cloneSkinnedMesh.bind(sharedSkeleton, matrixWorld); - } - - return { - gltf: clone as GLTF, - sharedSkeleton: sharedSkeleton as Skeleton, - matrixWorld: matrixWorld as Matrix4, - }; - } -} diff --git a/packages/3d-web-avatar/src/helpers/cloneSkinnedMesh.ts b/packages/3d-web-avatar/src/helpers/cloneSkinnedMesh.ts new file mode 100644 index 00000000..c11cc81b --- /dev/null +++ b/packages/3d-web-avatar/src/helpers/cloneSkinnedMesh.ts @@ -0,0 +1,6 @@ +import { Group } from "three"; +import * as SkeletonUtils from "three/examples/jsm/utils/SkeletonUtils.js"; + +export function cloneSkinnedMesh(model: Group) { + return SkeletonUtils.clone(model); +} diff --git a/packages/3d-web-avatar/src/index.ts b/packages/3d-web-avatar/src/index.ts index e22ad622..7240f489 100644 --- a/packages/3d-web-avatar/src/index.ts +++ b/packages/3d-web-avatar/src/index.ts @@ -1,7 +1,6 @@ export { MMLCharacter } from "./character/MMLCharacter"; -export { cloneModel } from "./helpers/SkeletonHelpers"; +export { cloneSkinnedMesh } from "./helpers/cloneSkinnedMesh"; export { TimeManagerInterface } from "./character/types"; -export { ModelLoader } from "./character/ModelLoader"; export { type LoadingErrors, type MMLCharacterDescriptionPart, diff --git a/packages/3d-web-client-core/package.json b/packages/3d-web-client-core/package.json index bcab8bb1..78e1bc3e 100644 --- a/packages/3d-web-client-core/package.json +++ b/packages/3d-web-client-core/package.json @@ -18,18 +18,20 @@ "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" }, "dependencies": { + "@mml-io/model-loader": "0.14.0", "@mml-io/3d-web-avatar": "^0.15.0", + "@monogrid/gainmap-js": "^3.0.5", "@tweakpane/core": "2.0.3", "@tweakpane/plugin-essentials": "0.2.1", - "mml-web": "0.13.0", - "postprocessing": "6.34.1", - "three-mesh-bvh": "0.7.1", + "mml-web": "0.14.0", + "postprocessing": "6.35.3", + "three-mesh-bvh": "0.7.4", "tweakpane": "4.0.3" }, "peerDependencies": { - "three": ">= 0.153.0" + "three": ">= 0.163.0" }, "devDependencies": { - "@types/three": "0.153.0" + "@types/three": "0.163.0" } } diff --git a/packages/3d-web-client-core/src/camera/CameraManager.ts b/packages/3d-web-client-core/src/camera/CameraManager.ts index e0e281fe..c67fea93 100644 --- a/packages/3d-web-client-core/src/camera/CameraManager.ts +++ b/packages/3d-web-client-core/src/camera/CameraManager.ts @@ -91,11 +91,9 @@ export class CameraManager { private onTouchStart(evt: TouchEvent): void { Array.from(evt.touches).forEach((touch) => { - if (!VirtualJoystick.isTouchOnJoystick(touch)) { - this.dragging = true; - this.lastTouchX = touch.clientX; - this.lastTouchY = touch.clientY; - } + this.dragging = true; + this.lastTouchX = touch.clientX; + this.lastTouchY = touch.clientY; }); } @@ -105,7 +103,8 @@ export class CameraManager { } evt.preventDefault(); - const touch = Array.from(evt.touches).find((t) => !VirtualJoystick.isTouchOnJoystick(t)); + // TODO - handle multi-touch correctly + const touch = Array.from(evt.touches).find((t) => true); if (touch) { const dx = touch.clientX - this.lastTouchX; const dy = touch.clientY - this.lastTouchY; @@ -122,9 +121,8 @@ export class CameraManager { private onTouchEnd(evt: TouchEvent): void { if (this.dragging) { - const touchEnded = Array.from(evt.changedTouches).some( - (t) => !VirtualJoystick.isTouchOnJoystick(t), - ); + // TODO - handle multi-touch correctly + const touchEnded = Array.from(evt.changedTouches).some((t) => true); if (touchEnded) { this.dragging = false; } diff --git a/packages/3d-web-client-core/src/character/Character.ts b/packages/3d-web-client-core/src/character/Character.ts index 18ed95ff..c8b86e0d 100644 --- a/packages/3d-web-client-core/src/character/Character.ts +++ b/packages/3d-web-client-core/src/character/Character.ts @@ -32,56 +32,58 @@ export type CharacterDescription = { } ); +export type CharacterConfig = { + username: string; + characterDescription: CharacterDescription; + animationConfig: AnimationConfig; + characterModelLoader: CharacterModelLoader; + characterId: number; + modelLoadedCallback: () => void; + cameraManager: CameraManager; + composer: Composer; + isLocal: boolean; +}; + export class Character extends Group { private model: CharacterModel | null = null; public color: Color = new Color(); public tooltip: CharacterTooltip; public speakingIndicator: CharacterSpeakingIndicator | null = null; - constructor( - private username: string, - private characterDescription: CharacterDescription, - private readonly animationConfig: AnimationConfig, - private readonly characterModelLoader: CharacterModelLoader, - private readonly characterId: number, - private readonly modelLoadedCallback: () => void, - private readonly cameraManager: CameraManager, - private readonly composer: Composer, - private readonly isLocal: boolean, - ) { + constructor(private config: CharacterConfig) { super(); this.tooltip = new CharacterTooltip(); - this.tooltip.setText(this.username, isLocal); + this.tooltip.setText(this.config.username, this.config.isLocal); this.add(this.tooltip); this.load().then(() => { - this.modelLoadedCallback(); + this.config.modelLoadedCallback(); }); } updateCharacter(username: string, characterDescription: CharacterDescription) { - this.username = username; - this.characterDescription = characterDescription; + this.config.username = username; + this.config.characterDescription = characterDescription; this.load(); - this.tooltip.setText(username, this.isLocal); + this.tooltip.setText(username, this.config.isLocal); } - private async load(callback?: () => void): Promise { + private async load(): Promise { const previousModel = this.model; - this.model = new CharacterModel( - this.characterDescription, - this.animationConfig, - this.characterModelLoader, - this.cameraManager, - this.characterId, - this.isLocal, - ); + this.model = new CharacterModel({ + characterDescription: this.config.characterDescription, + animationConfig: this.config.animationConfig, + characterModelLoader: this.config.characterModelLoader, + cameraManager: this.config.cameraManager, + characterId: this.config.characterId, + isLocal: this.config.isLocal, + }); await this.model.init(); if (previousModel && previousModel.mesh) { this.remove(previousModel.mesh!); } this.add(this.model.mesh!); if (this.speakingIndicator === null) { - this.speakingIndicator = new CharacterSpeakingIndicator(this.composer.postPostScene); + this.speakingIndicator = new CharacterSpeakingIndicator(this.config.composer.postPostScene); } } @@ -92,14 +94,14 @@ export class Character extends Group { public update(time: number, deltaTime: number) { if (!this.model) return; if (this.tooltip) { - this.tooltip.update(this.cameraManager.camera); + this.tooltip.update(this.config.cameraManager.camera); } if (this.speakingIndicator) { this.speakingIndicator.setTime(time); if (this.model.mesh && this.model.headBone) { this.speakingIndicator.setBillboarding( this.model.headBone?.getWorldPosition(new Vector3()), - this.cameraManager.camera, + this.config.cameraManager.camera, ); } } diff --git a/packages/3d-web-client-core/src/character/CharacterManager.ts b/packages/3d-web-client-core/src/character/CharacterManager.ts index 2ccda34b..53c1d13a 100644 --- a/packages/3d-web-client-core/src/character/CharacterManager.ts +++ b/packages/3d-web-client-core/src/character/CharacterManager.ts @@ -5,6 +5,7 @@ import { CameraManager } from "../camera/CameraManager"; import { CollisionsManager } from "../collisions/CollisionsManager"; import { ease } from "../helpers/math-helpers"; import { KeyInputManager } from "../input/KeyInputManager"; +import { VirtualJoystick } from "../input/VirtualJoystick"; import { Composer } from "../rendering/composer"; import { TimeManager } from "../time/TimeManager"; @@ -15,6 +16,23 @@ import { LocalController } from "./LocalController"; import { RemoteController } from "./RemoteController"; import { encodeCharacterAndCamera } from "./url-position"; +export type CharacterManagerConfig = { + composer: Composer; + characterModelLoader: CharacterModelLoader; + collisionsManager: CollisionsManager; + cameraManager: CameraManager; + timeManager: TimeManager; + keyInputManager: KeyInputManager; + virtualJoystick?: VirtualJoystick; + remoteUserStates: Map; + sendUpdate: (update: CharacterState) => void; + animationConfig: AnimationConfig; + characterResolve: (clientId: number) => { + username: string; + characterDescription: CharacterDescription; + }; +}; + export class CharacterManager { private updateLocationHash = true; @@ -33,21 +51,7 @@ export class CharacterManager { public readonly group: Group; - constructor( - private readonly composer: Composer, - private readonly characterModelLoader: CharacterModelLoader, - private readonly collisionsManager: CollisionsManager, - private readonly cameraManager: CameraManager, - private readonly timeManager: TimeManager, - private readonly keyInputManager: KeyInputManager, - private readonly clientStates: Map, - private readonly sendUpdate: (update: CharacterState) => void, - private readonly animationConfig: AnimationConfig, - private readonly characterResolve: (clientId: number) => { - username: string; - characterDescription: CharacterDescription; - }, - ) { + constructor(private config: CharacterManagerConfig) { this.group = new Group(); } @@ -58,21 +62,21 @@ export class CharacterManager { spawnPosition: Vector3 = new Vector3(), spawnRotation: Euler = new Euler(), ) { - const character = new Character( + const character = new Character({ username, characterDescription, - this.animationConfig, - this.characterModelLoader, - id, - () => { + animationConfig: this.config.animationConfig, + characterModelLoader: this.config.characterModelLoader, + characterId: id, + modelLoadedCallback: () => { // character loaded callback }, - this.cameraManager, - this.composer, - true, - ); + cameraManager: this.config.cameraManager, + composer: this.config.composer, + isLocal: true, + }); const quaternion = new Quaternion().setFromEuler(character.rotation); - this.sendUpdate({ + this.config.sendUpdate({ id: id, position: { x: spawnPosition.x, @@ -84,14 +88,15 @@ export class CharacterManager { }); this.localClientId = id; this.localCharacter = character; - this.localController = new LocalController( - this.localCharacter, - this.localClientId, - this.collisionsManager, - this.keyInputManager, - this.cameraManager, - this.timeManager, - ); + this.localController = new LocalController({ + character: this.localCharacter, + id: this.localClientId, + collisionsManager: this.config.collisionsManager, + keyInputManager: this.config.keyInputManager, + virtualJoystick: this.config.virtualJoystick, + cameraManager: this.config.cameraManager, + timeManager: this.config.timeManager, + }); this.localCharacter.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z); this.localCharacter.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z); this.group.add(character); @@ -105,24 +110,24 @@ export class CharacterManager { spawnPosition: Vector3 = new Vector3(), spawnRotation: Euler = new Euler(), ) { - const character = new Character( + const character = new Character({ username, characterDescription, - this.animationConfig, - this.characterModelLoader, - id, - () => { + animationConfig: this.config.animationConfig, + characterModelLoader: this.config.characterModelLoader, + characterId: id, + modelLoadedCallback: () => { // character loaded callback }, - this.cameraManager, - this.composer, - false, - ); + cameraManager: this.config.cameraManager, + composer: this.config.composer, + isLocal: false, + }); this.remoteCharacters.set(id, character); - const remoteController = new RemoteController(character, id); - remoteController.character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z); - remoteController.character.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z); + character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z); + character.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z); + const remoteController = new RemoteController({ character, id }); this.remoteCharacterControllers.set(id, remoteController); this.group.add(character); } @@ -157,7 +162,7 @@ export class CharacterManager { } public respawnIfPresent(id: number) { - const characterInfo = this.characterResolve(id); + const characterInfo = this.config.characterResolve(id); if (this.localCharacter && this.localClientId == id) { this.localCharacter.updateCharacter( @@ -174,7 +179,7 @@ export class CharacterManager { public update() { if (this.localCharacter) { - this.localCharacter.update(this.timeManager.time, this.timeManager.deltaTime); + this.localCharacter.update(this.config.timeManager.time, this.config.timeManager.deltaTime); if (this.speakingCharacters.has(this.localClientId)) { this.localCharacter.speakingIndicator?.setSpeaking( this.speakingCharacters.get(this.localClientId)!, @@ -182,8 +187,8 @@ export class CharacterManager { } this.localController.update(); - if (this.timeManager.frame % 2 === 0) { - this.sendUpdate(this.localController.networkState); + if (this.config.timeManager.frame % 2 === 0) { + this.config.sendUpdate(this.localController.networkState); } const targetOffset = new Vector3(); @@ -191,9 +196,9 @@ export class CharacterManager { .add(this.headTargetOffset) .applyQuaternion(this.localCharacter.quaternion) .add(this.localCharacter.position); - this.cameraManager.setTarget(targetOffset); + this.config.cameraManager.setTarget(targetOffset); - for (const [id, update] of this.clientStates) { + for (const [id, update] of this.config.remoteUserStates) { if (this.remoteCharacters.has(id) && this.speakingCharacters.has(id)) { const character = this.remoteCharacters.get(id); character?.speakingIndicator?.setSpeaking(this.speakingCharacters.get(id)!); @@ -201,7 +206,7 @@ export class CharacterManager { const { position } = update; if (!this.remoteCharacters.has(id) && this.localCharacterSpawned === true) { - const characterInfo = this.characterResolve(id); + const characterInfo = this.config.characterResolve(id); this.spawnRemoteCharacter( id, characterInfo.username, @@ -212,12 +217,16 @@ export class CharacterManager { const characterController = this.remoteCharacterControllers.get(id); if (characterController) { - characterController.update(update, this.timeManager.time, this.timeManager.deltaTime); + characterController.update( + update, + this.config.timeManager.time, + this.config.timeManager.deltaTime, + ); } } for (const [id, character] of this.remoteCharacters) { - if (!this.clientStates.has(id)) { + if (!this.config.remoteUserStates.has(id)) { character.speakingIndicator?.dispose(); this.group.remove(character); this.remoteCharacters.delete(id); @@ -225,10 +234,10 @@ export class CharacterManager { } } - if (this.updateLocationHash && this.timeManager.frame % 60 === 0) { + if (this.updateLocationHash && this.config.timeManager.frame % 60 === 0) { window.location.hash = encodeCharacterAndCamera( this.localCharacter, - this.cameraManager.camera, + this.config.cameraManager.camera, ); } } diff --git a/packages/3d-web-client-core/src/character/CharacterMaterial.ts b/packages/3d-web-client-core/src/character/CharacterMaterial.ts index 63f08ce9..08643511 100644 --- a/packages/3d-web-client-core/src/character/CharacterMaterial.ts +++ b/packages/3d-web-client-core/src/character/CharacterMaterial.ts @@ -12,6 +12,14 @@ import { characterValues } from "../tweakpane/blades/characterFolder"; type TUniform = { value: TValue }; +export type CharacterMaterialConfig = { + isLocal: boolean; + cameraManager: CameraManager; + characterId: number; + originalMaterial: MeshStandardMaterial; + colorOverride?: Color; +}; + export class CharacterMaterial extends MeshStandardMaterial { private uniforms: Record = { discardAll: { value: 1 }, @@ -22,21 +30,15 @@ export class CharacterMaterial extends MeshStandardMaterial { private targetAlpha: number = 1; private currentAlpha: number = 1; - constructor( - private isLocal: boolean, - private cameraManager: CameraManager, - private characterId: number, - private originalMaterial: MeshStandardMaterial, - private colorOverride?: Color, - ) { + constructor(private config: CharacterMaterialConfig) { super(); - this.copy(this.originalMaterial); + this.copy(this.config.originalMaterial); this.generateColorCube(); - this.color = this.colorOverride || this.colorsCube216[this.characterId]; + this.color = this.config.colorOverride || this.colorsCube216[this.config.characterId]; this.envMapIntensity = characterValues.envMapIntensity; this.transparent = true; - this.side = this.originalMaterial.side; + this.side = this.config.originalMaterial.side; this.onBeforeCompile = (shader) => { this.uniforms = UniformsUtils.clone(shader.uniforms); @@ -117,16 +119,16 @@ export class CharacterMaterial extends MeshStandardMaterial { } public update() { - if (this.isLocal) { - this.targetAlpha = this.cameraManager.targetDistance < 0.4 ? 0.0 : 1.0; + if (this.config.isLocal) { + this.targetAlpha = this.config.cameraManager.targetDistance < 0.4 ? 0.0 : 1.0; this.currentAlpha += ease(this.targetAlpha, this.currentAlpha, 0.07); if (this.currentAlpha > 0.999) { this.currentAlpha = 1; - this.cameraManager.minPolarAngle = Math.PI * 0.25; + this.config.cameraManager.minPolarAngle = Math.PI * 0.25; } if (this.currentAlpha < 0.001) { this.currentAlpha = 0; - this.cameraManager.minPolarAngle = Math.PI * 0.35; + this.config.cameraManager.minPolarAngle = Math.PI * 0.35; } this.uniforms.discardAll.value = this.currentAlpha === 0 ? 1 : 0; if (this.currentAlpha !== this.opacity) { diff --git a/packages/3d-web-client-core/src/character/CharacterModel.ts b/packages/3d-web-client-core/src/character/CharacterModel.ts index 900d8765..ef6d645e 100644 --- a/packages/3d-web-client-core/src/character/CharacterModel.ts +++ b/packages/3d-web-client-core/src/character/CharacterModel.ts @@ -1,9 +1,9 @@ import { MMLCharacter, type MMLCharacterDescription, - ModelLoader, parseMMLDescription, } from "@mml-io/3d-web-avatar"; +import { ModelLoader } from "@mml-io/model-loader"; import { AnimationAction, AnimationClip, @@ -23,7 +23,18 @@ import { CharacterMaterial } from "./CharacterMaterial"; import { CharacterModelLoader } from "./CharacterModelLoader"; import { AnimationState } from "./CharacterState"; +export type CharacterModelConfig = { + characterDescription: CharacterDescription; + animationConfig: AnimationConfig; + characterModelLoader: CharacterModelLoader; + cameraManager: CameraManager; + characterId: number; + isLocal: boolean; +}; + export class CharacterModel { + public static ModelLoader: ModelLoader = new ModelLoader(); + public mesh: Object3D | null = null; public headBone: Bone | null = null; @@ -35,27 +46,26 @@ export class CharacterModel { public mmlCharacterDescription: MMLCharacterDescription; - constructor( - private readonly characterDescription: CharacterDescription, - private readonly animationConfig: AnimationConfig, - private characterModelLoader: CharacterModelLoader, - private readonly cameraManager: CameraManager, - private readonly characterId: number, - private readonly isLocal: boolean, - ) {} + constructor(private config: CharacterModelConfig) {} public async init(): Promise { await this.loadMainMesh(); - await this.setAnimationFromFile(this.animationConfig.idleAnimationFileUrl, AnimationState.idle); await this.setAnimationFromFile( - this.animationConfig.jogAnimationFileUrl, + this.config.animationConfig.idleAnimationFileUrl, + AnimationState.idle, + ); + await this.setAnimationFromFile( + this.config.animationConfig.jogAnimationFileUrl, AnimationState.walking, ); await this.setAnimationFromFile( - this.animationConfig.sprintAnimationFileUrl, + this.config.animationConfig.sprintAnimationFileUrl, AnimationState.running, ); - await this.setAnimationFromFile(this.animationConfig.airAnimationFileUrl, AnimationState.air); + await this.setAnimationFromFile( + this.config.animationConfig.airAnimationFileUrl, + AnimationState.air, + ); this.applyCustomMaterials(); } @@ -70,19 +80,19 @@ export class CharacterModel { } else { const material = originalMaterial.name === "body_replaceable_color" - ? new CharacterMaterial( - this.isLocal, - this.cameraManager, - this.characterId, + ? new CharacterMaterial({ + isLocal: this.config.isLocal, + cameraManager: this.config.cameraManager, + characterId: this.config.characterId, originalMaterial, - ) - : new CharacterMaterial( - this.isLocal, - this.cameraManager, - this.characterId, + }) + : new CharacterMaterial({ + isLocal: this.config.isLocal, + cameraManager: this.config.cameraManager, + characterId: this.config.characterId, originalMaterial, - originalMaterial.color, - ); + colorOverride: originalMaterial.color, + }); this.materials.set(originalMaterial.name, material); asMesh.material = material; } @@ -113,7 +123,7 @@ export class CharacterModel { ): Promise { if (mmlCharacterDescription.base?.url.length === 0) { throw new Error( - "ERROR: An MML Character Description was provided but it's not a valid string, or a valid URL", + "ERROR: An MML Character Description was provided, but it's not a valid string, or a valid URL", ); } @@ -122,32 +132,34 @@ export class CharacterModel { const characterBase = mmlCharacterDescription.base?.url || null; if (characterBase) { this.mmlCharacterDescription = mmlCharacterDescription; - const mmlCharacter = new MMLCharacter(new ModelLoader()); + const mmlCharacter = new MMLCharacter(CharacterModel.ModelLoader); mergedCharacter = await mmlCharacter.mergeBodyParts( characterBase, mmlCharacterDescription.parts, ); if (mergedCharacter) { - return mergedCharacter.children[0].children[0]; + return mergedCharacter; } } } } private async loadCharacterFromDescription(): Promise { - if (this.characterDescription.meshFileUrl) { + if (this.config.characterDescription.meshFileUrl) { return ( - (await this.characterModelLoader.load(this.characterDescription.meshFileUrl, "model")) || - null + (await this.config.characterModelLoader.load( + this.config.characterDescription.meshFileUrl, + "model", + )) || null ); } let mmlCharacterSource: string; - if (this.characterDescription.mmlCharacterUrl) { - const res = await fetch(this.characterDescription.mmlCharacterUrl); + if (this.config.characterDescription.mmlCharacterUrl) { + const res = await fetch(this.config.characterDescription.mmlCharacterUrl); mmlCharacterSource = await res.text(); - } else if (this.characterDescription.mmlCharacterString) { - mmlCharacterSource = this.characterDescription.mmlCharacterString; + } else if (this.config.characterDescription.mmlCharacterString) { + mmlCharacterSource = this.config.characterDescription.mmlCharacterString; } else { throw new Error( "ERROR: No Character Description was provided. Specify one of meshFileUrl, mmlCharacterUrl or mmlCharacterString", @@ -197,7 +209,7 @@ export class CharacterModel { animationType: AnimationState, ): Promise { return new Promise(async (resolve, reject) => { - const animation = await this.characterModelLoader.load(animationFileUrl, "animation"); + const animation = await this.config.characterModelLoader.load(animationFileUrl, "animation"); const cleanAnimation = this.cleanAnimationClips(this.mesh!, animation as AnimationClip); if (typeof animation !== "undefined" && cleanAnimation instanceof AnimationClip) { this.animations[animationType] = this.animationMixer!.clipAction(cleanAnimation); diff --git a/packages/3d-web-client-core/src/character/CharacterModelLoader.ts b/packages/3d-web-client-core/src/character/CharacterModelLoader.ts index fe6c4224..9c35f738 100644 --- a/packages/3d-web-client-core/src/character/CharacterModelLoader.ts +++ b/packages/3d-web-client-core/src/character/CharacterModelLoader.ts @@ -1,42 +1,6 @@ -import { AnimationClip, LoadingManager, Object3D } from "three"; -import { GLTF, GLTFLoader as ThreeGLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; - -class CachedGLTFLoader extends ThreeGLTFLoader { - private blobCache: Map; - - constructor( - manager?: LoadingManager, - private debug: boolean = false, - ) { - super(manager); - this.blobCache = new Map(); - } - - setBlobUrl(originalUrl: string, blobUrl: string) { - this.blobCache.set(originalUrl, blobUrl); - } - - getBlobUrl(originalUrl: string): string | undefined { - return this.blobCache.get(originalUrl); - } - - load( - url: string, - onLoad: (gltf: GLTF) => void, - onProgress?: ((event: ProgressEvent) => void) | undefined, - onError?: ((event: ErrorEvent) => void) | undefined, - ): void { - const blobUrl = this.getBlobUrl(url); - if (blobUrl) { - if (this.debug === true) { - console.log(`Loading cached ${url.split("/").pop()}`); - } - super.load(blobUrl, onLoad, onProgress, onError); - } else { - super.load(url, onLoad, onProgress, onError); - } - } -} +import { ModelLoader, ModelLoadResult } from "@mml-io/model-loader"; +import { AnimationClip, Object3D } from "three"; +import { GLTF } from "three/examples/jsm/loaders/GLTFLoader.js"; class LRUCache { private maxSize: number; @@ -71,8 +35,7 @@ interface CachedModel { } export class CharacterModelLoader { - private readonly loadingManager: LoadingManager; - private readonly gltfLoader: CachedGLTFLoader; + private readonly modelLoader: ModelLoader = new ModelLoader(); private modelCache: LRUCache; private ongoingLoads: Map> = new Map(); @@ -80,8 +43,6 @@ export class CharacterModelLoader { maxCacheSize: number = 100, private debug: boolean = false, ) { - this.loadingManager = new LoadingManager(); - this.gltfLoader = new CachedGLTFLoader(this.loadingManager, this.debug); this.modelCache = new LRUCache(maxCacheSize); } @@ -94,8 +55,6 @@ export class CharacterModelLoader { const cachedModel = this.modelCache.get(fileUrl); if (cachedModel) { - const blobURL = URL.createObjectURL(cachedModel.blob); - this.gltfLoader.setBlobUrl(fileUrl, blobURL); return this.loadFromUrl(fileUrl, fileType, cachedModel.originalExtension); } else { if (this.debug === true) { @@ -132,26 +91,22 @@ export class CharacterModelLoader { extension: string, ): Promise { if (["gltf", "glb"].includes(extension)) { - return new Promise((resolve, reject) => { - this.gltfLoader.load( + return new Promise(async (resolve, reject) => { + const modelLoadResult: ModelLoadResult = await this.modelLoader.load( url, - (object: GLTF) => { - if (fileType === "model") { - resolve(object.scene as Object3D); - } else if (fileType === "animation") { - resolve(object.animations[0] as AnimationClip); - } else { - const error = `Trying to load unknown ${fileType} type of element from file ${url}`; - console.error(error); - reject(error); - } - }, - undefined, - (error) => { - console.error(`Error loading GL(B|TF) from ${url}: ${error}`); - reject(error); + (loaded: number, total: number) => { + // no-op }, ); + if (fileType === "model") { + resolve(modelLoadResult.group as Object3D); + } else if (fileType === "animation") { + resolve(modelLoadResult.animations[0] as AnimationClip); + } else { + const error = `Trying to load unknown ${fileType} type of element from file ${url}`; + console.error(error); + reject(error); + } }); } else { console.error(`Error: can't recognize ${url} extension: ${extension}`); diff --git a/packages/3d-web-client-core/src/character/CharacterTooltip.ts b/packages/3d-web-client-core/src/character/CharacterTooltip.ts index 52072874..2057b9ff 100644 --- a/packages/3d-web-client-core/src/character/CharacterTooltip.ts +++ b/packages/3d-web-client-core/src/character/CharacterTooltip.ts @@ -5,7 +5,6 @@ import { LinearFilter, Mesh, MeshBasicMaterial, - Object3D, PlaneGeometry, } from "three"; @@ -29,27 +28,39 @@ const defaultLabelCastShadows = true; const tooltipGeometry = new PlaneGeometry(1, 1, 1, 1); +export type CharacterTooltipConfig = { + alignment: LabelAlignment; + width: number; + height: number; + fontSize: number; + padding: number; + color: Color; + fontColor: Color; + castShadows: boolean; +}; + export class CharacterTooltip extends Mesh { private tooltipMaterial: MeshBasicMaterial; private visibleOpacity: number = 0.85; private targetOpacity: number = 0; private fadingSpeed: number = 0.02; private secondsToFadeOut: number = 10; + private config: CharacterTooltipConfig; - private props = { - content: "", - alignment: defaultLabelAlignment, - width: defaultLabelWidth, - height: defaultLabelHeight, - fontSize: defaultLabelFontSize, - padding: defaultLabelPadding, - color: defaultLabelColor, - fontColor: defaultFontColor, - castShadows: defaultLabelCastShadows, - }; - - constructor() { + constructor(configArg?: Partial) { super(tooltipGeometry); + this.config = { + alignment: defaultLabelAlignment, + width: defaultLabelWidth, + height: defaultLabelHeight, + fontSize: defaultLabelFontSize, + padding: defaultLabelPadding, + color: defaultLabelColor, + fontColor: defaultFontColor, + castShadows: defaultLabelCastShadows, + ...configArg, + }; + this.tooltipMaterial = new MeshBasicMaterial({ map: null, transparent: true, @@ -70,21 +81,21 @@ export class CharacterTooltip extends Mesh { } const { texture, width, height } = THREECanvasTextTexture(content, { bold: true, - fontSize: this.props.fontSize * fontScale, - paddingPx: this.props.padding, + fontSize: this.config.fontSize * fontScale, + paddingPx: this.config.padding, textColorRGB255A1: { - r: this.props.fontColor.r * 255, - g: this.props.fontColor.g * 255, - b: this.props.fontColor.b * 255, + r: this.config.fontColor.r * 255, + g: this.config.fontColor.g * 255, + b: this.config.fontColor.b * 255, a: 1.0, }, backgroundColorRGB255A1: { - r: this.props.color.r * 255, - g: this.props.color.g * 255, - b: this.props.color.b * 255, + r: this.config.color.r * 255, + g: this.config.color.g * 255, + b: this.config.color.b * 255, a: 1.0, }, - alignment: this.props.alignment, + alignment: this.config.alignment, }); this.tooltipMaterial.map = texture; diff --git a/packages/3d-web-client-core/src/character/LocalController.ts b/packages/3d-web-client-core/src/character/LocalController.ts index dc4956a3..647cf0ea 100644 --- a/packages/3d-web-client-core/src/character/LocalController.ts +++ b/packages/3d-web-client-core/src/character/LocalController.ts @@ -3,6 +3,7 @@ import { Euler, Line3, Matrix4, Quaternion, Ray, Raycaster, Vector3 } from "thre import { CameraManager } from "../camera/CameraManager"; import { CollisionMeshState, CollisionsManager } from "../collisions/CollisionsManager"; import { KeyInputManager } from "../input/KeyInputManager"; +import { VirtualJoystick } from "../input/VirtualJoystick"; import { TimeManager } from "../time/TimeManager"; import { Character } from "./Character"; @@ -19,6 +20,16 @@ const baseControl = 200; const collisionDetectionSteps = 15; const minimumSurfaceAngle = 0.9; +export type LocalControllerConfig = { + id: number; + character: Character; + collisionsManager: CollisionsManager; + keyInputManager: KeyInputManager; + virtualJoystick?: VirtualJoystick; + cameraManager: CameraManager; + timeManager: TimeManager; +}; + export class LocalController { public capsuleInfo = { radius: 0.4, @@ -81,16 +92,9 @@ export class LocalController { public networkState: CharacterState; - constructor( - private readonly character: Character, - private readonly id: number, - private readonly collisionsManager: CollisionsManager, - private readonly keyInputManager: KeyInputManager, - private readonly cameraManager: CameraManager, - private readonly timeManager: TimeManager, - ) { + constructor(private config: LocalControllerConfig) { this.networkState = { - id: this.id, + id: this.config.id, position: { x: 0, y: 0, z: 0 }, rotation: { quaternionY: 0, quaternionW: 1 }, state: AnimationState.idle, @@ -98,21 +102,25 @@ export class LocalController { } private updateControllerState(): void { - this.forward = this.keyInputManager.forward; - this.backward = this.keyInputManager.backward; - this.left = this.keyInputManager.left; - this.right = this.keyInputManager.right; - this.run = this.keyInputManager.run; - this.jump = this.keyInputManager.jump; - this.anyDirection = this.keyInputManager.anyDirection; - this.conflictingDirections = this.keyInputManager.conflictingDirection; + this.forward = this.config.keyInputManager.forward || this.config.virtualJoystick?.up || false; + this.backward = + this.config.keyInputManager.backward || this.config.virtualJoystick?.down || false; + this.left = this.config.keyInputManager.left || this.config.virtualJoystick?.left || false; + this.right = this.config.keyInputManager.right || this.config.virtualJoystick?.right || false; + this.run = this.config.keyInputManager.run; + this.jump = this.config.keyInputManager.jump; + this.anyDirection = + this.config.keyInputManager.anyDirection || + this.config.virtualJoystick?.hasDirection || + false; + this.conflictingDirections = this.config.keyInputManager.conflictingDirection; } public update(): void { this.updateControllerState(); - this.rayCaster.set(this.character.position, this.vectorDown); - const firstRaycastHit = this.collisionsManager.raycastFirst(this.rayCaster.ray); + this.rayCaster.set(this.config.character.position, this.vectorDown); + const firstRaycastHit = this.config.collisionsManager.raycastFirst(this.rayCaster.ray); if (firstRaycastHit !== null) { this.currentHeight = firstRaycastHit[0]; this.currentSurfaceAngle.copy(firstRaycastHit[1]); @@ -120,9 +128,9 @@ export class LocalController { if (this.anyDirection || !this.characterOnGround) { const targetAnimation = this.getTargetAnimation(); - this.character.updateAnimation(targetAnimation); + this.config.character.updateAnimation(targetAnimation); } else { - this.character.updateAnimation(AnimationState.idle); + this.config.character.updateAnimation(AnimationState.idle); } if (this.anyDirection) { @@ -131,20 +139,20 @@ export class LocalController { for (let i = 0; i < collisionDetectionSteps; i++) { this.updatePosition( - this.timeManager.deltaTime, - this.timeManager.deltaTime / collisionDetectionSteps, + this.config.timeManager.deltaTime, + this.config.timeManager.deltaTime / collisionDetectionSteps, i, ); } - if (this.character.position.y < 0) { + if (this.config.character.position.y < 0) { this.resetPosition(); } this.updateNetworkState(); } private getTargetAnimation(): AnimationState { - if (!this.character) return AnimationState.idle; + if (!this.config.character) return AnimationState.idle; const jumpHeight = this.characterVelocity.y > 0 ? 0.2 : 1.8; if (this.currentHeight > jumpHeight && !this.characterOnGround) { @@ -178,25 +186,25 @@ export class LocalController { } private updateAzimuthalAngle(): void { - const camToModelDistance = this.cameraManager.camera.position.distanceTo( - this.character.position, + const camToModelDistance = this.config.cameraManager.camera.position.distanceTo( + this.config.character.position, ); const isCameraFirstPerson = camToModelDistance < 2; if (isCameraFirstPerson) { const cameraForward = this.tempVector .set(0, 0, 1) - .applyQuaternion(this.cameraManager.camera.quaternion); + .applyQuaternion(this.config.cameraManager.camera.quaternion); this.azimuthalAngle = Math.atan2(cameraForward.x, cameraForward.z); } else { this.azimuthalAngle = Math.atan2( - this.cameraManager.camera.position.x - this.character.position.x, - this.cameraManager.camera.position.z - this.character.position.z, + this.config.cameraManager.camera.position.x - this.config.character.position.x, + this.config.cameraManager.camera.position.z - this.config.character.position.z, ); } } private computeAngularDifference(rotationQuaternion: Quaternion): number { - return 2 * Math.acos(Math.abs(this.character.quaternion.dot(rotationQuaternion))); + return 2 * Math.acos(Math.abs(this.config.character.quaternion.dot(rotationQuaternion))); } private updateRotation(): void { @@ -209,8 +217,8 @@ export class LocalController { const angularDifference = this.computeAngularDifference(rotationQuaternion); const desiredTime = 0.07; const angularSpeed = angularDifference / desiredTime; - const frameRotation = angularSpeed * this.timeManager.deltaTime; - this.character.quaternion.rotateTowards(rotationQuaternion, frameRotation); + const frameRotation = angularSpeed * this.config.timeManager.deltaTime; + this.config.character.quaternion.rotateTowards(rotationQuaternion, frameRotation); } private applyControls(deltaTime: number) { @@ -288,35 +296,37 @@ export class LocalController { acceleration.add(controlAcceleration); this.characterVelocity.addScaledVector(acceleration, deltaTime); - this.character.position.addScaledVector(this.characterVelocity, deltaTime); + this.config.character.position.addScaledVector(this.characterVelocity, deltaTime); } private updatePosition(deltaTime: number, stepDeltaTime: number, iter: number): void { this.applyControls(stepDeltaTime); if (iter === 0) { - const lastMovement = this.getMovementFromSurfaces(this.character.position, deltaTime); + const lastMovement = this.getMovementFromSurfaces(this.config.character.position, deltaTime); if (lastMovement) { - this.character.position.add(lastMovement.position); - const asQuaternion = this.tempQuaternion.setFromEuler(this.character.rotation); + this.config.character.position.add(lastMovement.position); + const asQuaternion = this.tempQuaternion.setFromEuler(this.config.character.rotation); const lastMovementEuler = this.tempEuler.setFromQuaternion(lastMovement.rotation); lastMovementEuler.x = 0; lastMovementEuler.z = 0; lastMovement.rotation.setFromEuler(lastMovementEuler); asQuaternion.multiply(lastMovement.rotation); - this.character.rotation.setFromQuaternion(asQuaternion); + this.config.character.rotation.setFromQuaternion(asQuaternion); } } - this.character.updateMatrixWorld(); + this.config.character.updateMatrixWorld(); const avatarSegment = this.tempSegment; avatarSegment.copy(this.capsuleInfo.segment!); - avatarSegment.start.applyMatrix4(this.character.matrixWorld).applyMatrix4(this.tempMatrix); - avatarSegment.end.applyMatrix4(this.character.matrixWorld).applyMatrix4(this.tempMatrix); + avatarSegment.start + .applyMatrix4(this.config.character.matrixWorld) + .applyMatrix4(this.tempMatrix); + avatarSegment.end.applyMatrix4(this.config.character.matrixWorld).applyMatrix4(this.tempMatrix); const positionBeforeCollisions = this.tempVector.copy(avatarSegment.start); - this.collisionsManager.applyColliders(avatarSegment, this.capsuleInfo.radius!); - this.character.position.copy(avatarSegment.start); + this.config.collisionsManager.applyColliders(avatarSegment, this.capsuleInfo.radius!); + this.config.character.position.copy(avatarSegment.start); const deltaCollisionPosition = avatarSegment.start.sub(positionBeforeCollisions); this.characterOnGround = deltaCollisionPosition.y > 0; @@ -403,7 +413,7 @@ export class LocalController { // Raycast down from the new position to see if there is a surface below the user which will be tracked in the next frame const ray = this.surfaceTempRay.set(newPosition, downVector); - const hit = this.collisionsManager.raycastFirst(ray); + const hit = this.config.collisionsManager.raycastFirst(ray); if (hit && hit[0] < 0.8) { // There is a surface below the user const currentCollisionMeshState = hit[2]; @@ -424,22 +434,22 @@ export class LocalController { } private updateNetworkState(): void { - const characterQuaternion = this.character.getWorldQuaternion(this.tempQuaternion); + const characterQuaternion = this.config.character.getWorldQuaternion(this.tempQuaternion); this.networkState = { - id: this.id, + id: this.config.id, position: { - x: this.character.position.x, - y: this.character.position.y, - z: this.character.position.z, + x: this.config.character.position.x, + y: this.config.character.position.y, + z: this.config.character.position.z, }, rotation: { quaternionY: characterQuaternion.y, quaternionW: characterQuaternion.w }, - state: this.character.getCurrentAnimation(), + state: this.config.character.getCurrentAnimation(), }; } private resetPosition(): void { this.characterVelocity.y = 0; - this.character.position.y = 3; + this.config.character.position.y = 3; this.characterOnGround = false; } } diff --git a/packages/3d-web-client-core/src/character/RemoteController.ts b/packages/3d-web-client-core/src/character/RemoteController.ts index 4bf366dd..c1f05272 100644 --- a/packages/3d-web-client-core/src/character/RemoteController.ts +++ b/packages/3d-web-client-core/src/character/RemoteController.ts @@ -3,37 +3,50 @@ import { Quaternion, Vector3 } from "three"; import { Character } from "./Character"; import { AnimationState, CharacterState } from "./CharacterState"; +export type RemoteControllerConfig = { + id: number; + character: Character; +}; + +const tempQuaternion = new Quaternion(); + export class RemoteController { public currentAnimation: AnimationState = AnimationState.idle; public networkState: CharacterState; - constructor( - public readonly character: Character, - public readonly id: number, - ) { + constructor(private config: RemoteControllerConfig) { this.networkState = { - id: this.id, - position: { x: 0, y: 0, z: 0 }, - rotation: { quaternionY: 0, quaternionW: 1 }, + id: this.config.id, + position: { + x: this.config.character.position.x, + y: this.config.character.position.y, + z: this.config.character.position.z, + }, + rotation: { + quaternionY: tempQuaternion.setFromEuler(this.config.character.rotation).y, + quaternionW: 1, + }, state: this.currentAnimation as AnimationState, }; } public update(clientUpdate: CharacterState, time: number, deltaTime: number): void { - if (!this.character) return; + if (!this.config.character) { + return; + } this.updateFromNetwork(clientUpdate); - this.character.update(time, deltaTime); + this.config.character.update(time, deltaTime); } private updateFromNetwork(clientUpdate: CharacterState): void { const { position, rotation, state } = clientUpdate; - this.character.position.lerp(new Vector3(position.x, position.y, position.z), 0.15); + this.config.character.position.lerp(new Vector3(position.x, position.y, position.z), 0.15); const rotationQuaternion = new Quaternion(0, rotation.quaternionY, 0, rotation.quaternionW); - this.character.quaternion.slerp(rotationQuaternion, 0.6); + this.config.character.quaternion.slerp(rotationQuaternion, 0.6); if (state !== this.currentAnimation) { this.currentAnimation = state; - this.character.updateAnimation(state); + this.config.character.updateAnimation(state); } } } diff --git a/example/web-client/src/Room.ts b/packages/3d-web-client-core/src/ground-plane/GroundPlane.ts similarity index 51% rename from example/web-client/src/Room.ts rename to packages/3d-web-client-core/src/ground-plane/GroundPlane.ts index 43385989..a89ed819 100644 --- a/example/web-client/src/Room.ts +++ b/packages/3d-web-client-core/src/ground-plane/GroundPlane.ts @@ -1,20 +1,28 @@ import { + CanvasTexture, CircleGeometry, FrontSide, Group, LinearMipMapLinearFilter, - LoadingManager, Mesh, MeshStandardMaterial, NearestFilter, RepeatWrapping, Texture, - TextureLoader, } from "three"; -import checkerTextureUrl from "../../assets/textures/checker.png"; +// Create a simple 2x2 checkerboard image +const canvas = document.createElement("canvas"); +canvas.width = 2; +canvas.height = 2; +const ctx = canvas.getContext("2d")!; +ctx.fillStyle = "#C0C0C0"; +ctx.fillRect(0, 0, 2, 2); +ctx.fillStyle = "#808080"; +ctx.fillRect(0, 0, 1, 1); +ctx.fillRect(1, 1, 1, 1); -export class Room extends Group { +export class GroundPlane extends Group { private readonly floorSize = 210; private readonly floorTexture: Texture | null = null; private readonly floorGeometry = new CircleGeometry(this.floorSize, this.floorSize); @@ -35,14 +43,13 @@ export class Room extends Group { this.floorMesh.rotation.x = Math.PI * -0.5; this.add(this.floorMesh); - this.floorTexture = new TextureLoader(new LoadingManager()).load(checkerTextureUrl, () => { - this.floorTexture!.wrapS = RepeatWrapping; - this.floorTexture!.wrapT = RepeatWrapping; - this.floorTexture!.magFilter = NearestFilter; - this.floorTexture!.minFilter = LinearMipMapLinearFilter; - this.floorTexture!.repeat.set(this.floorSize / 1.5, this.floorSize / 1.5); - this.floorMaterial.map = this.floorTexture; - this.floorMaterial.needsUpdate = true; - }); + this.floorTexture = new CanvasTexture(canvas); + this.floorTexture!.wrapS = RepeatWrapping; + this.floorTexture!.wrapT = RepeatWrapping; + this.floorTexture!.magFilter = NearestFilter; + this.floorTexture!.minFilter = LinearMipMapLinearFilter; + this.floorTexture!.repeat.set(this.floorSize / 1.5, this.floorSize / 1.5); + this.floorMaterial.map = this.floorTexture; + this.floorMaterial.needsUpdate = true; } } diff --git a/packages/3d-web-client-core/src/index.ts b/packages/3d-web-client-core/src/index.ts index 7b9c4dd9..4dc0eb2c 100644 --- a/packages/3d-web-client-core/src/index.ts +++ b/packages/3d-web-client-core/src/index.ts @@ -6,9 +6,12 @@ export * from "./helpers/math-helpers"; export { CharacterModelLoader } from "./character/CharacterModelLoader"; export { CharacterState, AnimationState } from "./character/CharacterState"; export { KeyInputManager } from "./input/KeyInputManager"; +export { VirtualJoystick } from "./input/VirtualJoystick"; export { MMLCompositionScene } from "./mml/MMLCompositionScene"; export { TweakPane } from "./tweakpane/TweakPane"; export { Composer } from "./rendering/composer"; export { TimeManager } from "./time/TimeManager"; export { CollisionsManager } from "./collisions/CollisionsManager"; export { Sun } from "./sun/Sun"; +export { GroundPlane } from "./ground-plane/GroundPlane"; +export { LoadingScreen } from "./loading-screen/LoadingScreen"; diff --git a/packages/3d-web-client-core/src/input/KeyInputManager.ts b/packages/3d-web-client-core/src/input/KeyInputManager.ts index d4ca0909..ef27d00c 100644 --- a/packages/3d-web-client-core/src/input/KeyInputManager.ts +++ b/packages/3d-web-client-core/src/input/KeyInputManager.ts @@ -13,19 +13,11 @@ enum Key { export class KeyInputManager { private keys = new Map(); private eventHandlerCollection = new EventHandlerCollection(); - private directionJoystick: VirtualJoystick | null = null; constructor(private shouldCaptureKeyPress: () => boolean = () => true) { this.eventHandlerCollection.add(document, "keydown", this.onKeyDown.bind(this)); this.eventHandlerCollection.add(document, "keyup", this.onKeyUp.bind(this)); this.eventHandlerCollection.add(window, "blur", this.handleUnfocus.bind(this)); - this.directionJoystick = new VirtualJoystick({ - radius: 70, - inner_radius: 20, - x: 70, - y: 0, - mouse_support: false, - }); } private handleUnfocus(_event: FocusEvent): void { @@ -56,26 +48,23 @@ export class KeyInputManager { } public isMovementKeyPressed(): boolean { - return ( - [Key.W, Key.A, Key.S, Key.D].some((key) => this.isKeyPressed(key)) || - this.directionJoystick!.hasDirection - ); + return [Key.W, Key.A, Key.S, Key.D].some((key) => this.isKeyPressed(key)); } get forward(): boolean { - return this.isKeyPressed(Key.W) || this.directionJoystick!.up; + return this.isKeyPressed(Key.W); } get backward(): boolean { - return this.isKeyPressed(Key.S) || this.directionJoystick!.down; + return this.isKeyPressed(Key.S); } get left(): boolean { - return this.isKeyPressed(Key.A) || this.directionJoystick!.left; + return this.isKeyPressed(Key.A); } get right(): boolean { - return this.isKeyPressed(Key.D) || this.directionJoystick!.right; + return this.isKeyPressed(Key.D); } get run(): boolean { diff --git a/packages/3d-web-client-core/src/input/VirtualJoystick.ts b/packages/3d-web-client-core/src/input/VirtualJoystick.ts index 2a566359..2644c7e6 100644 --- a/packages/3d-web-client-core/src/input/VirtualJoystick.ts +++ b/packages/3d-web-client-core/src/input/VirtualJoystick.ts @@ -11,8 +11,6 @@ interface JoyStickAttributes { } export class VirtualJoystick { - public static JOYSTICK_DIV: HTMLDivElement | null = null; - private radius: number; private inner_radius: number; private anchor: "left" | "right"; @@ -32,7 +30,10 @@ export class VirtualJoystick { public down: boolean = false; public hasDirection: boolean = false; - constructor(attrs: JoyStickAttributes) { + constructor( + private holderElement: HTMLElement, + attrs: JoyStickAttributes, + ) { this.radius = attrs.radius || 50; this.inner_radius = attrs.inner_radius || this.radius / 2; this.anchor = attrs.anchor || "left"; @@ -42,7 +43,24 @@ export class VirtualJoystick { this.height = attrs.height || this.radius * 2 + this.inner_radius * 2; this.mouse_support = this.checkTouch() || attrs.mouse_support === true; - this.initializeJoystick(); + this.div = document.createElement("div"); + const divStyle = this.div.style; + divStyle.display = this.checkTouch() || this.mouse_support ? "visible" : "none"; + divStyle.position = "fixed"; + if (this.anchor === "left") { + divStyle.left = `${this.x}px`; + } else { + divStyle.right = `${this.x}px`; + } + divStyle.bottom = `${this.y}px`; + divStyle.width = `${this.width}px`; + divStyle.height = `${this.height}px`; + divStyle.zIndex = "10000"; + divStyle.overflow = "hidden"; + this.holderElement.appendChild(this.div); + + this.setupBaseAndControl(); + this.bindEvents(); } public static checkForTouch(): boolean { @@ -54,47 +72,10 @@ export class VirtualJoystick { } } - public static isTouchOnJoystick(touch: Touch): boolean { - if (!VirtualJoystick.JOYSTICK_DIV) { - return false; - } - const divRect = VirtualJoystick.JOYSTICK_DIV.getBoundingClientRect(); - return ( - touch.clientX >= divRect.left && - touch.clientX <= divRect.right && - touch.clientY >= divRect.top && - touch.clientY <= divRect.bottom - ); - } - private checkTouch() { return VirtualJoystick.checkForTouch(); } - private initializeJoystick(): void { - if (!VirtualJoystick.JOYSTICK_DIV) { - this.div = document.createElement("div"); - const divStyle = this.div.style; - divStyle.display = this.checkTouch() || this.mouse_support ? "visible" : "none"; - divStyle.position = "fixed"; - if (this.anchor === "left") { - divStyle.left = `${this.x}px`; - } else { - divStyle.right = `${this.x}px`; - } - divStyle.bottom = `${this.y}px`; - divStyle.width = `${this.width}px`; - divStyle.height = `${this.height}px`; - divStyle.zIndex = "10000"; - divStyle.overflow = "hidden"; - document.body.appendChild(this.div); - VirtualJoystick.JOYSTICK_DIV = this.div; - } - - this.setupBaseAndControl(); - this.bindEvents(); - } - private setupBaseAndControl(): void { this.base = document.createElement("span"); let divStyle = this.base.style; @@ -138,6 +119,7 @@ export class VirtualJoystick { private handleTouchStart(evt: TouchEvent): void { evt.preventDefault(); + evt.stopPropagation(); if (evt.touches) { const touch = evt.touches[0]; this.updateControlAndDirection(touch); @@ -146,6 +128,7 @@ export class VirtualJoystick { private handleTouchMove(evt: TouchEvent): void { evt.preventDefault(); + evt.stopPropagation(); if (evt.touches.length > 0) { const touch = evt.touches[0]; this.updateControlAndDirection(touch); @@ -154,12 +137,14 @@ export class VirtualJoystick { private handleMouseDown(evt: MouseEvent): void { evt.preventDefault(); + evt.stopPropagation(); this.updateControlAndDirection(evt); } private handleMouseMove(evt: MouseEvent): void { if (evt.buttons === 1) { evt.preventDefault(); + evt.stopPropagation(); this.updateControlAndDirection(evt); } } diff --git a/example/web-client/src/LoadingScreen.ts b/packages/3d-web-client-core/src/loading-screen/LoadingScreen.ts similarity index 99% rename from example/web-client/src/LoadingScreen.ts rename to packages/3d-web-client-core/src/loading-screen/LoadingScreen.ts index b4eee0fd..9233d2f9 100644 --- a/example/web-client/src/LoadingScreen.ts +++ b/packages/3d-web-client-core/src/loading-screen/LoadingScreen.ts @@ -53,6 +53,7 @@ export class LoadingScreen { this.loadingBannerText.style.color = "white"; this.loadingBannerText.style.fontSize = "80px"; this.loadingBannerText.style.fontWeight = "bold"; + this.loadingBannerText.style.fontFamily = "sans-serif"; this.loadingBannerText.style.alignItems = "center"; this.loadingBannerText.style.justifyContent = "center"; this.element.append(this.loadingBannerText); diff --git a/packages/3d-web-client-core/src/mml/MMLCompositionScene.ts b/packages/3d-web-client-core/src/mml/MMLCompositionScene.ts index 8ee11ec5..bfc8fcb5 100644 --- a/packages/3d-web-client-core/src/mml/MMLCompositionScene.ts +++ b/packages/3d-web-client-core/src/mml/MMLCompositionScene.ts @@ -15,6 +15,16 @@ import { AudioListener, Group, Object3D, PerspectiveCamera, Scene, WebGLRenderer import { CollisionsManager } from "../collisions/CollisionsManager"; +type MMLCompositionSceneConfig = { + targetElement: HTMLElement; + renderer: WebGLRenderer; + scene: Scene; + camera: PerspectiveCamera; + audioListener: AudioListener; + collisionsManager: CollisionsManager; + getUserPositionAndRotation: () => PositionAndRotation; +}; + export class MMLCompositionScene { public group: Group; @@ -26,43 +36,35 @@ export class MMLCompositionScene { private readonly clickTrigger: MMLClickTrigger; private readonly loadingProgressManager: LoadingProgressManager; - constructor( - targetElement: HTMLElement, - private renderer: WebGLRenderer, - private scene: Scene, - private camera: PerspectiveCamera, - private audioListener: AudioListener, - private collisionsManager: CollisionsManager, - private getUserPositionAndRotation: () => PositionAndRotation, - ) { + constructor(private config: MMLCompositionSceneConfig) { this.group = new Group(); - this.promptManager = PromptManager.init(targetElement); + this.promptManager = PromptManager.init(this.config.targetElement); const { interactionListener, interactionManager } = InteractionManager.init( - targetElement, - this.camera, - this.scene, + this.config.targetElement, + this.config.camera, + this.config.scene, ); this.interactionManager = interactionManager; this.interactionListener = interactionListener; this.loadingProgressManager = new LoadingProgressManager(); this.mmlScene = { - getAudioListener: () => this.audioListener, - getRenderer: () => this.renderer, - getThreeScene: () => this.scene, + getAudioListener: () => this.config.audioListener, + getRenderer: () => this.config.renderer, + getThreeScene: () => this.config.scene, getRootContainer: () => this.group, - getCamera: () => this.camera, + getCamera: () => this.config.camera, addCollider: (object: Object3D, mElement: MElement) => { - this.collisionsManager.addMeshesGroup(object as Group, mElement); + this.config.collisionsManager.addMeshesGroup(object as Group, mElement); }, updateCollider: (object: Object3D) => { - this.collisionsManager.updateMeshesGroup(object as Group); + this.config.collisionsManager.updateMeshesGroup(object as Group); }, removeCollider: (object: Object3D) => { - this.collisionsManager.removeMeshesGroup(object as Group); + this.config.collisionsManager.removeMeshesGroup(object as Group); }, - getUserPositionAndRotation: this.getUserPositionAndRotation, + getUserPositionAndRotation: this.config.getUserPositionAndRotation, addInteraction: (interaction: Interaction) => { this.interactionListener.addInteraction(interaction); }, @@ -89,7 +91,7 @@ export class MMLCompositionScene { }, }; - this.clickTrigger = MMLClickTrigger.init(targetElement, this.mmlScene as IMMLScene); + this.clickTrigger = MMLClickTrigger.init(this.config.targetElement, this.mmlScene as IMMLScene); } onChatMessage(message: string) { diff --git a/packages/3d-web-client-core/src/rendering/composer.ts b/packages/3d-web-client-core/src/rendering/composer.ts index 7448636c..3792f3eb 100644 --- a/packages/3d-web-client-core/src/rendering/composer.ts +++ b/packages/3d-web-client-core/src/rendering/composer.ts @@ -1,3 +1,4 @@ +import { HDRJPGLoader } from "@monogrid/gainmap-js"; import { EffectComposer, RenderPass, @@ -30,6 +31,7 @@ import { ToneMapping, Vector2, WebGLRenderer, + EquirectangularReflectionMapping, } from "three"; import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js"; @@ -295,6 +297,29 @@ export class Composer { this.renderer.render(this.postPostScene, this.camera); } + public useHDRJPG(url: string, fromFile: boolean = false): void { + const pmremGenerator = new PMREMGenerator(this.renderer); + const hdrJpg = new HDRJPGLoader(this.renderer).load(url, () => { + const hdrJpgEquirectangularMap = hdrJpg.renderTarget.texture; + + hdrJpgEquirectangularMap.mapping = EquirectangularReflectionMapping; + hdrJpgEquirectangularMap.needsUpdate = true; + + const envMap = pmremGenerator!.fromEquirectangular(hdrJpgEquirectangularMap).texture; + if (envMap) { + envMap.colorSpace = LinearSRGBColorSpace; + envMap.needsUpdate = true; + this.scene.background = envMap; + this.scene.backgroundIntensity = rendererValues.bgIntensity; + this.isEnvHDRI = true; + hdrJpgEquirectangularMap.dispose(); + pmremGenerator!.dispose(); + } + + hdrJpg.dispose(); + }); + } + public useHDRI(url: string, fromFile: boolean = false): void { if ((this.isEnvHDRI && fromFile === false) || !this.renderer) return; const pmremGenerator = new PMREMGenerator(this.renderer); @@ -323,16 +348,23 @@ export class Composer { if (!this.renderer) return; const fileInput = document.createElement("input"); fileInput.type = "file"; - fileInput.accept = ".hdr"; + fileInput.accept = ".hdr,.jpg"; fileInput.addEventListener("change", () => { const file = fileInput.files?.[0]; if (!file) { console.log("no file"); return; } + const extension = file.name.split(".").pop(); const fileURL = URL.createObjectURL(file); if (fileURL) { - this.useHDRI(fileURL, true); + if (extension === "hdr") { + this.useHDRI(fileURL, true); + } else if (extension === "jpg") { + this.useHDRJPG(fileURL); + } else { + console.error(`Unrecognized extension for HDR file ${file.name}`); + } URL.revokeObjectURL(fileURL); document.body.removeChild(fileInput); } diff --git a/packages/3d-web-client-core/src/sun/Sun.ts b/packages/3d-web-client-core/src/sun/Sun.ts index a02b15e1..2020b872 100644 --- a/packages/3d-web-client-core/src/sun/Sun.ts +++ b/packages/3d-web-client-core/src/sun/Sun.ts @@ -31,7 +31,7 @@ export class Sun extends Group { if (this.debug === true) { this.camHelper = new CameraHelper(this.shadowCamera); } - this.directionalLight = new DirectionalLight(0xffffff, 0.5); + this.directionalLight = new DirectionalLight(0xffffff); this.directionalLight.intensity = sunValues.sunIntensity; this.directionalLight.shadow.normalBias = 0.01; this.directionalLight.shadow.radius = 0.02; diff --git a/packages/3d-web-client-core/src/tweakpane/TweakPane.ts b/packages/3d-web-client-core/src/tweakpane/TweakPane.ts index 4272e1d1..139a904a 100644 --- a/packages/3d-web-client-core/src/tweakpane/TweakPane.ts +++ b/packages/3d-web-client-core/src/tweakpane/TweakPane.ts @@ -45,14 +45,24 @@ export class TweakPane { public guiVisible: boolean = false; constructor( + private holderElement: HTMLElement, private renderer: WebGLRenderer, private scene: Scene, private composer: EffectComposer, ) { - const appWrapper = document.getElementById("app")!; const tweakPaneWrapper = document.createElement("div"); - tweakPaneWrapper.id = "tweakpane-panel"; - appWrapper.appendChild(tweakPaneWrapper); + tweakPaneWrapper.style.position = "fixed"; + tweakPaneWrapper.style.width = "400px"; + tweakPaneWrapper.style.height = "100%"; + tweakPaneWrapper.style.top = "0px"; + tweakPaneWrapper.style.right = "calc(-50vw)"; + tweakPaneWrapper.style.zIndex = "99"; + tweakPaneWrapper.style.overflow = "auto"; + tweakPaneWrapper.style.backgroundColor = "rgba(0, 0, 0, 0.66)"; + tweakPaneWrapper.style.paddingLeft = "5px"; + tweakPaneWrapper.style.boxShadow = "-7px 0px 12px rgba(0, 0, 0, 0.5)"; + tweakPaneWrapper.style.transition = "right cubic-bezier(0.83, 0, 0.17, 1) 0.7s"; + holderElement.appendChild(tweakPaneWrapper); this.gui = new Pane({ container: tweakPaneWrapper! }); this.gui.registerPlugin(EssentialsPlugin); diff --git a/packages/3d-web-client-core/src/tweakpane/blades/environmentFolder.ts b/packages/3d-web-client-core/src/tweakpane/blades/environmentFolder.ts index 10b0556a..d448cc44 100644 --- a/packages/3d-web-client-core/src/tweakpane/blades/environmentFolder.ts +++ b/packages/3d-web-client-core/src/tweakpane/blades/environmentFolder.ts @@ -8,7 +8,7 @@ export const sunValues = { sunAzimuthalAngle: 214.5, sunPolarAngle: -41.5, }, - sunIntensity: 1, + sunIntensity: 2, sunColor: { r: 1.0, g: 1.0, b: 1.0 }, }; @@ -22,7 +22,7 @@ const sunOptions = { export const envValues = { ambientLight: { - ambientLightIntensity: 0.05, + ambientLightIntensity: 0.1, ambientLightColor: { r: 1, g: 1, b: 1 }, }, fog: { diff --git a/packages/3d-web-client-core/src/tweakpane/blades/ssaoFolder.ts b/packages/3d-web-client-core/src/tweakpane/blades/ssaoFolder.ts index f7f3c340..e4cc646f 100644 --- a/packages/3d-web-client-core/src/tweakpane/blades/ssaoFolder.ts +++ b/packages/3d-web-client-core/src/tweakpane/blades/ssaoFolder.ts @@ -247,6 +247,10 @@ export class SSAOFolder { case "enabled": if (e.value === true) { composer.addPass(n8aopass, this.postProcessingSSAOIndex + 2); + composer.passes[this.postProcessingSSAOIndex + 2].setSize( + window.innerWidth, + window.innerHeight, + ); } else { composer.removePass(n8aopass); } diff --git a/packages/3d-web-experience-client/build.ts b/packages/3d-web-experience-client/build.ts new file mode 100644 index 00000000..120c09e4 --- /dev/null +++ b/packages/3d-web-experience-client/build.ts @@ -0,0 +1,3 @@ +import { handleLibraryBuild } from "../../utils/build-library"; + +handleLibraryBuild(); diff --git a/example/local-multi-web-client/package.json b/packages/3d-web-experience-client/package.json similarity index 66% rename from example/local-multi-web-client/package.json rename to packages/3d-web-experience-client/package.json index 45189043..8d48f296 100644 --- a/example/local-multi-web-client/package.json +++ b/packages/3d-web-experience-client/package.json @@ -1,13 +1,17 @@ { - "name": "@example/local-multi-web-client", - "private": true, + "name": "@mml-io/3d-web-experience-client", "version": "0.15.0", + "publishConfig": { + "access": "public" + }, + "main": "./build/index.js", + "types": "./build/index.d.ts", + "type": "module", "files": [ "/build" ], - "type": "module", "scripts": { - "build": "rimraf ./build && tsx ./build.ts --build", + "build": "tsx ./build.ts --build", "iterate": "tsx ./build.ts --watch", "type-check": "tsc --noEmit", "lint": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --max-warnings 0", @@ -18,10 +22,10 @@ "@mml-io/3d-web-text-chat": "^0.15.0", "@mml-io/3d-web-user-networking": "^0.15.0", "@mml-io/3d-web-voice-chat": "^0.15.0", - "mml-web-runner": "0.13.0", - "three": "0.153.0" + "three": "0.163.0" }, "devDependencies": { - "@types/three": "0.153.0" + "@types/node": "^20.12.7", + "@types/three": "0.163.0" } } diff --git a/example/web-client/src/index.ts b/packages/3d-web-experience-client/src/Networked3dWebExperienceClient.ts similarity index 79% rename from example/web-client/src/index.ts rename to packages/3d-web-experience-client/src/Networked3dWebExperienceClient.ts index 7fd3dfd9..b88114d3 100644 --- a/example/web-client/src/index.ts +++ b/packages/3d-web-experience-client/src/Networked3dWebExperienceClient.ts @@ -13,6 +13,9 @@ import { MMLCompositionScene, TimeManager, TweakPane, + GroundPlane, + LoadingScreen, + VirtualJoystick, } from "@mml-io/3d-web-client-core"; import { ChatNetworkingClient, FromClientChatMessage, TextChatUI } from "@mml-io/3d-web-text-chat"; import { @@ -30,87 +33,87 @@ import { } from "mml-web"; import { AudioListener, Euler, Scene, Vector3 } from "three"; -import hdrUrl from "../../assets/hdr/puresky_2k.hdr"; -import airAnimationFileUrl from "../../assets/models/anim_air.glb"; -import idleAnimationFileUrl from "../../assets/models/anim_idle.glb"; -import jogAnimationFileUrl from "../../assets/models/anim_jog.glb"; -import sprintAnimationFileUrl from "../../assets/models/anim_run.glb"; - -import { LoadingScreen } from "./LoadingScreen"; -import { Room } from "./Room"; - -const animationConfig: AnimationConfig = { - airAnimationFileUrl, - idleAnimationFileUrl, - jogAnimationFileUrl, - sprintAnimationFileUrl, +export type Networked3dWebExperienceClientConfig = { + sessionToken: string; + chatNetworkAddress: string; + userNetworkAddress: string; + mmlDocumentAddresses: string[]; + animationConfig: AnimationConfig; + hdrJpgUrl: string; }; -const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; -const host = window.location.host; -const userNetworkAddress = `${protocol}//${host}/network`; - -export class App { +export class Networked3dWebExperienceClient { private element: HTMLDivElement; - private composer: Composer; - private tweakPane: TweakPane; private scene = new Scene(); + private composer: Composer; + private tweakPane: TweakPane; private audioListener = new AudioListener(); + + private cameraManager: CameraManager; + + private collisionsManager = new CollisionsManager(this.scene); + private characterModelLoader = new CharacterModelLoader(); + private characterManager: CharacterManager; + private timeManager = new TimeManager(); + private keyInputManager = new KeyInputManager(); - private characterManager: CharacterManager; - private cameraManager: CameraManager; - private collisionsManager = new CollisionsManager(this.scene); + private virtualJoystick: VirtualJoystick; + private mmlCompositionScene: MMLCompositionScene; + + private clientId: number | null = null; private networkClient: UserNetworkingClient; private remoteUserStates = new Map(); - // A dictionary holding information about my own user and all remote users private userProfiles = new Map(); private networkChat: ChatNetworkingClient | null = null; private textChatUI: TextChatUI | null = null; private voiceChatManager: VoiceChatManager | null = null; - private readonly latestCharacterObject = { characterState: null as null | CharacterState, }; - private clientId: number | null = null; private initialLoadCompleted = false; private loadingProgressManager = new LoadingProgressManager(); private loadingScreen: LoadingScreen; - private appWrapper = document.getElementById("app"); - private initialNetworkLoadRef = {}; + constructor( + private holderElement: HTMLElement, + private config: Networked3dWebExperienceClientConfig, + ) { + this.element = document.createElement("div"); + this.element.style.position = "absolute"; + this.element.style.width = "100%"; + this.element.style.height = "100%"; + this.holderElement.appendChild(this.element); - constructor(private sessionToken: string) { document.addEventListener("mousedown", () => { if (this.audioListener.context.state === "suspended") { this.audioListener.context.resume(); } }); - this.element = document.createElement("div"); - this.element.style.position = "absolute"; - this.element.style.width = "100%"; - this.element.style.height = "100%"; - if (this.appWrapper) { - this.appWrapper.appendChild(this.element); - } else { - document.body.appendChild(this.element); - } - this.cameraManager = new CameraManager(this.element, this.collisionsManager); this.cameraManager.camera.add(this.audioListener); + this.virtualJoystick = new VirtualJoystick(this.element, { + radius: 70, + inner_radius: 20, + x: 70, + y: 0, + mouse_support: false, + }); + this.composer = new Composer(this.scene, this.cameraManager.camera, true); - this.composer.useHDRI(hdrUrl); + this.composer.useHDRJPG(this.config.hdrJpgUrl); this.element.appendChild(this.composer.renderer.domElement); this.tweakPane = new TweakPane( + this.element, this.composer.renderer, this.scene, this.composer.effectComposer, @@ -122,10 +125,11 @@ export class App { }); resizeObserver.observe(this.element); - this.loadingProgressManager.addLoadingAsset(this.initialNetworkLoadRef, "network", "network"); + const initialNetworkLoadRef = {}; + this.loadingProgressManager.addLoadingAsset(initialNetworkLoadRef, "network", "network"); this.networkClient = new UserNetworkingClient({ - url: userNetworkAddress, - sessionToken: this.sessionToken, + url: this.config.userNetworkAddress, + sessionToken: this.config.sessionToken, websocketFactory: (url: string) => new WebSocket(url), statusUpdateCallback: (status: WebsocketStatus) => { if (status === WebsocketStatus.Disconnected || status === WebsocketStatus.Reconnecting) { @@ -142,7 +146,7 @@ export class App { // Already loaded - respawn the character this.spawnCharacter(); } else { - this.loadingProgressManager.completedLoadingAsset(this.initialNetworkLoadRef); + this.loadingProgressManager.completedLoadingAsset(initialNetworkLoadRef); } }, clientUpdate: ( @@ -167,28 +171,29 @@ export class App { }, }); - this.characterManager = new CharacterManager( - this.composer, - this.characterModelLoader, - this.collisionsManager, - this.cameraManager, - this.timeManager, - this.keyInputManager, - this.remoteUserStates, - (characterState: CharacterState) => { + this.characterManager = new CharacterManager({ + composer: this.composer, + characterModelLoader: this.characterModelLoader, + collisionsManager: this.collisionsManager, + cameraManager: this.cameraManager, + timeManager: this.timeManager, + keyInputManager: this.keyInputManager, + virtualJoystick: this.virtualJoystick, + remoteUserStates: this.remoteUserStates, + sendUpdate: (characterState: CharacterState) => { this.latestCharacterObject.characterState = characterState; this.networkClient.sendUpdate(characterState); }, - animationConfig, - (characterId: number) => { + animationConfig: this.config.animationConfig, + characterResolve: (characterId: number) => { return this.resolveCharacterData(characterId); }, - ); + }); this.scene.add(this.characterManager.group); - const room = new Room(); - this.collisionsManager.addMeshesGroup(room); - this.scene.add(room); + const groundPlane = new GroundPlane(); + this.collisionsManager.addMeshesGroup(groundPlane); + this.scene.add(groundPlane); this.setupMMLScene(); @@ -211,6 +216,19 @@ export class App { this.loadingProgressManager.setInitialLoad(true); } + static createFullscreenHolder(): HTMLDivElement { + document.body.style.margin = "0"; + document.body.style.overflow = "hidden"; + + const holder = document.createElement("div"); + holder.style.position = "absolute"; + holder.style.width = "100%"; + holder.style.height = "100%"; + holder.style.overflow = "hidden"; + document.body.appendChild(holder); + return holder; + } + private resolveCharacterData(clientId: number): { username: string; characterDescription: CharacterDescription; @@ -245,6 +263,7 @@ export class App { if (this.voiceChatManager === null) { this.voiceChatManager = new VoiceChatManager( + this.element, this.clientId, this.remoteUserStates, this.latestCharacterObject, @@ -262,14 +281,18 @@ export class App { } if (this.textChatUI === null) { - this.textChatUI = new TextChatUI(user.username, this.sendChatMessageToServer.bind(this)); + this.textChatUI = new TextChatUI( + this.element, + user.username, + this.sendChatMessageToServer.bind(this), + ); this.textChatUI.init(); } if (this.networkChat === null) { this.networkChat = new ChatNetworkingClient({ - url: `${protocol}//${host}/chat-network`, - sessionToken: this.sessionToken, + url: this.config.chatNetworkAddress, + sessionToken: this.config.sessionToken, websocketFactory: (url: string) => new WebSocket(`${url}?id=${this.clientId}`), statusUpdateCallback: (status: WebsocketStatus) => { if (status === WebsocketStatus.Disconnected || status === WebsocketStatus.Reconnecting) { @@ -342,22 +365,21 @@ export class App { private setupMMLScene() { registerCustomElementsToWindow(window); - this.mmlCompositionScene = new MMLCompositionScene( - this.element, - this.composer.renderer, - this.scene, - this.cameraManager.camera, - this.audioListener, - this.collisionsManager, - () => { + this.mmlCompositionScene = new MMLCompositionScene({ + targetElement: this.element, + renderer: this.composer.renderer, + scene: this.scene, + camera: this.cameraManager.camera, + audioListener: this.audioListener, + collisionsManager: this.collisionsManager, + getUserPositionAndRotation: () => { return this.characterManager.getLocalCharacterPositionAndRotation(); }, - ); + }); this.scene.add(this.mmlCompositionScene.group); setGlobalMMLScene(this.mmlCompositionScene.mmlScene as IMMLScene); - const documentAddresses = [`${protocol}//${host}/mml-documents/example-mml.html`]; - for (const address of documentAddresses) { + for (const address of this.config.mmlDocumentAddresses) { const frameElement = document.createElement("m-frame"); frameElement.setAttribute("src", address); document.body.appendChild(frameElement); @@ -371,6 +393,3 @@ export class App { mmlProgressManager.setInitialLoad(true); } } - -const app = new App((window as any).SESSION_TOKEN); -app.update(); diff --git a/packages/3d-web-experience-client/src/index.ts b/packages/3d-web-experience-client/src/index.ts new file mode 100644 index 00000000..2ccbc41e --- /dev/null +++ b/packages/3d-web-experience-client/src/index.ts @@ -0,0 +1 @@ +export * from "./Networked3dWebExperienceClient"; diff --git a/packages/3d-web-experience-client/tsconfig.json b/packages/3d-web-experience-client/tsconfig.json new file mode 100644 index 00000000..e2abbe6a --- /dev/null +++ b/packages/3d-web-experience-client/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "noImplicitAny": true, + "module": "esnext", + "target": "ES6", + "jsx": "react-jsx", + "lib": ["es2020", "dom"], + "esModuleInterop": true, + "sourceMap": true, + "allowJs": true, + "types": ["node", "jest"], + "strictNullChecks": true, + "allowSyntheticDefaultImports": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "downlevelIteration": true, + "outDir": "./build", + "incremental": true, + "skipLibCheck": true + }, + "include": ["src/**/*", "test/**/*", "./build.ts"], + "exclude": ["**/build/*", "types-src"] +} diff --git a/packages/3d-web-experience-server/build.ts b/packages/3d-web-experience-server/build.ts new file mode 100644 index 00000000..120c09e4 --- /dev/null +++ b/packages/3d-web-experience-server/build.ts @@ -0,0 +1,3 @@ +import { handleLibraryBuild } from "../../utils/build-library"; + +handleLibraryBuild(); diff --git a/packages/3d-web-experience-server/package.json b/packages/3d-web-experience-server/package.json new file mode 100644 index 00000000..b301aed5 --- /dev/null +++ b/packages/3d-web-experience-server/package.json @@ -0,0 +1,31 @@ +{ + "name": "@mml-io/3d-web-experience-server", + "version": "0.15.0", + "publishConfig": { + "access": "public" + }, + "main": "./build/index.js", + "types": "./build/index.d.ts", + "type": "module", + "files": [ + "/build" + ], + "scripts": { + "build": "tsx ./build.ts --build", + "iterate": "tsx ./build.ts --watch", + "type-check": "tsc --noEmit", + "lint": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --max-warnings 0", + "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" + }, + "dependencies": { + "@mml-io/3d-web-client-core": "^0.15.0", + "@mml-io/3d-web-text-chat": "^0.15.0", + "@mml-io/3d-web-user-networking": "^0.15.0", + "@mml-io/3d-web-voice-chat": "^0.15.0", + "three": "0.163.0" + }, + "devDependencies": { + "@types/node": "^20.12.7", + "@types/three": "0.163.0" + } +} diff --git a/example/server/src/router/MMLDocumentsServer.ts b/packages/3d-web-experience-server/src/MMLDocumentsServer.ts similarity index 100% rename from example/server/src/router/MMLDocumentsServer.ts rename to packages/3d-web-experience-server/src/MMLDocumentsServer.ts diff --git a/packages/3d-web-experience-server/src/Networked3dWebExperienceServer.ts b/packages/3d-web-experience-server/src/Networked3dWebExperienceServer.ts new file mode 100644 index 00000000..f94aaff6 --- /dev/null +++ b/packages/3d-web-experience-server/src/Networked3dWebExperienceServer.ts @@ -0,0 +1,153 @@ +import { ChatNetworkingServer } from "@mml-io/3d-web-text-chat"; +import { UserData, UserIdentity, UserNetworkingServer } from "@mml-io/3d-web-user-networking"; +import cors from "cors"; +import express from "express"; +import enableWs from "express-ws"; +import WebSocket from "ws"; + +import { websocketDirectoryChangeListener } from "../../../utils/websocketDirectoryChangeListener"; + +import { MMLDocumentsServer } from "./MMLDocumentsServer"; + +type UserAuthenticator = { + generateAuthorizedSessionToken(req: express.Request): string | null; + getClientIdForSessionToken: (sessionToken: string) => { + id: number; + } | null; + onClientConnect( + clientId: number, + sessionToken: string, + userIdentityPresentedOnConnection?: UserIdentity, + ): UserData | null; + onClientUserIdentityUpdate(clientId: number, userIdentity: UserIdentity): UserData | null; + onClientDisconnect(clientId: number): void; +}; + +export const defaultSessionTokenPlaceholder = "SESSION.TOKEN.PLACEHOLDER"; + +export type Networked3dWebExperienceServerConfig = { + networkPath: string; + webClientServing: { + indexUrl: string; + indexContent: string; + sessionTokenPlaceholder?: string; + + clientBuildDir: string; + clientUrl: string; + clientWatchWebsocketPath?: string; + }; + chatNetworkPath?: string; + assetServing?: { + assetsDir: string; + assetsUrl: string; + }; + mmlServing?: { + documentsWatchPath: string; + documentsUrl: string; + }; + userAuthenticator: UserAuthenticator; +}; + +export class Networked3dWebExperienceServer { + private userNetworkingServer: UserNetworkingServer; + + private chatNetworkingServer?: ChatNetworkingServer; + + private mmlDocumentsServer?: MMLDocumentsServer; + + constructor(private config: Networked3dWebExperienceServerConfig) { + if (this.config.mmlServing) { + this.mmlDocumentsServer = new MMLDocumentsServer(this.config.mmlServing.documentsWatchPath); + } + + this.chatNetworkingServer = new ChatNetworkingServer({ + getChatUserIdentity: (sessionToken: string) => { + return this.config.userAuthenticator.getClientIdForSessionToken(sessionToken); + }, + }); + + this.userNetworkingServer = new UserNetworkingServer({ + onClientConnect: ( + clientId: number, + sessionToken: string, + userIdentityPresentedOnConnection?: UserIdentity, + ): UserData | null => { + return this.config.userAuthenticator.onClientConnect( + clientId, + sessionToken, + userIdentityPresentedOnConnection, + ); + }, + onClientUserIdentityUpdate: ( + clientId: number, + userIdentity: UserIdentity, + ): UserData | null => { + // Called whenever a user connects or updates their character/identity + return this.config.userAuthenticator.onClientUserIdentityUpdate(clientId, userIdentity); + }, + onClientDisconnect: (clientId: number): void => { + this.config.userAuthenticator.onClientDisconnect(clientId); + // Disconnect the corresponding chat client to avoid later conflicts of client ids + if (this.chatNetworkingServer) { + this.chatNetworkingServer.disconnectClientId(clientId); + } + }, + }); + } + + registerExpressRoutes(app: enableWs.Application) { + app.ws(this.config.networkPath, (ws) => { + this.userNetworkingServer.connectClient(ws); + }); + + if (this.config.chatNetworkPath && this.chatNetworkingServer) { + const chatServer = this.chatNetworkingServer; + app.ws(this.config.chatNetworkPath, (ws) => { + chatServer.connectClient(ws); + }); + } + + const webClientServing = this.config.webClientServing; + if (webClientServing) { + app.get(webClientServing.indexUrl, (req: express.Request, res: express.Response) => { + const token = this.config.userAuthenticator.generateAuthorizedSessionToken(req); + if (!token) { + res.send("Error: Could not generate token"); + return; + } + const authorizedDemoIndexContent = webClientServing.indexContent.replace( + webClientServing.sessionTokenPlaceholder || defaultSessionTokenPlaceholder, + token, + ); + res.send(authorizedDemoIndexContent); + }); + + app.use(webClientServing.clientUrl, express.static(webClientServing.clientBuildDir)); + if (webClientServing.clientWatchWebsocketPath) { + websocketDirectoryChangeListener(app, { + directory: webClientServing.clientBuildDir, + websocketPath: webClientServing.clientWatchWebsocketPath, + }); + } + } + + const mmlDocumentsServer = this.mmlDocumentsServer; + const mmlServing = this.config.mmlServing; + // Handle example document sockets + if (mmlServing && mmlDocumentsServer) { + app.ws(`${mmlServing.documentsUrl}:filename`, (ws: WebSocket, req: express.Request) => { + const { filename } = req.params; + mmlDocumentsServer.handle(filename, ws); + }); + } + + if (this.config.assetServing) { + // Serve assets with CORS allowing all origins + app.use( + this.config.assetServing.assetsUrl, + cors(), + express.static(this.config.assetServing.assetsDir), + ); + } + } +} diff --git a/packages/3d-web-experience-server/src/index.ts b/packages/3d-web-experience-server/src/index.ts new file mode 100644 index 00000000..85d15b35 --- /dev/null +++ b/packages/3d-web-experience-server/src/index.ts @@ -0,0 +1,2 @@ +export * from "./MMLDocumentsServer"; +export * from "./Networked3dWebExperienceServer"; diff --git a/packages/3d-web-experience-server/tsconfig.json b/packages/3d-web-experience-server/tsconfig.json new file mode 100644 index 00000000..e2abbe6a --- /dev/null +++ b/packages/3d-web-experience-server/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "noImplicitAny": true, + "module": "esnext", + "target": "ES6", + "jsx": "react-jsx", + "lib": ["es2020", "dom"], + "esModuleInterop": true, + "sourceMap": true, + "allowJs": true, + "types": ["node", "jest"], + "strictNullChecks": true, + "allowSyntheticDefaultImports": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "downlevelIteration": true, + "outDir": "./build", + "incremental": true, + "skipLibCheck": true + }, + "include": ["src/**/*", "test/**/*", "./build.ts"], + "exclude": ["**/build/*", "types-src"] +} diff --git a/packages/3d-web-standalone-avatar-editor/build.ts b/packages/3d-web-standalone-avatar-editor/build.ts index 17b91697..6e3aa3be 100644 --- a/packages/3d-web-standalone-avatar-editor/build.ts +++ b/packages/3d-web-standalone-avatar-editor/build.ts @@ -2,14 +2,14 @@ import cssModulesPlugin from "esbuild-css-modules-plugin"; import { handleLibraryBuild } from "../../utils/build-library"; -handleLibraryBuild( - [ +handleLibraryBuild({ + plugins: [ cssModulesPlugin({ inject: true, emitDeclarationFile: true, }), ], - { + loader: { ".svg": "text", }, -); +}); diff --git a/packages/3d-web-standalone-avatar-editor/package.json b/packages/3d-web-standalone-avatar-editor/package.json index b50d6ebb..94e29982 100644 --- a/packages/3d-web-standalone-avatar-editor/package.json +++ b/packages/3d-web-standalone-avatar-editor/package.json @@ -19,18 +19,19 @@ "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" }, "dependencies": { + "@mml-io/model-loader": "0.14.0", "@mml-io/3d-web-avatar": "^0.15.0", "@mml-io/3d-web-avatar-editor-ui": "^0.15.0", "@mml-io/3d-web-client-core": "^0.15.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "three": "0.153.0" + "three": "0.163.0" }, "devDependencies": { - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", - "@types/three": "0.153.0", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", + "@types/three": "0.163.0", "esbuild-css-modules-plugin": "3.1.0" } } diff --git a/packages/3d-web-standalone-avatar-editor/src/AvatarRenderer.ts b/packages/3d-web-standalone-avatar-editor/src/AvatarRenderer.ts index ce1cc05c..583a5a77 100644 --- a/packages/3d-web-standalone-avatar-editor/src/AvatarRenderer.ts +++ b/packages/3d-web-standalone-avatar-editor/src/AvatarRenderer.ts @@ -1,5 +1,5 @@ -import { ModelLoader } from "@mml-io/3d-web-avatar"; import { TimeManager, CameraManager, CollisionsManager } from "@mml-io/3d-web-client-core"; +import { ModelLoader, ModelLoadResult } from "@mml-io/model-loader"; import { AnimationClip, AnimationMixer, @@ -36,7 +36,7 @@ export class AvatarRenderer { public scene: Scene; private mixer: AnimationMixer | null = null; - private animationAsset: GLTF | null | undefined = null; + private animationAsset: ModelLoadResult | null | undefined = null; private lights: Lights; private mirror: Mirror | null = null; @@ -154,7 +154,7 @@ export class AvatarRenderer { } if (this.animationAsset && this.animationAsset.animations) { const animationClip = this.cleanupNonRotationAnimTracks - ? this.cleanAnimationClips(this.animationAsset.scene, this.animationAsset.animations[0]) + ? this.cleanAnimationClips(this.animationAsset.group, this.animationAsset.animations[0]) : this.animationAsset.animations[0]; const animationAction = this.mixer.clipAction(animationClip); diff --git a/packages/3d-web-standalone-avatar-editor/src/index.ts b/packages/3d-web-standalone-avatar-editor/src/index.ts index cc94d921..ff25f0c0 100644 --- a/packages/3d-web-standalone-avatar-editor/src/index.ts +++ b/packages/3d-web-standalone-avatar-editor/src/index.ts @@ -4,12 +4,8 @@ export type { CharacterComposition, } from "@mml-io/3d-web-avatar-editor-ui"; export { CharacterPartsSelector, findAssetsInCollection } from "@mml-io/3d-web-avatar-editor-ui"; -export { - MMLCharacter, - ModelLoader, - parseMMLDescription, - createMMLCharacterString, -} from "@mml-io/3d-web-avatar"; +export { MMLCharacter, parseMMLDescription, createMMLCharacterString } from "@mml-io/3d-web-avatar"; export { AvatarRenderer } from "./AvatarRenderer"; export { AvatarVisualizer } from "./AvatarVisualizer"; export { ModelScreenshotter } from "./screenshot/ModelScreenshotter"; +export { ModelLoader } from "@mml-io/model-loader"; diff --git a/packages/3d-web-standalone-avatar-editor/src/screenshot/ModelScreenshotter.ts b/packages/3d-web-standalone-avatar-editor/src/screenshot/ModelScreenshotter.ts index 3b5e56a5..2b3f3f6c 100644 --- a/packages/3d-web-standalone-avatar-editor/src/screenshot/ModelScreenshotter.ts +++ b/packages/3d-web-standalone-avatar-editor/src/screenshot/ModelScreenshotter.ts @@ -1,4 +1,4 @@ -import { ModelLoader } from "@mml-io/3d-web-avatar"; +import { ModelLoader } from "@mml-io/model-loader"; import { AnimationMixer, Box3, @@ -77,8 +77,8 @@ export class ModelScreenshotter { if (model instanceof Object3D) { loadedModel = model; } else { - const gltf = (await this.modelLoader.load(model)) as GLTF; - loadedModel = gltf.scene; + const modelLoadResult = await this.modelLoader.load(model); + loadedModel = modelLoadResult.group; } const mixer = new AnimationMixer(loadedModel); @@ -105,9 +105,9 @@ export class ModelScreenshotter { }); } - const animationAsset = await this.modelLoader.load(animationURL); - if (animationAsset && animationAsset.animations) { - const animationClip = animationAsset.animations[0]; + const modelLoadResult = await this.modelLoader.load(animationURL); + if (modelLoadResult && modelLoadResult.animations) { + const animationClip = modelLoadResult.animations[0]; const animationAction = mixer.clipAction(animationClip); animationAction.play(); mixer.setTime(animationTime); diff --git a/packages/3d-web-text-chat/build.ts b/packages/3d-web-text-chat/build.ts index 17b91697..6e3aa3be 100644 --- a/packages/3d-web-text-chat/build.ts +++ b/packages/3d-web-text-chat/build.ts @@ -2,14 +2,14 @@ import cssModulesPlugin from "esbuild-css-modules-plugin"; import { handleLibraryBuild } from "../../utils/build-library"; -handleLibraryBuild( - [ +handleLibraryBuild({ + plugins: [ cssModulesPlugin({ inject: true, emitDeclarationFile: true, }), ], - { + loader: { ".svg": "text", }, -); +}); diff --git a/packages/3d-web-text-chat/package.json b/packages/3d-web-text-chat/package.json index 04b2a5eb..d1d2fee6 100644 --- a/packages/3d-web-text-chat/package.json +++ b/packages/3d-web-text-chat/package.json @@ -18,7 +18,7 @@ "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" }, "dependencies": { - "express": "4.18.2", + "express": "4.19.2", "express-ws": "5.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -27,9 +27,9 @@ "devDependencies": { "@types/express": "^4.17.21", "@types/express-ws": "^3.0.4", - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", "@types/ws": "^8.5.10", "esbuild-css-modules-plugin": "3.1.0" } diff --git a/packages/3d-web-text-chat/src/chat-ui/TextChatUI.tsx b/packages/3d-web-text-chat/src/chat-ui/TextChatUI.tsx index ff70141c..ce753eb1 100644 --- a/packages/3d-web-text-chat/src/chat-ui/TextChatUI.tsx +++ b/packages/3d-web-text-chat/src/chat-ui/TextChatUI.tsx @@ -21,13 +21,13 @@ export class TextChatUI { } private wrapper = document.createElement("div"); - private container = document.getElementById("app")!; constructor( + private holderElement: HTMLElement, private clientname: string, private sendMessageToServerMethod: (message: string) => void, ) { - this.container.appendChild(this.wrapper); + this.holderElement.appendChild(this.wrapper); this.root = createRoot(this.wrapper); this.sendMessageToServerMethod = sendMessageToServerMethod; } diff --git a/packages/3d-web-user-networking/package.json b/packages/3d-web-user-networking/package.json index a593f397..dfe78bf1 100644 --- a/packages/3d-web-user-networking/package.json +++ b/packages/3d-web-user-networking/package.json @@ -24,9 +24,9 @@ "devDependencies": { "@types/express": "^4.17.21", "@types/express-ws": "^3.0.4", - "@types/node": "^20.11.13", + "@types/node": "^20.12.7", "@types/ws": "^8.5.10", - "express": "4.18.2", + "express": "4.19.2", "express-ws": "5.0.2" } } diff --git a/packages/3d-web-user-networking/src/UserNetworkingServer.ts b/packages/3d-web-user-networking/src/UserNetworkingServer.ts index d52c2297..45ab6461 100644 --- a/packages/3d-web-user-networking/src/UserNetworkingServer.ts +++ b/packages/3d-web-user-networking/src/UserNetworkingServer.ts @@ -32,14 +32,17 @@ export type UserNetworkingServerOptions = { clientId: number, sessionToken: string, userIdentity?: UserIdentity, - ) => UserData | null; - onClientUserIdentityUpdate: (clientId: number, userIdentity: UserIdentity) => UserData | null; + ) => Promise | UserData | null; + onClientUserIdentityUpdate: ( + clientId: number, + userIdentity: UserIdentity, + ) => Promise | UserData | null; onClientDisconnect: (clientId: number) => void; }; export class UserNetworkingServer { private allClients = new Set(); - private clientsById: Map = new Map(); + private authenticatedClientsById: Map = new Map(); constructor(private options: UserNetworkingServerOptions) { setInterval(this.sendUpdates.bind(this), packetsUpdateRate); @@ -58,7 +61,7 @@ export class UserNetworkingServer { } private pingClients() { - this.clientsById.forEach((client) => { + this.authenticatedClientsById.forEach((client) => { if (client.socket.readyState === WebSocketOpenStatus) { client.socket.send(JSON.stringify({ type: "ping" } as FromServerMessage)); } @@ -67,7 +70,7 @@ export class UserNetworkingServer { private getId(): number { let id = 1; - while (this.clientsById.has(id)) { + while (this.authenticatedClientsById.has(id)) { id++; } return id; @@ -91,7 +94,6 @@ export class UserNetworkingServer { }, }; this.allClients.add(client); - this.clientsById.set(id, client); socket.on("message", (message: WebSocket.Data, _isBinary: boolean) => { if (message instanceof Buffer) { @@ -109,10 +111,14 @@ export class UserNetworkingServer { } if (!client.authenticatedUser) { if (parsed.type === USER_AUTHENTICATE_MESSAGE_TYPE) { - if (!this.handleUserAuth(id, parsed)) { - // If the user is not authorized, disconnect the client - socket.close(); - } + this.handleUserAuth(client, parsed).then((authResult) => { + if (!authResult) { + // If the user is not authorized, disconnect the client + socket.close(); + } else { + this.authenticatedClientsById.set(id, client); + } + }); } else { console.error(`Unhandled message pre-auth: ${JSON.stringify(parsed)}`); socket.close(); @@ -144,56 +150,56 @@ export class UserNetworkingServer { if (!this.allClients.has(client)) { return; } + this.allClients.delete(client); if (client.authenticatedUser !== null) { // Only report disconnections of clients that were authenticated this.options.onClientDisconnect(client.id); - } - this.clientsById.delete(client.id); - this.allClients.delete(client); - const disconnectMessage = JSON.stringify({ - id: client.id, - type: DISCONNECTED_MESSAGE_TYPE, - } as FromServerMessage); - for (const otherClient of this.allClients) { - if ( - otherClient.authenticatedUser !== null && - otherClient.socket.readyState === WebSocketOpenStatus - ) { - otherClient.socket.send(disconnectMessage); + this.authenticatedClientsById.delete(client.id); + const disconnectMessage = JSON.stringify({ + id: client.id, + type: DISCONNECTED_MESSAGE_TYPE, + } as FromServerMessage); + for (const [, otherClient] of this.authenticatedClientsById) { + if (otherClient.socket.readyState === WebSocketOpenStatus) { + otherClient.socket.send(disconnectMessage); + } } } } - private handleUserAuth(clientId: number, credentials: UserAuthenticateMessage): boolean { + private async handleUserAuth( + client: Client, + credentials: UserAuthenticateMessage, + ): Promise { const userData = this.options.onClientConnect( - clientId, + client.id, credentials.sessionToken, credentials.userIdentity, ); - if (!userData) { - console.error(`Client-id ${clientId} user_auth unauthorized and ignored`); - return false; + let resolvedUserData; + if (userData instanceof Promise) { + resolvedUserData = await userData; + } else { + resolvedUserData = userData; } - - const client = this.clientsById.get(clientId); - if (!client) { - console.error(`Client-id ${clientId}, client not found`); + if (resolvedUserData === null) { + console.error(`Client-id ${client.id} user_auth unauthorized and ignored`); return false; } - console.log("Client authenticated", clientId, userData); - client.authenticatedUser = userData; + console.log("Client authenticated", client.id, resolvedUserData); + client.authenticatedUser = resolvedUserData; const identityMessage = JSON.stringify({ - id: clientId, + id: client.id, type: IDENTITY_MESSAGE_TYPE, } as FromServerMessage); const userProfileMessage = JSON.stringify({ - id: clientId, + id: client.id, type: USER_PROFILE_MESSAGE_TYPE, - username: userData.username, - characterDescription: userData.characterDescription, + username: resolvedUserData.username, + characterDescription: resolvedUserData.characterDescription, } as FromServerMessage); client.socket.send(userProfileMessage); @@ -202,12 +208,8 @@ export class UserNetworkingServer { const userUpdateMessage = UserNetworkingCodec.encodeUpdate(client.update); // Send information about all other clients to the freshly connected client and vice versa - for (const otherClient of this.clientsById.values()) { - if ( - otherClient.socket.readyState !== WebSocketOpenStatus || - otherClient.authenticatedUser == null || - otherClient === client - ) { + for (const [, otherClient] of this.authenticatedClientsById) { + if (otherClient.socket.readyState !== WebSocketOpenStatus || otherClient === client) { // Do not send updates for any clients which have not yet authenticated or not yet connected continue; } @@ -226,7 +228,7 @@ export class UserNetworkingServer { otherClient.socket.send(userUpdateMessage); } - console.log("Client authenticated", clientId); + console.log("Client authenticated", client.id); return true; } @@ -237,10 +239,10 @@ export class UserNetworkingServer { private internalUpdateUser(clientId: number, userData: UserData) { // This function assumes authorization has already been done - const client = this.clientsById.get(clientId)!; + const client = this.authenticatedClientsById.get(clientId)!; client.authenticatedUser = userData; - this.clientsById.set(clientId, client); + this.authenticatedClientsById.set(clientId, client); const newUserData = JSON.stringify({ id: clientId, @@ -252,19 +254,15 @@ export class UserNetworkingServer { // Broadcast the new userdata to all sockets, INCLUDING the user of the calling socket // Clients will always render based on the public userProfile. // This makes it intuitive, as it is "what you see is what other's see" from a user's perspective. - for (const [otherClientId, otherClient] of this.clientsById) { - if (!otherClient.authenticatedUser) { - // Do not send updates for any clients which have no user yet - continue; - } + for (const [otherClientId, otherClient] of this.authenticatedClientsById) { if (otherClient.socket.readyState === WebSocketOpenStatus) { otherClient.socket.send(newUserData); } } } - private handleUserUpdate(clientId: number, message: UserUpdateMessage): void { - const client = this.clientsById.get(clientId); + private async handleUserUpdate(clientId: number, message: UserUpdateMessage): Promise { + const client = this.authenticatedClientsById.get(clientId); if (!client) { console.error(`Client-id ${clientId} user_update ignored, client not found`); return; @@ -275,30 +273,28 @@ export class UserNetworkingServer { clientId, message.userIdentity, ); - if (!authorizedUserData) { + let resolvedAuthorizedUserData; + if (authorizedUserData instanceof Promise) { + resolvedAuthorizedUserData = await authorizedUserData; + } else { + resolvedAuthorizedUserData = authorizedUserData; + } + if (!resolvedAuthorizedUserData) { // TODO - inform the client about the unauthorized update console.warn(`Client-id ${clientId} user_update unauthorized and ignored`); return; } - this.internalUpdateUser(clientId, authorizedUserData); + this.internalUpdateUser(clientId, resolvedAuthorizedUserData); } private sendUpdates(): void { - for (const [clientId, client] of this.clientsById) { - if (!client.authenticatedUser) { - // Do not send updates about unauthenticated clients - continue; - } + for (const [clientId, client] of this.authenticatedClientsById) { const update = client.update; const encodedUpdate = UserNetworkingCodec.encodeUpdate(update); - for (const [otherClientId, otherClient] of this.clientsById) { - if ( - otherClient.authenticatedUser !== null && - otherClientId !== clientId && - otherClient.socket.readyState === WebSocketOpenStatus - ) { + for (const [otherClientId, otherClient] of this.authenticatedClientsById) { + if (otherClientId !== clientId && otherClient.socket.readyState === WebSocketOpenStatus) { otherClient.socket.send(encodedUpdate); } } diff --git a/packages/3d-web-voice-chat/build.ts b/packages/3d-web-voice-chat/build.ts index 17b91697..6e3aa3be 100644 --- a/packages/3d-web-voice-chat/build.ts +++ b/packages/3d-web-voice-chat/build.ts @@ -2,14 +2,14 @@ import cssModulesPlugin from "esbuild-css-modules-plugin"; import { handleLibraryBuild } from "../../utils/build-library"; -handleLibraryBuild( - [ +handleLibraryBuild({ + plugins: [ cssModulesPlugin({ inject: true, emitDeclarationFile: true, }), ], - { + loader: { ".svg": "text", }, -); +}); diff --git a/packages/3d-web-voice-chat/package.json b/packages/3d-web-voice-chat/package.json index eebf4a6a..7086be45 100644 --- a/packages/3d-web-voice-chat/package.json +++ b/packages/3d-web-voice-chat/package.json @@ -18,7 +18,7 @@ "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" }, "dependencies": { - "@voxeet/voxeet-web-sdk": "3.11.0", + "@voxeet/voxeet-web-sdk": "3.11.1", "react": "^18.2.0", "react-dom": "^18.2.0", "ws": "^8.16.0" @@ -26,12 +26,12 @@ "devDependencies": { "@types/express": "^4.17.21", "@types/express-ws": "^3.0.4", - "@types/node": "^20.11.13", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", "@types/ws": "^8.5.10", "esbuild-css-modules-plugin": "3.1.0", - "express": "4.18.2", + "express": "4.19.2", "express-ws": "5.0.2" } } diff --git a/packages/3d-web-voice-chat/src/chat-ui/components/voice-chat-ui.tsx b/packages/3d-web-voice-chat/src/chat-ui/components/voice-chat-ui.tsx index 7c2302f7..8b7b1799 100644 --- a/packages/3d-web-voice-chat/src/chat-ui/components/voice-chat-ui.tsx +++ b/packages/3d-web-voice-chat/src/chat-ui/components/voice-chat-ui.tsx @@ -129,7 +129,6 @@ const VoiceChatUIComponent = (props: VoiceChatUIComponentProps) => { export class VoiceChatUI { private root: Root; private wrapper = document.createElement("div"); - private container = document.getElementById("app")!; private activeSpeakers: number = 0; private speaking: boolean = false; @@ -137,10 +136,11 @@ export class VoiceChatUI { private passwordModal: boolean = false; constructor( + private holderElement: HTMLElement, private handleClickMic: () => void, private handlePassword: (password: string) => void, ) { - this.container.appendChild(this.wrapper); + this.holderElement.appendChild(this.wrapper); this.root = createRoot(this.wrapper); } diff --git a/packages/3d-web-voice-chat/src/voice-chat-manager/VoiceChatManager.ts b/packages/3d-web-voice-chat/src/voice-chat-manager/VoiceChatManager.ts index c01548ff..74945736 100644 --- a/packages/3d-web-voice-chat/src/voice-chat-manager/VoiceChatManager.ts +++ b/packages/3d-web-voice-chat/src/voice-chat-manager/VoiceChatManager.ts @@ -74,6 +74,7 @@ export class VoiceChatManager { private tickInterval: NodeJS.Timeout | null = null; constructor( + private holderElement: HTMLElement, private userId: number, private remoteUserStates: Map, private latestCharacterObj: { @@ -84,6 +85,7 @@ export class VoiceChatManager { this.conferenceAlias = window.location.host; this.voiceChatUI = new VoiceChatUI( + this.holderElement, this.handleJoinClick.bind(this), this.handlePassword.bind(this), ); diff --git a/tsconfig.json b/tsconfig.json index 2f980427..c1259836 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,19 @@ { "compilerOptions": { - "esModuleInterop": true + "noImplicitAny": true, + "module": "esnext", + "target": "es2022", + "sourceMap": true, + "esModuleInterop": true, + "allowJs": true, + "strictNullChecks": true, + "allowSyntheticDefaultImports": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "downlevelIteration": true, + "noEmit": true, + "baseUrl": ".", + "incremental": true, + "skipLibCheck": true } } diff --git a/utils/build-library.ts b/utils/build-library.ts index de838f00..ff1250d3 100644 --- a/utils/build-library.ts +++ b/utils/build-library.ts @@ -7,10 +7,23 @@ const watchMode = "--watch"; const helpString = `Mode must be provided as one of ${buildMode} or ${watchMode}`; -export function handleLibraryBuild( - plugins: Array = [], - loader: { [key: string]: esbuild.Loader } = {}, -) { +type LibraryBuildOptions = { + entryPoints: { + [key: string]: string; + }; + plugins: Array; + loader: { [key: string]: esbuild.Loader }; +}; + +export function handleLibraryBuild(optionsArg?: Partial) { + const options = { + plugins: [], + loader: {}, + entryPoints: { + index: "src/index.ts", + }, + ...optionsArg, + }; const args = process.argv.splice(2); if (args.length !== 1) { @@ -21,9 +34,7 @@ export function handleLibraryBuild( const mode = args[0]; const buildOptions: esbuild.BuildOptions = { - entryPoints: { - index: "src/index.ts", - }, + entryPoints: options.entryPoints, write: true, bundle: true, metafile: true, @@ -34,9 +45,9 @@ export function handleLibraryBuild( sourcemap: true, target: "node14", loader: { - ...loader, + ...options.loader, }, - plugins: [...plugins, dtsPlugin()], + plugins: [...options.plugins, dtsPlugin()], }; switch (mode) { diff --git a/utils/websocketDirectoryChangeListener.ts b/utils/websocketDirectoryChangeListener.ts new file mode 100644 index 00000000..d49721be --- /dev/null +++ b/utils/websocketDirectoryChangeListener.ts @@ -0,0 +1,25 @@ +import chokidar from "chokidar"; +import enableWs from "express-ws"; +import WebSocket from "ws"; + +export function websocketDirectoryChangeListener( + app: enableWs.Application, + options: { + directory: string; + websocketPath: string; + }, +) { + const listeningClients = new Set(); + chokidar.watch(options.directory).on("all", () => { + for (const client of listeningClients) { + client.send("change"); + } + }); + // Create an event-source that updates whenever the build folder gets modified + app.ws(options.websocketPath, (ws: WebSocket) => { + listeningClients.add(ws); + ws.on("close", () => { + listeningClients.delete(ws); + }); + }); +}