@pyric/cli 0.1.0-alpha.9

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 (1169) hide show
  1. package/LICENSE +216 -0
  2. package/README.md +156 -0
  3. package/README.md.orig +138 -0
  4. package/dist/assurance/attachment.d.ts +24 -0
  5. package/dist/assurance/attachment.d.ts.map +1 -0
  6. package/dist/assurance/attachment.js +138 -0
  7. package/dist/assurance/attachment.js.map +1 -0
  8. package/dist/assurance/browser.d.ts +7 -0
  9. package/dist/assurance/browser.d.ts.map +1 -0
  10. package/dist/assurance/browser.js +68 -0
  11. package/dist/assurance/browser.js.map +1 -0
  12. package/dist/assurance/campaign.d.ts +41 -0
  13. package/dist/assurance/campaign.d.ts.map +1 -0
  14. package/dist/assurance/campaign.js +364 -0
  15. package/dist/assurance/campaign.js.map +1 -0
  16. package/dist/assurance/capabilities.d.ts +7 -0
  17. package/dist/assurance/capabilities.d.ts.map +1 -0
  18. package/dist/assurance/capabilities.js +295 -0
  19. package/dist/assurance/capabilities.js.map +1 -0
  20. package/dist/assurance/cases.d.ts +14 -0
  21. package/dist/assurance/cases.d.ts.map +1 -0
  22. package/dist/assurance/cases.js +27 -0
  23. package/dist/assurance/cases.js.map +1 -0
  24. package/dist/assurance/generated-capabilities.d.ts +52 -0
  25. package/dist/assurance/generated-capabilities.d.ts.map +1 -0
  26. package/dist/assurance/generated-capabilities.js +329 -0
  27. package/dist/assurance/generated-capabilities.js.map +1 -0
  28. package/dist/assurance/index.d.ts +11 -0
  29. package/dist/assurance/index.d.ts.map +1 -0
  30. package/dist/assurance/index.js +9 -0
  31. package/dist/assurance/index.js.map +1 -0
  32. package/dist/assurance/runner.d.ts +3 -0
  33. package/dist/assurance/runner.d.ts.map +1 -0
  34. package/dist/assurance/runner.js +633 -0
  35. package/dist/assurance/runner.js.map +1 -0
  36. package/dist/assurance/tool-names.d.ts +4 -0
  37. package/dist/assurance/tool-names.d.ts.map +1 -0
  38. package/dist/assurance/tool-names.js +14 -0
  39. package/dist/assurance/tool-names.js.map +1 -0
  40. package/dist/assurance/tools.d.ts +19 -0
  41. package/dist/assurance/tools.d.ts.map +1 -0
  42. package/dist/assurance/tools.js +740 -0
  43. package/dist/assurance/tools.js.map +1 -0
  44. package/dist/assurance/types.d.ts +348 -0
  45. package/dist/assurance/types.d.ts.map +1 -0
  46. package/dist/assurance/types.js +7 -0
  47. package/dist/assurance/types.js.map +1 -0
  48. package/dist/assurance/validation.d.ts +8 -0
  49. package/dist/assurance/validation.d.ts.map +1 -0
  50. package/dist/assurance/validation.js +269 -0
  51. package/dist/assurance/validation.js.map +1 -0
  52. package/dist/bridge/client/bridge.d.ts +133 -0
  53. package/dist/bridge/client/bridge.d.ts.map +1 -0
  54. package/dist/bridge/client/bridge.js +429 -0
  55. package/dist/bridge/client/bridge.js.map +1 -0
  56. package/dist/bridge/client/dispatch.d.ts +41 -0
  57. package/dist/bridge/client/dispatch.d.ts.map +1 -0
  58. package/dist/bridge/client/dispatch.js +111 -0
  59. package/dist/bridge/client/dispatch.js.map +1 -0
  60. package/dist/bridge/client.d.ts +24 -0
  61. package/dist/bridge/client.d.ts.map +1 -0
  62. package/dist/bridge/client.js +26 -0
  63. package/dist/bridge/client.js.map +1 -0
  64. package/dist/bridge/protocol.d.ts +227 -0
  65. package/dist/bridge/protocol.d.ts.map +1 -0
  66. package/dist/bridge/protocol.js +131 -0
  67. package/dist/bridge/protocol.js.map +1 -0
  68. package/dist/bridge/server/audit.d.ts +19 -0
  69. package/dist/bridge/server/audit.d.ts.map +1 -0
  70. package/dist/bridge/server/audit.js +46 -0
  71. package/dist/bridge/server/audit.js.map +1 -0
  72. package/dist/bridge/server/bridge.d.ts +126 -0
  73. package/dist/bridge/server/bridge.d.ts.map +1 -0
  74. package/dist/bridge/server/bridge.js +383 -0
  75. package/dist/bridge/server/bridge.js.map +1 -0
  76. package/dist/bridge/server/headless.d.ts +36 -0
  77. package/dist/bridge/server/headless.d.ts.map +1 -0
  78. package/dist/bridge/server/headless.js +142 -0
  79. package/dist/bridge/server/headless.js.map +1 -0
  80. package/dist/bridge/server/json-schema-to-zod.d.ts +37 -0
  81. package/dist/bridge/server/json-schema-to-zod.d.ts.map +1 -0
  82. package/dist/bridge/server/json-schema-to-zod.js +93 -0
  83. package/dist/bridge/server/json-schema-to-zod.js.map +1 -0
  84. package/dist/bridge/server/local-bridge.d.ts +33 -0
  85. package/dist/bridge/server/local-bridge.d.ts.map +1 -0
  86. package/dist/bridge/server/local-bridge.js +41 -0
  87. package/dist/bridge/server/local-bridge.js.map +1 -0
  88. package/dist/bridge/server/logger.d.ts +28 -0
  89. package/dist/bridge/server/logger.d.ts.map +1 -0
  90. package/dist/bridge/server/logger.js +42 -0
  91. package/dist/bridge/server/logger.js.map +1 -0
  92. package/dist/bridge/server/mcp-contract.d.ts +21 -0
  93. package/dist/bridge/server/mcp-contract.d.ts.map +1 -0
  94. package/dist/bridge/server/mcp-contract.js +62 -0
  95. package/dist/bridge/server/mcp-contract.js.map +1 -0
  96. package/dist/bridge/server/mcp.d.ts +26 -0
  97. package/dist/bridge/server/mcp.d.ts.map +1 -0
  98. package/dist/bridge/server/mcp.js +102 -0
  99. package/dist/bridge/server/mcp.js.map +1 -0
  100. package/dist/bridge/server/peer.d.ts +39 -0
  101. package/dist/bridge/server/peer.d.ts.map +1 -0
  102. package/dist/bridge/server/peer.js +189 -0
  103. package/dist/bridge/server/peer.js.map +1 -0
  104. package/dist/bridge/server/standalone.d.ts +49 -0
  105. package/dist/bridge/server/standalone.d.ts.map +1 -0
  106. package/dist/bridge/server/standalone.js +267 -0
  107. package/dist/bridge/server/standalone.js.map +1 -0
  108. package/dist/bridge/server/tool-metadata.d.ts +38 -0
  109. package/dist/bridge/server/tool-metadata.d.ts.map +1 -0
  110. package/dist/bridge/server/tool-metadata.js +81 -0
  111. package/dist/bridge/server/tool-metadata.js.map +1 -0
  112. package/dist/bridge/server.d.ts +21 -0
  113. package/dist/bridge/server.d.ts.map +1 -0
  114. package/dist/bridge/server.js +18 -0
  115. package/dist/bridge/server.js.map +1 -0
  116. package/dist/cli/database-rules.d.ts +43 -0
  117. package/dist/cli/database-rules.d.ts.map +1 -0
  118. package/dist/cli/database-rules.js +261 -0
  119. package/dist/cli/database-rules.js.map +1 -0
  120. package/dist/cli/dev-runner.d.ts +112 -0
  121. package/dist/cli/dev-runner.d.ts.map +1 -0
  122. package/dist/cli/dev-runner.js +239 -0
  123. package/dist/cli/dev-runner.js.map +1 -0
  124. package/dist/cli/firebase-json.d.ts +66 -0
  125. package/dist/cli/firebase-json.d.ts.map +1 -0
  126. package/dist/cli/firebase-json.js +60 -0
  127. package/dist/cli/firebase-json.js.map +1 -0
  128. package/dist/cli/firestore-indexes.d.ts +21 -0
  129. package/dist/cli/firestore-indexes.d.ts.map +1 -0
  130. package/dist/cli/firestore-indexes.js +39 -0
  131. package/dist/cli/firestore-indexes.js.map +1 -0
  132. package/dist/cli/index.d.ts +56 -0
  133. package/dist/cli/index.d.ts.map +1 -0
  134. package/dist/cli/index.js +379 -0
  135. package/dist/cli/index.js.map +1 -0
  136. package/dist/cli/init.d.ts +50 -0
  137. package/dist/cli/init.d.ts.map +1 -0
  138. package/dist/cli/init.js +182 -0
  139. package/dist/cli/init.js.map +1 -0
  140. package/dist/cli/mcp-proxy.d.ts +10 -0
  141. package/dist/cli/mcp-proxy.d.ts.map +1 -0
  142. package/dist/cli/mcp-proxy.js +129 -0
  143. package/dist/cli/mcp-proxy.js.map +1 -0
  144. package/dist/cli/parse-args.d.ts +20 -0
  145. package/dist/cli/parse-args.d.ts.map +1 -0
  146. package/dist/cli/parse-args.js +69 -0
  147. package/dist/cli/parse-args.js.map +1 -0
  148. package/dist/cli/rules.d.ts +55 -0
  149. package/dist/cli/rules.d.ts.map +1 -0
  150. package/dist/cli/rules.js +199 -0
  151. package/dist/cli/rules.js.map +1 -0
  152. package/dist/cli/scope.d.ts +12 -0
  153. package/dist/cli/scope.d.ts.map +1 -0
  154. package/dist/cli/scope.js +44 -0
  155. package/dist/cli/scope.js.map +1 -0
  156. package/dist/cli/serve.d.ts +122 -0
  157. package/dist/cli/serve.d.ts.map +1 -0
  158. package/dist/cli/serve.js +844 -0
  159. package/dist/cli/serve.js.map +1 -0
  160. package/dist/cli/service-commands.d.ts +8 -0
  161. package/dist/cli/service-commands.d.ts.map +1 -0
  162. package/dist/cli/service-commands.js +58 -0
  163. package/dist/cli/service-commands.js.map +1 -0
  164. package/dist/cli/snapshot.d.ts +22 -0
  165. package/dist/cli/snapshot.d.ts.map +1 -0
  166. package/dist/cli/snapshot.js +139 -0
  167. package/dist/cli/snapshot.js.map +1 -0
  168. package/dist/cli/storage-rules.d.ts +21 -0
  169. package/dist/cli/storage-rules.d.ts.map +1 -0
  170. package/dist/cli/storage-rules.js +121 -0
  171. package/dist/cli/storage-rules.js.map +1 -0
  172. package/dist/cli/verify.d.ts +23 -0
  173. package/dist/cli/verify.d.ts.map +1 -0
  174. package/dist/cli/verify.js +349 -0
  175. package/dist/cli/verify.js.map +1 -0
  176. package/dist/credentials/core/memoize-ttl.d.ts +58 -0
  177. package/dist/credentials/core/memoize-ttl.d.ts.map +1 -0
  178. package/dist/credentials/core/memoize-ttl.js +88 -0
  179. package/dist/credentials/core/memoize-ttl.js.map +1 -0
  180. package/dist/credentials/core/types.d.ts +11 -0
  181. package/dist/credentials/core/types.d.ts.map +1 -0
  182. package/dist/credentials/core/types.js +2 -0
  183. package/dist/credentials/core/types.js.map +1 -0
  184. package/dist/credentials/node/from-adc.d.ts +10 -0
  185. package/dist/credentials/node/from-adc.d.ts.map +1 -0
  186. package/dist/credentials/node/from-adc.js +76 -0
  187. package/dist/credentials/node/from-adc.js.map +1 -0
  188. package/dist/credentials/node/from-service-account.d.ts +24 -0
  189. package/dist/credentials/node/from-service-account.d.ts.map +1 -0
  190. package/dist/credentials/node/from-service-account.js +108 -0
  191. package/dist/credentials/node/from-service-account.js.map +1 -0
  192. package/dist/credentials/node/index.d.ts +7 -0
  193. package/dist/credentials/node/index.d.ts.map +1 -0
  194. package/dist/credentials/node/index.js +7 -0
  195. package/dist/credentials/node/index.js.map +1 -0
  196. package/dist/discover/concurrency.d.ts +42 -0
  197. package/dist/discover/concurrency.d.ts.map +1 -0
  198. package/dist/discover/concurrency.js +113 -0
  199. package/dist/discover/concurrency.js.map +1 -0
  200. package/dist/discover/crawler-adapter.d.ts +48 -0
  201. package/dist/discover/crawler-adapter.d.ts.map +1 -0
  202. package/dist/discover/crawler-adapter.js +92 -0
  203. package/dist/discover/crawler-adapter.js.map +1 -0
  204. package/dist/discover/crawler.d.ts +294 -0
  205. package/dist/discover/crawler.d.ts.map +1 -0
  206. package/dist/discover/crawler.js +764 -0
  207. package/dist/discover/crawler.js.map +1 -0
  208. package/dist/discover/credential-free.d.ts +19 -0
  209. package/dist/discover/credential-free.d.ts.map +1 -0
  210. package/dist/discover/credential-free.js +18 -0
  211. package/dist/discover/credential-free.js.map +1 -0
  212. package/dist/discover/findCollectionGroup.d.ts +44 -0
  213. package/dist/discover/findCollectionGroup.d.ts.map +1 -0
  214. package/dist/discover/findCollectionGroup.js +81 -0
  215. package/dist/discover/findCollectionGroup.js.map +1 -0
  216. package/dist/discover/firestore-source.d.ts +60 -0
  217. package/dist/discover/firestore-source.d.ts.map +1 -0
  218. package/dist/discover/firestore-source.js +11 -0
  219. package/dist/discover/firestore-source.js.map +1 -0
  220. package/dist/discover/index.d.ts +3 -0
  221. package/dist/discover/index.d.ts.map +1 -0
  222. package/dist/discover/index.js +5 -0
  223. package/dist/discover/index.js.map +1 -0
  224. package/dist/discover/merge.d.ts +108 -0
  225. package/dist/discover/merge.d.ts.map +1 -0
  226. package/dist/discover/merge.js +394 -0
  227. package/dist/discover/merge.js.map +1 -0
  228. package/dist/discover/session.d.ts +116 -0
  229. package/dist/discover/session.d.ts.map +1 -0
  230. package/dist/discover/session.js +331 -0
  231. package/dist/discover/session.js.map +1 -0
  232. package/dist/discover/tools.d.ts +58 -0
  233. package/dist/discover/tools.d.ts.map +1 -0
  234. package/dist/discover/tools.js +115 -0
  235. package/dist/discover/tools.js.map +1 -0
  236. package/dist/discover/types.d.ts +190 -0
  237. package/dist/discover/types.d.ts.map +1 -0
  238. package/dist/discover/types.js +12 -0
  239. package/dist/discover/types.js.map +1 -0
  240. package/dist/discover/wire.d.ts +70 -0
  241. package/dist/discover/wire.d.ts.map +1 -0
  242. package/dist/discover/wire.js +309 -0
  243. package/dist/discover/wire.js.map +1 -0
  244. package/dist/functions-rtdb/child.d.ts +52 -0
  245. package/dist/functions-rtdb/child.d.ts.map +1 -0
  246. package/dist/functions-rtdb/child.js +283 -0
  247. package/dist/functions-rtdb/child.js.map +1 -0
  248. package/dist/functions-rtdb/delivery.d.ts +4 -0
  249. package/dist/functions-rtdb/delivery.d.ts.map +1 -0
  250. package/dist/functions-rtdb/delivery.js +2 -0
  251. package/dist/functions-rtdb/delivery.js.map +1 -0
  252. package/dist/functions-rtdb/discovery.d.ts +41 -0
  253. package/dist/functions-rtdb/discovery.d.ts.map +1 -0
  254. package/dist/functions-rtdb/discovery.js +86 -0
  255. package/dist/functions-rtdb/discovery.js.map +1 -0
  256. package/dist/functions-rtdb/event.d.ts +20 -0
  257. package/dist/functions-rtdb/event.d.ts.map +1 -0
  258. package/dist/functions-rtdb/event.js +45 -0
  259. package/dist/functions-rtdb/event.js.map +1 -0
  260. package/dist/functions-rtdb/execution.d.ts +20 -0
  261. package/dist/functions-rtdb/execution.d.ts.map +1 -0
  262. package/dist/functions-rtdb/execution.js +70 -0
  263. package/dist/functions-rtdb/execution.js.map +1 -0
  264. package/dist/functions-rtdb/in-memory-delivery.d.ts +9 -0
  265. package/dist/functions-rtdb/in-memory-delivery.d.ts.map +1 -0
  266. package/dist/functions-rtdb/in-memory-delivery.js +36 -0
  267. package/dist/functions-rtdb/in-memory-delivery.js.map +1 -0
  268. package/dist/functions-rtdb/project.d.ts +7 -0
  269. package/dist/functions-rtdb/project.d.ts.map +1 -0
  270. package/dist/functions-rtdb/project.js +54 -0
  271. package/dist/functions-rtdb/project.js.map +1 -0
  272. package/dist/functions-rtdb/projection.d.ts +14 -0
  273. package/dist/functions-rtdb/projection.d.ts.map +1 -0
  274. package/dist/functions-rtdb/projection.js +65 -0
  275. package/dist/functions-rtdb/projection.js.map +1 -0
  276. package/dist/functions-rtdb/reference-pattern.d.ts +5 -0
  277. package/dist/functions-rtdb/reference-pattern.d.ts.map +1 -0
  278. package/dist/functions-rtdb/reference-pattern.js +14 -0
  279. package/dist/functions-rtdb/reference-pattern.js.map +1 -0
  280. package/dist/functions-rtdb/remote-delivery.d.ts +9 -0
  281. package/dist/functions-rtdb/remote-delivery.d.ts.map +1 -0
  282. package/dist/functions-rtdb/remote-delivery.js +11 -0
  283. package/dist/functions-rtdb/remote-delivery.js.map +1 -0
  284. package/dist/pkg-version.d.ts +2 -0
  285. package/dist/pkg-version.d.ts.map +1 -0
  286. package/dist/pkg-version.js +47 -0
  287. package/dist/pkg-version.js.map +1 -0
  288. package/dist/register/esm-exports.d.ts +26 -0
  289. package/dist/register/esm-exports.d.ts.map +1 -0
  290. package/dist/register/esm-exports.js +61 -0
  291. package/dist/register/esm-exports.js.map +1 -0
  292. package/dist/register/hooks.d.ts +13 -0
  293. package/dist/register/hooks.d.ts.map +1 -0
  294. package/dist/register/hooks.js +15 -0
  295. package/dist/register/hooks.js.map +1 -0
  296. package/dist/register/index.d.ts +5 -0
  297. package/dist/register/index.d.ts.map +1 -0
  298. package/dist/register/index.js +124 -0
  299. package/dist/register/index.js.map +1 -0
  300. package/dist/register/mapping.d.ts +19 -0
  301. package/dist/register/mapping.d.ts.map +1 -0
  302. package/dist/register/mapping.js +35 -0
  303. package/dist/register/mapping.js.map +1 -0
  304. package/dist/remote/index.d.ts +232 -0
  305. package/dist/remote/index.d.ts.map +1 -0
  306. package/dist/remote/index.js +720 -0
  307. package/dist/remote/index.js.map +1 -0
  308. package/dist/rtdb/crawl-snapshot.d.ts +17 -0
  309. package/dist/rtdb/crawl-snapshot.d.ts.map +1 -0
  310. package/dist/rtdb/crawl-snapshot.js +72 -0
  311. package/dist/rtdb/crawl-snapshot.js.map +1 -0
  312. package/dist/rtdb/inspection.d.ts +8 -0
  313. package/dist/rtdb/inspection.d.ts.map +1 -0
  314. package/dist/rtdb/inspection.js +111 -0
  315. package/dist/rtdb/inspection.js.map +1 -0
  316. package/dist/rtdb/load-rules-document.d.ts +25 -0
  317. package/dist/rtdb/load-rules-document.d.ts.map +1 -0
  318. package/dist/rtdb/load-rules-document.js +38 -0
  319. package/dist/rtdb/load-rules-document.js.map +1 -0
  320. package/dist/rtdb/rules-generation-tool.d.ts +4 -0
  321. package/dist/rtdb/rules-generation-tool.d.ts.map +1 -0
  322. package/dist/rtdb/rules-generation-tool.js +35 -0
  323. package/dist/rtdb/rules-generation-tool.js.map +1 -0
  324. package/dist/rtdb/rules-json.d.ts +8 -0
  325. package/dist/rtdb/rules-json.d.ts.map +1 -0
  326. package/dist/rtdb/rules-json.js +17 -0
  327. package/dist/rtdb/rules-json.js.map +1 -0
  328. package/dist/serve/bridge-mount.d.ts +36 -0
  329. package/dist/serve/bridge-mount.d.ts.map +1 -0
  330. package/dist/serve/bridge-mount.js +162 -0
  331. package/dist/serve/bridge-mount.js.map +1 -0
  332. package/dist/serve/bundler.d.ts +110 -0
  333. package/dist/serve/bundler.d.ts.map +1 -0
  334. package/dist/serve/bundler.js +432 -0
  335. package/dist/serve/bundler.js.map +1 -0
  336. package/dist/serve/capture-store.d.ts +27 -0
  337. package/dist/serve/capture-store.d.ts.map +1 -0
  338. package/dist/serve/capture-store.js +47 -0
  339. package/dist/serve/capture-store.js.map +1 -0
  340. package/dist/serve/discovery.d.ts +71 -0
  341. package/dist/serve/discovery.d.ts.map +1 -0
  342. package/dist/serve/discovery.js +158 -0
  343. package/dist/serve/discovery.js.map +1 -0
  344. package/dist/serve/docs-ui/_astro/_slug_.CQYSemvw.css +1 -0
  345. package/dist/serve/docs-ui/docs/_rhythm/index.html +99 -0
  346. package/dist/serve/docs-ui/docs/_rhythm.md +101 -0
  347. package/dist/serve/docs-ui/docs/api-reference/index.html +64 -0
  348. package/dist/serve/docs-ui/docs/api-reference.md +67 -0
  349. package/dist/serve/docs-ui/docs/audit-your-rules/index.html +34 -0
  350. package/dist/serve/docs-ui/docs/audit-your-rules.md +50 -0
  351. package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +498 -0
  352. package/dist/serve/docs-ui/docs/create-pyric-reference-api.md +345 -0
  353. package/dist/serve/docs-ui/docs/firestore-rules-limits/index.html +59 -0
  354. package/dist/serve/docs-ui/docs/firestore-rules-limits.md +54 -0
  355. package/dist/serve/docs-ui/docs/how-the-swap-works/index.html +47 -0
  356. package/dist/serve/docs-ui/docs/how-the-swap-works.md +43 -0
  357. package/dist/serve/docs-ui/docs/how-we-know-it-matches-firebase/index.html +131 -0
  358. package/dist/serve/docs-ui/docs/how-we-know-it-matches-firebase.md +169 -0
  359. package/dist/serve/docs-ui/docs/index.html +2 -0
  360. package/dist/serve/docs-ui/docs/index.json +18637 -0
  361. package/dist/serve/docs-ui/docs/overview/index.html +23 -0
  362. package/dist/serve/docs-ui/docs/overview.md +40 -0
  363. package/dist/serve/docs-ui/docs/pyric-admin-app/index.html +19 -0
  364. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +185 -0
  365. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api.md +206 -0
  366. package/dist/serve/docs-ui/docs/pyric-admin-app.md +27 -0
  367. package/dist/serve/docs-ui/docs/pyric-admin-auth/index.html +24 -0
  368. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +617 -0
  369. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api.md +441 -0
  370. package/dist/serve/docs-ui/docs/pyric-admin-auth.md +29 -0
  371. package/dist/serve/docs-ui/docs/pyric-admin-database/index.html +26 -0
  372. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +583 -0
  373. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api.md +597 -0
  374. package/dist/serve/docs-ui/docs/pyric-admin-database.md +31 -0
  375. package/dist/serve/docs-ui/docs/pyric-admin-firestore/index.html +38 -0
  376. package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-error-translation/index.html +57 -0
  377. package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-error-translation.md +95 -0
  378. package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-per-call-delegate/index.html +58 -0
  379. package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-per-call-delegate.md +94 -0
  380. package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape/index.html +59 -0
  381. package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape.md +88 -0
  382. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-run-a-transaction/index.html +53 -0
  383. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-run-a-transaction.md +76 -0
  384. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules/index.html +62 -0
  385. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules.md +96 -0
  386. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-translate-denials/index.html +80 -0
  387. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-translate-denials.md +98 -0
  388. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-use-onsnapshot/index.html +57 -0
  389. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-use-onsnapshot.md +88 -0
  390. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-write-a-batch/index.html +50 -0
  391. package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-write-a-batch.md +73 -0
  392. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +32 -0
  393. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api.md +30 -0
  394. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-onsnapshot/index.html +68 -0
  395. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-onsnapshot.md +81 -0
  396. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-re-exported-types/index.html +76 -0
  397. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-re-exported-types.md +103 -0
  398. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-sandbox-firestore/index.html +40 -0
  399. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-sandbox-firestore.md +77 -0
  400. package/dist/serve/docs-ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session/index.html +118 -0
  401. package/dist/serve/docs-ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session.md +166 -0
  402. package/dist/serve/docs-ui/docs/pyric-admin-firestore.md +53 -0
  403. package/dist/serve/docs-ui/docs/pyric-admin-storage/index.html +25 -0
  404. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +317 -0
  405. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api.md +285 -0
  406. package/dist/serve/docs-ui/docs/pyric-admin-storage.md +30 -0
  407. package/dist/serve/docs-ui/docs/pyric-ai-compat/index.html +436 -0
  408. package/dist/serve/docs-ui/docs/pyric-ai-compat.md +471 -0
  409. package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +5831 -0
  410. package/dist/serve/docs-ui/docs/pyric-ai-reference-api.md +5440 -0
  411. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +159 -0
  412. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api.md +122 -0
  413. package/dist/serve/docs-ui/docs/pyric-app-compat/index.html +180 -0
  414. package/dist/serve/docs-ui/docs/pyric-app-compat.md +199 -0
  415. package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +420 -0
  416. package/dist/serve/docs-ui/docs/pyric-app-reference-api.md +326 -0
  417. package/dist/serve/docs-ui/docs/pyric-auth/index.html +59 -0
  418. package/dist/serve/docs-ui/docs/pyric-auth-compat/index.html +804 -0
  419. package/dist/serve/docs-ui/docs/pyric-auth-compat.md +847 -0
  420. package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +5452 -0
  421. package/dist/serve/docs-ui/docs/pyric-auth-reference-api.md +5271 -0
  422. package/dist/serve/docs-ui/docs/pyric-auth-reference-feature-matrix/index.html +781 -0
  423. package/dist/serve/docs-ui/docs/pyric-auth-reference-feature-matrix.md +198 -0
  424. package/dist/serve/docs-ui/docs/pyric-auth-reference-sandbox-test-driver/index.html +71 -0
  425. package/dist/serve/docs-ui/docs/pyric-auth-reference-sandbox-test-driver.md +108 -0
  426. package/dist/serve/docs-ui/docs/pyric-auth.md +86 -0
  427. package/dist/serve/docs-ui/docs/pyric-cli/index.html +40 -0
  428. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +98 -0
  429. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api.md +88 -0
  430. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +2355 -0
  431. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api.md +1554 -0
  432. package/dist/serve/docs-ui/docs/pyric-cli-bridge/index.html +69 -0
  433. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +546 -0
  434. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api.md +485 -0
  435. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +506 -0
  436. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api.md +419 -0
  437. package/dist/serve/docs-ui/docs/pyric-cli-bridge.md +99 -0
  438. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +67 -0
  439. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api.md +59 -0
  440. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +2355 -0
  441. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api.md +2036 -0
  442. package/dist/serve/docs-ui/docs/pyric-cli-functions-rtdb-compat/index.html +112 -0
  443. package/dist/serve/docs-ui/docs/pyric-cli-functions-rtdb-compat.md +124 -0
  444. package/dist/serve/docs-ui/docs/pyric-cli-how-to-build-a-standalone-binary/index.html +91 -0
  445. package/dist/serve/docs-ui/docs/pyric-cli-how-to-build-a-standalone-binary.md +105 -0
  446. package/dist/serve/docs-ui/docs/pyric-cli-how-to-promote-sandbox-state-to-a-fixture/index.html +52 -0
  447. package/dist/serve/docs-ui/docs/pyric-cli-how-to-promote-sandbox-state-to-a-fixture.md +98 -0
  448. package/dist/serve/docs-ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated/index.html +66 -0
  449. package/dist/serve/docs-ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated.md +100 -0
  450. package/dist/serve/docs-ui/docs/pyric-cli-how-to-serve-persistence-and-multi-tab/index.html +228 -0
  451. package/dist/serve/docs-ui/docs/pyric-cli-how-to-serve-persistence-and-multi-tab.md +179 -0
  452. package/dist/serve/docs-ui/docs/pyric-cli-how-to-use-the-vite-plugin/index.html +341 -0
  453. package/dist/serve/docs-ui/docs/pyric-cli-how-to-use-the-vite-plugin.md +309 -0
  454. package/dist/serve/docs-ui/docs/pyric-cli-how-to-verify-against-a-captured-session/index.html +128 -0
  455. package/dist/serve/docs-ui/docs/pyric-cli-how-to-verify-against-a-captured-session.md +207 -0
  456. package/dist/serve/docs-ui/docs/pyric-cli-reference-cli/index.html +404 -0
  457. package/dist/serve/docs-ui/docs/pyric-cli-reference-cli.md +249 -0
  458. package/dist/serve/docs-ui/docs/pyric-cli-reference-package-and-resolution/index.html +93 -0
  459. package/dist/serve/docs-ui/docs/pyric-cli-reference-package-and-resolution.md +65 -0
  460. package/dist/serve/docs-ui/docs/pyric-cli-reference-verify/index.html +81 -0
  461. package/dist/serve/docs-ui/docs/pyric-cli-reference-verify.md +110 -0
  462. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +10 -0
  463. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api.md +16 -0
  464. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1044 -0
  465. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api.md +952 -0
  466. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +5041 -0
  467. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +4739 -0
  468. package/dist/serve/docs-ui/docs/pyric-cli-tutorials-server-adoption/index.html +219 -0
  469. package/dist/serve/docs-ui/docs/pyric-cli-tutorials-server-adoption.md +251 -0
  470. package/dist/serve/docs-ui/docs/pyric-cli-tutorials-wire-claude-code/index.html +136 -0
  471. package/dist/serve/docs-ui/docs/pyric-cli-tutorials-wire-claude-code.md +217 -0
  472. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +926 -0
  473. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api.md +586 -0
  474. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +102 -0
  475. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +76 -0
  476. package/dist/serve/docs-ui/docs/pyric-cli.md +42 -0
  477. package/dist/serve/docs-ui/docs/pyric-conformance-scores/index.html +180 -0
  478. package/dist/serve/docs-ui/docs/pyric-conformance-scores.md +184 -0
  479. package/dist/serve/docs-ui/docs/pyric-database/index.html +43 -0
  480. package/dist/serve/docs-ui/docs/pyric-database-compat/index.html +1224 -0
  481. package/dist/serve/docs-ui/docs/pyric-database-compat.md +1289 -0
  482. package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate/index.html +16 -0
  483. package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate.md +23 -0
  484. package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +1851 -0
  485. package/dist/serve/docs-ui/docs/pyric-database-reference-api.md +1842 -0
  486. package/dist/serve/docs-ui/docs/pyric-database-reference-constraints/index.html +381 -0
  487. package/dist/serve/docs-ui/docs/pyric-database-reference-constraints.md +168 -0
  488. package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling/index.html +218 -0
  489. package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling.md +303 -0
  490. package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints/index.html +125 -0
  491. package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints.md +171 -0
  492. package/dist/serve/docs-ui/docs/pyric-database.md +26 -0
  493. package/dist/serve/docs-ui/docs/pyric-explanation-versioning-and-compatibility/index.html +40 -0
  494. package/dist/serve/docs-ui/docs/pyric-explanation-versioning-and-compatibility.md +68 -0
  495. package/dist/serve/docs-ui/docs/pyric-firestore/index.html +48 -0
  496. package/dist/serve/docs-ui/docs/pyric-firestore-compat/index.html +868 -0
  497. package/dist/serve/docs-ui/docs/pyric-firestore-compat.md +939 -0
  498. package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate/index.html +92 -0
  499. package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate.md +70 -0
  500. package/dist/serve/docs-ui/docs/pyric-firestore-explanation-target-symbol-opacity/index.html +59 -0
  501. package/dist/serve/docs-ui/docs/pyric-firestore-explanation-target-symbol-opacity.md +91 -0
  502. package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface/index.html +43 -0
  503. package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface.md +58 -0
  504. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore/index.html +58 -0
  505. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore.md +86 -0
  506. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend/index.html +52 -0
  507. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend.md +83 -0
  508. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-run-a-transaction/index.html +42 -0
  509. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-run-a-transaction.md +59 -0
  510. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot/index.html +66 -0
  511. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot.md +96 -0
  512. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops/index.html +61 -0
  513. package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops.md +92 -0
  514. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +3623 -0
  515. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api.md +3399 -0
  516. package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix/index.html +80 -0
  517. package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix.md +66 -0
  518. package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore/index.html +46 -0
  519. package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore.md +73 -0
  520. package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints/index.html +80 -0
  521. package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints.md +129 -0
  522. package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops/index.html +58 -0
  523. package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops.md +88 -0
  524. package/dist/serve/docs-ui/docs/pyric-firestore-reference-tool-factories/index.html +51 -0
  525. package/dist/serve/docs-ui/docs/pyric-firestore-reference-tool-factories.md +71 -0
  526. package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo/index.html +130 -0
  527. package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo.md +180 -0
  528. package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend/index.html +59 -0
  529. package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend.md +92 -0
  530. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +30 -0
  531. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +30 -0
  532. package/dist/serve/docs-ui/docs/pyric-firestore.md +72 -0
  533. package/dist/serve/docs-ui/docs/pyric-messaging-compat/index.html +300 -0
  534. package/dist/serve/docs-ui/docs/pyric-messaging-compat.md +321 -0
  535. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +508 -0
  536. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api.md +374 -0
  537. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +482 -0
  538. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api.md +348 -0
  539. package/dist/serve/docs-ui/docs/pyric-rules/index.html +87 -0
  540. package/dist/serve/docs-ui/docs/pyric-rules-compat/index.html +328 -0
  541. package/dist/serve/docs-ui/docs/pyric-rules-compat.md +347 -0
  542. package/dist/serve/docs-ui/docs/pyric-rules-explanation-agent-failure-modes/index.html +50 -0
  543. package/dist/serve/docs-ui/docs/pyric-rules-explanation-agent-failure-modes.md +78 -0
  544. package/dist/serve/docs-ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test/index.html +79 -0
  545. package/dist/serve/docs-ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test.md +69 -0
  546. package/dist/serve/docs-ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates/index.html +67 -0
  547. package/dist/serve/docs-ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates.md +75 -0
  548. package/dist/serve/docs-ui/docs/pyric-rules-explanation-sentinel-expression-engine/index.html +49 -0
  549. package/dist/serve/docs-ui/docs/pyric-rules-explanation-sentinel-expression-engine.md +74 -0
  550. package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api/index.html +95 -0
  551. package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api.md +80 -0
  552. package/dist/serve/docs-ui/docs/pyric-rules-explanation-the-2-plus-modules-extension/index.html +58 -0
  553. package/dist/serve/docs-ui/docs/pyric-rules-explanation-the-2-plus-modules-extension.md +79 -0
  554. package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design/index.html +63 -0
  555. package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design.md +84 -0
  556. package/dist/serve/docs-ui/docs/pyric-rules-explanation-why-this-package-exists/index.html +34 -0
  557. package/dist/serve/docs-ui/docs/pyric-rules-explanation-why-this-package-exists.md +43 -0
  558. package/dist/serve/docs-ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening/index.html +55 -0
  559. package/dist/serve/docs-ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening.md +77 -0
  560. package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast/index.html +90 -0
  561. package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast.md +129 -0
  562. package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source/index.html +55 -0
  563. package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source.md +84 -0
  564. package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time/index.html +49 -0
  565. package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time.md +64 -0
  566. package/dist/serve/docs-ui/docs/pyric-rules-how-to-register-tools-with-an-agent/index.html +61 -0
  567. package/dist/serve/docs-ui/docs/pyric-rules-how-to-register-tools-with-an-agent.md +87 -0
  568. package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports/index.html +93 -0
  569. package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports.md +105 -0
  570. package/dist/serve/docs-ui/docs/pyric-rules-how-to-simulate-rules-locally/index.html +89 -0
  571. package/dist/serve/docs-ui/docs/pyric-rules-how-to-simulate-rules-locally.md +134 -0
  572. package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase/index.html +66 -0
  573. package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase.md +102 -0
  574. package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +2629 -0
  575. package/dist/serve/docs-ui/docs/pyric-rules-reference-api.md +2213 -0
  576. package/dist/serve/docs-ui/docs/pyric-rules-reference-ast/index.html +85 -0
  577. package/dist/serve/docs-ui/docs/pyric-rules-reference-ast.md +121 -0
  578. package/dist/serve/docs-ui/docs/pyric-rules-reference-conformance-gaps/index.html +277 -0
  579. package/dist/serve/docs-ui/docs/pyric-rules-reference-conformance-gaps.md +360 -0
  580. package/dist/serve/docs-ui/docs/pyric-rules-reference-errors/index.html +76 -0
  581. package/dist/serve/docs-ui/docs/pyric-rules-reference-errors.md +123 -0
  582. package/dist/serve/docs-ui/docs/pyric-rules-reference-lint-rules/index.html +148 -0
  583. package/dist/serve/docs-ui/docs/pyric-rules-reference-lint-rules.md +159 -0
  584. package/dist/serve/docs-ui/docs/pyric-rules-reference-simulator-context/index.html +66 -0
  585. package/dist/serve/docs-ui/docs/pyric-rules-reference-simulator-context.md +104 -0
  586. package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules/index.html +241 -0
  587. package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules.md +143 -0
  588. package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema/index.html +94 -0
  589. package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema.md +121 -0
  590. package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings/index.html +87 -0
  591. package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings.md +117 -0
  592. package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers/index.html +102 -0
  593. package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers.md +152 -0
  594. package/dist/serve/docs-ui/docs/pyric-rules.md +93 -0
  595. package/dist/serve/docs-ui/docs/pyric-sandbox/index.html +67 -0
  596. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +120 -0
  597. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api.md +110 -0
  598. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-every-op-is-a-request/index.html +141 -0
  599. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-every-op-is-a-request.md +161 -0
  600. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-identity-is-a-context/index.html +66 -0
  601. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-identity-is-a-context.md +110 -0
  602. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-internal-adapter-protocol/index.html +71 -0
  603. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-internal-adapter-protocol.md +111 -0
  604. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-listener-re-evaluation/index.html +56 -0
  605. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-listener-re-evaluation.md +82 -0
  606. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline/index.html +64 -0
  607. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline.md +56 -0
  608. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings/index.html +92 -0
  609. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings.md +90 -0
  610. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-this-package-exists/index.html +69 -0
  611. package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-this-package-exists.md +57 -0
  612. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +202 -0
  613. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api.md +134 -0
  614. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes/index.html +63 -0
  615. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes.md +89 -0
  616. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-observe-events/index.html +159 -0
  617. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-observe-events.md +168 -0
  618. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-pick-an-adapter/index.html +79 -0
  619. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-pick-an-adapter.md +75 -0
  620. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events/index.html +88 -0
  621. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events.md +92 -0
  622. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-reset-between-tests/index.html +68 -0
  623. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-reset-between-tests.md +92 -0
  624. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-seed-data-and-rules/index.html +91 -0
  625. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-seed-data-and-rules.md +122 -0
  626. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-switch-users/index.html +50 -0
  627. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-switch-users.md +78 -0
  628. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-use-admin-reads/index.html +54 -0
  629. package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-use-admin-reads.md +85 -0
  630. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +5019 -0
  631. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +4060 -0
  632. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-divergences/index.html +125 -0
  633. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-divergences.md +151 -0
  634. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-error-codes/index.html +110 -0
  635. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-error-codes.md +118 -0
  636. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-internal-protocol/index.html +72 -0
  637. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-internal-protocol.md +109 -0
  638. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-and-context/index.html +90 -0
  639. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-and-context.md +140 -0
  640. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-event/index.html +146 -0
  641. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-event.md +204 -0
  642. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-snapshot-and-admin/index.html +53 -0
  643. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-snapshot-and-admin.md +89 -0
  644. package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session/index.html +115 -0
  645. package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session.md +176 -0
  646. package/dist/serve/docs-ui/docs/pyric-sandbox.md +69 -0
  647. package/dist/serve/docs-ui/docs/pyric-storage/index.html +65 -0
  648. package/dist/serve/docs-ui/docs/pyric-storage-compat/index.html +676 -0
  649. package/dist/serve/docs-ui/docs/pyric-storage-compat.md +699 -0
  650. package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope/index.html +52 -0
  651. package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope.md +85 -0
  652. package/dist/serve/docs-ui/docs/pyric-storage-explanation-session-archive-use-case/index.html +58 -0
  653. package/dist/serve/docs-ui/docs/pyric-storage-explanation-session-archive-use-case.md +82 -0
  654. package/dist/serve/docs-ui/docs/pyric-storage-explanation-why-indexeddb/index.html +50 -0
  655. package/dist/serve/docs-ui/docs/pyric-storage-explanation-why-indexeddb.md +82 -0
  656. package/dist/serve/docs-ui/docs/pyric-storage-how-to-enforce-rules/index.html +120 -0
  657. package/dist/serve/docs-ui/docs/pyric-storage-how-to-enforce-rules.md +127 -0
  658. package/dist/serve/docs-ui/docs/pyric-storage-how-to-list-and-delete/index.html +53 -0
  659. package/dist/serve/docs-ui/docs/pyric-storage-how-to-list-and-delete.md +86 -0
  660. package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends/index.html +43 -0
  661. package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends.md +65 -0
  662. package/dist/serve/docs-ui/docs/pyric-storage-how-to-test-rule-expressions/index.html +70 -0
  663. package/dist/serve/docs-ui/docs/pyric-storage-how-to-test-rule-expressions.md +88 -0
  664. package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +2120 -0
  665. package/dist/serve/docs-ui/docs/pyric-storage-reference-api.md +1687 -0
  666. package/dist/serve/docs-ui/docs/pyric-storage-reference-conformance-gaps/index.html +137 -0
  667. package/dist/serve/docs-ui/docs/pyric-storage-reference-conformance-gaps.md +171 -0
  668. package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes/index.html +37 -0
  669. package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes.md +57 -0
  670. package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset/index.html +96 -0
  671. package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset.md +134 -0
  672. package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options/index.html +39 -0
  673. package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options.md +61 -0
  674. package/dist/serve/docs-ui/docs/pyric-storage.md +67 -0
  675. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +638 -0
  676. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api.md +430 -0
  677. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +813 -0
  678. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api.md +634 -0
  679. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +1708 -0
  680. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api.md +1300 -0
  681. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +177 -0
  682. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api.md +111 -0
  683. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +1542 -0
  684. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api.md +903 -0
  685. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1024 -0
  686. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api.md +640 -0
  687. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +2753 -0
  688. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api.md +2171 -0
  689. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +1005 -0
  690. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api.md +693 -0
  691. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +1388 -0
  692. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api.md +1340 -0
  693. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +131 -0
  694. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api.md +76 -0
  695. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +648 -0
  696. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api.md +508 -0
  697. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1457 -0
  698. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api.md +1029 -0
  699. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +2476 -0
  700. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api.md +1919 -0
  701. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1241 -0
  702. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api.md +817 -0
  703. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +2289 -0
  704. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api.md +1489 -0
  705. package/dist/serve/docs-ui/docs/read-a-denial/index.html +40 -0
  706. package/dist/serve/docs-ui/docs/read-a-denial.md +62 -0
  707. package/dist/serve/docs-ui/docs/receive-messages/index.html +28 -0
  708. package/dist/serve/docs-ui/docs/receive-messages.md +43 -0
  709. package/dist/serve/docs-ui/docs/rtdb-rules-in-typescript/index.html +67 -0
  710. package/dist/serve/docs-ui/docs/rtdb-rules-in-typescript.md +101 -0
  711. package/dist/serve/docs-ui/docs/rules-patterns/index.html +68 -0
  712. package/dist/serve/docs-ui/docs/rules-patterns.md +104 -0
  713. package/dist/serve/docs-ui/docs/rules-standard-library/index.html +87 -0
  714. package/dist/serve/docs-ui/docs/rules-standard-library.md +93 -0
  715. package/dist/serve/docs-ui/docs/run-ai-logic-locally/index.html +27 -0
  716. package/dist/serve/docs-ui/docs/run-ai-logic-locally.md +43 -0
  717. package/dist/serve/docs-ui/docs/secure-it-with-rules/index.html +69 -0
  718. package/dist/serve/docs-ui/docs/secure-it-with-rules.md +101 -0
  719. package/dist/serve/docs-ui/docs/see-whats-happening/index.html +73 -0
  720. package/dist/serve/docs-ui/docs/see-whats-happening.md +77 -0
  721. package/dist/serve/docs-ui/docs/set-up-the-project/index.html +14 -0
  722. package/dist/serve/docs-ui/docs/set-up-the-project.md +19 -0
  723. package/dist/serve/docs-ui/docs/set-up-your-agent/index.html +42 -0
  724. package/dist/serve/docs-ui/docs/set-up-your-agent.md +86 -0
  725. package/dist/serve/docs-ui/docs/shape-your-data/index.html +44 -0
  726. package/dist/serve/docs-ui/docs/shape-your-data.md +88 -0
  727. package/dist/serve/docs-ui/docs/ship-to-production/index.html +36 -0
  728. package/dist/serve/docs-ui/docs/ship-to-production.md +80 -0
  729. package/dist/serve/docs-ui/docs/sign-in-and-manage-users/index.html +31 -0
  730. package/dist/serve/docs-ui/docs/sign-in-and-manage-users.md +50 -0
  731. package/dist/serve/docs-ui/docs/simulate-and-lint/index.html +95 -0
  732. package/dist/serve/docs-ui/docs/simulate-and-lint.md +99 -0
  733. package/dist/serve/docs-ui/docs/skills/index.html +20 -0
  734. package/dist/serve/docs-ui/docs/skills.md +34 -0
  735. package/dist/serve/docs-ui/docs/start-building/index.html +32 -0
  736. package/dist/serve/docs-ui/docs/start-building.md +64 -0
  737. package/dist/serve/docs-ui/docs/store-and-query-data/index.html +16 -0
  738. package/dist/serve/docs-ui/docs/store-and-query-data.md +33 -0
  739. package/dist/serve/docs-ui/docs/store-files/index.html +13 -0
  740. package/dist/serve/docs-ui/docs/store-files.md +25 -0
  741. package/dist/serve/docs-ui/docs/sync-realtime-data/index.html +15 -0
  742. package/dist/serve/docs-ui/docs/sync-realtime-data.md +27 -0
  743. package/dist/serve/docs-ui/docs/test-in-node/index.html +74 -0
  744. package/dist/serve/docs-ui/docs/test-in-node.md +100 -0
  745. package/dist/serve/docs-ui/docs/ui/index.html +76 -0
  746. package/dist/serve/docs-ui/docs/ui-auth-authsigninhelper/index.html +194 -0
  747. package/dist/serve/docs-ui/docs/ui-auth-authsigninhelper.md +114 -0
  748. package/dist/serve/docs-ui/docs/ui-auth-authusers/index.html +263 -0
  749. package/dist/serve/docs-ui/docs/ui-auth-authusers.md +183 -0
  750. package/dist/serve/docs-ui/docs/ui-firestore-collectionlist/index.html +92 -0
  751. package/dist/serve/docs-ui/docs/ui-firestore-collectionlist.md +79 -0
  752. package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm/index.html +128 -0
  753. package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm.md +104 -0
  754. package/dist/serve/docs-ui/docs/ui-firestore-documenteditor/index.html +154 -0
  755. package/dist/serve/docs-ui/docs/ui-firestore-documenteditor.md +117 -0
  756. package/dist/serve/docs-ui/docs/ui-firestore-documentlist/index.html +132 -0
  757. package/dist/serve/docs-ui/docs/ui-firestore-documentlist.md +92 -0
  758. package/dist/serve/docs-ui/docs/ui-firestore-documentpreview/index.html +159 -0
  759. package/dist/serve/docs-ui/docs/ui-firestore-documentpreview.md +84 -0
  760. package/dist/serve/docs-ui/docs/ui-firestore-querybuilder/index.html +104 -0
  761. package/dist/serve/docs-ui/docs/ui-firestore-querybuilder.md +103 -0
  762. package/dist/serve/docs-ui/docs/ui-firestore-referencepicker/index.html +113 -0
  763. package/dist/serve/docs-ui/docs/ui-firestore-referencepicker.md +93 -0
  764. package/dist/serve/docs-ui/docs/ui-primitives-badge/index.html +56 -0
  765. package/dist/serve/docs-ui/docs/ui-primitives-badge.md +40 -0
  766. package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog/index.html +140 -0
  767. package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog.md +108 -0
  768. package/dist/serve/docs-ui/docs/ui-primitives-copybutton/index.html +58 -0
  769. package/dist/serve/docs-ui/docs/ui-primitives-copybutton.md +37 -0
  770. package/dist/serve/docs-ui/docs/ui-primitives-jsonview/index.html +58 -0
  771. package/dist/serve/docs-ui/docs/ui-primitives-jsonview.md +47 -0
  772. package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol/index.html +70 -0
  773. package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol.md +50 -0
  774. package/dist/serve/docs-ui/docs/ui-primitives-toast/index.html +87 -0
  775. package/dist/serve/docs-ui/docs/ui-primitives-toast.md +82 -0
  776. package/dist/serve/docs-ui/docs/ui-primitives-virtuallist/index.html +85 -0
  777. package/dist/serve/docs-ui/docs/ui-primitives-virtuallist.md +54 -0
  778. package/dist/serve/docs-ui/docs/ui-storage/index.html +150 -0
  779. package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm/index.html +126 -0
  780. package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm.md +88 -0
  781. package/dist/serve/docs-ui/docs/ui-storage-objectbrowser/index.html +137 -0
  782. package/dist/serve/docs-ui/docs/ui-storage-objectbrowser.md +90 -0
  783. package/dist/serve/docs-ui/docs/ui-storage-objectinspector/index.html +139 -0
  784. package/dist/serve/docs-ui/docs/ui-storage-objectinspector.md +93 -0
  785. package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb/index.html +72 -0
  786. package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb.md +57 -0
  787. package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances/index.html +60 -0
  788. package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances.md +52 -0
  789. package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone/index.html +93 -0
  790. package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone.md +78 -0
  791. package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate/index.html +144 -0
  792. package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate.md +101 -0
  793. package/dist/serve/docs-ui/docs/ui-storage.md +165 -0
  794. package/dist/serve/docs-ui/docs/ui-traffic/index.html +88 -0
  795. package/dist/serve/docs-ui/docs/ui-traffic-ruleheatmap/index.html +79 -0
  796. package/dist/serve/docs-ui/docs/ui-traffic-ruleheatmap.md +60 -0
  797. package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail/index.html +78 -0
  798. package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail.md +59 -0
  799. package/dist/serve/docs-ui/docs/ui-traffic-trafficlog/index.html +118 -0
  800. package/dist/serve/docs-ui/docs/ui-traffic-trafficlog.md +69 -0
  801. package/dist/serve/docs-ui/docs/ui-traffic-trafficstats/index.html +51 -0
  802. package/dist/serve/docs-ui/docs/ui-traffic-trafficstats.md +46 -0
  803. package/dist/serve/docs-ui/docs/ui-traffic.md +102 -0
  804. package/dist/serve/docs-ui/docs/ui.md +90 -0
  805. package/dist/serve/docs-ui/docs/watch-and-review/index.html +25 -0
  806. package/dist/serve/docs-ui/docs/watch-and-review.md +40 -0
  807. package/dist/serve/docs-ui/docs/what-your-agent-can-do/index.html +81 -0
  808. package/dist/serve/docs-ui/docs/what-your-agent-can-do.md +78 -0
  809. package/dist/serve/docs-ui/docs/whats-experimental/index.html +22 -0
  810. package/dist/serve/docs-ui/docs/whats-experimental.md +33 -0
  811. package/dist/serve/docs-ui/docs/whats-possible/index.html +63 -0
  812. package/dist/serve/docs-ui/docs/whats-possible.md +53 -0
  813. package/dist/serve/docs-ui/docs/which-data-service/index.html +8 -0
  814. package/dist/serve/docs-ui/docs/which-data-service.md +11 -0
  815. package/dist/serve/docs-ui/docs/write-a-rules-test-suite/index.html +85 -0
  816. package/dist/serve/docs-ui/docs/write-a-rules-test-suite.md +119 -0
  817. package/dist/serve/docs-ui/index.html +1 -0
  818. package/dist/serve/docs-ui/llms.txt +308 -0
  819. package/dist/serve/entries/ai.d.ts +4 -0
  820. package/dist/serve/entries/ai.d.ts.map +1 -0
  821. package/dist/serve/entries/ai.js +184 -0
  822. package/dist/serve/entries/ai.js.map +1 -0
  823. package/dist/serve/entries/app-backend.d.ts +2 -0
  824. package/dist/serve/entries/app-backend.d.ts.map +1 -0
  825. package/dist/serve/entries/app-backend.js +4 -0
  826. package/dist/serve/entries/app-backend.js.map +1 -0
  827. package/dist/serve/entries/app-client.d.ts +5 -0
  828. package/dist/serve/entries/app-client.d.ts.map +1 -0
  829. package/dist/serve/entries/app-client.js +23 -0
  830. package/dist/serve/entries/app-client.js.map +1 -0
  831. package/dist/serve/entries/app-session-store.d.ts +14 -0
  832. package/dist/serve/entries/app-session-store.d.ts.map +1 -0
  833. package/dist/serve/entries/app-session-store.js +37 -0
  834. package/dist/serve/entries/app-session-store.js.map +1 -0
  835. package/dist/serve/entries/app.d.ts +2 -0
  836. package/dist/serve/entries/app.d.ts.map +1 -0
  837. package/dist/serve/entries/app.js +10 -0
  838. package/dist/serve/entries/app.js.map +1 -0
  839. package/dist/serve/entries/auth-helper-core.d.ts +52 -0
  840. package/dist/serve/entries/auth-helper-core.d.ts.map +1 -0
  841. package/dist/serve/entries/auth-helper-core.js +118 -0
  842. package/dist/serve/entries/auth-helper-core.js.map +1 -0
  843. package/dist/serve/entries/auth-helper-dom.d.ts +14 -0
  844. package/dist/serve/entries/auth-helper-dom.d.ts.map +1 -0
  845. package/dist/serve/entries/auth-helper-dom.js +116 -0
  846. package/dist/serve/entries/auth-helper-dom.js.map +1 -0
  847. package/dist/serve/entries/auth-helper-runtime.d.ts +5 -0
  848. package/dist/serve/entries/auth-helper-runtime.d.ts.map +1 -0
  849. package/dist/serve/entries/auth-helper-runtime.js +11 -0
  850. package/dist/serve/entries/auth-helper-runtime.js.map +1 -0
  851. package/dist/serve/entries/auth.d.ts +77 -0
  852. package/dist/serve/entries/auth.d.ts.map +1 -0
  853. package/dist/serve/entries/auth.js +201 -0
  854. package/dist/serve/entries/auth.js.map +1 -0
  855. package/dist/serve/entries/bridge-url.d.ts +25 -0
  856. package/dist/serve/entries/bridge-url.d.ts.map +1 -0
  857. package/dist/serve/entries/bridge-url.js +30 -0
  858. package/dist/serve/entries/bridge-url.js.map +1 -0
  859. package/dist/serve/entries/database.d.ts +46 -0
  860. package/dist/serve/entries/database.d.ts.map +1 -0
  861. package/dist/serve/entries/database.js +80 -0
  862. package/dist/serve/entries/database.js.map +1 -0
  863. package/dist/serve/entries/firestore.d.ts +104 -0
  864. package/dist/serve/entries/firestore.d.ts.map +1 -0
  865. package/dist/serve/entries/firestore.js +202 -0
  866. package/dist/serve/entries/firestore.js.map +1 -0
  867. package/dist/serve/entries/init.d.ts +2 -0
  868. package/dist/serve/entries/init.d.ts.map +1 -0
  869. package/dist/serve/entries/init.js +40 -0
  870. package/dist/serve/entries/init.js.map +1 -0
  871. package/dist/serve/entries/keepalive.d.ts +20 -0
  872. package/dist/serve/entries/keepalive.d.ts.map +1 -0
  873. package/dist/serve/entries/keepalive.js +38 -0
  874. package/dist/serve/entries/keepalive.js.map +1 -0
  875. package/dist/serve/entries/messaging-sw.d.ts +10 -0
  876. package/dist/serve/entries/messaging-sw.d.ts.map +1 -0
  877. package/dist/serve/entries/messaging-sw.js +36 -0
  878. package/dist/serve/entries/messaging-sw.js.map +1 -0
  879. package/dist/serve/entries/messaging.d.ts +11 -0
  880. package/dist/serve/entries/messaging.d.ts.map +1 -0
  881. package/dist/serve/entries/messaging.js +53 -0
  882. package/dist/serve/entries/messaging.js.map +1 -0
  883. package/dist/serve/entries/runtime.d.ts +46 -0
  884. package/dist/serve/entries/runtime.d.ts.map +1 -0
  885. package/dist/serve/entries/runtime.js +435 -0
  886. package/dist/serve/entries/runtime.js.map +1 -0
  887. package/dist/serve/entries/session-store.d.ts +48 -0
  888. package/dist/serve/entries/session-store.d.ts.map +1 -0
  889. package/dist/serve/entries/session-store.js +82 -0
  890. package/dist/serve/entries/session-store.js.map +1 -0
  891. package/dist/serve/entries/storage.d.ts +25 -0
  892. package/dist/serve/entries/storage.d.ts.map +1 -0
  893. package/dist/serve/entries/storage.js +61 -0
  894. package/dist/serve/entries/storage.js.map +1 -0
  895. package/dist/serve/entries/tab-sync-wiring.d.ts +88 -0
  896. package/dist/serve/entries/tab-sync-wiring.d.ts.map +1 -0
  897. package/dist/serve/entries/tab-sync-wiring.js +217 -0
  898. package/dist/serve/entries/tab-sync-wiring.js.map +1 -0
  899. package/dist/serve/entries/worker-runtime.d.ts +10 -0
  900. package/dist/serve/entries/worker-runtime.d.ts.map +1 -0
  901. package/dist/serve/entries/worker-runtime.js +59 -0
  902. package/dist/serve/entries/worker-runtime.js.map +1 -0
  903. package/dist/serve/init-payload.d.ts +21 -0
  904. package/dist/serve/init-payload.d.ts.map +1 -0
  905. package/dist/serve/init-payload.js +2 -0
  906. package/dist/serve/init-payload.js.map +1 -0
  907. package/dist/serve/namespace.d.ts +73 -0
  908. package/dist/serve/namespace.d.ts.map +1 -0
  909. package/dist/serve/namespace.js +470 -0
  910. package/dist/serve/namespace.js.map +1 -0
  911. package/dist/serve/open-browser.d.ts +23 -0
  912. package/dist/serve/open-browser.d.ts.map +1 -0
  913. package/dist/serve/open-browser.js +58 -0
  914. package/dist/serve/open-browser.js.map +1 -0
  915. package/dist/serve/rules.d.ts +77 -0
  916. package/dist/serve/rules.d.ts.map +1 -0
  917. package/dist/serve/rules.js +202 -0
  918. package/dist/serve/rules.js.map +1 -0
  919. package/dist/serve/sandbox-marker.d.ts +9 -0
  920. package/dist/serve/sandbox-marker.d.ts.map +1 -0
  921. package/dist/serve/sandbox-marker.js +31 -0
  922. package/dist/serve/sandbox-marker.js.map +1 -0
  923. package/dist/serve/server.d.ts +135 -0
  924. package/dist/serve/server.d.ts.map +1 -0
  925. package/dist/serve/server.js +328 -0
  926. package/dist/serve/server.js.map +1 -0
  927. package/dist/serve/standalone-assets.d.ts +67 -0
  928. package/dist/serve/standalone-assets.d.ts.map +1 -0
  929. package/dist/serve/standalone-assets.js +134 -0
  930. package/dist/serve/standalone-assets.js.map +1 -0
  931. package/dist/serve/state-store.d.ts +45 -0
  932. package/dist/serve/state-store.d.ts.map +1 -0
  933. package/dist/serve/state-store.js +120 -0
  934. package/dist/serve/state-store.js.map +1 -0
  935. package/dist/serve/studio/disk-project-store.d.ts +9 -0
  936. package/dist/serve/studio/disk-project-store.d.ts.map +1 -0
  937. package/dist/serve/studio/disk-project-store.js +173 -0
  938. package/dist/serve/studio/disk-project-store.js.map +1 -0
  939. package/dist/serve/studio/disk-workspace.d.ts +14 -0
  940. package/dist/serve/studio/disk-workspace.d.ts.map +1 -0
  941. package/dist/serve/studio/disk-workspace.js +152 -0
  942. package/dist/serve/studio/disk-workspace.js.map +1 -0
  943. package/dist/serve/studio/index.d.ts +10 -0
  944. package/dist/serve/studio/index.d.ts.map +1 -0
  945. package/dist/serve/studio/index.js +9 -0
  946. package/dist/serve/studio/index.js.map +1 -0
  947. package/dist/serve/studio/routes.d.ts +40 -0
  948. package/dist/serve/studio/routes.d.ts.map +1 -0
  949. package/dist/serve/studio/routes.js +182 -0
  950. package/dist/serve/studio/routes.js.map +1 -0
  951. package/dist/serve/studio/store-types.d.ts +45 -0
  952. package/dist/serve/studio/store-types.d.ts.map +1 -0
  953. package/dist/serve/studio/store-types.js +11 -0
  954. package/dist/serve/studio/store-types.js.map +1 -0
  955. package/dist/serve/studio-ui/assets/RulesCodeEditor-BZpD57II.js +23 -0
  956. package/dist/serve/studio-ui/assets/index-Bsa-TQNK.css +1 -0
  957. package/dist/serve/studio-ui/assets/index-DGaVuOhE.js +1211 -0
  958. package/dist/serve/studio-ui/assets/seed-CTmn6YuO.js +2 -0
  959. package/dist/serve/studio-ui/index.html +32 -0
  960. package/dist/serve/studio-ui/pyric-logo.svg +76 -0
  961. package/dist/serve/vite-plugin.d.ts +57 -0
  962. package/dist/serve/vite-plugin.d.ts.map +1 -0
  963. package/dist/serve/vite-plugin.js +658 -0
  964. package/dist/serve/vite-plugin.js.map +1 -0
  965. package/dist/serve/worker/client/admin-firestore.d.ts +18 -0
  966. package/dist/serve/worker/client/admin-firestore.d.ts.map +1 -0
  967. package/dist/serve/worker/client/admin-firestore.js +26 -0
  968. package/dist/serve/worker/client/admin-firestore.js.map +1 -0
  969. package/dist/serve/worker/client/ai.d.ts +31 -0
  970. package/dist/serve/worker/client/ai.d.ts.map +1 -0
  971. package/dist/serve/worker/client/ai.js +89 -0
  972. package/dist/serve/worker/client/ai.js.map +1 -0
  973. package/dist/serve/worker/client/auth.d.ts +168 -0
  974. package/dist/serve/worker/client/auth.d.ts.map +1 -0
  975. package/dist/serve/worker/client/auth.js +322 -0
  976. package/dist/serve/worker/client/auth.js.map +1 -0
  977. package/dist/serve/worker/client/connection.d.ts +80 -0
  978. package/dist/serve/worker/client/connection.d.ts.map +1 -0
  979. package/dist/serve/worker/client/connection.js +148 -0
  980. package/dist/serve/worker/client/connection.js.map +1 -0
  981. package/dist/serve/worker/client/core.d.ts +109 -0
  982. package/dist/serve/worker/client/core.d.ts.map +1 -0
  983. package/dist/serve/worker/client/core.js +248 -0
  984. package/dist/serve/worker/client/core.js.map +1 -0
  985. package/dist/serve/worker/client/disconnect.d.ts +7 -0
  986. package/dist/serve/worker/client/disconnect.d.ts.map +1 -0
  987. package/dist/serve/worker/client/disconnect.js +26 -0
  988. package/dist/serve/worker/client/disconnect.js.map +1 -0
  989. package/dist/serve/worker/client/firestore-reads.d.ts +49 -0
  990. package/dist/serve/worker/client/firestore-reads.d.ts.map +1 -0
  991. package/dist/serve/worker/client/firestore-reads.js +139 -0
  992. package/dist/serve/worker/client/firestore-reads.js.map +1 -0
  993. package/dist/serve/worker/client/firestore-refs.d.ts +54 -0
  994. package/dist/serve/worker/client/firestore-refs.d.ts.map +1 -0
  995. package/dist/serve/worker/client/firestore-refs.js +167 -0
  996. package/dist/serve/worker/client/firestore-refs.js.map +1 -0
  997. package/dist/serve/worker/client/firestore-writes.d.ts +70 -0
  998. package/dist/serve/worker/client/firestore-writes.d.ts.map +1 -0
  999. package/dist/serve/worker/client/firestore-writes.js +169 -0
  1000. package/dist/serve/worker/client/firestore-writes.js.map +1 -0
  1001. package/dist/serve/worker/client/handles.d.ts +73 -0
  1002. package/dist/serve/worker/client/handles.d.ts.map +1 -0
  1003. package/dist/serve/worker/client/handles.js +4 -0
  1004. package/dist/serve/worker/client/handles.js.map +1 -0
  1005. package/dist/serve/worker/client/messaging.d.ts +16 -0
  1006. package/dist/serve/worker/client/messaging.d.ts.map +1 -0
  1007. package/dist/serve/worker/client/messaging.js +60 -0
  1008. package/dist/serve/worker/client/messaging.js.map +1 -0
  1009. package/dist/serve/worker/client/presence.d.ts +43 -0
  1010. package/dist/serve/worker/client/presence.d.ts.map +1 -0
  1011. package/dist/serve/worker/client/presence.js +132 -0
  1012. package/dist/serve/worker/client/presence.js.map +1 -0
  1013. package/dist/serve/worker/client/rtdb.d.ts +36 -0
  1014. package/dist/serve/worker/client/rtdb.d.ts.map +1 -0
  1015. package/dist/serve/worker/client/rtdb.js +241 -0
  1016. package/dist/serve/worker/client/rtdb.js.map +1 -0
  1017. package/dist/serve/worker/client/rules.d.ts +24 -0
  1018. package/dist/serve/worker/client/rules.d.ts.map +1 -0
  1019. package/dist/serve/worker/client/rules.js +44 -0
  1020. package/dist/serve/worker/client/rules.js.map +1 -0
  1021. package/dist/serve/worker/client/service-worker-connection.d.ts +3 -0
  1022. package/dist/serve/worker/client/service-worker-connection.d.ts.map +1 -0
  1023. package/dist/serve/worker/client/service-worker-connection.js +53 -0
  1024. package/dist/serve/worker/client/service-worker-connection.js.map +1 -0
  1025. package/dist/serve/worker/client/snapshots.d.ts +32 -0
  1026. package/dist/serve/worker/client/snapshots.d.ts.map +1 -0
  1027. package/dist/serve/worker/client/snapshots.js +46 -0
  1028. package/dist/serve/worker/client/snapshots.js.map +1 -0
  1029. package/dist/serve/worker/client/storage.d.ts +64 -0
  1030. package/dist/serve/worker/client/storage.d.ts.map +1 -0
  1031. package/dist/serve/worker/client/storage.js +125 -0
  1032. package/dist/serve/worker/client/storage.js.map +1 -0
  1033. package/dist/serve/worker/client/studio.d.ts +32 -0
  1034. package/dist/serve/worker/client/studio.d.ts.map +1 -0
  1035. package/dist/serve/worker/client/studio.js +61 -0
  1036. package/dist/serve/worker/client/studio.js.map +1 -0
  1037. package/dist/serve/worker/client.d.ts +43 -0
  1038. package/dist/serve/worker/client.d.ts.map +1 -0
  1039. package/dist/serve/worker/client.js +44 -0
  1040. package/dist/serve/worker/client.js.map +1 -0
  1041. package/dist/serve/worker/entry.d.ts +40 -0
  1042. package/dist/serve/worker/entry.d.ts.map +1 -0
  1043. package/dist/serve/worker/entry.js +144 -0
  1044. package/dist/serve/worker/entry.js.map +1 -0
  1045. package/dist/serve/worker/host/admin-firestore.d.ts +17 -0
  1046. package/dist/serve/worker/host/admin-firestore.d.ts.map +1 -0
  1047. package/dist/serve/worker/host/admin-firestore.js +92 -0
  1048. package/dist/serve/worker/host/admin-firestore.js.map +1 -0
  1049. package/dist/serve/worker/host/connection.d.ts +40 -0
  1050. package/dist/serve/worker/host/connection.d.ts.map +1 -0
  1051. package/dist/serve/worker/host/connection.js +153 -0
  1052. package/dist/serve/worker/host/connection.js.map +1 -0
  1053. package/dist/serve/worker/host/core.d.ts +159 -0
  1054. package/dist/serve/worker/host/core.d.ts.map +1 -0
  1055. package/dist/serve/worker/host/core.js +296 -0
  1056. package/dist/serve/worker/host/core.js.map +1 -0
  1057. package/dist/serve/worker/host/dispatch.d.ts +34 -0
  1058. package/dist/serve/worker/host/dispatch.d.ts.map +1 -0
  1059. package/dist/serve/worker/host/dispatch.js +267 -0
  1060. package/dist/serve/worker/host/dispatch.js.map +1 -0
  1061. package/dist/serve/worker/host/firestore-reads.d.ts +17 -0
  1062. package/dist/serve/worker/host/firestore-reads.d.ts.map +1 -0
  1063. package/dist/serve/worker/host/firestore-reads.js +108 -0
  1064. package/dist/serve/worker/host/firestore-reads.js.map +1 -0
  1065. package/dist/serve/worker/host/firestore-writes.d.ts +37 -0
  1066. package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -0
  1067. package/dist/serve/worker/host/firestore-writes.js +409 -0
  1068. package/dist/serve/worker/host/firestore-writes.js.map +1 -0
  1069. package/dist/serve/worker/host/presence.d.ts +38 -0
  1070. package/dist/serve/worker/host/presence.d.ts.map +1 -0
  1071. package/dist/serve/worker/host/presence.js +280 -0
  1072. package/dist/serve/worker/host/presence.js.map +1 -0
  1073. package/dist/serve/worker/host/rtdb.d.ts +18 -0
  1074. package/dist/serve/worker/host/rtdb.d.ts.map +1 -0
  1075. package/dist/serve/worker/host/rtdb.js +128 -0
  1076. package/dist/serve/worker/host/rtdb.js.map +1 -0
  1077. package/dist/serve/worker/host/rules.d.ts +17 -0
  1078. package/dist/serve/worker/host/rules.d.ts.map +1 -0
  1079. package/dist/serve/worker/host/rules.js +118 -0
  1080. package/dist/serve/worker/host/rules.js.map +1 -0
  1081. package/dist/serve/worker/host/storage.d.ts +19 -0
  1082. package/dist/serve/worker/host/storage.d.ts.map +1 -0
  1083. package/dist/serve/worker/host/storage.js +260 -0
  1084. package/dist/serve/worker/host/storage.js.map +1 -0
  1085. package/dist/serve/worker/host/studio.d.ts +13 -0
  1086. package/dist/serve/worker/host/studio.d.ts.map +1 -0
  1087. package/dist/serve/worker/host/studio.js +30 -0
  1088. package/dist/serve/worker/host/studio.js.map +1 -0
  1089. package/dist/serve/worker/host/subscriptions.d.ts +21 -0
  1090. package/dist/serve/worker/host/subscriptions.d.ts.map +1 -0
  1091. package/dist/serve/worker/host/subscriptions.js +162 -0
  1092. package/dist/serve/worker/host/subscriptions.js.map +1 -0
  1093. package/dist/serve/worker/host-ai.d.ts +59 -0
  1094. package/dist/serve/worker/host-ai.d.ts.map +1 -0
  1095. package/dist/serve/worker/host-ai.js +158 -0
  1096. package/dist/serve/worker/host-ai.js.map +1 -0
  1097. package/dist/serve/worker/host-auth.d.ts +47 -0
  1098. package/dist/serve/worker/host-auth.d.ts.map +1 -0
  1099. package/dist/serve/worker/host-auth.js +464 -0
  1100. package/dist/serve/worker/host-auth.js.map +1 -0
  1101. package/dist/serve/worker/host-context.d.ts +220 -0
  1102. package/dist/serve/worker/host-context.d.ts.map +1 -0
  1103. package/dist/serve/worker/host-context.js +45 -0
  1104. package/dist/serve/worker/host-context.js.map +1 -0
  1105. package/dist/serve/worker/host-events.d.ts +21 -0
  1106. package/dist/serve/worker/host-events.d.ts.map +1 -0
  1107. package/dist/serve/worker/host-events.js +87 -0
  1108. package/dist/serve/worker/host-events.js.map +1 -0
  1109. package/dist/serve/worker/host-messaging.d.ts +60 -0
  1110. package/dist/serve/worker/host-messaging.d.ts.map +1 -0
  1111. package/dist/serve/worker/host-messaging.js +226 -0
  1112. package/dist/serve/worker/host-messaging.js.map +1 -0
  1113. package/dist/serve/worker/host.d.ts +36 -0
  1114. package/dist/serve/worker/host.d.ts.map +1 -0
  1115. package/dist/serve/worker/host.js +39 -0
  1116. package/dist/serve/worker/host.js.map +1 -0
  1117. package/dist/serve/worker/index.d.ts +22 -0
  1118. package/dist/serve/worker/index.d.ts.map +1 -0
  1119. package/dist/serve/worker/index.js +61 -0
  1120. package/dist/serve/worker/index.js.map +1 -0
  1121. package/dist/serve/worker/presence-timing.d.ts +14 -0
  1122. package/dist/serve/worker/presence-timing.d.ts.map +1 -0
  1123. package/dist/serve/worker/presence-timing.js +14 -0
  1124. package/dist/serve/worker/presence-timing.js.map +1 -0
  1125. package/dist/serve/worker/protocol.d.ts +1150 -0
  1126. package/dist/serve/worker/protocol.d.ts.map +1 -0
  1127. package/dist/serve/worker/protocol.js +228 -0
  1128. package/dist/serve/worker/protocol.js.map +1 -0
  1129. package/dist/serve/worker/serve-init.d.ts +201 -0
  1130. package/dist/serve/worker/serve-init.d.ts.map +1 -0
  1131. package/dist/serve/worker/serve-init.js +579 -0
  1132. package/dist/serve/worker/serve-init.js.map +1 -0
  1133. package/dist/serve/worker/service-worker-channel.d.ts +23 -0
  1134. package/dist/serve/worker/service-worker-channel.d.ts.map +1 -0
  1135. package/dist/serve/worker/service-worker-channel.js +9 -0
  1136. package/dist/serve/worker/service-worker-channel.js.map +1 -0
  1137. package/dist/serve/worker/service-worker-relay.d.ts +22 -0
  1138. package/dist/serve/worker/service-worker-relay.d.ts.map +1 -0
  1139. package/dist/serve/worker/service-worker-relay.js +63 -0
  1140. package/dist/serve/worker/service-worker-relay.js.map +1 -0
  1141. package/dist/serve/writer-lock.d.ts +32 -0
  1142. package/dist/serve/writer-lock.d.ts.map +1 -0
  1143. package/dist/serve/writer-lock.js +43 -0
  1144. package/dist/serve/writer-lock.js.map +1 -0
  1145. package/dist/verify/cases.d.ts +37 -0
  1146. package/dist/verify/cases.d.ts.map +1 -0
  1147. package/dist/verify/cases.js +173 -0
  1148. package/dist/verify/cases.js.map +1 -0
  1149. package/dist/verify/fixture.d.ts +100 -0
  1150. package/dist/verify/fixture.d.ts.map +1 -0
  1151. package/dist/verify/fixture.js +156 -0
  1152. package/dist/verify/fixture.js.map +1 -0
  1153. package/dist/verify/index.d.ts +102 -0
  1154. package/dist/verify/index.d.ts.map +1 -0
  1155. package/dist/verify/index.js +318 -0
  1156. package/dist/verify/index.js.map +1 -0
  1157. package/dist/verify/tools.d.ts +7 -0
  1158. package/dist/verify/tools.d.ts.map +1 -0
  1159. package/dist/verify/tools.js +83 -0
  1160. package/dist/verify/tools.js.map +1 -0
  1161. package/dist/version/compat-target.d.ts +18 -0
  1162. package/dist/version/compat-target.d.ts.map +1 -0
  1163. package/dist/version/compat-target.js +18 -0
  1164. package/dist/version/compat-target.js.map +1 -0
  1165. package/dist/vite.d.ts +12 -0
  1166. package/dist/vite.d.ts.map +1 -0
  1167. package/dist/vite.js +16 -0
  1168. package/dist/vite.js.map +1 -0
  1169. package/package.json +133 -0
@@ -0,0 +1,4060 @@
1
+
2
+ <!-- Generated from published package declarations via TypeDoc. Do not edit by hand; run bun run docs:api:generate. -->
3
+
4
+ ## Classes
5
+
6
+ <a id="persistenceschemaerror"></a>
7
+
8
+ ### PersistenceSchemaError
9
+
10
+ #### Extends
11
+
12
+ - `Error`
13
+
14
+ #### Constructors
15
+
16
+ <a id="constructor"></a>
17
+
18
+ ##### Constructor
19
+
20
+ ```ts
21
+ new PersistenceSchemaError(message: string): PersistenceSchemaError;
22
+ ```
23
+
24
+ ###### Parameters
25
+
26
+ | Parameter | Type |
27
+ | :------ | :------ |
28
+ | `message` | `string` |
29
+
30
+ ###### Returns
31
+
32
+ [`PersistenceSchemaError`](#persistenceschemaerror)
33
+
34
+ ###### Overrides
35
+
36
+ ```ts
37
+ Error.constructor
38
+ ```
39
+
40
+ ***
41
+
42
+ <a id="sandboxcontextimpl"></a>
43
+
44
+ ### SandboxContextImpl
45
+
46
+ Identity-bearing handle on a [Sandbox](#sandbox-3). A
47
+ `(sandbox, auth, operationContext)`
48
+ tuple — cheap to create, immutable, freely shareable. Service
49
+ factories require a `SandboxContext`; bare `Sandbox` is a type
50
+ error so every call site states identity explicitly.
51
+
52
+ Constructed via `Sandbox.withAuth(auth)` or chained via
53
+ `SandboxContext.withAuth(auth)`. The concrete class is exported
54
+ from `pyric/sandbox` for `instanceof` routing in service
55
+ factories; consumers don't construct it directly.
56
+
57
+ #### Implements
58
+
59
+ - [`SandboxContext`](#sandboxcontext)
60
+
61
+ #### Constructors
62
+
63
+ <a id="constructor-1"></a>
64
+
65
+ ##### Constructor
66
+
67
+ ```ts
68
+ new SandboxContextImpl(
69
+ sandbox: Sandbox,
70
+ auth: {
71
+ token?: Record<string, unknown>;
72
+ uid: string;
73
+ },
74
+ operationContext?: OperationContext): SandboxContextImpl;
75
+ ```
76
+
77
+ ###### Parameters
78
+
79
+ | Parameter | Type |
80
+ | :------ | :------ |
81
+ | `sandbox` | [`Sandbox`](#sandbox-3) |
82
+ | `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
83
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
84
+ | `auth.uid?` | `string` |
85
+ | `operationContext?` | [`OperationContext`](#operationcontext-2) |
86
+
87
+ ###### Returns
88
+
89
+ [`SandboxContextImpl`](#sandboxcontextimpl)
90
+
91
+ #### Properties
92
+
93
+ | Property | Modifier | Type | Description |
94
+ | :------ | :------ | :------ | :------ |
95
+ | <a id="auth"></a> `auth` | `readonly` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | The identity rules evaluate under for operations through this context. |
96
+ | `auth.token?` | `public` | `Record`\<`string`, `unknown`\> | - |
97
+ | `auth.uid` | `public` | `string` | - |
98
+ | <a id="operationcontext"></a> `operationContext` | `readonly` | [`OperationContext`](#operationcontext-2) | Immutable provenance bound to every operation issued through this handle. |
99
+ | <a id="sandbox"></a> `sandbox` | `readonly` | [`Sandbox`](#sandbox-3) | The data foundation this context operates against. |
100
+
101
+ #### Methods
102
+
103
+ <a id="withauth"></a>
104
+
105
+ ##### withAuth()
106
+
107
+ ```ts
108
+ withAuth(auth: {
109
+ token?: Record<string, unknown>;
110
+ uid: string;
111
+ }): SandboxContext;
112
+ ```
113
+
114
+ Derive a sibling context on the same sandbox with different auth.
115
+ Replaces auth and its lens while preserving the operation source and
116
+ optional plan identity.
117
+
118
+ ###### Parameters
119
+
120
+ | Parameter | Type |
121
+ | :------ | :------ |
122
+ | `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
123
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
124
+ | `auth.uid` | `string` |
125
+
126
+ ###### Returns
127
+
128
+ [`SandboxContext`](#sandboxcontext)
129
+
130
+ ###### Implementation of
131
+
132
+ [`SandboxContext`](#sandboxcontext).[`withAuth`](#withauth-8)
133
+
134
+ ***
135
+
136
+ <a id="sandboxerror"></a>
137
+
138
+ ### SandboxError
139
+
140
+ Sandbox-layer error. Catch with `instanceof SandboxError` and switch
141
+ on `code`. `denialContext` is populated for `permission-denied` only
142
+ (and only after Slice 4 wires it through).
143
+
144
+ Two construction forms are supported:
145
+ - Positional: `new SandboxError(code, message, denialContext?)` —
146
+ the original signature, kept for backward compatibility with
147
+ existing internal call sites.
148
+ - Options bag: `new SandboxError({ code, message, remediation? })` —
149
+ used when attaching remediation guidance.
150
+
151
+ #### Extends
152
+
153
+ - `Error`
154
+
155
+ #### Constructors
156
+
157
+ <a id="constructor-2"></a>
158
+
159
+ ##### Constructor
160
+
161
+ ```ts
162
+ new SandboxError(
163
+ code: SandboxErrorCode,
164
+ message: string,
165
+ denialContext?: DenialContext): SandboxError;
166
+ ```
167
+
168
+ ###### Parameters
169
+
170
+ | Parameter | Type |
171
+ | :------ | :------ |
172
+ | `code` | [`SandboxErrorCode`](#sandboxerrorcode-1) |
173
+ | `message` | `string` |
174
+ | `denialContext?` | [`DenialContext`](#denialcontext-1) |
175
+
176
+ ###### Returns
177
+
178
+ [`SandboxError`](#sandboxerror)
179
+
180
+ ###### Overrides
181
+
182
+ ```ts
183
+ Error.constructor
184
+ ```
185
+
186
+ ##### Constructor
187
+
188
+ ```ts
189
+ new SandboxError(options: SandboxErrorOptions): SandboxError;
190
+ ```
191
+
192
+ ###### Parameters
193
+
194
+ | Parameter | Type |
195
+ | :------ | :------ |
196
+ | `options` | `SandboxErrorOptions` |
197
+
198
+ ###### Returns
199
+
200
+ [`SandboxError`](#sandboxerror)
201
+
202
+ ###### Overrides
203
+
204
+ ```ts
205
+ Error.constructor
206
+ ```
207
+
208
+ #### Properties
209
+
210
+ | Property | Modifier | Type |
211
+ | :------ | :------ | :------ |
212
+ | <a id="code"></a> `code` | `readonly` | [`SandboxErrorCode`](#sandboxerrorcode-1) |
213
+ | <a id="denialcontext"></a> `denialContext?` | `readonly` | [`DenialContext`](#denialcontext-1) |
214
+ | <a id="remediation"></a> `remediation?` | `readonly` | `string` |
215
+
216
+ ## Interfaces
217
+
218
+ <a id="branch"></a>
219
+
220
+ ### Branch
221
+
222
+ An isolated, in-memory experiment seeded from a [SandboxSnapshot](#sandboxsnapshot-2).
223
+
224
+ A branch owns its own [LocalSandbox](#localsandbox) (fully isolated from the source —
225
+ separate `LocalEnvironment`, separate event history) plus the
226
+ accumulated [SandboxEvent](#sandboxevent)s applied to it via [apply](#apply). The
227
+ applied events are what [promote](#promote) replays onto the target.
228
+
229
+ #### Properties
230
+
231
+ | Property | Modifier | Type | Description |
232
+ | :------ | :------ | :------ | :------ |
233
+ | <a id="base"></a> `base` | `readonly` | [`SandboxSnapshot`](#sandboxsnapshot-2) | The snapshot this branch was forked from. Retained so [diff](#diff) and [promote](#promote) can reason about the baseline. |
234
+ | <a id="discarded"></a> `discarded` | `public` | `boolean` | Flipped by [discard](#discard); subsequent [apply](#apply)/[promote](#promote) calls throw. |
235
+ | <a id="events"></a> `events` | `readonly` | [`SandboxEvent`](#sandboxevent)[] | Write/op events applied to this branch since fork, in order. These are replayed onto the target by [promote](#promote). |
236
+ | <a id="rules"></a> `rules` | `readonly` | `string` | Rules the branch was forked with — carried so [promote](#promote) can re-seed a replay target identically. |
237
+ | <a id="sandbox-1"></a> `sandbox` | `readonly` | [`LocalSandbox`](#localsandbox) | The branch's own sandbox. Inspect it directly (`branch.sandbox.snapshot()`) or read docs via `branch.sandbox.admin.getDocument(path)`. |
238
+
239
+ ***
240
+
241
+ <a id="broadcastchannellike"></a>
242
+
243
+ ### BroadcastChannelLike
244
+
245
+ Minimal interface that `BroadcastChannel` satisfies. Provided as an
246
+ injectable seam so tests can run without a real browser channel.
247
+
248
+ The real `BroadcastChannel` global satisfies this interface out of the
249
+ box — pass it directly:
250
+
251
+ ```ts
252
+ sandbox.enableTabSync({
253
+ channel: new BroadcastChannel('pyric:tabsync'),
254
+ });
255
+ ```
256
+
257
+ For SSR / Node environments, the default channel construction is guarded
258
+ (`typeof BroadcastChannel !== 'undefined'`) so the call site doesn't need
259
+ to branch — a missing global just means no sync, which is fine for server
260
+ renders that only care about initial data.
261
+
262
+ #### Methods
263
+
264
+ <a id="addeventlistener"></a>
265
+
266
+ ##### addEventListener()
267
+
268
+ ```ts
269
+ addEventListener(type: "message", listener: (ev: {
270
+ data: unknown;
271
+ }) => void): void;
272
+ ```
273
+
274
+ ###### Parameters
275
+
276
+ | Parameter | Type |
277
+ | :------ | :------ |
278
+ | `type` | `"message"` |
279
+ | `listener` | (`ev`: \{ `data`: `unknown`; \}) => `void` |
280
+
281
+ ###### Returns
282
+
283
+ `void`
284
+
285
+ <a id="close"></a>
286
+
287
+ ##### close()
288
+
289
+ ```ts
290
+ close(): void;
291
+ ```
292
+
293
+ ###### Returns
294
+
295
+ `void`
296
+
297
+ <a id="postmessage"></a>
298
+
299
+ ##### postMessage()
300
+
301
+ ```ts
302
+ postMessage(message: unknown): void;
303
+ ```
304
+
305
+ ###### Parameters
306
+
307
+ | Parameter | Type |
308
+ | :------ | :------ |
309
+ | `message` | `unknown` |
310
+
311
+ ###### Returns
312
+
313
+ `void`
314
+
315
+ <a id="removeeventlistener"></a>
316
+
317
+ ##### removeEventListener()
318
+
319
+ ```ts
320
+ removeEventListener(type: "message", listener: (ev: {
321
+ data: unknown;
322
+ }) => void): void;
323
+ ```
324
+
325
+ ###### Parameters
326
+
327
+ | Parameter | Type |
328
+ | :------ | :------ |
329
+ | `type` | `"message"` |
330
+ | `listener` | (`ev`: \{ `data`: `unknown`; \}) => `void` |
331
+
332
+ ###### Returns
333
+
334
+ `void`
335
+
336
+ ***
337
+
338
+ <a id="denialcontext-1"></a>
339
+
340
+ ### DenialContext
341
+
342
+ Structured denial context emitted alongside a `permission-denied`
343
+ error. Real Firebase strips this server-side for security; the
344
+ sandbox can expose it because it's a development tool.
345
+
346
+ `auth` and `reasons` are populated whenever the sandbox raises a
347
+ `permission-denied` error. `rule` (line + expression) requires
348
+ source-position tracking in the rules AST and is deferred — see
349
+ design rationale "Open questions" for the follow-up.
350
+ `failedFields` will be filled in once the evaluator surfaces field-
351
+ reference traces.
352
+
353
+ #### Properties
354
+
355
+ | Property | Type | Description |
356
+ | :------ | :------ | :------ |
357
+ | <a id="auth-1"></a> `auth?` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | Auth identity that was active when the denial fired. |
358
+ | `auth.token?` | `Record`\<`string`, `unknown`\> | - |
359
+ | `auth.uid` | `string` | - |
360
+ | <a id="failedfields"></a> `failedFields?` | `string`[] | Field paths in `request.resource.data` that the rule referenced and that failed. |
361
+ | <a id="reasons"></a> `reasons?` | `string`[] | Raw simulator reasoning lines (the underlying engine's `debugMessages`). Always present on `permission-denied`. Stable enough for log surfacing; not stable as machine-parseable data. |
362
+ | <a id="request"></a> `request?` | \{ `method`: `"get"` \| `"list"` \| `"create"` \| `"update"` \| `"delete"`; `path`: `string`; `resourceData?`: `Record`\<`string`, `unknown`\>; \} | Eval-time request shape — what the rule saw on `request.*`. Lets callers render a "why did this deny" frame (auth, method, path, `request.resource.data` with sentinels resolved) without re-deriving any of it from out-of-band state. |
363
+ | `request.method` | `"get"` \| `"list"` \| `"create"` \| `"update"` \| `"delete"` | - |
364
+ | `request.path` | `string` | - |
365
+ | `request.resourceData?` | `Record`\<`string`, `unknown`\> | The user's proposed `request.resource.data` — pre-resolution. `FieldValue.*` sentinels are preserved as their marker shapes (`{ __type: 'serverTimestamp' }`, etc.). The rule engine evaluated against the resolved form; what surfaces here is the caller's INTENT so consumers see what they tried to write. Absent for reads (no proposed write) and for `delete` (no payload). |
366
+ | <a id="resource"></a> `resource?` | \{ `data`: `Record`\<`string`, `unknown`\>; `exists`: `boolean`; \} | Eval-time existing-document snapshot — what the rule saw on `resource.data`. `null` data with `exists: false` mirrors how the rule sees an absent doc. Absent for collection ops (`list`). |
367
+ | `resource.data` | `Record`\<`string`, `unknown`\> | - |
368
+ | `resource.exists` | `boolean` | - |
369
+ | <a id="rule"></a> `rule?` | \{ `expression`: `string`; `line`: `number`; \} | The rule whose evaluation produced the denial. Best effort; may be absent until source positions land in the AST. |
370
+ | `rule.expression` | `string` | - |
371
+ | `rule.line` | `number` | - |
372
+
373
+ ***
374
+
375
+ <a id="denialevent"></a>
376
+
377
+ ### DenialEvent
378
+
379
+ Eval-time payload emitted to Sandbox.onDenial subscribers.
380
+
381
+ Mirrors the structured fields [DenialContext](#denialcontext-1) carries (`request`
382
+ + `resource` + `reasons` + `auth`) so a host environment that wants
383
+ to surface denials independent of try/catch behavior gets the same
384
+ frame either way.
385
+
386
+ #### Properties
387
+
388
+ | Property | Type |
389
+ | :------ | :------ |
390
+ | <a id="auth-2"></a> `auth?` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
391
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
392
+ | `auth.uid` | `string` |
393
+ | <a id="code-1"></a> `code` | `"permission-denied"` |
394
+ | <a id="message"></a> `message` | `string` |
395
+ | <a id="reasons-1"></a> `reasons?` | `string`[] |
396
+ | <a id="request-1"></a> `request?` | \{ `method`: `"get"` \| `"list"` \| `"create"` \| `"update"` \| `"delete"`; `path`: `string`; `resourceData?`: `Record`\<`string`, `unknown`\>; \} |
397
+ | `request.method` | `"get"` \| `"list"` \| `"create"` \| `"update"` \| `"delete"` |
398
+ | `request.path` | `string` |
399
+ | `request.resourceData?` | `Record`\<`string`, `unknown`\> |
400
+ | <a id="resource-1"></a> `resource?` | \{ `data`: `Record`\<`string`, `unknown`\>; `exists`: `boolean`; \} |
401
+ | `resource.data` | `Record`\<`string`, `unknown`\> |
402
+ | `resource.exists` | `boolean` |
403
+
404
+ ***
405
+
406
+ <a id="eventprovenance"></a>
407
+
408
+ ### EventProvenance
409
+
410
+ Compatibility provenance carried by sandbox events while producers and
411
+ consumers migrate to the canonical `operationContext`.
412
+
413
+ #### Properties
414
+
415
+ | Property | Type | Description |
416
+ | :------ | :------ | :------ |
417
+ | <a id="actor"></a> `actor?` | [`EventActor`](#eventactor) | - |
418
+ | <a id="authlens"></a> `authLens?` | [`AuthLens`](#authlens-2) | - |
419
+ | <a id="operationcontext-1"></a> `operationContext?` | [`OperationContext`](#operationcontext-2) | - |
420
+ | <a id="planid"></a> `planId?` | `string` | Set when the op is part of an agent plan. |
421
+ | <a id="service"></a> `service?` | [`EventService`](#eventservice) | - |
422
+
423
+ ***
424
+
425
+ <a id="listenerlifecycleevent"></a>
426
+
427
+ ### ListenerLifecycleEvent
428
+
429
+ Listener lifecycle event — attach, detach, or errored. Errored
430
+ supersedes the prior `onSnapshotError` channel; `error` is populated
431
+ on the errored phase only.
432
+
433
+ #### Properties
434
+
435
+ | Property | Type | Description |
436
+ | :------ | :------ | :------ |
437
+ | <a id="at"></a> `at` | `number` | - |
438
+ | <a id="auth-3"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | - |
439
+ | `auth.token?` | `Record`\<`string`, `unknown`\> | - |
440
+ | `auth.uid` | `string` | - |
441
+ | <a id="error"></a> `error?` | \{ `code`: `"permission-denied"`; `message`: `string`; `reasons?`: `string`[]; \} | Populated on `listener_errored` only. |
442
+ | `error.code` | `"permission-denied"` | - |
443
+ | `error.message` | `string` | - |
444
+ | `error.reasons?` | `string`[] | - |
445
+ | <a id="id"></a> `id` | `string` | - |
446
+ | <a id="kind"></a> `kind` | `"listener_attach"` \| `"listener_detach"` \| `"listener_errored"` | - |
447
+ | <a id="listenerid"></a> `listenerId` | `string` | - |
448
+ | <a id="target"></a> `target` | \| \{ `kind`: `"doc"`; `path`: `string`; \} \| \{ `collection`: `string`; `kind`: `"query"`; \} | - |
449
+
450
+ ***
451
+
452
+ <a id="localsandbox"></a>
453
+
454
+ ### LocalSandbox
455
+
456
+ An in-process sandbox created by [initializeSandbox](#initializesandbox).
457
+
458
+ Service controls whose implementation requires synchronous access to local
459
+ state accept this type. Remote worker handles remain [Sandbox](#sandbox-3)s, but
460
+ are deliberately not assignable to this local-only interface.
461
+
462
+ #### Extends
463
+
464
+ - [`Sandbox`](#sandbox-3)
465
+
466
+ #### Properties
467
+
468
+ | Property | Modifier | Type | Description |
469
+ | :------ | :------ | :------ | :------ |
470
+ | <a id="local_sandbox"></a> `[LOCAL_SANDBOX]` | `readonly` | `true` | - |
471
+ | <a id="admin"></a> `admin` | `readonly` | `SandboxAdmin` | Admin-plane access (rule-bypass reads). Identity-agnostic by design — admin reads aren't gated on auth, so they live on the sandbox, not on a context. See SandboxAdmin. |
472
+ | <a id="currentuser"></a> `currentUser` | `public` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | Current authenticated user across the sandbox. Mutated by `pyric/auth`'s `signInAnonymously` / `signInWithEmailAndPassword` / `signOut` / `sandbox.setUser`. Read per-call by service factories (e.g. a future `getFirestore(sandbox)` overload) so they see auth state changes without re-binding handles. Defaults to `null` (anonymous / signed out). **Independent of `withAuth({uid})`** — `withAuth` still produces a frozen [SandboxContext](#sandboxcontext) that carries its own identity for the runner's test code (the existing pattern: explicit identity per service call). `currentUser` exists for the `pyric/auth` mirror, where consumer app code drives identity through a stateful `Auth` handle rather than naming it per call. |
473
+ | `currentUser.token?` | `public` | `Record`\<`string`, `unknown`\> | - |
474
+ | `currentUser.uid` | `public` | `string` | - |
475
+
476
+ #### Methods
477
+
478
+ <a id="clearpersistence"></a>
479
+
480
+ ##### clearPersistence()
481
+
482
+ ```ts
483
+ clearPersistence(): Promise<void>;
484
+ ```
485
+
486
+ Wipe the persisted blob for this sandbox's `key`. In-memory state
487
+ is left intact — call `reset()` if you want both. Useful for
488
+ "sign out and forget" flows.
489
+
490
+ No-op when persistence is not enabled.
491
+
492
+ ###### Returns
493
+
494
+ `Promise`\<`void`\>
495
+
496
+ ###### Inherited from
497
+
498
+ [`Sandbox`](#sandbox-3).[`clearPersistence`](#clearpersistence-4)
499
+
500
+ <a id="dispose"></a>
501
+
502
+ ##### dispose()
503
+
504
+ ```ts
505
+ dispose(): void;
506
+ ```
507
+
508
+ Tear down listener registries on this sandbox's environment without
509
+ replacing it. Use this when you're about to discard the sandbox
510
+ itself (e.g. `runner.reseed()` builds a fresh sandbox rather than
511
+ calling `reset()`) and want to drop callback references on the
512
+ outgoing instance defensively. Idempotent. Does not touch data.
513
+
514
+ ###### Returns
515
+
516
+ `void`
517
+
518
+ ###### Inherited from
519
+
520
+ [`Sandbox`](#sandbox-3).[`dispose`](#dispose-6)
521
+
522
+ <a id="enablepersistence"></a>
523
+
524
+ ##### enablePersistence()
525
+
526
+ ```ts
527
+ enablePersistence(options: SandboxPersistenceOptions): Promise<void>;
528
+ ```
529
+
530
+ Persist the sandbox's data to a backend and restore it on next
531
+ `enablePersistence` call. The default `'indexedDB'` backend turns
532
+ the sandbox into the host page's local Firestore — writes flush
533
+ automatically and a fresh `initializeSandbox()` rehydrates from
534
+ the prior session.
535
+
536
+ Restoration happens before the promise resolves; awaiting this
537
+ call is sufficient to guarantee in-memory state matches the
538
+ persisted blob.
539
+
540
+ Idempotent across the same `key` — calling twice in one process
541
+ is a no-op on the second call. Different keys are rejected as an
542
+ error (a sandbox can persist to at most one backend at a time).
543
+
544
+ Listener semantics: every write event the sandbox emits triggers
545
+ a debounced flush (default 250ms). Browser hosts additionally
546
+ flush on `beforeunload` so a page navigation doesn't lose the
547
+ tail of the debounce window.
548
+
549
+ See [SandboxPersistenceOptions](#sandboxpersistenceoptions) for backend selection and
550
+ tuning.
551
+
552
+ ###### Parameters
553
+
554
+ | Parameter | Type |
555
+ | :------ | :------ |
556
+ | `options` | [`SandboxPersistenceOptions`](#sandboxpersistenceoptions) |
557
+
558
+ ###### Returns
559
+
560
+ `Promise`\<`void`\>
561
+
562
+ ###### Inherited from
563
+
564
+ [`Sandbox`](#sandbox-3).[`enablePersistence`](#enablepersistence-4)
565
+
566
+ <a id="enabletabsync"></a>
567
+
568
+ ##### enableTabSync()
569
+
570
+ ```ts
571
+ enableTabSync(options?: TabSyncOptions): () => void;
572
+ ```
573
+
574
+ Enable cross-tab realtime sync via `BroadcastChannel`. A write in
575
+ this tab will propagate to every OTHER tab of the same origin that
576
+ also called `enableTabSync`, causing their `onSnapshot` listeners to
577
+ re-evaluate — restoring production's cross-client realtime behavior.
578
+
579
+ **Opt-in, OFF by default.** Firestore only (RTDB is a follow-on).
580
+
581
+ Returns a disable function. Calling it removes the `onEvent`
582
+ subscription, the channel message listener, and closes the channel
583
+ (when it was created internally). After disable, no further propagation
584
+ occurs in either direction.
585
+
586
+ **Multi-writer note:** concurrent writes from two tabs to the same doc
587
+ produce last-write-wins divergence — there is no conflict resolution.
588
+ The intended model is one active writer (one user, one tab) with
589
+ observers in other tabs; this covers the overwhelming majority of
590
+ local development scenarios.
591
+
592
+ ###### Parameters
593
+
594
+ | Parameter | Type |
595
+ | :------ | :------ |
596
+ | `options?` | [`TabSyncOptions`](#tabsyncoptions) |
597
+
598
+ ###### Returns
599
+
600
+ ```ts
601
+ (): void;
602
+ ```
603
+
604
+ ###### Returns
605
+
606
+ `void`
607
+
608
+ ###### See
609
+
610
+ [TabSyncOptions](#tabsyncoptions) for channel injection (tests) and originId.
611
+
612
+ ###### Example
613
+
614
+ ```ts
615
+ // In every tab that should participate in realtime:
616
+ const sandbox = initializeSandbox();
617
+ const disableSync = sandbox.enableTabSync();
618
+ // Later, to stop syncing:
619
+ disableSync();
620
+ ```
621
+
622
+ ###### Inherited from
623
+
624
+ [`Sandbox`](#sandbox-3).[`enableTabSync`](#enabletabsync-4)
625
+
626
+ <a id="flush"></a>
627
+
628
+ ##### flush()
629
+
630
+ ```ts
631
+ flush(): Promise<void>;
632
+ ```
633
+
634
+ Force a snapshot to the configured persistence backend right now.
635
+ Useful before a manual navigation, or in tests that need
636
+ deterministic ordering against the debounce window. Resolves once
637
+ the write hits the backend.
638
+
639
+ Throws if persistence is not enabled.
640
+
641
+ ###### Returns
642
+
643
+ `Promise`\<`void`\>
644
+
645
+ ###### Inherited from
646
+
647
+ [`Sandbox`](#sandbox-3).[`flush`](#flush-6)
648
+
649
+ <a id="history"></a>
650
+
651
+ ##### history()
652
+
653
+ ```ts
654
+ history(): SandboxEvent[];
655
+ ```
656
+
657
+ Every [SandboxEvent](#sandboxevent) this sandbox has emitted since init or
658
+ the last `reset()`. Returns a defensive copy.
659
+
660
+ Use this for replay: hand the array to `replay(events, rules)`
661
+ from `pyric/sandbox` and the engine re-issues every
662
+ captured write against a fresh sandbox.
663
+
664
+ Unlike [onEvent](#onevent-4) (live stream from the moment of subscribe),
665
+ `history()` returns *every* event the sandbox has seen — useful
666
+ for consumers that attach late (e.g., loading a saved session
667
+ before subscribing) or that need a snapshot at a particular moment.
668
+
669
+ `reset()` and `dispose()` each append a closing `session_boundary`
670
+ event; `reset()` then clears the history. Consumers that took a
671
+ snapshot *before* reset retain the boundary in their copy.
672
+
673
+ ###### Returns
674
+
675
+ [`SandboxEvent`](#sandboxevent)[]
676
+
677
+ ###### Inherited from
678
+
679
+ [`Sandbox`](#sandbox-3).[`history`](#history-4)
680
+
681
+ <a id="loadsnapshot"></a>
682
+
683
+ ##### loadSnapshot()
684
+
685
+ ```ts
686
+ loadSnapshot(data: SandboxSnapshot): void;
687
+ ```
688
+
689
+ CLOBBER-restore the sandbox's entire state from a prior [snapshot](#snapshot-6):
690
+ `reset()` (clears firestore + the signed-in session), then rebuild firestore
691
+ from `data` and restore each registered service. This is a TOTAL replace —
692
+ documents absent from `data` do NOT survive — and is the counterpart to
693
+ [snapshot](#snapshot-6). It is what makes "transfer (clobber) one instance's data
694
+ into another" and named-branch switching possible.
695
+
696
+ Fires a `session_boundary` (reset phase), re-evaluates live listeners against
697
+ the loaded state, and the next persistence flush writes the loaded state.
698
+ Services present in `data` but not currently registered are skipped (a
699
+ snapshot taken via [snapshot](#snapshot-6) always includes every registered
700
+ service, so this only affects cross-instance imports from a sandbox that had
701
+ a service this one lacks).
702
+
703
+ ###### Parameters
704
+
705
+ | Parameter | Type |
706
+ | :------ | :------ |
707
+ | `data` | [`SandboxSnapshot`](#sandboxsnapshot-2) |
708
+
709
+ ###### Returns
710
+
711
+ `void`
712
+
713
+ ###### Inherited from
714
+
715
+ [`Sandbox`](#sandbox-3).[`loadSnapshot`](#loadsnapshot-4)
716
+
717
+ <a id="oncurrentuserchanged"></a>
718
+
719
+ ##### onCurrentUserChanged()
720
+
721
+ ```ts
722
+ onCurrentUserChanged(cb: (user: {
723
+ token?: Record<string, unknown>;
724
+ uid: string;
725
+ }) => void): () => void;
726
+ ```
727
+
728
+ Subscribe to `currentUser` changes. Fires on every mutation —
729
+ sign-in, sign-out, user swap. Does NOT fire on subscribe.
730
+
731
+ Survives `reset()` and `dispose()` only as a no-op: a disposed
732
+ sandbox emits nothing further; a reset sandbox clears
733
+ `currentUser` to `null` (and fires the change) before swapping
734
+ the env.
735
+
736
+ Returns an unsubscribe function. Listener errors are swallowed —
737
+ subscribers are observational, the sandbox does not propagate
738
+ their errors.
739
+
740
+ ###### Parameters
741
+
742
+ | Parameter | Type |
743
+ | :------ | :------ |
744
+ | `cb` | (`user`: \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \}) => `void` |
745
+
746
+ ###### Returns
747
+
748
+ ```ts
749
+ (): void;
750
+ ```
751
+
752
+ ###### Returns
753
+
754
+ `void`
755
+
756
+ ###### Inherited from
757
+
758
+ [`Sandbox`](#sandbox-3).[`onCurrentUserChanged`](#oncurrentuserchanged-4)
759
+
760
+ <a id="onevent"></a>
761
+
762
+ ##### onEvent()
763
+
764
+ ```ts
765
+ onEvent(cb: (event: SandboxEvent) => void): () => void;
766
+ ```
767
+
768
+ Subscribe to every event the sandbox emits — see [SandboxEvent](#sandboxevent)
769
+ for the discriminated-union shape. One subscription covers
770
+ request/denial/snapshot-error/listener-lifecycle/session-boundary;
771
+ filter on `event.kind` to recover individual streams.
772
+
773
+ Replaces the prior three-channel surface (`onRequest` / `onDenial`
774
+ / `onSnapshotError`) — see issue #307. Filter cookbook:
775
+ - All denials: `event.kind === 'request' && event.result === 'deny'`
776
+ - Stream errors: `event.kind === 'listener_errored'`
777
+ - Per-op traffic: `event.kind === 'request'`
778
+
779
+ Survives `sandbox.reset()` — the subscription is held on the
780
+ sandbox, not on the underlying environment. A `session_boundary`
781
+ event with `phase: 'reset'` fires before the env swap so consumers
782
+ can segment their stream.
783
+
784
+ Returns an unsubscribe function. Listener errors are swallowed so a
785
+ faulty subscriber can't change rule semantics or hide other events.
786
+ Both synchronous throws and rejected Promises from async callbacks
787
+ are silently discarded — subscribers are **observational**, the
788
+ sandbox doesn't await them and doesn't propagate their errors.
789
+
790
+ ###### Parameters
791
+
792
+ | Parameter | Type |
793
+ | :------ | :------ |
794
+ | `cb` | (`event`: [`SandboxEvent`](#sandboxevent)) => `void` |
795
+
796
+ ###### Returns
797
+
798
+ ```ts
799
+ (): void;
800
+ ```
801
+
802
+ ###### Returns
803
+
804
+ `void`
805
+
806
+ ###### Inherited from
807
+
808
+ [`Sandbox`](#sandbox-3).[`onEvent`](#onevent-4)
809
+
810
+ <a id="registerpersistableservice"></a>
811
+
812
+ ##### registerPersistableService()
813
+
814
+ ```ts
815
+ registerPersistableService(name: string, hooks: PersistableService): () => void;
816
+ ```
817
+
818
+ Register a service (auth, storage, …) as a persistence participant.
819
+ The sandbox calls `hooks.snapshot()` on every flush and
820
+ `hooks.restore(data)` on restore. If `hooks.subscribe` is provided,
821
+ the persistence controller subscribes and schedules a debounced
822
+ flush on each change — so auth-user edits flush promptly, not only
823
+ on the next Firestore write.
824
+
825
+ Returns an unregister function — call it if the service is torn
826
+ down before the sandbox is disposed (uncommon in practice; the
827
+ sandbox's `dispose()` clears the registry anyway).
828
+
829
+ Throws `failed-precondition` when a service with the same `name` is
830
+ already registered — the auth package registers `'auth'` once when
831
+ `getAuth(sandbox)` first creates a backend, so accidental double-
832
+ registration is a caller bug, not a no-op.
833
+
834
+ **Advanced / internal API.** Service packages (auth, storage) call
835
+ this when they first attach to a sandbox. Consumer app code should
836
+ not need to call this directly.
837
+
838
+ ###### Parameters
839
+
840
+ | Parameter | Type |
841
+ | :------ | :------ |
842
+ | `name` | `string` |
843
+ | `hooks` | [`PersistableService`](#persistableservice) |
844
+
845
+ ###### Returns
846
+
847
+ ```ts
848
+ (): void;
849
+ ```
850
+
851
+ ###### Returns
852
+
853
+ `void`
854
+
855
+ ###### Inherited from
856
+
857
+ [`Sandbox`](#sandbox-3).[`registerPersistableService`](#registerpersistableservice-4)
858
+
859
+ <a id="reset"></a>
860
+
861
+ ##### reset()
862
+
863
+ ```ts
864
+ reset(): void;
865
+ ```
866
+
867
+ Reset the underlying environment to a fresh state — wipes data,
868
+ rules, and any service-specific configuration.
869
+
870
+ Snapshot listeners attached to the OLD environment are dropped at
871
+ the swap — they can't survive because their target docs have been
872
+ wiped. `onEvent` subscribers DO survive — the registry lives on
873
+ the sandbox, and a `session_boundary` event with `phase: 'reset'`
874
+ fires before the swap so subscribers know the rollover happened.
875
+ Existing [SandboxContext](#sandboxcontext)s continue to work — their sandbox
876
+ reference is stable; subsequent operations resolve to the new env.
877
+
878
+ ###### Returns
879
+
880
+ `void`
881
+
882
+ ###### Inherited from
883
+
884
+ [`Sandbox`](#sandbox-3).[`reset`](#reset-4)
885
+
886
+ <a id="runwithprovenance"></a>
887
+
888
+ ##### runWithProvenance()?
889
+
890
+ ```ts
891
+ optional runWithProvenance<T>(provenance: EventProvenance, fn: () => T): T;
892
+ ```
893
+
894
+ Run `fn` with ambient [EventProvenance](#eventprovenance) defaults: every event
895
+ emitted SYNCHRONOUSLY during `fn` that doesn't already carry a
896
+ provenance field (on the event itself or via an explicit per-emit
897
+ override) is stamped with these values instead of the global
898
+ defaults. This is the mechanical "who issued this op" seam the
899
+ serve worker uses to tag Studio-issued ops (`actor: { kind:
900
+ 'studio' }`) and to stamp the auth lens an op ran under
901
+ (`authLens`) — declared by the caller that issues the op, never
902
+ inferred from the op's shape.
903
+
904
+ SYNCHRONOUS WINDOW: the ambient values apply only until `fn`
905
+ returns (for an async `fn`, its synchronous prefix — which covers
906
+ the local environment's rules eval + event emission, since those
907
+ run before the op's promise is handed back). Work an op DEFERS
908
+ (snapshot-listener deliveries and re-evals drain on a microtask,
909
+ off-stack) is intentionally OUTSIDE the window: a listener re-eval
910
+ belongs to the listener's owner, not to whoever's write triggered
911
+ it. Nested calls stack — the innermost window wins per field, and
912
+ each window restores the previous one on exit (including on throw).
913
+
914
+ OPTIONAL because remote sandbox proxies can't provide an ambient
915
+ emit window (events are emitted in the worker they front). Callers
916
+ spell `sandbox.runWithProvenance?.(prov, fn) ?? fn()`.
917
+
918
+ ###### Type Parameters
919
+
920
+ | Type Parameter |
921
+ | :------ |
922
+ | `T` |
923
+
924
+ ###### Parameters
925
+
926
+ | Parameter | Type |
927
+ | :------ | :------ |
928
+ | `provenance` | [`EventProvenance`](#eventprovenance) |
929
+ | `fn` | () => `T` |
930
+
931
+ ###### Returns
932
+
933
+ `T`
934
+
935
+ ###### Inherited from
936
+
937
+ [`Sandbox`](#sandbox-3).[`runWithProvenance`](#runwithprovenance-4)
938
+
939
+ <a id="snapshot"></a>
940
+
941
+ ##### snapshot()
942
+
943
+ ```ts
944
+ snapshot(): SandboxSnapshot;
945
+ ```
946
+
947
+ Capture a snapshot of every service's state. For v1 with only
948
+ Firestore, the return value carries a `firestore` key mapping doc
949
+ paths to data. Future services will add their own keys.
950
+
951
+ ###### Returns
952
+
953
+ [`SandboxSnapshot`](#sandboxsnapshot-2)
954
+
955
+ ###### Inherited from
956
+
957
+ [`Sandbox`](#sandbox-3).[`snapshot`](#snapshot-6)
958
+
959
+ <a id="withauth-2"></a>
960
+
961
+ ##### withAuth()
962
+
963
+ ```ts
964
+ withAuth(auth: {
965
+ token?: Record<string, unknown>;
966
+ uid: string;
967
+ }): SandboxContext;
968
+ ```
969
+
970
+ Derive a context bound to this sandbox under the given auth
971
+ identity. Operations through services attached to the returned
972
+ context evaluate rules under that identity. Many contexts can
973
+ coexist for one sandbox; data is shared.
974
+
975
+ `null` is anonymous; an `AuthState` object names the user (and
976
+ optional custom claims). Passing `undefined` is a deliberate
977
+ error — say `withAuth(null)` for anonymous so the call site is
978
+ unambiguous.
979
+
980
+ ###### Parameters
981
+
982
+ | Parameter | Type |
983
+ | :------ | :------ |
984
+ | `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
985
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
986
+ | `auth.uid` | `string` |
987
+
988
+ ###### Returns
989
+
990
+ [`SandboxContext`](#sandboxcontext)
991
+
992
+ ###### Example
993
+
994
+ ```ts
995
+ const sandbox = initializeSandbox();
996
+ const dbAlice = getFirestore(sandbox.withAuth({ uid: 'alice' }));
997
+ const dbAnon = getFirestore(sandbox.withAuth(null));
998
+ ```
999
+
1000
+ ###### Inherited from
1001
+
1002
+ [`Sandbox`](#sandbox-3).[`withAuth`](#withauth-6)
1003
+
1004
+ ***
1005
+
1006
+ <a id="operationcontext-2"></a>
1007
+
1008
+ ### OperationContext
1009
+
1010
+ Immutable operation provenance, bound where an operation is issued.
1011
+ Source and auth lens are deliberately orthogonal: Studio may evaluate rules
1012
+ as a user, while an app or agent may use an admin lens.
1013
+
1014
+ #### Properties
1015
+
1016
+ | Property | Modifier | Type |
1017
+ | :------ | :------ | :------ |
1018
+ | <a id="authlens-1"></a> `authLens` | `readonly` | [`AuthLens`](#authlens-2) |
1019
+ | <a id="planid-1"></a> `planId?` | `readonly` | `string` |
1020
+ | <a id="source"></a> `source` | `readonly` | [`EventActor`](#eventactor) |
1021
+
1022
+ ***
1023
+
1024
+ <a id="operationrecord"></a>
1025
+
1026
+ ### OperationRecord
1027
+
1028
+ #### Properties
1029
+
1030
+ | Property | Modifier | Type |
1031
+ | :------ | :------ | :------ |
1032
+ | <a id="at-1"></a> `at` | `readonly` | `number` |
1033
+ | <a id="auth-4"></a> `auth` | `readonly` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
1034
+ | `auth.token?` | `public` | `Record`\<`string`, `unknown`\> |
1035
+ | `auth.uid` | `public` | `string` |
1036
+ | <a id="context"></a> `context` | `readonly` | [`OperationContext`](#operationcontext-2) |
1037
+ | <a id="eventkind"></a> `eventKind` | `readonly` | `"request"` \| `"operation"` |
1038
+ | <a id="id-1"></a> `id` | `readonly` | `string` |
1039
+ | <a id="method"></a> `method` | `readonly` | `string` |
1040
+ | <a id="path"></a> `path?` | `readonly` | `string` |
1041
+ | <a id="result"></a> `result` | `readonly` | `"allow"` \| `"deny"` \| `"unsupported"` \| `"error"` \| `"not-applicable"` |
1042
+ | <a id="rules-1"></a> `rules` | `readonly` | [`RulesDisposition`](#rulesdisposition-2) |
1043
+ | <a id="service-1"></a> `service` | `readonly` | [`EventService`](#eventservice) |
1044
+
1045
+ ***
1046
+
1047
+ <a id="persistableservice"></a>
1048
+
1049
+ ### PersistableService
1050
+
1051
+ Contract for a service that can contribute its state to the sandbox
1052
+ persistence layer. Services (auth, storage, database) register
1053
+ themselves via [Sandbox.registerPersistableService](#registerpersistableservice-4) so the
1054
+ sandbox core stays service-agnostic — the sandbox doesn't know what
1055
+ auth or storage look like; it just calls `snapshot()` / `restore()`.
1056
+
1057
+ `subscribe` is optional but strongly recommended: without it, a
1058
+ service's changes (e.g. new users created via auth) only reach the
1059
+ persisted blob on the next Firestore write. With `subscribe`, the
1060
+ controller debounces a flush on every user-DB change — same latency
1061
+ as Firestore writes.
1062
+
1063
+ #### Properties
1064
+
1065
+ | Property | Type | Description |
1066
+ | :------ | :------ | :------ |
1067
+ | <a id="session"></a> `session?` | \{ `currentUid`: `string`; `mode`: `"LOCAL"` \| `"SESSION"` \| `"NONE"`; `restore`: `void`; `subscribe`: () => `void`; \} | Optional: session-level persistence hooks. When provided, the persistence controller uses these to save and restore the CURRENTLY SIGNED-IN user (not the user database — that's `snapshot`/`restore`). The controller calls `session.subscribe` so it hears every sign-in / sign-out, then writes the uid to the appropriate web-storage slot (determined by `session.mode()`). On init, the controller reads the stored uid and its storage-derived mode, then calls `session.restore(uid, mode)` to re-establish both before firing `onAuthStateChanged` as if the user just signed in. Only active when `SandboxPersistenceOptions.sessionStorage` is provided; omitting `sessionStorage` causes the controller to skip session persistence entirely (no fake durability). Auth is the only service that provides session hooks today. The field is on the generic interface so the controller stays service-agnostic — if a second service ever needs session-style semantics it can add its own hooks without changing the controller. |
1068
+ | `session.currentUid` | `string` | - |
1069
+ | `session.mode` | `"LOCAL"` \| `"SESSION"` \| `"NONE"` | - |
1070
+ | `session.restore` | `void` | - |
1071
+ | `session.subscribe` | () => `void` | - |
1072
+ | <a id="subscribe"></a> `subscribe?` | (`onChange`: () => `void`) => () => `void` | Optional: subscribe to changes in this service's state. When provided, the persistence controller hooks it up and schedules a debounced flush on each change — ensuring auth-user edits reach the backend promptly, not only on the next Firestore write. Must return an unsubscribe function. The controller unsubscribes on `dispose()`. |
1073
+
1074
+ #### Methods
1075
+
1076
+ <a id="restore"></a>
1077
+
1078
+ ##### restore()
1079
+
1080
+ ```ts
1081
+ restore(data: unknown): void;
1082
+ ```
1083
+
1084
+ Restore previously snapshotted state. Called once during
1085
+ `enablePersistence`, AFTER Firestore docs have been restored (so
1086
+ any service that needs Firestore to be hydrated first can rely on
1087
+ that ordering). Guard against bad data — the blob came from disk
1088
+ and may be stale or from a schema migration.
1089
+
1090
+ ###### Parameters
1091
+
1092
+ | Parameter | Type |
1093
+ | :------ | :------ |
1094
+ | `data` | `unknown` |
1095
+
1096
+ ###### Returns
1097
+
1098
+ `void`
1099
+
1100
+ <a id="snapshot-2"></a>
1101
+
1102
+ ##### snapshot()
1103
+
1104
+ ```ts
1105
+ snapshot(): unknown;
1106
+ ```
1107
+
1108
+ Return a plain-JSON-serializable snapshot of this service's state.
1109
+ Called by the persistence controller on every flush. The return
1110
+ value is stored under the service's registered name in the
1111
+ `services` map of the persisted blob.
1112
+
1113
+ ###### Returns
1114
+
1115
+ `unknown`
1116
+
1117
+ ***
1118
+
1119
+ <a id="persistencebackend"></a>
1120
+
1121
+ ### PersistenceBackend
1122
+
1123
+ Backend contract: read/write/list/delete RECORDS under a key. The controller
1124
+ partitions a snapshot into structured-clone bucket records (chunk-format.ts) so
1125
+ the backend stores many small records natively, never one keyspace-sized blob.
1126
+ Record values are structured-clone-safe objects; the backend never interprets
1127
+ them. (v2 and earlier used a single string blob; v3 is record-shaped.)
1128
+
1129
+ #### Methods
1130
+
1131
+ <a id="clear"></a>
1132
+
1133
+ ##### clear()
1134
+
1135
+ ```ts
1136
+ clear(key: string): Promise<void>;
1137
+ ```
1138
+
1139
+ Remove ALL records under `key`. No-op if none exist.
1140
+
1141
+ ###### Parameters
1142
+
1143
+ | Parameter | Type |
1144
+ | :------ | :------ |
1145
+ | `key` | `string` |
1146
+
1147
+ ###### Returns
1148
+
1149
+ `Promise`\<`void`\>
1150
+
1151
+ <a id="deleterecords"></a>
1152
+
1153
+ ##### deleteRecords()
1154
+
1155
+ ```ts
1156
+ deleteRecords(key: string, recordIds: readonly string[]): Promise<void>;
1157
+ ```
1158
+
1159
+ Delete the given record ids under `key`. No-op for ids that don't exist.
1160
+
1161
+ ###### Parameters
1162
+
1163
+ | Parameter | Type |
1164
+ | :------ | :------ |
1165
+ | `key` | `string` |
1166
+ | `recordIds` | readonly `string`[] |
1167
+
1168
+ ###### Returns
1169
+
1170
+ `Promise`\<`void`\>
1171
+
1172
+ <a id="estimate"></a>
1173
+
1174
+ ##### estimate()?
1175
+
1176
+ ```ts
1177
+ optional estimate(): Promise<{
1178
+ quota: number;
1179
+ usage: number;
1180
+ }>;
1181
+ ```
1182
+
1183
+ Best-effort storage usage estimate (bytes used + the quota ceiling), or
1184
+ `null` when the backend can't report it. Surfaced by the metadata API so a
1185
+ host can show how close the sandbox is to its storage limit. Optional: a
1186
+ backend that can't estimate simply omits it.
1187
+
1188
+ ###### Returns
1189
+
1190
+ `Promise`\<\{
1191
+ `quota`: `number`;
1192
+ `usage`: `number`;
1193
+ \}\>
1194
+
1195
+ <a id="getrecord"></a>
1196
+
1197
+ ##### getRecord()
1198
+
1199
+ ```ts
1200
+ getRecord(key: string, recordId: string): Promise<unknown>;
1201
+ ```
1202
+
1203
+ Read one record by id under `key`. Resolves `null` when absent.
1204
+
1205
+ ###### Parameters
1206
+
1207
+ | Parameter | Type |
1208
+ | :------ | :------ |
1209
+ | `key` | `string` |
1210
+ | `recordId` | `string` |
1211
+
1212
+ ###### Returns
1213
+
1214
+ `Promise`\<`unknown`\>
1215
+
1216
+ <a id="listrecords"></a>
1217
+
1218
+ ##### listRecords()
1219
+
1220
+ ```ts
1221
+ listRecords(key: string): Promise<string[]>;
1222
+ ```
1223
+
1224
+ List all record ids under `key`, any order.
1225
+
1226
+ ###### Parameters
1227
+
1228
+ | Parameter | Type |
1229
+ | :------ | :------ |
1230
+ | `key` | `string` |
1231
+
1232
+ ###### Returns
1233
+
1234
+ `Promise`\<`string`[]\>
1235
+
1236
+ <a id="putrecords"></a>
1237
+
1238
+ ##### putRecords()
1239
+
1240
+ ```ts
1241
+ putRecords(key: string, records: ReadonlyMap<string, unknown>): Promise<void>;
1242
+ ```
1243
+
1244
+ Write each `[recordId, value]` under `key`, replacing any prior value.
1245
+
1246
+ ###### Parameters
1247
+
1248
+ | Parameter | Type |
1249
+ | :------ | :------ |
1250
+ | `key` | `string` |
1251
+ | `records` | `ReadonlyMap`\<`string`, `unknown`\> |
1252
+
1253
+ ###### Returns
1254
+
1255
+ `Promise`\<`void`\>
1256
+
1257
+ ***
1258
+
1259
+ <a id="persistencecontroller"></a>
1260
+
1261
+ ### PersistenceController
1262
+
1263
+ #### Properties
1264
+
1265
+ | Property | Modifier | Type |
1266
+ | :------ | :------ | :------ |
1267
+ | <a id="options"></a> `options` | `readonly` | `Readonly`\<[`SandboxPersistenceOptions`](#sandboxpersistenceoptions)\> |
1268
+
1269
+ #### Methods
1270
+
1271
+ <a id="clear-2"></a>
1272
+
1273
+ ##### clear()
1274
+
1275
+ ```ts
1276
+ clear(): Promise<void>;
1277
+ ```
1278
+
1279
+ Wipe persisted state. In-memory state is untouched.
1280
+
1281
+ ###### Returns
1282
+
1283
+ `Promise`\<`void`\>
1284
+
1285
+ <a id="dispose-2"></a>
1286
+
1287
+ ##### dispose()
1288
+
1289
+ ```ts
1290
+ dispose(): void;
1291
+ ```
1292
+
1293
+ Detach event subscription + beforeunload listener.
1294
+
1295
+ ###### Returns
1296
+
1297
+ `void`
1298
+
1299
+ <a id="flush-2"></a>
1300
+
1301
+ ##### flush()
1302
+
1303
+ ```ts
1304
+ flush(): Promise<void>;
1305
+ ```
1306
+
1307
+ Force a flush of the current sandbox state to the backend.
1308
+
1309
+ ###### Returns
1310
+
1311
+ `Promise`\<`void`\>
1312
+
1313
+ ***
1314
+
1315
+ <a id="remotesandbox"></a>
1316
+
1317
+ ### RemoteSandbox
1318
+
1319
+ A branded remote sandbox handle. Structurally a [Sandbox](#sandbox-3) — it can
1320
+ be passed anywhere a `Sandbox` is accepted (notably
1321
+ `pyric-admin/app`'s `initializeApp({ sandbox })`) — but sync-only members
1322
+ that cannot be mirrored over the wire (`admin`, `snapshot()`,
1323
+ `history()`, …) throw a remediating error. Consumers with a remote arm
1324
+ dispatch on [isRemoteSandbox](#isremotesandbox) and use [channel](#channel) instead.
1325
+
1326
+ #### Extends
1327
+
1328
+ - [`Sandbox`](#sandbox-3)
1329
+
1330
+ #### Properties
1331
+
1332
+ | Property | Modifier | Type | Description |
1333
+ | :------ | :------ | :------ | :------ |
1334
+ | <a id="remote_sandbox"></a> `[REMOTE_SANDBOX]` | `readonly` | `true` | - |
1335
+ | <a id="admin-1"></a> `admin` | `readonly` | `SandboxAdmin` | Admin-plane access (rule-bypass reads). Identity-agnostic by design — admin reads aren't gated on auth, so they live on the sandbox, not on a context. See SandboxAdmin. |
1336
+ | <a id="channel"></a> `channel` | `readonly` | [`RemoteSandboxChannel`](#remotesandboxchannel-1) | The raw worker op/sub relay channel. |
1337
+ | <a id="currentuser-1"></a> `currentUser` | `public` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | Current authenticated user across the sandbox. Mutated by `pyric/auth`'s `signInAnonymously` / `signInWithEmailAndPassword` / `signOut` / `sandbox.setUser`. Read per-call by service factories (e.g. a future `getFirestore(sandbox)` overload) so they see auth state changes without re-binding handles. Defaults to `null` (anonymous / signed out). **Independent of `withAuth({uid})`** — `withAuth` still produces a frozen [SandboxContext](#sandboxcontext) that carries its own identity for the runner's test code (the existing pattern: explicit identity per service call). `currentUser` exists for the `pyric/auth` mirror, where consumer app code drives identity through a stateful `Auth` handle rather than naming it per call. |
1338
+ | `currentUser.token?` | `public` | `Record`\<`string`, `unknown`\> | - |
1339
+ | `currentUser.uid` | `public` | `string` | - |
1340
+ | <a id="serveurl"></a> `serveUrl` | `readonly` | `string` | Base URL of the `pyric dev` this handle is attached to (used in error guidance: "open <serveUrl> in a browser and retry"). |
1341
+
1342
+ #### Methods
1343
+
1344
+ <a id="clearpersistence-2"></a>
1345
+
1346
+ ##### clearPersistence()
1347
+
1348
+ ```ts
1349
+ clearPersistence(): Promise<void>;
1350
+ ```
1351
+
1352
+ Wipe the persisted blob for this sandbox's `key`. In-memory state
1353
+ is left intact — call `reset()` if you want both. Useful for
1354
+ "sign out and forget" flows.
1355
+
1356
+ No-op when persistence is not enabled.
1357
+
1358
+ ###### Returns
1359
+
1360
+ `Promise`\<`void`\>
1361
+
1362
+ ###### Inherited from
1363
+
1364
+ [`Sandbox`](#sandbox-3).[`clearPersistence`](#clearpersistence-4)
1365
+
1366
+ <a id="dispose-4"></a>
1367
+
1368
+ ##### dispose()
1369
+
1370
+ ```ts
1371
+ dispose(): void;
1372
+ ```
1373
+
1374
+ Tear down listener registries on this sandbox's environment without
1375
+ replacing it. Use this when you're about to discard the sandbox
1376
+ itself (e.g. `runner.reseed()` builds a fresh sandbox rather than
1377
+ calling `reset()`) and want to drop callback references on the
1378
+ outgoing instance defensively. Idempotent. Does not touch data.
1379
+
1380
+ ###### Returns
1381
+
1382
+ `void`
1383
+
1384
+ ###### Inherited from
1385
+
1386
+ [`Sandbox`](#sandbox-3).[`dispose`](#dispose-6)
1387
+
1388
+ <a id="enablepersistence-2"></a>
1389
+
1390
+ ##### enablePersistence()
1391
+
1392
+ ```ts
1393
+ enablePersistence(options: SandboxPersistenceOptions): Promise<void>;
1394
+ ```
1395
+
1396
+ Persist the sandbox's data to a backend and restore it on next
1397
+ `enablePersistence` call. The default `'indexedDB'` backend turns
1398
+ the sandbox into the host page's local Firestore — writes flush
1399
+ automatically and a fresh `initializeSandbox()` rehydrates from
1400
+ the prior session.
1401
+
1402
+ Restoration happens before the promise resolves; awaiting this
1403
+ call is sufficient to guarantee in-memory state matches the
1404
+ persisted blob.
1405
+
1406
+ Idempotent across the same `key` — calling twice in one process
1407
+ is a no-op on the second call. Different keys are rejected as an
1408
+ error (a sandbox can persist to at most one backend at a time).
1409
+
1410
+ Listener semantics: every write event the sandbox emits triggers
1411
+ a debounced flush (default 250ms). Browser hosts additionally
1412
+ flush on `beforeunload` so a page navigation doesn't lose the
1413
+ tail of the debounce window.
1414
+
1415
+ See [SandboxPersistenceOptions](#sandboxpersistenceoptions) for backend selection and
1416
+ tuning.
1417
+
1418
+ ###### Parameters
1419
+
1420
+ | Parameter | Type |
1421
+ | :------ | :------ |
1422
+ | `options` | [`SandboxPersistenceOptions`](#sandboxpersistenceoptions) |
1423
+
1424
+ ###### Returns
1425
+
1426
+ `Promise`\<`void`\>
1427
+
1428
+ ###### Inherited from
1429
+
1430
+ [`Sandbox`](#sandbox-3).[`enablePersistence`](#enablepersistence-4)
1431
+
1432
+ <a id="enabletabsync-2"></a>
1433
+
1434
+ ##### enableTabSync()
1435
+
1436
+ ```ts
1437
+ enableTabSync(options?: TabSyncOptions): () => void;
1438
+ ```
1439
+
1440
+ Enable cross-tab realtime sync via `BroadcastChannel`. A write in
1441
+ this tab will propagate to every OTHER tab of the same origin that
1442
+ also called `enableTabSync`, causing their `onSnapshot` listeners to
1443
+ re-evaluate — restoring production's cross-client realtime behavior.
1444
+
1445
+ **Opt-in, OFF by default.** Firestore only (RTDB is a follow-on).
1446
+
1447
+ Returns a disable function. Calling it removes the `onEvent`
1448
+ subscription, the channel message listener, and closes the channel
1449
+ (when it was created internally). After disable, no further propagation
1450
+ occurs in either direction.
1451
+
1452
+ **Multi-writer note:** concurrent writes from two tabs to the same doc
1453
+ produce last-write-wins divergence — there is no conflict resolution.
1454
+ The intended model is one active writer (one user, one tab) with
1455
+ observers in other tabs; this covers the overwhelming majority of
1456
+ local development scenarios.
1457
+
1458
+ ###### Parameters
1459
+
1460
+ | Parameter | Type |
1461
+ | :------ | :------ |
1462
+ | `options?` | [`TabSyncOptions`](#tabsyncoptions) |
1463
+
1464
+ ###### Returns
1465
+
1466
+ ```ts
1467
+ (): void;
1468
+ ```
1469
+
1470
+ ###### Returns
1471
+
1472
+ `void`
1473
+
1474
+ ###### See
1475
+
1476
+ [TabSyncOptions](#tabsyncoptions) for channel injection (tests) and originId.
1477
+
1478
+ ###### Example
1479
+
1480
+ ```ts
1481
+ // In every tab that should participate in realtime:
1482
+ const sandbox = initializeSandbox();
1483
+ const disableSync = sandbox.enableTabSync();
1484
+ // Later, to stop syncing:
1485
+ disableSync();
1486
+ ```
1487
+
1488
+ ###### Inherited from
1489
+
1490
+ [`Sandbox`](#sandbox-3).[`enableTabSync`](#enabletabsync-4)
1491
+
1492
+ <a id="flush-4"></a>
1493
+
1494
+ ##### flush()
1495
+
1496
+ ```ts
1497
+ flush(): Promise<void>;
1498
+ ```
1499
+
1500
+ Force a snapshot to the configured persistence backend right now.
1501
+ Useful before a manual navigation, or in tests that need
1502
+ deterministic ordering against the debounce window. Resolves once
1503
+ the write hits the backend.
1504
+
1505
+ Throws if persistence is not enabled.
1506
+
1507
+ ###### Returns
1508
+
1509
+ `Promise`\<`void`\>
1510
+
1511
+ ###### Inherited from
1512
+
1513
+ [`Sandbox`](#sandbox-3).[`flush`](#flush-6)
1514
+
1515
+ <a id="history-2"></a>
1516
+
1517
+ ##### history()
1518
+
1519
+ ```ts
1520
+ history(): SandboxEvent[];
1521
+ ```
1522
+
1523
+ Every [SandboxEvent](#sandboxevent) this sandbox has emitted since init or
1524
+ the last `reset()`. Returns a defensive copy.
1525
+
1526
+ Use this for replay: hand the array to `replay(events, rules)`
1527
+ from `pyric/sandbox` and the engine re-issues every
1528
+ captured write against a fresh sandbox.
1529
+
1530
+ Unlike [onEvent](#onevent-4) (live stream from the moment of subscribe),
1531
+ `history()` returns *every* event the sandbox has seen — useful
1532
+ for consumers that attach late (e.g., loading a saved session
1533
+ before subscribing) or that need a snapshot at a particular moment.
1534
+
1535
+ `reset()` and `dispose()` each append a closing `session_boundary`
1536
+ event; `reset()` then clears the history. Consumers that took a
1537
+ snapshot *before* reset retain the boundary in their copy.
1538
+
1539
+ ###### Returns
1540
+
1541
+ [`SandboxEvent`](#sandboxevent)[]
1542
+
1543
+ ###### Inherited from
1544
+
1545
+ [`Sandbox`](#sandbox-3).[`history`](#history-4)
1546
+
1547
+ <a id="loadsnapshot-2"></a>
1548
+
1549
+ ##### loadSnapshot()
1550
+
1551
+ ```ts
1552
+ loadSnapshot(data: SandboxSnapshot): void;
1553
+ ```
1554
+
1555
+ CLOBBER-restore the sandbox's entire state from a prior [snapshot](#snapshot-6):
1556
+ `reset()` (clears firestore + the signed-in session), then rebuild firestore
1557
+ from `data` and restore each registered service. This is a TOTAL replace —
1558
+ documents absent from `data` do NOT survive — and is the counterpart to
1559
+ [snapshot](#snapshot-6). It is what makes "transfer (clobber) one instance's data
1560
+ into another" and named-branch switching possible.
1561
+
1562
+ Fires a `session_boundary` (reset phase), re-evaluates live listeners against
1563
+ the loaded state, and the next persistence flush writes the loaded state.
1564
+ Services present in `data` but not currently registered are skipped (a
1565
+ snapshot taken via [snapshot](#snapshot-6) always includes every registered
1566
+ service, so this only affects cross-instance imports from a sandbox that had
1567
+ a service this one lacks).
1568
+
1569
+ ###### Parameters
1570
+
1571
+ | Parameter | Type |
1572
+ | :------ | :------ |
1573
+ | `data` | [`SandboxSnapshot`](#sandboxsnapshot-2) |
1574
+
1575
+ ###### Returns
1576
+
1577
+ `void`
1578
+
1579
+ ###### Inherited from
1580
+
1581
+ [`Sandbox`](#sandbox-3).[`loadSnapshot`](#loadsnapshot-4)
1582
+
1583
+ <a id="oncurrentuserchanged-2"></a>
1584
+
1585
+ ##### onCurrentUserChanged()
1586
+
1587
+ ```ts
1588
+ onCurrentUserChanged(cb: (user: {
1589
+ token?: Record<string, unknown>;
1590
+ uid: string;
1591
+ }) => void): () => void;
1592
+ ```
1593
+
1594
+ Subscribe to `currentUser` changes. Fires on every mutation —
1595
+ sign-in, sign-out, user swap. Does NOT fire on subscribe.
1596
+
1597
+ Survives `reset()` and `dispose()` only as a no-op: a disposed
1598
+ sandbox emits nothing further; a reset sandbox clears
1599
+ `currentUser` to `null` (and fires the change) before swapping
1600
+ the env.
1601
+
1602
+ Returns an unsubscribe function. Listener errors are swallowed —
1603
+ subscribers are observational, the sandbox does not propagate
1604
+ their errors.
1605
+
1606
+ ###### Parameters
1607
+
1608
+ | Parameter | Type |
1609
+ | :------ | :------ |
1610
+ | `cb` | (`user`: \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \}) => `void` |
1611
+
1612
+ ###### Returns
1613
+
1614
+ ```ts
1615
+ (): void;
1616
+ ```
1617
+
1618
+ ###### Returns
1619
+
1620
+ `void`
1621
+
1622
+ ###### Inherited from
1623
+
1624
+ [`Sandbox`](#sandbox-3).[`onCurrentUserChanged`](#oncurrentuserchanged-4)
1625
+
1626
+ <a id="onevent-2"></a>
1627
+
1628
+ ##### onEvent()
1629
+
1630
+ ```ts
1631
+ onEvent(cb: (event: SandboxEvent) => void): () => void;
1632
+ ```
1633
+
1634
+ Subscribe to every event the sandbox emits — see [SandboxEvent](#sandboxevent)
1635
+ for the discriminated-union shape. One subscription covers
1636
+ request/denial/snapshot-error/listener-lifecycle/session-boundary;
1637
+ filter on `event.kind` to recover individual streams.
1638
+
1639
+ Replaces the prior three-channel surface (`onRequest` / `onDenial`
1640
+ / `onSnapshotError`) — see issue #307. Filter cookbook:
1641
+ - All denials: `event.kind === 'request' && event.result === 'deny'`
1642
+ - Stream errors: `event.kind === 'listener_errored'`
1643
+ - Per-op traffic: `event.kind === 'request'`
1644
+
1645
+ Survives `sandbox.reset()` — the subscription is held on the
1646
+ sandbox, not on the underlying environment. A `session_boundary`
1647
+ event with `phase: 'reset'` fires before the env swap so consumers
1648
+ can segment their stream.
1649
+
1650
+ Returns an unsubscribe function. Listener errors are swallowed so a
1651
+ faulty subscriber can't change rule semantics or hide other events.
1652
+ Both synchronous throws and rejected Promises from async callbacks
1653
+ are silently discarded — subscribers are **observational**, the
1654
+ sandbox doesn't await them and doesn't propagate their errors.
1655
+
1656
+ ###### Parameters
1657
+
1658
+ | Parameter | Type |
1659
+ | :------ | :------ |
1660
+ | `cb` | (`event`: [`SandboxEvent`](#sandboxevent)) => `void` |
1661
+
1662
+ ###### Returns
1663
+
1664
+ ```ts
1665
+ (): void;
1666
+ ```
1667
+
1668
+ ###### Returns
1669
+
1670
+ `void`
1671
+
1672
+ ###### Inherited from
1673
+
1674
+ [`Sandbox`](#sandbox-3).[`onEvent`](#onevent-4)
1675
+
1676
+ <a id="registerpersistableservice-2"></a>
1677
+
1678
+ ##### registerPersistableService()
1679
+
1680
+ ```ts
1681
+ registerPersistableService(name: string, hooks: PersistableService): () => void;
1682
+ ```
1683
+
1684
+ Register a service (auth, storage, …) as a persistence participant.
1685
+ The sandbox calls `hooks.snapshot()` on every flush and
1686
+ `hooks.restore(data)` on restore. If `hooks.subscribe` is provided,
1687
+ the persistence controller subscribes and schedules a debounced
1688
+ flush on each change — so auth-user edits flush promptly, not only
1689
+ on the next Firestore write.
1690
+
1691
+ Returns an unregister function — call it if the service is torn
1692
+ down before the sandbox is disposed (uncommon in practice; the
1693
+ sandbox's `dispose()` clears the registry anyway).
1694
+
1695
+ Throws `failed-precondition` when a service with the same `name` is
1696
+ already registered — the auth package registers `'auth'` once when
1697
+ `getAuth(sandbox)` first creates a backend, so accidental double-
1698
+ registration is a caller bug, not a no-op.
1699
+
1700
+ **Advanced / internal API.** Service packages (auth, storage) call
1701
+ this when they first attach to a sandbox. Consumer app code should
1702
+ not need to call this directly.
1703
+
1704
+ ###### Parameters
1705
+
1706
+ | Parameter | Type |
1707
+ | :------ | :------ |
1708
+ | `name` | `string` |
1709
+ | `hooks` | [`PersistableService`](#persistableservice) |
1710
+
1711
+ ###### Returns
1712
+
1713
+ ```ts
1714
+ (): void;
1715
+ ```
1716
+
1717
+ ###### Returns
1718
+
1719
+ `void`
1720
+
1721
+ ###### Inherited from
1722
+
1723
+ [`Sandbox`](#sandbox-3).[`registerPersistableService`](#registerpersistableservice-4)
1724
+
1725
+ <a id="reset-2"></a>
1726
+
1727
+ ##### reset()
1728
+
1729
+ ```ts
1730
+ reset(): void;
1731
+ ```
1732
+
1733
+ Reset the underlying environment to a fresh state — wipes data,
1734
+ rules, and any service-specific configuration.
1735
+
1736
+ Snapshot listeners attached to the OLD environment are dropped at
1737
+ the swap — they can't survive because their target docs have been
1738
+ wiped. `onEvent` subscribers DO survive — the registry lives on
1739
+ the sandbox, and a `session_boundary` event with `phase: 'reset'`
1740
+ fires before the swap so subscribers know the rollover happened.
1741
+ Existing [SandboxContext](#sandboxcontext)s continue to work — their sandbox
1742
+ reference is stable; subsequent operations resolve to the new env.
1743
+
1744
+ ###### Returns
1745
+
1746
+ `void`
1747
+
1748
+ ###### Inherited from
1749
+
1750
+ [`Sandbox`](#sandbox-3).[`reset`](#reset-4)
1751
+
1752
+ <a id="runwithprovenance-2"></a>
1753
+
1754
+ ##### runWithProvenance()?
1755
+
1756
+ ```ts
1757
+ optional runWithProvenance<T>(provenance: EventProvenance, fn: () => T): T;
1758
+ ```
1759
+
1760
+ Run `fn` with ambient [EventProvenance](#eventprovenance) defaults: every event
1761
+ emitted SYNCHRONOUSLY during `fn` that doesn't already carry a
1762
+ provenance field (on the event itself or via an explicit per-emit
1763
+ override) is stamped with these values instead of the global
1764
+ defaults. This is the mechanical "who issued this op" seam the
1765
+ serve worker uses to tag Studio-issued ops (`actor: { kind:
1766
+ 'studio' }`) and to stamp the auth lens an op ran under
1767
+ (`authLens`) — declared by the caller that issues the op, never
1768
+ inferred from the op's shape.
1769
+
1770
+ SYNCHRONOUS WINDOW: the ambient values apply only until `fn`
1771
+ returns (for an async `fn`, its synchronous prefix — which covers
1772
+ the local environment's rules eval + event emission, since those
1773
+ run before the op's promise is handed back). Work an op DEFERS
1774
+ (snapshot-listener deliveries and re-evals drain on a microtask,
1775
+ off-stack) is intentionally OUTSIDE the window: a listener re-eval
1776
+ belongs to the listener's owner, not to whoever's write triggered
1777
+ it. Nested calls stack — the innermost window wins per field, and
1778
+ each window restores the previous one on exit (including on throw).
1779
+
1780
+ OPTIONAL because remote sandbox proxies can't provide an ambient
1781
+ emit window (events are emitted in the worker they front). Callers
1782
+ spell `sandbox.runWithProvenance?.(prov, fn) ?? fn()`.
1783
+
1784
+ ###### Type Parameters
1785
+
1786
+ | Type Parameter |
1787
+ | :------ |
1788
+ | `T` |
1789
+
1790
+ ###### Parameters
1791
+
1792
+ | Parameter | Type |
1793
+ | :------ | :------ |
1794
+ | `provenance` | [`EventProvenance`](#eventprovenance) |
1795
+ | `fn` | () => `T` |
1796
+
1797
+ ###### Returns
1798
+
1799
+ `T`
1800
+
1801
+ ###### Inherited from
1802
+
1803
+ [`Sandbox`](#sandbox-3).[`runWithProvenance`](#runwithprovenance-4)
1804
+
1805
+ <a id="snapshot-4"></a>
1806
+
1807
+ ##### snapshot()
1808
+
1809
+ ```ts
1810
+ snapshot(): SandboxSnapshot;
1811
+ ```
1812
+
1813
+ Capture a snapshot of every service's state. For v1 with only
1814
+ Firestore, the return value carries a `firestore` key mapping doc
1815
+ paths to data. Future services will add their own keys.
1816
+
1817
+ ###### Returns
1818
+
1819
+ [`SandboxSnapshot`](#sandboxsnapshot-2)
1820
+
1821
+ ###### Inherited from
1822
+
1823
+ [`Sandbox`](#sandbox-3).[`snapshot`](#snapshot-6)
1824
+
1825
+ <a id="withauth-4"></a>
1826
+
1827
+ ##### withAuth()
1828
+
1829
+ ```ts
1830
+ withAuth(auth: {
1831
+ token?: Record<string, unknown>;
1832
+ uid: string;
1833
+ }): SandboxContext;
1834
+ ```
1835
+
1836
+ Derive a context bound to this sandbox under the given auth
1837
+ identity. Operations through services attached to the returned
1838
+ context evaluate rules under that identity. Many contexts can
1839
+ coexist for one sandbox; data is shared.
1840
+
1841
+ `null` is anonymous; an `AuthState` object names the user (and
1842
+ optional custom claims). Passing `undefined` is a deliberate
1843
+ error — say `withAuth(null)` for anonymous so the call site is
1844
+ unambiguous.
1845
+
1846
+ ###### Parameters
1847
+
1848
+ | Parameter | Type |
1849
+ | :------ | :------ |
1850
+ | `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
1851
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
1852
+ | `auth.uid` | `string` |
1853
+
1854
+ ###### Returns
1855
+
1856
+ [`SandboxContext`](#sandboxcontext)
1857
+
1858
+ ###### Example
1859
+
1860
+ ```ts
1861
+ const sandbox = initializeSandbox();
1862
+ const dbAlice = getFirestore(sandbox.withAuth({ uid: 'alice' }));
1863
+ const dbAnon = getFirestore(sandbox.withAuth(null));
1864
+ ```
1865
+
1866
+ ###### Inherited from
1867
+
1868
+ [`Sandbox`](#sandbox-3).[`withAuth`](#withauth-6)
1869
+
1870
+ ***
1871
+
1872
+ <a id="remotesandboxchannel-1"></a>
1873
+
1874
+ ### RemoteSandboxChannel
1875
+
1876
+ The minimal worker-relay channel a remote sandbox handle carries.
1877
+
1878
+ Structural mirror of `@pyric/cli/remote`'s `RemoteSandboxChannel`: one
1879
+ method to dispatch any SharedWorker-protocol op, one to register a
1880
+ snap-delivering subscription. Payloads are typed openly here (the real
1881
+ discriminated unions live in `@pyric/cli`' worker protocol); callers in
1882
+ `pyric-admin` spell the concrete op objects (`rtdb.set`, `auth.listUsers`,
1883
+ …) and pin their own `actAs` lens — nothing is pinned by the channel.
1884
+
1885
+ #### Methods
1886
+
1887
+ <a id="op"></a>
1888
+
1889
+ ##### op()
1890
+
1891
+ ```ts
1892
+ op(op: {
1893
+ method: string;
1894
+ } & Record<string, unknown>): Promise<unknown>;
1895
+ ```
1896
+
1897
+ Dispatch one worker op. Resolves with the worker's result value;
1898
+ rejects with an `Error` carrying a `.code` (including the fail-fast
1899
+ "no browser tab is connected — open <serve url>" guidance when no
1900
+ peer is registered).
1901
+
1902
+ ###### Parameters
1903
+
1904
+ | Parameter | Type |
1905
+ | :------ | :------ |
1906
+ | `op` | \{ `method`: `string`; \} & `Record`\<`string`, `unknown`\> |
1907
+
1908
+ ###### Returns
1909
+
1910
+ `Promise`\<`unknown`\>
1911
+
1912
+ <a id="subscribe-1"></a>
1913
+
1914
+ ##### subscribe()
1915
+
1916
+ ```ts
1917
+ subscribe(
1918
+ sub: {
1919
+ target: unknown;
1920
+ } & Record<string, unknown>,
1921
+ onSnap: (value: unknown) => void,
1922
+ onError?: (err: Error & {
1923
+ code: string;
1924
+ }) => void): () => void;
1925
+ ```
1926
+
1927
+ Register a worker subscription (e.g. an RTDB value listener:
1928
+ `{ target: { service: 'rtdb', path } }`). `onSnap` receives every snap
1929
+ value (initial + updates — and re-delivered fresh after peer
1930
+ replacement); an establishment failure routes to `onError` instead.
1931
+ Returns the unsubscribe function.
1932
+
1933
+ ###### Parameters
1934
+
1935
+ | Parameter | Type |
1936
+ | :------ | :------ |
1937
+ | `sub` | \{ `target`: `unknown`; \} & `Record`\<`string`, `unknown`\> |
1938
+ | `onSnap` | (`value`: `unknown`) => `void` |
1939
+ | `onError?` | (`err`: `Error` & \{ `code`: `string`; \}) => `void` |
1940
+
1941
+ ###### Returns
1942
+
1943
+ ```ts
1944
+ (): void;
1945
+ ```
1946
+
1947
+ ###### Returns
1948
+
1949
+ `void`
1950
+
1951
+ ***
1952
+
1953
+ <a id="remotesandboxfactoryoptions"></a>
1954
+
1955
+ ### RemoteSandboxFactoryOptions
1956
+
1957
+ Options accepted by the ambient remote-sandbox factory.
1958
+
1959
+ #### Properties
1960
+
1961
+ | Property | Type | Description |
1962
+ | :------ | :------ | :------ |
1963
+ | <a id="url"></a> `url?` | `string` | Explicit `pyric dev` base URL (from `PYRIC_SANDBOX=remote:<url>`). When omitted the factory discovers the running host itself (the `.pyric/serve.json` locator protocol). |
1964
+
1965
+ ***
1966
+
1967
+ <a id="replayoptions"></a>
1968
+
1969
+ ### ReplayOptions
1970
+
1971
+ #### Properties
1972
+
1973
+ | Property | Type | Description |
1974
+ | :------ | :------ | :------ |
1975
+ | <a id="pinrequesttime"></a> `pinRequestTime?` | `boolean` | When true (default), re-issue the captured `requestTime` so `serverTimestamp()` sentinels resolve to the same value as capture and `request.time`-gated rules evaluate identically. |
1976
+
1977
+ ***
1978
+
1979
+ <a id="replayresult"></a>
1980
+
1981
+ ### ReplayResult
1982
+
1983
+ #### Properties
1984
+
1985
+ | Property | Type | Description |
1986
+ | :------ | :------ | :------ |
1987
+ | <a id="divergences"></a> `divergences` | [`Divergence`](#divergence)[] | Field- and path-level differences between original and replayed state, classified. |
1988
+ | <a id="pathaliases"></a> `pathAliases` | `Map`\<`string`, `string`\> | Maps captured auto-id paths → freshly-minted replay paths. The diff classifier uses this to skip `autoid-alias` paths when computing field-level differences. |
1989
+ | <a id="sandbox-2"></a> `sandbox` | [`LocalSandbox`](#localsandbox) | Fresh sandbox with the captured writes re-applied. |
1990
+
1991
+ ***
1992
+
1993
+ <a id="requestevent"></a>
1994
+
1995
+ ### RequestEvent
1996
+
1997
+ Eval-time payload emitted to Sandbox.onRequest subscribers —
1998
+ one per evaluated op, regardless of outcome.
1999
+
2000
+ Issue #307: the playground today only renders denials, but every op
2001
+ the simulator evaluates is a request worth seeing. This event is the
2002
+ source of truth; [DenialEvent](#denialevent) is a filtered projection over
2003
+ the `result === 'deny'` subset.
2004
+
2005
+ Origin tells the consumer who initiated the eval:
2006
+ - `user` single op via the data-plane adapter (admin / firestore).
2007
+ - `batch` part of a multi-op batch — shares `groupId` with siblings.
2008
+ - `transaction` part of a transaction commit — shares `groupId`.
2009
+ - `listener` a write or `deployRules` triggered a snapshot listener
2010
+ to re-evaluate. Carries `triggeredBy` naming the
2011
+ originating user op (when knowable).
2012
+
2013
+ `evalMs` measures the wall-clock duration of the simulator's
2014
+ `simulate(...)` call. Sub-millisecond is normal for simple rules;
2015
+ rule-engine-heavy rules (deep boolean chains, many get() calls) can
2016
+ reach tens of milliseconds; a traffic-monitor validation probe measured
2017
+ connect-four rules at ~95ms p99. Surface this in your UI when it matters.
2018
+
2019
+ Listener throws are swallowed by the dispatcher so a faulty
2020
+ subscriber can't change rule semantics or hide other events.
2021
+
2022
+ #### See
2023
+
2024
+ traffic-monitor-decision.md for the field-by-field rationale.
2025
+
2026
+ #### Properties
2027
+
2028
+ | Property | Type | Description |
2029
+ | :------ | :------ | :------ |
2030
+ | <a id="at-2"></a> `at` | `number` | Wall-clock at op start, ms since epoch. |
2031
+ | <a id="auth-5"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | - |
2032
+ | `auth.token?` | `Record`\<`string`, `unknown`\> | - |
2033
+ | `auth.uid` | `string` | - |
2034
+ | <a id="detail"></a> `detail?` | \{ `admin?`: `boolean`; \} & `Record`\<`string`, `unknown`\> | Free-form operation metadata. `admin: true` marks a rules-bypassing setup/admin operation so fixture tooling can exclude it from protected behavior while still preserving it as replay context. |
2035
+ | <a id="evalms"></a> `evalMs` | `number` | Wall-clock duration of the simulator.simulate(...) call, in ms. |
2036
+ | <a id="evaluatedrule"></a> `evaluatedRule?` | `EvaluatedRuleInfo` | The DECIDING rule's verdict + 1-indexed source line + full sub-expression trace, projected from the simulator's structured `RuleEvaluation` (additive: present on `result: 'allow' | 'deny'` Firestore events when the simulator produced a per-rule trace — the allowing rule on an allow, the denying rule on a deny). Studio's rules inspector reads this to mark the deciding line and render the evaluation step-through ("show the work"). Absent on an implicit deny (no rule evaluated), a simulator-error deny, and unsupported results. |
2037
+ | <a id="groupid"></a> `groupId?` | `string` | Shared across ops in one batch or transaction. Opaque to consumers. |
2038
+ | <a id="groupkind"></a> `groupKind?` | `"transaction"` \| `"batch"` | Disambiguates `origin: 'transaction' | 'batch'` cases when consumers need to tell them apart without inspecting `origin` directly. |
2039
+ | <a id="id-2"></a> `id` | `string` | Unique within a sandbox process. Useful for React list keys. |
2040
+ | <a id="kind-1"></a> `kind` | `"request"` | Discriminator. |
2041
+ | <a id="matchedrule"></a> `matchedRule?` | \{ `operations`: `string`[]; `ruleIndex`: `number`; \} | Parsed from the simulator's "Rule #N → …" debug line. Absent when no rule matched (e.g. no allow rules at the path — implicit deny). |
2042
+ | `matchedRule.operations` | `string`[] | - |
2043
+ | `matchedRule.ruleIndex` | `number` | - |
2044
+ | <a id="method-1"></a> `method` | `"get"` \| `"list"` \| `"create"` \| `"update"` \| `"delete"` \| `"set"` | - |
2045
+ | <a id="origin"></a> `origin` | `"user"` \| `"listener"` \| `"transaction"` \| `"batch"` | - |
2046
+ | <a id="path-1"></a> `path` | `string` | - |
2047
+ | <a id="reasons-2"></a> `reasons` | `string`[] | Simulator debug messages — the per-rule trace (`Rule #0 (read) → ALLOW`). Same shape as `DenialEvent.reasons` so consumer code can share rendering. |
2048
+ | <a id="request-2"></a> `request?` | \{ `resourceData?`: `Record`\<`string`, `unknown`\>; \} | Proposed write payload, for create/update/set. Absent on reads + delete. Pre-resolution: `FieldValue.*` sentinels are preserved as their marker shapes (`{ __type: 'serverTimestamp' }`, etc.) so the replay engine can re-resolve them. The rule engine evaluated against the resolved form internally; that resolved form lives on [WriteSandboxEvent.nextState](#nextstate-1), not here. |
2049
+ | `request.resourceData?` | `Record`\<`string`, `unknown`\> | - |
2050
+ | <a id="resourceafter"></a> `resourceAfter?` | \{ `data`: `Record`\<`string`, `unknown`\>; `exists`: `boolean`; \} | Projected document state after the write. Absent on reads. |
2051
+ | `resourceAfter.data` | `Record`\<`string`, `unknown`\> | - |
2052
+ | `resourceAfter.exists` | `boolean` | - |
2053
+ | <a id="resourcebefore"></a> `resourceBefore?` | \{ `data`: `Record`\<`string`, `unknown`\>; `exists`: `boolean`; \} | Existing document state before the write (or read target for get). |
2054
+ | `resourceBefore.data` | `Record`\<`string`, `unknown`\> | - |
2055
+ | `resourceBefore.exists` | `boolean` | - |
2056
+ | <a id="result-1"></a> `result` | `"allow"` \| `"deny"` \| `"unsupported"` | `'unsupported'` fires when the simulator hit an unmodelled feature and the sandbox upgraded it (today: thrown as SimulatorUnsupportedError, surfaced here as a discrete result so the panel can show it distinctly from a real denial). |
2057
+ | <a id="rulesdisposition"></a> `rulesDisposition?` | [`RulesDisposition`](#rulesdisposition-2) | Canonical statement of whether Security Rules evaluated this request. Added by the sandbox event recorder when an older emitter omits it. |
2058
+ | <a id="triggeredby"></a> `triggeredBy?` | \{ `method`: `string`; `path`: `string`; \} | For listener re-evals: the originating user op that triggered this re-evaluation. Absent on the initial-snapshot fire. |
2059
+ | `triggeredBy.method` | `string` | - |
2060
+ | `triggeredBy.path` | `string` | - |
2061
+
2062
+ ***
2063
+
2064
+ <a id="sandbox-3"></a>
2065
+
2066
+ ### Sandbox
2067
+
2068
+ A Firebase sandbox — an isolated environment with one auth identity.
2069
+
2070
+ Created via `initializeSandbox(config)`. Use `fork({ auth })` to
2071
+ derive a new sandbox with a different identity that shares the
2072
+ underlying environment (rules, data, state). Fork is the only
2073
+ identity-switching mechanism — there are no per-op auth overrides
2074
+ and no in-place mutation.
2075
+
2076
+ #### Extended by
2077
+
2078
+ - [`LocalSandbox`](#localsandbox)
2079
+ - [`RemoteSandbox`](#remotesandbox)
2080
+
2081
+ #### Properties
2082
+
2083
+ | Property | Modifier | Type | Description |
2084
+ | :------ | :------ | :------ | :------ |
2085
+ | <a id="admin-2"></a> `admin` | `readonly` | `SandboxAdmin` | Admin-plane access (rule-bypass reads). Identity-agnostic by design — admin reads aren't gated on auth, so they live on the sandbox, not on a context. See SandboxAdmin. |
2086
+ | <a id="currentuser-2"></a> `currentUser` | `public` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | Current authenticated user across the sandbox. Mutated by `pyric/auth`'s `signInAnonymously` / `signInWithEmailAndPassword` / `signOut` / `sandbox.setUser`. Read per-call by service factories (e.g. a future `getFirestore(sandbox)` overload) so they see auth state changes without re-binding handles. Defaults to `null` (anonymous / signed out). **Independent of `withAuth({uid})`** — `withAuth` still produces a frozen [SandboxContext](#sandboxcontext) that carries its own identity for the runner's test code (the existing pattern: explicit identity per service call). `currentUser` exists for the `pyric/auth` mirror, where consumer app code drives identity through a stateful `Auth` handle rather than naming it per call. |
2087
+ | `currentUser.token?` | `public` | `Record`\<`string`, `unknown`\> | - |
2088
+ | `currentUser.uid` | `public` | `string` | - |
2089
+
2090
+ #### Methods
2091
+
2092
+ <a id="clearpersistence-4"></a>
2093
+
2094
+ ##### clearPersistence()
2095
+
2096
+ ```ts
2097
+ clearPersistence(): Promise<void>;
2098
+ ```
2099
+
2100
+ Wipe the persisted blob for this sandbox's `key`. In-memory state
2101
+ is left intact — call `reset()` if you want both. Useful for
2102
+ "sign out and forget" flows.
2103
+
2104
+ No-op when persistence is not enabled.
2105
+
2106
+ ###### Returns
2107
+
2108
+ `Promise`\<`void`\>
2109
+
2110
+ <a id="dispose-6"></a>
2111
+
2112
+ ##### dispose()
2113
+
2114
+ ```ts
2115
+ dispose(): void;
2116
+ ```
2117
+
2118
+ Tear down listener registries on this sandbox's environment without
2119
+ replacing it. Use this when you're about to discard the sandbox
2120
+ itself (e.g. `runner.reseed()` builds a fresh sandbox rather than
2121
+ calling `reset()`) and want to drop callback references on the
2122
+ outgoing instance defensively. Idempotent. Does not touch data.
2123
+
2124
+ ###### Returns
2125
+
2126
+ `void`
2127
+
2128
+ <a id="enablepersistence-4"></a>
2129
+
2130
+ ##### enablePersistence()
2131
+
2132
+ ```ts
2133
+ enablePersistence(options: SandboxPersistenceOptions): Promise<void>;
2134
+ ```
2135
+
2136
+ Persist the sandbox's data to a backend and restore it on next
2137
+ `enablePersistence` call. The default `'indexedDB'` backend turns
2138
+ the sandbox into the host page's local Firestore — writes flush
2139
+ automatically and a fresh `initializeSandbox()` rehydrates from
2140
+ the prior session.
2141
+
2142
+ Restoration happens before the promise resolves; awaiting this
2143
+ call is sufficient to guarantee in-memory state matches the
2144
+ persisted blob.
2145
+
2146
+ Idempotent across the same `key` — calling twice in one process
2147
+ is a no-op on the second call. Different keys are rejected as an
2148
+ error (a sandbox can persist to at most one backend at a time).
2149
+
2150
+ Listener semantics: every write event the sandbox emits triggers
2151
+ a debounced flush (default 250ms). Browser hosts additionally
2152
+ flush on `beforeunload` so a page navigation doesn't lose the
2153
+ tail of the debounce window.
2154
+
2155
+ See [SandboxPersistenceOptions](#sandboxpersistenceoptions) for backend selection and
2156
+ tuning.
2157
+
2158
+ ###### Parameters
2159
+
2160
+ | Parameter | Type |
2161
+ | :------ | :------ |
2162
+ | `options` | [`SandboxPersistenceOptions`](#sandboxpersistenceoptions) |
2163
+
2164
+ ###### Returns
2165
+
2166
+ `Promise`\<`void`\>
2167
+
2168
+ <a id="enabletabsync-4"></a>
2169
+
2170
+ ##### enableTabSync()
2171
+
2172
+ ```ts
2173
+ enableTabSync(options?: TabSyncOptions): () => void;
2174
+ ```
2175
+
2176
+ Enable cross-tab realtime sync via `BroadcastChannel`. A write in
2177
+ this tab will propagate to every OTHER tab of the same origin that
2178
+ also called `enableTabSync`, causing their `onSnapshot` listeners to
2179
+ re-evaluate — restoring production's cross-client realtime behavior.
2180
+
2181
+ **Opt-in, OFF by default.** Firestore only (RTDB is a follow-on).
2182
+
2183
+ Returns a disable function. Calling it removes the `onEvent`
2184
+ subscription, the channel message listener, and closes the channel
2185
+ (when it was created internally). After disable, no further propagation
2186
+ occurs in either direction.
2187
+
2188
+ **Multi-writer note:** concurrent writes from two tabs to the same doc
2189
+ produce last-write-wins divergence — there is no conflict resolution.
2190
+ The intended model is one active writer (one user, one tab) with
2191
+ observers in other tabs; this covers the overwhelming majority of
2192
+ local development scenarios.
2193
+
2194
+ ###### Parameters
2195
+
2196
+ | Parameter | Type |
2197
+ | :------ | :------ |
2198
+ | `options?` | [`TabSyncOptions`](#tabsyncoptions) |
2199
+
2200
+ ###### Returns
2201
+
2202
+ ```ts
2203
+ (): void;
2204
+ ```
2205
+
2206
+ ###### Returns
2207
+
2208
+ `void`
2209
+
2210
+ ###### See
2211
+
2212
+ [TabSyncOptions](#tabsyncoptions) for channel injection (tests) and originId.
2213
+
2214
+ ###### Example
2215
+
2216
+ ```ts
2217
+ // In every tab that should participate in realtime:
2218
+ const sandbox = initializeSandbox();
2219
+ const disableSync = sandbox.enableTabSync();
2220
+ // Later, to stop syncing:
2221
+ disableSync();
2222
+ ```
2223
+
2224
+ <a id="flush-6"></a>
2225
+
2226
+ ##### flush()
2227
+
2228
+ ```ts
2229
+ flush(): Promise<void>;
2230
+ ```
2231
+
2232
+ Force a snapshot to the configured persistence backend right now.
2233
+ Useful before a manual navigation, or in tests that need
2234
+ deterministic ordering against the debounce window. Resolves once
2235
+ the write hits the backend.
2236
+
2237
+ Throws if persistence is not enabled.
2238
+
2239
+ ###### Returns
2240
+
2241
+ `Promise`\<`void`\>
2242
+
2243
+ <a id="history-4"></a>
2244
+
2245
+ ##### history()
2246
+
2247
+ ```ts
2248
+ history(): SandboxEvent[];
2249
+ ```
2250
+
2251
+ Every [SandboxEvent](#sandboxevent) this sandbox has emitted since init or
2252
+ the last `reset()`. Returns a defensive copy.
2253
+
2254
+ Use this for replay: hand the array to `replay(events, rules)`
2255
+ from `pyric/sandbox` and the engine re-issues every
2256
+ captured write against a fresh sandbox.
2257
+
2258
+ Unlike [onEvent](#onevent-4) (live stream from the moment of subscribe),
2259
+ `history()` returns *every* event the sandbox has seen — useful
2260
+ for consumers that attach late (e.g., loading a saved session
2261
+ before subscribing) or that need a snapshot at a particular moment.
2262
+
2263
+ `reset()` and `dispose()` each append a closing `session_boundary`
2264
+ event; `reset()` then clears the history. Consumers that took a
2265
+ snapshot *before* reset retain the boundary in their copy.
2266
+
2267
+ ###### Returns
2268
+
2269
+ [`SandboxEvent`](#sandboxevent)[]
2270
+
2271
+ <a id="loadsnapshot-4"></a>
2272
+
2273
+ ##### loadSnapshot()
2274
+
2275
+ ```ts
2276
+ loadSnapshot(data: SandboxSnapshot): void;
2277
+ ```
2278
+
2279
+ CLOBBER-restore the sandbox's entire state from a prior [snapshot](#snapshot-6):
2280
+ `reset()` (clears firestore + the signed-in session), then rebuild firestore
2281
+ from `data` and restore each registered service. This is a TOTAL replace —
2282
+ documents absent from `data` do NOT survive — and is the counterpart to
2283
+ [snapshot](#snapshot-6). It is what makes "transfer (clobber) one instance's data
2284
+ into another" and named-branch switching possible.
2285
+
2286
+ Fires a `session_boundary` (reset phase), re-evaluates live listeners against
2287
+ the loaded state, and the next persistence flush writes the loaded state.
2288
+ Services present in `data` but not currently registered are skipped (a
2289
+ snapshot taken via [snapshot](#snapshot-6) always includes every registered
2290
+ service, so this only affects cross-instance imports from a sandbox that had
2291
+ a service this one lacks).
2292
+
2293
+ ###### Parameters
2294
+
2295
+ | Parameter | Type |
2296
+ | :------ | :------ |
2297
+ | `data` | [`SandboxSnapshot`](#sandboxsnapshot-2) |
2298
+
2299
+ ###### Returns
2300
+
2301
+ `void`
2302
+
2303
+ <a id="oncurrentuserchanged-4"></a>
2304
+
2305
+ ##### onCurrentUserChanged()
2306
+
2307
+ ```ts
2308
+ onCurrentUserChanged(cb: (user: {
2309
+ token?: Record<string, unknown>;
2310
+ uid: string;
2311
+ }) => void): () => void;
2312
+ ```
2313
+
2314
+ Subscribe to `currentUser` changes. Fires on every mutation —
2315
+ sign-in, sign-out, user swap. Does NOT fire on subscribe.
2316
+
2317
+ Survives `reset()` and `dispose()` only as a no-op: a disposed
2318
+ sandbox emits nothing further; a reset sandbox clears
2319
+ `currentUser` to `null` (and fires the change) before swapping
2320
+ the env.
2321
+
2322
+ Returns an unsubscribe function. Listener errors are swallowed —
2323
+ subscribers are observational, the sandbox does not propagate
2324
+ their errors.
2325
+
2326
+ ###### Parameters
2327
+
2328
+ | Parameter | Type |
2329
+ | :------ | :------ |
2330
+ | `cb` | (`user`: \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \}) => `void` |
2331
+
2332
+ ###### Returns
2333
+
2334
+ ```ts
2335
+ (): void;
2336
+ ```
2337
+
2338
+ ###### Returns
2339
+
2340
+ `void`
2341
+
2342
+ <a id="onevent-4"></a>
2343
+
2344
+ ##### onEvent()
2345
+
2346
+ ```ts
2347
+ onEvent(cb: (event: SandboxEvent) => void): () => void;
2348
+ ```
2349
+
2350
+ Subscribe to every event the sandbox emits — see [SandboxEvent](#sandboxevent)
2351
+ for the discriminated-union shape. One subscription covers
2352
+ request/denial/snapshot-error/listener-lifecycle/session-boundary;
2353
+ filter on `event.kind` to recover individual streams.
2354
+
2355
+ Replaces the prior three-channel surface (`onRequest` / `onDenial`
2356
+ / `onSnapshotError`) — see issue #307. Filter cookbook:
2357
+ - All denials: `event.kind === 'request' && event.result === 'deny'`
2358
+ - Stream errors: `event.kind === 'listener_errored'`
2359
+ - Per-op traffic: `event.kind === 'request'`
2360
+
2361
+ Survives `sandbox.reset()` — the subscription is held on the
2362
+ sandbox, not on the underlying environment. A `session_boundary`
2363
+ event with `phase: 'reset'` fires before the env swap so consumers
2364
+ can segment their stream.
2365
+
2366
+ Returns an unsubscribe function. Listener errors are swallowed so a
2367
+ faulty subscriber can't change rule semantics or hide other events.
2368
+ Both synchronous throws and rejected Promises from async callbacks
2369
+ are silently discarded — subscribers are **observational**, the
2370
+ sandbox doesn't await them and doesn't propagate their errors.
2371
+
2372
+ ###### Parameters
2373
+
2374
+ | Parameter | Type |
2375
+ | :------ | :------ |
2376
+ | `cb` | (`event`: [`SandboxEvent`](#sandboxevent)) => `void` |
2377
+
2378
+ ###### Returns
2379
+
2380
+ ```ts
2381
+ (): void;
2382
+ ```
2383
+
2384
+ ###### Returns
2385
+
2386
+ `void`
2387
+
2388
+ <a id="registerpersistableservice-4"></a>
2389
+
2390
+ ##### registerPersistableService()
2391
+
2392
+ ```ts
2393
+ registerPersistableService(name: string, hooks: PersistableService): () => void;
2394
+ ```
2395
+
2396
+ Register a service (auth, storage, …) as a persistence participant.
2397
+ The sandbox calls `hooks.snapshot()` on every flush and
2398
+ `hooks.restore(data)` on restore. If `hooks.subscribe` is provided,
2399
+ the persistence controller subscribes and schedules a debounced
2400
+ flush on each change — so auth-user edits flush promptly, not only
2401
+ on the next Firestore write.
2402
+
2403
+ Returns an unregister function — call it if the service is torn
2404
+ down before the sandbox is disposed (uncommon in practice; the
2405
+ sandbox's `dispose()` clears the registry anyway).
2406
+
2407
+ Throws `failed-precondition` when a service with the same `name` is
2408
+ already registered — the auth package registers `'auth'` once when
2409
+ `getAuth(sandbox)` first creates a backend, so accidental double-
2410
+ registration is a caller bug, not a no-op.
2411
+
2412
+ **Advanced / internal API.** Service packages (auth, storage) call
2413
+ this when they first attach to a sandbox. Consumer app code should
2414
+ not need to call this directly.
2415
+
2416
+ ###### Parameters
2417
+
2418
+ | Parameter | Type |
2419
+ | :------ | :------ |
2420
+ | `name` | `string` |
2421
+ | `hooks` | [`PersistableService`](#persistableservice) |
2422
+
2423
+ ###### Returns
2424
+
2425
+ ```ts
2426
+ (): void;
2427
+ ```
2428
+
2429
+ ###### Returns
2430
+
2431
+ `void`
2432
+
2433
+ <a id="reset-4"></a>
2434
+
2435
+ ##### reset()
2436
+
2437
+ ```ts
2438
+ reset(): void;
2439
+ ```
2440
+
2441
+ Reset the underlying environment to a fresh state — wipes data,
2442
+ rules, and any service-specific configuration.
2443
+
2444
+ Snapshot listeners attached to the OLD environment are dropped at
2445
+ the swap — they can't survive because their target docs have been
2446
+ wiped. `onEvent` subscribers DO survive — the registry lives on
2447
+ the sandbox, and a `session_boundary` event with `phase: 'reset'`
2448
+ fires before the swap so subscribers know the rollover happened.
2449
+ Existing [SandboxContext](#sandboxcontext)s continue to work — their sandbox
2450
+ reference is stable; subsequent operations resolve to the new env.
2451
+
2452
+ ###### Returns
2453
+
2454
+ `void`
2455
+
2456
+ <a id="runwithprovenance-4"></a>
2457
+
2458
+ ##### runWithProvenance()?
2459
+
2460
+ ```ts
2461
+ optional runWithProvenance<T>(provenance: EventProvenance, fn: () => T): T;
2462
+ ```
2463
+
2464
+ Run `fn` with ambient [EventProvenance](#eventprovenance) defaults: every event
2465
+ emitted SYNCHRONOUSLY during `fn` that doesn't already carry a
2466
+ provenance field (on the event itself or via an explicit per-emit
2467
+ override) is stamped with these values instead of the global
2468
+ defaults. This is the mechanical "who issued this op" seam the
2469
+ serve worker uses to tag Studio-issued ops (`actor: { kind:
2470
+ 'studio' }`) and to stamp the auth lens an op ran under
2471
+ (`authLens`) — declared by the caller that issues the op, never
2472
+ inferred from the op's shape.
2473
+
2474
+ SYNCHRONOUS WINDOW: the ambient values apply only until `fn`
2475
+ returns (for an async `fn`, its synchronous prefix — which covers
2476
+ the local environment's rules eval + event emission, since those
2477
+ run before the op's promise is handed back). Work an op DEFERS
2478
+ (snapshot-listener deliveries and re-evals drain on a microtask,
2479
+ off-stack) is intentionally OUTSIDE the window: a listener re-eval
2480
+ belongs to the listener's owner, not to whoever's write triggered
2481
+ it. Nested calls stack — the innermost window wins per field, and
2482
+ each window restores the previous one on exit (including on throw).
2483
+
2484
+ OPTIONAL because remote sandbox proxies can't provide an ambient
2485
+ emit window (events are emitted in the worker they front). Callers
2486
+ spell `sandbox.runWithProvenance?.(prov, fn) ?? fn()`.
2487
+
2488
+ ###### Type Parameters
2489
+
2490
+ | Type Parameter |
2491
+ | :------ |
2492
+ | `T` |
2493
+
2494
+ ###### Parameters
2495
+
2496
+ | Parameter | Type |
2497
+ | :------ | :------ |
2498
+ | `provenance` | [`EventProvenance`](#eventprovenance) |
2499
+ | `fn` | () => `T` |
2500
+
2501
+ ###### Returns
2502
+
2503
+ `T`
2504
+
2505
+ <a id="snapshot-6"></a>
2506
+
2507
+ ##### snapshot()
2508
+
2509
+ ```ts
2510
+ snapshot(): SandboxSnapshot;
2511
+ ```
2512
+
2513
+ Capture a snapshot of every service's state. For v1 with only
2514
+ Firestore, the return value carries a `firestore` key mapping doc
2515
+ paths to data. Future services will add their own keys.
2516
+
2517
+ ###### Returns
2518
+
2519
+ [`SandboxSnapshot`](#sandboxsnapshot-2)
2520
+
2521
+ <a id="withauth-6"></a>
2522
+
2523
+ ##### withAuth()
2524
+
2525
+ ```ts
2526
+ withAuth(auth: {
2527
+ token?: Record<string, unknown>;
2528
+ uid: string;
2529
+ }): SandboxContext;
2530
+ ```
2531
+
2532
+ Derive a context bound to this sandbox under the given auth
2533
+ identity. Operations through services attached to the returned
2534
+ context evaluate rules under that identity. Many contexts can
2535
+ coexist for one sandbox; data is shared.
2536
+
2537
+ `null` is anonymous; an `AuthState` object names the user (and
2538
+ optional custom claims). Passing `undefined` is a deliberate
2539
+ error — say `withAuth(null)` for anonymous so the call site is
2540
+ unambiguous.
2541
+
2542
+ ###### Parameters
2543
+
2544
+ | Parameter | Type |
2545
+ | :------ | :------ |
2546
+ | `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
2547
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
2548
+ | `auth.uid` | `string` |
2549
+
2550
+ ###### Returns
2551
+
2552
+ [`SandboxContext`](#sandboxcontext)
2553
+
2554
+ ###### Example
2555
+
2556
+ ```ts
2557
+ const sandbox = initializeSandbox();
2558
+ const dbAlice = getFirestore(sandbox.withAuth({ uid: 'alice' }));
2559
+ const dbAnon = getFirestore(sandbox.withAuth(null));
2560
+ ```
2561
+
2562
+ ***
2563
+
2564
+ <a id="sandboxcommitevent"></a>
2565
+
2566
+ ### SandboxCommitEvent
2567
+
2568
+ Canonical committed mutation event. Unlike `operation`, this fires only when
2569
+ state actually changed. Replay and branch tooling should eventually consume
2570
+ these service adapters instead of filtering Firestore-only `write` events.
2571
+
2572
+ #### Properties
2573
+
2574
+ | Property | Type |
2575
+ | :------ | :------ |
2576
+ | <a id="at-3"></a> `at` | `number` |
2577
+ | <a id="auth-6"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
2578
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
2579
+ | `auth.uid` | `string` |
2580
+ | <a id="data"></a> `data?` | `unknown` |
2581
+ | <a id="detail-1"></a> `detail?` | `Record`\<`string`, `unknown`\> |
2582
+ | <a id="groupid-1"></a> `groupId?` | `string` |
2583
+ | <a id="groupkind-1"></a> `groupKind?` | `"transaction"` \| `"batch"` |
2584
+ | <a id="id-3"></a> `id` | `string` |
2585
+ | <a id="kind-2"></a> `kind` | `"commit"` |
2586
+ | <a id="method-2"></a> `method` | `string` |
2587
+ | <a id="nextstate"></a> `nextState?` | `unknown` |
2588
+ | <a id="path-2"></a> `path?` | `string` |
2589
+ | <a id="priorstate"></a> `priorState?` | `unknown` |
2590
+ | <a id="replay"></a> `replay?` | \{ `autoId?`: `string`; `requestTime?`: `number`; `sentinels?`: \{ `field`: `string`; `kind`: `string`; \}[]; \} |
2591
+ | `replay.autoId?` | `string` |
2592
+ | `replay.requestTime?` | `number` |
2593
+ | `replay.sentinels?` | \{ `field`: `string`; `kind`: `string`; \}[] |
2594
+ | <a id="service-2"></a> `service` | [`EventService`](#eventservice) |
2595
+
2596
+ ***
2597
+
2598
+ <a id="sandboxconfig"></a>
2599
+
2600
+ ### SandboxConfig
2601
+
2602
+ Initialization config for a sandbox. All fields are optional; an
2603
+ empty config produces a sandbox with no rules and no seeded data.
2604
+
2605
+ **No `auth` field.** Identity belongs to [SandboxContext](#sandboxcontext), not
2606
+ the sandbox. Service handles always require an explicit context.
2607
+
2608
+ ***
2609
+
2610
+ <a id="sandboxcontext"></a>
2611
+
2612
+ ### SandboxContext
2613
+
2614
+ Identity-bearing handle on a [Sandbox](#sandbox-3). A
2615
+ `(sandbox, auth, operationContext)`
2616
+ tuple — cheap to create, immutable, freely shareable. Service
2617
+ factories require a `SandboxContext`; bare `Sandbox` is a type
2618
+ error so every call site states identity explicitly.
2619
+
2620
+ Constructed via `Sandbox.withAuth(auth)` or chained via
2621
+ `SandboxContext.withAuth(auth)`. The concrete class is exported
2622
+ from `pyric/sandbox` for `instanceof` routing in service
2623
+ factories; consumers don't construct it directly.
2624
+
2625
+ #### Properties
2626
+
2627
+ | Property | Modifier | Type | Description |
2628
+ | :------ | :------ | :------ | :------ |
2629
+ | <a id="auth-7"></a> `auth` | `readonly` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | The identity rules evaluate under for operations through this context. |
2630
+ | `auth.token?` | `public` | `Record`\<`string`, `unknown`\> | - |
2631
+ | `auth.uid` | `public` | `string` | - |
2632
+ | <a id="operationcontext-3"></a> `operationContext` | `readonly` | [`OperationContext`](#operationcontext-2) | Immutable provenance bound to every operation issued through this handle. |
2633
+ | <a id="sandbox-4"></a> `sandbox` | `readonly` | [`Sandbox`](#sandbox-3) | The data foundation this context operates against. |
2634
+
2635
+ #### Methods
2636
+
2637
+ <a id="withauth-8"></a>
2638
+
2639
+ ##### withAuth()
2640
+
2641
+ ```ts
2642
+ withAuth(auth: {
2643
+ token?: Record<string, unknown>;
2644
+ uid: string;
2645
+ }): SandboxContext;
2646
+ ```
2647
+
2648
+ Derive a sibling context on the same sandbox with different auth.
2649
+ Replaces auth and its lens while preserving the operation source and
2650
+ optional plan identity.
2651
+
2652
+ ###### Parameters
2653
+
2654
+ | Parameter | Type |
2655
+ | :------ | :------ |
2656
+ | `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
2657
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
2658
+ | `auth.uid` | `string` |
2659
+
2660
+ ###### Returns
2661
+
2662
+ [`SandboxContext`](#sandboxcontext)
2663
+
2664
+ ***
2665
+
2666
+ <a id="sandboxlistenerevent"></a>
2667
+
2668
+ ### SandboxListenerEvent
2669
+
2670
+ Canonical listener lifecycle/delivery event. Firestore's existing snapshot
2671
+ delivery/lifecycle variants are preserved; this shape gives RTDB and future
2672
+ service listeners the same debuggable surface.
2673
+
2674
+ #### Properties
2675
+
2676
+ | Property | Type |
2677
+ | :------ | :------ |
2678
+ | <a id="at-4"></a> `at` | `number` |
2679
+ | <a id="auth-8"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
2680
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
2681
+ | `auth.uid` | `string` |
2682
+ | <a id="detail-2"></a> `detail?` | `Record`\<`string`, `unknown`\> |
2683
+ | <a id="error-1"></a> `error?` | \{ `code?`: `string`; `message`: `string`; `reasons?`: `string`[]; \} |
2684
+ | `error.code?` | `string` |
2685
+ | `error.message` | `string` |
2686
+ | `error.reasons?` | `string`[] |
2687
+ | <a id="id-4"></a> `id` | `string` |
2688
+ | <a id="kind-3"></a> `kind` | `"listener"` |
2689
+ | <a id="listenerid-1"></a> `listenerId` | `string` |
2690
+ | <a id="phase"></a> `phase` | `"attach"` \| `"detach"` \| `"delivery"` \| `"suppressed"` \| `"errored"` |
2691
+ | <a id="reason"></a> `reason?` | `string` |
2692
+ | <a id="result-2"></a> `result?` | `"allow"` \| `"deny"` \| `"unsupported"` \| `"error"` |
2693
+ | <a id="sample"></a> `sample?` | `unknown` |
2694
+ | <a id="service-3"></a> `service` | [`EventService`](#eventservice) |
2695
+ | <a id="size"></a> `size?` | `number` |
2696
+ | <a id="target-1"></a> `target` | \{ `kind`: `string`; `path?`: `string`; `query?`: `unknown`; \} |
2697
+ | `target.kind` | `string` |
2698
+ | `target.path?` | `string` |
2699
+ | `target.query?` | `unknown` |
2700
+ | <a id="triggeredby-1"></a> `triggeredBy?` | \{ `method`: `string`; `path?`: `string`; \} |
2701
+ | `triggeredBy.method` | `string` |
2702
+ | `triggeredBy.path?` | `string` |
2703
+
2704
+ ***
2705
+
2706
+ <a id="sandboxoperationevent"></a>
2707
+
2708
+ ### SandboxOperationEvent
2709
+
2710
+ Canonical service operation event. This is the service-neutral successor to
2711
+ Firestore's `request` traffic shape: every user-visible operation can be
2712
+ represented here, whether it is backed by security rules (Firestore/RTDB/
2713
+ Storage) or by a service control plane (Auth).
2714
+
2715
+ Existing Firestore `request` events remain for compatibility. New cross-
2716
+ service consumers should prefer `operation` because it carries an explicit
2717
+ `service` discriminator and does not require RTDB/Storage/Auth to pretend
2718
+ their state is a Firestore document.
2719
+
2720
+ #### Properties
2721
+
2722
+ | Property | Type | Description |
2723
+ | :------ | :------ | :------ |
2724
+ | <a id="at-5"></a> `at` | `number` | - |
2725
+ | <a id="auth-9"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | - |
2726
+ | `auth.token?` | `Record`\<`string`, `unknown`\> | - |
2727
+ | `auth.uid` | `string` | - |
2728
+ | <a id="detail-3"></a> `detail?` | `Record`\<`string`, `unknown`\> | - |
2729
+ | <a id="durationms"></a> `durationMs?` | `number` | - |
2730
+ | <a id="groupid-2"></a> `groupId?` | `string` | - |
2731
+ | <a id="groupkind-2"></a> `groupKind?` | `"transaction"` \| `"batch"` | - |
2732
+ | <a id="id-5"></a> `id` | `string` | - |
2733
+ | <a id="kind-4"></a> `kind` | `"operation"` | - |
2734
+ | <a id="method-3"></a> `method` | `string` | - |
2735
+ | <a id="origin-1"></a> `origin` | `"admin"` \| `"user"` \| `"listener"` \| `"transaction"` \| `"batch"` \| `"system"` | - |
2736
+ | <a id="path-3"></a> `path?` | `string` | - |
2737
+ | <a id="reasons-3"></a> `reasons?` | `string`[] | - |
2738
+ | <a id="request-3"></a> `request?` | \{ `data?`: `unknown`; `query?`: `unknown`; `resourceData?`: `unknown`; \} | - |
2739
+ | `request.data?` | `unknown` | - |
2740
+ | `request.query?` | `unknown` | - |
2741
+ | `request.resourceData?` | `unknown` | - |
2742
+ | <a id="resourceafter-1"></a> `resourceAfter?` | \{ `data`: `unknown`; `exists`: `boolean`; \} | - |
2743
+ | `resourceAfter.data` | `unknown` | - |
2744
+ | `resourceAfter.exists` | `boolean` | - |
2745
+ | <a id="resourcebefore-1"></a> `resourceBefore?` | \{ `data`: `unknown`; `exists`: `boolean`; \} | - |
2746
+ | `resourceBefore.data` | `unknown` | - |
2747
+ | `resourceBefore.exists` | `boolean` | - |
2748
+ | <a id="result-3"></a> `result` | `"allow"` \| `"deny"` \| `"unsupported"` \| `"error"` \| `"not-applicable"` | - |
2749
+ | <a id="rules-2"></a> `rules?` | \{ `engine`: `"firestore"` \| `"storage"` \| `"rtdb"`; `errorCode?`: `string`; `matchedPath?`: `string`; `matchedRule?`: `string`; `operations?`: `string`[]; `pathVariableBindings?`: `Record`\<`string`, `string`\>; `reason?`: `string`; `ruleIndex?`: `number`; \} | - |
2750
+ | `rules.engine` | `"firestore"` \| `"storage"` \| `"rtdb"` | - |
2751
+ | `rules.errorCode?` | `string` | - |
2752
+ | `rules.matchedPath?` | `string` | - |
2753
+ | `rules.matchedRule?` | `string` | - |
2754
+ | `rules.operations?` | `string`[] | - |
2755
+ | `rules.pathVariableBindings?` | `Record`\<`string`, `string`\> | - |
2756
+ | `rules.reason?` | `string` | - |
2757
+ | `rules.ruleIndex?` | `number` | - |
2758
+ | <a id="rulesdisposition-1"></a> `rulesDisposition?` | [`RulesDisposition`](#rulesdisposition-2) | Canonical statement of whether Security Rules evaluated this operation. Service emitters may provide it directly; the recorder normalizes legacy operation shapes at the unified stream seam. |
2759
+ | <a id="service-4"></a> `service` | [`EventService`](#eventservice) | - |
2760
+ | <a id="triggeredby-2"></a> `triggeredBy?` | \{ `method`: `string`; `path?`: `string`; \} | - |
2761
+ | `triggeredBy.method` | `string` | - |
2762
+ | `triggeredBy.path?` | `string` | - |
2763
+
2764
+ ***
2765
+
2766
+ <a id="sandboxpersistenceoptions"></a>
2767
+
2768
+ ### SandboxPersistenceOptions
2769
+
2770
+ Controller options. See [Sandbox.enablePersistence](#enablepersistence-4).
2771
+
2772
+ #### Properties
2773
+
2774
+ | Property | Type | Description |
2775
+ | :------ | :------ | :------ |
2776
+ | <a id="backend"></a> `backend?` | `"indexedDB"` \| `"memory"` | Storage backend. `indexedDB` requires a browser environment; in non-browser hosts (Bun, Node, tests) the controller falls back to `memory` automatically unless an `injectedBackend` is supplied. Default: `indexedDB`. |
2777
+ | <a id="flushintervalms"></a> `flushIntervalMs?` | `number` | Debounce window before write events are flushed to the backend. Buffers rapid bursts (e.g., a batch of seed writes) into one flush. Default: 250ms. |
2778
+ | <a id="injectedbackend"></a> `injectedBackend?` | [`PersistenceBackend`](#persistencebackend) | Override the backend with an injected implementation. Used by tests and hosts that have their own storage adapter. When set, `backend` is ignored. |
2779
+ | <a id="key"></a> `key` | `string` | IndexedDB database name (or generic bucket key for other backends). Different keys persist to different storage locations — use one key per logical sandbox if you run several in parallel. |
2780
+ | <a id="sessionstorage"></a> `sessionStorage?` | \{ `local`: [`WebStorageLike`](#webstoragelike); `session`: [`WebStorageLike`](#webstoragelike); \} | Optional web-storage pair for current-session persistence. When provided, the controller reads and writes the signed-in uid here (honoring the auth `setPersistence` mode) so page reloads restore the signed-in user — exactly like `browserLocalPersistence` in prod Firebase. When omitted, the user DATABASE still persists (Phase 1), but the CURRENT SESSION is not restored on reload. This is the honest no-fake-durability choice for environments where web storage isn't available (Bun tests, Node servers, etc.). `local` maps to `localStorage` semantics (survives reload + restart); `session` maps to `sessionStorage` semantics (survives reload, cleared on tab close). The controller picks which store to write based on the auth `setPersistence` mode recorded on the backend: LOCAL → local (default; matches Firebase's default) SESSION → session NONE → neither (uid is not stored) Both storages are read on restore (mode-agnostic — a prior session may have used a different mode). Exactly one store holds the uid at any time; a mode change migrates the uid to the new store. |
2781
+ | `sessionStorage.local` | [`WebStorageLike`](#webstoragelike) | - |
2782
+ | `sessionStorage.session` | [`WebStorageLike`](#webstoragelike) | - |
2783
+
2784
+ ***
2785
+
2786
+ <a id="sandboxruntimeerrorevent"></a>
2787
+
2788
+ ### SandboxRuntimeErrorEvent
2789
+
2790
+ Canonical non-rules operational failure.
2791
+
2792
+ #### Properties
2793
+
2794
+ | Property | Type |
2795
+ | :------ | :------ |
2796
+ | <a id="at-6"></a> `at` | `number` |
2797
+ | <a id="auth-10"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
2798
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
2799
+ | `auth.uid` | `string` |
2800
+ | <a id="detail-4"></a> `detail?` | `Record`\<`string`, `unknown`\> |
2801
+ | <a id="error-2"></a> `error` | \{ `code?`: `string`; `message`: `string`; \} |
2802
+ | `error.code?` | `string` |
2803
+ | `error.message` | `string` |
2804
+ | <a id="id-6"></a> `id` | `string` |
2805
+ | <a id="kind-5"></a> `kind` | `"runtime_error"` |
2806
+ | <a id="method-4"></a> `method` | `string` |
2807
+ | <a id="path-4"></a> `path?` | `string` |
2808
+ | <a id="service-5"></a> `service` | [`EventService`](#eventservice) |
2809
+
2810
+ ***
2811
+
2812
+ <a id="sandboxsnapshot-2"></a>
2813
+
2814
+ ### SandboxSnapshot
2815
+
2816
+ Sandbox-level snapshot — a coarse capture of every service's state
2817
+ keyed by service name. The `firestore` key is always present; the
2818
+ `services` map holds one entry per registered persistable service
2819
+ (auth users, future storage objects, etc.). Service-specific
2820
+ snapshot types live in their service modules; `/app` keeps the index
2821
+ structural so it stays decoupled from service implementations.
2822
+
2823
+ v2 shape — `services` was added when the persistable-service registry
2824
+ landed. Prior `{ firestore }` v1 blobs are treated as having an empty
2825
+ `services` map on restore.
2826
+
2827
+ #### Properties
2828
+
2829
+ | Property | Type | Description |
2830
+ | :------ | :------ | :------ |
2831
+ | <a id="firestore"></a> `firestore` | `Record`\<`string`, `Record`\<`string`, `unknown`\>\> | Firestore documents, keyed by full path. Always present — empty `{}` for a fresh or just-reset sandbox. Per-document values are the post-resolution state the keyspace stored. |
2832
+ | <a id="services"></a> `services` | `Record`\<`string`, `unknown`\> | Per-service opaque state, keyed by service name (e.g. `'auth'`). Each entry is whatever the service's `PersistableService.snapshot()` returned. May be `{}` when no services are registered. |
2833
+
2834
+ ***
2835
+
2836
+ <a id="servicemutationevent"></a>
2837
+
2838
+ ### ServiceMutationEvent
2839
+
2840
+ Cross-service mutation event — the unified envelope the NON-Firestore
2841
+ services (`auth` / `storage` / `rtdb`) emit into the single
2842
+ `onEvent`/`history()` stream (Pyric Studio keystone, track T1).
2843
+
2844
+ **Why a new variant rather than reusing `request`/`write`.** Firestore's
2845
+ existing kinds are tightly coupled to the rules-simulator: `RequestEvent`
2846
+ carries `result: 'allow'|'deny'`, `evalMs`, the simulator's `reasons[]`,
2847
+ and `matchedRule`; `WriteSandboxEvent` carries Firestore-specific
2848
+ `sentinels`, `autoId`, and a Firestore `requestTime` Timestamp. Auth user-
2849
+ DB mutations (no path, no rule eval), Storage object puts, and RTDB tree
2850
+ writes don't have those concepts, and bending them into the Firestore
2851
+ shapes would either lie (synthesize a fake `result`/`requestTime`) or
2852
+ pollute the Firestore consumer contract. So this is ONE small, additive
2853
+ variant the three services share — Firestore consumers filter on their
2854
+ existing `kind`s and never see it. See the design rationale.
2855
+
2856
+ It is intentionally generic: `op` is a free-ish string discriminated by
2857
+ `service`, and `before`/`after` are best-effort serializable snapshots
2858
+ (omitted when not meaningful — e.g. a sign-out has no `after`). Studio's
2859
+ data grids / Action Center render `service` + `op` + `path` directly and
2860
+ diff `before`→`after` when both are present.
2861
+
2862
+ #### Properties
2863
+
2864
+ | Property | Type | Description |
2865
+ | :------ | :------ | :------ |
2866
+ | <a id="after"></a> `after?` | `unknown` | Best-effort serializable snapshot of the state AFTER the mutation. Absent on deletes / sign-outs (nothing remains). |
2867
+ | <a id="at-7"></a> `at` | `number` | - |
2868
+ | <a id="auth-11"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | Identity in effect when the op ran (the service's `request.auth` equivalent). `null` for admin/anonymous-driven mutations (e.g. `sandbox.createUser`, an unauthenticated RTDB write). |
2869
+ | `auth.token?` | `Record`\<`string`, `unknown`\> | - |
2870
+ | `auth.uid` | `string` | - |
2871
+ | <a id="before"></a> `before?` | `unknown` | Best-effort serializable snapshot of the state BEFORE the mutation. Absent when there was no prior state (a create) or it isn't cheap to capture. |
2872
+ | <a id="detail-5"></a> `detail?` | `Record`\<`string`, `unknown`\> | Free-form, service-specific extras a consumer may surface without re-deriving (e.g. storage `{ size, contentType }`, rtdb `{ committed }` for a transaction). Kept loose on purpose — it's a display hint, not a contract. |
2873
+ | <a id="id-7"></a> `id` | `string` | - |
2874
+ | <a id="kind-6"></a> `kind` | `"service_mutation"` | - |
2875
+ | <a id="op-2"></a> `op` | `string` | Service-scoped operation name. Stable, lowercase, snake/kebab-free: - auth: `user_create` | `user_update` | `user_delete` | `users_clear` | `sign_in` | `sign_out` - storage: `object_put` | `object_delete` | `metadata_update` - rtdb: `set` | `update` | `remove` | `transaction` - ai: `generate_content` | `stream_generate_content` | `count_tokens` | `request_rejected` New ops can be added without a breaking change (consumers switch with a default branch). |
2876
+ | <a id="path-5"></a> `path?` | `string` | The thing mutated, in the service's own addressing scheme: - auth: the user `uid` (or `'*'` for a clear-all). Absent for a sign-out with no prior user. - storage: the object `fullPath` (e.g. `avatars/alice.png`). - rtdb: the database path (e.g. `/rooms/r1/messages`), or for a multi-path `update` the ref path the call targeted. |
2877
+ | <a id="service-6"></a> `service` | `"auth"` \| `"storage"` \| `"rtdb"` \| `"messaging"` \| `"ai"` | Which service performed the mutation. Always one of the non-Firestore services — Firestore rides its own `request`/`write` path. (The provenance `service` field on the stamped event mirrors this; it is set redundantly here so a consumer matching purely on `kind` still gets the discriminator without reaching into provenance.) |
2878
+
2879
+ ***
2880
+
2881
+ <a id="sessionboundaryevent"></a>
2882
+
2883
+ ### SessionBoundaryEvent
2884
+
2885
+ Session boundary — emitted before `sandbox.reset()` swaps the env,
2886
+ and before `sandbox.dispose()` tears it down. Lets consumers segment
2887
+ a persisted event stream into "session N pre-reset" / "session N+1
2888
+ post-reset" runs.
2889
+
2890
+ #### Properties
2891
+
2892
+ | Property | Type | Description |
2893
+ | :------ | :------ | :------ |
2894
+ | <a id="at-8"></a> `at` | `number` | - |
2895
+ | <a id="id-8"></a> `id` | `string` | - |
2896
+ | <a id="kind-7"></a> `kind` | `"session_boundary"` | - |
2897
+ | <a id="phase-1"></a> `phase` | `"reset"` \| `"dispose"` | - |
2898
+ | <a id="prioropcount"></a> `priorOpCount` | `number` | Total events emitted on this sandbox before the boundary. |
2899
+
2900
+ ***
2901
+
2902
+ <a id="snapshotdeliveryevent"></a>
2903
+
2904
+ ### SnapshotDeliveryEvent
2905
+
2906
+ Snapshot delivered to a `onSnapshot` listener's user callback.
2907
+
2908
+ Fires AFTER the no-op suppression check — every `snapshot_delivery`
2909
+ event corresponds to an actual user-callback invocation. Listener
2910
+ re-evals that resolved to no-ops emit [SnapshotSuppressedEvent](#snapshotsuppressedevent)
2911
+ instead.
2912
+
2913
+ `sample` carries best-effort serializable views of the docs the
2914
+ callback received; consumers truncate before persisting if the
2915
+ scenario produces large snapshots.
2916
+
2917
+ #### Properties
2918
+
2919
+ | Property | Type | Description |
2920
+ | :------ | :------ | :------ |
2921
+ | <a id="addedcount"></a> `addedCount` | `number` | - |
2922
+ | <a id="at-9"></a> `at` | `number` | - |
2923
+ | <a id="auth-12"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | - |
2924
+ | `auth.token?` | `Record`\<`string`, `unknown`\> | - |
2925
+ | `auth.uid` | `string` | - |
2926
+ | <a id="id-9"></a> `id` | `string` | - |
2927
+ | <a id="kind-8"></a> `kind` | `"snapshot_delivery"` | - |
2928
+ | <a id="listenerid-2"></a> `listenerId` | `string` | Opaque listener id assigned at attach time. |
2929
+ | <a id="modifiedcount"></a> `modifiedCount` | `number` | - |
2930
+ | <a id="removedcount"></a> `removedCount` | `number` | - |
2931
+ | <a id="sample-1"></a> `sample?` | \{ `docs`: \{ `data`: `Record`\<`string`, `unknown`\>; `path`: `string`; \}[]; \} | Doc payloads, in the order the user callback saw them. |
2932
+ | `sample.docs` | \{ `data`: `Record`\<`string`, `unknown`\>; `path`: `string`; \}[] | - |
2933
+ | <a id="size-1"></a> `size` | `number` | `1` for doc-kind (exists) / `0` (deleted), `n` for query-kind. |
2934
+ | <a id="target-2"></a> `target` | \| \{ `kind`: `"doc"`; `path`: `string`; \} \| \{ `collection`: `string`; `kind`: `"query"`; \} | - |
2935
+ | <a id="triggeredby-3"></a> `triggeredBy?` | \{ `method`: `string`; `path`: `string`; \} | The user op that triggered this re-eval. Absent on initial fire and on `deployRules`-driven re-evals. |
2936
+ | `triggeredBy.method` | `string` | - |
2937
+ | `triggeredBy.path` | `string` | - |
2938
+
2939
+ ***
2940
+
2941
+ <a id="snapshoterrorevent"></a>
2942
+
2943
+ ### SnapshotErrorEvent
2944
+
2945
+ Eval-time payload emitted to Sandbox.onSnapshotError subscribers.
2946
+
2947
+ Stream-level error from a Firestore `onSnapshot` listener — the
2948
+ listener has been silently terminated and will deliver no further
2949
+ snapshots (matches production: a stream error is once-per-stream and
2950
+ the listener stays "subscribed" from the consumer's perspective but
2951
+ receives nothing further). Carries the `target` so the host UI can
2952
+ attribute the error to a specific watch.
2953
+
2954
+ Currently `permission-denied` is the only code the sandbox produces
2955
+ (production also emits `unavailable`, `aborted`, `resource-exhausted`
2956
+ — none of which have a sandbox analog: no network stream to drop, no
2957
+ quota, no concurrent transactions to conflict). Documented divergence
2958
+ from production; new codes can be added if a sandbox-specific
2959
+ scenario surfaces them.
2960
+
2961
+ #### Properties
2962
+
2963
+ | Property | Type |
2964
+ | :------ | :------ |
2965
+ | <a id="auth-13"></a> `auth?` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} |
2966
+ | `auth.token?` | `Record`\<`string`, `unknown`\> |
2967
+ | `auth.uid` | `string` |
2968
+ | <a id="code-2"></a> `code` | `"permission-denied"` |
2969
+ | <a id="message-1"></a> `message` | `string` |
2970
+ | <a id="reasons-4"></a> `reasons?` | `string`[] |
2971
+ | <a id="request-4"></a> `request?` | \{ `method`: `"get"` \| `"list"` \| `"create"` \| `"update"` \| `"delete"`; `path`: `string`; `resourceData?`: `Record`\<`string`, `unknown`\>; \} |
2972
+ | `request.method` | `"get"` \| `"list"` \| `"create"` \| `"update"` \| `"delete"` |
2973
+ | `request.path` | `string` |
2974
+ | `request.resourceData?` | `Record`\<`string`, `unknown`\> |
2975
+ | <a id="resource-2"></a> `resource?` | \{ `data`: `Record`\<`string`, `unknown`\>; `exists`: `boolean`; \} |
2976
+ | `resource.data` | `Record`\<`string`, `unknown`\> |
2977
+ | `resource.exists` | `boolean` |
2978
+ | <a id="target-3"></a> `target` | \| \{ `kind`: `"doc"`; `path`: `string`; \} \| \{ `collection`: `string`; `kind`: `"query"`; \} |
2979
+
2980
+ ***
2981
+
2982
+ <a id="snapshotsuppressedevent"></a>
2983
+
2984
+ ### SnapshotSuppressedEvent
2985
+
2986
+ Listener re-eval that was suppressed before delivery — the re-eval
2987
+ ran but produced no observable change vs the prior snapshot, so the
2988
+ user callback wasn't invoked.
2989
+
2990
+ Useful for "why didn't my listener fire" debugging. Default UIs
2991
+ should filter these out; only the inspector-style consumer needs
2992
+ them.
2993
+
2994
+ #### Properties
2995
+
2996
+ | Property | Type | Description |
2997
+ | :------ | :------ | :------ |
2998
+ | <a id="at-10"></a> `at` | `number` | - |
2999
+ | <a id="auth-14"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | - |
3000
+ | `auth.token?` | `Record`\<`string`, `unknown`\> | - |
3001
+ | `auth.uid` | `string` | - |
3002
+ | <a id="id-10"></a> `id` | `string` | - |
3003
+ | <a id="kind-9"></a> `kind` | `"snapshot_suppressed"` | - |
3004
+ | <a id="listenerid-3"></a> `listenerId` | `string` | - |
3005
+ | <a id="reason-1"></a> `reason` | `"no-op"` | Why this re-eval was suppressed. v1 only emits `'no-op'`. |
3006
+ | <a id="target-4"></a> `target` | \| \{ `kind`: `"doc"`; `path`: `string`; \} \| \{ `collection`: `string`; `kind`: `"query"`; \} | - |
3007
+ | <a id="triggeredby-4"></a> `triggeredBy?` | \{ `method`: `string`; `path`: `string`; \} | - |
3008
+ | `triggeredBy.method` | `string` | - |
3009
+ | `triggeredBy.path` | `string` | - |
3010
+
3011
+ ***
3012
+
3013
+ <a id="tabsyncoptions"></a>
3014
+
3015
+ ### TabSyncOptions
3016
+
3017
+ Options for `sandbox.enableTabSync(options?)`. All fields are optional;
3018
+ the defaults provide a ready-to-use configuration for browser environments.
3019
+
3020
+ #### Properties
3021
+
3022
+ | Property | Type | Description |
3023
+ | :------ | :------ | :------ |
3024
+ | <a id="channel-1"></a> `channel?` | [`BroadcastChannelLike`](#broadcastchannellike) | The broadcast channel to use. Defaults to `new BroadcastChannel('pyric:tabsync')` when omitted and `BroadcastChannel` is available in the global scope. Pass a custom implementation for tests or Node environments. |
3025
+ | <a id="originid"></a> `originId?` | `string` | A string that uniquely identifies this tab's sandbox instance. Used for echo suppression (messages with `origin === originId` are silently dropped) and for directing `state` replies to the requesting tab. Defaults to `crypto.randomUUID()` when available, otherwise a counter + process-uptime string (no `Date.now()` or `Math.random()` — those change every call and can collide in fast tests). |
3026
+
3027
+ ***
3028
+
3029
+ <a id="webstoragelike"></a>
3030
+
3031
+ ### WebStorageLike
3032
+
3033
+ Minimal web-storage-like contract the session persistence controller
3034
+ reads/writes. Matches the `localStorage` / `sessionStorage` browser
3035
+ API subset that `pyric dev`'s `SessionStore` already uses, so
3036
+ browsers pass real storages and tests pass in-memory Map-backed fakes.
3037
+
3038
+ Why the minimal subset (get/set/remove) instead of the full
3039
+ `Storage` interface: this library targets multiple environments
3040
+ (browser, Bun, Node) and the full `Storage` interface carries
3041
+ length + key() + clear() that aren't needed here — narrowing the
3042
+ contract keeps tests simple and Node/Bun hosts from having to
3043
+ implement a complete polyfill.
3044
+
3045
+ #### Methods
3046
+
3047
+ <a id="getitem"></a>
3048
+
3049
+ ##### getItem()
3050
+
3051
+ ```ts
3052
+ getItem(key: string): string;
3053
+ ```
3054
+
3055
+ ###### Parameters
3056
+
3057
+ | Parameter | Type |
3058
+ | :------ | :------ |
3059
+ | `key` | `string` |
3060
+
3061
+ ###### Returns
3062
+
3063
+ `string`
3064
+
3065
+ <a id="removeitem"></a>
3066
+
3067
+ ##### removeItem()
3068
+
3069
+ ```ts
3070
+ removeItem(key: string): void;
3071
+ ```
3072
+
3073
+ ###### Parameters
3074
+
3075
+ | Parameter | Type |
3076
+ | :------ | :------ |
3077
+ | `key` | `string` |
3078
+
3079
+ ###### Returns
3080
+
3081
+ `void`
3082
+
3083
+ <a id="setitem"></a>
3084
+
3085
+ ##### setItem()
3086
+
3087
+ ```ts
3088
+ setItem(key: string, value: string): void;
3089
+ ```
3090
+
3091
+ ###### Parameters
3092
+
3093
+ | Parameter | Type |
3094
+ | :------ | :------ |
3095
+ | `key` | `string` |
3096
+ | `value` | `string` |
3097
+
3098
+ ###### Returns
3099
+
3100
+ `void`
3101
+
3102
+ ***
3103
+
3104
+ <a id="writesandboxevent"></a>
3105
+
3106
+ ### WriteSandboxEvent
3107
+
3108
+ Committed write — a `create`/`update`/`set`/`delete` that the rule
3109
+ engine allowed AND that the keyspace successfully applied. Includes
3110
+ pre- and post-state so consumers can render diffs and (in a future
3111
+ `sandbox.history()` API) reconstruct state by replay.
3112
+
3113
+ Fires AFTER the corresponding `kind: 'request'` event for the same
3114
+ op. A denied or rolled-back write surfaces as a request-deny only;
3115
+ `write` events only fire for committed writes.
3116
+
3117
+ `sentinels` and `autoId` are placeholders for the eventual replay
3118
+ engine — v1 of the unified channel leaves them undefined. The shape
3119
+ is locked so consumers can build against it without churn when
3120
+ sentinel/auto-id capture lands.
3121
+
3122
+ #### Properties
3123
+
3124
+ | Property | Type | Description |
3125
+ | :------ | :------ | :------ |
3126
+ | <a id="at-11"></a> `at` | `number` | - |
3127
+ | <a id="auth-15"></a> `auth` | \{ `token?`: `Record`\<`string`, `unknown`\>; `uid`: `string`; \} | - |
3128
+ | `auth.token?` | `Record`\<`string`, `unknown`\> | - |
3129
+ | `auth.uid` | `string` | - |
3130
+ | <a id="autoid"></a> `autoId?` | `string` | Minted document ID when this write came from `collection.add()` / `LocalEnvironment.createWithAutoId`. The replay engine aliases the path's last segment to a fresh mint on replay (rather than preserving the original auto-ID). |
3131
+ | <a id="data-1"></a> `data?` | `Record`\<`string`, `unknown`\> | Pre-resolution write payload — `FieldValue.*` sentinels preserved as marker shapes (`{ __type: 'serverTimestamp' }`, etc.) so the replay engine can re-resolve them. The rule engine evaluated against the resolved form internally; the resolved form lives on [nextState](#nextstate-1). Absent on `delete`. |
3132
+ | <a id="detail-6"></a> `detail?` | \{ `admin?`: `boolean`; \} & `Record`\<`string`, `unknown`\> | Free-form write metadata. `admin: true` marks a rules-bypassing setup/admin commit so replay can apply it as context without asking candidate rules to permit it. |
3133
+ | <a id="groupid-3"></a> `groupId?` | `string` | - |
3134
+ | <a id="groupkind-3"></a> `groupKind?` | `"transaction"` \| `"batch"` | - |
3135
+ | <a id="id-11"></a> `id` | `string` | - |
3136
+ | <a id="kind-10"></a> `kind` | `"write"` | - |
3137
+ | <a id="method-5"></a> `method` | `"create"` \| `"update"` \| `"delete"` \| `"set"` | - |
3138
+ | <a id="nextstate-1"></a> `nextState` | `Record`\<`string`, `unknown`\> | State AFTER this write. `null` on `delete`. |
3139
+ | <a id="path-6"></a> `path` | `string` | - |
3140
+ | <a id="priorstate-1"></a> `priorState` | `Record`\<`string`, `unknown`\> | State BEFORE this write. `null` for a non-existent doc. |
3141
+ | <a id="requesttime"></a> `requestTime` | \{ `nanoseconds`: `number`; `seconds`: `number`; \} | Server time at which the rule engine evaluated this write — pinned per op (or shared across sub-ops in a batch / transaction). The replay engine re-issues this exact value when re-resolving `serverTimestamp()` sentinels so resolved fields are bit-identical on replay. Shape mirrors the Firestore Web SDK Timestamp (`{ seconds, nanoseconds }`). |
3142
+ | `requestTime.nanoseconds` | `number` | - |
3143
+ | `requestTime.seconds` | `number` | - |
3144
+ | <a id="sentinels"></a> `sentinels?` | \{ `field`: `string`; `kind`: \| `"delete"` \| `"serverTimestamp"` \| `"increment"` \| `"arrayUnion"` \| `"arrayRemove"`; \}[] | FieldValue sentinels (serverTimestamp / increment / arrayUnion / arrayRemove / deleteField → 'delete') extracted from the pre-resolution write payload. The replay engine consumes this to re-issue the same sentinels at replay time without consulting resolved values that would have drifted. Path syntax: dotted with bracket-indices ('a.b[0].c'). Absent when the write contained no sentinels. |
3145
+
3146
+ ## Type Aliases
3147
+
3148
+ <a id="authlens-2"></a>
3149
+
3150
+ ### AuthLens
3151
+
3152
+ ```ts
3153
+ type AuthLens =
3154
+ | {
3155
+ mode: "admin";
3156
+ }
3157
+ | {
3158
+ mode: "as";
3159
+ token?: Record<string, unknown>;
3160
+ uid: string;
3161
+ }
3162
+ | {
3163
+ mode: "app-session";
3164
+ }
3165
+ | {
3166
+ mode: "anon";
3167
+ };
3168
+ ```
3169
+
3170
+ The identity/rules lens an operation actually ran under.
3171
+
3172
+ ***
3173
+
3174
+ <a id="authstate"></a>
3175
+
3176
+ ### AuthState
3177
+
3178
+ ```ts
3179
+ type AuthState =
3180
+ | {
3181
+ token?: Record<string, unknown>;
3182
+ uid: string;
3183
+ }
3184
+ | null;
3185
+ ```
3186
+
3187
+ A signed-in identity for sandbox operations. `null` is anonymous.
3188
+
3189
+ `token` is the Firebase Auth token claims map (custom claims plus
3190
+ standard ones). It surfaces the same way it does in production rules
3191
+ via `request.auth.token.*`. Omit it for plain UID-only auth.
3192
+
3193
+ Renamed from `AuthContext` (pre-multi-context) so the data type
3194
+ doesn't visually collide with `SandboxContext` (the identity-bearing
3195
+ handle). They sit at different layers — payload vs. handle — and the
3196
+ names should reflect that.
3197
+
3198
+ ***
3199
+
3200
+ <a id="difftarget"></a>
3201
+
3202
+ ### DiffTarget
3203
+
3204
+ ```ts
3205
+ type DiffTarget = LocalSandbox | SandboxSnapshot;
3206
+ ```
3207
+
3208
+ A reference to diff a branch against: a live sandbox or a bare snapshot.
3209
+
3210
+ ***
3211
+
3212
+ <a id="divergence"></a>
3213
+
3214
+ ### Divergence
3215
+
3216
+ ```ts
3217
+ type Divergence =
3218
+ | {
3219
+ after: unknown;
3220
+ before: unknown;
3221
+ field: string;
3222
+ kind: "sentinel-drift";
3223
+ path: string;
3224
+ sentinelKind: | "serverTimestamp"
3225
+ | "increment"
3226
+ | "arrayUnion"
3227
+ | "arrayRemove"
3228
+ | "delete";
3229
+ }
3230
+ | {
3231
+ kind: "autoid-alias";
3232
+ originalPath: string;
3233
+ replayedPath: string;
3234
+ }
3235
+ | {
3236
+ after: unknown;
3237
+ before: unknown;
3238
+ field: string;
3239
+ kind: "time-drift";
3240
+ path: string;
3241
+ }
3242
+ | {
3243
+ after: unknown;
3244
+ before: unknown;
3245
+ field?: string;
3246
+ kind: "real-divergence";
3247
+ path: string;
3248
+ };
3249
+ ```
3250
+
3251
+ ***
3252
+
3253
+ <a id="eventactor"></a>
3254
+
3255
+ ### EventActor
3256
+
3257
+ ```ts
3258
+ type EventActor =
3259
+ | {
3260
+ kind: "app";
3261
+ }
3262
+ | {
3263
+ kind: "studio";
3264
+ }
3265
+ | {
3266
+ kind: "agent";
3267
+ name: string;
3268
+ }
3269
+ | {
3270
+ kind: "app-builder";
3271
+ }
3272
+ | {
3273
+ kind: "unattributed";
3274
+ };
3275
+ ```
3276
+
3277
+ Who initiated the operation behind an event. Missing source is represented
3278
+ explicitly as `unattributed`; it is never silently promoted to app traffic.
3279
+
3280
+ ***
3281
+
3282
+ <a id="eventservice"></a>
3283
+
3284
+ ### EventService
3285
+
3286
+ ```ts
3287
+ type EventService = "firestore" | "auth" | "storage" | "rtdb" | "messaging" | "ai";
3288
+ ```
3289
+
3290
+ Which sandbox service emitted an event.
3291
+
3292
+ ***
3293
+
3294
+ <a id="remotesandboxfactory"></a>
3295
+
3296
+ ### RemoteSandboxFactory()
3297
+
3298
+ ```ts
3299
+ type RemoteSandboxFactory = (opts?: RemoteSandboxFactoryOptions) => RemoteSandbox;
3300
+ ```
3301
+
3302
+ The factory `@pyric/cli/register` installs at
3303
+ `globalThis[`[REMOTE\_SANDBOX\_FACTORY](#remote_sandbox_factory)`]`. SYNCHRONOUS by contract:
3304
+ `initializeApp()` is sync in firebase-admin, so the factory must return
3305
+ the branded handle without awaiting (connection establishment may be
3306
+ lazy inside the handle's channel).
3307
+
3308
+ #### Parameters
3309
+
3310
+ | Parameter | Type |
3311
+ | :------ | :------ |
3312
+ | `opts?` | [`RemoteSandboxFactoryOptions`](#remotesandboxfactoryoptions) |
3313
+
3314
+ #### Returns
3315
+
3316
+ [`RemoteSandbox`](#remotesandbox)
3317
+
3318
+ ***
3319
+
3320
+ <a id="rulesdisposition-2"></a>
3321
+
3322
+ ### RulesDisposition
3323
+
3324
+ ```ts
3325
+ type RulesDisposition =
3326
+ | {
3327
+ kind: "evaluated";
3328
+ verdict: "allow" | "deny";
3329
+ }
3330
+ | {
3331
+ kind: "bypassed";
3332
+ reason: "admin";
3333
+ }
3334
+ | {
3335
+ kind: "not-evaluated";
3336
+ reason: "no-rules" | "unsupported" | "not-a-rules-operation" | "runtime-error";
3337
+ };
3338
+ ```
3339
+
3340
+ What happened at the Security Rules seam. Admin is a lens; `bypassed` is
3341
+ the rules disposition.
3342
+
3343
+ ***
3344
+
3345
+ <a id="sandboxerrorcode-1"></a>
3346
+
3347
+ ### SandboxErrorCode
3348
+
3349
+ ```ts
3350
+ type SandboxErrorCode =
3351
+ | "invalid-argument"
3352
+ | "permission-denied"
3353
+ | "not-found"
3354
+ | "already-exists"
3355
+ | "failed-precondition"
3356
+ | "aborted"
3357
+ | "unavailable"
3358
+ | "unimplemented"
3359
+ | "not-seeded"
3360
+ | "rules-not-loaded";
3361
+ ```
3362
+
3363
+ Error codes raised by the sandbox layer.
3364
+
3365
+ The first batch matches Firebase / gRPC conventions so existing
3366
+ `if (e.code === 'permission-denied')` code from production paths
3367
+ keeps working. The second batch is sandbox-specific and exists so
3368
+ agents can distinguish "sandbox doesn't simulate this" from "your
3369
+ code is wrong" without parsing message strings.
3370
+
3371
+ ***
3372
+
3373
+ <a id="sandboxevent"></a>
3374
+
3375
+ ### SandboxEvent
3376
+
3377
+ ```ts
3378
+ type SandboxEvent =
3379
+ | RequestEvent
3380
+ | WriteSandboxEvent
3381
+ | SnapshotDeliveryEvent
3382
+ | SnapshotSuppressedEvent
3383
+ | ListenerLifecycleEvent
3384
+ | SessionBoundaryEvent
3385
+ | ServiceMutationEvent
3386
+ | SandboxOperationEvent
3387
+ | SandboxCommitEvent
3388
+ | SandboxListenerEvent
3389
+ | SandboxRuntimeErrorEvent & EventProvenance;
3390
+ ```
3391
+
3392
+ Discriminated union of every event the sandbox emits to
3393
+ [Sandbox.onEvent](#onevent-4) subscribers.
3394
+
3395
+ Issue #307 — replaces the prior three-channel surface
3396
+ (`onRequest` / `onDenial` / `onSnapshotError`). Filter on `kind`
3397
+ to recover the subset each old channel covered:
3398
+ - request: `kind === 'request'`
3399
+ - denial: `kind === 'request' && result === 'deny'`
3400
+ - snapshotError: `kind === 'listener_errored'`
3401
+
3402
+ See the design rationale for the
3403
+ field-by-field rationale.
3404
+
3405
+ ## Variables
3406
+
3407
+ <a id="remote_sandbox-1"></a>
3408
+
3409
+ ### REMOTE\_SANDBOX
3410
+
3411
+ ```ts
3412
+ const REMOTE_SANDBOX: unique symbol;
3413
+ ```
3414
+
3415
+ Brand stamped (value `true`) on every remote sandbox handle.
3416
+ `Symbol.for` — registered globally so `pyric-admin`'s check matches the
3417
+ stamp even if two copies of `pyric` end up in one process.
3418
+
3419
+ ***
3420
+
3421
+ <a id="remote_sandbox_factory"></a>
3422
+
3423
+ ### REMOTE\_SANDBOX\_FACTORY
3424
+
3425
+ ```ts
3426
+ const REMOTE_SANDBOX_FACTORY: unique symbol;
3427
+ ```
3428
+
3429
+ Well-known global key under which `@pyric/cli/register` installs the
3430
+ remote-sandbox factory: `globalThis[REMOTE_SANDBOX_FACTORY]`.
3431
+
3432
+ This is the AMBIENT-INIT seam (adoption experience, layer 3): when
3433
+ `pyric-admin/app`'s bare `initializeApp()` sees `PYRIC_SANDBOX=remote[:url]`
3434
+ it reads this global and calls the installed [RemoteSandboxFactory](#remotesandboxfactory)
3435
+ to obtain the branded handle — without importing `@pyric/cli` (which is
3436
+ a devDependency of the app, not of `pyric-admin`). `Symbol.for` so the
3437
+ installer and the reader agree even across duplicated copies of `pyric`.
3438
+
3439
+ ## Functions
3440
+
3441
+ <a id="apply"></a>
3442
+
3443
+ ### apply()
3444
+
3445
+ ```ts
3446
+ function apply(branch: Branch, events: readonly SandboxEvent[]): Branch;
3447
+ ```
3448
+
3449
+ Apply a stream of events to a branch by re-issuing their writes against
3450
+ the branch's CURRENT state.
3451
+
3452
+ This is the same per-write re-issue logic `replay()` runs (filter to
3453
+ `kind: 'write'`, honour `autoId` / pinned `requestTime`, prefer the
3454
+ pre-resolution `request.resourceData` so sentinels re-resolve), but
3455
+ applied *incrementally* on the branch's existing env rather than on a
3456
+ fresh empty sandbox — so it composes over base docs (e.g. an `update`
3457
+ lands on a doc the snapshot seeded) and accumulates across multiple
3458
+ `apply` calls. The applied events are folded into `branch.events` so
3459
+ [promote](#promote) can reproduce the same sequence on the target.
3460
+
3461
+ #### Parameters
3462
+
3463
+ | Parameter | Type |
3464
+ | :------ | :------ |
3465
+ | `branch` | [`Branch`](#branch) |
3466
+ | `events` | readonly [`SandboxEvent`](#sandboxevent)[] |
3467
+
3468
+ #### Returns
3469
+
3470
+ [`Branch`](#branch)
3471
+
3472
+ the same branch (mutated in place) for chaining.
3473
+
3474
+ ***
3475
+
3476
+ <a id="attachpersistence"></a>
3477
+
3478
+ ### attachPersistence()
3479
+
3480
+ ```ts
3481
+ function attachPersistence(sandbox: Sandbox, rawOptions: SandboxPersistenceOptions): Promise<PersistenceController>;
3482
+ ```
3483
+
3484
+ Construct a controller, restore any prior snapshot, and wire the
3485
+ auto-flush subscription. Returns once restore has completed (callers
3486
+ can `await sandbox.enablePersistence(...)` and be sure the in-memory
3487
+ state reflects the persisted blob).
3488
+
3489
+ Late service registration: services (e.g. auth) may register with the
3490
+ sandbox AFTER this call returns (the user calls `enablePersistence`
3491
+ then later `getAuth(sandbox)` which triggers `registerPersistableService`).
3492
+ We handle this in two parts:
3493
+ 1. `restore()` returns the raw `services` blob map so the controller
3494
+ can apply it to late-arriving services.
3495
+ 2. `setServiceRegistrationHook` fires on each registration — we
3496
+ immediately apply the saved blob data (if any) AND subscribe the
3497
+ service's change notifier for future flushes.
3498
+
3499
+ #### Parameters
3500
+
3501
+ | Parameter | Type |
3502
+ | :------ | :------ |
3503
+ | `sandbox` | [`Sandbox`](#sandbox-3) |
3504
+ | `rawOptions` | [`SandboxPersistenceOptions`](#sandboxpersistenceoptions) |
3505
+
3506
+ #### Returns
3507
+
3508
+ `Promise`\<[`PersistenceController`](#persistencecontroller)\>
3509
+
3510
+ ***
3511
+
3512
+ <a id="attachtabsync"></a>
3513
+
3514
+ ### attachTabSync()
3515
+
3516
+ ```ts
3517
+ function attachTabSync(sandbox: LocalSandbox, options?: TabSyncOptions): () => void;
3518
+ ```
3519
+
3520
+ Attach cross-tab sync to a sandbox. Called by `SandboxImpl.enableTabSync`;
3521
+ kept in a separate module so `sandbox-impl.ts` stays thin.
3522
+
3523
+ Returns a `disable` function: calling it unsubscribes the onEvent listener,
3524
+ removes the channel message listener, and closes the channel.
3525
+
3526
+ #### Parameters
3527
+
3528
+ | Parameter | Type | Description |
3529
+ | :------ | :------ | :------ |
3530
+ | `sandbox` | [`LocalSandbox`](#localsandbox) | The sandbox to sync. Must expose `onEvent`, `admin`, and `snapshot`. |
3531
+ | `options?` | [`TabSyncOptions`](#tabsyncoptions) | Optional channel and origin override. |
3532
+
3533
+ #### Returns
3534
+
3535
+ ```ts
3536
+ (): void;
3537
+ ```
3538
+
3539
+ ##### Returns
3540
+
3541
+ `void`
3542
+
3543
+ ***
3544
+
3545
+ <a id="bundlerecords"></a>
3546
+
3547
+ ### bundleRecords()
3548
+
3549
+ ```ts
3550
+ function bundleRecords(records: ReadonlyMap<string, unknown>): string;
3551
+ ```
3552
+
3553
+ Bundle v3 records into one committable JSON string, for single-blob stores
3554
+ (serve's exportable `.pyric/state` file, an HTTP state endpoint). Inverse of
3555
+ [parseBundle](#parsebundle). This deliberately collapses the chunking into one blob:
3556
+ it is the single-artifact EXPORT shape, not the scale path (that is the
3557
+ record-shaped backend).
3558
+
3559
+ #### Parameters
3560
+
3561
+ | Parameter | Type |
3562
+ | :------ | :------ |
3563
+ | `records` | `ReadonlyMap`\<`string`, `unknown`\> |
3564
+
3565
+ #### Returns
3566
+
3567
+ `string`
3568
+
3569
+ ***
3570
+
3571
+ <a id="createindexeddbbackend"></a>
3572
+
3573
+ ### createIndexedDBBackend()
3574
+
3575
+ ```ts
3576
+ function createIndexedDBBackend(): PersistenceBackend;
3577
+ ```
3578
+
3579
+ Build an IndexedDB-backed `PersistenceBackend`. Throws synchronously when
3580
+ called outside a browser (no `indexedDB` global) so callers can detect the
3581
+ absence and fall back to memory.
3582
+
3583
+ #### Returns
3584
+
3585
+ [`PersistenceBackend`](#persistencebackend)
3586
+
3587
+ ***
3588
+
3589
+ <a id="creatememorybackend"></a>
3590
+
3591
+ ### createMemoryBackend()
3592
+
3593
+ ```ts
3594
+ function createMemoryBackend(): PersistenceBackend;
3595
+ ```
3596
+
3597
+ #### Returns
3598
+
3599
+ [`PersistenceBackend`](#persistencebackend)
3600
+
3601
+ ***
3602
+
3603
+ <a id="deserializefrombuckets"></a>
3604
+
3605
+ ### deserializeFromBuckets()
3606
+
3607
+ ```ts
3608
+ function deserializeFromBuckets(records: Iterable<[string, unknown]>): {
3609
+ firestore: Record<string, Record<string, unknown>>;
3610
+ services: Record<string, unknown>;
3611
+ };
3612
+ ```
3613
+
3614
+ Reassemble a firestore snapshot + services from v3 records (any iterable of
3615
+ [recordId, record] pairs). Rehydrates wrapper types from their markers.
3616
+
3617
+ #### Parameters
3618
+
3619
+ | Parameter | Type |
3620
+ | :------ | :------ |
3621
+ | `records` | `Iterable`\<\[`string`, `unknown`\]\> |
3622
+
3623
+ #### Returns
3624
+
3625
+ ```ts
3626
+ {
3627
+ firestore: Record<string, Record<string, unknown>>;
3628
+ services: Record<string, unknown>;
3629
+ }
3630
+ ```
3631
+
3632
+ ##### firestore
3633
+
3634
+ ```ts
3635
+ firestore: Record<string, Record<string, unknown>>;
3636
+ ```
3637
+
3638
+ ##### services
3639
+
3640
+ ```ts
3641
+ services: Record<string, unknown>;
3642
+ ```
3643
+
3644
+ ***
3645
+
3646
+ <a id="diff"></a>
3647
+
3648
+ ### diff()
3649
+
3650
+ ```ts
3651
+ function diff(branch: Branch, target: DiffTarget): Divergence[];
3652
+ ```
3653
+
3654
+ Structural diff of a branch's current state against a reference.
3655
+
3656
+ Reuses the replay engine's `Divergence` result type and mirrors its
3657
+ doc-level + field-level walk (see diffDocSets). With no captured
3658
+ write metadata in play, differences surface as `real-divergence`
3659
+ (field/doc changed) — the honest classification for "branch vs live".
3660
+ Added/removed docs surface as presence divergences (one side
3661
+ `undefined`).
3662
+
3663
+ #### Parameters
3664
+
3665
+ | Parameter | Type | Description |
3666
+ | :------ | :------ | :------ |
3667
+ | `branch` | [`Branch`](#branch) | The experiment. |
3668
+ | `target` | [`DiffTarget`](#difftarget) | Live sandbox or a snapshot to compare against. |
3669
+
3670
+ #### Returns
3671
+
3672
+ [`Divergence`](#divergence)[]
3673
+
3674
+ ***
3675
+
3676
+ <a id="discard"></a>
3677
+
3678
+ ### discard()
3679
+
3680
+ ```ts
3681
+ function discard(branch: Branch): void;
3682
+ ```
3683
+
3684
+ Discard a branch: drop its sandbox and mark it spent. The target is
3685
+ never touched (nothing was promoted). Idempotent.
3686
+
3687
+ #### Parameters
3688
+
3689
+ | Parameter | Type |
3690
+ | :------ | :------ |
3691
+ | `branch` | [`Branch`](#branch) |
3692
+
3693
+ #### Returns
3694
+
3695
+ `void`
3696
+
3697
+ ***
3698
+
3699
+ <a id="fork"></a>
3700
+
3701
+ ### fork()
3702
+
3703
+ ```ts
3704
+ function fork(snapshot: SandboxSnapshot, rules?: string): Branch;
3705
+ ```
3706
+
3707
+ Fork a new branch from a snapshot.
3708
+
3709
+ Seeds a fresh sandbox with `rules` and the snapshot's Firestore docs
3710
+ (the same `seed({ rules, documents })` path replay uses to stand up a
3711
+ clean environment). The branch is fully isolated: writes on it never
3712
+ touch the source sandbox.
3713
+
3714
+ #### Parameters
3715
+
3716
+ | Parameter | Type | Description |
3717
+ | :------ | :------ | :------ |
3718
+ | `snapshot` | [`SandboxSnapshot`](#sandboxsnapshot-2) | Baseline state — typically `liveSandbox.snapshot()`. |
3719
+ | `rules?` | `string` | Rules source for the branch. Pass the live rules to reproduce production behaviour, or an *edited* ruleset to test a rules change in isolation (Studio F4). |
3720
+
3721
+ #### Returns
3722
+
3723
+ [`Branch`](#branch)
3724
+
3725
+ ***
3726
+
3727
+ <a id="initializesandbox"></a>
3728
+
3729
+ ### initializeSandbox()
3730
+
3731
+ ```ts
3732
+ function initializeSandbox(_config?: SandboxConfig): LocalSandbox;
3733
+ ```
3734
+
3735
+ Create a sandbox.
3736
+
3737
+ Identity is **not** part of init — call `sandbox.withAuth(...)` to
3738
+ derive a [SandboxContext](#sandboxcontext) for service operations. Service-
3739
+ specific configuration (rules, seed data) happens through service-specific
3740
+ sandbox controls — for example, `setRules(sandbox, source)` from
3741
+ `pyric/sandbox/firestore`.
3742
+
3743
+ #### Parameters
3744
+
3745
+ | Parameter | Type |
3746
+ | :------ | :------ |
3747
+ | `_config?` | [`SandboxConfig`](#sandboxconfig) |
3748
+
3749
+ #### Returns
3750
+
3751
+ [`LocalSandbox`](#localsandbox)
3752
+
3753
+ #### Example
3754
+
3755
+ ```ts
3756
+ import { initializeSandbox } from 'pyric/sandbox';
3757
+ import { getFirestore } from 'pyric-admin/firestore';
3758
+
3759
+ const sandbox = initializeSandbox();
3760
+ const dbAlice = getFirestore(sandbox.withAuth({ uid: 'alice' }));
3761
+ const dbAnon = getFirestore(sandbox.withAuth(null));
3762
+ ```
3763
+
3764
+ ***
3765
+
3766
+ <a id="isoperationevent"></a>
3767
+
3768
+ ### isOperationEvent()
3769
+
3770
+ ```ts
3771
+ function isOperationEvent(event: SandboxEvent): event is OperationEvent;
3772
+ ```
3773
+
3774
+ #### Parameters
3775
+
3776
+ | Parameter | Type |
3777
+ | :------ | :------ |
3778
+ | `event` | [`SandboxEvent`](#sandboxevent) |
3779
+
3780
+ #### Returns
3781
+
3782
+ `event is OperationEvent`
3783
+
3784
+ ***
3785
+
3786
+ <a id="isremotesandbox"></a>
3787
+
3788
+ ### isRemoteSandbox()
3789
+
3790
+ ```ts
3791
+ function isRemoteSandbox(sandbox: Sandbox): sandbox is RemoteSandbox;
3792
+ ```
3793
+
3794
+ Is this sandbox a remote handle? Backend dispatch guard for consumers
3795
+ (e.g. `pyric-admin`'s RTDB/Auth sandbox backends) that must route a
3796
+ remote sandbox's operations through [RemoteSandbox.channel](#channel) rather
3797
+ than into process-local state.
3798
+
3799
+ #### Parameters
3800
+
3801
+ | Parameter | Type |
3802
+ | :------ | :------ |
3803
+ | `sandbox` | [`Sandbox`](#sandbox-3) |
3804
+
3805
+ #### Returns
3806
+
3807
+ `sandbox is RemoteSandbox`
3808
+
3809
+ ***
3810
+
3811
+ <a id="operationcontextfor"></a>
3812
+
3813
+ ### operationContextFor()
3814
+
3815
+ ```ts
3816
+ function operationContextFor(event: Pick<EventProvenance, "operationContext" | "actor" | "authLens" | "planId">): OperationContext;
3817
+ ```
3818
+
3819
+ The canonical context on a recorded event. Old/pre-context events are
3820
+ explicitly unattributed rather than silently asserted to be app traffic.
3821
+
3822
+ #### Parameters
3823
+
3824
+ | Parameter | Type |
3825
+ | :------ | :------ |
3826
+ | `event` | `Pick`\<[`EventProvenance`](#eventprovenance), `"operationContext"` \| `"actor"` \| `"authLens"` \| `"planId"`\> |
3827
+
3828
+ #### Returns
3829
+
3830
+ [`OperationContext`](#operationcontext-2)
3831
+
3832
+ ***
3833
+
3834
+ <a id="parsebundle"></a>
3835
+
3836
+ ### parseBundle()
3837
+
3838
+ ```ts
3839
+ function parseBundle(blob: string): Map<string, unknown>;
3840
+ ```
3841
+
3842
+ Parse a v3 bundle blob back into records. Returns an empty map for an
3843
+ unrecognized blob (e.g. a legacy v2 single-blob snapshot); migrate-on-open (a
3844
+ later commit) handles converting a v2 blob to v3 records.
3845
+
3846
+ #### Parameters
3847
+
3848
+ | Parameter | Type |
3849
+ | :------ | :------ |
3850
+ | `blob` | `string` |
3851
+
3852
+ #### Returns
3853
+
3854
+ `Map`\<`string`, `unknown`\>
3855
+
3856
+ ***
3857
+
3858
+ <a id="promote"></a>
3859
+
3860
+ ### promote()
3861
+
3862
+ ```ts
3863
+ function promote(branch: Branch, target: LocalSandbox): void;
3864
+ ```
3865
+
3866
+ Promote a branch's mutations onto a target (live) sandbox.
3867
+
3868
+ "Honest promote": it computes the doc-level delta between the branch's
3869
+ BASE snapshot and its current state — i.e. exactly what the applied
3870
+ events changed — and lands only those mutations on the target through
3871
+ the admin plane:
3872
+ - docs added/changed on the branch → `admin.setDocument`
3873
+ - docs deleted on the branch → `admin.deleteDocument`
3874
+ - docs the branch never touched → left untouched on the target
3875
+
3876
+ Admin-plane application fires the target's listeners (matching how
3877
+ persistence restore lands docs), so live UI/handles see the promotion.
3878
+
3879
+ The branch is marked discarded afterward — a promoted branch is spent.
3880
+
3881
+ #### Parameters
3882
+
3883
+ | Parameter | Type | Description |
3884
+ | :------ | :------ | :------ |
3885
+ | `branch` | [`Branch`](#branch) | The experiment to land. |
3886
+ | `target` | [`LocalSandbox`](#localsandbox) | The live sandbox to land it on. |
3887
+
3888
+ #### Returns
3889
+
3890
+ `void`
3891
+
3892
+ ***
3893
+
3894
+ <a id="recordbackendoverblob"></a>
3895
+
3896
+ ### recordBackendOverBlob()
3897
+
3898
+ ```ts
3899
+ function recordBackendOverBlob(io: {
3900
+ clear: Promise<void>;
3901
+ read: Promise<string>;
3902
+ write: Promise<void>;
3903
+ }): PersistenceBackend;
3904
+ ```
3905
+
3906
+ A record-shaped backend over a single-blob store (read/write/clear ONE blob).
3907
+ The whole record set is bundled into that blob, for serve's committable export
3908
+ file / HTTP state endpoint and any single-key store. It loses chunking's scale
3909
+ benefit by design (the blob IS the single artifact). The blob is loaded once and
3910
+ cached, so a restore (list + per-record get) costs one read, not one per record.
3911
+
3912
+ #### Parameters
3913
+
3914
+ | Parameter | Type |
3915
+ | :------ | :------ |
3916
+ | `io` | \{ `clear`: `Promise`\<`void`\>; `read`: `Promise`\<`string`\>; `write`: `Promise`\<`void`\>; \} |
3917
+ | `io.clear` |
3918
+ | `io.read` |
3919
+ | `io.write` |
3920
+
3921
+ #### Returns
3922
+
3923
+ [`PersistenceBackend`](#persistencebackend)
3924
+
3925
+ ***
3926
+
3927
+ <a id="rehydratedocvalue"></a>
3928
+
3929
+ ### rehydrateDocValue()
3930
+
3931
+ ```ts
3932
+ function rehydrateDocValue(value: unknown): unknown;
3933
+ ```
3934
+
3935
+ Walk a parsed JSON tree and re-wrap any marker shape back into its real
3936
+ wrapper-class instance. Visits arrays and plain objects recursively. Plain
3937
+ values (and plain objects without a recognized discriminator) pass through.
3938
+
3939
+ This is the canonical rehydrate used by BOTH the sandbox persistence
3940
+ serializer and the SharedWorker wire protocol, so the IDB format and the
3941
+ MessagePort wire format are guaranteed identical.
3942
+
3943
+ #### Parameters
3944
+
3945
+ | Parameter | Type |
3946
+ | :------ | :------ |
3947
+ | `value` | `unknown` |
3948
+
3949
+ #### Returns
3950
+
3951
+ `unknown`
3952
+
3953
+ ***
3954
+
3955
+ <a id="replay-1"></a>
3956
+
3957
+ ### replay()
3958
+
3959
+ ```ts
3960
+ function replay(
3961
+ events: readonly SandboxEvent[],
3962
+ rules: string,
3963
+ options?: ReplayOptions,
3964
+ originalState?: Record<string, DocData>): ReplayResult;
3965
+ ```
3966
+
3967
+ Replay a captured SandboxEvent stream on a fresh sandbox.
3968
+
3969
+ The `originalState` snapshot is optional — when provided, the engine
3970
+ diffs the replayed sandbox's final state against it and returns
3971
+ classified divergences. When omitted, divergences is `[]` (you still
3972
+ get the replayed sandbox; you can inspect its state manually).
3973
+
3974
+ #### Parameters
3975
+
3976
+ | Parameter | Type |
3977
+ | :------ | :------ |
3978
+ | `events` | readonly [`SandboxEvent`](#sandboxevent)[] |
3979
+ | `rules` | `string` |
3980
+ | `options?` | [`ReplayOptions`](#replayoptions) |
3981
+ | `originalState?` | `Record`\<`string`, `DocData`\> |
3982
+
3983
+ #### Returns
3984
+
3985
+ [`ReplayResult`](#replayresult)
3986
+
3987
+ ***
3988
+
3989
+ <a id="rulesdispositionfor"></a>
3990
+
3991
+ ### rulesDispositionFor()
3992
+
3993
+ ```ts
3994
+ function rulesDispositionFor(event: OperationEvent): RulesDisposition;
3995
+ ```
3996
+
3997
+ Normalize the legacy per-service markers exactly once, at the sandbox
3998
+ stream seam. Consumers must not inspect `detail.admin`, `origin`, or the
3999
+ presence of a trace themselves.
4000
+
4001
+ #### Parameters
4002
+
4003
+ | Parameter | Type |
4004
+ | :------ | :------ |
4005
+ | `event` | `OperationEvent` |
4006
+
4007
+ #### Returns
4008
+
4009
+ [`RulesDisposition`](#rulesdisposition-2)
4010
+
4011
+ ***
4012
+
4013
+ <a id="serializetobuckets"></a>
4014
+
4015
+ ### serializeToBuckets()
4016
+
4017
+ ```ts
4018
+ function serializeToBuckets(
4019
+ firestore: Record<string, Record<string, unknown>>,
4020
+ services: Record<string, unknown>,
4021
+ savedAt: number): Map<string, BucketRecord | MetaRecord>;
4022
+ ```
4023
+
4024
+ Partition a firestore doc map into v3 records: one bucket record per occupied
4025
+ bucket plus the `meta` record. The returned map's keys are record ids; values
4026
+ are structured-clone-safe.
4027
+
4028
+ #### Parameters
4029
+
4030
+ | Parameter | Type |
4031
+ | :------ | :------ |
4032
+ | `firestore` | `Record`\<`string`, `Record`\<`string`, `unknown`\>\> |
4033
+ | `services` | `Record`\<`string`, `unknown`\> |
4034
+ | `savedAt` | `number` |
4035
+
4036
+ #### Returns
4037
+
4038
+ `Map`\<`string`, `BucketRecord` \| `MetaRecord`\>
4039
+
4040
+ ***
4041
+
4042
+ <a id="tooperationrecord"></a>
4043
+
4044
+ ### toOperationRecord()
4045
+
4046
+ ```ts
4047
+ function toOperationRecord(event: SandboxEvent): OperationRecord;
4048
+ ```
4049
+
4050
+ Project either traffic event family into the canonical record.
4051
+
4052
+ #### Parameters
4053
+
4054
+ | Parameter | Type |
4055
+ | :------ | :------ |
4056
+ | `event` | [`SandboxEvent`](#sandboxevent) |
4057
+
4058
+ #### Returns
4059
+
4060
+ [`OperationRecord`](#operationrecord)