@pyric/cli 0.1.0-alpha.10 → 0.1.0-alpha.12

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 (498) hide show
  1. package/README.md.orig +2 -2
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts +16 -0
  3. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  4. package/dist/assurance/.generated/conformance-verdicts.js +16 -0
  5. package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
  6. package/dist/bridge/server/peer.d.ts +1 -1
  7. package/dist/bridge/server.d.ts +1 -1
  8. package/dist/bridge/server.js +1 -1
  9. package/dist/cli/index.d.ts +11 -0
  10. package/dist/cli/index.d.ts.map +1 -1
  11. package/dist/cli/index.js +13 -1
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/cli/init.d.ts +3 -3
  14. package/dist/cli/init.d.ts.map +1 -1
  15. package/dist/cli/init.js +5 -5
  16. package/dist/cli/init.js.map +1 -1
  17. package/dist/cli/serve.d.ts.map +1 -1
  18. package/dist/cli/serve.js +8 -2
  19. package/dist/cli/serve.js.map +1 -1
  20. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  21. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  22. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  23. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  24. package/dist/conformance/.generated/can-i-use.js +2 -2
  25. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  26. package/dist/conformance/.generated/conformance-docs.d.ts +12 -0
  27. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -0
  28. package/dist/conformance/.generated/conformance-docs.js +2 -0
  29. package/dist/conformance/.generated/conformance-docs.js.map +1 -0
  30. package/dist/conformance/docs.d.ts +6 -0
  31. package/dist/conformance/docs.d.ts.map +1 -0
  32. package/dist/conformance/docs.js +6 -0
  33. package/dist/conformance/docs.js.map +1 -0
  34. package/dist/remote/index.d.ts.map +1 -1
  35. package/dist/remote/index.js +1 -0
  36. package/dist/remote/index.js.map +1 -1
  37. package/dist/serve/activity-guard.d.ts +4 -0
  38. package/dist/serve/activity-guard.d.ts.map +1 -0
  39. package/dist/serve/activity-guard.js +22 -0
  40. package/dist/serve/activity-guard.js.map +1 -0
  41. package/dist/serve/activity-route.d.ts +4 -0
  42. package/dist/serve/activity-route.d.ts.map +1 -0
  43. package/dist/serve/activity-route.js +157 -0
  44. package/dist/serve/activity-route.js.map +1 -0
  45. package/dist/serve/activity-warning.d.ts +4 -0
  46. package/dist/serve/activity-warning.d.ts.map +1 -0
  47. package/dist/serve/activity-warning.js +21 -0
  48. package/dist/serve/activity-warning.js.map +1 -0
  49. package/dist/serve/bridge-mount.d.ts +5 -0
  50. package/dist/serve/bridge-mount.d.ts.map +1 -1
  51. package/dist/serve/bridge-mount.js +1 -0
  52. package/dist/serve/bridge-mount.js.map +1 -1
  53. package/dist/serve/docs-ui/404.html +3 -0
  54. package/dist/serve/docs-ui/_astro/{_slug_.DPUwShm2.css → _slug_.CXh9yTP1.css} +1 -1
  55. package/dist/serve/docs-ui/_astro/_slug_.DUci-duz.css +1 -0
  56. package/dist/serve/docs-ui/docs/_rhythm/index.html +2 -1
  57. package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +3 -2
  58. package/dist/serve/docs-ui/docs/agent/set-up-your-agent.md +1 -1
  59. package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +2 -1
  60. package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +2 -1
  61. package/dist/serve/docs-ui/docs/ai-compat/index.html +2 -1
  62. package/dist/serve/docs-ui/docs/api-reference/index.html +51 -49
  63. package/dist/serve/docs-ui/docs/api-reference.md +3 -3
  64. package/dist/serve/docs-ui/docs/app-compat/index.html +2 -1
  65. package/dist/serve/docs-ui/docs/auth-compat/index.html +2 -1
  66. package/dist/serve/docs-ui/docs/build/ai-logic/index.html +18 -3
  67. package/dist/serve/docs-ui/docs/build/ai-logic.md +30 -2
  68. package/dist/serve/docs-ui/docs/build/authentication/index.html +2 -1
  69. package/dist/serve/docs-ui/docs/build/authentication.md +1 -1
  70. package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +2 -1
  71. package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +46 -2
  72. package/dist/serve/docs-ui/docs/build/cloud-messaging.md +56 -1
  73. package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +2 -1
  74. package/dist/serve/docs-ui/docs/build/cloud-storage.md +1 -1
  75. package/dist/serve/docs-ui/docs/build/realtime-database/index.html +21 -3
  76. package/dist/serve/docs-ui/docs/build/realtime-database.md +25 -1
  77. package/dist/serve/docs-ui/docs/conformance-scores/index.html +2 -1
  78. package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +61 -28
  79. package/dist/serve/docs-ui/docs/create-pyric-reference-api.md +65 -20
  80. package/dist/serve/docs-ui/docs/database-compat/index.html +2 -1
  81. package/dist/serve/docs-ui/docs/firestore-compat/index.html +6 -5
  82. package/dist/serve/docs-ui/docs/firestore-compat.md +4 -4
  83. package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +2 -1
  84. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +2 -1
  85. package/dist/serve/docs-ui/docs/get-started/start-building/index.html +4 -3
  86. package/dist/serve/docs-ui/docs/get-started/start-building.md +2 -2
  87. package/dist/serve/docs-ui/docs/index.json +979 -579
  88. package/dist/serve/docs-ui/docs/messaging-compat/index.html +2 -1
  89. package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +2 -1
  90. package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +2 -1
  91. package/dist/serve/docs-ui/docs/overview/index.html +2 -1
  92. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +5 -4
  93. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api.md +3 -4
  94. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +5 -4
  95. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api.md +3 -4
  96. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +5 -4
  97. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api.md +3 -4
  98. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +2503 -12
  99. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api.md +2219 -8
  100. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api/index.html +916 -0
  101. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api.md +706 -0
  102. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +4 -3
  103. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api.md +2 -3
  104. package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +16 -11
  105. package/dist/serve/docs-ui/docs/pyric-ai-reference-api.md +14 -13
  106. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +4 -3
  107. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api.md +2 -3
  108. package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +7 -2
  109. package/dist/serve/docs-ui/docs/pyric-app-reference-api.md +5 -2
  110. package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +23 -12
  111. package/dist/serve/docs-ui/docs/pyric-auth-reference-api.md +15 -12
  112. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +10 -48
  113. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api.md +11 -24
  114. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +87 -97
  115. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api.md +53 -65
  116. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +14 -15
  117. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api.md +19 -28
  118. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +4 -3
  119. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api.md +2 -3
  120. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +3 -2
  121. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api.md +1 -2
  122. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +51 -0
  123. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api.md +36 -0
  124. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +3 -2
  125. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api.md +1 -2
  126. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +3 -2
  127. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api.md +1 -2
  128. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +3 -2
  129. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api.md +1 -2
  130. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +3 -2
  131. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api.md +1 -2
  132. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1067 -83
  133. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api.md +1291 -160
  134. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +253 -157
  135. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +179 -85
  136. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +72 -7
  137. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api.md +22 -7
  138. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +33 -12
  139. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +15 -12
  140. package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +18 -17
  141. package/dist/serve/docs-ui/docs/pyric-database-reference-api.md +19 -22
  142. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1512 -545
  143. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api.md +1311 -316
  144. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +5 -4
  145. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api.md +3 -4
  146. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +69 -369
  147. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api.md +103 -216
  148. package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +10 -9
  149. package/dist/serve/docs-ui/docs/pyric-rules-reference-api.md +9 -10
  150. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +8 -7
  151. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api.md +6 -7
  152. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +10 -9
  153. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api.md +9 -10
  154. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +371 -884
  155. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +369 -883
  156. package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +25 -17
  157. package/dist/serve/docs-ui/docs/pyric-storage-reference-api.md +21 -19
  158. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +3 -2
  159. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api.md +1 -2
  160. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +63 -776
  161. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api.md +69 -510
  162. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +22 -21
  163. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api.md +29 -30
  164. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +15 -168
  165. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api.md +17 -87
  166. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +6 -5
  167. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api.md +5 -6
  168. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +82 -970
  169. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api.md +104 -479
  170. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +30 -29
  171. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api.md +54 -55
  172. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +3 -2
  173. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api.md +1 -2
  174. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +5 -4
  175. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api.md +3 -4
  176. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +9 -124
  177. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api.md +7 -58
  178. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +24 -23
  179. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api.md +31 -34
  180. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +104 -1385
  181. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api.md +133 -817
  182. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +34 -33
  183. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api.md +37 -38
  184. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +116 -1169
  185. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api.md +142 -590
  186. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +4 -3
  187. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api.md +3 -4
  188. package/dist/serve/docs-ui/docs/rules-compat/index.html +34 -1
  189. package/dist/serve/docs-ui/docs/rules-compat.md +32 -0
  190. package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +19 -2
  191. package/dist/serve/docs-ui/docs/secure/audit-your-rules.md +32 -0
  192. package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +2 -1
  193. package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +2 -1
  194. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +2 -1
  195. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript.md +1 -1
  196. package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +2 -1
  197. package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +2 -1
  198. package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +2 -1
  199. package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +2 -1
  200. package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +2 -1
  201. package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +2 -1
  202. package/dist/serve/docs-ui/docs/storage-compat/index.html +2 -1
  203. package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +2 -1
  204. package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +2 -1
  205. package/dist/serve/docs-ui/llms.txt +2 -1
  206. package/dist/serve/entries/ai.d.ts.map +1 -1
  207. package/dist/serve/entries/ai.js +39 -1
  208. package/dist/serve/entries/ai.js.map +1 -1
  209. package/dist/serve/entries/messaging-sw.d.ts.map +1 -1
  210. package/dist/serve/entries/messaging-sw.js +5 -1
  211. package/dist/serve/entries/messaging-sw.js.map +1 -1
  212. package/dist/serve/entries/messaging.d.ts.map +1 -1
  213. package/dist/serve/entries/messaging.js +7 -1
  214. package/dist/serve/entries/messaging.js.map +1 -1
  215. package/dist/serve/entries/runtime.d.ts.map +1 -1
  216. package/dist/serve/entries/runtime.js +20 -1
  217. package/dist/serve/entries/runtime.js.map +1 -1
  218. package/dist/serve/init-payload.d.ts +25 -0
  219. package/dist/serve/init-payload.d.ts.map +1 -1
  220. package/dist/serve/namespace.d.ts +39 -0
  221. package/dist/serve/namespace.d.ts.map +1 -1
  222. package/dist/serve/namespace.js +80 -1
  223. package/dist/serve/namespace.js.map +1 -1
  224. package/dist/serve/standalone-assets.d.ts +11 -9
  225. package/dist/serve/standalone-assets.d.ts.map +1 -1
  226. package/dist/serve/standalone-assets.js +6 -5
  227. package/dist/serve/standalone-assets.js.map +1 -1
  228. package/dist/serve/studio-ui/assets/{RulesCodeEditor-CXdSLKhO.js → RulesCodeEditor-CxVYcZXw.js} +1 -1
  229. package/dist/serve/studio-ui/assets/index-cpSfgQ7H.js +1218 -0
  230. package/dist/serve/studio-ui/assets/seed-DeuFKi4J.js +20 -0
  231. package/dist/serve/studio-ui/index.html +1 -1
  232. package/dist/serve/vite-plugin.d.ts +92 -15
  233. package/dist/serve/vite-plugin.d.ts.map +1 -1
  234. package/dist/serve/vite-plugin.js +281 -11
  235. package/dist/serve/vite-plugin.js.map +1 -1
  236. package/dist/serve/worker/activity-bootstrap.d.ts +8 -0
  237. package/dist/serve/worker/activity-bootstrap.d.ts.map +1 -0
  238. package/dist/serve/worker/activity-bootstrap.js +11 -0
  239. package/dist/serve/worker/activity-bootstrap.js.map +1 -0
  240. package/dist/serve/worker/client/connection.d.ts.map +1 -1
  241. package/dist/serve/worker/client/connection.js +17 -5
  242. package/dist/serve/worker/client/connection.js.map +1 -1
  243. package/dist/serve/worker/client/core.d.ts +2 -2
  244. package/dist/serve/worker/client/core.d.ts.map +1 -1
  245. package/dist/serve/worker/client/core.js +33 -5
  246. package/dist/serve/worker/client/core.js.map +1 -1
  247. package/dist/serve/worker/client/firestore-writes.d.ts.map +1 -1
  248. package/dist/serve/worker/client/firestore-writes.js +1 -0
  249. package/dist/serve/worker/client/firestore-writes.js.map +1 -1
  250. package/dist/serve/worker/client/messaging.d.ts +9 -1
  251. package/dist/serve/worker/client/messaging.d.ts.map +1 -1
  252. package/dist/serve/worker/client/messaging.js +15 -0
  253. package/dist/serve/worker/client/messaging.js.map +1 -1
  254. package/dist/serve/worker/client/studio.d.ts +10 -0
  255. package/dist/serve/worker/client/studio.d.ts.map +1 -1
  256. package/dist/serve/worker/client/studio.js +11 -0
  257. package/dist/serve/worker/client/studio.js.map +1 -1
  258. package/dist/serve/worker/durable-persistence.d.ts +12 -0
  259. package/dist/serve/worker/durable-persistence.d.ts.map +1 -0
  260. package/dist/serve/worker/durable-persistence.js +118 -0
  261. package/dist/serve/worker/durable-persistence.js.map +1 -0
  262. package/dist/serve/worker/entry.d.ts +7 -3
  263. package/dist/serve/worker/entry.d.ts.map +1 -1
  264. package/dist/serve/worker/entry.js +7 -3
  265. package/dist/serve/worker/entry.js.map +1 -1
  266. package/dist/serve/worker/host/core.d.ts +9 -5
  267. package/dist/serve/worker/host/core.d.ts.map +1 -1
  268. package/dist/serve/worker/host/core.js +34 -9
  269. package/dist/serve/worker/host/core.js.map +1 -1
  270. package/dist/serve/worker/host/dispatch.d.ts.map +1 -1
  271. package/dist/serve/worker/host/dispatch.js +9 -2
  272. package/dist/serve/worker/host/dispatch.js.map +1 -1
  273. package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -1
  274. package/dist/serve/worker/host/firestore-writes.js +3 -2
  275. package/dist/serve/worker/host/firestore-writes.js.map +1 -1
  276. package/dist/serve/worker/host/studio.d.ts +1 -1
  277. package/dist/serve/worker/host/studio.d.ts.map +1 -1
  278. package/dist/serve/worker/host/studio.js +36 -1
  279. package/dist/serve/worker/host/studio.js.map +1 -1
  280. package/dist/serve/worker/host/subscriptions.d.ts.map +1 -1
  281. package/dist/serve/worker/host/subscriptions.js +27 -7
  282. package/dist/serve/worker/host/subscriptions.js.map +1 -1
  283. package/dist/serve/worker/host-context.d.ts +15 -0
  284. package/dist/serve/worker/host-context.d.ts.map +1 -1
  285. package/dist/serve/worker/host-context.js +10 -0
  286. package/dist/serve/worker/host-context.js.map +1 -1
  287. package/dist/serve/worker/host-messaging.d.ts.map +1 -1
  288. package/dist/serve/worker/host-messaging.js +9 -2
  289. package/dist/serve/worker/host-messaging.js.map +1 -1
  290. package/dist/serve/worker/index.d.ts +3 -2
  291. package/dist/serve/worker/index.d.ts.map +1 -1
  292. package/dist/serve/worker/index.js +4 -1
  293. package/dist/serve/worker/index.js.map +1 -1
  294. package/dist/serve/worker/protocol.d.ts +25 -3
  295. package/dist/serve/worker/protocol.d.ts.map +1 -1
  296. package/dist/serve/worker/protocol.js +2 -2
  297. package/dist/serve/worker/protocol.js.map +1 -1
  298. package/dist/serve/worker/serve-init.d.ts +23 -37
  299. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  300. package/dist/serve/worker/serve-init.js +95 -172
  301. package/dist/serve/worker/serve-init.js.map +1 -1
  302. package/dist/vite.d.ts +4 -4
  303. package/dist/vite.d.ts.map +1 -1
  304. package/dist/vite.js +3 -3
  305. package/dist/vite.js.map +1 -1
  306. package/package.json +9 -4
  307. package/src/assurance/.generated/conformance-verdicts.ts +1090 -0
  308. package/src/assurance/attachment.ts +211 -0
  309. package/src/assurance/browser.ts +80 -0
  310. package/src/assurance/campaign.ts +496 -0
  311. package/src/assurance/capabilities.ts +446 -0
  312. package/src/assurance/cases.ts +43 -0
  313. package/src/assurance/index.ts +75 -0
  314. package/src/assurance/runner.ts +885 -0
  315. package/src/assurance/tool-names.ts +15 -0
  316. package/src/assurance/tools.ts +830 -0
  317. package/src/assurance/types.ts +352 -0
  318. package/src/assurance/validation.ts +434 -0
  319. package/src/bridge/client/bridge.ts +550 -0
  320. package/src/bridge/client/dispatch.ts +137 -0
  321. package/src/bridge/client.ts +45 -0
  322. package/src/bridge/protocol.ts +351 -0
  323. package/src/bridge/server/audit.ts +53 -0
  324. package/src/bridge/server/bridge.ts +597 -0
  325. package/src/bridge/server/headless.ts +160 -0
  326. package/src/bridge/server/json-schema-to-zod.ts +108 -0
  327. package/src/bridge/server/local-bridge.ts +66 -0
  328. package/src/bridge/server/logger.ts +50 -0
  329. package/src/bridge/server/mcp-contract.ts +93 -0
  330. package/src/bridge/server/mcp.ts +129 -0
  331. package/src/bridge/server/peer.ts +232 -0
  332. package/src/bridge/server/standalone.ts +347 -0
  333. package/src/bridge/server/tool-metadata.ts +99 -0
  334. package/src/bridge/server.ts +28 -0
  335. package/src/cli/can-i-use.ts +50 -0
  336. package/src/cli/cli.test.ts +493 -0
  337. package/src/cli/database-rules.ts +329 -0
  338. package/src/cli/dev-runner.ts +282 -0
  339. package/src/cli/firebase-json.ts +100 -0
  340. package/src/cli/firestore-indexes.ts +70 -0
  341. package/src/cli/index.ts +425 -0
  342. package/src/cli/init.ts +260 -0
  343. package/src/cli/mcp-proxy.ts +196 -0
  344. package/src/cli/parse-args.ts +80 -0
  345. package/src/cli/rules.ts +259 -0
  346. package/src/cli/scope.ts +67 -0
  347. package/src/cli/serve.ts +996 -0
  348. package/src/cli/service-commands.ts +73 -0
  349. package/src/cli/snapshot.ts +164 -0
  350. package/src/cli/storage-rules.ts +172 -0
  351. package/src/cli/verify.ts +416 -0
  352. package/src/conformance/.generated/can-i-use-browser.ts +113 -0
  353. package/src/conformance/.generated/can-i-use.ts +117 -0
  354. package/src/conformance/.generated/conformance-docs.ts +14 -0
  355. package/src/conformance/browser.ts +24 -0
  356. package/src/conformance/can-i-use-tool.ts +51 -0
  357. package/src/conformance/can-i-use.ts +18 -0
  358. package/src/conformance/docs.ts +8 -0
  359. package/src/conformance/index.ts +20 -0
  360. package/src/conformance/tools.ts +16 -0
  361. package/src/credentials/core/memoize-ttl.ts +142 -0
  362. package/src/credentials/core/types.ts +10 -0
  363. package/src/credentials/node/from-adc.ts +96 -0
  364. package/src/credentials/node/from-service-account.ts +133 -0
  365. package/src/credentials/node/index.ts +6 -0
  366. package/src/discover/concurrency.ts +127 -0
  367. package/src/discover/crawler-adapter.ts +142 -0
  368. package/src/discover/crawler.ts +1127 -0
  369. package/src/discover/credential-free.ts +27 -0
  370. package/src/discover/findCollectionGroup.ts +131 -0
  371. package/src/discover/firestore-source.ts +59 -0
  372. package/src/discover/index.ts +5 -0
  373. package/src/discover/merge.ts +523 -0
  374. package/src/discover/session.ts +402 -0
  375. package/src/discover/tools.ts +201 -0
  376. package/src/discover/types.ts +187 -0
  377. package/src/discover/wire.ts +324 -0
  378. package/src/functions-rtdb/child.ts +382 -0
  379. package/src/functions-rtdb/delivery.ts +7 -0
  380. package/src/functions-rtdb/discovery.ts +136 -0
  381. package/src/functions-rtdb/event.ts +64 -0
  382. package/src/functions-rtdb/execution.ts +111 -0
  383. package/src/functions-rtdb/in-memory-delivery.ts +40 -0
  384. package/src/functions-rtdb/project.ts +74 -0
  385. package/src/functions-rtdb/projection.ts +104 -0
  386. package/src/functions-rtdb/reference-pattern.ts +20 -0
  387. package/src/functions-rtdb/remote-delivery.ts +23 -0
  388. package/src/pkg-version.ts +49 -0
  389. package/src/register/esm-exports.ts +63 -0
  390. package/src/register/hooks.ts +30 -0
  391. package/src/register/index.ts +150 -0
  392. package/src/register/mapping.ts +33 -0
  393. package/src/remote/index.ts +1050 -0
  394. package/src/rtdb/crawl-snapshot.ts +118 -0
  395. package/src/rtdb/inspection.ts +137 -0
  396. package/src/rtdb/load-rules-document.ts +56 -0
  397. package/src/rtdb/rules-generation-tool.ts +38 -0
  398. package/src/rtdb/rules-json.ts +29 -0
  399. package/src/serve/activity-guard.ts +29 -0
  400. package/src/serve/activity-route.ts +164 -0
  401. package/src/serve/activity-warning.ts +26 -0
  402. package/src/serve/bridge-mount.ts +200 -0
  403. package/src/serve/bundler.ts +493 -0
  404. package/src/serve/capture-store.ts +65 -0
  405. package/src/serve/discovery.ts +199 -0
  406. package/src/serve/entries/ai.ts +292 -0
  407. package/src/serve/entries/app-backend.ts +4 -0
  408. package/src/serve/entries/app-client.ts +26 -0
  409. package/src/serve/entries/app-session-store.ts +47 -0
  410. package/src/serve/entries/app.ts +11 -0
  411. package/src/serve/entries/auth-helper-core.ts +181 -0
  412. package/src/serve/entries/auth-helper-dom.ts +134 -0
  413. package/src/serve/entries/auth-helper-runtime.ts +20 -0
  414. package/src/serve/entries/auth.ts +255 -0
  415. package/src/serve/entries/bridge-url.ts +31 -0
  416. package/src/serve/entries/database.ts +129 -0
  417. package/src/serve/entries/firestore.ts +232 -0
  418. package/src/serve/entries/init.ts +46 -0
  419. package/src/serve/entries/keepalive.ts +46 -0
  420. package/src/serve/entries/messaging-sw.ts +75 -0
  421. package/src/serve/entries/messaging.ts +96 -0
  422. package/src/serve/entries/runtime.ts +540 -0
  423. package/src/serve/entries/session-store.ts +97 -0
  424. package/src/serve/entries/storage.ts +92 -0
  425. package/src/serve/entries/tab-sync-wiring.ts +274 -0
  426. package/src/serve/entries/worker-runtime.ts +75 -0
  427. package/src/serve/init-payload.ts +42 -0
  428. package/src/serve/namespace.ts +675 -0
  429. package/src/serve/open-browser.ts +68 -0
  430. package/src/serve/rules.ts +272 -0
  431. package/src/serve/sandbox-marker.ts +31 -0
  432. package/src/serve/server.ts +428 -0
  433. package/src/serve/standalone-assets.ts +180 -0
  434. package/src/serve/state-store.ts +166 -0
  435. package/src/serve/studio/disk-project-store.ts +185 -0
  436. package/src/serve/studio/disk-workspace.ts +162 -0
  437. package/src/serve/studio/index.ts +20 -0
  438. package/src/serve/studio/routes.ts +237 -0
  439. package/src/serve/studio/store-types.ts +48 -0
  440. package/src/serve/studio/studio-storage.test.ts +289 -0
  441. package/src/serve/vite-plugin.ts +1102 -0
  442. package/src/serve/worker/activity-bootstrap.ts +24 -0
  443. package/src/serve/worker/client/admin-firestore.ts +38 -0
  444. package/src/serve/worker/client/ai.ts +124 -0
  445. package/src/serve/worker/client/auth.ts +489 -0
  446. package/src/serve/worker/client/connection.ts +202 -0
  447. package/src/serve/worker/client/core.ts +350 -0
  448. package/src/serve/worker/client/disconnect.ts +45 -0
  449. package/src/serve/worker/client/firestore-reads.ts +181 -0
  450. package/src/serve/worker/client/firestore-refs.ts +226 -0
  451. package/src/serve/worker/client/firestore-writes.ts +232 -0
  452. package/src/serve/worker/client/handles.ts +91 -0
  453. package/src/serve/worker/client/messaging.ts +119 -0
  454. package/src/serve/worker/client/presence.ts +174 -0
  455. package/src/serve/worker/client/rtdb.ts +311 -0
  456. package/src/serve/worker/client/rules.ts +63 -0
  457. package/src/serve/worker/client/service-worker-connection.ts +59 -0
  458. package/src/serve/worker/client/snapshots.ts +86 -0
  459. package/src/serve/worker/client/storage.ts +195 -0
  460. package/src/serve/worker/client/studio.ts +88 -0
  461. package/src/serve/worker/client.ts +57 -0
  462. package/src/serve/worker/durable-persistence.ts +137 -0
  463. package/src/serve/worker/entry.ts +179 -0
  464. package/src/serve/worker/host/admin-firestore.ts +88 -0
  465. package/src/serve/worker/host/connection.ts +179 -0
  466. package/src/serve/worker/host/core.ts +387 -0
  467. package/src/serve/worker/host/dispatch.ts +316 -0
  468. package/src/serve/worker/host/firestore-reads.ts +117 -0
  469. package/src/serve/worker/host/firestore-writes.ts +456 -0
  470. package/src/serve/worker/host/presence.ts +312 -0
  471. package/src/serve/worker/host/rtdb.ts +136 -0
  472. package/src/serve/worker/host/rules.ts +128 -0
  473. package/src/serve/worker/host/storage.ts +312 -0
  474. package/src/serve/worker/host/studio.ts +75 -0
  475. package/src/serve/worker/host/subscriptions.ts +238 -0
  476. package/src/serve/worker/host-ai.ts +165 -0
  477. package/src/serve/worker/host-auth.ts +469 -0
  478. package/src/serve/worker/host-context.ts +273 -0
  479. package/src/serve/worker/host-events.ts +94 -0
  480. package/src/serve/worker/host-messaging.ts +240 -0
  481. package/src/serve/worker/host.ts +47 -0
  482. package/src/serve/worker/index.ts +196 -0
  483. package/src/serve/worker/presence-timing.ts +15 -0
  484. package/src/serve/worker/protocol.ts +1112 -0
  485. package/src/serve/worker/serve-init.ts +606 -0
  486. package/src/serve/worker/service-worker-channel.ts +33 -0
  487. package/src/serve/worker/service-worker-relay.ts +86 -0
  488. package/src/serve/writer-lock.ts +53 -0
  489. package/src/verify/cases.ts +233 -0
  490. package/src/verify/fixture.ts +258 -0
  491. package/src/verify/index.ts +519 -0
  492. package/src/verify/tools.ts +108 -0
  493. package/src/version/compat-target.ts +17 -0
  494. package/src/vite.ts +17 -0
  495. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -30
  496. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -30
  497. package/dist/serve/studio-ui/assets/index-BvtQIpGn.js +0 -1211
  498. package/dist/serve/studio-ui/assets/seed-3DMedLL3.js +0 -2
@@ -0,0 +1,597 @@
1
+ /**
2
+ * Bridge core — process-local state for forwarding MCP tool calls
3
+ * from external clients to the (one) connected sandbox peer in the
4
+ * browser. Transport-agnostic: the HTTP MCP server and the WS server
5
+ * both plug into this through `dispatch()` / `handleSandboxMessage()`
6
+ * / `registerSandboxPeer()`.
7
+ *
8
+ * Multi-tab is naive: last-connection-wins. New peer replaces the
9
+ * old, pending calls against the old peer reject with a clear error.
10
+ *
11
+ * Every tool call is forwarded over WS to the browser. The bridge does not
12
+ * execute data-plane tools itself; it acts as a relay with a tool-name
13
+ * allow-list pinned by the peer's `hello`.
14
+ */
15
+
16
+ import { randomUUID } from 'node:crypto';
17
+ import type {
18
+ BridgeMessage,
19
+ HealthReport,
20
+ ToolCallResponse,
21
+ WorkerOpPayload,
22
+ WorkerSubPayload,
23
+ WorkerResFrame,
24
+ WorkerSnapFrame,
25
+ } from '../protocol.js';
26
+ import {
27
+ NO_SANDBOX_ERROR_MESSAGE,
28
+ NO_WORKER_RELAY_ERROR_MESSAGE,
29
+ WORKER_RELAY_CAPABILITY,
30
+ } from '../protocol.js';
31
+
32
+ /** Subset of `@inbrowser/agent`'s `ToolResult` shape the bridge emits. */
33
+ export interface BridgeToolResult {
34
+ ok: boolean;
35
+ summary: string;
36
+ data?: unknown;
37
+ }
38
+
39
+ /** Function the bridge calls to send a message to the current sandbox peer. */
40
+ export type SendToPeer = (msg: BridgeMessage) => void;
41
+
42
+ export interface BridgeOptions {
43
+ /** Sandbox label surfaced in /health and audit-log paths. */
44
+ project?: string;
45
+ /** Bridge version surfaced in /health + Hello messages. */
46
+ version: string;
47
+ /**
48
+ * Per-call request timeout in ms when forwarding to the browser.
49
+ * Defaults to 30s; the bridge rejects the MCP call with a clear
50
+ * "sandbox call timed out" error after this.
51
+ */
52
+ callTimeoutMs?: number;
53
+ /**
54
+ * Hook called whenever a tool finishes (success or failure).
55
+ * Use this for the audit log — write the entry to disk here.
56
+ * The bridge does not own audit-log persistence.
57
+ */
58
+ onToolEvent?: (event: BridgeToolEvent) => void;
59
+ }
60
+
61
+ export interface BridgeToolEvent {
62
+ timestamp: string;
63
+ mode: 'sandbox';
64
+ project: string;
65
+ tool: string;
66
+ args: Record<string, unknown>;
67
+ result: BridgeToolResult | { ok: false; summary: string; error?: { code: string; message: string } };
68
+ durationMs: number;
69
+ }
70
+
71
+ export interface Bridge {
72
+ readonly project: string;
73
+ readonly version: string;
74
+ readonly startedAt: string;
75
+ /** Stable per-process identity (see HealthReport.instanceId). */
76
+ readonly instanceId: string;
77
+ /**
78
+ * Record a tool event in the bridge's audit pipeline. In-process sandbox
79
+ * tools use this path; forwarded tools log inside dispatch().
80
+ */
81
+ recordToolEvent(event: BridgeToolEvent): void;
82
+
83
+ /**
84
+ * Register a browser-side peer. Returns a disconnect function the
85
+ * caller MUST invoke when the WS closes. Last-wins: a new
86
+ * registration disconnects the previous peer (its pending calls
87
+ * fail with a clear error).
88
+ *
89
+ * `capabilities` come from the peer's `hello` — the bridge only sends
90
+ * `worker-*` frames to a peer that declared `'worker-relay'`.
91
+ *
92
+ * `onReplaced` fires when a NEWER registration displaces this peer. The
93
+ * transport MUST use it to close the old socket: the browser side's
94
+ * close handler tears down its relayed worker subscriptions — without
95
+ * this, a replaced tab's SharedWorker listeners would live until the tab
96
+ * closed, streaming snaps the bridge drops as stale-generation forever.
97
+ */
98
+ registerSandboxPeer(
99
+ send: SendToPeer,
100
+ tools: string[],
101
+ sandboxId: string,
102
+ capabilities?: string[],
103
+ onReplaced?: () => void,
104
+ ): () => void;
105
+
106
+ /** True if a sandbox peer is currently registered. */
107
+ isSandboxConnected(): boolean;
108
+
109
+ /**
110
+ * Generation counter of the CURRENT peer registration (0 = no peer has
111
+ * ever registered). The transport captures this right after registering
112
+ * and tags every inbound message with it, so a frame arriving on a
113
+ * REPLACED peer's socket (tab refresh mid-flight) can never resolve a new
114
+ * peer's pending call or deliver a stale subscription snapshot.
115
+ */
116
+ peerGeneration(): number;
117
+
118
+ /** Tool names the bridge currently exposes to MCP. */
119
+ toolNames(): string[];
120
+
121
+ /** Dispatch a tool call to the connected sandbox peer. */
122
+ dispatch(name: string, args: Record<string, unknown>): Promise<BridgeToolResult>;
123
+
124
+ /**
125
+ * Relay a generic worker op to the peer's SharedWorker. Resolves with the
126
+ * worker's `res.value`; rejects with an Error carrying `.code` on worker
127
+ * failure, timeout, no peer, or a peer without the worker relay.
128
+ */
129
+ dispatchWorkerOp(op: WorkerOpPayload): Promise<unknown>;
130
+
131
+ /**
132
+ * Register a worker subscription. Ownership lives HERE: the registry
133
+ * survives peer churn, and every registered sub is re-issued to a new
134
+ * peer on registration (RTDB value / auth-state subs re-deliver a fresh
135
+ * initial snapshot, so replay is cursor-free). `onSnap` receives every
136
+ * relayed snap value verbatim — including the worker host's
137
+ * `{ __error: { code, message } }` establishment-failure convention.
138
+ * Returns the unsubscribe function.
139
+ */
140
+ subscribeWorker(sub: WorkerSubPayload, onSnap: (value: unknown) => void): () => void;
141
+
142
+ /**
143
+ * Handle a message from the sandbox peer (tool-result, pong, …).
144
+ * `generation` is the peer generation the transport captured at
145
+ * registration; when provided, `worker-res`/`worker-snap` frames from a
146
+ * stale generation are dropped.
147
+ */
148
+ handleSandboxMessage(msg: BridgeMessage, generation?: number): void;
149
+
150
+ /** /health endpoint payload. */
151
+ health(): HealthReport;
152
+ }
153
+
154
+ interface PendingCall {
155
+ id: string;
156
+ resolve: (result: BridgeToolResult) => void;
157
+ timer: ReturnType<typeof setTimeout>;
158
+ tool: string;
159
+ }
160
+
161
+ interface ActivePeer {
162
+ send: SendToPeer;
163
+ tools: Set<string>;
164
+ sandboxId: string;
165
+ capabilities: Set<string>;
166
+ onReplaced?: () => void;
167
+ }
168
+
169
+ interface PendingWorkerOp {
170
+ resolve: (value: unknown) => void;
171
+ reject: (err: Error) => void;
172
+ timer: ReturnType<typeof setTimeout>;
173
+ method: string;
174
+ }
175
+
176
+ interface WorkerSubEntry {
177
+ sub: WorkerSubPayload;
178
+ onSnap: (value: unknown) => void;
179
+ /**
180
+ * JSON of the last snap value delivered to `onSnap` — the re-issue dedup
181
+ * baseline. Lives on the bridge-side entry because this registry is the
182
+ * only state that SURVIVES peer churn (the browser tab and the worker
183
+ * listener are both rebuilt per peer).
184
+ */
185
+ lastDeliveredJson?: string;
186
+ /**
187
+ * Set when this sub was just (re-)issued to a newly registered peer and
188
+ * the next inbound snap is the fresh listener's INITIAL snapshot. When
189
+ * that snapshot is byte-identical to `lastDeliveredJson`, nothing changed
190
+ * while the peer churned and the frame is suppressed — real Firestore /
191
+ * RTDB listeners fire on CHANGE, not on transport reconnection. Live,
192
+ * two tabs fighting over last-wins registration (each reconnecting after
193
+ * ~500ms) re-issued every sub once per registration, so a consumer's
194
+ * doc listener fired ~1/sec with identical data forever. A snapshot that
195
+ * DIFFERS from the baseline (state changed while no peer was attached)
196
+ * still delivers. Scoped to the one-frame re-issue window so steady-state
197
+ * delivery is untouched.
198
+ */
199
+ awaitingReissueSnap?: boolean;
200
+ }
201
+
202
+ /** Build the typed Error worker-op rejections carry. `denialContext` (spike
203
+ * gap 6) is re-attached when the wire error carried one, so the structured
204
+ * denial frame survives the bridge hop. */
205
+ function workerOpError(
206
+ code: string,
207
+ message: string,
208
+ denialContext?: unknown,
209
+ ): Error & { code: string; denialContext?: unknown } {
210
+ const err = new Error(message) as Error & { code: string; denialContext?: unknown };
211
+ err.code = code;
212
+ if (denialContext !== undefined) err.denialContext = denialContext;
213
+ return err;
214
+ }
215
+
216
+ export function createBridge(opts: BridgeOptions): Bridge {
217
+ const project = opts.project ?? 'sandbox';
218
+ const version = opts.version;
219
+ const callTimeoutMs = opts.callTimeoutMs ?? 30_000;
220
+ const startedAt = new Date().toISOString();
221
+ // Per-process identity (see HealthReport.instanceId): the discovery pointer
222
+ // records this so a proxy can verify it reached THIS server, not a different
223
+ // sandbox squatting the same port on the other loopback family.
224
+ const instanceId = randomUUID();
225
+ const onToolEvent = opts.onToolEvent;
226
+
227
+ let peer: ActivePeer | null = null;
228
+ const pending = new Map<string, PendingCall>();
229
+ // ── worker relay state ──
230
+ // Generation counter: bumped on every peer registration. Inbound frames
231
+ // tagged with an older generation are stale (a replaced tab's socket) and
232
+ // must not resolve ops / deliver snaps registered under the new peer.
233
+ let generation = 0;
234
+ const workerPending = new Map<string, PendingWorkerOp>();
235
+ // Subscription ownership lives on the bridge: entries survive peer churn
236
+ // and are re-issued to every newly registered relay-capable peer.
237
+ const workerSubs = new Map<string, WorkerSubEntry>();
238
+
239
+ function failAllPending(reason: string) {
240
+ for (const call of pending.values()) {
241
+ clearTimeout(call.timer);
242
+ call.resolve({
243
+ ok: false,
244
+ summary: reason,
245
+ });
246
+ }
247
+ pending.clear();
248
+ for (const op of workerPending.values()) {
249
+ clearTimeout(op.timer);
250
+ op.reject(workerOpError('unavailable', reason));
251
+ }
252
+ workerPending.clear();
253
+ }
254
+
255
+ function peerHasRelay(): boolean {
256
+ return peer !== null && peer.capabilities.has(WORKER_RELAY_CAPABILITY);
257
+ }
258
+
259
+ function registerSandboxPeer(
260
+ send: SendToPeer,
261
+ tools: string[],
262
+ sandboxId: string,
263
+ capabilities: string[] = [],
264
+ onReplaced?: () => void,
265
+ ): () => void {
266
+ if (peer) {
267
+ // Last-wins: kick the old peer and reject its pending calls.
268
+ failAllPending('sandbox peer replaced by a newer connection');
269
+ // Tear the old peer down (the transport closes its socket). The
270
+ // browser's close handler tears down its relayed worker
271
+ // subscriptions — otherwise the replaced tab's SharedWorker
272
+ // listeners would keep posting snaps this bridge drops as
273
+ // stale-generation until the tab closed.
274
+ try {
275
+ peer.onReplaced?.();
276
+ } catch {
277
+ // A failing transport hook must not block the new registration.
278
+ }
279
+ }
280
+ generation += 1;
281
+ const myPeer: ActivePeer = {
282
+ send,
283
+ tools: new Set(tools),
284
+ sandboxId,
285
+ capabilities: new Set(capabilities),
286
+ onReplaced,
287
+ };
288
+ peer = myPeer;
289
+ // Re-issue every registered worker subscription to the new peer — the
290
+ // replay is cursor-free because each (re)subscribe delivers a fresh
291
+ // initial snapshot. That snapshot is a DUPLICATE whenever nothing
292
+ // changed while the peer churned, so `awaitingReissueSnap` arms the
293
+ // per-sub dedup (see WorkerSubEntry) — without it, tabs cycling through
294
+ // last-wins registration re-fire every consumer listener with
295
+ // byte-identical data on every registration.
296
+ if (myPeer.capabilities.has(WORKER_RELAY_CAPABILITY)) {
297
+ for (const [subId, entry] of workerSubs) {
298
+ entry.awaitingReissueSnap = true;
299
+ try {
300
+ myPeer.send({ type: 'worker-sub', subId, sub: entry.sub });
301
+ } catch {
302
+ // Socket failure surfaces via the transport's close handler.
303
+ }
304
+ }
305
+ }
306
+ return () => {
307
+ if (peer === myPeer) {
308
+ failAllPending(NO_SANDBOX_ERROR_MESSAGE);
309
+ peer = null;
310
+ }
311
+ };
312
+ }
313
+
314
+ function isSandboxConnected(): boolean {
315
+ return peer !== null;
316
+ }
317
+
318
+ function peerGeneration(): number {
319
+ return generation;
320
+ }
321
+
322
+ function toolNames(): string[] {
323
+ return peer ? Array.from(peer.tools).sort() : [];
324
+ }
325
+
326
+ async function dispatch(
327
+ name: string,
328
+ args: Record<string, unknown>,
329
+ ): Promise<BridgeToolResult> {
330
+ const startedAtMs = Date.now();
331
+ let result: BridgeToolResult;
332
+ try {
333
+ result = await dispatchSandbox(name, args);
334
+ } catch (err) {
335
+ result = {
336
+ ok: false,
337
+ summary: err instanceof Error ? err.message : String(err),
338
+ };
339
+ }
340
+ if (onToolEvent) {
341
+ try {
342
+ onToolEvent({
343
+ timestamp: new Date(startedAtMs).toISOString(),
344
+ mode: 'sandbox',
345
+ project,
346
+ tool: name,
347
+ args,
348
+ result,
349
+ durationMs: Date.now() - startedAtMs,
350
+ });
351
+ } catch {
352
+ // Audit-log failures must not break tool dispatch.
353
+ }
354
+ }
355
+ return result;
356
+ }
357
+
358
+ function dispatchSandbox(
359
+ name: string,
360
+ args: Record<string, unknown>,
361
+ ): Promise<BridgeToolResult> {
362
+ if (!peer) {
363
+ return Promise.resolve({ ok: false, summary: NO_SANDBOX_ERROR_MESSAGE });
364
+ }
365
+ if (!peer.tools.has(name)) {
366
+ return Promise.resolve({
367
+ ok: false,
368
+ summary: `tool '${name}' is not registered with the connected sandbox peer`,
369
+ });
370
+ }
371
+ return new Promise<BridgeToolResult>((resolve) => {
372
+ const id = randomUUID();
373
+ const timer = setTimeout(() => {
374
+ if (pending.has(id)) {
375
+ pending.delete(id);
376
+ resolve({
377
+ ok: false,
378
+ summary: `sandbox call timed out after ${callTimeoutMs}ms (tool: ${name})`,
379
+ });
380
+ }
381
+ }, callTimeoutMs);
382
+ pending.set(id, { id, resolve, timer, tool: name });
383
+ try {
384
+ peer!.send({
385
+ type: 'tool-call',
386
+ id,
387
+ name,
388
+ args,
389
+ });
390
+ } catch (err) {
391
+ clearTimeout(timer);
392
+ pending.delete(id);
393
+ resolve({
394
+ ok: false,
395
+ summary: `failed to send tool call to sandbox: ${err instanceof Error ? err.message : String(err)}`,
396
+ });
397
+ }
398
+ });
399
+ }
400
+
401
+ function dispatchWorkerOp(op: WorkerOpPayload): Promise<unknown> {
402
+ if (!peer) {
403
+ return Promise.reject(workerOpError('unavailable', NO_SANDBOX_ERROR_MESSAGE));
404
+ }
405
+ if (!peerHasRelay()) {
406
+ return Promise.reject(workerOpError('unimplemented', NO_WORKER_RELAY_ERROR_MESSAGE));
407
+ }
408
+ return new Promise<unknown>((resolve, reject) => {
409
+ const id = randomUUID();
410
+ const timer = setTimeout(() => {
411
+ if (workerPending.has(id)) {
412
+ workerPending.delete(id);
413
+ reject(
414
+ workerOpError(
415
+ 'deadline-exceeded',
416
+ `sandbox worker op timed out after ${callTimeoutMs}ms (op: ${op.method})`,
417
+ ),
418
+ );
419
+ }
420
+ }, callTimeoutMs);
421
+ workerPending.set(id, { resolve, reject, timer, method: op.method });
422
+ try {
423
+ peer!.send({ type: 'worker-op', id, op });
424
+ } catch (err) {
425
+ clearTimeout(timer);
426
+ workerPending.delete(id);
427
+ reject(
428
+ workerOpError(
429
+ 'unavailable',
430
+ `failed to send worker op to sandbox: ${err instanceof Error ? err.message : String(err)}`,
431
+ ),
432
+ );
433
+ }
434
+ });
435
+ }
436
+
437
+ function subscribeWorker(
438
+ sub: WorkerSubPayload,
439
+ onSnap: (value: unknown) => void,
440
+ ): () => void {
441
+ const subId = randomUUID();
442
+ workerSubs.set(subId, { sub, onSnap });
443
+ if (peerHasRelay()) {
444
+ try {
445
+ peer!.send({ type: 'worker-sub', subId, sub });
446
+ } catch {
447
+ // Socket failure surfaces via the transport's close handler; the
448
+ // registry entry replays on the next peer registration.
449
+ }
450
+ }
451
+ // No peer (or a relay-less peer) is NOT an error here: the registry is
452
+ // replayed on the next registration, mirroring RTDB's offline semantics.
453
+ return () => {
454
+ if (!workerSubs.delete(subId)) return;
455
+ if (peerHasRelay()) {
456
+ try {
457
+ peer!.send({ type: 'worker-unsub', subId });
458
+ } catch {}
459
+ }
460
+ };
461
+ }
462
+
463
+ function handleSandboxMessage(msg: BridgeMessage, msgGeneration?: number): void {
464
+ // Frames from a REPLACED peer's socket must not act on the current
465
+ // peer's state (subscriptions make stale delivery likely on tab
466
+ // refresh: the old tab's worker port keeps firing until its WS dies).
467
+ const stale = msgGeneration !== undefined && msgGeneration !== generation;
468
+ switch (msg.type) {
469
+ case 'worker-res': {
470
+ if (stale) return;
471
+ const res = msg as WorkerResFrame;
472
+ const op = workerPending.get(res.id);
473
+ if (!op) return; // late or unknown — drop silently
474
+ clearTimeout(op.timer);
475
+ workerPending.delete(res.id);
476
+ if (res.ok) {
477
+ op.resolve(res.value);
478
+ } else {
479
+ op.reject(
480
+ workerOpError(
481
+ res.error?.code ?? 'unknown',
482
+ res.error?.message ?? 'unknown sandbox error',
483
+ res.error?.denialContext,
484
+ ),
485
+ );
486
+ }
487
+ return;
488
+ }
489
+ case 'worker-snap': {
490
+ if (stale) return;
491
+ const snap = msg as WorkerSnapFrame;
492
+ const entry = workerSubs.get(snap.subId);
493
+ if (!entry) return; // unsubscribed or unknown — drop silently
494
+ // Re-issue dedup (see WorkerSubEntry.awaitingReissueSnap): the first
495
+ // snap after a peer (re)registration is the re-established listener's
496
+ // initial snapshot — suppress it when byte-identical to what the
497
+ // consumer already holds. Values are JSON-clean (they crossed the WS
498
+ // legs) and produced by the same serializer each time, so string
499
+ // equality is exact. One-frame window: the flag clears on the first
500
+ // snap either way, keeping steady-state delivery 1:1.
501
+ const json = JSON.stringify(snap.value);
502
+ const duplicate = entry.awaitingReissueSnap === true && json === entry.lastDeliveredJson;
503
+ entry.awaitingReissueSnap = false;
504
+ entry.lastDeliveredJson = json;
505
+ if (duplicate) return;
506
+ try {
507
+ entry.onSnap(snap.value);
508
+ } catch {
509
+ // Consumer callback failures must not break the relay loop.
510
+ }
511
+ return;
512
+ }
513
+ default:
514
+ break;
515
+ }
516
+ switch (msg.type) {
517
+ case 'tool-result': {
518
+ const response = msg as ToolCallResponse;
519
+ const call = pending.get(response.id);
520
+ if (!call) return; // late or unknown — drop silently
521
+ clearTimeout(call.timer);
522
+ pending.delete(response.id);
523
+ if (response.ok && response.result) {
524
+ call.resolve({
525
+ ok: response.result.ok,
526
+ summary: response.result.summary,
527
+ data: response.result.data,
528
+ });
529
+ } else {
530
+ const error = response.error;
531
+ call.resolve({
532
+ ok: false,
533
+ summary: error?.message ?? 'unknown sandbox error',
534
+ });
535
+ }
536
+ break;
537
+ }
538
+ case 'pong': {
539
+ // Keepalive ack; no-op.
540
+ break;
541
+ }
542
+ case 'ping': {
543
+ // Browser-initiated ping; echo back.
544
+ if (peer) {
545
+ peer.send({ type: 'pong', id: msg.id });
546
+ }
547
+ break;
548
+ }
549
+ case 'hello': {
550
+ // Re-hello after reconnect would arrive here, but the
551
+ // registration path is owned by the transport layer (it sees
552
+ // the WS first). Ignore.
553
+ break;
554
+ }
555
+ default:
556
+ break;
557
+ }
558
+ }
559
+
560
+ function health(): HealthReport {
561
+ return {
562
+ status: 'ok',
563
+ mode: 'sandbox',
564
+ project,
565
+ sandboxConnected: peer !== null,
566
+ version,
567
+ startedAt,
568
+ instanceId,
569
+ };
570
+ }
571
+
572
+ function recordToolEvent(event: BridgeToolEvent): void {
573
+ if (!onToolEvent) return;
574
+ try {
575
+ onToolEvent(event);
576
+ } catch {
577
+ // Audit-log failures must not break tool dispatch.
578
+ }
579
+ }
580
+
581
+ return {
582
+ project,
583
+ version,
584
+ startedAt,
585
+ instanceId,
586
+ recordToolEvent,
587
+ registerSandboxPeer,
588
+ isSandboxConnected,
589
+ peerGeneration,
590
+ toolNames,
591
+ dispatch,
592
+ dispatchWorkerOp,
593
+ subscribeWorker,
594
+ handleSandboxMessage,
595
+ health,
596
+ };
597
+ }