@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.
- package/dist/assurance/.generated/conformance-verdicts.d.ts +16 -0
- package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
- package/dist/assurance/.generated/conformance-verdicts.js +16 -0
- package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
- package/dist/bridge/surface/arguments/assurance.d.ts +6 -6
- package/dist/bridge/surface/arguments/messaging.d.ts +2 -2
- package/dist/bridge/surface/methods/assurance/map.d.ts +6 -6
- package/dist/bridge/surface/methods/assurance/replaySession.d.ts.map +1 -1
- package/dist/bridge/surface/methods/assurance/replaySession.js +18 -6
- package/dist/bridge/surface/methods/assurance/replaySession.js.map +1 -1
- package/dist/bridge/surface/methods/messaging/send.d.ts +4 -4
- package/dist/bridge/surface/render/discriminator-schemas.d.ts +4 -4
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +15 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/run.d.ts +42 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +115 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
- package/dist/conformance/.generated/can-i-use.js +1 -1
- package/dist/conformance/.generated/can-i-use.js.map +1 -1
- package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
- package/dist/conformance/.generated/conformance-docs.js +1 -1
- package/dist/conformance/.generated/conformance-docs.js.map +1 -1
- package/dist/remote/local-storage-url.d.ts +2 -15
- package/dist/remote/local-storage-url.d.ts.map +1 -1
- package/dist/remote/local-storage-url.js +1 -60
- package/dist/remote/local-storage-url.js.map +1 -1
- package/dist/serve/assets/avatar-route.d.ts.map +1 -1
- package/dist/serve/assets/avatar-route.js +6 -6
- package/dist/serve/assets/avatar-route.js.map +1 -1
- package/dist/serve/assets/resolver.d.ts +3 -0
- package/dist/serve/assets/resolver.d.ts.map +1 -1
- package/dist/serve/assets/resolver.js +1 -1
- package/dist/serve/assets/resolver.js.map +1 -1
- package/dist/serve/entries/app-client.d.ts.map +1 -1
- package/dist/serve/entries/app-client.js +6 -0
- package/dist/serve/entries/app-client.js.map +1 -1
- package/dist/serve/site-ui/_astro/{RulesCodeEditor.kBYcclwV.js → RulesCodeEditor.Cp_-FK3b.js} +1 -1
- package/dist/serve/site-ui/_astro/app.C--T2qDK.js +151 -0
- package/dist/serve/site-ui/_astro/app.DqyhRyrU.js +1 -0
- package/dist/serve/site-ui/_astro/{chess-showcase.CZe_3fJZ.js → chess-showcase.CVhCNUi_.js} +1 -1
- package/dist/serve/site-ui/_astro/{example-runtime.CXSZXHZF.js → example-runtime.zC1l-Yka.js} +1 -1
- package/dist/serve/site-ui/_astro/{sandbox-controls.Bp5PoonS.js → sandbox-controls.Bv6lfpIe.js} +39 -39
- package/dist/serve/site-ui/_astro/{seed.BpXSRzLo.js → seed.B4vza_Bv.js} +1 -1
- package/dist/serve/site-ui/_astro/{writes.DHSW22XD.js → writes.Bg0YEEA7.js} +1 -1
- package/dist/serve/site-ui/auth/index.html +1 -1
- package/dist/serve/site-ui/docs/_rhythm/index.html +1 -1
- package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +1 -1
- package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +1 -1
- package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +1 -1
- package/dist/serve/site-ui/docs/ai-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/api-reference/index.html +2 -1
- package/dist/serve/site-ui/docs/api-reference.md +1 -0
- package/dist/serve/site-ui/docs/app-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/auth-compat/index.html +2 -2
- package/dist/serve/site-ui/docs/auth-compat.md +1 -1
- package/dist/serve/site-ui/docs/auth-flutter-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/auth-kotlin-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/auth-swift-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/build/ai-logic/index.html +1 -1
- package/dist/serve/site-ui/docs/build/authentication/index.html +1 -1
- package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +1 -1
- package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +1 -1
- package/dist/serve/site-ui/docs/build/cloud-storage/index.html +13 -2
- package/dist/serve/site-ui/docs/build/cloud-storage.md +23 -0
- package/dist/serve/site-ui/docs/build/default-avatars/index.html +1 -1
- package/dist/serve/site-ui/docs/build/inspect-activity/index.html +1 -1
- package/dist/serve/site-ui/docs/build/realtime-database/index.html +1 -1
- package/dist/serve/site-ui/docs/conformance-scores/index.html +1 -1
- package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/database-compat/index.html +18 -18
- package/dist/serve/site-ui/docs/database-compat.md +17 -17
- package/dist/serve/site-ui/docs/examples/chess/index.html +1 -1
- package/dist/serve/site-ui/docs/examples/index.html +1 -1
- package/dist/serve/site-ui/docs/firestore-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/firestore-flutter-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/firestore-kotlin-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/firestore-swift-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/get-started/backend-bundlers/index.html +1 -1
- package/dist/serve/site-ui/docs/get-started/flutter/index.html +1 -1
- package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +1 -1
- package/dist/serve/site-ui/docs/get-started/nextjs/index.html +1 -1
- package/dist/serve/site-ui/docs/get-started/node-host/index.html +1 -1
- package/dist/serve/site-ui/docs/get-started/start-building/index.html +1 -1
- package/dist/serve/site-ui/docs/get-started/vite/index.html +4 -2
- package/dist/serve/site-ui/docs/get-started/vite.md +4 -0
- package/dist/serve/site-ui/docs/index.json +60 -10
- package/dist/serve/site-ui/docs/messaging-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +1 -1
- package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +1 -1
- package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +1 -1
- package/dist/serve/site-ui/docs/observe/switch-and-impersonate-identities/index.html +1 -1
- package/dist/serve/site-ui/docs/overview/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-app-check-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-data-connect-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-eventarc-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-extensions-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-functions-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-installations-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-instance-id-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-machine-learning-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-phone-number-verification-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-project-management-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-remote-config-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-security-rules-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-analytics-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-app-check-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +2 -2
- package/dist/serve/site-ui/docs/pyric-auth-reference-api.md +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-flow-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-register-client-app-bridge-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-register-client-app-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-register-client-auth-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-register-client-database-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-register-client-firestore-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-register-client-storage-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-repro-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +17 -3
- package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api.md +7 -5
- package/dist/serve/site-ui/docs/pyric-cli-vite-ssr-loader-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-functions-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-performance-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-remote-config-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +120 -120
- package/dist/serve/site-ui/docs/pyric-rules-reference-api.md +53 -53
- package/dist/serve/site-ui/docs/pyric-sandbox-branches-store-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-sandbox-checkpoints-directory-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-sandbox-checkpoints-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-storage-sw-reference-api/index.html +102 -0
- package/dist/serve/site-ui/docs/pyric-storage-sw-reference-api.md +76 -0
- package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-listener-owner-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/reference/cli/index.html +12 -2
- package/dist/serve/site-ui/docs/reference/cli.md +24 -0
- package/dist/serve/site-ui/docs/rtdb-flutter-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/rtdb-kotlin-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/rtdb-swift-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/rules-compat/index.html +68 -4
- package/dist/serve/site-ui/docs/rules-compat.md +67 -3
- package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/rtdb-rules-standard-library/index.html +18 -5
- package/dist/serve/site-ui/docs/secure/rtdb-rules-standard-library.md +19 -4
- package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +5 -5
- package/dist/serve/site-ui/docs/secure/simulate-and-lint.md +8 -8
- package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
- package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +1 -1
- package/dist/serve/site-ui/docs/ship/test-in-node/index.html +1 -1
- package/dist/serve/site-ui/docs/storage-compat/index.html +1 -1
- package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
- package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +1 -1
- package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
- package/dist/serve/site-ui/docs/tutorial/index.html +1 -1
- package/dist/serve/site-ui/examples/chess/index.html +1 -1
- package/dist/serve/site-ui/firestore/index.html +1 -1
- package/dist/serve/site-ui/llms.txt +1 -0
- package/dist/serve/site-ui/rtdb/index.html +1 -1
- package/dist/serve/site-ui/settings/index.html +1 -1
- package/dist/serve/site-ui/storage/index.html +1 -1
- package/dist/serve/site-ui/studio/index.html +1 -1
- package/dist/serve/site-ui/traffic/index.html +1 -1
- package/dist/serve/vite-plugin.d.ts +6 -0
- package/dist/serve/vite-plugin.d.ts.map +1 -1
- package/dist/serve/vite-plugin.js +11 -1
- package/dist/serve/vite-plugin.js.map +1 -1
- package/dist/serve/vite-service-worker.d.ts +12 -0
- package/dist/serve/vite-service-worker.d.ts.map +1 -0
- package/dist/serve/vite-service-worker.js +33 -0
- package/dist/serve/vite-service-worker.js.map +1 -0
- package/dist/serve/worker/client/auth.d.ts.map +1 -1
- package/dist/serve/worker/client/auth.js +4 -3
- package/dist/serve/worker/client/auth.js.map +1 -1
- package/dist/serve/worker/client/rtdb-info.d.ts +0 -2
- package/dist/serve/worker/client/rtdb-info.d.ts.map +1 -1
- package/dist/serve/worker/client/rtdb-info.js +4 -17
- package/dist/serve/worker/client/rtdb-info.js.map +1 -1
- package/dist/serve/worker/client/rtdb-reads.d.ts.map +1 -1
- package/dist/serve/worker/client/rtdb-reads.js +3 -5
- package/dist/serve/worker/client/rtdb-reads.js.map +1 -1
- package/dist/serve/worker/host/auth-action-codes.js +2 -2
- package/dist/serve/worker/host/auth-action-codes.js.map +1 -1
- package/dist/serve/worker/host/auth-custom-token.d.ts.map +1 -1
- package/dist/serve/worker/host/auth-custom-token.js +4 -2
- package/dist/serve/worker/host/auth-custom-token.js.map +1 -1
- package/dist/serve/worker/host/dispatch.d.ts.map +1 -1
- package/dist/serve/worker/host/dispatch.js +3 -1
- package/dist/serve/worker/host/dispatch.js.map +1 -1
- package/dist/serve/worker/host-auth.d.ts +6 -0
- package/dist/serve/worker/host-auth.d.ts.map +1 -1
- package/dist/serve/worker/host-auth.js +16 -5
- package/dist/serve/worker/host-auth.js.map +1 -1
- package/dist/serve/worker/inbound-validation.d.ts.map +1 -1
- package/dist/serve/worker/inbound-validation.js +1 -0
- package/dist/serve/worker/inbound-validation.js.map +1 -1
- package/dist/serve/worker/protocol/storage.d.ts +1 -8
- package/dist/serve/worker/protocol/storage.d.ts.map +1 -1
- package/dist/serve/worker/protocol/storage.js +2 -14
- package/dist/serve/worker/protocol/storage.js.map +1 -1
- package/dist/serve/worker/protocol.d.ts +2 -0
- package/dist/serve/worker/protocol.d.ts.map +1 -1
- package/dist/serve/worker/protocol.js.map +1 -1
- package/package.json +12 -8
- package/src/assurance/.generated/conformance-verdicts.ts +16 -0
- package/src/bridge/surface/methods/assurance/replaySession.ts +19 -6
- package/src/cli/index.ts +15 -1
- package/src/cli/run.ts +139 -0
- package/src/conformance/.generated/can-i-use.ts +1 -1
- package/src/conformance/.generated/conformance-docs.ts +1 -1
- package/src/remote/local-storage-url.ts +1 -58
- package/src/serve/assets/avatar-route.ts +6 -7
- package/src/serve/assets/resolver.ts +4 -1
- package/src/serve/entries/app-client.ts +7 -0
- package/src/serve/vite-plugin.ts +15 -1
- package/src/serve/vite-service-worker.ts +44 -0
- package/src/serve/worker/client/auth.ts +4 -3
- package/src/serve/worker/client/rtdb-info.ts +4 -17
- package/src/serve/worker/client/rtdb-reads.ts +3 -4
- package/src/serve/worker/host/auth-action-codes.ts +2 -2
- package/src/serve/worker/host/auth-custom-token.ts +4 -2
- package/src/serve/worker/host/dispatch.ts +2 -0
- package/src/serve/worker/host-auth.ts +18 -5
- package/src/serve/worker/inbound-validation.ts +1 -0
- package/src/serve/worker/protocol/storage.ts +2 -14
- package/src/serve/worker/protocol.ts +2 -0
- package/dist/serve/site-ui/_astro/app.CiMHEvEW.js +0 -147
- package/dist/serve/site-ui/_astro/app.DpzsBfos.js +0 -1
|
@@ -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" open> <summary>Secure & 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/" aria-current="page"> 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 & 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 & 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 & 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 & 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" open> <summary>Secure & 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/" aria-current="page"> 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 & 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 & 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 & 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 & 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> <nav class="docs-breadcrumbs" aria-label="Breadcrumb"> <ol> <li> <a href="/__pyric/ui/docs/secure/secure-it-with-rules/">Secure & debug</a> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span aria-current="page">Simulate and lint before you deploy</span> </li> </ol> </nav> <article class="prose" data-astro-cid-mw7aashj> <h1 id="simulate-and-lint-security-rules-before-deployment">Simulate and lint Security Rules before deployment</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" open> <summary>Secure & 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/" aria-current="page"> 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 & 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 & 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 & 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 & 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" open> <summary>Secure & 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/" aria-current="page"> 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 & 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 & 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 & 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 & 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> <nav class="docs-breadcrumbs" aria-label="Breadcrumb"> <ol> <li> <a href="/__pyric/ui/docs/secure/secure-it-with-rules/">Secure & debug</a> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span aria-current="page">Simulate and lint before you deploy</span> </li> </ol> </nav> <article class="prose" data-astro-cid-mw7aashj> <h1 id="simulate-and-lint-security-rules-before-deployment">Simulate and lint Security Rules before deployment</h1>
|
|
6
6
|
<p>A broken ruleset fails late: a <code>400</code> at deploy time, or a <code>403</code> at runtime. Pyric moves both failures to your machine, before the deploy.</p>
|
|
7
7
|
<p>Simulation tells you what a rule decides. Linting tells you what the production compiler and runtime will reject, and why, in the language of the mistake you made.</p>
|
|
8
8
|
<h2 id="simulate-a-hypothetical-request">Simulate a hypothetical request</h2>
|
|
@@ -132,7 +132,7 @@ The linter checks two different kinds of failure.</p>
|
|
|
132
132
|
<pre class="astro-code one-dark-pro" style="background-color:#282c34;color:#abb2bf; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>matchedPath: /records/$recordId/title</span></span>
|
|
133
133
|
<span class="line"><span>matchedRule: newData.isString() && newData.val().length <= 80</span></span>
|
|
134
134
|
<span class="line"><span>reason: Validation rule evaluated to false</span></span></code></pre>
|
|
135
|
-
<p><code>matchedPath</code> is the rule’s location in the ruleset, so it shows the <code>$recordId</code> wildcard rather than the concrete path. <code>UNSUPPORTED</code> means the case reached an expression the simulator cannot evaluate
|
|
135
|
+
<p><code>matchedPath</code> is the rule’s location in the ruleset, so it shows the <code>$recordId</code> wildcard rather than the concrete path. <code>UNSUPPORTED</code> means the simulator did not evaluate the case, and <code>reason</code> says why. Either the case reached an expression the simulator cannot evaluate, and it abstains rather than guesses, or no client could send the request. The second covers a path with <code>.</code>, <code>#</code>, <code>$</code>, <code>[</code> or <code>]</code> in it, update paths that overlap, a write under <code>/.info</code>, a query the SDK refuses to build, <code>updates</code> that leave out the case’s <code>path</code> or give it a value other than <code>newData</code>, and a ruleset that does not compile. For a request the SDK refuses, <code>reason</code> is the SDK’s own error text.</p>
|
|
136
136
|
<p>The result also carries a <code>trace</code> with every rule the simulator ran, in order:</p>
|
|
137
137
|
<pre class="astro-code one-dark-pro" style="background-color:#282c34;color:#abb2bf; overflow-x: auto;" tabindex="0" data-language="ts"><code><span class="line"><span style="color:#C678DD">for</span><span style="color:#ABB2BF"> (</span><span style="color:#C678DD">const</span><span style="color:#E5C07B"> step</span><span style="color:#C678DD"> of</span><span style="color:#E06C75"> cases</span><span style="color:#ABB2BF">[</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">].</span><span style="color:#E06C75">trace</span><span style="color:#ABB2BF">) {</span></span>
|
|
138
138
|
<span class="line"><span style="color:#E5C07B"> console</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">log</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">`</span><span style="color:#C678DD">${</span><span style="color:#E5C07B">step</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">path</span><span style="color:#C678DD">}</span><span style="color:#98C379"> .</span><span style="color:#C678DD">${</span><span style="color:#E5C07B">step</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">kind</span><span style="color:#C678DD">}</span><span style="color:#98C379"> -> </span><span style="color:#C678DD">${</span><span style="color:#E5C07B">step</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">verdict</span><span style="color:#C678DD">}</span><span style="color:#98C379">: </span><span style="color:#C678DD">${</span><span style="color:#E5C07B">step</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">conditionText</span><span style="color:#C678DD">}</span><span style="color:#98C379">`</span><span style="color:#ABB2BF">);</span></span>
|
|
@@ -253,8 +253,8 @@ The linter checks two different kinds of failure.</p>
|
|
|
253
253
|
|
|
254
254
|
|
|
255
255
|
|
|
256
|
-
<table><thead><tr><th>Code</th><th>What it reports</th></tr></thead><tbody><tr><td><code>PARSE_ERROR</code></td><td>The expression does not parse.</td></tr><tr><td><code>NOT_BOOLEAN</code></td><td>The rule does not evaluate to a boolean, such as a <code>.read</code> of <code>auth.uid</code>.</td></tr><tr><td><code>INVALID_OPERAND</code></td><td>An operator gets an operand type it does not take, such as <code>data.val() > true</code>, or <code>!</code> on a string.</td></tr><tr><td><code>INVALID_ARGUMENT</code></td><td>A method gets the wrong number or type of arguments, such as <code>child(1)</code>, or <code>matches()</code> with anything other than a regular expression literal.</td></tr><tr><td><code>INVALID_REGEX</code></td><td>A regular expression literal
|
|
257
|
-
<p><code>INDEX_ON_SHAPE</code> and <code>INVALID_KEY</code> are warnings, not errors, for related forms: any other <code>.indexOn</code> that is not a string or an array of strings,
|
|
256
|
+
<table><thead><tr><th>Code</th><th>What it reports</th></tr></thead><tbody><tr><td><code>PARSE_ERROR</code></td><td>The expression does not parse.</td></tr><tr><td><code>NOT_BOOLEAN</code></td><td>The rule does not evaluate to a boolean, such as a <code>.read</code> of <code>auth.uid</code>.</td></tr><tr><td><code>INVALID_OPERAND</code></td><td>An operator gets an operand type it does not take, such as <code>data.val() > true</code>, or <code>!</code> on a string.</td></tr><tr><td><code>INVALID_ARGUMENT</code></td><td>A method gets the wrong number or type of arguments, such as <code>child(1)</code>, or <code>matches()</code> with anything other than a regular expression literal.</td></tr><tr><td><code>INVALID_REGEX</code></td><td>A regular expression literal production refuses: a flag other than <code>i</code>, a <code>^</code> that is not the first character or a <code>$</code> that is not the last, or an unclosed group, repeat count or character set. A repeat count above 2,147,483,647 and a pattern too large to determinize, such as <code>a{100000}</code>, fail with production’s texts. A pattern past pyric’s own limits (more than 200,000 matcher states, or nesting deeper than 1,000 levels) reports here too, with a message that names the limit.</td></tr><tr><td><code>NO_SUCH_MEMBER</code></td><td>The value has no such method or property, such as <code>data.nope()</code>.</td></tr><tr><td><code>NOT_AN_OBJECT</code></td><td>A property access on a number, boolean, null, or regular expression.</td></tr><tr><td><code>NOT_A_FUNCTION</code></td><td>A call on something that is not a method, such as <code>auth.uid()</code>.</td></tr><tr><td><code>INVALID_PROPERTY_ACCESS</code></td><td>An index with a computed key, <code>x[expr]</code>, on anything other than <code>auth</code>.</td></tr><tr><td><code>UNEXPECTED_ARRAY</code></td><td>An array literal anywhere other than the argument of <code>hasChildren()</code>.</td></tr><tr><td><code>UNKNOWN_IDENTIFIER</code></td><td>The variable is not available, such as a <code>$name</code> that no enclosing key declares.</td></tr><tr><td><code>NEWDATA_IN_READ</code></td><td>A <code>.read</code> rule uses <code>newData</code>, which exists only for writes.</td></tr><tr><td><code>MULTIPLE_WILDCARDS</code></td><td>One location has two <code>$</code> children.</td></tr><tr><td><code>RULE_NOT_EXPRESSION</code></td><td>A <code>.read</code>, <code>.write</code>, or <code>.validate</code> value is a number or a plain object rather than a boolean or a string.</td></tr><tr><td><code>INDEX_ON_SHAPE</code></td><td><code>.indexOn</code> is a number.</td></tr><tr><td><code>INVALID_KEY</code></td><td>A key contains <code>#</code>, an unknown key that starts with <code>.</code> holds an object, or an <code>.indexOn</code> entry other than <code>.value</code> contains <code>.</code>.</td></tr><tr><td><code>EXPECTED_OBJECT</code></td><td>An unknown key that starts with <code>.</code>, or a child key, holds a string.</td></tr></tbody></table></div>
|
|
257
|
+
<p><code>INDEX_ON_SHAPE</code> and <code>INVALID_KEY</code> are warnings, not errors, for related forms: any other <code>.indexOn</code> that is not a string or an array of strings, a key that contains <code>.</code>, <code>/</code>, <code>[</code>, <code>]</code>, or an inner <code>$</code> but no <code>#</code>, and an <code>.indexOn</code> entry that contains <code>#</code>, <code>$</code>, <code>[</code> or <code>]</code>. Their text comes from the deploy’s message for the related form, and no deploy of these forms has been recorded.</p>
|
|
258
258
|
<p>The second group is the rest of the per-rule checks:</p>
|
|
259
259
|
<div class="table-scroll">
|
|
260
260
|
|
|
@@ -330,7 +330,7 @@ The linter checks two different kinds of failure.</p>
|
|
|
330
330
|
|
|
331
331
|
|
|
332
332
|
|
|
333
|
-
<table><thead><tr><th>Code</th><th>What it reports</th></tr></thead><tbody><tr><td><code>RTDB-SEC-1</code></td><td>A <code>.write</code> of <code>true</code>,
|
|
333
|
+
<table><thead><tr><th>Code</th><th>What it reports</th></tr></thead><tbody><tr><td><code>RTDB-SEC-1</code></td><td>A <code>.write</code> of <code>true</code>, or one true for every request signed in or not (such as <code>auth != null || true</code>), so anyone can write, replace, or delete values under that path.</td></tr><tr><td><code>RTDB-SEC-2</code></td><td>A <code>.read</code> of <code>true</code>, or one true for every request, so anyone can read everything under that path. At the root, this exposes the entire database.</td></tr><tr><td><code>RTDB-SEC-3</code></td><td>A conditional <code>.write</code> that never reads <code>auth</code>, so a signed-out client can write whenever the condition holds.</td></tr><tr><td><code>RTDB-SEC-4</code></td><td>A rule that tries to restrict access that an ancestor already grants, such as <code>auth.uid == $uid</code> under an ancestor’s <code>auth != null</code>. A deeper rule cannot revoke an ancestor’s grant, so the deeper rule restricts nothing.</td></tr><tr><td><code>RTDB-SEC-5</code></td><td>A <code>.validate</code> that a delete skips. <code>.validate</code> runs only on a non-null new value, so a client that can write <code>null</code> at an ancestor bypasses it.</td></tr><tr><td><code>RTDB-SEC-6</code></td><td>A <code>.write</code> that accepts any value: no <code>.validate</code> that reads its own new value sits at or below it, and the write rule does not check <code>newData</code>.</td></tr><tr><td><code>RTDB-SEC-7</code></td><td>A node that names children in <code>.validate</code> but has no <code>$other</code> rule, so a write can add any other key under it.</td></tr></tbody></table></div>
|
|
334
334
|
<p>For a ruleset that names children in <code>.validate</code>, <code>"$other": { ".validate": false }</code> rejects the keys it does not name.</p>
|
|
335
335
|
<p>Lint a ruleset before you simulate it. <code>simulate</code> does not run the deploy check. A case that reaches an expression that does not parse comes back <code>UNSUPPORTED</code>, and a rule the deploy refuses can still evaluate: a <code>.read</code> of <code>auth.uid</code> grants any signed-in reader in the simulator, and production never loads that ruleset at all.</p>
|
|
336
336
|
<p><code>pyric database rules validate database.rules.json</code> prints the errors in a file and exits with status 2 when it finds any. A finding about one rule includes the <code>line</code> and <code>column</code> of its rule key in the file, and comments in the file do not shift them.</p>
|
|
@@ -126,7 +126,7 @@ matchedPath: /records/$recordId/title
|
|
|
126
126
|
matchedRule: newData.isString() && newData.val().length <= 80
|
|
127
127
|
reason: Validation rule evaluated to false
|
|
128
128
|
```
|
|
129
|
-
`matchedPath` is the rule's location in the ruleset, so it shows the `$recordId` wildcard rather than the concrete path. `UNSUPPORTED` means the case reached an expression the simulator cannot evaluate
|
|
129
|
+
`matchedPath` is the rule's location in the ruleset, so it shows the `$recordId` wildcard rather than the concrete path. `UNSUPPORTED` means the simulator did not evaluate the case, and `reason` says why. Either the case reached an expression the simulator cannot evaluate, and it abstains rather than guesses, or no client could send the request. The second covers a path with `.`, `#`, `$`, `[` or `]` in it, update paths that overlap, a write under `/.info`, a query the SDK refuses to build, `updates` that leave out the case's `path` or give it a value other than `newData`, and a ruleset that does not compile. For a request the SDK refuses, `reason` is the SDK's own error text.
|
|
130
130
|
|
|
131
131
|
The result also carries a `trace` with every rule the simulator ran, in order:
|
|
132
132
|
```ts
|
|
@@ -197,7 +197,7 @@ The errors in the first group are the ones `firebase deploy` refuses, and each m
|
|
|
197
197
|
| `NOT_BOOLEAN` | The rule does not evaluate to a boolean, such as a `.read` of `auth.uid`. |
|
|
198
198
|
| `INVALID_OPERAND` | An operator gets an operand type it does not take, such as `data.val() > true`, or `!` on a string. |
|
|
199
199
|
| `INVALID_ARGUMENT` | A method gets the wrong number or type of arguments, such as `child(1)`, or `matches()` with anything other than a regular expression literal. |
|
|
200
|
-
| `INVALID_REGEX` | A regular expression literal
|
|
200
|
+
| `INVALID_REGEX` | A regular expression literal production refuses: a flag other than `i`, a `^` that is not the first character or a `$` that is not the last, or an unclosed group, repeat count or character set. A repeat count above 2,147,483,647 and a pattern too large to determinize, such as `a{100000}`, fail with production's texts. A pattern past pyric's own limits (more than 200,000 matcher states, or nesting deeper than 1,000 levels) reports here too, with a message that names the limit. |
|
|
201
201
|
| `NO_SUCH_MEMBER` | The value has no such method or property, such as `data.nope()`. |
|
|
202
202
|
| `NOT_AN_OBJECT` | A property access on a number, boolean, null, or regular expression. |
|
|
203
203
|
| `NOT_A_FUNCTION` | A call on something that is not a method, such as `auth.uid()`. |
|
|
@@ -208,10 +208,10 @@ The errors in the first group are the ones `firebase deploy` refuses, and each m
|
|
|
208
208
|
| `MULTIPLE_WILDCARDS` | One location has two `$` children. |
|
|
209
209
|
| `RULE_NOT_EXPRESSION` | A `.read`, `.write`, or `.validate` value is a number or a plain object rather than a boolean or a string. |
|
|
210
210
|
| `INDEX_ON_SHAPE` | `.indexOn` is a number. |
|
|
211
|
-
| `INVALID_KEY` | A key contains `#`,
|
|
211
|
+
| `INVALID_KEY` | A key contains `#`, an unknown key that starts with `.` holds an object, or an `.indexOn` entry other than `.value` contains `.`. |
|
|
212
212
|
| `EXPECTED_OBJECT` | An unknown key that starts with `.`, or a child key, holds a string. |
|
|
213
213
|
|
|
214
|
-
`INDEX_ON_SHAPE` and `INVALID_KEY` are warnings, not errors, for related forms: any other `.indexOn` that is not a string or an array of strings,
|
|
214
|
+
`INDEX_ON_SHAPE` and `INVALID_KEY` are warnings, not errors, for related forms: any other `.indexOn` that is not a string or an array of strings, a key that contains `.`, `/`, `[`, `]`, or an inner `$` but no `#`, and an `.indexOn` entry that contains `#`, `$`, `[` or `]`. Their text comes from the deploy's message for the related form, and no deploy of these forms has been recorded.
|
|
215
215
|
|
|
216
216
|
The second group is the rest of the per-rule checks:
|
|
217
217
|
|
|
@@ -227,12 +227,12 @@ The third group reads the whole ruleset, because the common RTDB mistakes come f
|
|
|
227
227
|
|
|
228
228
|
| Code | What it reports |
|
|
229
229
|
|---|---|
|
|
230
|
-
| `RTDB-SEC-1` | A `.write` of `true`,
|
|
231
|
-
| `RTDB-SEC-2` | A `.read` of `true`, so anyone can read everything under that path. At the root, this exposes the entire database. |
|
|
230
|
+
| `RTDB-SEC-1` | A `.write` of `true`, or one true for every request signed in or not (such as `auth != null \|\| true`), so anyone can write, replace, or delete values under that path. |
|
|
231
|
+
| `RTDB-SEC-2` | A `.read` of `true`, or one true for every request, so anyone can read everything under that path. At the root, this exposes the entire database. |
|
|
232
232
|
| `RTDB-SEC-3` | A conditional `.write` that never reads `auth`, so a signed-out client can write whenever the condition holds. |
|
|
233
|
-
| `RTDB-SEC-4` | A rule that tries to restrict access that an ancestor already grants. A deeper rule cannot revoke an ancestor's grant, so the deeper rule restricts nothing. |
|
|
233
|
+
| `RTDB-SEC-4` | A rule that tries to restrict access that an ancestor already grants, such as `auth.uid == $uid` under an ancestor's `auth != null`. A deeper rule cannot revoke an ancestor's grant, so the deeper rule restricts nothing. |
|
|
234
234
|
| `RTDB-SEC-5` | A `.validate` that a delete skips. `.validate` runs only on a non-null new value, so a client that can write `null` at an ancestor bypasses it. |
|
|
235
|
-
| `RTDB-SEC-6` | A `.write` that accepts any value: no `.validate` sits at or below it and the write rule does not check `newData`. |
|
|
235
|
+
| `RTDB-SEC-6` | A `.write` that accepts any value: no `.validate` that reads its own new value sits at or below it, and the write rule does not check `newData`. |
|
|
236
236
|
| `RTDB-SEC-7` | A node that names children in `.validate` but has no `$other` rule, so a write can add any other key under it. |
|
|
237
237
|
|
|
238
238
|
For a ruleset that names children in `.validate`, `"$other": { ".validate": false }` rejects the keys it does not name.
|