@pyric/cli 0.1.0-alpha.27 → 0.1.0-alpha.29

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 (283) hide show
  1. package/dist/assurance/.generated/conformance-verdicts.d.ts +16 -0
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  3. package/dist/assurance/.generated/conformance-verdicts.js +16 -0
  4. package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
  5. package/dist/bridge/surface/arguments/assurance.d.ts +6 -6
  6. package/dist/bridge/surface/arguments/messaging.d.ts +2 -2
  7. package/dist/bridge/surface/methods/assurance/map.d.ts +6 -6
  8. package/dist/bridge/surface/methods/assurance/replaySession.d.ts.map +1 -1
  9. package/dist/bridge/surface/methods/assurance/replaySession.js +18 -6
  10. package/dist/bridge/surface/methods/assurance/replaySession.js.map +1 -1
  11. package/dist/bridge/surface/methods/messaging/send.d.ts +4 -4
  12. package/dist/bridge/surface/render/discriminator-schemas.d.ts +4 -4
  13. package/dist/cli/index.d.ts +1 -0
  14. package/dist/cli/index.d.ts.map +1 -1
  15. package/dist/cli/index.js +15 -1
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/cli/run.d.ts +42 -0
  18. package/dist/cli/run.d.ts.map +1 -0
  19. package/dist/cli/run.js +115 -0
  20. package/dist/cli/run.js.map +1 -0
  21. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  22. package/dist/conformance/.generated/can-i-use.js +1 -1
  23. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  24. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
  25. package/dist/conformance/.generated/conformance-docs.js +1 -1
  26. package/dist/conformance/.generated/conformance-docs.js.map +1 -1
  27. package/dist/remote/local-storage-url.d.ts +2 -15
  28. package/dist/remote/local-storage-url.d.ts.map +1 -1
  29. package/dist/remote/local-storage-url.js +1 -60
  30. package/dist/remote/local-storage-url.js.map +1 -1
  31. package/dist/serve/assets/avatar-route.d.ts.map +1 -1
  32. package/dist/serve/assets/avatar-route.js +6 -6
  33. package/dist/serve/assets/avatar-route.js.map +1 -1
  34. package/dist/serve/assets/resolver.d.ts +3 -0
  35. package/dist/serve/assets/resolver.d.ts.map +1 -1
  36. package/dist/serve/assets/resolver.js +1 -1
  37. package/dist/serve/assets/resolver.js.map +1 -1
  38. package/dist/serve/entries/app-client.d.ts.map +1 -1
  39. package/dist/serve/entries/app-client.js +6 -0
  40. package/dist/serve/entries/app-client.js.map +1 -1
  41. package/dist/serve/site-ui/_astro/{RulesCodeEditor.kBYcclwV.js → RulesCodeEditor.Cp_-FK3b.js} +1 -1
  42. package/dist/serve/site-ui/_astro/app.C--T2qDK.js +151 -0
  43. package/dist/serve/site-ui/_astro/app.DqyhRyrU.js +1 -0
  44. package/dist/serve/site-ui/_astro/{chess-showcase.CZe_3fJZ.js → chess-showcase.CVhCNUi_.js} +1 -1
  45. package/dist/serve/site-ui/_astro/{example-runtime.CXSZXHZF.js → example-runtime.zC1l-Yka.js} +1 -1
  46. package/dist/serve/site-ui/_astro/{sandbox-controls.Bp5PoonS.js → sandbox-controls.Bv6lfpIe.js} +39 -39
  47. package/dist/serve/site-ui/_astro/{seed.BpXSRzLo.js → seed.B4vza_Bv.js} +1 -1
  48. package/dist/serve/site-ui/_astro/{writes.DHSW22XD.js → writes.Bg0YEEA7.js} +1 -1
  49. package/dist/serve/site-ui/auth/index.html +1 -1
  50. package/dist/serve/site-ui/docs/_rhythm/index.html +1 -1
  51. package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +1 -1
  52. package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +1 -1
  53. package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +1 -1
  54. package/dist/serve/site-ui/docs/ai-compat/index.html +1 -1
  55. package/dist/serve/site-ui/docs/api-reference/index.html +2 -1
  56. package/dist/serve/site-ui/docs/api-reference.md +1 -0
  57. package/dist/serve/site-ui/docs/app-compat/index.html +1 -1
  58. package/dist/serve/site-ui/docs/auth-compat/index.html +2 -2
  59. package/dist/serve/site-ui/docs/auth-compat.md +1 -1
  60. package/dist/serve/site-ui/docs/auth-flutter-compat/index.html +1 -1
  61. package/dist/serve/site-ui/docs/auth-kotlin-compat/index.html +1 -1
  62. package/dist/serve/site-ui/docs/auth-swift-compat/index.html +1 -1
  63. package/dist/serve/site-ui/docs/build/ai-logic/index.html +1 -1
  64. package/dist/serve/site-ui/docs/build/authentication/index.html +1 -1
  65. package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +1 -1
  66. package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +1 -1
  67. package/dist/serve/site-ui/docs/build/cloud-storage/index.html +13 -2
  68. package/dist/serve/site-ui/docs/build/cloud-storage.md +23 -0
  69. package/dist/serve/site-ui/docs/build/default-avatars/index.html +1 -1
  70. package/dist/serve/site-ui/docs/build/inspect-activity/index.html +1 -1
  71. package/dist/serve/site-ui/docs/build/realtime-database/index.html +1 -1
  72. package/dist/serve/site-ui/docs/conformance-scores/index.html +1 -1
  73. package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +1 -1
  74. package/dist/serve/site-ui/docs/database-compat/index.html +18 -18
  75. package/dist/serve/site-ui/docs/database-compat.md +17 -17
  76. package/dist/serve/site-ui/docs/examples/chess/index.html +1 -1
  77. package/dist/serve/site-ui/docs/examples/index.html +1 -1
  78. package/dist/serve/site-ui/docs/firestore-compat/index.html +1 -1
  79. package/dist/serve/site-ui/docs/firestore-flutter-compat/index.html +1 -1
  80. package/dist/serve/site-ui/docs/firestore-kotlin-compat/index.html +1 -1
  81. package/dist/serve/site-ui/docs/firestore-swift-compat/index.html +1 -1
  82. package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +1 -1
  83. package/dist/serve/site-ui/docs/get-started/backend-bundlers/index.html +1 -1
  84. package/dist/serve/site-ui/docs/get-started/flutter/index.html +1 -1
  85. package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +1 -1
  86. package/dist/serve/site-ui/docs/get-started/nextjs/index.html +1 -1
  87. package/dist/serve/site-ui/docs/get-started/node-host/index.html +1 -1
  88. package/dist/serve/site-ui/docs/get-started/start-building/index.html +1 -1
  89. package/dist/serve/site-ui/docs/get-started/vite/index.html +4 -2
  90. package/dist/serve/site-ui/docs/get-started/vite.md +4 -0
  91. package/dist/serve/site-ui/docs/index.json +60 -10
  92. package/dist/serve/site-ui/docs/messaging-compat/index.html +1 -1
  93. package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +1 -1
  94. package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +1 -1
  95. package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +1 -1
  96. package/dist/serve/site-ui/docs/observe/switch-and-impersonate-identities/index.html +1 -1
  97. package/dist/serve/site-ui/docs/overview/index.html +1 -1
  98. package/dist/serve/site-ui/docs/pyric-admin-app-check-reference-api/index.html +1 -1
  99. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
  100. package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  101. package/dist/serve/site-ui/docs/pyric-admin-data-connect-reference-api/index.html +1 -1
  102. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
  103. package/dist/serve/site-ui/docs/pyric-admin-eventarc-reference-api/index.html +1 -1
  104. package/dist/serve/site-ui/docs/pyric-admin-extensions-reference-api/index.html +1 -1
  105. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
  106. package/dist/serve/site-ui/docs/pyric-admin-functions-reference-api/index.html +1 -1
  107. package/dist/serve/site-ui/docs/pyric-admin-installations-reference-api/index.html +1 -1
  108. package/dist/serve/site-ui/docs/pyric-admin-instance-id-reference-api/index.html +1 -1
  109. package/dist/serve/site-ui/docs/pyric-admin-machine-learning-reference-api/index.html +1 -1
  110. package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +1 -1
  111. package/dist/serve/site-ui/docs/pyric-admin-phone-number-verification-reference-api/index.html +1 -1
  112. package/dist/serve/site-ui/docs/pyric-admin-project-management-reference-api/index.html +1 -1
  113. package/dist/serve/site-ui/docs/pyric-admin-reference-api/index.html +1 -1
  114. package/dist/serve/site-ui/docs/pyric-admin-remote-config-reference-api/index.html +1 -1
  115. package/dist/serve/site-ui/docs/pyric-admin-security-rules-reference-api/index.html +1 -1
  116. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
  117. package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +1 -1
  118. package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  119. package/dist/serve/site-ui/docs/pyric-analytics-reference-api/index.html +1 -1
  120. package/dist/serve/site-ui/docs/pyric-app-check-reference-api/index.html +1 -1
  121. package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +1 -1
  122. package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +2 -2
  123. package/dist/serve/site-ui/docs/pyric-auth-reference-api.md +1 -1
  124. package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  125. package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  126. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
  127. package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  128. package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api/index.html +1 -1
  129. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
  130. package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  131. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
  132. package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  133. package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  134. package/dist/serve/site-ui/docs/pyric-cli-flow-reference-api/index.html +1 -1
  135. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +1 -1
  136. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +1 -1
  137. package/dist/serve/site-ui/docs/pyric-cli-register-client-app-bridge-reference-api/index.html +1 -1
  138. package/dist/serve/site-ui/docs/pyric-cli-register-client-app-reference-api/index.html +1 -1
  139. package/dist/serve/site-ui/docs/pyric-cli-register-client-auth-reference-api/index.html +1 -1
  140. package/dist/serve/site-ui/docs/pyric-cli-register-client-database-reference-api/index.html +1 -1
  141. package/dist/serve/site-ui/docs/pyric-cli-register-client-firestore-reference-api/index.html +1 -1
  142. package/dist/serve/site-ui/docs/pyric-cli-register-client-storage-reference-api/index.html +1 -1
  143. package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  144. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
  145. package/dist/serve/site-ui/docs/pyric-cli-repro-reference-api/index.html +1 -1
  146. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +1 -1
  147. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
  148. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +17 -3
  149. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api.md +7 -5
  150. package/dist/serve/site-ui/docs/pyric-cli-vite-ssr-loader-reference-api/index.html +1 -1
  151. package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +1 -1
  152. package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api/index.html +1 -1
  153. package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +1 -1
  154. package/dist/serve/site-ui/docs/pyric-functions-reference-api/index.html +1 -1
  155. package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  156. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  157. package/dist/serve/site-ui/docs/pyric-performance-reference-api/index.html +1 -1
  158. package/dist/serve/site-ui/docs/pyric-remote-config-reference-api/index.html +1 -1
  159. package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +120 -120
  160. package/dist/serve/site-ui/docs/pyric-rules-reference-api.md +53 -53
  161. package/dist/serve/site-ui/docs/pyric-sandbox-branches-store-reference-api/index.html +1 -1
  162. package/dist/serve/site-ui/docs/pyric-sandbox-checkpoints-directory-reference-api/index.html +1 -1
  163. package/dist/serve/site-ui/docs/pyric-sandbox-checkpoints-reference-api/index.html +1 -1
  164. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +1 -1
  165. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  166. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +1 -1
  167. package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +1 -1
  168. package/dist/serve/site-ui/docs/pyric-storage-sw-reference-api/index.html +102 -0
  169. package/dist/serve/site-ui/docs/pyric-storage-sw-reference-api.md +76 -0
  170. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
  171. package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  172. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
  173. package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  174. package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  175. package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  176. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
  177. package/dist/serve/site-ui/docs/pyric-ui-listener-owner-reference-api/index.html +1 -1
  178. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
  179. package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  180. package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  181. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
  182. package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  183. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +1 -1
  184. package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  185. package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  186. package/dist/serve/site-ui/docs/reference/cli/index.html +12 -2
  187. package/dist/serve/site-ui/docs/reference/cli.md +24 -0
  188. package/dist/serve/site-ui/docs/rtdb-flutter-compat/index.html +1 -1
  189. package/dist/serve/site-ui/docs/rtdb-kotlin-compat/index.html +1 -1
  190. package/dist/serve/site-ui/docs/rtdb-swift-compat/index.html +1 -1
  191. package/dist/serve/site-ui/docs/rules-compat/index.html +68 -4
  192. package/dist/serve/site-ui/docs/rules-compat.md +67 -3
  193. package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +1 -1
  194. package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  195. package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +1 -1
  196. package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  197. package/dist/serve/site-ui/docs/secure/rtdb-rules-standard-library/index.html +18 -5
  198. package/dist/serve/site-ui/docs/secure/rtdb-rules-standard-library.md +19 -4
  199. package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +1 -1
  200. package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  201. package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +5 -5
  202. package/dist/serve/site-ui/docs/secure/simulate-and-lint.md +8 -8
  203. package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  204. package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +1 -1
  205. package/dist/serve/site-ui/docs/ship/test-in-node/index.html +1 -1
  206. package/dist/serve/site-ui/docs/storage-compat/index.html +1 -1
  207. package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  208. package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +1 -1
  209. package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  210. package/dist/serve/site-ui/docs/tutorial/index.html +1 -1
  211. package/dist/serve/site-ui/examples/chess/index.html +1 -1
  212. package/dist/serve/site-ui/firestore/index.html +1 -1
  213. package/dist/serve/site-ui/llms.txt +1 -0
  214. package/dist/serve/site-ui/rtdb/index.html +1 -1
  215. package/dist/serve/site-ui/settings/index.html +1 -1
  216. package/dist/serve/site-ui/storage/index.html +1 -1
  217. package/dist/serve/site-ui/studio/index.html +1 -1
  218. package/dist/serve/site-ui/traffic/index.html +1 -1
  219. package/dist/serve/vite-plugin.d.ts +6 -0
  220. package/dist/serve/vite-plugin.d.ts.map +1 -1
  221. package/dist/serve/vite-plugin.js +11 -1
  222. package/dist/serve/vite-plugin.js.map +1 -1
  223. package/dist/serve/vite-service-worker.d.ts +12 -0
  224. package/dist/serve/vite-service-worker.d.ts.map +1 -0
  225. package/dist/serve/vite-service-worker.js +33 -0
  226. package/dist/serve/vite-service-worker.js.map +1 -0
  227. package/dist/serve/worker/client/auth.d.ts.map +1 -1
  228. package/dist/serve/worker/client/auth.js +4 -3
  229. package/dist/serve/worker/client/auth.js.map +1 -1
  230. package/dist/serve/worker/client/rtdb-info.d.ts +0 -2
  231. package/dist/serve/worker/client/rtdb-info.d.ts.map +1 -1
  232. package/dist/serve/worker/client/rtdb-info.js +4 -17
  233. package/dist/serve/worker/client/rtdb-info.js.map +1 -1
  234. package/dist/serve/worker/client/rtdb-reads.d.ts.map +1 -1
  235. package/dist/serve/worker/client/rtdb-reads.js +3 -5
  236. package/dist/serve/worker/client/rtdb-reads.js.map +1 -1
  237. package/dist/serve/worker/host/auth-action-codes.js +2 -2
  238. package/dist/serve/worker/host/auth-action-codes.js.map +1 -1
  239. package/dist/serve/worker/host/auth-custom-token.d.ts.map +1 -1
  240. package/dist/serve/worker/host/auth-custom-token.js +4 -2
  241. package/dist/serve/worker/host/auth-custom-token.js.map +1 -1
  242. package/dist/serve/worker/host/dispatch.d.ts.map +1 -1
  243. package/dist/serve/worker/host/dispatch.js +3 -1
  244. package/dist/serve/worker/host/dispatch.js.map +1 -1
  245. package/dist/serve/worker/host-auth.d.ts +6 -0
  246. package/dist/serve/worker/host-auth.d.ts.map +1 -1
  247. package/dist/serve/worker/host-auth.js +16 -5
  248. package/dist/serve/worker/host-auth.js.map +1 -1
  249. package/dist/serve/worker/inbound-validation.d.ts.map +1 -1
  250. package/dist/serve/worker/inbound-validation.js +1 -0
  251. package/dist/serve/worker/inbound-validation.js.map +1 -1
  252. package/dist/serve/worker/protocol/storage.d.ts +1 -8
  253. package/dist/serve/worker/protocol/storage.d.ts.map +1 -1
  254. package/dist/serve/worker/protocol/storage.js +2 -14
  255. package/dist/serve/worker/protocol/storage.js.map +1 -1
  256. package/dist/serve/worker/protocol.d.ts +2 -0
  257. package/dist/serve/worker/protocol.d.ts.map +1 -1
  258. package/dist/serve/worker/protocol.js.map +1 -1
  259. package/package.json +12 -8
  260. package/src/assurance/.generated/conformance-verdicts.ts +16 -0
  261. package/src/bridge/surface/methods/assurance/replaySession.ts +19 -6
  262. package/src/cli/index.ts +15 -1
  263. package/src/cli/run.ts +139 -0
  264. package/src/conformance/.generated/can-i-use.ts +1 -1
  265. package/src/conformance/.generated/conformance-docs.ts +1 -1
  266. package/src/remote/local-storage-url.ts +1 -58
  267. package/src/serve/assets/avatar-route.ts +6 -7
  268. package/src/serve/assets/resolver.ts +4 -1
  269. package/src/serve/entries/app-client.ts +7 -0
  270. package/src/serve/vite-plugin.ts +15 -1
  271. package/src/serve/vite-service-worker.ts +44 -0
  272. package/src/serve/worker/client/auth.ts +4 -3
  273. package/src/serve/worker/client/rtdb-info.ts +4 -17
  274. package/src/serve/worker/client/rtdb-reads.ts +3 -4
  275. package/src/serve/worker/host/auth-action-codes.ts +2 -2
  276. package/src/serve/worker/host/auth-custom-token.ts +4 -2
  277. package/src/serve/worker/host/dispatch.ts +2 -0
  278. package/src/serve/worker/host-auth.ts +18 -5
  279. package/src/serve/worker/inbound-validation.ts +1 -0
  280. package/src/serve/worker/protocol/storage.ts +2 -14
  281. package/src/serve/worker/protocol.ts +2 -0
  282. package/dist/serve/site-ui/_astro/app.CiMHEvEW.js +0 -147
  283. package/dist/serve/site-ui/_astro/app.DpzsBfos.js +0 -1
@@ -1,4 +1,4 @@
1
- import{s as f,b7 as h,b8 as w}from"./sandbox-controls.Bp5PoonS.js";import{s as o,d as s}from"./writes.DHSW22XD.js";import{s as n,a as A,b as y,u as m,r as d}from"./app.CiMHEvEW.js";import"./index.DBy5LfQW.js";import"./index.DNyk7q8W.js";class g{static serverTimestamp(){return{__type:"serverTimestamp"}}static increment(a){return{__type:"increment",value:a}}static arrayUnion(...a){return{__type:"arrayUnion",values:a}}static arrayRemove(...a){return{__type:"arrayRemove",values:a}}static delete(){return{__type:"deleteField"}}}function p(){return g.serverTimestamp()}async function b(t){n.createUser(t,{uid:"alice",email:"alice@gmail.com",displayName:"Alice Nguyen",emailVerified:!0,photoUrl:"https://lh3.googleusercontent.com/a/alice",providerUserInfo:[{providerId:"google.com"}],customClaims:{plan:"pro"}}),n.createUser(t,{uid:"bob",email:"bob@example.com",password:"pyric-demo",displayName:"Bob Carter",emailVerified:!0,customClaims:{role:"editor"}}),n.createUser(t,{uid:"carol",email:"carol@example.com",displayName:"Carol Diaz",emailVerified:!1}),await A(t),await y(t)}const v=new w(37.7749,-122.4194);async function R(t){const a=Date.now(),i=e=>h.fromMillis(a-e*6e4),l=[{id:"alice",name:"Alice Nguyen",email:"alice@gmail.com",plan:"pro"},{id:"bob",name:"Bob Carter",email:"bob@example.com",plan:"free"},{id:"carol",name:"Carol Diaz",email:"carol@example.com",plan:"free"}];for(const e of l)await o(s(t,"users",e.id),{name:e.name,email:e.email,plan:e.plan,createdAt:p()});const r=["alice","bob","carol"],c=["Ship the redesign","Reply to carol","Buy milk","Draft the launch post","Review the rules","Plan offsite","Renew the domain","Read the spec","Fix the flaky test","Call the bank","Water the plants","Book the flights"];for(let e=0;e<c.length;e++){const u=r[e%r.length];await o(s(t,"notes",`note-${String(e+1).padStart(2,"0")}`),{title:c[e],done:e%3===0,pinned:e===0,priority:e%3+1,ownerId:u,ownerRef:`users/${u}`,tags:e%2===0?["work","urgent"]:["personal"],meta:{source:e%2===0?"app":"import",revision:e+1,flags:{starred:e%4===0,archived:!1}},location:e%3===0?v:null,createdAt:i(120-e*7),updatedAt:p()})}await o(s(t,"posts","post-hello"),{title:"Hello world",body:"First post from the seeded sandbox.",authorRef:"users/alice",published:!0,publishedAt:i(8)}),await o(s(t,"posts","post-draft"),{title:"Draft: roadmap",body:"Unpublished draft.",authorRef:"users/bob",published:!1})}async function C(t){const a=new TextEncoder,l=Uint8Array.from(atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="),r=>r.charCodeAt(0));await m(d(t,"avatars/alice.png"),l,{contentType:"image/png"}),await m(d(t,"notes/note-01/attachment.txt"),a.encode(`Attachment for the redesign note.
1
+ import{s as f,b8 as h,b9 as w}from"./sandbox-controls.Bv6lfpIe.js";import{s as o,d as s}from"./writes.Bg0YEEA7.js";import{s as n,a as A,b as y,u as m,r as d}from"./app.C--T2qDK.js";import"./index.DBy5LfQW.js";import"./index.DNyk7q8W.js";class g{static serverTimestamp(){return{__type:"serverTimestamp"}}static increment(a){return{__type:"increment",value:a}}static arrayUnion(...a){return{__type:"arrayUnion",values:a}}static arrayRemove(...a){return{__type:"arrayRemove",values:a}}static delete(){return{__type:"deleteField"}}}function p(){return g.serverTimestamp()}async function b(t){n.createUser(t,{uid:"alice",email:"alice@gmail.com",displayName:"Alice Nguyen",emailVerified:!0,photoUrl:"https://lh3.googleusercontent.com/a/alice",providerUserInfo:[{providerId:"google.com"}],customClaims:{plan:"pro"}}),n.createUser(t,{uid:"bob",email:"bob@example.com",password:"pyric-demo",displayName:"Bob Carter",emailVerified:!0,customClaims:{role:"editor"}}),n.createUser(t,{uid:"carol",email:"carol@example.com",displayName:"Carol Diaz",emailVerified:!1}),await A(t),await y(t)}const v=new w(37.7749,-122.4194);async function R(t){const a=Date.now(),i=e=>h.fromMillis(a-e*6e4),l=[{id:"alice",name:"Alice Nguyen",email:"alice@gmail.com",plan:"pro"},{id:"bob",name:"Bob Carter",email:"bob@example.com",plan:"free"},{id:"carol",name:"Carol Diaz",email:"carol@example.com",plan:"free"}];for(const e of l)await o(s(t,"users",e.id),{name:e.name,email:e.email,plan:e.plan,createdAt:p()});const r=["alice","bob","carol"],c=["Ship the redesign","Reply to carol","Buy milk","Draft the launch post","Review the rules","Plan offsite","Renew the domain","Read the spec","Fix the flaky test","Call the bank","Water the plants","Book the flights"];for(let e=0;e<c.length;e++){const u=r[e%r.length];await o(s(t,"notes",`note-${String(e+1).padStart(2,"0")}`),{title:c[e],done:e%3===0,pinned:e===0,priority:e%3+1,ownerId:u,ownerRef:`users/${u}`,tags:e%2===0?["work","urgent"]:["personal"],meta:{source:e%2===0?"app":"import",revision:e+1,flags:{starred:e%4===0,archived:!1}},location:e%3===0?v:null,createdAt:i(120-e*7),updatedAt:p()})}await o(s(t,"posts","post-hello"),{title:"Hello world",body:"First post from the seeded sandbox.",authorRef:"users/alice",published:!0,publishedAt:i(8)}),await o(s(t,"posts","post-draft"),{title:"Draft: roadmap",body:"Unpublished draft.",authorRef:"users/bob",published:!1})}async function C(t){const a=new TextEncoder,l=Uint8Array.from(atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="),r=>r.charCodeAt(0));await m(d(t,"avatars/alice.png"),l,{contentType:"image/png"}),await m(d(t,"notes/note-01/attachment.txt"),a.encode(`Attachment for the redesign note.
2
2
  `),{contentType:"text/plain"})}const U=`rules_version = '2';
3
3
  service cloud.firestore {
4
4
  match /databases/{database}/documents {
@@ -1 +1 @@
1
- import{c as jt,b9 as ve,aO as ne,aB as f,ba as _t,bb as Tt,b7 as le,bc as Pt,bd as qt,be as M,aJ as K,bf as Vt,bg as Mt,ay as et,bh as Re,ax as Oe,bi as P,bj as ke,bk as j,aP as tt,bl as ce,bm as It,bn as $t,U as nt,G as w,aA as T,aL as zt,bo as Lt,bp as Qt,bq as Ut,P as Ee,F as I,br as Fe,C as Wt,D as Nt,b6 as Bt,b8 as Gt,bs as Ht,bt as Yt,N as Jt,ab as Xt,bu as Kt,Q as Zt,bv as en,bw as tn}from"./sandbox-controls.Bp5PoonS.js";const nn=Symbol.for("pyric.remote.sandbox");function Ce(e){return e!=null&&e[nn]===!0}let Z;function ts(e){Z=e}function st(e){return Z?.resolve(e,!1)}function sn(){if(!Z)throw new TypeError("No default sandbox app registry is installed - import and initialize pyric/app before calling a service factory without an app.");return Z.defaultApp()}function Me(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:void 0}function rn(e,t,n,s){const r={collectionGroup:e.split("/").filter(Boolean).at(-1)??"",queryScope:t?"COLLECTION_GROUP":"COLLECTION",filters:[],orders:[]},i=(o,a)=>{const c=Me(o);if(!c||a>12||r.filters.length>=64){r.unsupported="This query exceeds the index checker’s supported limits.";return}if(c.kind==="and"&&Array.isArray(c.filters)){c.filters.forEach(u=>i(u,a+1));return}if(c.kind!=="where"||typeof c.field!="string"||typeof c.op!="string"){r.unsupported="This query uses a filter the index checker does not support yet.";return}r.filters.push({field:c.field,op:c.op})};n.forEach(o=>i(o,0));for(const o of s.slice(0,64)){const a=Me(o);if(!a||typeof a.field!="string"||a.direction!=="asc"&&a.direction!=="desc"){r.unsupported="This sort order cannot be checked yet.";continue}r.orders.push({field:a.field,direction:a.direction})}return s.length>64&&(r.unsupported="This query exceeds the index checker’s supported limits."),r}async function se(e,t,n){try{const s=await t();return e.complete(n?.()),s}catch(s){throw e.fail(),s}}const Ie=new Set;function on(e){return Ie.add(e),()=>{Ie.delete(e)}}function ns(e={}){return jt()}function $(e){return e.replace(/^\/+|\/+$/g,"").split("/")}function rt(e){return $(e).length%2===0&&$(e).length>0}function Ae(e){return $(e).length%2===1}function re(e){const t=$(e);return t[t.length-1]??""}function it(e){return $(e).slice(0,-1).join("/")}function ot(e,t){const n=t!==void 0,s=n?ve(t):void 0;return{id:e.id,ref:e,exists:n,data:()=>n?s:void 0,get:r=>ne(s,r)}}const $e=200,B=10,an=4;function cn(e){return e.length<=$e?{type:"string",value:e}:{type:"string",value:e.slice(0,$e),truncated:!0}}function at(e,t){const n=e*1e3+Math.floor(t/1e6);if(!Number.isFinite(n))return{type:"opaque"};try{return{type:"timestamp",iso:new Date(n).toISOString()}}catch{return{type:"opaque"}}}function un(e){if(typeof e!="object"||e===null)return{type:"opaque"};const t=e;return typeof t.path=="string"?{type:"reference",path:t.path}:t.type==="timestamp"&&typeof t.seconds=="number"&&typeof t.nanoseconds=="number"?at(t.seconds,t.nanoseconds):t.type==="geo-point"&&typeof t.latitude=="number"&&typeof t.longitude=="number"?{type:"geoPoint",latitude:t.latitude,longitude:t.longitude}:t.type==="bytes"&&Array.isArray(t.values)?{type:"bytes",length:t.values.length}:t.type==="vector"&&Array.isArray(t.values)?{type:"vector",length:t.values.length}:{type:"opaque"}}function he(e,t){if(e===null)return{type:"null"};if(typeof e=="string")return cn(e);if(typeof e=="number")return{type:"number",value:e};if(typeof e=="boolean")return{type:"boolean",value:e};if(typeof e!="object")return{type:"opaque"};if(t>=an)return{type:"opaque"};const n=e;if(n.type==="registered-firestore-value")return un(n.value);if(n.type==="timestamp"&&typeof n.seconds=="number"&&typeof n.nanoseconds=="number")return at(n.seconds,n.nanoseconds);if(n.type==="bytes"&&Array.isArray(n.values))return{type:"bytes",length:n.values.length};if(n.type==="array"&&Array.isArray(n.values)){const s=n.values.slice(0,B).map(r=>he(r,t+1));return n.values.length>B?{type:"array",values:s,truncated:!0}:{type:"array",values:s}}if(n.type==="map"&&Array.isArray(n.entries)){const s=n.entries.slice(0,B).filter(r=>Array.isArray(r)&&typeof r[0]=="string").map(([r,i])=>[r,he(i,t+1)]);return n.entries.length>B?{type:"map",entries:s,truncated:!0}:{type:"map",entries:s}}return{type:"opaque"}}function ze(e){return he(e,0)}function fe(e){if(e===null||typeof e!="object")return JSON.stringify(e);if(Array.isArray(e))return`[${e.map(n=>fe(n)).join(",")}]`;const t=e;return`{${Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${fe(t[n])}`).join(",")}}`}function dn(e){if(e!==null&&typeof e=="object"){const n="type"in e&&e.type==="timestamp",s="seconds"in e&&typeof e.seconds=="number",r="nanoseconds"in e&&typeof e.nanoseconds=="number";return n&&s&&r}return!1}function E(e){return new f({code:"invalid-argument",message:e})}function pe(e,t,n,s=!1,r=!1){if(e===null||typeof e=="string"||typeof e=="boolean")return{comparison:e,execution:e};if(typeof e=="number")return{comparison:e,execution:e};if(typeof e>"u"||typeof e=="bigint"||typeof e=="function"||typeof e=="symbol")throw E(`Unsupported Firestore query value: ${typeof e}.`);if(typeof e!="object")throw E("Unsupported Firestore query value.");const u=_t(e);if(u!==void 0){const m=Tt(e);if(m!==void 0&&n!==void 0&&m!==n)throw E("Document reference belongs to a different Firestore database.");if(dn(u)){const p=Math.floor(u.nanoseconds/1e3)*1e3,g=new le(u.seconds,p);return{comparison:{type:"registered-firestore-value",value:Object.freeze({type:"timestamp",seconds:g.seconds,nanoseconds:p})},execution:g}}return{comparison:{type:"registered-firestore-value",value:u},execution:Pt(e)}}if(e instanceof Date){const m=e.getTime();if(!Number.isFinite(m))throw E("Invalid Date query value.");const S=Math.floor(m/1e3),p=Object.freeze({seconds:S,nanoseconds:Math.floor((m-S*1e3)*1e6)}),g={type:"timestamp",...p};return qt(p,g,()=>Object.freeze({...p})),{comparison:{type:"registered-firestore-value",value:g},execution:p}}if(e instanceof Uint8Array){const m=e.slice();return{comparison:{type:"bytes",values:Array.from(m)},execution:m}}if(t.has(e))throw E("Cyclic query operands are not Firestore values.");const b=Object.getPrototypeOf(e);if(b!==Object.prototype&&b!==null&&!Array.isArray(e))throw E("Firestore query maps must be plain objects.");t.add(e);try{if(Array.isArray(e)){if(r&&!s)throw E("Nested arrays are not supported.");const g=e.map(q=>pe(q,t,n,s,!0)),N=g.map(q=>q.execution);return M(N,K(e)),{comparison:{type:"array",values:g.map(q=>q.comparison)},execution:N}}const O=Object.keys(e).sort().map(p=>({key:p,captured:pe(e[p],t,n,s,!1)})),S=Object.fromEntries(O.map(({key:p,captured:g})=>[p,g.execution]));return M(S,K(e)),{comparison:{type:"map",entries:O.map(({key:p,captured:g})=>[p,g.comparison])},execution:S}}finally{t.delete(e)}}function ct(e,t,n=!1){try{const s=pe(e,new Set,t,n);return Object.freeze({kind:"canonical",value:s.comparison,executionValue:s.execution})}catch(s){if(s instanceof f)throw s;const r=s instanceof Error?s.message:String(s);throw E(`Invalid Firestore query value: ${r}`)}}function ut(e,t){return Vt(e.value,t.value)}const ln=["<","<=","==","!=",">=",">","in","not-in","array-contains","array-contains-any"],hn=new Set(ln);function fn(e,t){if(!hn.has(e))throw new f({code:"invalid-argument",message:"Unsupported Firestore filter operator."});if((e==="in"||e==="not-in"||e==="array-contains-any")&&!Array.isArray(t))throw new f({code:"invalid-argument",message:`Firestore ${e} filter requires an array operand.`})}function H(e,t){if(e.kind==="where"){fn(e.op,e.value);const s="comparisonValue"in e,r=e.op==="in"||e.op==="not-in",i=s?e.comparisonValue:ct(e.value,t,r);return Object.freeze({kind:"where",field:e.field,op:e.op,value:i.executionValue,comparisonValue:i})}return Object.freeze({kind:e.kind,filters:Object.freeze(e.filters.map(s=>H(s,t)))})}function G(e,t,n,s){const r=e.map(i=>ct(i,s));return Object.freeze({values:Object.freeze(r.map(i=>i.executionValue)),comparisonValues:Object.freeze(r),inclusive:t,fromSnapshot:n})}function dt(e,t){return e.length!==t.length?!1:e.every((n,s)=>{const r=t[s];return n.kind!==r.kind?!1:n.kind==="where"&&r.kind==="where"?n.field===r.field&&n.op===r.op&&ut(n.comparisonValue,r.comparisonValue):n.kind!=="where"&&r.kind!=="where"&&dt(n.filters,r.filters)})}function Le(e,t){return e===void 0||t===void 0?e===t:e.inclusive===t.inclusive&&e.comparisonValues.length===t.comparisonValues.length&&e.comparisonValues.every((n,s)=>ut(n,t.comparisonValues[s]))}function pn(e,t){return e.kind!==t.kind?!1:e.kind==="collection"&&t.kind==="collection"?e.path===t.path:e.kind==="collection-group"&&t.kind==="collection-group"&&e.collectionId===t.collectionId}function lt(e){return e.kind==="where"?Object.freeze({kind:e.kind,field:e.field,op:e.op,value:e.value}):Object.freeze({kind:e.kind,filters:Object.freeze(e.filters.map(lt))})}function Qe(e){if(e!==void 0)return Object.freeze({values:e.values,inclusive:e.inclusive,fromSnapshot:e.fromSnapshot})}function mn(e,t){return dt(e.filters,t.filters)&&e.orders.length===t.orders.length&&e.orders.every((n,s)=>{const r=t.orders[s];return n.field===r.field&&n.direction===r.direction})&&e.limitCount===t.limitCount&&e.limitFromEnd===t.limitFromEnd&&Le(e.start,t.start)&&Le(e.end,t.end)}const ht="__name__";function Ue(e,t){const n=e.data();if(n===void 0)throw new f({code:"not-found",message:`Snapshot-based cursors require an existing document — got an empty snapshot for ${e.id??"<unknown>"}.`});return t.map(s=>s.field===ht?e.ref:n[s.field])}class z{env;auth;collectionPath;clauses;orders;limitCount;limitFromEnd;start;end;bypassRules;documentRef;constructor(t){this.env=t.env,this.auth=t.auth,this.collectionPath=t.collectionPath,this.documentRef=t.documentRef,this.clauses=Object.freeze((t.clauses??[]).map(n=>H(n))),this.orders=Object.freeze((t.orders??[]).map(n=>Object.freeze({...n}))),this.limitCount=t.limitCount,this.limitFromEnd=t.limitFromEnd??!1,this.start=t.start===void 0?void 0:Object.freeze({...t.start,values:Object.freeze(t.start.comparisonValues.map(n=>n.executionValue)),comparisonValues:t.start.comparisonValues}),this.end=t.end===void 0?void 0:Object.freeze({...t.end,values:Object.freeze(t.end.comparisonValues.map(n=>n.executionValue)),comparisonValues:t.end.comparisonValues}),this.bypassRules=t.bypassRules??!1}where(t,n,s){return this.clone({clauses:[...this.clauses,H({kind:"where",field:t,op:n,value:s})]})}applyFilter(t){return this.clone({clauses:[...this.clauses,H(t)]})}orderBy(t,n="asc"){if(n!=="asc"&&n!=="desc")throw new f({code:"invalid-argument",message:"orderBy() direction must be 'asc' or 'desc'."});return this.clone({orders:[...this.orders,{field:t,direction:n}]})}limit(t){return We(t),this.clone({limitCount:t,limitFromEnd:!1})}limitToLast(t){return We(t),this.clone({limitCount:t,limitFromEnd:!0})}startCursor(t,n){return this.clone({start:G(this.normalizeExplicitCursorValues(t),n,!1)})}endCursor(t,n){return this.clone({end:G(this.normalizeExplicitCursorValues(t),n,!1)})}startCursorFromSnapshot(t,n){return this.clone({start:G(Ue(t,this.normalizedOrders()),n,!0)})}endCursorFromSnapshot(t,n){return this.clone({end:G(Ue(t,this.normalizedOrders()),n,!0)})}isStructurallyEqual(t){return t instanceof z?this.env===t.env&&this.bypassRules===t.bypassRules&&pn(this.queryScope(),t.queryScope())&&mn(this.comparableExecutionSpec(),t.comparableExecutionSpec()):!1}clone(t){return new z({env:this.env,auth:this.auth,collectionPath:this.collectionPath,documentRef:this.documentRef,clauses:t.clauses??this.clauses,orders:t.orders??this.orders,limitCount:"limitCount"in t?t.limitCount:this.limitCount,limitFromEnd:t.limitFromEnd??this.limitFromEnd,start:"start"in t?t.start:this.start,end:"end"in t?t.end:this.end,bypassRules:this.bypassRules})}queryScope(){return{kind:"collection",path:this.collectionPath}}sdkActivitySource(){const t=this.queryScope();return{service:"firestore",target:t.kind==="collection"?t.path:t.collectionId,key:fe({scope:t,query:this.activityQuery()}),isQuery:!0,indexQuery:rn(t.kind==="collection"?t.path:t.collectionId,t.kind==="collection-group",this.clauses,this.orders)}}readQueryRows(t){const n=t?.auth!==void 0?t.auth:this.auth;let s;try{s=this.env.runQuery({scope:this.queryScope(),auth:n,execution:this.executionSpec(),bypassRules:this.bypassRules,activityQuery:this.activityQuery()})}catch(r){const i=r?.simError;throw i?new f(i):r}if(!s.allowed)throw new f(s.error);return s.docs}activityQuery(){const t=s=>s.kind==="where"?{kind:"where",field:s.field,op:s.op,value:K(s.value),display:ze(s.comparisonValue.value)}:{kind:s.kind,filters:s.filters.map(t)},n=s=>s===void 0?null:{values:s.values.map(r=>K(r)),display:s.comparisonValues.map(r=>ze(r.value)),inclusive:s.inclusive,fromSnapshot:s.fromSnapshot};return{scope:this.activityScope(),filters:this.clauses.map(t),orderBy:this.orders.map(s=>({...s})),limit:this.limitCount??null,limitFromEnd:this.limitFromEnd,start:n(this.start),end:n(this.end)}}activityScope(){return{kind:"collection"}}normalizedOrders(){return Mt(this.executionSpec())}normalizeExplicitCursorValues(t){const n=this.orders;return t.map((s,r)=>{if(n[r]?.field!==ht)return s;if(typeof s!="string")throw new f({code:"invalid-argument",message:"Expected a string for a document ID cursor value."});const i=s.includes("/")?s:`${this.collectionPath}/${s}`;return this.documentRef(i)})}executionSpec(){const t={filters:Object.freeze(this.clauses.map(lt)),orders:this.orders,limitCount:this.limitCount,limitFromEnd:this.limitFromEnd,start:Qe(this.start),end:Qe(this.end)};return Object.freeze(t)}comparableExecutionSpec(){return{filters:this.clauses,orders:this.orders,limitCount:this.limitCount,limitFromEnd:this.limitFromEnd,start:this.start,end:this.end}}snapshotScope(){return this.queryScope()}snapshotConstraints(){return Object.freeze({execution:this.executionSpec(),activityQuery:this.activityQuery()})}async get(t){const s=this.readQueryRows(t).map(r=>{const i=this.documentRef(r.path),o=ve(r.data);return{id:i.id,ref:i,exists:!0,data:()=>o,get:a=>ne(o,a)}});return{size:s.length,empty:s.length===0,docs:s,forEach:et(s)}}async aggregate(t,n){const s=this.readQueryRows(n),r={};for(const i of Object.keys(t))r[i]=bn(t[i],s);return{data:()=>r}}}function yn(e,t){if(!t.includes("."))return e[t];let n=e;for(const s of t.split(".")){if(typeof n!="object"||n===null||Array.isArray(n))return;n=n[s]}return n}function bn(e,t){if(e.kind==="count")return t.length;let n=0,s=0;for(const r of t){const i=yn(r.data,e.field);typeof i=="number"&&Number.isFinite(i)&&(n+=i,s++)}return e.kind==="sum"?n:s===0?null:n/s}function We(e){if(!Number.isFinite(e))throw new f({code:"invalid-argument",message:"Query limit must be a finite number."})}function D(e,t){if(e.error)throw new f(e.error);const n=e.debugMessages.length>0?e.debugMessages.join("; "):"(no debug message)";throw new f(j("permission-denied",`${t}: ${n}`))}class gn{env;auth;bypassRules;collectionRef;id;path;constructor(t,n,s,r=!1,i){this.env=t,this.auth=n,this.bypassRules=r,this.collectionRef=i,this.path=s,this.id=re(s),M(this,Re("reference",s)),Oe(this,s,t)}get parent(){return this.collectionRef(it(this.path))}collection(t){return this.collectionRef(`${this.path}/${t}`)}async get(t){const n=this.env.execute({method:"get",path:this.path,auth:t?.auth!==void 0?t.auth:this.auth,bypassRules:this.bypassRules});n.allowed||D(n,"get denied");const s=n.data===void 0||n.data===null?void 0:n.data;return ot(this,s)}async create(t,n){const s=this.env.execute({method:"create",path:this.path,data:t,auth:n?.auth!==void 0?n.auth:this.auth,bypassRules:this.bypassRules});s.allowed||D(s,"create denied")}async set(t,n){const s=n?.auth!==void 0?n.auth:this.auth;if(n?.mergeFields!==void 0){const i=n.mergeFields.map(u=>String(u)),a=this.env.getDocument(this.path)===null?"create":"update",c=this.env.execute({method:a,path:this.path,data:t,auth:s,merge:{mergeFields:i},bypassRules:this.bypassRules});c.allowed||D(c,`set denied (as ${a})`);return}if(n?.merge===!0){const o=this.env.getDocument(this.path)===null?"create":"update",a=this.env.execute({method:o,path:this.path,data:t,auth:s,merge:!0,bypassRules:this.bypassRules});a.allowed||D(a,`set denied (as ${o})`);return}const r=this.env.execute({method:"set",path:this.path,data:t,auth:s,bypassRules:this.bypassRules});r.allowed||D(r,"set denied")}update(t,...n){const{fields:s,options:r}=P(t,n);return this.commitUpdate(s,r)}async commitUpdate(t,n){const s=this.env.execute({method:"update",path:this.path,data:ke(t),auth:n?.auth!==void 0?n.auth:this.auth,bypassRules:this.bypassRules});s.allowed||D(s,"update denied")}async delete(t){const n=this.env.execute({method:"delete",path:this.path,auth:t?.auth!==void 0?t.auth:this.auth,bypassRules:this.bypassRules});n.allowed||D(n,"delete denied")}}function V(e,t,n,s){return new gn(e,t,n,s,r=>new ft(e,t,r,s))}class ft extends z{id;path;constructor(t,n,s,r=!1){super({env:t,auth:n,collectionPath:s,bypassRules:r,documentRef:i=>V(t,n,i,r)}),this.path=s,this.id=re(s)}doc(t){const n=t??tt();return V(this.env,this.auth,`${this.path}/${n}`,this.bypassRules)}async add(t,n){const s=n?.auth!==void 0?n.auth:this.auth,{path:r,result:i}=this.env.createWithAutoId(this.path,t,s,this.bypassRules);if(!i.allowed){if(i.error)throw new f(i.error);let o="(no debug message)";throw i.debugMessages.length>0&&(o=i.debugMessages.join("; ")),new f(j("permission-denied",`set denied: ${o}`))}return V(this.env,this.auth,r,this.bypassRules)}}class De extends z{collectionId;constructor(t){super({...t,collectionPath:"",documentRef:n=>V(t.env,t.auth,n,t.bypassRules??!1)}),this.collectionId=t.collectionId}clone(t){return new De({env:this.env,auth:this.auth,collectionId:this.collectionId,clauses:t.clauses??this.clauses,orders:t.orders??this.orders,limitCount:"limitCount"in t?t.limitCount:this.limitCount,limitFromEnd:t.limitFromEnd??this.limitFromEnd,start:"start"in t?t.start:this.start,end:"end"in t?t.end:this.end,bypassRules:this.bypassRules})}queryScope(){return{kind:"collection-group",collectionId:this.collectionId}}activityScope(){return{kind:"collection-group"}}}class wn{env;auth;bypassRules;ops=[];constructor(t,n,s=!1){this.env=t,this.auth=n,this.bypassRules=s}create(t,n){return this.ops.push({method:"create",path:t.path,data:ce(n)}),this}set(t,n,s){const r={method:"set",path:t.path,data:ce(n)},i=s?.mergeFields;return i!==void 0?r.merge={mergeFields:[...i]}:s?.merge===!0&&(r.merge=!0),this.ops.push(r),this}update(t,n,...s){const{fields:r}=P(n,s);return this.ops.push({method:"update",path:t.path,data:ce(ke(r))}),this}delete(t){return this.ops.push({method:"delete",path:t.path}),this}async commit(t){if(this.ops.length===0)return;const s=t?.auth,r=s!==void 0,i=this.env.batch(this.ops,r?s:this.auth,this.bypassRules),{allowed:o,error:a}=i;if(o)return;if(a!==void 0)throw new f(a);const y=i.results.find(d=>!d.allowed)?.debugMessages.join("; ")??"batch denied";throw new f(j("permission-denied",`batch failed: ${y}`))}}function xn(e){return typeof e.where=="function"}class Sn{simTx;constructor(t){this.simTx=t}async get(t){if(xn(t)){const i=await t.get();return i.size>0&&this.simTx.getAll(...i.docs.map(a=>a.ref.path)),i}const r=this.simTx.get(t.path).data();return ot(t,r)}create(t,n){return this.simTx.create(t.path,n),this}set(t,n,s){const r=s?.mergeFields;if(r!==void 0)return this.simTx.set(t.path,n,{mergeFields:r}),this;const o=s?.merge===!0;return this.simTx.set(t.path,n,o?!0:void 0),this}update(t,n,...s){const{fields:r}=P(n,s);return this.simTx.update(t.path,ke(r)),this}delete(t){return this.simTx.delete(t.path),this}}class vn{env;auth;bypassRules;provenance;constructor(t,n,s=!1,r){this.env=t,this.auth=n,this.bypassRules=s,this.provenance=r}collection(t){if(!Ae(t))throw new f(j("invalid-argument",`collection path must have an odd number of segments: ${t}`));return new ft(this.env,this.auth,t,this.bypassRules)}doc(t){if(!rt(t))throw new f(j("invalid-argument",`document path must have an even number of segments: ${t}`));return V(this.env,this.auth,t,this.bypassRules)}collectionGroup(t){if(t.length===0||t.includes("/"))throw new f(j("invalid-argument",`collection group id must be a single non-empty segment with no '/': ${t}`));return new De({env:this.env,auth:this.auth,collectionId:t,bypassRules:this.bypassRules})}batch(){return new wn(this.env,this.auth,this.bypassRules)}async runTransaction(t,n){let s;try{s=await this.env.transaction(r=>{const i=new Sn(r);return t(i)},{auth:n?.auth!==void 0?n.auth:this.auth,bypassRules:this.bypassRules,provenance:this.provenance,maxAttempts:n?.maxAttempts})}catch(r){throw r instanceof It?new f(r.simError):r instanceof $t?new f(r.simError):r}if(!s.allowed){if(s.error)throw new f(s.error);const i=s.writes.find(o=>!o.allowed)?.debugMessages.join("; ")??"transaction denied at commit";throw new f(j("permission-denied",`transaction failed: ${i}`))}return s.returnValue}}function Rn(e,t){return new vn(e,t?.auth??null,t?.bypassRules??!1,t?.provenance)}const On=Symbol("pyric/sandbox/context"),kn=Symbol("pyric/sandbox/bypassRules");let me=null;function ss(e){me=e}const En=Symbol.for("pyric.firestore.modular-value");function Ne(e){return En in e}function Fn(e){const t=e;return typeof t.path=="string"&&t.path.length>0||typeof t.collectionPath=="string"&&t.collectionPath.length>0||typeof t.snapshotScope=="function"}function Cn(e){const t=e.trim();if(!t)return[];const n=t.indexOf(": ");if(n!==-1){const r=t.slice(n+2).trim().split("; ").map(i=>i.trim()).filter(i=>i.length>0);if(r.length>0)return r}return[t]}function Be(e,t){if(e instanceof f===!1)return e;const s=e.code;if(s==="permission-denied"===!1)return new w(s,e.message);const i={engine:"firestore",auth:t.auth,reasons:Cn(e.message)},o=e.simError;if(o!==void 0){if(o.queryProof!==void 0&&(i.queryProof=o.queryProof),o.request!==void 0){const l=o.request;i.request={method:l.method,path:l.path},l.resourceData!==void 0&&(i.request.resourceData=l.resourceData),l.updateMask!==void 0&&(i.request.updateMask=l.updateMask)}if(o.resource!==void 0&&(i.resource={data:o.resource.data,exists:o.resource.exists}),o.query!==void 0&&(i.query=o.query),o.rule!==void 0&&(i.rule=o.rule),o.repro!==void 0&&(i.repro=o.repro),o.remediation!==void 0)return new w({code:s,message:e.message,denialContext:i,remediation:o.remediation})}return new w(s,e.message,i)}function ee(e,t,n=!1){return new Proxy(e,{get(s,r,i){if(r===On)return t;if(r===kn)return n;if(r==="onSnapshot"&&me!==null&&!(r in s)&&Fn(s))return(...a)=>me(i,...a);const o=Reflect.get(s,r,i);return typeof o!="function"?o:function(...a){let c;try{const u=()=>o.apply(s,a);c=typeof t.sandbox.runWithProvenance=="function"?t.sandbox.runWithProvenance(nt(t.operationContext),u):u()}catch(u){throw Be(u,t)}return c instanceof Promise?c.then(u=>u&&typeof u=="object"&&!Ne(u)?ee(u,t,n):u).catch(u=>{throw Be(u,t)}):c&&typeof c=="object"&&!Ne(c)?ee(c,t,n):c}}})}function pt(e,t=!1){if(Ce(e.sandbox))throw new Error("pyric/sandbox/admin-firestore: internal — a remote sandbox context reached the local engine builder; remote dispatch should have handled it. Please report this.");const n=()=>Rn(T(e.sandbox),{auth:e.auth,bypassRules:t,provenance:nt(e.operationContext)});return{collection(s){return n().collection(s)},doc(s){return n().doc(s)},collectionGroup(s){return n().collectionGroup(s)},batch(){return n().batch()},runTransaction(s,r){return n().runTransaction(s,r)},setRules(s){return T(e.sandbox).deployRules(s)},seed(s){const r=T(e.sandbox);return r.seed({rules:r.getRules(),documents:s?.documents??{}})},snapshot(){return T(e.sandbox).snapshot()}}}function ye(e){if(e instanceof w)return e;if(e!==null&&typeof e=="object"){const t=e;if(typeof t.code=="string"&&typeof t.message=="string"){const n=t.denialContext!==null&&typeof t.denialContext=="object"?t.denialContext:void 0;return new w(t.code,t.message,n)}}return e}function k(e){return new w("invalid-argument",e)}async function x(e,t){try{return await e.sandbox.channel.op({...t,actAs:e.lens})}catch(n){throw ye(n)}}const An=new Set(["serverTimestamp","increment","arrayUnion","arrayRemove","deleteField"]);function Dn(e){return e!==null&&typeof e=="object"&&typeof e.__type=="string"&&An.has(e.__type)}function jn(e){switch(e.__type){case"serverTimestamp":return{__sentinel:"serverTimestamp"};case"increment":return{__sentinel:"increment",n:e.value};case"arrayUnion":return{__sentinel:"arrayUnion",values:e.values.map(v)};case"arrayRemove":return{__sentinel:"arrayRemove",values:e.values.map(v)};case"deleteField":return{__sentinel:"deleteField"}}}function v(e){if(e===null||typeof e!="object")return e;if(Dn(e))return jn(e);if(e instanceof le)return e.toJSON();if(e instanceof Date)return le.fromDate(e).toJSON();if(Array.isArray(e))return e.map(v);const t=Object.getPrototypeOf(e);if(t!==Object.prototype&&t!==null){const s=e.toJSON;if(typeof s=="function")return s.call(e);throw k(`remote Firestore: cannot serialize a ${t.constructor?.name??"class"} instance for the wire — use plain data, Timestamp, Date, or FieldValue sentinels.`)}const n={};for(const[s,r]of Object.entries(e))n[s]=v(r);return n}function _(e){return v(e)}function je(e){return e.map(t=>({path:[...t.path],value:v(t.value)}))}function be(e){return zt(JSON.parse(e.json),e.valueEncoding)}function mt(e){return ve(be(e))}function yt(e,t){const n=t.exists&&t.data?mt(t.data):void 0;return{id:e.id,ref:e,exists:t.exists,data:()=>n,get:s=>ne(n,s)}}function bt(e,t){const n=t.docs.map(s=>{const r=s.path??s.id,i=te(e,r),o=s.data?mt(s.data):{};return{id:i.id,ref:i,exists:!0,data:()=>o,get:a=>ne(o,a)}});return{size:n.length,empty:n.length===0,docs:n,forEach:et(n)}}const _e=Symbol("pyric/sandbox/admin-firestore/remoteSnapshotRegistrar");function rs(e){if(e===null||typeof e!="object")return;const t=e[_e];return typeof t=="function"?t:void 0}let ge=null;function is(e){ge=e}function gt(...e){if(ge===null)throw new w("failed-precondition","remote Firestore: onSnapshot is not wired yet — import pyric-admin/firestore (or pyric/sandbox/admin-firestore) before subscribing.");return ge(this,...e)}function wt(e,t,n,s,r){const i=n.includeMetadataChanges!==!0;let o;function a(u){const y=ye(u);r!==void 0?r(y):console.error("pyric remote Firestore: uncaught onSnapshot error:",y)}let c;try{c=e.sandbox.channel.subscribe({target:t,actAs:e.lens},u=>{if(s===void 0)return;let d;try{const l=u,b=l.docs;if(Array.isArray(b)){const m=b.map(O=>{const S=O.data,p=S!==void 0;return{path:O.path??O.id,data:p?be(S):{}}});d=Lt({path:xt(t)},m,{excludesMetadataChanges:i},o),o=m}else{const m=l.id;if(typeof m=="string"){const S=l.path??m,p=l.data,N=l.exists===!0&&p!==void 0?be(p):null;d=Qt(S,N)}}}catch(l){c(),a(l);return}d!==void 0&&s(d)},a)}catch(u){throw ye(u)}return c}function xt(e){switch(e.__ref){case"query":return xt(e.source);case"group":return e.collectionId;default:return e.path}}const St=Symbol("pyric/sandbox/admin-firestore/remoteQueryState");function _n(e){if(!(e===null||typeof e!="object"))return e[St]}function vt(e){return e.kind==="where"?(Rt(e.op),{kind:"where",field:e.field,op:e.op,value:v(e.value)}):{kind:e.kind,filters:e.filters.map(vt)}}const Tn=new Set(["<","<=","==","!=",">=",">","in","not-in","array-contains","array-contains-any"]);function Rt(e){if(!Tn.has(e))throw k(`invalid where operator: ${String(e)}`)}function Y(e){const t=[...e.filters];for(const n of e.orders)t.push({kind:"orderBy",field:n.field,direction:n.direction});return e.start&&t.push({kind:e.start.inclusive?"startAt":"startAfter",values:e.start.values.map(v)}),e.end&&t.push({kind:e.end.inclusive?"endAt":"endBefore",values:e.end.values.map(v)}),e.limitCount!==void 0&&t.push(e.limitFromEnd?{kind:"limitToLast",n:e.limitCount}:{kind:"limit",n:e.limitCount}),t.length===0?e.source:{__ref:"query",source:e.source,constraints:t}}function Ge(e,t,n){if(t.length===0)throw k(`${n}(snapshot) on a remote sandbox requires at least one explicit orderBy() clause — the relay protocol has no document-key cursor.`);if(t.some(r=>r.field==="__name__"))throw k(`${n}(snapshot) on a remote sandbox does not support orderBy('__name__') — the relay protocol has no document-key cursor, and __name__ is not a data field a value cursor can carry. Order by a real document field instead.`);const s=e.data();if(s===void 0)throw new w("not-found",`Snapshot-based cursors require an existing document — got an empty snapshot for ${e.id??"<unknown>"}.`);return t.map(r=>s[r.field])}function Te(e,t){const n=r=>Te(e,{...t,...r});return{[St]:t,where(r,i,o){return Rt(i),n({filters:[...t.filters,{kind:"where",field:r,op:i,value:v(o)}]})},applyFilter(r){return n({filters:[...t.filters,vt(r)]})},orderBy(r,i="asc"){return n({orders:[...t.orders,{field:r,direction:i}]})},limit(r){return n({limitCount:r,limitFromEnd:!1})},limitToLast(r){return n({limitCount:r,limitFromEnd:!0})},startCursor(r,i){return n({start:{values:[...r],inclusive:i}})},endCursor(r,i){return n({end:{values:[...r],inclusive:i}})},startCursorFromSnapshot(r,i){return n({start:{values:Ge(r,t.orders,i?"startAt":"startAfter"),inclusive:i}})},endCursorFromSnapshot(r,i){return n({end:{values:Ge(r,t.orders,i?"endAt":"endBefore"),inclusive:i}})},async get(r){J(t);const i=await x(e,{method:"getDocs",source:Y(t)});return bt(e,i)},async aggregate(r){J(t);const i=await x(e,{method:"aggregate",source:Y(t),spec:r});return{data:()=>i.data}},[_e]:(r,i,o)=>(J(t),wt(e,Y(t),r,i,o)),onSnapshot:gt}}function J(e){if(e.limitFromEnd&&e.orders.length===0)throw k("limitToLast() queries require at least one orderBy clause.")}function we(e,t){const n=Te(e,{source:{__ref:"collection",path:t},filters:[],orders:[],limitFromEnd:!1});return Object.assign(Object.create(Object.getPrototypeOf(n)),n,{id:re(t),path:t,doc(r){const i=r??tt();return te(e,`${t}/${i}`)},async add(r,i){const o=await x(e,{method:"addDoc",collectionPath:t,data:_(r)});return te(e,o.path)}})}function te(e,t){const n={id:re(t),path:t,get parent(){return we(e,it(t))},collection(s){const r=`${t}/${s}`;if(!Ae(r))throw k(`collection path must have an odd number of segments: ${r}`);return we(e,r)},async get(s){const r=await x(e,{method:"getDoc",path:t});return yt(n,r)},async create(s,r){await x(e,{method:"batchCommit",writes:[{method:"create",path:t,data:_(s)}]})},async set(s,r){await x(e,{method:"setDoc",path:t,data:_(s),...He(r)?{options:He(r)}:{}})},update(s,...r){const{fields:i}=P(s,r),o=je(i);return x(e,{method:"updateDoc",path:t,fields:o}).then(()=>{})},async delete(s){await x(e,{method:"deleteDoc",path:t})},[_e]:(s,r,i)=>wt(e,{__ref:"doc",path:t},s,r,i),onSnapshot:gt};return n}function He(e){if(!e)return;const t={};return e.merge!==void 0&&(t.merge=e.merge),e.mergeFields!==void 0&&(t.mergeFields=[...e.mergeFields]),t.merge!==void 0||t.mergeFields!==void 0?t:void 0}function Ot(e){if(e===void 0)return;const t={};return"merge"in e&&e.merge!==void 0&&(t.merge=e.merge),"mergeFields"in e&&e.mergeFields!==void 0&&(t.mergeFields=e.mergeFields.map(n=>String(n))),t}function Pn(e){const t=[];let n=!1;const s={create(i,o){return r(),t.push({method:"create",path:i.path,data:_(o)}),s},set(i,o,a){r();const c={method:"set",path:i.path,data:_(o)},u=Ot(a);return u!==void 0&&(c.options=u),t.push(c),s},update(i,o,...a){r();const{fields:c}=P(o,a);return t.push({method:"update",path:i.path,fields:je(c)}),s},delete(i){return r(),t.push({method:"delete",path:i.path}),s},async commit(i){r(),n=!0,await x(e,{method:"batchCommit",writes:t})}};function r(){if(n)throw new w("failed-precondition","WriteBatch has already been committed.")}return s}const qn=5;async function Vn(e,t,n=qn){for(let s=0;s<n;s++){const r=[],i=[],o=()=>{if(i.length>0)throw new w("failed-precondition",Ut)},a={get(d){o();const h=_n(d);return h!==void 0?u(h):c(d)},create(d,h){return i.push({method:"create",path:d.path,data:_(h)}),a},set(d,h,l){const b={method:"set",path:d.path,data:_(h)},A=Ot(l);return A!==void 0&&(b.options=A),i.push(b),a},update(d,h,...l){const{fields:b}=P(h,l);return i.push({method:"update",path:d.path,fields:je(b)}),a},delete(d){return i.push({method:"delete",path:d.path}),a}};async function c(d){const h=await x(e,{method:"getDoc",path:d.path});return r.push({path:h.path??d.path,data:h.exists&&h.data?h.data:null}),yt(d,h)}async function u(d){J(d);const h=await x(e,{method:"getDocs",source:Y(d)});for(const l of h.docs)r.push({path:l.path??l.id,data:l.data??null});return bt(e,h)}const y=await t(a);try{return await x(e,{method:"txnCommit",reads:r,writes:i}),y}catch(d){if(d instanceof w&&d.code==="aborted")continue;throw d}}throw new w("aborted",`Transaction failed after ${n} attempts due to repeated conflicts. Another writer is concurrently updating the same documents.`)}function ue(e,t){return new w("unimplemented",`SandboxFirestore.${e} is not available on a remote sandbox — its return value is synchronous and the data lives in the browser worker. ${t}`)}function kt(e,t){const n={sandbox:e,lens:t};return{collection(s){if(!Ae(s))throw k(`collection path must have an odd number of segments: ${s}`);return we(n,s)},doc(s){if(!rt(s))throw k(`document path must have an even number of segments: ${s}`);return te(n,s)},collectionGroup(s){if(s.length===0||s.includes("/"))throw k(`collection group id must be a single non-empty segment with no '/': ${s}`);return Te(n,{source:{__ref:"group",collectionId:s},filters:[],orders:[],limitFromEnd:!1})},batch(){return Pn(n)},runTransaction(s,r){return Vn(n,s,r?.maxAttempts)},setRules(){throw ue("setRules","Deploy rules asynchronously through the relay instead: `await sandbox.channel.op({ method: 'setFirestoreRules', source })`.")},seed(){throw ue("seed","The relay has no atomic seed op; write seed docs through this handle (`db.doc(path).set(data)` / `db.batch()`), or drive `sandbox.channel.op({ method: 'admin.setDocument', path, data })` per document.")},snapshot(){throw ue("snapshot","Read the worker state asynchronously instead: `await sandbox.channel.op({ method: 'admin.readState' })`.")}}}const Ye=new WeakMap;function Et(e){const t=Ye.get(e);if(t)return t;const n=Ce(e.sandbox)?kt(e.sandbox,Mn(e.auth)):ee(pt(e),e);return Ye.set(e,n),n}function Mn(e){if(e==null)return{mode:"anon"};const t={mode:"as",uid:e.uid};return e.token!==void 0&&(t.token=e.token),e.tenant!==void 0&&(t.tenant=e.tenant),t}const Je=new WeakMap;function In(e){const t=$n(e)?e:e.withAuth(null),n=Je.get(t);if(n)return n;const s=t.operationContext.authLens.mode==="admin"?t:Ee(t,{source:t.operationContext.source,authLens:{mode:"admin"},...t.operationContext.planId===void 0?{}:{planId:t.operationContext.planId}}),r=Ce(s.sandbox)?kt(s.sandbox,{mode:"admin"}):ee(pt(s,!0),s,!0);return Je.set(t,r),r}function $n(e){return e!==null&&typeof e=="object"&&"sandbox"in e&&typeof e.withAuth=="function"}function zn(e){return e instanceof Error&&"code"in e&&typeof e.code=="string"}function Ln(e){if(e instanceof I||!zn(e))return e;const t={};e.denialContext!==void 0&&(t.denialContext=e.denialContext),e.remediation!==void 0&&(t.remediation=e.remediation);const n=new I(e.code,e.message,Object.keys(t).length===0?void 0:t);e.denialContext!==void 0&&Object.assign(n,{denialContext:e.denialContext}),e.remediation!==void 0&&Object.assign(n,{remediation:e.remediation});for(const s of["request","resource","query","rule","queryProof"])e[s]!==void 0&&Object.assign(n,{[s]:e[s]});return n}async function ie(e){try{return await e()}catch(t){throw Ln(t)}}class Qn{static[Symbol.hasInstance](t){return!!(t&&typeof t=="object"&&"id"in t&&"path"in t&&typeof t.path=="string"&&!("docs"in t)&&!("exists"in t)&&!("doc"in t)&&!("add"in t))}}function Ft(e,t){const n=R(e);if(t===null)return n;const r=C(e),i=Ve(n,r,t);return Fe(n,i),xe(i)}function xe(e){function t(n){return Ft(e,n)}return Object.assign(e,{withConverter:t})}function X(e,t,n,s=null){function r(c){return c===null?Xe(a,null):Xe(a,c)}const i=R(e),o=Ve(i,n,s),a=Object.assign(o,{withConverter:r});return M(a,Re("reference",t)),Oe(i,t,n),Fe(i,a),a}function os(e,...t){const n=C(e),s=F in e,r=s?void 0:qe(e),i=U(n);if(s){if(t.length===0)throw new TypeError("doc(db, path) requires at least one path segment.");const l=t.join("/"),b=i.doc(l),A=Q(b,n,m=>m.doc(l));return X(A,l,n)}const o=R(e),a=t.length===0;let c;a?c=o.doc():c=o.doc(t.join("/"));const u=c.path,y=Q(c,n,h=>h.doc(u));return r!=null?X(y,u,n,r):X(y,u,n)}function as(e,...t){const n=C(e),s=F in e;if(t.length===0)throw new TypeError("collection() requires at least one path segment.");if(s){const c=t.join("/"),u=xe(U(n).collection(c));return Q(u,n,y=>y.collection(c))}const r=R(e),i=t.join("/"),o=xe(r.collection(i)),a=o.path;return Q(o,n,c=>c.collection(a))}function Xe(e,t){const n=C(e),s=R(e);return s instanceof Qn?X(s,s.path,n,t):Ft(e,t)}class Un{started=!1;networkEnabled=!0;persistenceMode;pending=new Set;cachedPaths=new Set;cachedQueries=new WeakSet;syncObservers=new Set;syncScheduled=!1;markStarted(){this.started=!0}enablePersistence(t){if(this.started||this.persistenceMode!==void 0)throw new I("failed-precondition","Firestore has already been started and persistence can no longer be enabled.");this.persistenceMode=t,this.started=!0}disableNetwork(){this.started=!0,this.networkEnabled=!1}async enableNetwork(){this.started=!0,this.networkEnabled=!0;for(const t of this.pending)t.localDone&&t.resolve(t.value);await Promise.all([...this.pending].map(t=>t.promise))}runWrite(t,n){if(this.started=!0,n&&this.cachedPaths.add(n),this.networkEnabled)return t();let s,r;const i=new Promise((a,c)=>{s=a,r=c}),o={path:n,promise:i,localDone:!1,resolve:s,reject:r};return this.pending.add(o),t().then(a=>{o.localDone=!0,o.value=a,this.networkEnabled&&o.resolve(a)},a=>o.reject(a)),i.then(()=>this.pending.delete(o),()=>this.pending.delete(o)),i}waitForPendingWrites(){this.started=!0;const t=[...this.pending].map(n=>n.promise);return Promise.all(t).then(()=>{})}cachePath(t){this.started=!0,this.cachedPaths.add(t)}assertPathCached(t){if(this.started=!0,!this.cachedPaths.has(t))throw new I("unavailable","Failed to get document from cache. (However, this document may exist on the server.)")}cacheQuery(t){this.started=!0,this.cachedQueries.add(t)}hasCachedQuery(t){return this.started=!0,this.cachedQueries.has(t)||this.cachedPaths.size>0}snapshotMetadata(t){return Object.freeze({fromCache:!this.networkEnabled,hasPendingWrites:[...this.pending].some(n=>n.path===t)})}querySnapshotMetadata(){return Object.freeze({fromCache:!this.networkEnabled,hasPendingWrites:this.pending.size>0})}addSnapshotsInSyncObserver(t){return this.syncObservers.add(t),t(),()=>this.syncObservers.delete(t)}notifySnapshotDelivered(){this.syncScheduled||this.syncObservers.size===0||(this.syncScheduled=!0,queueMicrotask(()=>{this.syncScheduled=!1;for(const t of[...this.syncObservers])t()}))}}const Ke=new WeakMap;function L(e){let t=Ke.get(e);return t||(t=new Un,Ke.set(e,t)),t}function oe(e,t,n,s,r){const i=R(t),o=typeof i.sdkActivitySource=="function"?i.sdkActivitySource():{service:"firestore",target:i.path,key:`doc:${i.path}`};return Wt.begin({app:e.activityApp??e,source:o,method:n,kind:s,owners:Nt(r?.owner,r?.owners)})}const F=Symbol("pyric/firestore/target");function U(e){return e.kind==="sandbox"?e.db:e.getDb()}const ae=new WeakMap;function Wn(e,t){return ae.set(e,t),e}const W=new WeakMap;function Nn(e,t,n){return ae.set(e,t),W.set(e,n),e}function Pe(e,t){const n=R(t);if(e.kind==="sandbox")return n;const s=W.get(n);if(!s)throw new TypeError("pyric/firestore: live ref missing rebuild closure — was it produced by a factory in this package?");return s(U(e))}function Bn(e,t){const n=R(t);if(e.kind==="sandbox")return n;const s=W.get(n);if(!s)throw new TypeError("pyric/firestore: live collection ref missing rebuild closure.");return s(U(e))}function cs(e,t){const n=R(t);if(e.kind==="sandbox")return n;const s=W.get(n);if(!s)throw new TypeError("pyric/firestore: live query missing rebuild closure.");return s(U(e))}function Q(e,t,n){return t.kind==="sandbox-live"?Nn(e,t,n):Wn(e,t)}function us(e){const t=R(e),n=W.get(t);return n||(()=>t)}function C(e){const t=Gn(e);return t.assertUsable?.(),t}function Gn(e){let t;if(F in e?t=e[F]:t=ae.get(e),!t)throw new TypeError("pyric/firestore: unrecognized reference — was it produced by a factory in this package?");return t}const Hn=Symbol.for("pyric.firestore.modular-value"),Ct=new WeakMap,At=new WeakMap;function qe(e){return Ct.get(e)}function R(e){return At.get(e)??e}function Ve(e,t,n){const s={id:e.id??"",path:e.path??""};return Object.defineProperty(s,Hn,{value:!0}),Ct.set(s,n),At.set(s,e),ae.set(s,t),s}function Yn(e){return e instanceof Kt?Array.from(e.value):null}function Se(e,t){if(e instanceof Yt)return t?.create(e.path)??e;if(e instanceof Jt)return Bt.fromUint8Array(e.data);if(e instanceof Xt)return new Gt(e.lat,e.lng);const i=Yn(e);if(i!==null)return Ht(i);if(Array.isArray(e))return e.map(u=>Se(u,t));if(e!==null&&typeof e=="object"){const u=Object.getPrototypeOf(e);if(u===Object.prototype||u===null){const d={};for(const[h,l]of Object.entries(e))d[h]=Se(l,t);return d}}return e}function ds(e,t){if(e!==void 0)return Se(e,t)}function Jn(e){if(e===void 0)return Jn(sn());const t=st(e);if(t)return t.service("firestore/default",()=>{const{sandbox:n,session:s}=t,r=de();t.onDelete(r.terminate);const i=t.authScope;i&&(r.own(s.onCurrentUserChanged(a=>{T(n).reevaluateLiveListeners(a,i)})),r.own(on(a=>{const c=a?.mode==="anon"?null:a?.mode==="as"?{uid:a.uid,...a.tenant?{tenant:a.tenant}:{}}:s.currentUser;T(n).reevaluateLiveListeners(c,i)})));const o={kind:"sandbox-live",activityApp:e,sandbox:n,getDb:Ze(n,()=>s.currentUser),authScope:i,...r};return{[F]:o,app:e}});if(Dt(e)){const n=Et(e),s={kind:"sandbox",activityApp:e,db:n,sandbox:e.sandbox,...de()};return{[F]:s}}if(Kn(e)){const n={kind:"sandbox-live",activityApp:e,sandbox:e,getDb:Ze(e),...de()};return{[F]:n}}throw new TypeError("pyric/firestore is a sandbox-only mirror. Package resolution must leave firebase/firestore unchanged for production; activate pyric sandbox or @pyric/cli/register before importing to select the sandbox.")}function de(){let e=!1;const t=new Set;return{own(n){return e?(n(),()=>{}):(t.add(n),()=>t.delete(n))},assertUsable(){if(e)throw new I("failed-precondition","The client has already been terminated.")},terminate(){if(!e){e=!0;for(const n of t)n();t.clear()}}}}function Xn(e){const t=st(e);if(t){t.assertAlive();const o=t.sandbox;return Xn(Ee(o.withAuth(null),{source:{kind:"app"},authLens:{mode:"admin"}}))}const n=Dt(e)?e:e.withAuth(null),s=n.sandbox,i={kind:"sandbox",db:In(n),sandbox:s};return{[F]:i}}function Dt(e){return e instanceof Zt}function Kn(e){if(e===null||typeof e!="object")return!1;const t=e;return typeof t.withAuth=="function"&&typeof t.onCurrentUserChanged=="function"&&"currentUser"in t&&"admin"in t}function Ze(e,t=()=>e.currentUser){return()=>{const n=t(),s=Ee(e.withAuth(n),{source:{kind:"app"},authLens:{mode:"app-session"}});return Et(s)}}function Zn(e,t,n,s){const r=en(e,t,n,s);if(r.length===0)return[{}];const i=[];for(const o of r)i.push(new tn(...o.path),o.value);return i}async function ls(e,t,n){const s=C(e);return se(oe(s,e,"setDoc","operation"),async()=>{const r=qe(e),i=r?r.toFirestore(t):t;return L(s).runWrite(()=>ie(()=>Pe(s,e).set(i,n)),e.path)})}function hs(e,t,...n){const s=C(e),r=Zn("updateDoc",e.path,t,n);return se(oe(s,e,"updateDoc","operation"),async()=>L(s).runWrite(()=>ie(()=>Pe(s,e).update(...r)),e.path))}async function fs(e){const t=C(e);return se(oe(t,e,"deleteDoc","operation"),async()=>L(t).runWrite(()=>ie(()=>Pe(t,e).delete()),e.path))}async function ps(e,t){const n=C(e);return se(oe(n,e,"addDoc","operation"),async()=>{const s=qe(e),r=s?s.toFirestore(t):t,i=await L(n).runWrite(async()=>{const c=await ie(()=>Bn(n,e).add(r));return L(n).cachePath(c.path),c}),o=i.path,a=Q(i,n,c=>c.doc(o));if(M(a,Re("reference",o)),Oe(a,o,n,a),s){const c=Ve(a,n,s);return Fe(a,c),c}return a})}export{us as A,kn as B,On as C,Ln as D,xe as E,Q as F,Ft as G,as as H,ps as I,hs as J,fs as K,ts as L,rn as M,se as N,Xn as O,ln as Q,F as T,sn as a,fe as b,L as c,os as d,qe as e,ds as f,Jn as g,At as h,ns as i,U as j,W as k,ct as l,ut as m,oe as n,C as o,cs as p,Pe as q,st as r,ls as s,Wn as t,R as u,ss as v,ie as w,is as x,rs as y,Be as z};
1
+ import{c as jt,ba as ve,aP as ne,aC as f,bb as _t,bc as Tt,b8 as le,bd as Pt,be as qt,bf as M,aK as K,bg as Vt,bh as Mt,az as et,bi as Re,ay as Oe,bj as P,bk as ke,bl as j,aQ as tt,bm as ce,bn as It,bo as zt,V as nt,H as w,aB as T,aM as $t,bp as Lt,bq as Qt,br as Wt,Q as Ee,F as I,bs as Fe,D as Ut,E as Nt,b7 as Bt,b9 as Gt,bt as Ht,bu as Yt,O as Jt,ac as Xt,bv as Kt,T as Zt,bw as en,bx as tn}from"./sandbox-controls.Bv6lfpIe.js";const nn=Symbol.for("pyric.remote.sandbox");function Ce(e){return e!=null&&e[nn]===!0}let Z;function ts(e){Z=e}function st(e){return Z?.resolve(e,!1)}function sn(){if(!Z)throw new TypeError("No default sandbox app registry is installed - import and initialize pyric/app before calling a service factory without an app.");return Z.defaultApp()}function Me(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:void 0}function rn(e,t,n,s){const r={collectionGroup:e.split("/").filter(Boolean).at(-1)??"",queryScope:t?"COLLECTION_GROUP":"COLLECTION",filters:[],orders:[]},i=(o,a)=>{const c=Me(o);if(!c||a>12||r.filters.length>=64){r.unsupported="This query exceeds the index checker’s supported limits.";return}if(c.kind==="and"&&Array.isArray(c.filters)){c.filters.forEach(u=>i(u,a+1));return}if(c.kind!=="where"||typeof c.field!="string"||typeof c.op!="string"){r.unsupported="This query uses a filter the index checker does not support yet.";return}r.filters.push({field:c.field,op:c.op})};n.forEach(o=>i(o,0));for(const o of s.slice(0,64)){const a=Me(o);if(!a||typeof a.field!="string"||a.direction!=="asc"&&a.direction!=="desc"){r.unsupported="This sort order cannot be checked yet.";continue}r.orders.push({field:a.field,direction:a.direction})}return s.length>64&&(r.unsupported="This query exceeds the index checker’s supported limits."),r}async function se(e,t,n){try{const s=await t();return e.complete(n?.()),s}catch(s){throw e.fail(),s}}const Ie=new Set;function on(e){return Ie.add(e),()=>{Ie.delete(e)}}function ns(e={}){return jt()}function z(e){return e.replace(/^\/+|\/+$/g,"").split("/")}function rt(e){return z(e).length%2===0&&z(e).length>0}function Ae(e){return z(e).length%2===1}function re(e){const t=z(e);return t[t.length-1]??""}function it(e){return z(e).slice(0,-1).join("/")}function ot(e,t){const n=t!==void 0,s=n?ve(t):void 0;return{id:e.id,ref:e,exists:n,data:()=>n?s:void 0,get:r=>ne(s,r)}}const ze=200,B=10,an=4;function cn(e){return e.length<=ze?{type:"string",value:e}:{type:"string",value:e.slice(0,ze),truncated:!0}}function at(e,t){const n=e*1e3+Math.floor(t/1e6);if(!Number.isFinite(n))return{type:"opaque"};try{return{type:"timestamp",iso:new Date(n).toISOString()}}catch{return{type:"opaque"}}}function un(e){if(typeof e!="object"||e===null)return{type:"opaque"};const t=e;return typeof t.path=="string"?{type:"reference",path:t.path}:t.type==="timestamp"&&typeof t.seconds=="number"&&typeof t.nanoseconds=="number"?at(t.seconds,t.nanoseconds):t.type==="geo-point"&&typeof t.latitude=="number"&&typeof t.longitude=="number"?{type:"geoPoint",latitude:t.latitude,longitude:t.longitude}:t.type==="bytes"&&Array.isArray(t.values)?{type:"bytes",length:t.values.length}:t.type==="vector"&&Array.isArray(t.values)?{type:"vector",length:t.values.length}:{type:"opaque"}}function he(e,t){if(e===null)return{type:"null"};if(typeof e=="string")return cn(e);if(typeof e=="number")return{type:"number",value:e};if(typeof e=="boolean")return{type:"boolean",value:e};if(typeof e!="object")return{type:"opaque"};if(t>=an)return{type:"opaque"};const n=e;if(n.type==="registered-firestore-value")return un(n.value);if(n.type==="timestamp"&&typeof n.seconds=="number"&&typeof n.nanoseconds=="number")return at(n.seconds,n.nanoseconds);if(n.type==="bytes"&&Array.isArray(n.values))return{type:"bytes",length:n.values.length};if(n.type==="array"&&Array.isArray(n.values)){const s=n.values.slice(0,B).map(r=>he(r,t+1));return n.values.length>B?{type:"array",values:s,truncated:!0}:{type:"array",values:s}}if(n.type==="map"&&Array.isArray(n.entries)){const s=n.entries.slice(0,B).filter(r=>Array.isArray(r)&&typeof r[0]=="string").map(([r,i])=>[r,he(i,t+1)]);return n.entries.length>B?{type:"map",entries:s,truncated:!0}:{type:"map",entries:s}}return{type:"opaque"}}function $e(e){return he(e,0)}function fe(e){if(e===null||typeof e!="object")return JSON.stringify(e);if(Array.isArray(e))return`[${e.map(n=>fe(n)).join(",")}]`;const t=e;return`{${Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${fe(t[n])}`).join(",")}}`}function dn(e){if(e!==null&&typeof e=="object"){const n="type"in e&&e.type==="timestamp",s="seconds"in e&&typeof e.seconds=="number",r="nanoseconds"in e&&typeof e.nanoseconds=="number";return n&&s&&r}return!1}function E(e){return new f({code:"invalid-argument",message:e})}function pe(e,t,n,s=!1,r=!1){if(e===null||typeof e=="string"||typeof e=="boolean")return{comparison:e,execution:e};if(typeof e=="number")return{comparison:e,execution:e};if(typeof e>"u"||typeof e=="bigint"||typeof e=="function"||typeof e=="symbol")throw E(`Unsupported Firestore query value: ${typeof e}.`);if(typeof e!="object")throw E("Unsupported Firestore query value.");const u=_t(e);if(u!==void 0){const m=Tt(e);if(m!==void 0&&n!==void 0&&m!==n)throw E("Document reference belongs to a different Firestore database.");if(dn(u)){const p=Math.floor(u.nanoseconds/1e3)*1e3,g=new le(u.seconds,p);return{comparison:{type:"registered-firestore-value",value:Object.freeze({type:"timestamp",seconds:g.seconds,nanoseconds:p})},execution:g}}return{comparison:{type:"registered-firestore-value",value:u},execution:Pt(e)}}if(e instanceof Date){const m=e.getTime();if(!Number.isFinite(m))throw E("Invalid Date query value.");const S=Math.floor(m/1e3),p=Object.freeze({seconds:S,nanoseconds:Math.floor((m-S*1e3)*1e6)}),g={type:"timestamp",...p};return qt(p,g,()=>Object.freeze({...p})),{comparison:{type:"registered-firestore-value",value:g},execution:p}}if(e instanceof Uint8Array){const m=e.slice();return{comparison:{type:"bytes",values:Array.from(m)},execution:m}}if(t.has(e))throw E("Cyclic query operands are not Firestore values.");const b=Object.getPrototypeOf(e);if(b!==Object.prototype&&b!==null&&!Array.isArray(e))throw E("Firestore query maps must be plain objects.");t.add(e);try{if(Array.isArray(e)){if(r&&!s)throw E("Nested arrays are not supported.");const g=e.map(q=>pe(q,t,n,s,!0)),N=g.map(q=>q.execution);return M(N,K(e)),{comparison:{type:"array",values:g.map(q=>q.comparison)},execution:N}}const O=Object.keys(e).sort().map(p=>({key:p,captured:pe(e[p],t,n,s,!1)})),S=Object.fromEntries(O.map(({key:p,captured:g})=>[p,g.execution]));return M(S,K(e)),{comparison:{type:"map",entries:O.map(({key:p,captured:g})=>[p,g.comparison])},execution:S}}finally{t.delete(e)}}function ct(e,t,n=!1){try{const s=pe(e,new Set,t,n);return Object.freeze({kind:"canonical",value:s.comparison,executionValue:s.execution})}catch(s){if(s instanceof f)throw s;const r=s instanceof Error?s.message:String(s);throw E(`Invalid Firestore query value: ${r}`)}}function ut(e,t){return Vt(e.value,t.value)}const ln=["<","<=","==","!=",">=",">","in","not-in","array-contains","array-contains-any"],hn=new Set(ln);function fn(e,t){if(!hn.has(e))throw new f({code:"invalid-argument",message:"Unsupported Firestore filter operator."});if((e==="in"||e==="not-in"||e==="array-contains-any")&&!Array.isArray(t))throw new f({code:"invalid-argument",message:`Firestore ${e} filter requires an array operand.`})}function H(e,t){if(e.kind==="where"){fn(e.op,e.value);const s="comparisonValue"in e,r=e.op==="in"||e.op==="not-in",i=s?e.comparisonValue:ct(e.value,t,r);return Object.freeze({kind:"where",field:e.field,op:e.op,value:i.executionValue,comparisonValue:i})}return Object.freeze({kind:e.kind,filters:Object.freeze(e.filters.map(s=>H(s,t)))})}function G(e,t,n,s){const r=e.map(i=>ct(i,s));return Object.freeze({values:Object.freeze(r.map(i=>i.executionValue)),comparisonValues:Object.freeze(r),inclusive:t,fromSnapshot:n})}function dt(e,t){return e.length!==t.length?!1:e.every((n,s)=>{const r=t[s];return n.kind!==r.kind?!1:n.kind==="where"&&r.kind==="where"?n.field===r.field&&n.op===r.op&&ut(n.comparisonValue,r.comparisonValue):n.kind!=="where"&&r.kind!=="where"&&dt(n.filters,r.filters)})}function Le(e,t){return e===void 0||t===void 0?e===t:e.inclusive===t.inclusive&&e.comparisonValues.length===t.comparisonValues.length&&e.comparisonValues.every((n,s)=>ut(n,t.comparisonValues[s]))}function pn(e,t){return e.kind!==t.kind?!1:e.kind==="collection"&&t.kind==="collection"?e.path===t.path:e.kind==="collection-group"&&t.kind==="collection-group"&&e.collectionId===t.collectionId}function lt(e){return e.kind==="where"?Object.freeze({kind:e.kind,field:e.field,op:e.op,value:e.value}):Object.freeze({kind:e.kind,filters:Object.freeze(e.filters.map(lt))})}function Qe(e){if(e!==void 0)return Object.freeze({values:e.values,inclusive:e.inclusive,fromSnapshot:e.fromSnapshot})}function mn(e,t){return dt(e.filters,t.filters)&&e.orders.length===t.orders.length&&e.orders.every((n,s)=>{const r=t.orders[s];return n.field===r.field&&n.direction===r.direction})&&e.limitCount===t.limitCount&&e.limitFromEnd===t.limitFromEnd&&Le(e.start,t.start)&&Le(e.end,t.end)}const ht="__name__";function We(e,t){const n=e.data();if(n===void 0)throw new f({code:"not-found",message:`Snapshot-based cursors require an existing document — got an empty snapshot for ${e.id??"<unknown>"}.`});return t.map(s=>s.field===ht?e.ref:n[s.field])}class ${env;auth;collectionPath;clauses;orders;limitCount;limitFromEnd;start;end;bypassRules;documentRef;constructor(t){this.env=t.env,this.auth=t.auth,this.collectionPath=t.collectionPath,this.documentRef=t.documentRef,this.clauses=Object.freeze((t.clauses??[]).map(n=>H(n))),this.orders=Object.freeze((t.orders??[]).map(n=>Object.freeze({...n}))),this.limitCount=t.limitCount,this.limitFromEnd=t.limitFromEnd??!1,this.start=t.start===void 0?void 0:Object.freeze({...t.start,values:Object.freeze(t.start.comparisonValues.map(n=>n.executionValue)),comparisonValues:t.start.comparisonValues}),this.end=t.end===void 0?void 0:Object.freeze({...t.end,values:Object.freeze(t.end.comparisonValues.map(n=>n.executionValue)),comparisonValues:t.end.comparisonValues}),this.bypassRules=t.bypassRules??!1}where(t,n,s){return this.clone({clauses:[...this.clauses,H({kind:"where",field:t,op:n,value:s})]})}applyFilter(t){return this.clone({clauses:[...this.clauses,H(t)]})}orderBy(t,n="asc"){if(n!=="asc"&&n!=="desc")throw new f({code:"invalid-argument",message:"orderBy() direction must be 'asc' or 'desc'."});return this.clone({orders:[...this.orders,{field:t,direction:n}]})}limit(t){return Ue(t),this.clone({limitCount:t,limitFromEnd:!1})}limitToLast(t){return Ue(t),this.clone({limitCount:t,limitFromEnd:!0})}startCursor(t,n){return this.clone({start:G(this.normalizeExplicitCursorValues(t),n,!1)})}endCursor(t,n){return this.clone({end:G(this.normalizeExplicitCursorValues(t),n,!1)})}startCursorFromSnapshot(t,n){return this.clone({start:G(We(t,this.normalizedOrders()),n,!0)})}endCursorFromSnapshot(t,n){return this.clone({end:G(We(t,this.normalizedOrders()),n,!0)})}isStructurallyEqual(t){return t instanceof $?this.env===t.env&&this.bypassRules===t.bypassRules&&pn(this.queryScope(),t.queryScope())&&mn(this.comparableExecutionSpec(),t.comparableExecutionSpec()):!1}clone(t){return new $({env:this.env,auth:this.auth,collectionPath:this.collectionPath,documentRef:this.documentRef,clauses:t.clauses??this.clauses,orders:t.orders??this.orders,limitCount:"limitCount"in t?t.limitCount:this.limitCount,limitFromEnd:t.limitFromEnd??this.limitFromEnd,start:"start"in t?t.start:this.start,end:"end"in t?t.end:this.end,bypassRules:this.bypassRules})}queryScope(){return{kind:"collection",path:this.collectionPath}}sdkActivitySource(){const t=this.queryScope();return{service:"firestore",target:t.kind==="collection"?t.path:t.collectionId,key:fe({scope:t,query:this.activityQuery()}),isQuery:!0,indexQuery:rn(t.kind==="collection"?t.path:t.collectionId,t.kind==="collection-group",this.clauses,this.orders)}}readQueryRows(t){const n=t?.auth!==void 0?t.auth:this.auth;let s;try{s=this.env.runQuery({scope:this.queryScope(),auth:n,execution:this.executionSpec(),bypassRules:this.bypassRules,activityQuery:this.activityQuery()})}catch(r){const i=r?.simError;throw i?new f(i):r}if(!s.allowed)throw new f(s.error);return s.docs}activityQuery(){const t=s=>s.kind==="where"?{kind:"where",field:s.field,op:s.op,value:K(s.value),display:$e(s.comparisonValue.value)}:{kind:s.kind,filters:s.filters.map(t)},n=s=>s===void 0?null:{values:s.values.map(r=>K(r)),display:s.comparisonValues.map(r=>$e(r.value)),inclusive:s.inclusive,fromSnapshot:s.fromSnapshot};return{scope:this.activityScope(),filters:this.clauses.map(t),orderBy:this.orders.map(s=>({...s})),limit:this.limitCount??null,limitFromEnd:this.limitFromEnd,start:n(this.start),end:n(this.end)}}activityScope(){return{kind:"collection"}}normalizedOrders(){return Mt(this.executionSpec())}normalizeExplicitCursorValues(t){const n=this.orders;return t.map((s,r)=>{if(n[r]?.field!==ht)return s;if(typeof s!="string")throw new f({code:"invalid-argument",message:"Expected a string for a document ID cursor value."});const i=s.includes("/")?s:`${this.collectionPath}/${s}`;return this.documentRef(i)})}executionSpec(){const t={filters:Object.freeze(this.clauses.map(lt)),orders:this.orders,limitCount:this.limitCount,limitFromEnd:this.limitFromEnd,start:Qe(this.start),end:Qe(this.end)};return Object.freeze(t)}comparableExecutionSpec(){return{filters:this.clauses,orders:this.orders,limitCount:this.limitCount,limitFromEnd:this.limitFromEnd,start:this.start,end:this.end}}snapshotScope(){return this.queryScope()}snapshotConstraints(){return Object.freeze({execution:this.executionSpec(),activityQuery:this.activityQuery()})}async get(t){const s=this.readQueryRows(t).map(r=>{const i=this.documentRef(r.path),o=ve(r.data);return{id:i.id,ref:i,exists:!0,data:()=>o,get:a=>ne(o,a)}});return{size:s.length,empty:s.length===0,docs:s,forEach:et(s)}}async aggregate(t,n){const s=this.readQueryRows(n),r={};for(const i of Object.keys(t))r[i]=bn(t[i],s);return{data:()=>r}}}function yn(e,t){if(!t.includes("."))return e[t];let n=e;for(const s of t.split(".")){if(typeof n!="object"||n===null||Array.isArray(n))return;n=n[s]}return n}function bn(e,t){if(e.kind==="count")return t.length;let n=0,s=0;for(const r of t){const i=yn(r.data,e.field);typeof i=="number"&&Number.isFinite(i)&&(n+=i,s++)}return e.kind==="sum"?n:s===0?null:n/s}function Ue(e){if(!Number.isFinite(e))throw new f({code:"invalid-argument",message:"Query limit must be a finite number."})}function D(e,t){if(e.error)throw new f(e.error);const n=e.debugMessages.length>0?e.debugMessages.join("; "):"(no debug message)";throw new f(j("permission-denied",`${t}: ${n}`))}class gn{env;auth;bypassRules;collectionRef;id;path;constructor(t,n,s,r=!1,i){this.env=t,this.auth=n,this.bypassRules=r,this.collectionRef=i,this.path=s,this.id=re(s),M(this,Re("reference",s)),Oe(this,s,t)}get parent(){return this.collectionRef(it(this.path))}collection(t){return this.collectionRef(`${this.path}/${t}`)}async get(t){const n=this.env.execute({method:"get",path:this.path,auth:t?.auth!==void 0?t.auth:this.auth,bypassRules:this.bypassRules});n.allowed||D(n,"get denied");const s=n.data===void 0||n.data===null?void 0:n.data;return ot(this,s)}async create(t,n){const s=this.env.execute({method:"create",path:this.path,data:t,auth:n?.auth!==void 0?n.auth:this.auth,bypassRules:this.bypassRules});s.allowed||D(s,"create denied")}async set(t,n){const s=n?.auth!==void 0?n.auth:this.auth;if(n?.mergeFields!==void 0){const i=n.mergeFields.map(u=>String(u)),a=this.env.getDocument(this.path)===null?"create":"update",c=this.env.execute({method:a,path:this.path,data:t,auth:s,merge:{mergeFields:i},bypassRules:this.bypassRules});c.allowed||D(c,`set denied (as ${a})`);return}if(n?.merge===!0){const o=this.env.getDocument(this.path)===null?"create":"update",a=this.env.execute({method:o,path:this.path,data:t,auth:s,merge:!0,bypassRules:this.bypassRules});a.allowed||D(a,`set denied (as ${o})`);return}const r=this.env.execute({method:"set",path:this.path,data:t,auth:s,bypassRules:this.bypassRules});r.allowed||D(r,"set denied")}update(t,...n){const{fields:s,options:r}=P(t,n);return this.commitUpdate(s,r)}async commitUpdate(t,n){const s=this.env.execute({method:"update",path:this.path,data:ke(t),auth:n?.auth!==void 0?n.auth:this.auth,bypassRules:this.bypassRules});s.allowed||D(s,"update denied")}async delete(t){const n=this.env.execute({method:"delete",path:this.path,auth:t?.auth!==void 0?t.auth:this.auth,bypassRules:this.bypassRules});n.allowed||D(n,"delete denied")}}function V(e,t,n,s){return new gn(e,t,n,s,r=>new ft(e,t,r,s))}class ft extends ${id;path;constructor(t,n,s,r=!1){super({env:t,auth:n,collectionPath:s,bypassRules:r,documentRef:i=>V(t,n,i,r)}),this.path=s,this.id=re(s)}doc(t){const n=t??tt();return V(this.env,this.auth,`${this.path}/${n}`,this.bypassRules)}async add(t,n){const s=n?.auth!==void 0?n.auth:this.auth,{path:r,result:i}=this.env.createWithAutoId(this.path,t,s,this.bypassRules);if(!i.allowed){if(i.error)throw new f(i.error);let o="(no debug message)";throw i.debugMessages.length>0&&(o=i.debugMessages.join("; ")),new f(j("permission-denied",`set denied: ${o}`))}return V(this.env,this.auth,r,this.bypassRules)}}class De extends ${collectionId;constructor(t){super({...t,collectionPath:"",documentRef:n=>V(t.env,t.auth,n,t.bypassRules??!1)}),this.collectionId=t.collectionId}clone(t){return new De({env:this.env,auth:this.auth,collectionId:this.collectionId,clauses:t.clauses??this.clauses,orders:t.orders??this.orders,limitCount:"limitCount"in t?t.limitCount:this.limitCount,limitFromEnd:t.limitFromEnd??this.limitFromEnd,start:"start"in t?t.start:this.start,end:"end"in t?t.end:this.end,bypassRules:this.bypassRules})}queryScope(){return{kind:"collection-group",collectionId:this.collectionId}}activityScope(){return{kind:"collection-group"}}}class wn{env;auth;bypassRules;ops=[];constructor(t,n,s=!1){this.env=t,this.auth=n,this.bypassRules=s}create(t,n){return this.ops.push({method:"create",path:t.path,data:ce(n)}),this}set(t,n,s){const r={method:"set",path:t.path,data:ce(n)},i=s?.mergeFields;return i!==void 0?r.merge={mergeFields:[...i]}:s?.merge===!0&&(r.merge=!0),this.ops.push(r),this}update(t,n,...s){const{fields:r}=P(n,s);return this.ops.push({method:"update",path:t.path,data:ce(ke(r))}),this}delete(t){return this.ops.push({method:"delete",path:t.path}),this}async commit(t){if(this.ops.length===0)return;const s=t?.auth,r=s!==void 0,i=this.env.batch(this.ops,r?s:this.auth,this.bypassRules),{allowed:o,error:a}=i;if(o)return;if(a!==void 0)throw new f(a);const y=i.results.find(d=>!d.allowed)?.debugMessages.join("; ")??"batch denied";throw new f(j("permission-denied",`batch failed: ${y}`))}}function xn(e){return typeof e.where=="function"}class Sn{simTx;constructor(t){this.simTx=t}async get(t){if(xn(t)){const i=await t.get();return i.size>0&&this.simTx.getAll(...i.docs.map(a=>a.ref.path)),i}const r=this.simTx.get(t.path).data();return ot(t,r)}create(t,n){return this.simTx.create(t.path,n),this}set(t,n,s){const r=s?.mergeFields;if(r!==void 0)return this.simTx.set(t.path,n,{mergeFields:r}),this;const o=s?.merge===!0;return this.simTx.set(t.path,n,o?!0:void 0),this}update(t,n,...s){const{fields:r}=P(n,s);return this.simTx.update(t.path,ke(r)),this}delete(t){return this.simTx.delete(t.path),this}}class vn{env;auth;bypassRules;provenance;constructor(t,n,s=!1,r){this.env=t,this.auth=n,this.bypassRules=s,this.provenance=r}collection(t){if(!Ae(t))throw new f(j("invalid-argument",`collection path must have an odd number of segments: ${t}`));return new ft(this.env,this.auth,t,this.bypassRules)}doc(t){if(!rt(t))throw new f(j("invalid-argument",`document path must have an even number of segments: ${t}`));return V(this.env,this.auth,t,this.bypassRules)}collectionGroup(t){if(t.length===0||t.includes("/"))throw new f(j("invalid-argument",`collection group id must be a single non-empty segment with no '/': ${t}`));return new De({env:this.env,auth:this.auth,collectionId:t,bypassRules:this.bypassRules})}batch(){return new wn(this.env,this.auth,this.bypassRules)}async runTransaction(t,n){let s;try{s=await this.env.transaction(r=>{const i=new Sn(r);return t(i)},{auth:n?.auth!==void 0?n.auth:this.auth,bypassRules:this.bypassRules,provenance:this.provenance,maxAttempts:n?.maxAttempts})}catch(r){throw r instanceof It?new f(r.simError):r instanceof zt?new f(r.simError):r}if(!s.allowed){if(s.error)throw new f(s.error);const i=s.writes.find(o=>!o.allowed)?.debugMessages.join("; ")??"transaction denied at commit";throw new f(j("permission-denied",`transaction failed: ${i}`))}return s.returnValue}}function Rn(e,t){return new vn(e,t?.auth??null,t?.bypassRules??!1,t?.provenance)}const On=Symbol("pyric/sandbox/context"),kn=Symbol("pyric/sandbox/bypassRules");let me=null;function ss(e){me=e}const En=Symbol.for("pyric.firestore.modular-value");function Ne(e){return En in e}function Fn(e){const t=e;return typeof t.path=="string"&&t.path.length>0||typeof t.collectionPath=="string"&&t.collectionPath.length>0||typeof t.snapshotScope=="function"}function Cn(e){const t=e.trim();if(!t)return[];const n=t.indexOf(": ");if(n!==-1){const r=t.slice(n+2).trim().split("; ").map(i=>i.trim()).filter(i=>i.length>0);if(r.length>0)return r}return[t]}function Be(e,t){if(e instanceof f===!1)return e;const s=e.code;if(s==="permission-denied"===!1)return new w(s,e.message);const i={engine:"firestore",auth:t.auth,reasons:Cn(e.message)},o=e.simError;if(o!==void 0){if(o.queryProof!==void 0&&(i.queryProof=o.queryProof),o.request!==void 0){const l=o.request;i.request={method:l.method,path:l.path},l.resourceData!==void 0&&(i.request.resourceData=l.resourceData),l.updateMask!==void 0&&(i.request.updateMask=l.updateMask)}if(o.resource!==void 0&&(i.resource={data:o.resource.data,exists:o.resource.exists}),o.query!==void 0&&(i.query=o.query),o.rule!==void 0&&(i.rule=o.rule),o.repro!==void 0&&(i.repro=o.repro),o.remediation!==void 0)return new w({code:s,message:e.message,denialContext:i,remediation:o.remediation})}return new w(s,e.message,i)}function ee(e,t,n=!1){return new Proxy(e,{get(s,r,i){if(r===On)return t;if(r===kn)return n;if(r==="onSnapshot"&&me!==null&&!(r in s)&&Fn(s))return(...a)=>me(i,...a);const o=Reflect.get(s,r,i);return typeof o!="function"?o:function(...a){let c;try{const u=()=>o.apply(s,a);c=typeof t.sandbox.runWithProvenance=="function"?t.sandbox.runWithProvenance(nt(t.operationContext),u):u()}catch(u){throw Be(u,t)}return c instanceof Promise?c.then(u=>u&&typeof u=="object"&&!Ne(u)?ee(u,t,n):u).catch(u=>{throw Be(u,t)}):c&&typeof c=="object"&&!Ne(c)?ee(c,t,n):c}}})}function pt(e,t=!1){if(Ce(e.sandbox))throw new Error("pyric/sandbox/admin-firestore: internal — a remote sandbox context reached the local engine builder; remote dispatch should have handled it. Please report this.");const n=()=>Rn(T(e.sandbox),{auth:e.auth,bypassRules:t,provenance:nt(e.operationContext)});return{collection(s){return n().collection(s)},doc(s){return n().doc(s)},collectionGroup(s){return n().collectionGroup(s)},batch(){return n().batch()},runTransaction(s,r){return n().runTransaction(s,r)},setRules(s){return T(e.sandbox).deployRules(s)},seed(s){const r=T(e.sandbox);return r.seed({rules:r.getRules(),documents:s?.documents??{}})},snapshot(){return T(e.sandbox).snapshot()}}}function ye(e){if(e instanceof w)return e;if(e!==null&&typeof e=="object"){const t=e;if(typeof t.code=="string"&&typeof t.message=="string"){const n=t.denialContext!==null&&typeof t.denialContext=="object"?t.denialContext:void 0;return new w(t.code,t.message,n)}}return e}function k(e){return new w("invalid-argument",e)}async function x(e,t){try{return await e.sandbox.channel.op({...t,actAs:e.lens})}catch(n){throw ye(n)}}const An=new Set(["serverTimestamp","increment","arrayUnion","arrayRemove","deleteField"]);function Dn(e){return e!==null&&typeof e=="object"&&typeof e.__type=="string"&&An.has(e.__type)}function jn(e){switch(e.__type){case"serverTimestamp":return{__sentinel:"serverTimestamp"};case"increment":return{__sentinel:"increment",n:e.value};case"arrayUnion":return{__sentinel:"arrayUnion",values:e.values.map(v)};case"arrayRemove":return{__sentinel:"arrayRemove",values:e.values.map(v)};case"deleteField":return{__sentinel:"deleteField"}}}function v(e){if(e===null||typeof e!="object")return e;if(Dn(e))return jn(e);if(e instanceof le)return e.toJSON();if(e instanceof Date)return le.fromDate(e).toJSON();if(Array.isArray(e))return e.map(v);const t=Object.getPrototypeOf(e);if(t!==Object.prototype&&t!==null){const s=e.toJSON;if(typeof s=="function")return s.call(e);throw k(`remote Firestore: cannot serialize a ${t.constructor?.name??"class"} instance for the wire — use plain data, Timestamp, Date, or FieldValue sentinels.`)}const n={};for(const[s,r]of Object.entries(e))n[s]=v(r);return n}function _(e){return v(e)}function je(e){return e.map(t=>({path:[...t.path],value:v(t.value)}))}function be(e){return $t(JSON.parse(e.json),e.valueEncoding)}function mt(e){return ve(be(e))}function yt(e,t){const n=t.exists&&t.data?mt(t.data):void 0;return{id:e.id,ref:e,exists:t.exists,data:()=>n,get:s=>ne(n,s)}}function bt(e,t){const n=t.docs.map(s=>{const r=s.path??s.id,i=te(e,r),o=s.data?mt(s.data):{};return{id:i.id,ref:i,exists:!0,data:()=>o,get:a=>ne(o,a)}});return{size:n.length,empty:n.length===0,docs:n,forEach:et(n)}}const _e=Symbol("pyric/sandbox/admin-firestore/remoteSnapshotRegistrar");function rs(e){if(e===null||typeof e!="object")return;const t=e[_e];return typeof t=="function"?t:void 0}let ge=null;function is(e){ge=e}function gt(...e){if(ge===null)throw new w("failed-precondition","remote Firestore: onSnapshot is not wired yet — import pyric-admin/firestore (or pyric/sandbox/admin-firestore) before subscribing.");return ge(this,...e)}function wt(e,t,n,s,r){const i=n.includeMetadataChanges!==!0;let o;function a(u){const y=ye(u);r!==void 0?r(y):console.error("pyric remote Firestore: uncaught onSnapshot error:",y)}let c;try{c=e.sandbox.channel.subscribe({target:t,actAs:e.lens},u=>{if(s===void 0)return;let d;try{const l=u,b=l.docs;if(Array.isArray(b)){const m=b.map(O=>{const S=O.data,p=S!==void 0;return{path:O.path??O.id,data:p?be(S):{}}});d=Lt({path:xt(t)},m,{excludesMetadataChanges:i},o),o=m}else{const m=l.id;if(typeof m=="string"){const S=l.path??m,p=l.data,N=l.exists===!0&&p!==void 0?be(p):null;d=Qt(S,N)}}}catch(l){c(),a(l);return}d!==void 0&&s(d)},a)}catch(u){throw ye(u)}return c}function xt(e){switch(e.__ref){case"query":return xt(e.source);case"group":return e.collectionId;default:return e.path}}const St=Symbol("pyric/sandbox/admin-firestore/remoteQueryState");function _n(e){if(!(e===null||typeof e!="object"))return e[St]}function vt(e){return e.kind==="where"?(Rt(e.op),{kind:"where",field:e.field,op:e.op,value:v(e.value)}):{kind:e.kind,filters:e.filters.map(vt)}}const Tn=new Set(["<","<=","==","!=",">=",">","in","not-in","array-contains","array-contains-any"]);function Rt(e){if(!Tn.has(e))throw k(`invalid where operator: ${String(e)}`)}function Y(e){const t=[...e.filters];for(const n of e.orders)t.push({kind:"orderBy",field:n.field,direction:n.direction});return e.start&&t.push({kind:e.start.inclusive?"startAt":"startAfter",values:e.start.values.map(v)}),e.end&&t.push({kind:e.end.inclusive?"endAt":"endBefore",values:e.end.values.map(v)}),e.limitCount!==void 0&&t.push(e.limitFromEnd?{kind:"limitToLast",n:e.limitCount}:{kind:"limit",n:e.limitCount}),t.length===0?e.source:{__ref:"query",source:e.source,constraints:t}}function Ge(e,t,n){if(t.length===0)throw k(`${n}(snapshot) on a remote sandbox requires at least one explicit orderBy() clause — the relay protocol has no document-key cursor.`);if(t.some(r=>r.field==="__name__"))throw k(`${n}(snapshot) on a remote sandbox does not support orderBy('__name__') — the relay protocol has no document-key cursor, and __name__ is not a data field a value cursor can carry. Order by a real document field instead.`);const s=e.data();if(s===void 0)throw new w("not-found",`Snapshot-based cursors require an existing document — got an empty snapshot for ${e.id??"<unknown>"}.`);return t.map(r=>s[r.field])}function Te(e,t){const n=r=>Te(e,{...t,...r});return{[St]:t,where(r,i,o){return Rt(i),n({filters:[...t.filters,{kind:"where",field:r,op:i,value:v(o)}]})},applyFilter(r){return n({filters:[...t.filters,vt(r)]})},orderBy(r,i="asc"){return n({orders:[...t.orders,{field:r,direction:i}]})},limit(r){return n({limitCount:r,limitFromEnd:!1})},limitToLast(r){return n({limitCount:r,limitFromEnd:!0})},startCursor(r,i){return n({start:{values:[...r],inclusive:i}})},endCursor(r,i){return n({end:{values:[...r],inclusive:i}})},startCursorFromSnapshot(r,i){return n({start:{values:Ge(r,t.orders,i?"startAt":"startAfter"),inclusive:i}})},endCursorFromSnapshot(r,i){return n({end:{values:Ge(r,t.orders,i?"endAt":"endBefore"),inclusive:i}})},async get(r){J(t);const i=await x(e,{method:"getDocs",source:Y(t)});return bt(e,i)},async aggregate(r){J(t);const i=await x(e,{method:"aggregate",source:Y(t),spec:r});return{data:()=>i.data}},[_e]:(r,i,o)=>(J(t),wt(e,Y(t),r,i,o)),onSnapshot:gt}}function J(e){if(e.limitFromEnd&&e.orders.length===0)throw k("limitToLast() queries require at least one orderBy clause.")}function we(e,t){const n=Te(e,{source:{__ref:"collection",path:t},filters:[],orders:[],limitFromEnd:!1});return Object.assign(Object.create(Object.getPrototypeOf(n)),n,{id:re(t),path:t,doc(r){const i=r??tt();return te(e,`${t}/${i}`)},async add(r,i){const o=await x(e,{method:"addDoc",collectionPath:t,data:_(r)});return te(e,o.path)}})}function te(e,t){const n={id:re(t),path:t,get parent(){return we(e,it(t))},collection(s){const r=`${t}/${s}`;if(!Ae(r))throw k(`collection path must have an odd number of segments: ${r}`);return we(e,r)},async get(s){const r=await x(e,{method:"getDoc",path:t});return yt(n,r)},async create(s,r){await x(e,{method:"batchCommit",writes:[{method:"create",path:t,data:_(s)}]})},async set(s,r){await x(e,{method:"setDoc",path:t,data:_(s),...He(r)?{options:He(r)}:{}})},update(s,...r){const{fields:i}=P(s,r),o=je(i);return x(e,{method:"updateDoc",path:t,fields:o}).then(()=>{})},async delete(s){await x(e,{method:"deleteDoc",path:t})},[_e]:(s,r,i)=>wt(e,{__ref:"doc",path:t},s,r,i),onSnapshot:gt};return n}function He(e){if(!e)return;const t={};return e.merge!==void 0&&(t.merge=e.merge),e.mergeFields!==void 0&&(t.mergeFields=[...e.mergeFields]),t.merge!==void 0||t.mergeFields!==void 0?t:void 0}function Ot(e){if(e===void 0)return;const t={};return"merge"in e&&e.merge!==void 0&&(t.merge=e.merge),"mergeFields"in e&&e.mergeFields!==void 0&&(t.mergeFields=e.mergeFields.map(n=>String(n))),t}function Pn(e){const t=[];let n=!1;const s={create(i,o){return r(),t.push({method:"create",path:i.path,data:_(o)}),s},set(i,o,a){r();const c={method:"set",path:i.path,data:_(o)},u=Ot(a);return u!==void 0&&(c.options=u),t.push(c),s},update(i,o,...a){r();const{fields:c}=P(o,a);return t.push({method:"update",path:i.path,fields:je(c)}),s},delete(i){return r(),t.push({method:"delete",path:i.path}),s},async commit(i){r(),n=!0,await x(e,{method:"batchCommit",writes:t})}};function r(){if(n)throw new w("failed-precondition","WriteBatch has already been committed.")}return s}const qn=5;async function Vn(e,t,n=qn){for(let s=0;s<n;s++){const r=[],i=[],o=()=>{if(i.length>0)throw new w("failed-precondition",Wt)},a={get(d){o();const h=_n(d);return h!==void 0?u(h):c(d)},create(d,h){return i.push({method:"create",path:d.path,data:_(h)}),a},set(d,h,l){const b={method:"set",path:d.path,data:_(h)},A=Ot(l);return A!==void 0&&(b.options=A),i.push(b),a},update(d,h,...l){const{fields:b}=P(h,l);return i.push({method:"update",path:d.path,fields:je(b)}),a},delete(d){return i.push({method:"delete",path:d.path}),a}};async function c(d){const h=await x(e,{method:"getDoc",path:d.path});return r.push({path:h.path??d.path,data:h.exists&&h.data?h.data:null}),yt(d,h)}async function u(d){J(d);const h=await x(e,{method:"getDocs",source:Y(d)});for(const l of h.docs)r.push({path:l.path??l.id,data:l.data??null});return bt(e,h)}const y=await t(a);try{return await x(e,{method:"txnCommit",reads:r,writes:i}),y}catch(d){if(d instanceof w&&d.code==="aborted")continue;throw d}}throw new w("aborted",`Transaction failed after ${n} attempts due to repeated conflicts. Another writer is concurrently updating the same documents.`)}function ue(e,t){return new w("unimplemented",`SandboxFirestore.${e} is not available on a remote sandbox — its return value is synchronous and the data lives in the browser worker. ${t}`)}function kt(e,t){const n={sandbox:e,lens:t};return{collection(s){if(!Ae(s))throw k(`collection path must have an odd number of segments: ${s}`);return we(n,s)},doc(s){if(!rt(s))throw k(`document path must have an even number of segments: ${s}`);return te(n,s)},collectionGroup(s){if(s.length===0||s.includes("/"))throw k(`collection group id must be a single non-empty segment with no '/': ${s}`);return Te(n,{source:{__ref:"group",collectionId:s},filters:[],orders:[],limitFromEnd:!1})},batch(){return Pn(n)},runTransaction(s,r){return Vn(n,s,r?.maxAttempts)},setRules(){throw ue("setRules","Deploy rules asynchronously through the relay instead: `await sandbox.channel.op({ method: 'setFirestoreRules', source })`.")},seed(){throw ue("seed","The relay has no atomic seed op; write seed docs through this handle (`db.doc(path).set(data)` / `db.batch()`), or drive `sandbox.channel.op({ method: 'admin.setDocument', path, data })` per document.")},snapshot(){throw ue("snapshot","Read the worker state asynchronously instead: `await sandbox.channel.op({ method: 'admin.readState' })`.")}}}const Ye=new WeakMap;function Et(e){const t=Ye.get(e);if(t)return t;const n=Ce(e.sandbox)?kt(e.sandbox,Mn(e.auth)):ee(pt(e),e);return Ye.set(e,n),n}function Mn(e){if(e==null)return{mode:"anon"};const t={mode:"as",uid:e.uid};return e.token!==void 0&&(t.token=e.token),e.tenant!==void 0&&(t.tenant=e.tenant),t}const Je=new WeakMap;function In(e){const t=zn(e)?e:e.withAuth(null),n=Je.get(t);if(n)return n;const s=t.operationContext.authLens.mode==="admin"?t:Ee(t,{source:t.operationContext.source,authLens:{mode:"admin"},...t.operationContext.planId===void 0?{}:{planId:t.operationContext.planId}}),r=Ce(s.sandbox)?kt(s.sandbox,{mode:"admin"}):ee(pt(s,!0),s,!0);return Je.set(t,r),r}function zn(e){return e!==null&&typeof e=="object"&&"sandbox"in e&&typeof e.withAuth=="function"}function $n(e){return e instanceof Error&&"code"in e&&typeof e.code=="string"}function Ln(e){if(e instanceof I||!$n(e))return e;const t={};e.denialContext!==void 0&&(t.denialContext=e.denialContext),e.remediation!==void 0&&(t.remediation=e.remediation);const n=new I(e.code,e.message,Object.keys(t).length===0?void 0:t);e.denialContext!==void 0&&Object.assign(n,{denialContext:e.denialContext}),e.remediation!==void 0&&Object.assign(n,{remediation:e.remediation});for(const s of["request","resource","query","rule","queryProof"])e[s]!==void 0&&Object.assign(n,{[s]:e[s]});return n}async function ie(e){try{return await e()}catch(t){throw Ln(t)}}class Qn{static[Symbol.hasInstance](t){return!!(t&&typeof t=="object"&&"id"in t&&"path"in t&&typeof t.path=="string"&&!("docs"in t)&&!("exists"in t)&&!("doc"in t)&&!("add"in t))}}function Ft(e,t){const n=R(e);if(t===null)return n;const r=C(e),i=Ve(n,r,t);return Fe(n,i),xe(i)}function xe(e){function t(n){return Ft(e,n)}return Object.assign(e,{withConverter:t})}function X(e,t,n,s=null){function r(c){return c===null?Xe(a,null):Xe(a,c)}const i=R(e),o=Ve(i,n,s),a=Object.assign(o,{withConverter:r});return M(a,Re("reference",t)),Oe(i,t,n),Fe(i,a),a}function os(e,...t){const n=C(e),s=F in e,r=s?void 0:qe(e),i=W(n);if(s){if(t.length===0)throw new TypeError("doc(db, path) requires at least one path segment.");const l=t.join("/"),b=i.doc(l),A=Q(b,n,m=>m.doc(l));return X(A,l,n)}const o=R(e),a=t.length===0;let c;a?c=o.doc():c=o.doc(t.join("/"));const u=c.path,y=Q(c,n,h=>h.doc(u));return r!=null?X(y,u,n,r):X(y,u,n)}function as(e,...t){const n=C(e),s=F in e;if(t.length===0)throw new TypeError("collection() requires at least one path segment.");if(s){const c=t.join("/"),u=xe(W(n).collection(c));return Q(u,n,y=>y.collection(c))}const r=R(e),i=t.join("/"),o=xe(r.collection(i)),a=o.path;return Q(o,n,c=>c.collection(a))}function Xe(e,t){const n=C(e),s=R(e);return s instanceof Qn?X(s,s.path,n,t):Ft(e,t)}class Wn{started=!1;networkEnabled=!0;persistenceMode;pending=new Set;cachedPaths=new Set;cachedQueries=new WeakSet;syncObservers=new Set;syncScheduled=!1;markStarted(){this.started=!0}enablePersistence(t){if(this.started||this.persistenceMode!==void 0)throw new I("failed-precondition","Firestore has already been started and persistence can no longer be enabled.");this.persistenceMode=t,this.started=!0}disableNetwork(){this.started=!0,this.networkEnabled=!1}async enableNetwork(){this.started=!0,this.networkEnabled=!0;for(const t of this.pending)t.localDone&&t.resolve(t.value);await Promise.all([...this.pending].map(t=>t.promise))}runWrite(t,n){if(this.started=!0,n&&this.cachedPaths.add(n),this.networkEnabled)return t();let s,r;const i=new Promise((a,c)=>{s=a,r=c}),o={path:n,promise:i,localDone:!1,resolve:s,reject:r};return this.pending.add(o),t().then(a=>{o.localDone=!0,o.value=a,this.networkEnabled&&o.resolve(a)},a=>o.reject(a)),i.then(()=>this.pending.delete(o),()=>this.pending.delete(o)),i}waitForPendingWrites(){this.started=!0;const t=[...this.pending].map(n=>n.promise);return Promise.all(t).then(()=>{})}cachePath(t){this.started=!0,this.cachedPaths.add(t)}assertPathCached(t){if(this.started=!0,!this.cachedPaths.has(t))throw new I("unavailable","Failed to get document from cache. (However, this document may exist on the server.)")}cacheQuery(t){this.started=!0,this.cachedQueries.add(t)}hasCachedQuery(t){return this.started=!0,this.cachedQueries.has(t)||this.cachedPaths.size>0}snapshotMetadata(t){return Object.freeze({fromCache:!this.networkEnabled,hasPendingWrites:[...this.pending].some(n=>n.path===t)})}querySnapshotMetadata(){return Object.freeze({fromCache:!this.networkEnabled,hasPendingWrites:this.pending.size>0})}addSnapshotsInSyncObserver(t){return this.syncObservers.add(t),t(),()=>this.syncObservers.delete(t)}notifySnapshotDelivered(){this.syncScheduled||this.syncObservers.size===0||(this.syncScheduled=!0,queueMicrotask(()=>{this.syncScheduled=!1;for(const t of[...this.syncObservers])t()}))}}const Ke=new WeakMap;function L(e){let t=Ke.get(e);return t||(t=new Wn,Ke.set(e,t)),t}function oe(e,t,n,s,r){const i=R(t),o=typeof i.sdkActivitySource=="function"?i.sdkActivitySource():{service:"firestore",target:i.path,key:`doc:${i.path}`};return Ut.begin({app:e.activityApp??e,source:o,method:n,kind:s,owners:Nt(r?.owner,r?.owners)})}const F=Symbol("pyric/firestore/target");function W(e){return e.kind==="sandbox"?e.db:e.getDb()}const ae=new WeakMap;function Un(e,t){return ae.set(e,t),e}const U=new WeakMap;function Nn(e,t,n){return ae.set(e,t),U.set(e,n),e}function Pe(e,t){const n=R(t);if(e.kind==="sandbox")return n;const s=U.get(n);if(!s)throw new TypeError("pyric/firestore: live ref missing rebuild closure — was it produced by a factory in this package?");return s(W(e))}function Bn(e,t){const n=R(t);if(e.kind==="sandbox")return n;const s=U.get(n);if(!s)throw new TypeError("pyric/firestore: live collection ref missing rebuild closure.");return s(W(e))}function cs(e,t){const n=R(t);if(e.kind==="sandbox")return n;const s=U.get(n);if(!s)throw new TypeError("pyric/firestore: live query missing rebuild closure.");return s(W(e))}function Q(e,t,n){return t.kind==="sandbox-live"?Nn(e,t,n):Un(e,t)}function us(e){const t=R(e),n=U.get(t);return n||(()=>t)}function C(e){const t=Gn(e);return t.assertUsable?.(),t}function Gn(e){let t;if(F in e?t=e[F]:t=ae.get(e),!t)throw new TypeError("pyric/firestore: unrecognized reference — was it produced by a factory in this package?");return t}const Hn=Symbol.for("pyric.firestore.modular-value"),Ct=new WeakMap,At=new WeakMap;function qe(e){return Ct.get(e)}function R(e){return At.get(e)??e}function Ve(e,t,n){const s={id:e.id??"",path:e.path??""};return Object.defineProperty(s,Hn,{value:!0}),Ct.set(s,n),At.set(s,e),ae.set(s,t),s}function Yn(e){return e instanceof Kt?Array.from(e.value):null}function Se(e,t){if(e instanceof Yt)return t?.create(e.path)??e;if(e instanceof Jt)return Bt.fromUint8Array(e.data);if(e instanceof Xt)return new Gt(e.lat,e.lng);const i=Yn(e);if(i!==null)return Ht(i);if(Array.isArray(e))return e.map(u=>Se(u,t));if(e!==null&&typeof e=="object"){const u=Object.getPrototypeOf(e);if(u===Object.prototype||u===null){const d={};for(const[h,l]of Object.entries(e))d[h]=Se(l,t);return d}}return e}function ds(e,t){if(e!==void 0)return Se(e,t)}function Jn(e){if(e===void 0)return Jn(sn());const t=st(e);if(t)return t.service("firestore/default",()=>{const{sandbox:n,session:s}=t,r=de();t.onDelete(r.terminate);const i=t.authScope;i&&(r.own(s.onCurrentUserChanged(a=>{T(n).reevaluateLiveListeners(a,i)})),r.own(on(a=>{const c=a?.mode==="anon"?null:a?.mode==="as"?{uid:a.uid,...a.tenant?{tenant:a.tenant}:{}}:s.currentUser;T(n).reevaluateLiveListeners(c,i)})));const o={kind:"sandbox-live",activityApp:e,sandbox:n,getDb:Ze(n,()=>s.currentUser),authScope:i,...r};return{[F]:o,app:e}});if(Dt(e)){const n=Et(e),s={kind:"sandbox",activityApp:e,db:n,sandbox:e.sandbox,...de()};return{[F]:s}}if(Kn(e)){const n={kind:"sandbox-live",activityApp:e,sandbox:e,getDb:Ze(e),...de()};return{[F]:n}}throw new TypeError("pyric/firestore is a sandbox-only mirror. Package resolution must leave firebase/firestore unchanged for production; activate pyric sandbox or @pyric/cli/register before importing to select the sandbox.")}function de(){let e=!1;const t=new Set;return{own(n){return e?(n(),()=>{}):(t.add(n),()=>t.delete(n))},assertUsable(){if(e)throw new I("failed-precondition","The client has already been terminated.")},terminate(){if(!e){e=!0;for(const n of t)n();t.clear()}}}}function Xn(e){const t=st(e);if(t){t.assertAlive();const o=t.sandbox;return Xn(Ee(o.withAuth(null),{source:{kind:"app"},authLens:{mode:"admin"}}))}const n=Dt(e)?e:e.withAuth(null),s=n.sandbox,i={kind:"sandbox",db:In(n),sandbox:s};return{[F]:i}}function Dt(e){return e instanceof Zt}function Kn(e){if(e===null||typeof e!="object")return!1;const t=e;return typeof t.withAuth=="function"&&typeof t.onCurrentUserChanged=="function"&&"currentUser"in t&&"admin"in t}function Ze(e,t=()=>e.currentUser){return()=>{const n=t(),s=Ee(e.withAuth(n),{source:{kind:"app"},authLens:{mode:"app-session"}});return Et(s)}}function Zn(e,t,n,s){const r=en(e,t,n,s);if(r.length===0)return[{}];const i=[];for(const o of r)i.push(new tn(...o.path),o.value);return i}async function ls(e,t,n){const s=C(e);return se(oe(s,e,"setDoc","operation"),async()=>{const r=qe(e),i=r?r.toFirestore(t):t;return L(s).runWrite(()=>ie(()=>Pe(s,e).set(i,n)),e.path)})}function hs(e,t,...n){const s=C(e),r=Zn("updateDoc",e.path,t,n);return se(oe(s,e,"updateDoc","operation"),async()=>L(s).runWrite(()=>ie(()=>Pe(s,e).update(...r)),e.path))}async function fs(e){const t=C(e);return se(oe(t,e,"deleteDoc","operation"),async()=>L(t).runWrite(()=>ie(()=>Pe(t,e).delete()),e.path))}async function ps(e,t){const n=C(e);return se(oe(n,e,"addDoc","operation"),async()=>{const s=qe(e),r=s?s.toFirestore(t):t,i=await L(n).runWrite(async()=>{const c=await ie(()=>Bn(n,e).add(r));return L(n).cachePath(c.path),c}),o=i.path,a=Q(i,n,c=>c.doc(o));if(M(a,Re("reference",o)),Oe(a,o,n,a),s){const c=Ve(a,n,s);return Fe(a,c),c}return a})}export{us as A,kn as B,On as C,Ln as D,xe as E,Q as F,Ft as G,as as H,ps as I,hs as J,fs as K,ts as L,rn as M,se as N,Xn as O,ln as Q,F as T,sn as a,fe as b,L as c,os as d,qe as e,ds as f,Jn as g,At as h,ns as i,W as j,U as k,ct as l,ut as m,oe as n,C as o,cs as p,Pe as q,st as r,ls as s,Un as t,R as u,ss as v,ie as w,is as x,rs as y,Be as z};
@@ -6,7 +6,7 @@
6
6
  </script><link rel="preconnect" href="https://use.typekit.net" crossorigin><link rel="stylesheet" href="https://use.typekit.net/jwb3ycu.css"><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link rel="stylesheet" href="/__pyric/ui/_astro/_studio_.CzyEuvVS.css">
7
7
  <style>html{scrollbar-gutter:stable}
8
8
  </style>
9
- <link rel="stylesheet" href="/__pyric/ui/_astro/app.8TtSeQQX.css"></head> <body> <div id="root" data-astro-cid-w5sm6wlz> <style>astro-island,astro-slot,astro-static-slot{display:contents}</style><script>(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).only=e;window.dispatchEvent(new Event("astro:only"));})();</script><script>(()=>{var A=Object.defineProperty;var g=(i,o,a)=>o in i?A(i,o,{enumerable:!0,configurable:!0,writable:!0,value:a}):i[o]=a;var d=(i,o,a)=>g(i,typeof o!="symbol"?o+"":o,a);{let i={0:t=>m(t),1:t=>a(t),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(a(t)),5:t=>new Set(a(t)),6:t=>BigInt(t),7:t=>new URL(t),8:t=>new Uint8Array(t),9:t=>new Uint16Array(t),10:t=>new Uint32Array(t),11:t=>1/0*t},o=t=>{let[l,e]=t;return l in i?i[l](e):void 0},a=t=>t.map(o),m=t=>typeof t!="object"||t===null?t:Object.fromEntries(Object.entries(t).map(([l,e])=>[l,o(e)]));class y extends HTMLElement{constructor(){super(...arguments);d(this,"Component");d(this,"hydrator");d(this,"hydrate",async()=>{var b;if(!this.hydrator||!this.isConnected)return;let e=(b=this.parentElement)==null?void 0:b.closest("astro-island[ssr]");if(e){e.addEventListener("astro:hydrate",this.hydrate,{once:!0});return}let c=this.querySelectorAll("astro-slot"),n={},h=this.querySelectorAll("template[data-astro-template]");for(let r of h){let s=r.closest(this.tagName);s!=null&&s.isSameNode(this)&&(n[r.getAttribute("data-astro-template")||"default"]=r.innerHTML,r.remove())}for(let r of c){let s=r.closest(this.tagName);s!=null&&s.isSameNode(this)&&(n[r.getAttribute("name")||"default"]=r.innerHTML)}let p;try{p=this.hasAttribute("props")?m(JSON.parse(this.getAttribute("props"))):{}}catch(r){let s=this.getAttribute("component-url")||"<unknown>",v=this.getAttribute("component-export");throw v&&(s+=` (export ${v})`),console.error(`[hydrate] Error parsing props for component ${s}`,this.getAttribute("props"),r),r}let u;await this.hydrator(this)(this.Component,p,n,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),this.dispatchEvent(new CustomEvent("astro:hydrate"))});d(this,"unmount",()=>{this.isConnected||this.dispatchEvent(new CustomEvent("astro:unmount"))})}disconnectedCallback(){document.removeEventListener("astro:after-swap",this.unmount),document.addEventListener("astro:after-swap",this.unmount,{once:!0})}connectedCallback(){if(!this.hasAttribute("await-children")||document.readyState==="interactive"||document.readyState==="complete")this.childrenConnectedCallback();else{let e=()=>{document.removeEventListener("DOMContentLoaded",e),c.disconnect(),this.childrenConnectedCallback()},c=new MutationObserver(()=>{var n;((n=this.lastChild)==null?void 0:n.nodeType)===Node.COMMENT_NODE&&this.lastChild.nodeValue==="astro:end"&&(this.lastChild.remove(),e())});c.observe(this,{childList:!0}),document.addEventListener("DOMContentLoaded",e)}}async childrenConnectedCallback(){let e=this.getAttribute("before-hydration-url");e&&await import(e),this.start()}async start(){let e=JSON.parse(this.getAttribute("opts")),c=this.getAttribute("client");if(Astro[c]===void 0){window.addEventListener(`astro:${c}`,()=>this.start(),{once:!0});return}try{await Astro[c](async()=>{let n=this.getAttribute("renderer-url"),[h,{default:p}]=await Promise.all([import(this.getAttribute("component-url")),n?import(n):()=>()=>{}]),u=this.getAttribute("component-export")||"default";if(!u.includes("."))this.Component=h[u];else{this.Component=h;for(let f of u.split("."))this.Component=this.Component[f]}return this.hydrator=p,this.hydrate},e,this)}catch(n){console.error(`[astro-island] Error hydrating ${this.getAttribute("component-url")}`,n)}}attributeChangedCallback(){this.hydrate()}}d(y,"observedAttributes",["props"]),customElements.get("astro-island")||customElements.define("astro-island",y)}})();</script><astro-island uid="b1btC" component-url="/__pyric/ui/_astro/app.DpzsBfos.js" component-export="StudioApp" renderer-url="/__pyric/ui/_astro/client.D2ORs4B-.js" props="{&quot;data-astro-cid-w5sm6wlz&quot;:[0,true]}" ssr client="only" opts="{&quot;name&quot;:&quot;StudioApp&quot;,&quot;value&quot;:&quot;react&quot;}" await-children><p class="studio-loading" aria-live="polite" data-astro-cid-w5sm6wlz>
9
+ <link rel="stylesheet" href="/__pyric/ui/_astro/app.8TtSeQQX.css"></head> <body> <div id="root" data-astro-cid-w5sm6wlz> <style>astro-island,astro-slot,astro-static-slot{display:contents}</style><script>(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).only=e;window.dispatchEvent(new Event("astro:only"));})();</script><script>(()=>{var A=Object.defineProperty;var g=(i,o,a)=>o in i?A(i,o,{enumerable:!0,configurable:!0,writable:!0,value:a}):i[o]=a;var d=(i,o,a)=>g(i,typeof o!="symbol"?o+"":o,a);{let i={0:t=>m(t),1:t=>a(t),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(a(t)),5:t=>new Set(a(t)),6:t=>BigInt(t),7:t=>new URL(t),8:t=>new Uint8Array(t),9:t=>new Uint16Array(t),10:t=>new Uint32Array(t),11:t=>1/0*t},o=t=>{let[l,e]=t;return l in i?i[l](e):void 0},a=t=>t.map(o),m=t=>typeof t!="object"||t===null?t:Object.fromEntries(Object.entries(t).map(([l,e])=>[l,o(e)]));class y extends HTMLElement{constructor(){super(...arguments);d(this,"Component");d(this,"hydrator");d(this,"hydrate",async()=>{var b;if(!this.hydrator||!this.isConnected)return;let e=(b=this.parentElement)==null?void 0:b.closest("astro-island[ssr]");if(e){e.addEventListener("astro:hydrate",this.hydrate,{once:!0});return}let c=this.querySelectorAll("astro-slot"),n={},h=this.querySelectorAll("template[data-astro-template]");for(let r of h){let s=r.closest(this.tagName);s!=null&&s.isSameNode(this)&&(n[r.getAttribute("data-astro-template")||"default"]=r.innerHTML,r.remove())}for(let r of c){let s=r.closest(this.tagName);s!=null&&s.isSameNode(this)&&(n[r.getAttribute("name")||"default"]=r.innerHTML)}let p;try{p=this.hasAttribute("props")?m(JSON.parse(this.getAttribute("props"))):{}}catch(r){let s=this.getAttribute("component-url")||"<unknown>",v=this.getAttribute("component-export");throw v&&(s+=` (export ${v})`),console.error(`[hydrate] Error parsing props for component ${s}`,this.getAttribute("props"),r),r}let u;await this.hydrator(this)(this.Component,p,n,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),this.dispatchEvent(new CustomEvent("astro:hydrate"))});d(this,"unmount",()=>{this.isConnected||this.dispatchEvent(new CustomEvent("astro:unmount"))})}disconnectedCallback(){document.removeEventListener("astro:after-swap",this.unmount),document.addEventListener("astro:after-swap",this.unmount,{once:!0})}connectedCallback(){if(!this.hasAttribute("await-children")||document.readyState==="interactive"||document.readyState==="complete")this.childrenConnectedCallback();else{let e=()=>{document.removeEventListener("DOMContentLoaded",e),c.disconnect(),this.childrenConnectedCallback()},c=new MutationObserver(()=>{var n;((n=this.lastChild)==null?void 0:n.nodeType)===Node.COMMENT_NODE&&this.lastChild.nodeValue==="astro:end"&&(this.lastChild.remove(),e())});c.observe(this,{childList:!0}),document.addEventListener("DOMContentLoaded",e)}}async childrenConnectedCallback(){let e=this.getAttribute("before-hydration-url");e&&await import(e),this.start()}async start(){let e=JSON.parse(this.getAttribute("opts")),c=this.getAttribute("client");if(Astro[c]===void 0){window.addEventListener(`astro:${c}`,()=>this.start(),{once:!0});return}try{await Astro[c](async()=>{let n=this.getAttribute("renderer-url"),[h,{default:p}]=await Promise.all([import(this.getAttribute("component-url")),n?import(n):()=>()=>{}]),u=this.getAttribute("component-export")||"default";if(!u.includes("."))this.Component=h[u];else{this.Component=h;for(let f of u.split("."))this.Component=this.Component[f]}return this.hydrator=p,this.hydrate},e,this)}catch(n){console.error(`[astro-island] Error hydrating ${this.getAttribute("component-url")}`,n)}}attributeChangedCallback(){this.hydrate()}}d(y,"observedAttributes",["props"]),customElements.get("astro-island")||customElements.define("astro-island",y)}})();</script><astro-island uid="b1btC" component-url="/__pyric/ui/_astro/app.DqyhRyrU.js" component-export="StudioApp" renderer-url="/__pyric/ui/_astro/client.D2ORs4B-.js" props="{&quot;data-astro-cid-w5sm6wlz&quot;:[0,true]}" ssr client="only" opts="{&quot;name&quot;:&quot;StudioApp&quot;,&quot;value&quot;:&quot;react&quot;}" await-children><p class="studio-loading" aria-live="polite" data-astro-cid-w5sm6wlz>
10
10
  Starting Pyric Studio…
11
11
  </p><template data-astro-template="fallback"><p class="studio-loading" aria-live="polite" data-astro-cid-w5sm6wlz>
12
12
  Starting Pyric Studio…
@@ -2,7 +2,7 @@
2
2
  <link rel="stylesheet" href="/__pyric/ui/_astro/_slug_.Da5VLhW1.css">
3
3
  <style>:root{--rhythm-para: .875rem;--rhythm-group: 1.5rem;--rhythm-subsection: 2.25rem;--rhythm-section: 3.25rem;--rhythm-list: calc(var(--rhythm-para) * .75)}.prose>*,.prose blockquote>*,.prose li>*,.prose .compat-stat>*{margin-block:0}.prose>*+*{margin-block-start:var(--rhythm-group)}.prose>*+h2{margin-block-start:var(--rhythm-section)}.prose>*+h3,.prose>*+h4{margin-block-start:var(--rhythm-subsection)}.prose>h1+*,.prose>h2+*,.prose>h3+*,.prose>h4+*{margin-block-start:var(--rhythm-para)}.prose>p+p{margin-block-start:var(--rhythm-para)}.prose>p+ul,.prose>p+ol,.prose>p+blockquote{margin-block-start:var(--rhythm-para)}.prose li+li{margin-block-start:var(--rhythm-list)}.prose li>ul,.prose li>ol{margin-block-start:var(--rhythm-list)}.prose li>*+*,.prose blockquote>*+*{margin-block-start:var(--rhythm-para)}
4
4
  html{scrollbar-gutter:stable}
5
- </style></head> <body> <header class="studio__chrome"> <div class="studio__bar"> <div class="studio__chrome-inner"> <nav class="studio__nav" aria-label="Site"> <a class="studio__brand" href="/__pyric/ui/" aria-label="Pyric">pyric</a> <a class="studio__nav-tab" href="/__pyric/ui/"> Home </a><a class="studio__nav-tab" href="/__pyric/ui/docs" aria-current="page"> Docs </a><a class="studio__nav-tab" href="/__pyric/ui/studio"> Studio </a> </nav> </div> </div> </header> <div class="docs-shell" data-astro-cid-mw7aashj> <details class="docs-nav-drawer" data-astro-cid-mw7aashj> <summary data-astro-cid-mw7aashj>Navigate</summary> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <script type="module">let i=null;function d(t){return i||(i=fetch(t).then(e=>e.json())),i}function l(t,e){return t.title.toLowerCase().includes(e)||t.excerpt.toLowerCase().includes(e)?!0:t.headings.some(r=>r.text.toLowerCase().includes(e))}function u(t,e,r){if(e.innerHTML="",t.length===0){e.hidden=!1;{const n=document.createElement("li");n.className="docs-search-empty",n.textContent="No matches",e.appendChild(n)}return}e.hidden=!1;for(const n of t.slice(0,8)){const s=document.createElement("li"),c=document.createElement("a");c.href=n.path;const o=document.createElement("span");o.className="docs-search-result-title",o.textContent=n.title;const a=document.createElement("span");a.className="docs-search-result-meta",a.textContent=[n.group,n.section].filter(Boolean).join(" / "),c.append(o,a),s.appendChild(c),e.appendChild(s)}}document.querySelectorAll(".docs-search").forEach(t=>{const e=t.dataset.indexUrl,r=t.querySelector(".docs-search-input"),n=t.querySelector(".docs-search-results");r.addEventListener("input",async()=>{const s=r.value.trim().toLowerCase();if(!s){n.hidden=!0,n.innerHTML="";return}const{pages:c}=await d(e);r.value.trim().toLowerCase()===s&&u(c.filter(o=>l(o,s)),n)}),r.addEventListener("focus",()=>{d(e),n.childElementCount>0&&(n.hidden=!1)}),r.addEventListener("keydown",s=>{s.key==="Escape"&&(r.value="",n.hidden=!0,n.innerHTML="",r.blur())}),r.addEventListener("blur",()=>{window.setTimeout(()=>{n.hidden=!0},150)})});document.addEventListener("keydown",t=>{if(!(t.metaKey||t.ctrlKey)||t.key.toLowerCase()!=="k")return;const e=[...document.querySelectorAll(".docs-search-input")].find(r=>r.offsetParent!==null);e&&(t.preventDefault(),e.focus(),e.select())});</script> <details class="docs-nav-group"> <summary>Overview</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/overview/"> Overview </a> </li><li> <a href="/__pyric/ui/docs/tutorial/"> Tutorial </a> </li><li> <a href="/__pyric/ui/docs/examples/"> Examples </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Get started</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/get-started/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/get-started/vite/"> Vite </a> </li><li> <a href="/__pyric/ui/docs/get-started/node-host/"> Node host </a> </li><li> <a href="/__pyric/ui/docs/get-started/nextjs/"> Next.js </a> </li><li> <a href="/__pyric/ui/docs/get-started/backend-bundlers/"> Backend bundlers </a> </li><li> <a href="/__pyric/ui/docs/get-started/flutter/"> Flutter </a> </li><li> <a href="/__pyric/ui/docs/get-started/how-the-swap-works/"> How the swap works </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Build</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/build/authentication/"> Authentication </a> </li><li> <a href="/__pyric/ui/docs/build/default-avatars/"> Default avatars </a> </li><li> <a href="/__pyric/ui/docs/build/inspect-activity/"> Activity on the page </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-firestore/"> Cloud Firestore </a> </li><li> <a href="/__pyric/ui/docs/build/realtime-database/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-storage/"> Cloud Storage </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-messaging/"> Cloud Messaging </a> </li><li> <a href="/__pyric/ui/docs/build/ai-logic/"> AI Logic </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Secure &amp; debug</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/secure/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/secure/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/secure/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/secure/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/secure/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-standard-library/"> RTDB rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/secure/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Examples </h2> <ul> <li> <a href="/__pyric/ui/docs/examples/chess/"> Chess showcase </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Observe &amp; shape</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/observe/see-whats-happening/"> Traffic &amp; rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/observe/resolve-runtime-status/"> Runtime status </a> </li><li> <a href="/__pyric/ui/docs/observe/switch-and-impersonate-identities/"> Impersonate &amp; tenants </a> </li><li> <a href="/__pyric/ui/docs/observe/shape-your-data/"> Seed, snapshot, replay </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Ship &amp; test</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/ship/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Work with an agent</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/agent/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/agent/work-with-an-agent/"> Use the MCP tools </a> </li><li> <a href="/__pyric/ui/docs/agent/watch-and-review/"> Watch in Pyric Studio </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Trust</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/trust/versioning-and-compatibility/"> Versioning and the fb tag </a> </li><li> <a href="/__pyric/ui/docs/trust/rules-standard-library/"> Rules standard library reference </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/trust/how-we-know-it-matches-firebase/"> How we know it matches Firebase </a> </li><li> <a href="/__pyric/ui/docs/app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/functions-rtdb-compat/"> Functions · RTDB </a> </li><li> <a href="/__pyric/ui/docs/rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/firestore-flutter-compat/"> Firestore · Flutter </a> </li><li> <a href="/__pyric/ui/docs/firestore-kotlin-compat/"> Firestore · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/firestore-swift-compat/"> Firestore · Swift </a> </li><li> <a href="/__pyric/ui/docs/auth-flutter-compat/"> Auth · Flutter </a> </li><li> <a href="/__pyric/ui/docs/auth-kotlin-compat/"> Auth · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/auth-swift-compat/"> FirebaseAuth Swift </a> </li><li> <a href="/__pyric/ui/docs/rtdb-flutter-compat/"> Realtime Database · Flutter </a> </li><li> <a href="/__pyric/ui/docs/rtdb-kotlin-compat/"> Realtime Database · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/rtdb-swift-compat/"> Realtime Database · Swift </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group"> <summary>Reference</summary> <div class="docs-nav-group-body docs-nav-group-body--reference"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">pyric</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-app-reference-api/"> pyric/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-api/"> pyric/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-lite-reference-api/"> pyric/firestore/lite </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-reference-api/"> pyric/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-reference-api/"> pyric/ai </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-scripting-reference-api/"> pyric/ai/scripting </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-reference-api/"> pyric/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-api/"> pyric/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-reference-api/"> pyric/messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-sw-reference-api/"> pyric/messaging/sw </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-api/"> pyric/rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-api/"> pyric/sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-branches-store-reference-api/"> pyric/sandbox/branches/store </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-checkpoints-reference-api/"> pyric/sandbox/checkpoints </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-checkpoints-directory-reference-api/"> pyric/sandbox/checkpoints/directory </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-firestore-reference-api/"> pyric/sandbox/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-database-reference-api/"> pyric/sandbox/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-check-reference-api/"> pyric/app-check </a> </li><li> <a href="/__pyric/ui/docs/pyric-functions-reference-api/"> pyric/functions </a> </li><li> <a href="/__pyric/ui/docs/pyric-analytics-reference-api/"> pyric/analytics </a> </li><li> <a href="/__pyric/ui/docs/pyric-performance-reference-api/"> pyric/performance </a> </li><li> <a href="/__pyric/ui/docs/pyric-remote-config-reference-api/"> pyric/remote-config </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">pyric-admin</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-reference-api/"> pyric-admin </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app-reference-api/"> pyric-admin/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-api/"> pyric-admin/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth-reference-api/"> pyric-admin/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database-reference-api/"> pyric-admin/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage-reference-api/"> pyric-admin/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-messaging-reference-api/"> pyric-admin/messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app-check-reference-api/"> pyric-admin/app-check </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-data-connect-reference-api/"> pyric-admin/data-connect </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-eventarc-reference-api/"> pyric-admin/eventarc </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-extensions-reference-api/"> pyric-admin/extensions </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-functions-reference-api/"> pyric-admin/functions </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-installations-reference-api/"> pyric-admin/installations </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-instance-id-reference-api/"> pyric-admin/instance-id </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-machine-learning-reference-api/"> pyric-admin/machine-learning </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-phone-number-verification-reference-api/"> pyric-admin/phone-number-verification </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-project-management-reference-api/"> pyric-admin/project-management </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-remote-config-reference-api/"> pyric-admin/remote-config </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-security-rules-reference-api/"> pyric-admin/security-rules </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">create-pyric</h2> <ul> <li> <a href="/__pyric/ui/docs/create-pyric-reference-api/"> create-pyric </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/cli</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-credentials-node-reference-api/"> @pyric/cli/credentials/node </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-verify-reference-api/"> @pyric/cli/verify </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-repro-reference-api/"> @pyric/cli/repro </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-reference-api/"> @pyric/cli/conformance </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-browser-reference-api/"> @pyric/cli/conformance/browser </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-docs-reference-api/"> @pyric/cli/conformance/docs </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-assurance-reference-api/"> @pyric/cli/assurance </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-assurance-browser-reference-api/"> @pyric/cli/assurance/browser </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bridge-reference-api/"> @pyric/cli/bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bridge-client-reference-api/"> @pyric/cli/bridge/client </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-discover-reference-api/"> @pyric/cli/discover </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-vite-reference-api/"> @pyric/cli/vite </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-vite-ssr-loader-reference-api/"> @pyric/cli/vite/ssr-loader </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-next-reference-api/"> @pyric/cli/next </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bundler-reference-api/"> @pyric/cli/bundler </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-serve-worker-reference-api/"> @pyric/cli/serve/worker </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-remote-reference-api/"> @pyric/cli/remote </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-reference-api/"> @pyric/cli/register </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-app-bridge-reference-api/"> @pyric/cli/register/app-bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-app-reference-api/"> @pyric/cli/register/client/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-app-bridge-reference-api/"> @pyric/cli/register/client/app-bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-auth-reference-api/"> @pyric/cli/register/client/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-database-reference-api/"> @pyric/cli/register/client/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-firestore-reference-api/"> @pyric/cli/register/client/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-storage-reference-api/"> @pyric/cli/register/client/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-flow-reference-api/"> @pyric/cli/flow </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/ui</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-ui-auth-reference-api/"> @pyric/ui/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-auth-hooks-reference-api/"> @pyric/ui/auth/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-primitives-reference-api/"> @pyric/ui/primitives </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-listener-owner-reference-api/"> @pyric/ui/listener-owner </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-firestore-reference-api/"> @pyric/ui/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-firestore-hooks-reference-api/"> @pyric/ui/firestore/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rtdb-reference-api/"> @pyric/ui/rtdb </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-storage-reference-api/"> @pyric/ui/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-storage-hooks-reference-api/"> @pyric/ui/storage/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-traffic-reference-api/"> @pyric/ui/traffic </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-traffic-hooks-reference-api/"> @pyric/ui/traffic/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-events-reference-api/"> @pyric/ui/events </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-events-hooks-reference-api/"> @pyric/ui/events/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-agents-reference-api/"> @pyric/ui/agents </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rules-reference-api/"> @pyric/ui/rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rules-hooks-reference-api/"> @pyric/ui/rules/hooks </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/cli</h2> <ul> <li> <a href="/__pyric/ui/docs/reference/cli/"> CLI </a> </li> </ul> </div> </div> </details> </nav> </details> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <details class="docs-nav-group" id="nav-group-overview"> <summary>Overview</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/overview/"> Overview </a> </li><li> <a href="/__pyric/ui/docs/tutorial/"> Tutorial </a> </li><li> <a href="/__pyric/ui/docs/examples/"> Examples </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-get-started"> <summary>Get started</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/get-started/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/get-started/vite/"> Vite </a> </li><li> <a href="/__pyric/ui/docs/get-started/node-host/"> Node host </a> </li><li> <a href="/__pyric/ui/docs/get-started/nextjs/"> Next.js </a> </li><li> <a href="/__pyric/ui/docs/get-started/backend-bundlers/"> Backend bundlers </a> </li><li> <a href="/__pyric/ui/docs/get-started/flutter/"> Flutter </a> </li><li> <a href="/__pyric/ui/docs/get-started/how-the-swap-works/"> How the swap works </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-build"> <summary>Build</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/build/authentication/"> Authentication </a> </li><li> <a href="/__pyric/ui/docs/build/default-avatars/"> Default avatars </a> </li><li> <a href="/__pyric/ui/docs/build/inspect-activity/"> Activity on the page </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-firestore/"> Cloud Firestore </a> </li><li> <a href="/__pyric/ui/docs/build/realtime-database/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-storage/"> Cloud Storage </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-messaging/"> Cloud Messaging </a> </li><li> <a href="/__pyric/ui/docs/build/ai-logic/"> AI Logic </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-secure-debug"> <summary>Secure &amp; debug</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/secure/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/secure/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/secure/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/secure/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/secure/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-standard-library/"> RTDB rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/secure/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-secure-debug-examples"> Examples </h2> <ul> <li> <a href="/__pyric/ui/docs/examples/chess/"> Chess showcase </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-observe-shape"> <summary>Observe &amp; shape</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/observe/see-whats-happening/"> Traffic &amp; rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/observe/resolve-runtime-status/"> Runtime status </a> </li><li> <a href="/__pyric/ui/docs/observe/switch-and-impersonate-identities/"> Impersonate &amp; tenants </a> </li><li> <a href="/__pyric/ui/docs/observe/shape-your-data/"> Seed, snapshot, replay </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-ship-test"> <summary>Ship &amp; test</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/ship/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-work-with-an-agent"> <summary>Work with an agent</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/agent/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/agent/work-with-an-agent/"> Use the MCP tools </a> </li><li> <a href="/__pyric/ui/docs/agent/watch-and-review/"> Watch in Pyric Studio </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-trust"> <summary>Trust</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/trust/versioning-and-compatibility/"> Versioning and the fb tag </a> </li><li> <a href="/__pyric/ui/docs/trust/rules-standard-library/"> Rules standard library reference </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-conformance"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/trust/how-we-know-it-matches-firebase/"> How we know it matches Firebase </a> </li><li> <a href="/__pyric/ui/docs/app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/functions-rtdb-compat/"> Functions · RTDB </a> </li><li> <a href="/__pyric/ui/docs/rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/firestore-flutter-compat/"> Firestore · Flutter </a> </li><li> <a href="/__pyric/ui/docs/firestore-kotlin-compat/"> Firestore · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/firestore-swift-compat/"> Firestore · Swift </a> </li><li> <a href="/__pyric/ui/docs/auth-flutter-compat/"> Auth · Flutter </a> </li><li> <a href="/__pyric/ui/docs/auth-kotlin-compat/"> Auth · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/auth-swift-compat/"> FirebaseAuth Swift </a> </li><li> <a href="/__pyric/ui/docs/rtdb-flutter-compat/"> Realtime Database · Flutter </a> </li><li> <a href="/__pyric/ui/docs/rtdb-kotlin-compat/"> Realtime Database · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/rtdb-swift-compat/"> Realtime Database · Swift </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group" id="nav-group-reference"> <summary>Reference</summary> <div class="docs-nav-group-body docs-nav-group-body--reference"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">pyric</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-app-reference-api/"> pyric/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-api/"> pyric/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-lite-reference-api/"> pyric/firestore/lite </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-reference-api/"> pyric/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-reference-api/"> pyric/ai </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-scripting-reference-api/"> pyric/ai/scripting </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-reference-api/"> pyric/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-api/"> pyric/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-reference-api/"> pyric/messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-sw-reference-api/"> pyric/messaging/sw </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-api/"> pyric/rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-api/"> pyric/sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-branches-store-reference-api/"> pyric/sandbox/branches/store </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-checkpoints-reference-api/"> pyric/sandbox/checkpoints </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-checkpoints-directory-reference-api/"> pyric/sandbox/checkpoints/directory </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-firestore-reference-api/"> pyric/sandbox/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-database-reference-api/"> pyric/sandbox/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-check-reference-api/"> pyric/app-check </a> </li><li> <a href="/__pyric/ui/docs/pyric-functions-reference-api/"> pyric/functions </a> </li><li> <a href="/__pyric/ui/docs/pyric-analytics-reference-api/"> pyric/analytics </a> </li><li> <a href="/__pyric/ui/docs/pyric-performance-reference-api/"> pyric/performance </a> </li><li> <a href="/__pyric/ui/docs/pyric-remote-config-reference-api/"> pyric/remote-config </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">pyric-admin</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-reference-api/"> pyric-admin </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app-reference-api/"> pyric-admin/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-api/"> pyric-admin/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth-reference-api/"> pyric-admin/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database-reference-api/"> pyric-admin/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage-reference-api/"> pyric-admin/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-messaging-reference-api/"> pyric-admin/messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app-check-reference-api/"> pyric-admin/app-check </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-data-connect-reference-api/"> pyric-admin/data-connect </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-eventarc-reference-api/"> pyric-admin/eventarc </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-extensions-reference-api/"> pyric-admin/extensions </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-functions-reference-api/"> pyric-admin/functions </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-installations-reference-api/"> pyric-admin/installations </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-instance-id-reference-api/"> pyric-admin/instance-id </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-machine-learning-reference-api/"> pyric-admin/machine-learning </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-phone-number-verification-reference-api/"> pyric-admin/phone-number-verification </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-project-management-reference-api/"> pyric-admin/project-management </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-remote-config-reference-api/"> pyric-admin/remote-config </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-security-rules-reference-api/"> pyric-admin/security-rules </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">create-pyric</h2> <ul> <li> <a href="/__pyric/ui/docs/create-pyric-reference-api/"> create-pyric </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/cli</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-credentials-node-reference-api/"> @pyric/cli/credentials/node </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-verify-reference-api/"> @pyric/cli/verify </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-repro-reference-api/"> @pyric/cli/repro </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-reference-api/"> @pyric/cli/conformance </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-browser-reference-api/"> @pyric/cli/conformance/browser </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-docs-reference-api/"> @pyric/cli/conformance/docs </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-assurance-reference-api/"> @pyric/cli/assurance </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-assurance-browser-reference-api/"> @pyric/cli/assurance/browser </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bridge-reference-api/"> @pyric/cli/bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bridge-client-reference-api/"> @pyric/cli/bridge/client </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-discover-reference-api/"> @pyric/cli/discover </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-vite-reference-api/"> @pyric/cli/vite </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-vite-ssr-loader-reference-api/"> @pyric/cli/vite/ssr-loader </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-next-reference-api/"> @pyric/cli/next </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bundler-reference-api/"> @pyric/cli/bundler </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-serve-worker-reference-api/"> @pyric/cli/serve/worker </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-remote-reference-api/"> @pyric/cli/remote </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-reference-api/"> @pyric/cli/register </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-app-bridge-reference-api/"> @pyric/cli/register/app-bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-app-reference-api/"> @pyric/cli/register/client/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-app-bridge-reference-api/"> @pyric/cli/register/client/app-bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-auth-reference-api/"> @pyric/cli/register/client/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-database-reference-api/"> @pyric/cli/register/client/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-firestore-reference-api/"> @pyric/cli/register/client/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-storage-reference-api/"> @pyric/cli/register/client/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-flow-reference-api/"> @pyric/cli/flow </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/ui</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-ui-auth-reference-api/"> @pyric/ui/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-auth-hooks-reference-api/"> @pyric/ui/auth/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-primitives-reference-api/"> @pyric/ui/primitives </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-listener-owner-reference-api/"> @pyric/ui/listener-owner </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-firestore-reference-api/"> @pyric/ui/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-firestore-hooks-reference-api/"> @pyric/ui/firestore/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rtdb-reference-api/"> @pyric/ui/rtdb </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-storage-reference-api/"> @pyric/ui/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-storage-hooks-reference-api/"> @pyric/ui/storage/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-traffic-reference-api/"> @pyric/ui/traffic </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-traffic-hooks-reference-api/"> @pyric/ui/traffic/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-events-reference-api/"> @pyric/ui/events </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-events-hooks-reference-api/"> @pyric/ui/events/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-agents-reference-api/"> @pyric/ui/agents </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rules-reference-api/"> @pyric/ui/rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rules-hooks-reference-api/"> @pyric/ui/rules/hooks </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/cli</h2> <ul> <li> <a href="/__pyric/ui/docs/reference/cli/"> CLI </a> </li> </ul> </div> </div> </details> </nav> <main class="doc-main" data-astro-cid-mw7aashj> <article class="prose" data-astro-cid-mw7aashj> <h1 id="rhythm-audit">Rhythm audit</h1>
5
+ </style></head> <body> <header class="studio__chrome"> <div class="studio__bar"> <div class="studio__chrome-inner"> <nav class="studio__nav" aria-label="Site"> <a class="studio__brand" href="/__pyric/ui/" aria-label="Pyric">pyric</a> <a class="studio__nav-tab" href="/__pyric/ui/"> Home </a><a class="studio__nav-tab" href="/__pyric/ui/docs" aria-current="page"> Docs </a><a class="studio__nav-tab" href="/__pyric/ui/studio"> Studio </a> </nav> </div> </div> </header> <div class="docs-shell" data-astro-cid-mw7aashj> <details class="docs-nav-drawer" data-astro-cid-mw7aashj> <summary data-astro-cid-mw7aashj>Navigate</summary> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <script type="module">let i=null;function d(t){return i||(i=fetch(t).then(e=>e.json())),i}function l(t,e){return t.title.toLowerCase().includes(e)||t.excerpt.toLowerCase().includes(e)?!0:t.headings.some(r=>r.text.toLowerCase().includes(e))}function u(t,e,r){if(e.innerHTML="",t.length===0){e.hidden=!1;{const n=document.createElement("li");n.className="docs-search-empty",n.textContent="No matches",e.appendChild(n)}return}e.hidden=!1;for(const n of t.slice(0,8)){const s=document.createElement("li"),c=document.createElement("a");c.href=n.path;const o=document.createElement("span");o.className="docs-search-result-title",o.textContent=n.title;const a=document.createElement("span");a.className="docs-search-result-meta",a.textContent=[n.group,n.section].filter(Boolean).join(" / "),c.append(o,a),s.appendChild(c),e.appendChild(s)}}document.querySelectorAll(".docs-search").forEach(t=>{const e=t.dataset.indexUrl,r=t.querySelector(".docs-search-input"),n=t.querySelector(".docs-search-results");r.addEventListener("input",async()=>{const s=r.value.trim().toLowerCase();if(!s){n.hidden=!0,n.innerHTML="";return}const{pages:c}=await d(e);r.value.trim().toLowerCase()===s&&u(c.filter(o=>l(o,s)),n)}),r.addEventListener("focus",()=>{d(e),n.childElementCount>0&&(n.hidden=!1)}),r.addEventListener("keydown",s=>{s.key==="Escape"&&(r.value="",n.hidden=!0,n.innerHTML="",r.blur())}),r.addEventListener("blur",()=>{window.setTimeout(()=>{n.hidden=!0},150)})});document.addEventListener("keydown",t=>{if(!(t.metaKey||t.ctrlKey)||t.key.toLowerCase()!=="k")return;const e=[...document.querySelectorAll(".docs-search-input")].find(r=>r.offsetParent!==null);e&&(t.preventDefault(),e.focus(),e.select())});</script> <details class="docs-nav-group"> <summary>Overview</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/overview/"> Overview </a> </li><li> <a href="/__pyric/ui/docs/tutorial/"> Tutorial </a> </li><li> <a href="/__pyric/ui/docs/examples/"> Examples </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Get started</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/get-started/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/get-started/vite/"> Vite </a> </li><li> <a href="/__pyric/ui/docs/get-started/node-host/"> Node host </a> </li><li> <a href="/__pyric/ui/docs/get-started/nextjs/"> Next.js </a> </li><li> <a href="/__pyric/ui/docs/get-started/backend-bundlers/"> Backend bundlers </a> </li><li> <a href="/__pyric/ui/docs/get-started/flutter/"> Flutter </a> </li><li> <a href="/__pyric/ui/docs/get-started/how-the-swap-works/"> How the swap works </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Build</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/build/authentication/"> Authentication </a> </li><li> <a href="/__pyric/ui/docs/build/default-avatars/"> Default avatars </a> </li><li> <a href="/__pyric/ui/docs/build/inspect-activity/"> Activity on the page </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-firestore/"> Cloud Firestore </a> </li><li> <a href="/__pyric/ui/docs/build/realtime-database/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-storage/"> Cloud Storage </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-messaging/"> Cloud Messaging </a> </li><li> <a href="/__pyric/ui/docs/build/ai-logic/"> AI Logic </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Secure &amp; debug</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/secure/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/secure/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/secure/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/secure/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/secure/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-standard-library/"> RTDB rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/secure/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Examples </h2> <ul> <li> <a href="/__pyric/ui/docs/examples/chess/"> Chess showcase </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Observe &amp; shape</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/observe/see-whats-happening/"> Traffic &amp; rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/observe/resolve-runtime-status/"> Runtime status </a> </li><li> <a href="/__pyric/ui/docs/observe/switch-and-impersonate-identities/"> Impersonate &amp; tenants </a> </li><li> <a href="/__pyric/ui/docs/observe/shape-your-data/"> Seed, snapshot, replay </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Ship &amp; test</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/ship/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Work with an agent</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/agent/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/agent/work-with-an-agent/"> Use the MCP tools </a> </li><li> <a href="/__pyric/ui/docs/agent/watch-and-review/"> Watch in Pyric Studio </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Trust</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/trust/versioning-and-compatibility/"> Versioning and the fb tag </a> </li><li> <a href="/__pyric/ui/docs/trust/rules-standard-library/"> Rules standard library reference </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/trust/how-we-know-it-matches-firebase/"> How we know it matches Firebase </a> </li><li> <a href="/__pyric/ui/docs/app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/functions-rtdb-compat/"> Functions · RTDB </a> </li><li> <a href="/__pyric/ui/docs/rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/firestore-flutter-compat/"> Firestore · Flutter </a> </li><li> <a href="/__pyric/ui/docs/firestore-kotlin-compat/"> Firestore · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/firestore-swift-compat/"> Firestore · Swift </a> </li><li> <a href="/__pyric/ui/docs/auth-flutter-compat/"> Auth · Flutter </a> </li><li> <a href="/__pyric/ui/docs/auth-kotlin-compat/"> Auth · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/auth-swift-compat/"> FirebaseAuth Swift </a> </li><li> <a href="/__pyric/ui/docs/rtdb-flutter-compat/"> Realtime Database · Flutter </a> </li><li> <a href="/__pyric/ui/docs/rtdb-kotlin-compat/"> Realtime Database · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/rtdb-swift-compat/"> Realtime Database · Swift </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group"> <summary>Reference</summary> <div class="docs-nav-group-body docs-nav-group-body--reference"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">pyric</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-app-reference-api/"> pyric/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-api/"> pyric/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-lite-reference-api/"> pyric/firestore/lite </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-reference-api/"> pyric/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-reference-api/"> pyric/ai </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-scripting-reference-api/"> pyric/ai/scripting </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-reference-api/"> pyric/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-api/"> pyric/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-sw-reference-api/"> pyric/storage/sw </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-reference-api/"> pyric/messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-sw-reference-api/"> pyric/messaging/sw </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-api/"> pyric/rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-api/"> pyric/sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-branches-store-reference-api/"> pyric/sandbox/branches/store </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-checkpoints-reference-api/"> pyric/sandbox/checkpoints </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-checkpoints-directory-reference-api/"> pyric/sandbox/checkpoints/directory </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-firestore-reference-api/"> pyric/sandbox/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-database-reference-api/"> pyric/sandbox/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-check-reference-api/"> pyric/app-check </a> </li><li> <a href="/__pyric/ui/docs/pyric-functions-reference-api/"> pyric/functions </a> </li><li> <a href="/__pyric/ui/docs/pyric-analytics-reference-api/"> pyric/analytics </a> </li><li> <a href="/__pyric/ui/docs/pyric-performance-reference-api/"> pyric/performance </a> </li><li> <a href="/__pyric/ui/docs/pyric-remote-config-reference-api/"> pyric/remote-config </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">pyric-admin</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-reference-api/"> pyric-admin </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app-reference-api/"> pyric-admin/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-api/"> pyric-admin/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth-reference-api/"> pyric-admin/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database-reference-api/"> pyric-admin/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage-reference-api/"> pyric-admin/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-messaging-reference-api/"> pyric-admin/messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app-check-reference-api/"> pyric-admin/app-check </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-data-connect-reference-api/"> pyric-admin/data-connect </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-eventarc-reference-api/"> pyric-admin/eventarc </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-extensions-reference-api/"> pyric-admin/extensions </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-functions-reference-api/"> pyric-admin/functions </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-installations-reference-api/"> pyric-admin/installations </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-instance-id-reference-api/"> pyric-admin/instance-id </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-machine-learning-reference-api/"> pyric-admin/machine-learning </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-phone-number-verification-reference-api/"> pyric-admin/phone-number-verification </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-project-management-reference-api/"> pyric-admin/project-management </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-remote-config-reference-api/"> pyric-admin/remote-config </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-security-rules-reference-api/"> pyric-admin/security-rules </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">create-pyric</h2> <ul> <li> <a href="/__pyric/ui/docs/create-pyric-reference-api/"> create-pyric </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/cli</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-credentials-node-reference-api/"> @pyric/cli/credentials/node </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-verify-reference-api/"> @pyric/cli/verify </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-repro-reference-api/"> @pyric/cli/repro </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-reference-api/"> @pyric/cli/conformance </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-browser-reference-api/"> @pyric/cli/conformance/browser </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-docs-reference-api/"> @pyric/cli/conformance/docs </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-assurance-reference-api/"> @pyric/cli/assurance </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-assurance-browser-reference-api/"> @pyric/cli/assurance/browser </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bridge-reference-api/"> @pyric/cli/bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bridge-client-reference-api/"> @pyric/cli/bridge/client </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-discover-reference-api/"> @pyric/cli/discover </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-vite-reference-api/"> @pyric/cli/vite </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-vite-ssr-loader-reference-api/"> @pyric/cli/vite/ssr-loader </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-next-reference-api/"> @pyric/cli/next </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bundler-reference-api/"> @pyric/cli/bundler </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-serve-worker-reference-api/"> @pyric/cli/serve/worker </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-remote-reference-api/"> @pyric/cli/remote </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-reference-api/"> @pyric/cli/register </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-app-bridge-reference-api/"> @pyric/cli/register/app-bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-app-reference-api/"> @pyric/cli/register/client/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-app-bridge-reference-api/"> @pyric/cli/register/client/app-bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-auth-reference-api/"> @pyric/cli/register/client/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-database-reference-api/"> @pyric/cli/register/client/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-firestore-reference-api/"> @pyric/cli/register/client/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-storage-reference-api/"> @pyric/cli/register/client/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-flow-reference-api/"> @pyric/cli/flow </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/ui</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-ui-auth-reference-api/"> @pyric/ui/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-auth-hooks-reference-api/"> @pyric/ui/auth/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-primitives-reference-api/"> @pyric/ui/primitives </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-listener-owner-reference-api/"> @pyric/ui/listener-owner </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-firestore-reference-api/"> @pyric/ui/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-firestore-hooks-reference-api/"> @pyric/ui/firestore/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rtdb-reference-api/"> @pyric/ui/rtdb </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-storage-reference-api/"> @pyric/ui/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-storage-hooks-reference-api/"> @pyric/ui/storage/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-traffic-reference-api/"> @pyric/ui/traffic </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-traffic-hooks-reference-api/"> @pyric/ui/traffic/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-events-reference-api/"> @pyric/ui/events </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-events-hooks-reference-api/"> @pyric/ui/events/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-agents-reference-api/"> @pyric/ui/agents </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rules-reference-api/"> @pyric/ui/rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rules-hooks-reference-api/"> @pyric/ui/rules/hooks </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/cli</h2> <ul> <li> <a href="/__pyric/ui/docs/reference/cli/"> CLI </a> </li> </ul> </div> </div> </details> </nav> </details> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <details class="docs-nav-group" id="nav-group-overview"> <summary>Overview</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/overview/"> Overview </a> </li><li> <a href="/__pyric/ui/docs/tutorial/"> Tutorial </a> </li><li> <a href="/__pyric/ui/docs/examples/"> Examples </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-get-started"> <summary>Get started</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/get-started/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/get-started/vite/"> Vite </a> </li><li> <a href="/__pyric/ui/docs/get-started/node-host/"> Node host </a> </li><li> <a href="/__pyric/ui/docs/get-started/nextjs/"> Next.js </a> </li><li> <a href="/__pyric/ui/docs/get-started/backend-bundlers/"> Backend bundlers </a> </li><li> <a href="/__pyric/ui/docs/get-started/flutter/"> Flutter </a> </li><li> <a href="/__pyric/ui/docs/get-started/how-the-swap-works/"> How the swap works </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-build"> <summary>Build</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/build/authentication/"> Authentication </a> </li><li> <a href="/__pyric/ui/docs/build/default-avatars/"> Default avatars </a> </li><li> <a href="/__pyric/ui/docs/build/inspect-activity/"> Activity on the page </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-firestore/"> Cloud Firestore </a> </li><li> <a href="/__pyric/ui/docs/build/realtime-database/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-storage/"> Cloud Storage </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-messaging/"> Cloud Messaging </a> </li><li> <a href="/__pyric/ui/docs/build/ai-logic/"> AI Logic </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-secure-debug"> <summary>Secure &amp; debug</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/secure/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/secure/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/secure/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/secure/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/secure/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-standard-library/"> RTDB rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/secure/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-secure-debug-examples"> Examples </h2> <ul> <li> <a href="/__pyric/ui/docs/examples/chess/"> Chess showcase </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-observe-shape"> <summary>Observe &amp; shape</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/observe/see-whats-happening/"> Traffic &amp; rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/observe/resolve-runtime-status/"> Runtime status </a> </li><li> <a href="/__pyric/ui/docs/observe/switch-and-impersonate-identities/"> Impersonate &amp; tenants </a> </li><li> <a href="/__pyric/ui/docs/observe/shape-your-data/"> Seed, snapshot, replay </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-ship-test"> <summary>Ship &amp; test</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/ship/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-work-with-an-agent"> <summary>Work with an agent</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/agent/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/agent/work-with-an-agent/"> Use the MCP tools </a> </li><li> <a href="/__pyric/ui/docs/agent/watch-and-review/"> Watch in Pyric Studio </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-trust"> <summary>Trust</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/trust/versioning-and-compatibility/"> Versioning and the fb tag </a> </li><li> <a href="/__pyric/ui/docs/trust/rules-standard-library/"> Rules standard library reference </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-conformance"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/trust/how-we-know-it-matches-firebase/"> How we know it matches Firebase </a> </li><li> <a href="/__pyric/ui/docs/app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/functions-rtdb-compat/"> Functions · RTDB </a> </li><li> <a href="/__pyric/ui/docs/rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/firestore-flutter-compat/"> Firestore · Flutter </a> </li><li> <a href="/__pyric/ui/docs/firestore-kotlin-compat/"> Firestore · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/firestore-swift-compat/"> Firestore · Swift </a> </li><li> <a href="/__pyric/ui/docs/auth-flutter-compat/"> Auth · Flutter </a> </li><li> <a href="/__pyric/ui/docs/auth-kotlin-compat/"> Auth · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/auth-swift-compat/"> FirebaseAuth Swift </a> </li><li> <a href="/__pyric/ui/docs/rtdb-flutter-compat/"> Realtime Database · Flutter </a> </li><li> <a href="/__pyric/ui/docs/rtdb-kotlin-compat/"> Realtime Database · Kotlin </a> </li><li> <a href="/__pyric/ui/docs/rtdb-swift-compat/"> Realtime Database · Swift </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group" id="nav-group-reference"> <summary>Reference</summary> <div class="docs-nav-group-body docs-nav-group-body--reference"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">pyric</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-app-reference-api/"> pyric/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-api/"> pyric/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-lite-reference-api/"> pyric/firestore/lite </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-reference-api/"> pyric/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-reference-api/"> pyric/ai </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-scripting-reference-api/"> pyric/ai/scripting </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-reference-api/"> pyric/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-api/"> pyric/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-sw-reference-api/"> pyric/storage/sw </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-reference-api/"> pyric/messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-sw-reference-api/"> pyric/messaging/sw </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-api/"> pyric/rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-api/"> pyric/sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-branches-store-reference-api/"> pyric/sandbox/branches/store </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-checkpoints-reference-api/"> pyric/sandbox/checkpoints </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-checkpoints-directory-reference-api/"> pyric/sandbox/checkpoints/directory </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-firestore-reference-api/"> pyric/sandbox/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-database-reference-api/"> pyric/sandbox/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-check-reference-api/"> pyric/app-check </a> </li><li> <a href="/__pyric/ui/docs/pyric-functions-reference-api/"> pyric/functions </a> </li><li> <a href="/__pyric/ui/docs/pyric-analytics-reference-api/"> pyric/analytics </a> </li><li> <a href="/__pyric/ui/docs/pyric-performance-reference-api/"> pyric/performance </a> </li><li> <a href="/__pyric/ui/docs/pyric-remote-config-reference-api/"> pyric/remote-config </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">pyric-admin</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-reference-api/"> pyric-admin </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app-reference-api/"> pyric-admin/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-api/"> pyric-admin/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth-reference-api/"> pyric-admin/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database-reference-api/"> pyric-admin/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage-reference-api/"> pyric-admin/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-messaging-reference-api/"> pyric-admin/messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app-check-reference-api/"> pyric-admin/app-check </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-data-connect-reference-api/"> pyric-admin/data-connect </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-eventarc-reference-api/"> pyric-admin/eventarc </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-extensions-reference-api/"> pyric-admin/extensions </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-functions-reference-api/"> pyric-admin/functions </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-installations-reference-api/"> pyric-admin/installations </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-instance-id-reference-api/"> pyric-admin/instance-id </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-machine-learning-reference-api/"> pyric-admin/machine-learning </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-phone-number-verification-reference-api/"> pyric-admin/phone-number-verification </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-project-management-reference-api/"> pyric-admin/project-management </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-remote-config-reference-api/"> pyric-admin/remote-config </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-security-rules-reference-api/"> pyric-admin/security-rules </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">create-pyric</h2> <ul> <li> <a href="/__pyric/ui/docs/create-pyric-reference-api/"> create-pyric </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/cli</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-credentials-node-reference-api/"> @pyric/cli/credentials/node </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-verify-reference-api/"> @pyric/cli/verify </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-repro-reference-api/"> @pyric/cli/repro </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-reference-api/"> @pyric/cli/conformance </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-browser-reference-api/"> @pyric/cli/conformance/browser </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-conformance-docs-reference-api/"> @pyric/cli/conformance/docs </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-assurance-reference-api/"> @pyric/cli/assurance </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-assurance-browser-reference-api/"> @pyric/cli/assurance/browser </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bridge-reference-api/"> @pyric/cli/bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bridge-client-reference-api/"> @pyric/cli/bridge/client </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-discover-reference-api/"> @pyric/cli/discover </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-vite-reference-api/"> @pyric/cli/vite </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-vite-ssr-loader-reference-api/"> @pyric/cli/vite/ssr-loader </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-next-reference-api/"> @pyric/cli/next </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-bundler-reference-api/"> @pyric/cli/bundler </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-serve-worker-reference-api/"> @pyric/cli/serve/worker </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-remote-reference-api/"> @pyric/cli/remote </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-reference-api/"> @pyric/cli/register </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-app-bridge-reference-api/"> @pyric/cli/register/app-bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-app-reference-api/"> @pyric/cli/register/client/app </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-app-bridge-reference-api/"> @pyric/cli/register/client/app-bridge </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-auth-reference-api/"> @pyric/cli/register/client/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-database-reference-api/"> @pyric/cli/register/client/database </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-firestore-reference-api/"> @pyric/cli/register/client/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-register-client-storage-reference-api/"> @pyric/cli/register/client/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-flow-reference-api/"> @pyric/cli/flow </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/ui</h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-ui-auth-reference-api/"> @pyric/ui/auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-auth-hooks-reference-api/"> @pyric/ui/auth/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-primitives-reference-api/"> @pyric/ui/primitives </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-listener-owner-reference-api/"> @pyric/ui/listener-owner </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-firestore-reference-api/"> @pyric/ui/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-firestore-hooks-reference-api/"> @pyric/ui/firestore/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rtdb-reference-api/"> @pyric/ui/rtdb </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-storage-reference-api/"> @pyric/ui/storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-storage-hooks-reference-api/"> @pyric/ui/storage/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-traffic-reference-api/"> @pyric/ui/traffic </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-traffic-hooks-reference-api/"> @pyric/ui/traffic/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-events-reference-api/"> @pyric/ui/events </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-events-hooks-reference-api/"> @pyric/ui/events/hooks </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-agents-reference-api/"> @pyric/ui/agents </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rules-reference-api/"> @pyric/ui/rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-ui-rules-hooks-reference-api/"> @pyric/ui/rules/hooks </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading">@pyric/cli</h2> <ul> <li> <a href="/__pyric/ui/docs/reference/cli/"> CLI </a> </li> </ul> </div> </div> </details> </nav> <main class="doc-main" data-astro-cid-mw7aashj> <article class="prose" data-astro-cid-mw7aashj> <h1 id="rhythm-audit">Rhythm audit</h1>
6
6
  <p>This page exists to audit vertical rhythm in one screenshot. Every
7
7
  adjacency styled by <code>rhythm.css</code> appears below, labeled. It is excluded
8
8
  from the nav, llms.txt, and the search index.</p>