@voltro/plugin-rooms 0.0.0-stage → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/CHANGELOG.md +24329 -0
  2. package/LICENSE +61 -0
  3. package/README.md +9204 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +11322 -0
  6. package/dist/actor.js +1474 -0
  7. package/dist/apiBinding.js +678 -0
  8. package/dist/apiRegistryBinding.js +399 -0
  9. package/dist/apiReservations.js +433 -0
  10. package/dist/baselines.js +73 -0
  11. package/dist/bots.d.ts +1485 -0
  12. package/dist/bots.js +563 -0
  13. package/dist/catalog.js +80 -0
  14. package/dist/checkpointJson.js +24 -0
  15. package/dist/checkpointStore.js +386 -0
  16. package/dist/client.js +56 -0
  17. package/dist/clockSync.js +51 -0
  18. package/dist/collision.js +156 -0
  19. package/dist/commandDelivery.js +101 -0
  20. package/dist/commandRecord.js +11 -0
  21. package/dist/commandWithdrawal.js +183 -0
  22. package/dist/connection.js +497 -0
  23. package/dist/controlCarrier.js +375 -0
  24. package/dist/controlRegistry.js +79 -0
  25. package/dist/controlTarget.js +45 -0
  26. package/dist/controlTransport.js +574 -0
  27. package/dist/developmentBinding.js +113 -0
  28. package/dist/directory.js +323 -0
  29. package/dist/directoryProjection.js +117 -0
  30. package/dist/errors.d.ts +125 -0
  31. package/dist/errors.js +53 -0
  32. package/dist/fixed.d.ts +284 -0
  33. package/dist/fixed.js +10 -0
  34. package/dist/fixed32.js +134 -0
  35. package/dist/fixedCollision.js +60 -0
  36. package/dist/fixedCollision32.js +109 -0
  37. package/dist/fixedMath.js +56 -0
  38. package/dist/fixedRaw.js +11 -0
  39. package/dist/fixedSlabs.js +34 -0
  40. package/dist/fixedTrig.js +48 -0
  41. package/dist/fixedTrig32.js +38 -0
  42. package/dist/fixedVectors.js +113 -0
  43. package/dist/fixedVectors32.js +95 -0
  44. package/dist/fixedWide.js +50 -0
  45. package/dist/fixedWords.js +46 -0
  46. package/dist/gateway.js +57 -0
  47. package/dist/geometry-retention-app/rooms.geometryJournalRetention.workflow.server.tsx +4 -0
  48. package/dist/geometry-retention-app/rooms.geometryJournalRetention.workflow.tsx +14 -0
  49. package/dist/geometry-worker/worker.d.mts +2 -0
  50. package/dist/geometry-worker/worker.mjs +50 -0
  51. package/dist/geometry.d.ts +2249 -0
  52. package/dist/geometry.js +40 -0
  53. package/dist/geometryActivation.js +82 -0
  54. package/dist/geometryActorInventory.js +108 -0
  55. package/dist/geometryAdminClient.js +87 -0
  56. package/dist/geometryAdminData.js +32 -0
  57. package/dist/geometryAdminFixtures.js +50 -0
  58. package/dist/geometryAdminPorts.js +5 -0
  59. package/dist/geometryAdminRpc.js +58 -0
  60. package/dist/geometryAdminRpcRoutes.js +49 -0
  61. package/dist/geometryAdminSchemas.js +39 -0
  62. package/dist/geometryAdministration.js +190 -0
  63. package/dist/geometryAdministrationPorts.js +5 -0
  64. package/dist/geometryApiBinding.js +165 -0
  65. package/dist/geometryAppStorage.js +58 -0
  66. package/dist/geometryArtifacts.js +198 -0
  67. package/dist/geometryAssetBundle.js +117 -0
  68. package/dist/geometryAssetClient.js +25 -0
  69. package/dist/geometryAssetData.js +106 -0
  70. package/dist/geometryAssetHttp.js +123 -0
  71. package/dist/geometryAssetPorts.js +5 -0
  72. package/dist/geometryAssetRpc.js +30 -0
  73. package/dist/geometryAssetRpcRoutes.js +40 -0
  74. package/dist/geometryAssetStorageGrant.js +103 -0
  75. package/dist/geometryBoxOverlap.js +110 -0
  76. package/dist/geometryCatalogueDigest.js +111 -0
  77. package/dist/geometryCellCoverage.js +85 -0
  78. package/dist/geometryCellLoader.js +28 -0
  79. package/dist/geometryChannel.js +134 -0
  80. package/dist/geometryChunkHttp.js +54 -0
  81. package/dist/geometryChunkLeases.js +22 -0
  82. package/dist/geometryClient.d.ts +1429 -0
  83. package/dist/geometryClient.js +149 -0
  84. package/dist/geometryClientChunks.js +330 -0
  85. package/dist/geometryClientDelta.js +25 -0
  86. package/dist/geometryClientHttp.js +37 -0
  87. package/dist/geometryClientInterest.js +109 -0
  88. package/dist/geometryClientStatic.js +34 -0
  89. package/dist/geometryCms.d.ts +763 -0
  90. package/dist/geometryCms.js +217 -0
  91. package/dist/geometryCommitCoordinator.js +241 -0
  92. package/dist/geometryCompactionFixture.js +84 -0
  93. package/dist/geometryCompactionStrategies.js +38 -0
  94. package/dist/geometryConnectionClient.js +23 -0
  95. package/dist/geometryDerivationFixtures.js +141 -0
  96. package/dist/geometryDerivationStrategies.js +27 -0
  97. package/dist/geometryDigest.js +13 -0
  98. package/dist/geometryEditChannel.js +70 -0
  99. package/dist/geometryEditIngress.js +263 -0
  100. package/dist/geometryEdits.js +366 -0
  101. package/dist/geometryEnvelope.js +41 -0
  102. package/dist/geometryGridRaycast.js +92 -0
  103. package/dist/geometryGridSweep.js +92 -0
  104. package/dist/geometryHeightfield.js +166 -0
  105. package/dist/geometryHeightfieldRaycast.js +74 -0
  106. package/dist/geometryHeightfieldSweep.js +85 -0
  107. package/dist/geometryHeightfieldVolume.js +45 -0
  108. package/dist/geometryHost.js +322 -0
  109. package/dist/geometryHostDirectory.js +207 -0
  110. package/dist/geometryHostMutations.js +137 -0
  111. package/dist/geometryHostStreams.js +124 -0
  112. package/dist/geometryHttpBody.js +76 -0
  113. package/dist/geometryHttpRoutes.js +112 -0
  114. package/dist/geometryImportGltf.js +300 -0
  115. package/dist/geometryImportLdtk.js +54 -0
  116. package/dist/geometryImportPng.js +144 -0
  117. package/dist/geometryImportPublication.js +67 -0
  118. package/dist/geometryImportTiled.js +39 -0
  119. package/dist/geometryImportTiles.js +136 -0
  120. package/dist/geometryImportVox.js +130 -0
  121. package/dist/geometryImportedSource.js +101 -0
  122. package/dist/geometryInspectEndpoint.js +248 -0
  123. package/dist/geometryInspection.js +92 -0
  124. package/dist/geometryInstall.js +121 -0
  125. package/dist/geometryJournalArchiveData.js +21 -0
  126. package/dist/geometryJournalArchiveIndex.js +330 -0
  127. package/dist/geometryJournalArchiveTable.js +21 -0
  128. package/dist/geometryJournalCompaction.js +100 -0
  129. package/dist/geometryJournalPatch.js +47 -0
  130. package/dist/geometryJournalRetention.js +112 -0
  131. package/dist/geometryJournalRetentionSchemas.js +36 -0
  132. package/dist/geometryJournalRetentionSweep.js +112 -0
  133. package/dist/geometryJournalRetentionWorkflow.js +28 -0
  134. package/dist/geometryJournalRetentionWorkflowData.js +31 -0
  135. package/dist/geometryJournalStorage.js +148 -0
  136. package/dist/geometryLoader.js +118 -0
  137. package/dist/geometryManifest.js +113 -0
  138. package/dist/geometryManifestChannel.js +93 -0
  139. package/dist/geometryManifestClient.js +122 -0
  140. package/dist/geometryManifestData.js +49 -0
  141. package/dist/geometryManifestPorts.js +5 -0
  142. package/dist/geometryManifestPublication.js +109 -0
  143. package/dist/geometryManifestSource.js +68 -0
  144. package/dist/geometryMigrationJournal.js +14 -0
  145. package/dist/geometryMigrationStrategies.js +7 -0
  146. package/dist/geometryMigrations.js +323 -0
  147. package/dist/geometryNativeMetadata.js +52 -0
  148. package/dist/geometryPatch.js +170 -0
  149. package/dist/geometryPersistence.js +449 -0
  150. package/dist/geometryPersistenceCapture.js +69 -0
  151. package/dist/geometryPersistenceData.js +140 -0
  152. package/dist/geometryPersistencePorts.js +5 -0
  153. package/dist/geometryPlayerAdmission.js +34 -0
  154. package/dist/geometryPlayerEditOwner.js +265 -0
  155. package/dist/geometryPlayerEdits.js +49 -0
  156. package/dist/geometryPrepared.js +188 -0
  157. package/dist/geometryPrivacyFence.js +24 -0
  158. package/dist/geometryProceduralPublication.js +91 -0
  159. package/dist/geometryProceduralWorker.js +164 -0
  160. package/dist/geometryPublication.js +110 -0
  161. package/dist/geometryRayAlgebra.js +116 -0
  162. package/dist/geometryReadClient.js +157 -0
  163. package/dist/geometryReadPorts.js +5 -0
  164. package/dist/geometryReadRpc.js +27 -0
  165. package/dist/geometryReadRpcRoutes.js +47 -0
  166. package/dist/geometryReliablePublication.js +82 -0
  167. package/dist/geometryReloadPorts.js +46 -0
  168. package/dist/geometryReloadSource.js +278 -0
  169. package/dist/geometryRenderCache.js +165 -0
  170. package/dist/geometryRenderLod.js +102 -0
  171. package/dist/geometryRollback.js +125 -0
  172. package/dist/geometryRollbackCoordinator.js +203 -0
  173. package/dist/geometryRollbackPorts.js +46 -0
  174. package/dist/geometryRollbackSource.js +209 -0
  175. package/dist/geometryRollbackStore.js +198 -0
  176. package/dist/geometrySchemas.js +27 -0
  177. package/dist/geometryServer.d.ts +2766 -0
  178. package/dist/geometryServer.js +62 -0
  179. package/dist/geometryShapeRaycast.js +111 -0
  180. package/dist/geometryShapeSegments.js +34 -0
  181. package/dist/geometryShapes.js +223 -0
  182. package/dist/geometrySnapshot.js +76 -0
  183. package/dist/geometrySnapshotChannel.js +160 -0
  184. package/dist/geometrySnapshotClient.js +159 -0
  185. package/dist/geometrySnapshotPreparation.js +76 -0
  186. package/dist/geometrySnapshotServer.js +191 -0
  187. package/dist/geometrySqlOwner.js +21 -0
  188. package/dist/geometryStorage.js +127 -0
  189. package/dist/geometryStorageGrant.js +69 -0
  190. package/dist/geometryStorageIdentity.js +9 -0
  191. package/dist/geometryTileArtifact.js +10 -0
  192. package/dist/geometryTileCodec.js +194 -0
  193. package/dist/geometryTileCollision.js +96 -0
  194. package/dist/geometryTileNavigation.js +128 -0
  195. package/dist/geometryTileView.js +35 -0
  196. package/dist/geometryVersionActivation.js +114 -0
  197. package/dist/geometryVersionClient.js +238 -0
  198. package/dist/geometryVersionCompare.js +40 -0
  199. package/dist/geometryVersionMigration.js +106 -0
  200. package/dist/geometryVoxel.js +253 -0
  201. package/dist/geometryWorldEntitySubject.js +32 -0
  202. package/dist/geometryWorldExtent.js +12 -0
  203. package/dist/geometryWorldMetadata.js +38 -0
  204. package/dist/geometryWorldStrategyFixtures.js +127 -0
  205. package/dist/geometryWorldView.js +307 -0
  206. package/dist/host.js +128 -0
  207. package/dist/hostBinding.js +277 -0
  208. package/dist/hostCellObservation.js +114 -0
  209. package/dist/hostClientCapacity.js +90 -0
  210. package/dist/hostCommandScope.js +64 -0
  211. package/dist/hostController.js +3094 -0
  212. package/dist/hostDeployment.js +65 -0
  213. package/dist/hostDrain.js +152 -0
  214. package/dist/hostDrainPorts.js +5 -0
  215. package/dist/hostDriver.js +179 -0
  216. package/dist/hostLane.js +288 -0
  217. package/dist/hostListener.js +79 -0
  218. package/dist/hostListenerBinding.js +19 -0
  219. package/dist/hostLoopObservation.js +90 -0
  220. package/dist/hostMetrics.js +56 -0
  221. package/dist/hostRegistryBinding.js +418 -0
  222. package/dist/hostSelection.js +16 -0
  223. package/dist/hostShutdown.js +47 -0
  224. package/dist/hostTurnObservation.js +53 -0
  225. package/dist/identities.js +4 -0
  226. package/dist/index.d.ts +8632 -0
  227. package/dist/index.js +232 -0
  228. package/dist/inputReceipts.js +63 -0
  229. package/dist/inputRedundancy.js +55 -0
  230. package/dist/inspect.js +238 -0
  231. package/dist/lockstep.d.ts +436 -0
  232. package/dist/lockstep.js +382 -0
  233. package/dist/lockstepAdmission.js +262 -0
  234. package/dist/lockstepAdmissionCodec.js +94 -0
  235. package/dist/lockstepAdmissionPorts.js +5 -0
  236. package/dist/lockstepClientSession.js +578 -0
  237. package/dist/lockstepDefinition.js +148 -0
  238. package/dist/lockstepHostLoop.js +243 -0
  239. package/dist/lockstepInitialAdmission.js +67 -0
  240. package/dist/lockstepInitialStrategyFixtures.js +45 -0
  241. package/dist/lockstepJournal.js +395 -0
  242. package/dist/lockstepJournalCodec.js +254 -0
  243. package/dist/lockstepJournalPorts.js +5 -0
  244. package/dist/lockstepJournalRebuild.js +208 -0
  245. package/dist/lockstepJournalRows.js +57 -0
  246. package/dist/lockstepMembers.js +131 -0
  247. package/dist/lockstepMessages.js +47 -0
  248. package/dist/lockstepOwnedRoom.js +764 -0
  249. package/dist/lockstepPolicies.js +84 -0
  250. package/dist/lockstepReact.js +47 -0
  251. package/dist/lockstepRecoveryTruth.js +121 -0
  252. package/dist/lockstepRosterConfig.js +32 -0
  253. package/dist/lockstepSeed.js +12 -0
  254. package/dist/lockstepSeedFixture.js +20 -0
  255. package/dist/lockstepServer.d.ts +3897 -0
  256. package/dist/lockstepServer.js +325 -0
  257. package/dist/lockstepServerConfig.js +101 -0
  258. package/dist/lockstepServerRoles.js +403 -0
  259. package/dist/lockstepServerStrategyFixtures.js +33 -0
  260. package/dist/lockstepStrategies.js +6 -0
  261. package/dist/lockstepStrategyFixtures.js +137 -0
  262. package/dist/lockstepTerminal.js +90 -0
  263. package/dist/lockstepTerminalPorts.js +5 -0
  264. package/dist/lockstepTransport.js +773 -0
  265. package/dist/lockstepTransportConfig.js +32 -0
  266. package/dist/lockstepWireRoster.js +34 -0
  267. package/dist/matchRoomProvider.js +32 -0
  268. package/dist/matchRooms.js +19 -0
  269. package/dist/membershipObserver.js +47 -0
  270. package/dist/moderation.js +98 -0
  271. package/dist/movementSpecials.js +104 -0
  272. package/dist/ownership.js +17 -0
  273. package/dist/ownershipWithdrawal.js +18 -0
  274. package/dist/pcg32.js +96 -0
  275. package/dist/ports.d.ts +1241 -0
  276. package/dist/ports.js +11 -0
  277. package/dist/quaternion.js +70 -0
  278. package/dist/react.d.ts +406 -0
  279. package/dist/react.js +109 -0
  280. package/dist/reaper-app/rooms.reaper.workflow.server.tsx +5 -0
  281. package/dist/reaper-app/rooms.reaper.workflow.tsx +13 -0
  282. package/dist/reaper.js +243 -0
  283. package/dist/reaperSchemas.js +42 -0
  284. package/dist/reaperWorkflow.js +70 -0
  285. package/dist/recovery.js +189 -0
  286. package/dist/recoverySeats.js +26 -0
  287. package/dist/replay.d.ts +273 -0
  288. package/dist/replay.js +485 -0
  289. package/dist/replayPorts.js +5 -0
  290. package/dist/replayRecording.js +67 -0
  291. package/dist/replaySchema.js +157 -0
  292. package/dist/replayStorage.d.ts +149 -0
  293. package/dist/replayStorage.js +485 -0
  294. package/dist/reservationBatch.js +422 -0
  295. package/dist/reservationSchemas.js +17 -0
  296. package/dist/reservations.js +259 -0
  297. package/dist/reservePort.js +69 -0
  298. package/dist/resolvedOptions.js +4 -0
  299. package/dist/room.d.ts +1006 -0
  300. package/dist/room.js +284 -0
  301. package/dist/roomAccessSweep.js +95 -0
  302. package/dist/roomAppCommandControl.js +59 -0
  303. package/dist/roomAuthoringStrategy.js +17 -0
  304. package/dist/roomErasure.js +198 -0
  305. package/dist/roomPoolRuntimeDefaults.js +24 -0
  306. package/dist/roomPoolSelection.js +19 -0
  307. package/dist/roomPoolTopology.js +212 -0
  308. package/dist/rpc.d.ts +551 -0
  309. package/dist/rpc.js +112 -0
  310. package/dist/rpcClient.js +152 -0
  311. package/dist/rpcRoutes.js +28 -0
  312. package/dist/runtime.js +1123 -0
  313. package/dist/schemaHistory.js +98 -0
  314. package/dist/seatStore.js +151 -0
  315. package/dist/seatStrategyFixtures.js +52 -0
  316. package/dist/seatSubject.js +32 -0
  317. package/dist/seats.js +130 -0
  318. package/dist/serverSession.js +811 -0
  319. package/dist/serverSessionConfig.js +43 -0
  320. package/dist/sessionAdmission.js +53 -0
  321. package/dist/sidecarAdmission.js +103 -0
  322. package/dist/sidecarConfig.js +116 -0
  323. package/dist/sidecarConfigPublication.js +64 -0
  324. package/dist/sidecarHostListener.js +208 -0
  325. package/dist/sidecarIpc.js +205 -0
  326. package/dist/sidecarPeer.js +310 -0
  327. package/dist/sidecarProcessPort.js +28 -0
  328. package/dist/sidecarRuntime.js +168 -0
  329. package/dist/sidecarSelection.js +142 -0
  330. package/dist/sidecarWire.js +178 -0
  331. package/dist/sidecarWrites.js +163 -0
  332. package/dist/simulation.d.ts +391 -0
  333. package/dist/simulation.js +282 -0
  334. package/dist/simulationAuthoring.js +29 -0
  335. package/dist/simulationBytes.js +27 -0
  336. package/dist/simulationConformance.js +305 -0
  337. package/dist/simulationInputHistoryCapture.js +35 -0
  338. package/dist/simulationInputHistoryWire.js +193 -0
  339. package/dist/simulationOptionsWire.js +78 -0
  340. package/dist/simulationRecoveryWire.js +134 -0
  341. package/dist/simulationReplay.js +127 -0
  342. package/dist/simulationSnapshotWire.js +112 -0
  343. package/dist/simulationState.js +178 -0
  344. package/dist/snapshotBlob.js +126 -0
  345. package/dist/snapshotBlobCleanup.js +93 -0
  346. package/dist/snapshotBlobIndex.js +38 -0
  347. package/dist/snapshotBudget.js +80 -0
  348. package/dist/snapshotChain.js +185 -0
  349. package/dist/snapshotErasure.js +172 -0
  350. package/dist/snapshotInspection.js +105 -0
  351. package/dist/snapshotSegmentBlobs.js +58 -0
  352. package/dist/snapshotUploads.js +166 -0
  353. package/dist/socketTransport.js +253 -0
  354. package/dist/spatial.js +104 -0
  355. package/dist/spectatorPolicy.js +26 -0
  356. package/dist/spectatorProducer.js +89 -0
  357. package/dist/startFailureCause.js +4 -0
  358. package/dist/stateCodec.js +658 -0
  359. package/dist/strategies.d.ts +210 -0
  360. package/dist/strategies.js +8 -0
  361. package/dist/strategiesServer.d.ts +286 -0
  362. package/dist/strategiesServer.js +11 -0
  363. package/dist/strategyFixtures.js +182 -0
  364. package/dist/streamFraming.js +122 -0
  365. package/dist/streamTransport.js +266 -0
  366. package/dist/subjectAdmission.js +50 -0
  367. package/dist/subjectPrivacy.js +281 -0
  368. package/dist/subjectPrivacyBinding.js +90 -0
  369. package/dist/systemManifest.js +182 -0
  370. package/dist/tables.js +159 -0
  371. package/dist/testHarness.js +89 -0
  372. package/dist/testing.d.ts +3684 -0
  373. package/dist/testing.js +221 -0
  374. package/dist/testingPorts.js +271 -0
  375. package/dist/testingServer.d.ts +4060 -0
  376. package/dist/testingServer.js +18 -0
  377. package/dist/transform.d.ts +692 -0
  378. package/dist/transform.js +217 -0
  379. package/dist/transform3d.js +118 -0
  380. package/dist/transformCollection.js +24 -0
  381. package/dist/transformCollection3d.js +24 -0
  382. package/dist/transformCollectionCore.js +156 -0
  383. package/dist/transformFrames.js +121 -0
  384. package/dist/transformPrediction3d.js +127 -0
  385. package/dist/transformRules.js +123 -0
  386. package/dist/transformSchemas.js +20 -0
  387. package/dist/transport.js +32 -0
  388. package/dist/transportAuthoring.js +29 -0
  389. package/dist/transportCleanup.js +22 -0
  390. package/dist/transportConformance.js +124 -0
  391. package/dist/transportConnector.js +82 -0
  392. package/dist/transportEndpoints.js +38 -0
  393. package/dist/transportsServer.d.ts +5515 -0
  394. package/dist/transportsServer.js +6 -0
  395. package/dist/viewProjection.js +16 -0
  396. package/dist/web.d.ts +2286 -0
  397. package/dist/web.js +518 -0
  398. package/dist/webTransportClient.js +173 -0
  399. package/dist/wire.d.ts +992 -0
  400. package/dist/wire.js +492 -0
  401. package/dist/withdrawalPort.js +28 -0
  402. package/dist/world.d.ts +1894 -0
  403. package/dist/world.js +333 -0
  404. package/dist/worldActorReceipts.js +48 -0
  405. package/dist/worldActorTransferSnapshot.js +14 -0
  406. package/dist/worldAdmissionPending.js +8 -0
  407. package/dist/worldBoundaryCoordinator.js +148 -0
  408. package/dist/worldCatalog.js +81 -0
  409. package/dist/worldCellAllocation.js +203 -0
  410. package/dist/worldCellDestination.js +68 -0
  411. package/dist/worldCells.js +489 -0
  412. package/dist/worldChange.js +32 -0
  413. package/dist/worldClient.js +664 -0
  414. package/dist/worldClientControl.js +141 -0
  415. package/dist/worldClientPendingInput.js +16 -0
  416. package/dist/worldClientRpc.js +133 -0
  417. package/dist/worldClientRpcRoutes.js +43 -0
  418. package/dist/worldClientSchemas.js +28 -0
  419. package/dist/worldCommands.js +140 -0
  420. package/dist/worldData.js +42 -0
  421. package/dist/worldDefaultBinding.js +377 -0
  422. package/dist/worldDefaultGroupAdmission.js +82 -0
  423. package/dist/worldDefaultGroupAppServices.js +31 -0
  424. package/dist/worldDefaultGroupCompensation.js +109 -0
  425. package/dist/worldDefaultGroupContinuation.js +96 -0
  426. package/dist/worldDefaultGroupControl.js +72 -0
  427. package/dist/worldDefaultGroupMembers.js +85 -0
  428. package/dist/worldDefaultGroups.js +21 -0
  429. package/dist/worldDefaultPending.js +79 -0
  430. package/dist/worldDefaultService.js +245 -0
  431. package/dist/worldEntities.js +2980 -0
  432. package/dist/worldEntityCodec.js +21 -0
  433. package/dist/worldEntityHandoffView.js +154 -0
  434. package/dist/worldGeometry.js +170 -0
  435. package/dist/worldGhostAdmission.js +65 -0
  436. package/dist/worldGhostDestination.js +118 -0
  437. package/dist/worldGhostGateway.js +132 -0
  438. package/dist/worldGhostHandshake.js +108 -0
  439. package/dist/worldGhostHost.js +42 -0
  440. package/dist/worldGhostIngress.js +132 -0
  441. package/dist/worldGhostNeighborhood.js +70 -0
  442. package/dist/worldGhostNeighbors.js +86 -0
  443. package/dist/worldGhostOutbound.js +110 -0
  444. package/dist/worldGhostPublisher.js +216 -0
  445. package/dist/worldGhostReceiver.js +213 -0
  446. package/dist/worldGhostSender.js +146 -0
  447. package/dist/worldGhostSocket.js +78 -0
  448. package/dist/worldGhostWire.js +172 -0
  449. package/dist/worldGroupCommand.js +49 -0
  450. package/dist/worldGroupDeadline.js +115 -0
  451. package/dist/worldGroupPreparation.js +115 -0
  452. package/dist/worldGroupReadyControl.js +128 -0
  453. package/dist/worldGroupSupervisor.js +120 -0
  454. package/dist/worldHandoffMetrics.js +59 -0
  455. package/dist/worldHandoffView.js +100 -0
  456. package/dist/worldHostSource.js +69 -0
  457. package/dist/worldInspectEndpoint.js +250 -0
  458. package/dist/worldInspection.js +109 -0
  459. package/dist/worldInstanceAdmission.js +31 -0
  460. package/dist/worldInstanceAllocation.js +116 -0
  461. package/dist/worldInstanceDestination.js +64 -0
  462. package/dist/worldInstanceExpiry.js +282 -0
  463. package/dist/worldInstanceExpirySupervisor.js +88 -0
  464. package/dist/worldInstanceLifecycle.js +103 -0
  465. package/dist/worldInstanceState.js +52 -0
  466. package/dist/worldInstances.js +478 -0
  467. package/dist/worldJoin.js +56 -0
  468. package/dist/worldLayers.js +151 -0
  469. package/dist/worldLeases.js +78 -0
  470. package/dist/worldManifest.js +25 -0
  471. package/dist/worldMovement.js +63 -0
  472. package/dist/worldPersistence.js +134 -0
  473. package/dist/worldProjection.js +221 -0
  474. package/dist/worldReact.js +110 -0
  475. package/dist/worldRecoveryActor.js +35 -0
  476. package/dist/worldReturnAnchor.js +49 -0
  477. package/dist/worldRoomHooks.js +57 -0
  478. package/dist/worldRoomPool.js +27 -0
  479. package/dist/worldRoomSteps.js +133 -0
  480. package/dist/worldSeatBinding.js +36 -0
  481. package/dist/worldServer.d.ts +6936 -0
  482. package/dist/worldServer.js +48 -0
  483. package/dist/worldSourceSeatPending.js +9 -0
  484. package/dist/worldStrategyFixtures.js +164 -0
  485. package/dist/worldTesting.js +27 -0
  486. package/dist/worldTransitionDefaults.js +198 -0
  487. package/dist/worldTransitionExecutor.js +519 -0
  488. package/dist/worldTransitionGroup.js +113 -0
  489. package/dist/worldTransitionPhysicalSteps.js +40 -0
  490. package/dist/worldTransitionResolver.js +228 -0
  491. package/dist/worldTransitionSeatGroup.js +64 -0
  492. package/dist/worldTransitionSeats.js +260 -0
  493. package/dist/worldTransitionState.js +95 -0
  494. package/dist/worldTransitions.js +101 -0
  495. package/package.json +189 -4
package/dist/actor.js ADDED
@@ -0,0 +1,1474 @@
1
+ import { BudgetExceeded as e, NotRoomMember as t, ProtocolError as n, RoomAuthoringError as r, RoomForbidden as i, RoomFull as a, RoomGone as o, RoomLocked as s } from "./errors.js";
2
+ import { captureWorldData as c } from "./worldData.js";
3
+ import { encodeRoomFrame as l } from "./wire.js";
4
+ import { makeWorldCellMovement as u } from "./worldMovement.js";
5
+ import { captureWorldTargetSeatBinding as d } from "./worldSeatBinding.js";
6
+ import { captureRoomConsumedSeat as f, captureRoomInputReceipts as p } from "./inputReceipts.js";
7
+ import { WorldAdmissionPending as m } from "./worldAdmissionPending.js";
8
+ import { captureWorldActorReceipts as h, worldActorCanonicalJson as g, worldActorFingerprint as _ } from "./worldActorReceipts.js";
9
+ import { captureGeometryWorldView as v } from "./geometryWorldView.js";
10
+ import { Effect as y, Result as b, Schema as x } from "effect";
11
+ //#region src/actor.ts
12
+ var S = (e, t, n) => {
13
+ if (t === void 0) return;
14
+ let i = t(n);
15
+ if (i !== void 0) throw i instanceof Promise && i.catch(() => void 0), new r({
16
+ room: e,
17
+ detail: "Room actor hooks must return undefined; async work belongs outside the tick"
18
+ });
19
+ }, C = (e, t, n) => {
20
+ if (t === void 0) return;
21
+ let i = t(n);
22
+ if (i !== void 0) throw i instanceof Promise && i.catch(() => void 0), new r({
23
+ room: e,
24
+ detail: "Use the asynchronous host lifecycle path for Effect hooks"
25
+ });
26
+ }, w = class {
27
+ id;
28
+ descriptor;
29
+ clock;
30
+ tenantId;
31
+ currentState;
32
+ lastGoodState;
33
+ lastGoodTick = 0;
34
+ options;
35
+ members = /* @__PURE__ */ new Map();
36
+ grace = /* @__PURE__ */ new Map();
37
+ inputs = [];
38
+ outbox = [];
39
+ clientOperations = [];
40
+ schedules = /* @__PURE__ */ new Map();
41
+ extensionDurationMs = Object.create(null);
42
+ extensionOverruns = Object.create(null);
43
+ tick = 0;
44
+ droppedTicks = 0;
45
+ commandSeq = 0;
46
+ epoch;
47
+ nextTickAt;
48
+ emptyAt;
49
+ locked = !1;
50
+ disposed = !1;
51
+ publicationHeldAt = null;
52
+ drainFrozen = !1;
53
+ drainAt = null;
54
+ retiring = !1;
55
+ faulted = !1;
56
+ ticking = !1;
57
+ lastNow = -1;
58
+ app;
59
+ scheduler;
60
+ worldPreviews = /* @__PURE__ */ new Set();
61
+ worldReceipts = /* @__PURE__ */ new Map();
62
+ deferredWorldLeaves = /* @__PURE__ */ new Map();
63
+ worldMovement;
64
+ worldMovementClamps = 0;
65
+ worldMovementMargin = 0;
66
+ worldMovementIntents = Object.freeze([]);
67
+ worldFinalizationHold = null;
68
+ worldPublishedTransitions = /* @__PURE__ */ new Set();
69
+ lifecycleTail = Promise.resolve();
70
+ lifecycleRequests = 0;
71
+ lifecycleActive = !1;
72
+ geometry;
73
+ constructor(t, n, i, a, o, s, c = {
74
+ epoch: 0,
75
+ commandCursor: 0
76
+ }, l) {
77
+ if (this.id = t, this.descriptor = n, this.clock = o, this.tenantId = s, this.geometry = l === void 0 ? void 0 : v(l, s), !s.trim()) throw new r({
78
+ room: n.name,
79
+ detail: "Every actor requires its explicit tenant identity"
80
+ });
81
+ if (![
82
+ c.epoch,
83
+ c.commandCursor,
84
+ c.tick ?? 0
85
+ ].every((e) => Number.isSafeInteger(e) && e >= 0)) throw new r({
86
+ room: n.name,
87
+ detail: "Actor recovery epoch and command cursor must be nonnegative safe integers"
88
+ });
89
+ for (let e of h(c.worldReceipts ?? [], n.world?.maxPendingTransitions ?? 128)) {
90
+ if (!n.world) throw new r({
91
+ room: n.name,
92
+ detail: "World receipts require the original configured hooks"
93
+ });
94
+ this.worldReceipts.set(e.requestId, e);
95
+ }
96
+ this.epoch = c.epoch, this.commandSeq = c.commandCursor, this.tick = c.tick ?? 0, this.lastGoodTick = this.tick;
97
+ let u = x.decodeUnknownSync(x.toType(n.state))(i);
98
+ this.currentState = structuredClone(u), this.options = structuredClone(x.decodeUnknownSync(x.toType(n.options))(a));
99
+ let d = this.now();
100
+ this.nextTickAt = d + 1e3 / n.tickRate, this.emptyAt = d, this.app = Object.freeze({
101
+ publish: (e, t, n) => this.stage("publish", e, t, n.key),
102
+ run: (e, t) => this.stage("run", e, t)
103
+ }), this.scheduler = Object.freeze({
104
+ after: (e, t) => this.schedule(e, t, !1),
105
+ every: (e, t) => this.schedule(e, t, !0),
106
+ cancel: (e) => {
107
+ this.schedules.delete(e);
108
+ }
109
+ });
110
+ for (let e of n.extensions) for (let t of e.fields) if (typeof this.state != "object" || this.state === null || !Object.hasOwn(this.state, t)) throw new r({
111
+ room: n.name,
112
+ detail: `Extension ${e.name} requires state field ${t}`
113
+ });
114
+ if ((c.schedules?.length ?? 0) > n.budgets.maxScheduledHooks) throw new e({
115
+ budget: "maxScheduledHooks",
116
+ limit: n.budgets.maxScheduledHooks
117
+ });
118
+ for (let e of c.schedules ?? []) {
119
+ if (!e.label.trim() || this.schedules.has(e.label) || !Number.isFinite(e.remainingMs) || e.remainingMs < 0 || e.intervalMs !== null && (!Number.isFinite(e.intervalMs) || e.intervalMs <= 0)) throw new r({
120
+ room: n.name,
121
+ detail: "Invalid recovered schedule"
122
+ });
123
+ this.schedules.set(e.label, {
124
+ label: e.label,
125
+ at: d + e.remainingMs,
126
+ interval: e.intervalMs
127
+ });
128
+ }
129
+ S(n.name, c.rehydrate ? n.onRehydrate : n.onCreate, {
130
+ state: this.state,
131
+ options: this.options,
132
+ app: this.app,
133
+ clock: o,
134
+ scheduler: this.scheduler,
135
+ ...this.geometry ? { geometry: this.geometry } : {}
136
+ }), x.decodeUnknownSync(x.toType(n.state))(this.state), this.lastGoodState = structuredClone(this.state);
137
+ }
138
+ get state() {
139
+ return this.currentState;
140
+ }
141
+ now() {
142
+ let e = this.clock.now();
143
+ if (!Number.isFinite(e) || e < 0 || e < this.lastNow) throw new r({
144
+ room: this.descriptor.name,
145
+ detail: "The injected monotonic clock must return finite nonnegative nondecreasing time"
146
+ });
147
+ return this.lastNow = e, e;
148
+ }
149
+ ensureOpen() {
150
+ if (this.disposed || this.faulted || this.retiring || this.drainFrozen) throw new o({ roomId: this.id });
151
+ }
152
+ stage(t, n, i, a) {
153
+ if (this.ensureOpen(), !n.trim() || t === "publish" && !a?.trim()) throw new r({
154
+ room: this.descriptor.name,
155
+ detail: "App commands require a name and publishes require a key"
156
+ });
157
+ if (this.outbox.length >= this.descriptor.budgets.maxOutboxCommands) throw new e({
158
+ budget: "maxOutboxCommands",
159
+ limit: this.descriptor.budgets.maxOutboxCommands
160
+ });
161
+ if (this.commandSeq >= 2 ** 53 - 1) throw new r({
162
+ room: this.descriptor.name,
163
+ detail: "Room command cursor is exhausted"
164
+ });
165
+ let o = `${this.id}:${this.epoch}:${++this.commandSeq}`;
166
+ return this.outbox.push(Object.freeze({
167
+ requestId: o,
168
+ kind: t,
169
+ name: n,
170
+ payload: structuredClone(i),
171
+ ...a === void 0 ? {} : { key: a }
172
+ })), o;
173
+ }
174
+ schedule(t, n, i) {
175
+ if (this.ensureOpen(), !Number.isFinite(t) || t <= 0 || !n.trim()) throw new r({
176
+ room: this.descriptor.name,
177
+ detail: "Scheduled hooks require a positive duration and nonempty label"
178
+ });
179
+ if (!this.schedules.has(n) && this.schedules.size >= this.descriptor.budgets.maxScheduledHooks) throw new e({
180
+ budget: "maxScheduledHooks",
181
+ limit: this.descriptor.budgets.maxScheduledHooks
182
+ });
183
+ this.schedules.set(n, {
184
+ label: n,
185
+ at: (this.publicationHeldAt ?? this.now()) + t,
186
+ interval: i ? t : null
187
+ });
188
+ }
189
+ join(e) {
190
+ this.assertSynchronousLifecycle();
191
+ let t = this.prepareJoin(e);
192
+ this.mutateMember(() => C(this.descriptor.name, this.descriptor.onJoin, t.context(this.state))), t.commit();
193
+ }
194
+ joinAsync(e, t) {
195
+ return this.serializeLifecycle(async () => {
196
+ let n = this.prepareJoin(e);
197
+ await this.mutateMemberAsync((e) => this.descriptor.onJoin?.(n.context(e)), t), n.commit();
198
+ });
199
+ }
200
+ joinReservedAsync(e, t, r, i) {
201
+ let a = f(t);
202
+ if (a.worldTarget) throw new n({ detail: "World target Seat requires transition-aware actor admission" });
203
+ if (typeof e?.send != "function" || typeof e.kick != "function") throw new n({ detail: "Reserved membership requires actual client callbacks" });
204
+ let o = Object.freeze({
205
+ ...e,
206
+ send: e.send.bind(e),
207
+ kick: e.kick.bind(e)
208
+ });
209
+ return this.serializeLifecycle(async () => {
210
+ let e = i ? await i() ?? void 0 : void 0, t = this.prepareJoin(o, !1, !0, a.lastAppliedSeq);
211
+ await this.mutateMemberAsync((n) => this.descriptor.onJoin?.({
212
+ ...t.context(n),
213
+ ...e === void 0 ? {} : { world: e }
214
+ }), r, !0, void 0, i === void 0 ? void 0 : async () => {
215
+ await i();
216
+ }), t.commit();
217
+ });
218
+ }
219
+ joinWorldReservedAsync(t, r, i, a) {
220
+ let o = f(r), s = o.worldTarget;
221
+ if (!s || !this.descriptor.world || typeof i != "function" || typeof t?.send != "function" || typeof t.kick != "function") throw new n({ detail: "Pending World membership requires bound Seat and actual Host admission" });
222
+ let c = Object.freeze({
223
+ ...t,
224
+ send: t.send.bind(t),
225
+ kick: t.kick.bind(t)
226
+ });
227
+ return this.serializeLifecycle(async () => {
228
+ if (a?.aborted) throw new n({ detail: "World membership admission aborted" });
229
+ let t = this.prepareJoin(c, !1, !0, o.lastAppliedSeq, s, o.discardedThrough ?? -1), r = await i();
230
+ if (a?.aborted) throw new n({ detail: "World membership admission aborted" });
231
+ let l = r === "settled" || r === "committed" && this.worldPublishedTransitions.has(s.transitionId);
232
+ if (!l && [...this.members.values()].filter((e) => e.worldPending).length >= (this.descriptor.world.maxPendingTransitions ?? 128)) throw new e({
233
+ budget: "worldPendingMembers",
234
+ limit: this.descriptor.world.maxPendingTransitions ?? 128
235
+ });
236
+ if (l && (this.assertWorldMemberEntity(s), !t.discardsPersisted)) throw new m();
237
+ t.commit();
238
+ let u = this.members.get(c.sessionId);
239
+ l && (u.worldPending = !1, await this.worldMemberEntered(u.client, s.entityId, a));
240
+ });
241
+ }
242
+ async worldMemberEntered(e, t, n) {
243
+ let r = this.descriptor.world?.onMemberEnter;
244
+ r && await this.mutateMemberAsync((n) => r({
245
+ state: n,
246
+ client: e,
247
+ entityId: t
248
+ }), n);
249
+ }
250
+ worldEntityPoint(e) {
251
+ let t = this.descriptor.world?.movement, n = Object.getOwnPropertyDescriptor(this.lastGoodState, "entities"), r = n && "value" in n ? n.value : void 0, i = t && typeof e == "string" && r && typeof r == "object" ? Object.getOwnPropertyDescriptor(r, e) : void 0;
252
+ if (!t || !i || !("value" in i)) return null;
253
+ try {
254
+ let e = t.position(c(i.value, t.maxBytesPerTick));
255
+ if (e instanceof Promise) return e.catch(() => void 0), null;
256
+ let n = c(e, 128);
257
+ return Array.isArray(n) && n.length === 2 && n.every((e) => typeof e == "number" && Number.isFinite(e)) ? Object.freeze([n[0], n[1]]) : null;
258
+ } catch {
259
+ return null;
260
+ }
261
+ }
262
+ activateWorldReservedAsync(e, t) {
263
+ let r = d(e);
264
+ if (typeof t != "function") throw new n({ detail: "World member activation requires actual Host authority" });
265
+ return this.serializeLifecycle(async () => {
266
+ this.ensureOpen();
267
+ let e = this.worldReceipts.get(`${r.transitionId}:enter`), i = Object.getOwnPropertyDescriptor(this.state, "entities"), a = i && "value" in i && i.value && typeof i.value == "object" ? Object.getOwnPropertyDescriptor(i.value, r.entityId) : void 0;
268
+ if (!this.descriptor.world || e?.operation !== "enter" || !a || !("value" in a) || a.value?.id !== r.entityId) throw new n({ detail: "World member activation lacks actual target enter" });
269
+ let o = [...this.members.values()].filter((e) => e.worldTarget?.transitionId === r.transitionId);
270
+ if (o.some((e) => JSON.stringify(e.worldTarget) !== JSON.stringify(r))) throw new n({ detail: "World member activation binding changed" });
271
+ if (await t(), o.some((e) => e.lastDiscardedSeq > e.checkpointedDiscardedSeq)) throw new n({ detail: "Pending World input discard must be checkpointed before activation" });
272
+ this.worldPublishedTransitions.add(r.transitionId);
273
+ for (let e of o) e.worldPending = !1;
274
+ for (let e of o) await this.worldMemberEntered(e.client, r.entityId);
275
+ });
276
+ }
277
+ assertWorldMemberEntity(e) {
278
+ let t = Object.getOwnPropertyDescriptor(this.state, "entities"), r = t && "value" in t && t.value && typeof t.value == "object" ? Object.getOwnPropertyDescriptor(t.value, e.entityId) : void 0;
279
+ if (!this.descriptor.world || !r || !("value" in r) || r.value?.id !== e.entityId) throw new n({ detail: "World reconnect lacks the actual owned target entity" });
280
+ }
281
+ isWorldPending(e) {
282
+ let t = this.members.get(e);
283
+ return t?.worldPending === !0 || t?.worldDeparture !== void 0;
284
+ }
285
+ joinBotAsync(e, t = !0, r) {
286
+ if (typeof t != "boolean") return Promise.reject(new n({ detail: "Bot capacity policy must be a boolean" }));
287
+ let i = Object.freeze({
288
+ sessionId: e.sessionId,
289
+ subjectId: e.subjectId,
290
+ tenantId: e.tenantId,
291
+ send: e.send.bind(e),
292
+ kick: e.kick.bind(e)
293
+ });
294
+ return this.serializeLifecycle(async () => {
295
+ let e = this.prepareJoin(i, !0, t);
296
+ await this.mutateMemberAsync((t) => this.descriptor.onJoin?.(e.context(t)), r), e.commit();
297
+ let n = this.members.get(i.sessionId);
298
+ return Object.freeze({
299
+ sessionId: i.sessionId,
300
+ isCurrent: () => this.members.get(i.sessionId) === n,
301
+ input: (e, t, r, a) => {
302
+ if (this.members.get(i.sessionId) !== n) throw new o({ roomId: this.id });
303
+ return this.input(i.sessionId, e, t, r, a);
304
+ },
305
+ leave: (e) => this.serializeLifecycle(async () => {
306
+ if (this.members.get(i.sessionId) !== n) return;
307
+ let t = this.prepareLeave(i.sessionId, "left");
308
+ await this.mutateMemberAsync((e) => this.descriptor.onLeave?.(t.context(e)), e), t.commit();
309
+ })
310
+ });
311
+ });
312
+ }
313
+ playerCount() {
314
+ return [...this.members.values()].filter((e) => e.client.countsAsPlayer !== !1).length;
315
+ }
316
+ availablePlayerSlots() {
317
+ return this.pruneGrace(this.now()), Math.max(0, this.descriptor.maxClients - this.playerCount() - this.grace.size);
318
+ }
319
+ monotonicNow() {
320
+ return this.now();
321
+ }
322
+ roster() {
323
+ return Object.freeze([...this.members.values()].map(({ client: e }) => Object.freeze({
324
+ sessionId: e.sessionId,
325
+ subjectId: e.subjectId,
326
+ tenantId: e.tenantId,
327
+ isBot: e.isBot === !0,
328
+ countsAsPlayer: e.countsAsPlayer !== !1
329
+ })));
330
+ }
331
+ humanAdmissionNeedsReplacement(e) {
332
+ let { resumed: t } = this.prepareClientIdentity(e, !1);
333
+ return this.playerCount() + this.grace.size - +!!t >= this.descriptor.maxClients;
334
+ }
335
+ prepareClientIdentity(e, t) {
336
+ if (this.ensureOpen(), !e || ![e.sessionId, e.tenantId].every((e) => typeof e == "string" && e.length > 0 && e.length <= 191) || e.subjectId !== null && (typeof e.subjectId != "string" || !e.subjectId || e.subjectId.length > 191)) throw new n({ detail: "Room membership requires bounded trusted identity" });
337
+ if (!t && (e.isBot === !0 || e.countsAsPlayer === !1)) throw new n({ detail: "Bot/NPC classification requires trusted local admission" });
338
+ if (e.tenantId !== this.tenantId || e.subjectId === null && this.descriptor.auth !== "public") throw new i({ roomId: this.id });
339
+ let a = this.now();
340
+ this.pruneGrace(a);
341
+ let o = this.grace.get(e.sessionId);
342
+ if (t && o) throw new n({ detail: "A local bot cannot resume a socket member grace seat" });
343
+ if (o && o.subjectId !== e.subjectId) throw new i({ roomId: this.id });
344
+ if (this.locked && !o) throw new s({ roomId: this.id });
345
+ if (this.members.has(e.sessionId)) throw new r({
346
+ room: this.descriptor.name,
347
+ detail: "A session is already connected"
348
+ });
349
+ return {
350
+ now: a,
351
+ resumed: o
352
+ };
353
+ }
354
+ prepareJoin(t, r = !1, i = !0, o = -1, s, c = -1) {
355
+ let { now: l, resumed: u } = this.prepareClientIdentity(t, r);
356
+ if (u?.worldDeparture) throw new n({ detail: "Departed World source membership awaits transfer compensation" });
357
+ if (u?.worldTarget && JSON.stringify(u.worldTarget) !== JSON.stringify(s)) throw new n({ detail: "World reconnect cannot discard its pending membership binding" });
358
+ if (i && this.playerCount() + this.grace.size - +!!u >= this.descriptor.maxClients) throw new a({ roomId: this.id });
359
+ if (!i && this.members.size - this.playerCount() >= this.descriptor.budgets.maxNpcs) throw new e({
360
+ budget: "maxNpcs",
361
+ limit: this.descriptor.budgets.maxNpcs
362
+ });
363
+ let d = Object.freeze({
364
+ sessionId: t.sessionId,
365
+ subjectId: t.subjectId,
366
+ tenantId: t.tenantId,
367
+ ...r ? {
368
+ isBot: !0,
369
+ countsAsPlayer: i
370
+ } : {},
371
+ ...t.attributes === void 0 ? {} : { attributes: Object.freeze({ ...t.attributes }) },
372
+ send: (e, r) => {
373
+ let i = this.descriptor.messages[e];
374
+ if (!i || i.direction === "client") throw new n({ detail: "Channel is not server-sendable" });
375
+ let a = structuredClone(x.decodeUnknownSync(i.schema)(r));
376
+ this.stageClientOperation(() => t.send(e, a));
377
+ },
378
+ kick: (e) => {
379
+ this.stageClientOperation(() => t.kick(e));
380
+ }
381
+ });
382
+ return {
383
+ discardsPersisted: (u?.discardedThrough ?? -1) <= c,
384
+ context: (e) => ({
385
+ state: e,
386
+ options: structuredClone(this.options),
387
+ client: d,
388
+ app: this.app,
389
+ clock: this.clock,
390
+ scheduler: this.scheduler,
391
+ ...this.geometry ? { geometry: this.geometry } : {}
392
+ }),
393
+ commit: () => {
394
+ this.grace.delete(t.sessionId);
395
+ let e = Math.max(o, u?.lastAppliedSeq ?? -1);
396
+ this.members.set(t.sessionId, {
397
+ client: d,
398
+ lastSeq: Math.max(e, c, u?.discardedThrough ?? -1),
399
+ lastAppliedSeq: e,
400
+ lastDiscardedSeq: Math.max(c, u?.discardedThrough ?? -1),
401
+ checkpointedDiscardedSeq: c,
402
+ ...s ? {
403
+ worldTarget: s,
404
+ worldPending: !0
405
+ } : {},
406
+ inputTokens: this.descriptor.budgets.burst,
407
+ byteTokens: this.descriptor.budgets.bytesPerSecond,
408
+ replenishedAt: l
409
+ }), this.emptyAt = null;
410
+ }
411
+ };
412
+ }
413
+ leave(e, t = "left") {
414
+ this.assertSynchronousLifecycle();
415
+ let n = this.prepareLeave(e, t);
416
+ n.pending || this.mutateMember(() => C(this.descriptor.name, this.descriptor.onLeave, n.context(this.state))), n.commit();
417
+ }
418
+ leaveAsync(e, n = "left", r) {
419
+ return this.serializeLifecycle(async () => {
420
+ if (this.worldFinalizationHold) {
421
+ if (!this.members.has(e)) throw new t({ sessionId: e });
422
+ this.deferredWorldLeaves.set(e, n);
423
+ return;
424
+ }
425
+ let i = this.prepareLeave(e, n);
426
+ i.pending || await this.mutateMemberAsync((e) => this.descriptor.onLeave?.(i.context(e)), r), i.commit();
427
+ }, () => this.worldFinalizationHold?.requestId);
428
+ }
429
+ prepareLeave(e, r) {
430
+ this.ensureOpen();
431
+ let i = this.members.get(e);
432
+ if (!i) throw new t({ sessionId: e });
433
+ if (i.client.isBot && r === "reconnecting") throw new n({ detail: "Local bots do not own socket reconnect grace" });
434
+ return {
435
+ pending: i.worldPending === !0,
436
+ context: (e) => ({
437
+ state: e,
438
+ options: structuredClone(this.options),
439
+ client: i.client,
440
+ app: this.app,
441
+ clock: this.clock,
442
+ scheduler: this.scheduler,
443
+ ...this.geometry ? { geometry: this.geometry } : {},
444
+ reason: r
445
+ }),
446
+ commit: () => {
447
+ this.members.delete(e), r === "reconnecting" ? this.grace.set(e, {
448
+ subjectId: i.client.subjectId,
449
+ expiresAt: this.now() + this.descriptor.reconnect.graceMs,
450
+ lastAppliedSeq: i.lastAppliedSeq,
451
+ ...i.worldDeparture ? { worldDeparture: i.worldDeparture } : {},
452
+ ...i.worldTarget ? {
453
+ worldTarget: i.worldTarget,
454
+ discardedThrough: i.lastDiscardedSeq
455
+ } : {}
456
+ }) : this.grace.delete(e);
457
+ for (let t = this.inputs.length - 1; t >= 0; t--) this.inputs[t]?.client.sessionId === e && this.inputs.splice(t, 1);
458
+ this.members.size === 0 && (this.emptyAt = this.now());
459
+ }
460
+ };
461
+ }
462
+ assertWorldArrival(e) {
463
+ if (e !== void 0) {
464
+ if (!e || Object.keys(e).sort().join(",") !== "at,epoch,layer,roomId,worldId,zoneId" || e.roomId !== this.id || e.epoch !== this.epoch || ![
465
+ e.worldId,
466
+ e.zoneId,
467
+ e.roomId
468
+ ].every((e) => typeof e == "string" && /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,190}$/.test(e)) || !Number.isSafeInteger(e.layer) || e.layer < 1 || !Array.isArray(e.at) || e.at.length !== 2 || !e.at.every(Number.isFinite)) throw new n({ detail: "World arrival must name this actual target actor" });
469
+ this.worldMovement && this.worldMovement.constrain(e.at, e.at);
470
+ }
471
+ }
472
+ enterWorldDraft(e, t, r, i) {
473
+ let a = this.descriptor.world, o = t.arrival, s = () => {
474
+ if (!o || !a.movement) return;
475
+ this.assertWorldHookResult(e, "enter", t.entity.id);
476
+ let r = Object.getOwnPropertyDescriptor(e, "entities").value, s = Object.getOwnPropertyDescriptor(r, t.entity.id), l = structuredClone(s.value), u = a.movement.move(l, o.at);
477
+ if (u !== void 0) throw u instanceof Promise && u.catch(() => void 0), new n({ detail: "World arrival movement must return synchronous void" });
478
+ let d = c(l, i), f = a.movement.position(d);
479
+ if (f instanceof Promise) throw f.catch(() => void 0), new n({ detail: "World arrival position must be synchronous" });
480
+ if (d.id !== t.entity.id || g(c(f, 128)) !== g(o.at)) throw new n({ detail: "World arrival writer did not establish the admitted target position" });
481
+ r[t.entity.id] = l;
482
+ }, l = a.onEnter({
483
+ state: e,
484
+ phase: r,
485
+ entity: t.entity,
486
+ from: t.location,
487
+ ...t.requestId === void 0 ? {} : { requestId: t.requestId },
488
+ ...o ? { to: o } : {}
489
+ });
490
+ if (l === void 0) s();
491
+ else {
492
+ if (!y.isEffect(l)) throw l instanceof Promise && l.catch(() => void 0), new n({ detail: "World entry hooks require synchronous void or Effect" });
493
+ return l.pipe(y.flatMap((e) => e === void 0 ? y.sync(s) : y.fail(new n({ detail: "World entry Effect must produce void" }))));
494
+ }
495
+ }
496
+ previewWorldEnter(t, r, i) {
497
+ let a = c(t, r);
498
+ return a.epoch !== this.epoch || !Number.isSafeInteger(a.epoch) || a.epoch < 1 || typeof a.requestId != "string" || !a.requestId || a.requestId.length > 191 || !a.entity || typeof a.entity.id != "string" || !a.entity.id || a.entity.id.length > 191 || !a.location || Object.keys(a.location).length !== 6 || !Array.isArray(a.location.at) || a.location.at.length !== 2 || !a.location.at.every((e) => typeof e == "number" && Number.isFinite(e)) || ![
499
+ a.location.worldId,
500
+ a.location.zoneId,
501
+ a.location.roomId
502
+ ].every((e) => typeof e == "string" && e.length > 0 && e.length <= 191) || ![a.location.epoch, a.location.layer].every((e) => Number.isSafeInteger(e) && e > 0) ? Promise.reject(new n({ detail: "World preview requires the actual actor epoch and bounded request/entity/location" })) : this.serializeLifecycle(async () => {
503
+ this.ensureOpen();
504
+ let t = this.descriptor.world;
505
+ if (!t) throw new n({ detail: "World preview requires configured actor hooks" });
506
+ if (this.assertWorldArrival(a.arrival), this.assertWorldEnterVacant(a.entity.id), !this.worldPreviews.has(a.requestId) && this.worldPreviews.size + this.worldReceipts.size >= (t.maxPendingTransitions ?? 128)) throw new e({
507
+ budget: "worldActorReceipts",
508
+ limit: t.maxPendingTransitions ?? 128
509
+ });
510
+ await this.mutateMemberAsync((e) => this.enterWorldDraft(e, a, "prepare", r), i, !1, (e) => this.assertWorldHookResult(e, "enter", a.entity.id)), this.worldPreviews.add(a.requestId);
511
+ });
512
+ }
513
+ applyWorldHook(t, r, i, a, o, s = !1, l, u = !1, d) {
514
+ let f = c(r, i), p = l === void 0 ? void 0 : c(l, i), m = d === void 0 ? [] : c(d, 1048576);
515
+ if (!Array.isArray(m) || m.length > 4096 || m.length > 0 && (t !== "enter" || !o)) return Promise.reject(new n({ detail: "World promotion requires bounded guarded target entry" }));
516
+ let v = f.location;
517
+ return ![
518
+ "enter",
519
+ "exit",
520
+ "ghost"
521
+ ].includes(t) || f.epoch !== this.epoch || !Number.isSafeInteger(f.epoch) || f.epoch < 1 || !f.entity || typeof f.entity.id != "string" || !f.entity.id || f.entity.id.length > 191 || f.requestId !== void 0 && (typeof f.requestId != "string" || !f.requestId || f.requestId.length > 191) || !v || Object.keys(v).length !== 6 || ![
522
+ v.worldId,
523
+ v.zoneId,
524
+ v.roomId
525
+ ].every((e) => typeof e == "string" && e.length > 0 && e.length <= 191) || ![v.epoch, v.layer].every((e) => Number.isSafeInteger(e) && e > 0) || !Array.isArray(v.at) || v.at.length !== 2 || !v.at.every((e) => typeof e == "number" && Number.isFinite(e)) ? Promise.reject(new n({ detail: "World hook lost its actual actor epoch or entity identity" })) : this.serializeLifecycle(async () => {
526
+ this.ensureOpen();
527
+ let r = this.descriptor.world;
528
+ if (!r) throw new n({ detail: "Room has no configured World lifecycle hooks" });
529
+ if (f.arrival && (t !== "enter" || s || !o)) throw new n({ detail: "World arrival belongs only to guarded target entry" });
530
+ if (this.assertWorldArrival(f.arrival), u && (t !== "ghost" || !o || !/^wghost-[0-9a-f]{64}:ghost$/.test(f.requestId ?? ""))) throw new n({ detail: "Retained ghost projection requires guarded streaming identity" });
531
+ let l = f.requestId === void 0 ? void 0 : await _({
532
+ roomId: this.id,
533
+ tenantId: this.tenantId,
534
+ operation: t,
535
+ entity: f.entity,
536
+ location: f.location,
537
+ ...f.arrival ? { arrival: f.arrival } : {}
538
+ }), d, v;
539
+ if (s) {
540
+ if (t !== "enter" || !f.requestId?.endsWith(":enter") || !o) throw new n({ detail: "World compensation requires guarded canonical enter receipt" });
541
+ d = `${f.requestId.slice(0, -6)}:exit`;
542
+ let e = this.worldReceipts.get(d);
543
+ if (e && (e.operation !== "exit" || e.fingerprint !== await _({
544
+ roomId: this.id,
545
+ tenantId: this.tenantId,
546
+ operation: "exit",
547
+ entity: f.entity,
548
+ location: f.location
549
+ }))) throw new n({ detail: "World compensation conflicts with captured source exit" });
550
+ if (!e && !this.worldReceipts.has(f.requestId)) throw new n({ detail: "World compensation requires its retained exit receipt" });
551
+ }
552
+ if (p !== void 0) {
553
+ if (t !== "ghost" || s || !o || !f.requestId?.endsWith(":ghost") || p.epoch !== this.epoch || !p.requestId?.endsWith(":ghost") || p.requestId === f.requestId || p.entity?.id !== f.entity.id) throw new n({ detail: "Ghost replacement requires exact prior projection and current authority" });
554
+ v = p.requestId;
555
+ let e = this.worldReceipts.get(v);
556
+ if (e && (e.operation !== "ghost" || e.fingerprint !== await _({
557
+ roomId: this.id,
558
+ tenantId: this.tenantId,
559
+ operation: "ghost",
560
+ entity: p.entity,
561
+ location: p.location
562
+ }))) throw new n({ detail: "Ghost replacement differs from its retained predecessor" });
563
+ if (!e && !this.worldReceipts.has(f.requestId)) throw new n({ detail: "Ghost replacement predecessor is absent" });
564
+ if (e && this.worldReceipts.has(f.requestId)) throw new n({ detail: "Ghost replacement has contradictory receipts" });
565
+ }
566
+ let b = /* @__PURE__ */ new Set();
567
+ for (let e of m) {
568
+ let t = c(e, i);
569
+ if (t.epoch !== this.epoch || t.entity?.id !== f.entity.id || !t.requestId?.endsWith(":ghost") || b.has(t.requestId)) throw new n({ detail: "World promotion escaped its exact target entity" });
570
+ let r = this.worldReceipts.get(t.requestId);
571
+ if (!r) {
572
+ if (f.requestId && this.worldReceipts.get(f.requestId)?.operation === "enter") continue;
573
+ throw new n({ detail: "World promotion requires its retained ghost receipt" });
574
+ }
575
+ if (r.operation !== "ghost" || r.fingerprint !== await _({
576
+ roomId: this.id,
577
+ tenantId: this.tenantId,
578
+ operation: "ghost",
579
+ entity: t.entity,
580
+ location: t.location
581
+ })) throw new n({ detail: "World promotion differs from its retained projection" });
582
+ b.add(t.requestId);
583
+ }
584
+ if (f.requestId !== void 0) {
585
+ let i = this.worldReceipts.get(f.requestId);
586
+ if (i) {
587
+ if (i.operation !== t || i.fingerprint !== l) throw new n({ detail: "World actor request conflicts with its retained receipt" });
588
+ if (u && !i.projection) {
589
+ let e = {
590
+ ...i,
591
+ projection: {
592
+ entity: f.entity,
593
+ location: f.location
594
+ }
595
+ };
596
+ h([...this.worldReceipts.values()].filter((e) => e.requestId !== i.requestId).concat(e)), await o(), this.worldReceipts.set(i.requestId, Object.freeze(e));
597
+ }
598
+ return;
599
+ }
600
+ if (this.worldReceipts.size + this.worldPreviews.size - b.size - (t === "enter" && this.worldPreviews.has(f.requestId) ? 1 : 0) >= (r.maxPendingTransitions ?? 128) && !(d && this.worldReceipts.has(d)) && !(v && this.worldReceipts.has(v))) throw new e({
601
+ budget: "worldActorReceipts",
602
+ limit: r.maxPendingTransitions ?? 128
603
+ });
604
+ }
605
+ let x = f.requestId === void 0 ? void 0 : Object.freeze({
606
+ requestId: f.requestId,
607
+ operation: t,
608
+ fingerprint: l,
609
+ ...u ? { projection: {
610
+ entity: f.entity,
611
+ location: f.location
612
+ } } : {}
613
+ });
614
+ if (x && h([...this.worldReceipts.values()].filter((e) => e.requestId !== d && e.requestId !== v && !b.has(e.requestId)).concat(x)), t === "enter" && this.assertWorldEnterVacant(f.entity.id), t === "exit") {
615
+ let e = Object.getOwnPropertyDescriptor(this.state, "entities"), t = e && "value" in e && e.value && typeof e.value == "object" ? Object.getOwnPropertyDescriptor(e.value, f.entity.id) : void 0;
616
+ if (!t || !("value" in t) || await _(c(t.value, i)) !== await _(f.entity)) throw new n({ detail: "World source entity changed since transition capture" });
617
+ }
618
+ await this.mutateMemberAsync((e) => {
619
+ let a = {
620
+ state: e,
621
+ phase: s ? "rollback" : "commit",
622
+ entity: f.entity,
623
+ ...f.requestId === void 0 ? {} : { requestId: f.requestId }
624
+ };
625
+ if (t === "enter" && b.size > 0) {
626
+ let t = this, a = (e) => y.suspend(() => {
627
+ let t = e();
628
+ if (t === void 0) return y.void;
629
+ if (!y.isEffect(t)) throw t instanceof Promise && t.catch(() => void 0), new n({ detail: "World promotion hooks require synchronous void or Effect" });
630
+ return t.pipe(y.flatMap((e) => e === void 0 ? y.void : y.fail(new n({ detail: "World promotion Effects must produce void" }))));
631
+ });
632
+ return y.gen(function* () {
633
+ for (let n of m) b.has(n.requestId) && (yield* a(() => r.onGhost({
634
+ state: e,
635
+ phase: "rollback",
636
+ entity: n.entity,
637
+ requestId: n.requestId
638
+ })), t.assertWorldHookResult(e, "ghost", f.entity.id));
639
+ yield* a(() => t.enterWorldDraft(e, f, s ? "rollback" : "commit", i));
640
+ });
641
+ }
642
+ return t === "enter" ? this.enterWorldDraft(e, f, s ? "rollback" : "commit", i) : t === "exit" ? r.onExit({
643
+ ...a,
644
+ to: f.location
645
+ }) : r.onGhost(a);
646
+ }, a, !0, (e) => {
647
+ if (this.assertWorldHookResult(e, t, f.entity.id), s) {
648
+ let t = Object.getOwnPropertyDescriptor(e, "entities"), r = Object.getOwnPropertyDescriptor(t.value, f.entity.id);
649
+ if (g(c(r.value, i)) !== g(f.entity)) throw new n({ detail: "World rollback hook must restore the exact captured source entity" });
650
+ }
651
+ }, o);
652
+ for (let e of b) this.worldReceipts.delete(e);
653
+ if (d) {
654
+ this.worldReceipts.delete(d);
655
+ for (let e of this.members.values()) e.worldDeparture === d && (delete e.worldDeparture, e.lastSeq = Math.max(e.lastAppliedSeq, e.lastDiscardedSeq));
656
+ for (let [e, t] of this.grace) if (t.worldDeparture === d) {
657
+ let { worldDeparture: n, ...r } = t;
658
+ this.grace.set(e, r);
659
+ }
660
+ }
661
+ v && this.worldReceipts.delete(v), x && this.worldReceipts.set(x.requestId, x), t === "enter" && f.requestId !== void 0 && this.worldPreviews.delete(f.requestId);
662
+ }, s && f.requestId?.endsWith(":enter") ? `${f.requestId.slice(0, -6)}:exit` : t === "exit" && o ? f.requestId : void 0);
663
+ }
664
+ assertWorldHookResult(e, t, r) {
665
+ let i = Object.getOwnPropertyDescriptor(e, "entities"), a = i && "value" in i && i.value && typeof i.value == "object" ? Object.getOwnPropertyDescriptor(i.value, r) : void 0;
666
+ if (t === "ghost") {
667
+ let e = Object.getOwnPropertyDescriptor(this.state, "entities"), t = e && "value" in e && e.value && typeof e.value == "object" ? Object.getOwnPropertyDescriptor(e.value, r) : void 0;
668
+ if (g(t && "value" in t ? t.value : null) !== g(a && "value" in a ? a.value : null)) throw new n({ detail: "World ghost hook cannot change authoritative entity ownership or state" });
669
+ } else if (t === "exit" ? a !== void 0 : !a || !("value" in a) || a.value?.id !== r) throw new n({ detail: "World hook did not establish its declared entity ownership result" });
670
+ }
671
+ assertWorldEnterVacant(e) {
672
+ let t = Object.getOwnPropertyDescriptor(this.state, "entities");
673
+ if (!t || !("value" in t) || !t.value || typeof t.value != "object" || Object.hasOwn(t.value, e)) throw new n({ detail: "World target entity slot is unavailable" });
674
+ }
675
+ retireWorldReceipt(e, t) {
676
+ return this.serializeLifecycle(async () => {
677
+ this.ensureOpen();
678
+ let r = this.worldReceipts.get(e);
679
+ if (r) {
680
+ if (r.operation !== t) throw new n({ detail: "World receipt retirement operation conflicts" });
681
+ this.worldReceipts.delete(e), t === "enter" && e.endsWith(":enter") && this.worldPublishedTransitions.delete(e.slice(0, -6));
682
+ }
683
+ });
684
+ }
685
+ cancelWorldGhost(e, t, r) {
686
+ let i = c(e, t);
687
+ return i.epoch !== this.epoch || !i.requestId?.endsWith(":ghost") || typeof r != "function" ? Promise.reject(new n({ detail: "World ghost rollback requires its exact actor request" })) : this.serializeLifecycle(async () => {
688
+ this.ensureOpen(), await r();
689
+ let e = this.worldReceipts.get(i.requestId);
690
+ if (!e) return;
691
+ let t = this.descriptor.world;
692
+ if (!t || e.operation !== "ghost" || e.fingerprint !== await _({
693
+ roomId: this.id,
694
+ tenantId: this.tenantId,
695
+ operation: "ghost",
696
+ entity: i.entity,
697
+ location: i.location
698
+ })) throw new n({ detail: "World ghost rollback differs from its retained projection" });
699
+ await this.mutateMemberAsync((e) => t.onGhost({
700
+ state: e,
701
+ phase: "rollback",
702
+ entity: i.entity,
703
+ requestId: i.requestId
704
+ }), void 0, !0, (e) => this.assertWorldHookResult(e, "ghost", i.entity.id), r), this.worldReceipts.delete(i.requestId);
705
+ });
706
+ }
707
+ cancelWorldPreview(e, t) {
708
+ return typeof e != "string" || !e || e.length > 191 || typeof t != "function" ? Promise.reject(new n({ detail: "World preview cancellation requires a bounded request and actual authority" })) : this.serializeLifecycle(async () => {
709
+ this.ensureOpen(), await t(), this.worldPreviews.delete(e);
710
+ });
711
+ }
712
+ hasWorldReceipt(e, t) {
713
+ if (this.ticking || this.isLifecycleBusy()) throw new r({
714
+ room: this.id,
715
+ detail: "World receipts are observed outside actor lifecycle work"
716
+ });
717
+ let i = this.worldReceipts.get(e);
718
+ if (i && i.operation !== t) throw new n({ detail: "World receipt operation conflicts" });
719
+ return i !== void 0;
720
+ }
721
+ worldReceiptSnapshot() {
722
+ if (this.ticking || this.isLifecycleBusy()) throw new r({
723
+ room: this.id,
724
+ detail: "World receipts are captured outside actor lifecycle work"
725
+ });
726
+ return h([...this.worldReceipts.values()].sort((e, t) => e.requestId.localeCompare(t.requestId)), this.descriptor.world?.maxPendingTransitions ?? 128);
727
+ }
728
+ captureWorldEntity(e, t, n) {
729
+ return this.serializeLifecycle(async () => this.captureWorldEntityOwned(e, t, n), this.worldFinalizationHold?.requestId);
730
+ }
731
+ configureWorldCellMovement(e, t, r = 0) {
732
+ if (!Number.isFinite(r) || r < 0) throw new n({ detail: "World movement margin must be finite and nonnegative" });
733
+ let i = t === void 0 ? void 0 : u(t);
734
+ return this.serializeLifecycle(async () => {
735
+ if (this.ensureOpen(), e !== this.epoch || !this.descriptor.world?.movement) throw new n({ detail: "World movement binding lost its configured actor epoch" });
736
+ this.worldMovement = i, this.worldMovementMargin = r, this.worldMovementIntents = Object.freeze([]);
737
+ });
738
+ }
739
+ worldMovementSnapshot() {
740
+ return Object.freeze({
741
+ bound: this.worldMovement !== void 0,
742
+ clamped: this.worldMovementClamps
743
+ });
744
+ }
745
+ captureWorldMovement(e) {
746
+ return this.serializeLifecycle(async () => {
747
+ this.ensureOpen();
748
+ let t = this.descriptor.world?.movement;
749
+ if (!t || !this.worldMovement || e !== this.epoch || this.faulted || this.worldFinalizationHold) throw new n({ detail: "World movement observation requires its live bounded actor" });
750
+ let r = [], i = t.maxBytesPerTick;
751
+ for (let e of this.worldMovementIntents) {
752
+ let a = Object.getOwnPropertyDescriptor(this.state, "entities"), o = a && "value" in a ? a.value : void 0, s = o && typeof o == "object" ? Object.getOwnPropertyDescriptor(o, e.entityId) : void 0;
753
+ if (!s || !("value" in s)) continue;
754
+ let l = c(s.value, i);
755
+ i -= new TextEncoder().encode(JSON.stringify(l)).length;
756
+ let u = t.position(l);
757
+ if (u instanceof Promise) throw u.catch(() => void 0), new n({ detail: "World movement observation must be synchronous" });
758
+ l.id === e.entityId && g(c(u, 128)) === g(e.sourceAt) && r.push(e);
759
+ }
760
+ return Object.freeze({
761
+ epoch: e,
762
+ tick: this.lastGoodTick,
763
+ intents: Object.freeze(r)
764
+ });
765
+ });
766
+ }
767
+ constrainWorldMovement() {
768
+ let t = this.descriptor.world?.movement;
769
+ if (!t) return {
770
+ clamped: 0,
771
+ intents: Object.freeze([])
772
+ };
773
+ let r = this.worldMovement;
774
+ if (!r) throw new n({ detail: "World movement requires acquired source cell bounds" });
775
+ let i = t.maxBytesPerTick, a = 0, o = 0, s = [], l = (e) => {
776
+ let t = c(e, i);
777
+ return i -= new TextEncoder().encode(JSON.stringify(t)).length, t;
778
+ }, u = (e) => {
779
+ let r = t.position(e);
780
+ if (r instanceof Promise) throw r.catch(() => void 0), new n({ detail: "World movement position must be synchronous" });
781
+ return c(r, 128);
782
+ }, d = Object.getOwnPropertyDescriptor(this.state, "entities"), f = Object.getOwnPropertyDescriptor(this.lastGoodState, "entities"), p = d && "value" in d ? d.value : void 0, m = f && "value" in f ? f.value : void 0;
783
+ if (!p || typeof p != "object" || Array.isArray(p) || ![null, Object.prototype].includes(Object.getPrototypeOf(p)) || !m || typeof m != "object" || Array.isArray(m)) throw new n({ detail: "World movement requires actual entity records" });
784
+ for (let i in p) if (Object.hasOwn(p, i)) {
785
+ if (++a > t.maxEntities) throw new e({
786
+ budget: "worldMovementEntities",
787
+ limit: t.maxEntities
788
+ });
789
+ let c = Object.getOwnPropertyDescriptor(p, i), d = Object.getOwnPropertyDescriptor(m, i);
790
+ if (!c || !("value" in c)) throw new n({ detail: "World movement requires own entity data" });
791
+ let f = l(c.value);
792
+ if (f.id !== i) throw new n({ detail: "World movement entity differs from its state key" });
793
+ let h = u(f), _ = d && "value" in d ? u(l(d.value)) : h, v = r.constrain(_, h), y = r.approach(_, h, this.worldMovementMargin);
794
+ if (y && s.push(Object.freeze({
795
+ entityId: i,
796
+ ...y
797
+ })), !v.clamped) continue;
798
+ let b = t.move(c.value, v.at);
799
+ if (b !== void 0) throw b instanceof Promise && b.catch(() => void 0), new n({ detail: "World movement write must return synchronous void" });
800
+ let x = l(c.value), S = u(x);
801
+ if (x.id !== i || g(S) !== g(v.at)) throw new n({ detail: "World movement writer did not establish its constrained position" });
802
+ o++;
803
+ }
804
+ if (this.worldMovementClamps > 2 ** 53 - 1 - o) throw new e({
805
+ budget: "worldMovementClamps",
806
+ limit: 2 ** 53 - 1
807
+ });
808
+ return {
809
+ clamped: o,
810
+ intents: Object.freeze(s)
811
+ };
812
+ }
813
+ listWorldEntityIds(t, r, i) {
814
+ return !Number.isSafeInteger(r) || r < 1 || r > 4095 || !Number.isSafeInteger(i) || i < 1 || i > 1048576 ? Promise.reject(new n({ detail: "World entity inventory requires a bounded count" })) : this.serializeLifecycle(async () => {
815
+ if (this.ensureOpen(), !this.descriptor.world || t !== this.epoch) throw new n({ detail: "World inventory lost its actor epoch" });
816
+ let a = Object.getOwnPropertyDescriptor(this.state, "entities"), o = a && "value" in a ? a.value : void 0;
817
+ if (!o || typeof o != "object" || Array.isArray(o) || ![null, Object.prototype].includes(Object.getPrototypeOf(o))) throw new n({ detail: "World inventory requires its actual entity record" });
818
+ let s = [];
819
+ for (let t in o) if (Object.hasOwn(o, t)) {
820
+ if (s.length >= r) throw new e({
821
+ budget: "worldGhostEntities",
822
+ limit: r
823
+ });
824
+ let i = Object.getOwnPropertyDescriptor(o, t), a = i && "value" in i ? i.value : void 0, c = a && typeof a == "object" ? Object.getOwnPropertyDescriptor(a, "id") : void 0;
825
+ if (!t || t.length > 191 || !c || !("value" in c) || c.value !== t) throw new n({ detail: "World inventory entity identity contradicts its state key" });
826
+ s.push(t);
827
+ }
828
+ return s.sort((e, t) => e < t ? -1 : +(e > t)), c(s, i);
829
+ });
830
+ }
831
+ captureWorldProjection(e, t, n) {
832
+ return this.serializeLifecycle(async () => Object.freeze({
833
+ ...this.captureWorldEntityOwned(e, t, n),
834
+ tick: this.tick
835
+ }));
836
+ }
837
+ captureWorldEntityOwned(e, t, r) {
838
+ this.ensureOpen();
839
+ let i = this.descriptor.world;
840
+ if (!i || t !== this.epoch || typeof e != "string" || !e || e.length > 191) throw new n({ detail: "World capture requires current configured actor authority" });
841
+ let a = Object.getOwnPropertyDescriptor(this.state, "entities"), o = a && "value" in a && a.value && typeof a.value == "object" ? Object.getOwnPropertyDescriptor(a.value, e) : void 0;
842
+ if (!o || !("value" in o)) throw new n({ detail: "World entity is absent from the actual actor state" });
843
+ let s = c(o.value, r);
844
+ if (!s || s.id !== e) throw new n({ detail: "World actor entity identity contradicts its state key" });
845
+ let l = i.persistEntity({ entity: s });
846
+ if (l instanceof Promise) throw l.catch(() => void 0), new n({ detail: "World entity persistence projection must be synchronous" });
847
+ return Object.freeze({
848
+ entity: s,
849
+ data: c(l, r)
850
+ });
851
+ }
852
+ finalizeWorldExit(t, r, i, a, o, s) {
853
+ let l = c(t, r);
854
+ if (!l || l.epoch !== this.epoch || !l.requestId?.endsWith(":exit") || l.requestId.length > 191 || !l.location || Object.keys(l.location).length !== 6 || ![
855
+ l.location.worldId,
856
+ l.location.zoneId,
857
+ l.location.roomId
858
+ ].every((e) => typeof e == "string" && e.length > 0 && e.length <= 191) || ![l.location.epoch, l.location.layer].every((e) => Number.isSafeInteger(e) && e > 0) || !Array.isArray(l.location.at) || l.location.at.length !== 2 || !l.location.at.every(Number.isFinite) || l.subjectId !== void 0 && (typeof l.subjectId != "string" || !l.subjectId || l.subjectId.length > 191) || l.afterglow !== void 0 && (!l.afterglow || Object.keys(l.afterglow).sort().join(",") !== "expiresAt,requestId" || !/^wghost-[0-9a-f]{64}:ghost$/.test(l.afterglow.requestId) || !Number.isSafeInteger(l.afterglow.expiresAt) || l.afterglow.expiresAt < 0) || typeof i != "function" || typeof a != "function") return Promise.reject(new n({ detail: "World finalization requires canonical exit and actual durable callbacks" }));
859
+ let u = o === void 0 ? void 0 : c(o, r);
860
+ return this.serializeLifecycle(async () => {
861
+ this.ensureOpen();
862
+ let t = this.captureWorldEntityOwned(l.entityId, l.epoch, r), o = this.worldFinalizationHold;
863
+ if (o && (g(o.afterglow ?? null) !== g(l.afterglow ?? null) || o.subjectId !== l.subjectId || o.entityId !== l.entityId || g(o.location) !== g(l.location) || g(o.entity) !== g(t.entity))) throw new n({ detail: "World finalization retry conflicts with retained source capture" });
864
+ if (u !== void 0 && g(u) !== g(t.entity)) throw new n({ detail: "World finalization requires exact retained final source entity" });
865
+ if (this.worldReceipts.has(l.requestId)) throw new n({ detail: "World finalization already has an exit receipt; replay its retained payload" });
866
+ if (this.worldReceipts.size + this.worldPreviews.size + +!!l.afterglow >= (this.descriptor.world.maxPendingTransitions ?? 128)) throw new e({
867
+ budget: "worldActorReceipts",
868
+ limit: this.descriptor.world.maxPendingTransitions ?? 128
869
+ });
870
+ let c = o ?? Object.freeze({
871
+ ...t,
872
+ requestId: l.requestId,
873
+ entityId: l.entityId,
874
+ location: l.location,
875
+ ...l.afterglow ? { afterglow: l.afterglow } : {},
876
+ ...l.subjectId === void 0 ? {} : { subjectId: l.subjectId },
877
+ heldAt: this.now()
878
+ });
879
+ this.worldFinalizationHold = c;
880
+ let d = await _({
881
+ roomId: this.id,
882
+ tenantId: this.tenantId,
883
+ operation: "exit",
884
+ entity: c.entity,
885
+ location: l.location
886
+ }), f = c.afterglow ? Object.freeze({
887
+ requestId: c.afterglow.requestId,
888
+ operation: "ghost",
889
+ fingerprint: await _({
890
+ roomId: this.id,
891
+ tenantId: this.tenantId,
892
+ operation: "ghost",
893
+ entity: c.entity,
894
+ location: l.location
895
+ }),
896
+ projection: {
897
+ entity: c.entity,
898
+ location: l.location,
899
+ expiresAt: c.afterglow.expiresAt
900
+ }
901
+ }) : void 0;
902
+ if (f && this.worldReceipts.has(f.requestId)) throw new n({ detail: "Source afterglow conflicts with a retained projection" });
903
+ if (h([
904
+ ...this.worldReceipts.values(),
905
+ {
906
+ requestId: l.requestId,
907
+ operation: "exit",
908
+ fingerprint: d
909
+ },
910
+ ...f ? [f] : []
911
+ ]), await this.mutateMemberAsync((e) => {
912
+ let t = this.descriptor.world, r = () => t.onExit({
913
+ state: e,
914
+ phase: "commit",
915
+ entity: c.entity,
916
+ to: l.location,
917
+ requestId: l.requestId
918
+ });
919
+ return f ? y.gen(function* () {
920
+ for (let i of [r, () => t.onGhost({
921
+ state: e,
922
+ phase: "commit",
923
+ entity: c.entity,
924
+ requestId: f.requestId
925
+ })]) {
926
+ let e = i();
927
+ if (e !== void 0) {
928
+ if (!y.isEffect(e)) throw e instanceof Promise && e.catch(() => void 0), new n({ detail: "Source afterglow requires synchronous void or Effect hooks" });
929
+ if ((yield* e) !== void 0) throw new n({ detail: "Source afterglow Effects must produce void" });
930
+ }
931
+ }
932
+ }) : r();
933
+ }, s, !0, (e) => this.assertWorldHookResult(e, "exit", l.entityId), async () => {
934
+ await a(), await i(Object.freeze({
935
+ entity: c.entity,
936
+ data: c.data
937
+ })), await a();
938
+ }), f && this.worldReceipts.set(f.requestId, f), this.worldReceipts.set(l.requestId, Object.freeze({
939
+ requestId: l.requestId,
940
+ operation: "exit",
941
+ fingerprint: d
942
+ })), l.subjectId !== void 0) {
943
+ for (let e of this.members.values()) e.client.subjectId === l.subjectId && (e.worldDeparture = l.requestId);
944
+ for (let [e, t] of this.grace) t.subjectId === l.subjectId && this.grace.set(e, {
945
+ ...t,
946
+ worldDeparture: l.requestId
947
+ });
948
+ for (let e = this.inputs.length - 1; e >= 0; e--) this.inputs[e].client.subjectId === l.subjectId && this.inputs.splice(e, 1);
949
+ }
950
+ }, l.requestId);
951
+ }
952
+ notifyWorldHandoff(e, t, r) {
953
+ let i = c(e, 2048), a = l({
954
+ ...i,
955
+ tick: 0
956
+ });
957
+ return b.isFailure(a) || i.kind !== "WorldHandoff" || typeof t != "function" || typeof r != "function" ? Promise.reject(new n({ detail: "World notice requires canonical metadata and actual authority" })) : this.serializeLifecycle(async () => {
958
+ if (this.ensureOpen(), !this.descriptor.world || i.sourceEpoch !== this.epoch) throw new n({ detail: "World notice lost its source epoch" });
959
+ let e = i.phase === "departed" ? "exit" : "enter", a = this.worldReceipts.get(`${i.transitionId}:${e}`);
960
+ if (!a || a.operation !== e) throw new n({ detail: "World notice requires its actual actor receipt" });
961
+ this.assertWorldHookResult(this.state, e, i.entityId), await t(), r(Object.freeze({
962
+ ...i,
963
+ tick: this.tick
964
+ }));
965
+ }, `${i.transitionId}:exit`);
966
+ }
967
+ completeWorldFinalization(e, t) {
968
+ return this.serializeLifecycle(async () => {
969
+ if (!this.worldFinalizationHold) return;
970
+ if (typeof t != "function") throw new n({ detail: "World completion requires actual durable authority" });
971
+ await t();
972
+ for (let [e, t] of this.deferredWorldLeaves) {
973
+ let n = this.prepareLeave(e, t);
974
+ n.pending || await this.mutateMemberAsync((e) => this.descriptor.onLeave?.(n.context(e))), n.commit(), this.deferredWorldLeaves.delete(e);
975
+ }
976
+ let e = this.now() - this.worldFinalizationHold.heldAt;
977
+ this.nextTickAt += e, this.emptyAt !== null && this.emptyAt <= this.worldFinalizationHold.heldAt && (this.emptyAt += e);
978
+ for (let t of this.schedules.values()) t.at += e;
979
+ this.worldFinalizationHold = null;
980
+ }, e);
981
+ }
982
+ worldFinalizationAfterglow() {
983
+ return this.worldFinalizationHold?.afterglow;
984
+ }
985
+ worldFinalizationRequest() {
986
+ return this.worldFinalizationHold?.requestId ?? null;
987
+ }
988
+ isWorldFinalizationHeld() {
989
+ return this.worldFinalizationHold !== null;
990
+ }
991
+ reconcileWorldSource(t, r, i, a) {
992
+ let o = c(t, r);
993
+ return !o || o.epoch !== this.epoch || !o.requestId?.endsWith(":enter") || o.requestId.length > 191 || !o.entity || typeof o.entity.id != "string" || !o.entity.id || o.entity.id.length > 191 || !o.location || Object.keys(o.location).length !== 6 || ![
994
+ o.location.worldId,
995
+ o.location.zoneId,
996
+ o.location.roomId
997
+ ].every((e) => typeof e == "string" && e.length > 0 && e.length <= 191) || ![o.location.epoch, o.location.layer].every((e) => Number.isSafeInteger(e) && e > 0) || !Array.isArray(o.location.at) || o.location.at.length !== 2 || !o.location.at.every(Number.isFinite) || typeof i != "function" ? Promise.reject(new n({ detail: "World source recovery requires canonical current authority" })) : this.serializeLifecycle(async () => {
998
+ if (this.ensureOpen(), !this.descriptor.world || this.publicationHeldAt === null && !this.worldFinalizationHold) throw new n({ detail: "World source recovery requires unpublished or held configured actor" });
999
+ if (this.publicationHeldAt === null && g(this.captureWorldEntityOwned(o.entity.id, o.epoch, r).entity) !== g(o.entity)) throw new n({ detail: "Live World compensation cannot replace divergent source state" });
1000
+ let t = await _({
1001
+ roomId: this.id,
1002
+ tenantId: this.tenantId,
1003
+ operation: "enter",
1004
+ entity: o.entity,
1005
+ location: o.location
1006
+ }), s = this.worldReceipts.get(o.requestId);
1007
+ if (s) {
1008
+ if (s.operation !== "enter" || s.fingerprint !== t) throw new n({ detail: "World recovery conflicts with retained receipt" });
1009
+ await i();
1010
+ } else {
1011
+ if (this.worldReceipts.size + this.worldPreviews.size >= (this.descriptor.world.maxPendingTransitions ?? 128)) throw new e({
1012
+ budget: "worldActorReceipts",
1013
+ limit: this.descriptor.world.maxPendingTransitions ?? 128
1014
+ });
1015
+ await this.mutateMemberAsync((e) => {
1016
+ let t = Object.getOwnPropertyDescriptor(e, "entities");
1017
+ if (!t || !("value" in t) || !t.value || typeof t.value != "object") throw new n({ detail: "World recovery requires actual entity state" });
1018
+ return delete t.value[o.entity.id], this.descriptor.world.onEnter({
1019
+ state: e,
1020
+ phase: "rollback",
1021
+ entity: o.entity,
1022
+ from: o.location,
1023
+ requestId: o.requestId
1024
+ });
1025
+ }, a, !0, (e) => {
1026
+ this.assertWorldHookResult(e, "enter", o.entity.id);
1027
+ let t = Object.getOwnPropertyDescriptor(e, "entities");
1028
+ if (g(c(t.value[o.entity.id], r)) !== g(o.entity)) throw new n({ detail: "World recovery must restore exact final source entity" });
1029
+ }, i), this.worldReceipts.set(o.requestId, Object.freeze({
1030
+ requestId: o.requestId,
1031
+ operation: "enter",
1032
+ fingerprint: t
1033
+ }));
1034
+ }
1035
+ }, `${o.requestId.slice(0, -6)}:exit`);
1036
+ }
1037
+ assertSynchronousLifecycle() {
1038
+ if (this.isLifecycleBusy() || this.worldFinalizationHold) throw new r({
1039
+ room: this.descriptor.name,
1040
+ detail: "A synchronous lifecycle call cannot overlap queued Effect hooks"
1041
+ });
1042
+ }
1043
+ serializeLifecycle(t, i) {
1044
+ if (this.ticking) return Promise.reject(new r({
1045
+ room: this.descriptor.name,
1046
+ detail: "Lifecycle work must run outside the tick"
1047
+ }));
1048
+ if (this.lifecycleRequests >= this.descriptor.budgets.maxQueuedLifecycleHooks) return Promise.reject(new e({
1049
+ budget: "maxQueuedLifecycleHooks",
1050
+ limit: this.descriptor.budgets.maxQueuedLifecycleHooks
1051
+ }));
1052
+ this.lifecycleRequests++;
1053
+ let a = this.lifecycleTail.then(async () => {
1054
+ this.lifecycleActive = !0;
1055
+ try {
1056
+ if (this.worldFinalizationHold && this.worldFinalizationHold.requestId !== (typeof i == "function" ? i() : i)) throw new n({ detail: "World finalization holds actor lifecycle until durable completion" });
1057
+ return await t();
1058
+ } finally {
1059
+ this.lifecycleActive = !1, this.lifecycleRequests--;
1060
+ }
1061
+ });
1062
+ return this.lifecycleTail = a.then(() => void 0, () => void 0), a;
1063
+ }
1064
+ async mutateMemberAsync(e, t, n = !0, i, a) {
1065
+ let o = structuredClone(this.state), s = this.outbox.length, c = this.clientOperations.length, l = [...this.schedules].map(([e, t]) => [e, { ...t }]), u = () => {
1066
+ this.outbox.splice(s), this.clientOperations.splice(c), this.schedules.clear();
1067
+ for (let [e, t] of l) this.schedules.set(e, t);
1068
+ };
1069
+ try {
1070
+ if (t?.aborted) throw new r({
1071
+ room: this.descriptor.name,
1072
+ detail: "Lifecycle operation was cancelled"
1073
+ });
1074
+ let s = e(o);
1075
+ if (s !== void 0) {
1076
+ if (!y.isEffect(s)) throw s instanceof Promise && s.catch(() => void 0), new r({
1077
+ room: this.descriptor.name,
1078
+ detail: "Lifecycle hooks must return undefined or Effect, never Promise"
1079
+ });
1080
+ let e = s.pipe(y.timeout(this.descriptor.lifecycleTimeoutMs)), n = await y.runPromise(y.result(e), { signal: t });
1081
+ if (b.isFailure(n)) throw n.failure;
1082
+ if (n.success !== void 0) throw new r({
1083
+ room: this.descriptor.name,
1084
+ detail: "Lifecycle Effects must produce void"
1085
+ });
1086
+ }
1087
+ if (t?.aborted) throw new r({
1088
+ room: this.descriptor.name,
1089
+ detail: "Lifecycle operation was cancelled"
1090
+ });
1091
+ if (x.decodeUnknownSync(x.toType(this.descriptor.state))(o), i?.(o), !n) {
1092
+ u();
1093
+ return;
1094
+ }
1095
+ let c = structuredClone(o);
1096
+ if (a && await a(), t?.aborted) throw new r({
1097
+ room: this.descriptor.name,
1098
+ detail: "Lifecycle operation was cancelled"
1099
+ });
1100
+ this.currentState = c, this.lastGoodState = structuredClone(c);
1101
+ } catch (e) {
1102
+ throw u(), e;
1103
+ }
1104
+ }
1105
+ pruneGrace(e) {
1106
+ for (let [t, n] of this.grace) n.expiresAt <= e && this.grace.delete(t);
1107
+ }
1108
+ mutateMember(e) {
1109
+ if (this.ticking) throw new r({
1110
+ room: this.descriptor.name,
1111
+ detail: "Membership hooks must run outside the tick"
1112
+ });
1113
+ let t = structuredClone(this.state), n = this.outbox.length, i = this.clientOperations.length, a = [...this.schedules].map(([e, t]) => [e, { ...t }]);
1114
+ try {
1115
+ e(), x.decodeUnknownSync(x.toType(this.descriptor.state))(this.state), this.lastGoodState = structuredClone(this.state);
1116
+ } catch (e) {
1117
+ this.currentState = t, this.outbox.splice(n), this.clientOperations.splice(i), this.schedules.clear();
1118
+ for (let [e, t] of a) this.schedules.set(e, t);
1119
+ throw e;
1120
+ }
1121
+ }
1122
+ input(r, i, a, o, s) {
1123
+ this.ensureOpen();
1124
+ let c = this.members.get(r);
1125
+ if (!c) throw new t({ sessionId: r });
1126
+ if (![
1127
+ i,
1128
+ a,
1129
+ s
1130
+ ].every((e) => Number.isSafeInteger(e) && e >= 0)) throw new n({ detail: "Input metadata must use nonnegative safe integers" });
1131
+ if (i <= c.lastSeq) return !1;
1132
+ let l = this.now(), u = Math.max(0, l - c.replenishedAt) / 1e3, d = this.descriptor.budgets;
1133
+ if (c.inputTokens = Math.min(d.burst, c.inputTokens + u * d.inputsPerSecond), c.byteTokens = Math.min(d.bytesPerSecond, c.byteTokens + u * d.bytesPerSecond), c.replenishedAt = l, c.inputTokens < 1) throw new e({
1134
+ budget: "inputsPerSecond",
1135
+ limit: d.inputsPerSecond
1136
+ });
1137
+ if (c.byteTokens < s) throw new e({
1138
+ budget: "bytesPerSecond",
1139
+ limit: d.bytesPerSecond
1140
+ });
1141
+ let f = x.decodeUnknownResult(this.descriptor.input)(o);
1142
+ if (b.isFailure(f)) throw new n({ detail: "Input does not match the declared intention schema" });
1143
+ let p = f.success;
1144
+ if (!c.worldPending && !c.worldDeparture && this.inputs.length >= d.maxQueuedInputs) throw new e({
1145
+ budget: "maxQueuedInputs",
1146
+ limit: d.maxQueuedInputs
1147
+ });
1148
+ return --c.inputTokens, c.byteTokens -= s, c.lastSeq = i, c.worldDeparture ? !1 : c.worldPending ? (c.lastDiscardedSeq = i, !1) : (this.inputs.push(Object.freeze({
1149
+ client: c.client,
1150
+ seq: i,
1151
+ tickHint: a,
1152
+ input: structuredClone(p)
1153
+ })), !0);
1154
+ }
1155
+ send(e, t, n) {
1156
+ let i = this.descriptor.messages[t];
1157
+ if (!i || i.direction === "client") throw new r({
1158
+ room: this.descriptor.name,
1159
+ detail: `Channel ${t} is not server-sendable`
1160
+ });
1161
+ e.send(t, x.decodeUnknownSync(i.schema)(n));
1162
+ }
1163
+ extension(e, n, r) {
1164
+ if (!n) return;
1165
+ let i = Object.create(null);
1166
+ for (let t of e.fields) i[t] = structuredClone(Reflect.get(Object(this.state), t));
1167
+ Object.preventExtensions(i);
1168
+ let a = this.now();
1169
+ S(this.descriptor.name, n, {
1170
+ state: i,
1171
+ tick: r.tick,
1172
+ dt: r.dt,
1173
+ inputs: r.inputs.map((e) => ({
1174
+ ...e,
1175
+ input: structuredClone(e.input),
1176
+ client: Object.freeze({
1177
+ sessionId: e.client.sessionId,
1178
+ subjectId: e.client.subjectId,
1179
+ tenantId: e.client.tenantId,
1180
+ ...e.client.isBot ? {
1181
+ isBot: !0,
1182
+ countsAsPlayer: e.client.countsAsPlayer !== !1
1183
+ } : {}
1184
+ })
1185
+ })),
1186
+ clock: this.clock,
1187
+ ...this.geometry ? { geometry: this.geometry } : {},
1188
+ send: (n, r) => {
1189
+ let i = this.members.get(n);
1190
+ if (!i) throw new t({ sessionId: n });
1191
+ this.send(i.client, e.channel, r);
1192
+ }
1193
+ });
1194
+ for (let t of e.fields) Reflect.set(Object(this.state), t, structuredClone(i[t]));
1195
+ let o = Math.max(0, this.now() - a);
1196
+ this.extensionDurationMs[e.name] = (this.extensionDurationMs[e.name] ?? 0) + o, o > e.tickBudgetMs && (this.extensionOverruns[e.name] = (this.extensionOverruns[e.name] ?? 0) + 1);
1197
+ }
1198
+ holdPublication() {
1199
+ if (this.ensureOpen(), this.assertSynchronousLifecycle(), this.ticking) throw new r({
1200
+ room: this.id,
1201
+ detail: "Publication cannot change inside a tick"
1202
+ });
1203
+ this.publicationHeldAt ??= this.now();
1204
+ }
1205
+ releasePublication() {
1206
+ if (this.ensureOpen(), this.assertSynchronousLifecycle(), this.publicationHeldAt === null) throw new n({ detail: "Actor publication has no retained hold" });
1207
+ let e = this.now() - this.publicationHeldAt;
1208
+ this.nextTickAt += e, this.emptyAt !== null && (this.emptyAt += e);
1209
+ for (let t of this.schedules.values()) t.at += e;
1210
+ for (let [t, n] of this.grace) this.grace.set(t, {
1211
+ ...n,
1212
+ expiresAt: n.expiresAt + e
1213
+ });
1214
+ this.publicationHeldAt = null;
1215
+ }
1216
+ advance() {
1217
+ if (this.drainFrozen || this.publicationHeldAt !== null || this.worldFinalizationHold || this.isLifecycleBusy() || this.descriptor.world?.movement && !this.worldMovement) return 0;
1218
+ if (this.ensureOpen(), this.ticking) throw new r({
1219
+ room: this.descriptor.name,
1220
+ detail: "A room cannot reenter its tick"
1221
+ });
1222
+ let e = this.now(), t = 1e3 / this.descriptor.tickRate;
1223
+ if (this.pruneGrace(e), this.emptyAt !== null && this.grace.size === 0 && this.worldReceipts.size === 0 && this.worldPreviews.size === 0 && e - this.emptyAt >= this.descriptor.autoDispose.afterEmptyMs) return this.retiring = !0, 0;
1224
+ if (e < this.nextTickAt) return 0;
1225
+ let n = Math.floor((e - this.nextTickAt) / t) + 1, i = Math.max(0, n - this.descriptor.maxCatchUpTicks);
1226
+ if (!Number.isSafeInteger(this.tick + n)) throw new r({
1227
+ room: this.descriptor.name,
1228
+ detail: "Room tick counter is exhausted"
1229
+ });
1230
+ this.droppedTicks += i, this.tick += i, this.nextTickAt += i * t;
1231
+ let a = 0, o = this.outbox.length, s = this.clientOperations.length;
1232
+ this.ticking = !0;
1233
+ try {
1234
+ for (; a < n - i; a++) {
1235
+ o = this.outbox.length, s = this.clientOperations.length, this.tick++;
1236
+ let e = Object.freeze(this.inputs.splice(0).sort((e, t) => e.client.sessionId < t.client.sessionId ? -1 : e.client.sessionId > t.client.sessionId ? 1 : e.seq - t.seq)), n = {
1237
+ state: this.state,
1238
+ tick: this.tick,
1239
+ dt: 1 / this.descriptor.tickRate,
1240
+ inputs: e,
1241
+ app: this.app,
1242
+ clock: this.clock,
1243
+ scheduler: this.scheduler,
1244
+ ...this.geometry ? { geometry: this.geometry } : {},
1245
+ broadcast: (e, t) => {
1246
+ for (let n of this.members.values()) this.send(n.client, e, t);
1247
+ }
1248
+ };
1249
+ for (let e of [...this.schedules.values()]) e.at > this.nextTickAt || this.schedules.get(e.label) !== e || (e.interval === null ? this.schedules.delete(e.label) : e.at += (Math.floor((this.nextTickAt - e.at) / e.interval) + 1) * e.interval, S(this.descriptor.name, this.descriptor.onSchedule, {
1250
+ ...n,
1251
+ label: e.label
1252
+ }));
1253
+ for (let e of this.descriptor.extensions) this.extension(e, e.beforeTick, n);
1254
+ S(this.descriptor.name, this.descriptor.onTick, n);
1255
+ for (let e of this.descriptor.extensions) this.extension(e, e.afterTick, n);
1256
+ let r = this.constrainWorldMovement();
1257
+ x.decodeUnknownSync(x.toType(this.descriptor.state))(this.state), this.worldMovementClamps += r.clamped, this.worldMovementIntents = r.intents;
1258
+ for (let t of e) {
1259
+ let e = this.members.get(t.client.sessionId);
1260
+ e && (e.lastAppliedSeq = Math.max(e.lastAppliedSeq, t.seq));
1261
+ }
1262
+ this.lastGoodState = structuredClone(this.state), this.lastGoodTick = this.tick, this.nextTickAt += t;
1263
+ }
1264
+ } catch (e) {
1265
+ throw this.faulted = !0, this.worldMovementIntents = Object.freeze([]), this.currentState = structuredClone(this.lastGoodState), this.outbox.splice(o), this.clientOperations.splice(s), this.schedules.clear(), this.inputs.length = 0, e;
1266
+ } finally {
1267
+ this.ticking = !1;
1268
+ }
1269
+ return a;
1270
+ }
1271
+ drainOutbox() {
1272
+ if (this.lifecycleActive) throw new r({
1273
+ room: this.descriptor.name,
1274
+ detail: "Lifecycle commands are drained only after the hook commits"
1275
+ });
1276
+ if (this.ticking) throw new r({
1277
+ room: this.descriptor.name,
1278
+ detail: "The app outbox can only be drained outside the tick"
1279
+ });
1280
+ return this.outbox.splice(0);
1281
+ }
1282
+ stageClientOperation(t) {
1283
+ if (this.clientOperations.length >= this.descriptor.budgets.maxOutboxCommands) throw new e({
1284
+ budget: "maxClientOperations",
1285
+ limit: this.descriptor.budgets.maxOutboxCommands
1286
+ });
1287
+ this.clientOperations.push(t);
1288
+ }
1289
+ flushClientOperations() {
1290
+ if (this.lifecycleActive) throw new r({
1291
+ room: this.descriptor.name,
1292
+ detail: "Lifecycle client operations flush only after the hook commits"
1293
+ });
1294
+ if (this.ticking) throw new r({
1295
+ room: this.descriptor.name,
1296
+ detail: "Client operations must be flushed outside the tick"
1297
+ });
1298
+ let e = [];
1299
+ for (let t of this.clientOperations.splice(0)) try {
1300
+ t();
1301
+ } catch (t) {
1302
+ e.push(t);
1303
+ }
1304
+ if (e.length) throw AggregateError(e, "Room client delivery failed");
1305
+ }
1306
+ inputReceiptSnapshot() {
1307
+ if (this.ticking || this.isLifecycleBusy()) throw new r({
1308
+ room: this.id,
1309
+ detail: "Input receipts are captured outside committed lifecycle and tick work"
1310
+ });
1311
+ this.pruneGrace(this.drainAt ?? this.publicationHeldAt ?? this.worldFinalizationHold?.heldAt ?? this.now());
1312
+ let e = [];
1313
+ for (let [t, n] of this.members) !n.client.isBot && (n.lastAppliedSeq >= 0 || n.lastDiscardedSeq >= 0) && e.push({
1314
+ sessionId: t,
1315
+ subjectId: n.client.subjectId,
1316
+ lastAppliedSeq: n.lastAppliedSeq,
1317
+ ...n.lastDiscardedSeq < 0 ? {} : { discardedThrough: n.lastDiscardedSeq }
1318
+ });
1319
+ for (let [t, n] of this.grace) (n.lastAppliedSeq >= 0 || (n.discardedThrough ?? -1) >= 0) && e.push({
1320
+ sessionId: t,
1321
+ subjectId: n.subjectId,
1322
+ lastAppliedSeq: n.lastAppliedSeq,
1323
+ ...(n.discardedThrough ?? -1) < 0 ? {} : { discardedThrough: n.discardedThrough }
1324
+ });
1325
+ return p(e, Math.min(this.descriptor.maxClients, 16384));
1326
+ }
1327
+ confirmInputCheckpoint(e) {
1328
+ for (let t of p(e, Math.min(this.descriptor.maxClients, 16384))) {
1329
+ let e = this.members.get(t.sessionId);
1330
+ e?.worldTarget && e.client.subjectId === t.subjectId && t.discardedThrough !== void 0 && (e.checkpointedDiscardedSeq = Math.max(e.checkpointedDiscardedSeq, Math.min(e.lastDiscardedSeq, t.discardedThrough)));
1331
+ }
1332
+ }
1333
+ lastAppliedInputSeq(e) {
1334
+ let n = this.members.get(e);
1335
+ if (!n) throw new t({ sessionId: e });
1336
+ return n.lastAppliedSeq;
1337
+ }
1338
+ lock() {
1339
+ this.ensureOpen(), this.locked = !0;
1340
+ }
1341
+ unlock() {
1342
+ this.ensureOpen(), this.locked = !1;
1343
+ }
1344
+ dispose() {
1345
+ if (this.assertSynchronousLifecycle(), this.disposed) return;
1346
+ if (this.ticking) throw new r({
1347
+ room: this.descriptor.name,
1348
+ detail: "Dispose must run outside the tick"
1349
+ });
1350
+ this.retiring = !1;
1351
+ let e = [];
1352
+ try {
1353
+ for (let [t, n] of this.members) try {
1354
+ this.faulted ? n.client.kick("Room fault") : this.leave(t, "disposed");
1355
+ } catch (t) {
1356
+ e.push(t);
1357
+ }
1358
+ if (!this.faulted) try {
1359
+ C(this.descriptor.name, this.descriptor.onDispose, {
1360
+ state: this.state,
1361
+ app: this.app,
1362
+ ...this.geometry ? { geometry: this.geometry } : {}
1363
+ });
1364
+ } catch (t) {
1365
+ e.push(t);
1366
+ }
1367
+ } finally {
1368
+ this.disposed = !0, this.members.clear(), this.grace.clear(), this.schedules.clear(), this.inputs.length = 0;
1369
+ }
1370
+ if (e.length) throw AggregateError(e, "Room disposal failed");
1371
+ }
1372
+ isDisposed() {
1373
+ return this.disposed;
1374
+ }
1375
+ isLifecycleBusy() {
1376
+ return this.lifecycleRequests > 0;
1377
+ }
1378
+ async freezeForDrain() {
1379
+ if (this.ticking || this.disposed || this.faulted || this.retiring) throw new o({ roomId: this.id });
1380
+ this.drainFrozen ||= (this.drainAt = this.now(), !0), await this.lifecycleTail;
1381
+ }
1382
+ releaseTransferred() {
1383
+ if (this.assertSynchronousLifecycle(), !this.disposed) {
1384
+ if (!this.drainFrozen || this.ticking || this.outbox.length || this.clientOperations.length) throw new r({
1385
+ room: this.id,
1386
+ detail: "Transferred actor release requires its frozen committed boundary"
1387
+ });
1388
+ this.disposed = !0, this.members.clear(), this.grace.clear(), this.schedules.clear(), this.inputs.length = 0;
1389
+ }
1390
+ }
1391
+ disposeAsync(e) {
1392
+ return this.serializeLifecycle(async () => {
1393
+ if (this.disposed) return;
1394
+ this.retiring = !1;
1395
+ let t = [];
1396
+ try {
1397
+ for (let [n, r] of this.members) try {
1398
+ if (this.faulted || this.worldFinalizationHold) r.client.kick("Room fault");
1399
+ else {
1400
+ let t = this.prepareLeave(n, "disposed");
1401
+ t.pending || await this.mutateMemberAsync((e) => this.descriptor.onLeave?.(t.context(e)), e), t.commit();
1402
+ }
1403
+ } catch (e) {
1404
+ t.push(e);
1405
+ }
1406
+ if (!this.faulted && !this.worldFinalizationHold) try {
1407
+ await this.mutateMemberAsync((e) => this.descriptor.onDispose?.({
1408
+ state: e,
1409
+ app: this.app,
1410
+ ...this.geometry ? { geometry: this.geometry } : {}
1411
+ }), e);
1412
+ } catch (e) {
1413
+ t.push(e);
1414
+ }
1415
+ } finally {
1416
+ this.disposed = !0, this.worldFinalizationHold = null, this.deferredWorldLeaves.clear(), this.members.clear(), this.grace.clear(), this.schedules.clear(), this.inputs.length = 0;
1417
+ }
1418
+ if (t.length) throw AggregateError(t, "Asynchronous Room disposal failed");
1419
+ }, () => this.worldFinalizationHold?.requestId);
1420
+ }
1421
+ isRetiring() {
1422
+ return this.retiring;
1423
+ }
1424
+ releaseHibernated() {
1425
+ if (this.assertSynchronousLifecycle(), !this.disposed) {
1426
+ if (this.ticking || !this.retiring || this.members.size || this.grace.size || this.outbox.length) throw new r({
1427
+ room: this.descriptor.name,
1428
+ detail: "Hibernate release requires an empty retired actor and committed outbox"
1429
+ });
1430
+ this.disposed = !0, this.retiring = !1, this.members.clear(), this.grace.clear(), this.schedules.clear(), this.inputs.length = 0, this.clientOperations.length = 0;
1431
+ }
1432
+ }
1433
+ isFaulted() {
1434
+ return this.faulted;
1435
+ }
1436
+ commandCursor() {
1437
+ return this.commandSeq;
1438
+ }
1439
+ scheduleSnapshot() {
1440
+ if (this.ticking) throw new r({
1441
+ room: this.descriptor.name,
1442
+ detail: "Schedules are checkpointed outside the tick"
1443
+ });
1444
+ let e = this.drainAt ?? this.publicationHeldAt ?? this.worldFinalizationHold?.heldAt ?? this.now();
1445
+ return [...this.schedules.values()].map((t) => Object.freeze({
1446
+ label: t.label,
1447
+ remainingMs: Math.max(0, t.at - e),
1448
+ intervalMs: t.interval
1449
+ }));
1450
+ }
1451
+ lastGoodSnapshot() {
1452
+ if (this.ticking) throw new r({
1453
+ room: this.descriptor.name,
1454
+ detail: "Fault snapshots are taken outside the tick"
1455
+ });
1456
+ return {
1457
+ tick: this.lastGoodTick,
1458
+ state: structuredClone(this.lastGoodState)
1459
+ };
1460
+ }
1461
+ metrics() {
1462
+ return {
1463
+ tick: this.tick,
1464
+ droppedTicks: this.droppedTicks,
1465
+ queuedInputs: this.inputs.length,
1466
+ outboxCommands: this.outbox.length,
1467
+ clients: this.members.size,
1468
+ extensionDurationMs: { ...this.extensionDurationMs },
1469
+ extensionOverruns: { ...this.extensionOverruns }
1470
+ };
1471
+ }
1472
+ };
1473
+ //#endregion
1474
+ export { w as RoomActor };