@pyric/cli 0.1.0-alpha.14 → 0.1.0-alpha.15
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 +120 -75
- package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
- package/dist/assurance/.generated/conformance-verdicts.js +120 -75
- package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
- package/dist/cli/serve.d.ts +1 -1
- package/dist/cli/serve.d.ts.map +1 -1
- package/dist/cli/serve.js +207 -284
- package/dist/cli/serve.js.map +1 -1
- package/dist/cli/service-command-records/database-rules-generate.d.ts +4 -0
- package/dist/cli/service-command-records/database-rules-generate.d.ts.map +1 -0
- package/dist/cli/service-command-records/database-rules-generate.js +3 -0
- package/dist/cli/service-command-records/database-rules-generate.js.map +1 -0
- package/dist/cli/service-command-records/database-rules-lint.d.ts +4 -0
- package/dist/cli/service-command-records/database-rules-lint.d.ts.map +1 -0
- package/dist/cli/service-command-records/database-rules-lint.js +3 -0
- package/dist/cli/service-command-records/database-rules-lint.js.map +1 -0
- package/dist/cli/service-command-records/database-rules-simulate.d.ts +4 -0
- package/dist/cli/service-command-records/database-rules-simulate.d.ts.map +1 -0
- package/dist/cli/service-command-records/database-rules-simulate.js +3 -0
- package/dist/cli/service-command-records/database-rules-simulate.js.map +1 -0
- package/dist/cli/service-command-records/database-rules-validate.d.ts +4 -0
- package/dist/cli/service-command-records/database-rules-validate.d.ts.map +1 -0
- package/dist/cli/service-command-records/database-rules-validate.js +3 -0
- package/dist/cli/service-command-records/database-rules-validate.js.map +1 -0
- package/dist/cli/service-command-records/firestore-indexes-generate.d.ts +4 -0
- package/dist/cli/service-command-records/firestore-indexes-generate.d.ts.map +1 -0
- package/dist/cli/service-command-records/firestore-indexes-generate.js +3 -0
- package/dist/cli/service-command-records/firestore-indexes-generate.js.map +1 -0
- package/dist/cli/service-command-records/firestore-rules-lint.d.ts +4 -0
- package/dist/cli/service-command-records/firestore-rules-lint.d.ts.map +1 -0
- package/dist/cli/service-command-records/firestore-rules-lint.js +3 -0
- package/dist/cli/service-command-records/firestore-rules-lint.js.map +1 -0
- package/dist/cli/service-command-records/firestore-rules-resolve.d.ts +4 -0
- package/dist/cli/service-command-records/firestore-rules-resolve.d.ts.map +1 -0
- package/dist/cli/service-command-records/firestore-rules-resolve.js +3 -0
- package/dist/cli/service-command-records/firestore-rules-resolve.js.map +1 -0
- package/dist/cli/service-command-records/firestore-rules-simulate.d.ts +4 -0
- package/dist/cli/service-command-records/firestore-rules-simulate.d.ts.map +1 -0
- package/dist/cli/service-command-records/firestore-rules-simulate.js +3 -0
- package/dist/cli/service-command-records/firestore-rules-simulate.js.map +1 -0
- package/dist/cli/service-command-records/firestore-rules-validate.d.ts +4 -0
- package/dist/cli/service-command-records/firestore-rules-validate.d.ts.map +1 -0
- package/dist/cli/service-command-records/firestore-rules-validate.js +3 -0
- package/dist/cli/service-command-records/firestore-rules-validate.js.map +1 -0
- package/dist/cli/service-command-records/storage-rules-lint.d.ts +4 -0
- package/dist/cli/service-command-records/storage-rules-lint.d.ts.map +1 -0
- package/dist/cli/service-command-records/storage-rules-lint.js +3 -0
- package/dist/cli/service-command-records/storage-rules-lint.js.map +1 -0
- package/dist/cli/service-command-records/storage-rules-simulate.d.ts +4 -0
- package/dist/cli/service-command-records/storage-rules-simulate.d.ts.map +1 -0
- package/dist/cli/service-command-records/storage-rules-simulate.js +3 -0
- package/dist/cli/service-command-records/storage-rules-simulate.js.map +1 -0
- package/dist/cli/service-commands.d.ts +7 -0
- package/dist/cli/service-commands.d.ts.map +1 -1
- package/dist/cli/service-commands.generated.d.ts +35 -0
- package/dist/cli/service-commands.generated.d.ts.map +1 -0
- package/dist/cli/service-commands.generated.js +25 -0
- package/dist/cli/service-commands.generated.js.map +1 -0
- package/dist/cli/service-commands.js +23 -40
- package/dist/cli/service-commands.js.map +1 -1
- package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
- package/dist/conformance/.generated/can-i-use-browser.js +1 -1
- package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
- 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/functions-rtdb/development-runtime.d.ts +63 -0
- package/dist/functions-rtdb/development-runtime.d.ts.map +1 -0
- package/dist/functions-rtdb/development-runtime.js +244 -0
- package/dist/functions-rtdb/development-runtime.js.map +1 -0
- package/dist/serve/bridge-mount.d.ts +32 -2
- package/dist/serve/bridge-mount.d.ts.map +1 -1
- package/dist/serve/bridge-mount.js +232 -18
- package/dist/serve/bridge-mount.js.map +1 -1
- package/dist/serve/bundler.d.ts +2 -18
- package/dist/serve/bundler.d.ts.map +1 -1
- package/dist/serve/bundler.js +7 -35
- package/dist/serve/bundler.js.map +1 -1
- package/dist/serve/entries/app-client.d.ts.map +1 -1
- package/dist/serve/entries/app-client.js +5 -5
- package/dist/serve/entries/app-client.js.map +1 -1
- package/dist/serve/entries/auth-helper-core.d.ts +23 -6
- package/dist/serve/entries/auth-helper-core.d.ts.map +1 -1
- package/dist/serve/entries/auth-helper-core.js +55 -24
- package/dist/serve/entries/auth-helper-core.js.map +1 -1
- package/dist/serve/entries/database.d.ts +28 -0
- package/dist/serve/entries/database.d.ts.map +1 -1
- package/dist/serve/entries/database.js +95 -26
- package/dist/serve/entries/database.js.map +1 -1
- package/dist/serve/entries/init.d.ts.map +1 -1
- package/dist/serve/entries/init.js +21 -12
- package/dist/serve/entries/init.js.map +1 -1
- package/dist/serve/html-injection.d.ts +5 -0
- package/dist/serve/html-injection.d.ts.map +1 -0
- package/dist/serve/html-injection.js +59 -0
- package/dist/serve/html-injection.js.map +1 -0
- package/dist/serve/namespace.d.ts +6 -22
- package/dist/serve/namespace.d.ts.map +1 -1
- package/dist/serve/namespace.js +23 -145
- package/dist/serve/namespace.js.map +1 -1
- package/dist/serve/runtime/worker-replacement.d.ts +1 -2
- package/dist/serve/runtime/worker-replacement.d.ts.map +1 -1
- package/dist/serve/sandbox-session.d.ts +78 -0
- package/dist/serve/sandbox-session.d.ts.map +1 -0
- package/dist/serve/sandbox-session.js +171 -0
- package/dist/serve/sandbox-session.js.map +1 -0
- package/dist/serve/server.d.ts +5 -2
- package/dist/serve/server.d.ts.map +1 -1
- package/dist/serve/server.js +21 -5
- package/dist/serve/server.js.map +1 -1
- package/dist/serve/site-tree.d.ts +8 -0
- package/dist/serve/site-tree.d.ts.map +1 -0
- package/dist/serve/site-tree.js +113 -0
- package/dist/serve/site-tree.js.map +1 -0
- package/dist/serve/site-ui/_astro/RulesCodeEditor.CzwHdCi9.js +23 -0
- package/dist/serve/site-ui/_astro/_example_.jevZ7OdV.css +1 -0
- package/dist/serve/site-ui/_astro/_slug_.BoKXYrnu.css +1 -0
- package/dist/serve/site-ui/_astro/_studio_.BtYpqe1A.css +1 -0
- package/dist/serve/site-ui/_astro/app.BnMC0ywl.js +109 -0
- package/dist/serve/site-ui/_astro/app.BsFsMjn0.css +1 -0
- package/dist/serve/site-ui/_astro/app.DVXXR-WI.js +1 -0
- package/dist/serve/site-ui/_astro/chess-showcase.DzPO6kz0.js +1 -0
- package/dist/serve/site-ui/_astro/chess-source-explorer.C5k9c5yK.js +1 -0
- package/dist/serve/site-ui/_astro/chess-v2.CFHmd3UL.js +354 -0
- package/dist/serve/site-ui/_astro/client.D2ORs4B-.js +25 -0
- package/dist/serve/site-ui/_astro/example-runtime.CM0H02rx.js +291 -0
- package/dist/serve/site-ui/_astro/index.B4Kh80he.js +1 -0
- package/dist/serve/site-ui/_astro/index.DBy5LfQW.js +9 -0
- package/dist/serve/site-ui/_astro/index.DNyk7q8W.js +9 -0
- package/dist/serve/site-ui/_astro/jsx-runtime.D_zvdyIk.js +9 -0
- package/dist/serve/site-ui/_astro/reads.D1exkX1-.js +1 -0
- package/dist/serve/site-ui/_astro/sandbox-controls.BqMePr5V.js +1153 -0
- package/dist/serve/site-ui/_astro/seed.BCn5DhHS.js +20 -0
- package/dist/serve/site-ui/auth/index.html +11 -0
- package/dist/serve/site-ui/docs/_rhythm/index.html +100 -0
- package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +43 -0
- package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +26 -0
- package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +70 -0
- package/dist/serve/{docs-ui → site-ui}/docs/ai-compat/index.html +3 -3
- package/dist/serve/site-ui/docs/api-reference/index.html +68 -0
- package/dist/serve/{docs-ui → site-ui}/docs/app-compat/index.html +3 -3
- package/dist/serve/{docs-ui → site-ui}/docs/auth-compat/index.html +3 -3
- package/dist/serve/site-ui/docs/build/ai-logic/index.html +64 -0
- package/dist/serve/site-ui/docs/build/authentication/index.html +66 -0
- package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +84 -0
- package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +71 -0
- package/dist/serve/site-ui/docs/build/cloud-storage/index.html +66 -0
- package/dist/serve/{docs-ui → site-ui}/docs/build/cloud-storage.md +2 -2
- package/dist/serve/site-ui/docs/build/realtime-database/index.html +67 -0
- package/dist/serve/site-ui/docs/conformance-scores/index.html +50 -0
- package/dist/serve/{docs-ui → site-ui}/docs/conformance-scores.md +3 -3
- package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +531 -0
- package/dist/serve/{docs-ui → site-ui}/docs/database-compat/index.html +211 -168
- package/dist/serve/{docs-ui → site-ui}/docs/database-compat.md +208 -170
- package/dist/serve/site-ui/docs/examples/chess/index.html +384 -0
- package/dist/serve/site-ui/docs/examples/chess.md +57 -0
- package/dist/serve/site-ui/docs/examples/index.html +3 -0
- package/dist/serve/site-ui/docs/examples.md +4 -0
- package/dist/serve/{docs-ui → site-ui}/docs/firestore-compat/index.html +55 -91
- package/dist/serve/{docs-ui → site-ui}/docs/firestore-compat.md +52 -88
- package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +73 -0
- package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +29 -0
- package/dist/serve/site-ui/docs/get-started/start-building/index.html +33 -0
- package/dist/serve/{docs-ui → site-ui}/docs/index.json +595 -26
- package/dist/serve/site-ui/docs/messaging-compat/index.html +324 -0
- package/dist/serve/{docs-ui → site-ui}/docs/messaging-compat.md +71 -1
- package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +28 -0
- package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +74 -0
- package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +45 -0
- package/dist/serve/site-ui/docs/overview/index.html +17 -0
- package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +186 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-auth-reference-api/index.html +4 -4
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-database-reference-api/index.html +4 -4
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-firestore-reference-api/index.html +318 -202
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-firestore-reference-api.md +154 -27
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-messaging-reference-api/index.html +5 -5
- package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +318 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ai-reference-api/index.html +5 -5
- package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +160 -0
- package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +425 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-auth-reference-api/index.html +5 -5
- package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +60 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-assurance-reference-api/index.html +4 -4
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-bridge-client-reference-api/index.html +4 -4
- package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +507 -0
- package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +258 -0
- package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +51 -0
- package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +308 -0
- package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +68 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-discover-reference-api/index.html +4 -4
- package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +11 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-remote-reference-api/index.html +4 -4
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-serve-worker-reference-api/index.html +1186 -1384
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-serve-worker-reference-api.md +817 -1291
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-verify-reference-api/index.html +4 -4
- package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +126 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-vite-reference-api.md +1 -1
- package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +2641 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-database-reference-api.md +1055 -158
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-firestore-reference-api/index.html +311 -249
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-firestore-reference-api.md +72 -54
- package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +509 -0
- package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +182 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-rules-reference-api/index.html +7 -26
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-rules-reference-api.md +13 -23
- package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +121 -0
- package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +203 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-sandbox-reference-api/index.html +26 -5
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-sandbox-reference-api.md +22 -22
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-storage-reference-api/index.html +5 -15
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-storage-reference-api.md +0 -13
- package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +639 -0
- package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +100 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-auth-reference-api/index.html +4 -4
- package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +24 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-events-reference-api/index.html +4 -4
- package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +136 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-firestore-reference-api/index.html +7 -7
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-firestore-reference-api.md +4 -4
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-primitives-reference-api/index.html +4 -4
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rtdb-reference-api/index.html +4 -4
- package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +16 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rules-reference-api/index.html +4 -4
- package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +176 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-storage-reference-api/index.html +10 -11
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-storage-reference-api.md +7 -8
- package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +188 -0
- package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-traffic-reference-api/index.html +4 -4
- package/dist/serve/{docs-ui → site-ui}/docs/rules-compat/index.html +87 -57
- package/dist/serve/{docs-ui → site-ui}/docs/rules-compat.md +84 -54
- package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +51 -0
- package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +106 -0
- package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +41 -0
- package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +67 -0
- package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +159 -0
- package/dist/serve/{docs-ui → site-ui}/docs/secure/rules-standard-library.md +2 -2
- package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +47 -0
- package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +95 -0
- package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +82 -0
- package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +37 -0
- package/dist/serve/site-ui/docs/ship/test-in-node/index.html +75 -0
- package/dist/serve/{docs-ui → site-ui}/docs/storage-compat/index.html +8 -8
- package/dist/serve/{docs-ui → site-ui}/docs/storage-compat.md +5 -5
- package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +132 -0
- package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +861 -0
- package/dist/serve/site-ui/docs/trust/rules-standard-library.md +344 -0
- package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research/index.html +582 -0
- package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research.md +448 -0
- package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +14 -0
- package/dist/serve/{docs-ui → site-ui}/docs/tutorial/index.html +4 -4
- package/dist/serve/{docs-ui → site-ui}/docs/tutorial.md +1 -1
- package/dist/serve/site-ui/examples/chess/index.html +2 -0
- package/dist/serve/site-ui/examples/firestore-first-write/index.html +2 -0
- package/dist/serve/site-ui/firestore/index.html +11 -0
- package/dist/serve/site-ui/index.html +11 -0
- package/dist/serve/{docs-ui → site-ui}/llms.txt +6 -2
- package/dist/serve/site-ui/rtdb/index.html +11 -0
- package/dist/serve/site-ui/settings/index.html +11 -0
- package/dist/serve/site-ui/storage/index.html +11 -0
- package/dist/serve/site-ui/studio-routes.json +1 -0
- package/dist/serve/site-ui/traffic/index.html +11 -0
- package/dist/serve/standalone-assets.d.ts +4 -10
- package/dist/serve/standalone-assets.d.ts.map +1 -1
- package/dist/serve/standalone-assets.js +8 -21
- package/dist/serve/standalone-assets.js.map +1 -1
- package/dist/serve/vite-functions-development.d.ts +29 -0
- package/dist/serve/vite-functions-development.d.ts.map +1 -0
- package/dist/serve/vite-functions-development.js +150 -0
- package/dist/serve/vite-functions-development.js.map +1 -0
- package/dist/serve/vite-generation-bridge.d.ts +17 -0
- package/dist/serve/vite-generation-bridge.d.ts.map +1 -0
- package/dist/serve/vite-generation-bridge.js +47 -0
- package/dist/serve/vite-generation-bridge.js.map +1 -0
- package/dist/serve/vite-generation-functions.d.ts +35 -0
- package/dist/serve/vite-generation-functions.d.ts.map +1 -0
- package/dist/serve/vite-generation-functions.js +46 -0
- package/dist/serve/vite-generation-functions.js.map +1 -0
- package/dist/serve/vite-generation-middleware.d.ts +10 -0
- package/dist/serve/vite-generation-middleware.d.ts.map +1 -0
- package/dist/serve/vite-generation-middleware.js +40 -0
- package/dist/serve/vite-generation-middleware.js.map +1 -0
- package/dist/serve/vite-generation-rules-watch.d.ts +8 -0
- package/dist/serve/vite-generation-rules-watch.d.ts.map +1 -0
- package/dist/serve/vite-generation-rules-watch.js +33 -0
- package/dist/serve/vite-generation-rules-watch.js.map +1 -0
- package/dist/serve/vite-module-swap.d.ts +16 -0
- package/dist/serve/vite-module-swap.d.ts.map +1 -0
- package/dist/serve/vite-module-swap.js +96 -0
- package/dist/serve/vite-module-swap.js.map +1 -0
- package/dist/serve/vite-page-runtime.d.ts +29 -0
- package/dist/serve/vite-page-runtime.d.ts.map +1 -0
- package/dist/serve/vite-page-runtime.js +71 -0
- package/dist/serve/vite-page-runtime.js.map +1 -0
- package/dist/serve/vite-plugin.d.ts +44 -4
- package/dist/serve/vite-plugin.d.ts.map +1 -1
- package/dist/serve/vite-plugin.js +62 -864
- package/dist/serve/vite-plugin.js.map +1 -1
- package/dist/serve/vite-sandbox-generation.d.ts +57 -0
- package/dist/serve/vite-sandbox-generation.d.ts.map +1 -0
- package/dist/serve/vite-sandbox-generation.js +178 -0
- package/dist/serve/vite-sandbox-generation.js.map +1 -0
- package/dist/serve/worker/client/disconnect.d.ts.map +1 -1
- package/dist/serve/worker/client/disconnect.js +2 -0
- package/dist/serve/worker/client/disconnect.js.map +1 -1
- package/dist/serve/worker/client/handles.d.ts +5 -0
- package/dist/serve/worker/client/handles.d.ts.map +1 -1
- package/dist/serve/worker/client/handles.js.map +1 -1
- package/dist/serve/worker/client/pagehide.d.ts +13 -0
- package/dist/serve/worker/client/pagehide.d.ts.map +1 -0
- package/dist/serve/worker/client/pagehide.js +19 -0
- package/dist/serve/worker/client/pagehide.js.map +1 -0
- package/dist/serve/worker/client/rtdb-admin.d.ts +8 -0
- package/dist/serve/worker/client/rtdb-admin.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb-admin.js +39 -0
- package/dist/serve/worker/client/rtdb-admin.js.map +1 -0
- package/dist/serve/worker/client/rtdb-connection-lifecycle.d.ts +15 -0
- package/dist/serve/worker/client/rtdb-connection-lifecycle.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb-connection-lifecycle.js +45 -0
- package/dist/serve/worker/client/rtdb-connection-lifecycle.js.map +1 -0
- package/dist/serve/worker/client/rtdb-controls.d.ts +6 -0
- package/dist/serve/worker/client/rtdb-controls.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb-controls.js +8 -0
- package/dist/serve/worker/client/rtdb-controls.js.map +1 -0
- package/dist/serve/worker/client/rtdb-listeners.d.ts +24 -0
- package/dist/serve/worker/client/rtdb-listeners.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb-listeners.js +262 -0
- package/dist/serve/worker/client/rtdb-listeners.js.map +1 -0
- package/dist/serve/worker/client/rtdb-reads.d.ts +4 -0
- package/dist/serve/worker/client/rtdb-reads.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb-reads.js +11 -0
- package/dist/serve/worker/client/rtdb-reads.js.map +1 -0
- package/dist/serve/worker/client/rtdb-references.d.ts +19 -0
- package/dist/serve/worker/client/rtdb-references.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb-references.js +63 -0
- package/dist/serve/worker/client/rtdb-references.js.map +1 -0
- package/dist/serve/worker/client/rtdb-snapshots.d.ts +20 -0
- package/dist/serve/worker/client/rtdb-snapshots.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb-snapshots.js +64 -0
- package/dist/serve/worker/client/rtdb-snapshots.js.map +1 -0
- package/dist/serve/worker/client/rtdb-transactions.d.ts +14 -0
- package/dist/serve/worker/client/rtdb-transactions.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb-transactions.js +34 -0
- package/dist/serve/worker/client/rtdb-transactions.js.map +1 -0
- package/dist/serve/worker/client/rtdb-writes.d.ts +8 -0
- package/dist/serve/worker/client/rtdb-writes.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb-writes.js +65 -0
- package/dist/serve/worker/client/rtdb-writes.js.map +1 -0
- package/dist/serve/worker/client.d.ts +0 -2
- package/dist/serve/worker/client.d.ts.map +1 -1
- package/dist/serve/worker/client.js +0 -2
- package/dist/serve/worker/client.js.map +1 -1
- package/dist/serve/worker/entry.js +2 -2
- package/dist/serve/worker/entry.js.map +1 -1
- package/dist/serve/worker/host/dispatch.d.ts +2 -0
- package/dist/serve/worker/host/dispatch.d.ts.map +1 -1
- package/dist/serve/worker/host/dispatch.js +24 -2
- package/dist/serve/worker/host/dispatch.js.map +1 -1
- package/dist/serve/worker/host/rtdb.d.ts +6 -2
- package/dist/serve/worker/host/rtdb.d.ts.map +1 -1
- package/dist/serve/worker/host/rtdb.js +224 -2
- package/dist/serve/worker/host/rtdb.js.map +1 -1
- package/dist/serve/worker/host/studio.d.ts.map +1 -1
- package/dist/serve/worker/host/studio.js +2 -0
- package/dist/serve/worker/host/studio.js.map +1 -1
- package/dist/serve/worker/host/subscriptions.d.ts.map +1 -1
- package/dist/serve/worker/host/subscriptions.js +3 -3
- package/dist/serve/worker/host/subscriptions.js.map +1 -1
- package/dist/serve/worker/host.d.ts +1 -1
- package/dist/serve/worker/host.d.ts.map +1 -1
- package/dist/serve/worker/host.js +1 -1
- package/dist/serve/worker/host.js.map +1 -1
- package/dist/serve/worker/index.d.ts +16 -1
- package/dist/serve/worker/index.d.ts.map +1 -1
- package/dist/serve/worker/index.js +17 -4
- package/dist/serve/worker/index.js.map +1 -1
- package/dist/serve/worker/protocol.d.ts +57 -0
- package/dist/serve/worker/protocol.d.ts.map +1 -1
- package/dist/serve/worker/protocol.js.map +1 -1
- package/dist/serve/worker/rtdb-value-equality.d.ts +3 -0
- package/dist/serve/worker/rtdb-value-equality.d.ts.map +1 -0
- package/dist/serve/worker/rtdb-value-equality.js +18 -0
- package/dist/serve/worker/rtdb-value-equality.js.map +1 -0
- package/dist/serve/worker/serve-init.js +2 -2
- package/dist/serve/worker/serve-init.js.map +1 -1
- package/dist/serve/worker/service-worker-relay.js +2 -2
- package/dist/serve/worker/service-worker-relay.js.map +1 -1
- package/package.json +7 -5
- package/src/assurance/.generated/conformance-verdicts.ts +120 -75
- package/src/cli/serve.ts +215 -307
- package/src/cli/service-command-records/database-rules-generate.ts +3 -0
- package/src/cli/service-command-records/database-rules-lint.ts +3 -0
- package/src/cli/service-command-records/database-rules-simulate.ts +3 -0
- package/src/cli/service-command-records/database-rules-validate.ts +3 -0
- package/src/cli/service-command-records/firestore-indexes-generate.ts +3 -0
- package/src/cli/service-command-records/firestore-rules-lint.ts +3 -0
- package/src/cli/service-command-records/firestore-rules-resolve.ts +3 -0
- package/src/cli/service-command-records/firestore-rules-simulate.ts +3 -0
- package/src/cli/service-command-records/firestore-rules-validate.ts +3 -0
- package/src/cli/service-command-records/storage-rules-lint.ts +3 -0
- package/src/cli/service-command-records/storage-rules-simulate.ts +3 -0
- package/src/cli/service-commands.generated.ts +27 -0
- package/src/cli/service-commands.test.ts +43 -0
- package/src/cli/service-commands.ts +36 -51
- package/src/conformance/.generated/can-i-use-browser.ts +1 -1
- package/src/conformance/.generated/can-i-use.ts +1 -1
- package/src/conformance/.generated/conformance-docs.ts +1 -1
- package/src/functions-rtdb/development-runtime.ts +299 -0
- package/src/serve/bridge-mount.ts +253 -19
- package/src/serve/bundler.ts +8 -34
- package/src/serve/entries/app-client.ts +5 -4
- package/src/serve/entries/auth-helper-core.ts +83 -30
- package/src/serve/entries/database.ts +180 -57
- package/src/serve/entries/init.ts +30 -20
- package/src/serve/html-injection.ts +65 -0
- package/src/serve/namespace.ts +26 -169
- package/src/serve/runtime/worker-replacement.ts +1 -1
- package/src/serve/sandbox-session.ts +233 -0
- package/src/serve/server.ts +20 -5
- package/src/serve/site-tree.ts +146 -0
- package/src/serve/standalone-assets.ts +9 -26
- package/src/serve/vite-functions-development.ts +201 -0
- package/src/serve/vite-generation-bridge.ts +66 -0
- package/src/serve/vite-generation-functions.ts +78 -0
- package/src/serve/vite-generation-middleware.ts +56 -0
- package/src/serve/vite-generation-rules-watch.ts +37 -0
- package/src/serve/vite-module-swap.ts +119 -0
- package/src/serve/vite-page-runtime.ts +100 -0
- package/src/serve/vite-plugin.ts +78 -883
- package/src/serve/vite-sandbox-generation.ts +255 -0
- package/src/serve/worker/client/disconnect.ts +3 -1
- package/src/serve/worker/client/handles.ts +5 -0
- package/src/serve/worker/client/pagehide.ts +31 -0
- package/src/serve/worker/client/rtdb-admin.ts +74 -0
- package/src/serve/worker/client/rtdb-connection-lifecycle.ts +52 -0
- package/src/serve/worker/client/rtdb-controls.ts +8 -0
- package/src/serve/worker/client/rtdb-listeners.ts +337 -0
- package/src/serve/worker/client/rtdb-reads.ts +12 -0
- package/src/serve/worker/client/rtdb-references.ts +85 -0
- package/src/serve/worker/client/rtdb-snapshots.ts +118 -0
- package/src/serve/worker/client/rtdb-transactions.ts +51 -0
- package/src/serve/worker/client/rtdb-writes.ts +74 -0
- package/src/serve/worker/client.ts +0 -2
- package/src/serve/worker/entry.ts +2 -2
- package/src/serve/worker/host/dispatch.ts +22 -2
- package/src/serve/worker/host/rtdb.ts +243 -2
- package/src/serve/worker/host/studio.ts +2 -0
- package/src/serve/worker/host/subscriptions.ts +8 -4
- package/src/serve/worker/host.ts +1 -1
- package/src/serve/worker/index.ts +58 -10
- package/src/serve/worker/protocol.ts +23 -2
- package/src/serve/worker/rtdb-value-equality.ts +17 -0
- package/src/serve/worker/serve-init.ts +2 -2
- package/src/serve/worker/service-worker-relay.ts +2 -2
- package/dist/serve/docs-ui/_astro/_slug_.DUci-duz.css +0 -1
- package/dist/serve/docs-ui/docs/_rhythm/index.html +0 -100
- package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +0 -43
- package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +0 -26
- package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +0 -70
- package/dist/serve/docs-ui/docs/api-reference/index.html +0 -68
- package/dist/serve/docs-ui/docs/build/ai-logic/index.html +0 -64
- package/dist/serve/docs-ui/docs/build/authentication/index.html +0 -66
- package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +0 -70
- package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +0 -71
- package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +0 -66
- package/dist/serve/docs-ui/docs/build/realtime-database/index.html +0 -67
- package/dist/serve/docs-ui/docs/conformance-scores/index.html +0 -50
- package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +0 -531
- package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +0 -73
- package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +0 -29
- package/dist/serve/docs-ui/docs/get-started/start-building/index.html +0 -33
- package/dist/serve/docs-ui/docs/messaging-compat/index.html +0 -265
- package/dist/serve/docs-ui/docs/observe/resolve-runtime-status/index.html +0 -28
- package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +0 -74
- package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +0 -45
- package/dist/serve/docs-ui/docs/overview/index.html +0 -17
- package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +0 -186
- package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +0 -318
- package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +0 -160
- package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +0 -425
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +0 -60
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +0 -507
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +0 -258
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +0 -51
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +0 -308
- package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +0 -68
- package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +0 -11
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +0 -126
- package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +0 -1852
- package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +0 -509
- package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +0 -182
- package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +0 -121
- package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +0 -203
- package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +0 -639
- package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +0 -100
- package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +0 -24
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +0 -136
- package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +0 -16
- package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +0 -176
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +0 -188
- package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +0 -51
- package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +0 -106
- package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +0 -41
- package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +0 -67
- package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +0 -159
- package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +0 -47
- package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +0 -95
- package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +0 -82
- package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +0 -37
- package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +0 -75
- package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +0 -132
- package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +0 -14
- package/dist/serve/docs-ui/index.html +0 -1
- package/dist/serve/studio-ui/assets/RulesCodeEditor-BDlH-5lp.js +0 -23
- package/dist/serve/studio-ui/assets/index-Bf9SSE8L.js +0 -1218
- package/dist/serve/studio-ui/assets/index-BlSGru_r.css +0 -1
- package/dist/serve/studio-ui/assets/seed-D_UjxfOU.js +0 -20
- package/dist/serve/studio-ui/index.html +0 -32
- package/dist/serve/worker/client/rtdb.d.ts +0 -36
- package/dist/serve/worker/client/rtdb.d.ts.map +0 -1
- package/dist/serve/worker/client/rtdb.js +0 -241
- package/dist/serve/worker/client/rtdb.js.map +0 -1
- package/src/serve/worker/client/rtdb.ts +0 -311
- /package/dist/serve/{docs-ui → site-ui}/404.html +0 -0
- /package/dist/serve/{docs-ui → site-ui}/_astro/_slug_.CXh9yTP1.css +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/_rhythm.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/agent/set-up-your-agent.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/agent/watch-and-review.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/agent/work-with-an-agent.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/ai-compat.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/api-reference.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/app-compat.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/auth-compat.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/build/ai-logic.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/build/authentication.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/build/cloud-firestore.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/build/cloud-messaging.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/build/realtime-database.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/create-pyric-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/functions-rtdb-compat.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/get-started/how-the-swap-works.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/get-started/start-building.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/index.html +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/observe/resolve-runtime-status.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/observe/see-whats-happening.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/observe/shape-your-data.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/overview.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-app-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-auth-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-database-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-messaging-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-storage-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ai-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ai-scripting-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-app-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-auth-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-assurance-browser-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-assurance-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-bridge-client-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-bridge-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-conformance-browser-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-conformance-docs-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-conformance-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-credentials-node-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-discover-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-register-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-remote-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-verify-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-messaging-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-messaging-sw-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-sandbox-database-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-sandbox-firestore-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-agents-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-auth-hooks-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-auth-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-events-hooks-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-events-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-firestore-hooks-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-primitives-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rtdb-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rules-hooks-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rules-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-storage-hooks-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-traffic-hooks-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-traffic-reference-api.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/secure/audit-your-rules.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/secure/firestore-rules-limits.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/secure/read-a-denial.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/secure/rtdb-rules-in-typescript.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/secure/secure-it-with-rules.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/secure/simulate-and-lint.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/secure/write-a-rules-test-suite.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/ship/ship-to-production.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/ship/test-in-node.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/trust/how-we-know-it-matches-firebase.md +0 -0
- /package/dist/serve/{docs-ui → site-ui}/docs/trust/versioning-and-compatibility.md +0 -0
- /package/dist/serve/{studio-ui → site-ui}/pyric-logo.svg +0 -0
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Storage Rules modules: evidence and design · Pyric Studio</title><meta name="description" content="The production probes, service boundaries, and staged proposal behind Pyric's Storage Rules standard library."><link rel="icon" type="image/svg+xml" href="/__pyric/ui/pyric-logo.svg"><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link rel="stylesheet" href="/__pyric/ui/_astro/_slug_.CXh9yTP1.css">
|
|
2
|
+
<link rel="stylesheet" href="/__pyric/ui/_astro/_slug_.BoKXYrnu.css"></head> <body> <header class="studio__bar" data-astro-cid-mw7aashj> <div class="studio__bar-inner" data-astro-cid-mw7aashj> <a class="studio__brand" href="/__pyric/ui/" aria-label="Pyric Studio" data-astro-cid-mw7aashj>Pyric</a> <nav class="studio__nav" aria-label="Studio tabs" data-astro-cid-mw7aashj> <a class="studio__nav-tab" href="/__pyric/ui/" data-astro-cid-mw7aashj> Home </a><a class="studio__nav-tab" href="/__pyric/ui/firestore" data-astro-cid-mw7aashj> Firestore </a><a class="studio__nav-tab" href="/__pyric/ui/auth" data-astro-cid-mw7aashj> Auth </a><a class="studio__nav-tab" href="/__pyric/ui/rtdb" data-astro-cid-mw7aashj> RTDB </a><a class="studio__nav-tab" href="/__pyric/ui/storage" data-astro-cid-mw7aashj> Storage </a><a class="studio__nav-tab" href="/__pyric/ui/traffic" data-astro-cid-mw7aashj> Traffic </a><a class="studio__nav-tab" href="/__pyric/ui/settings" data-astro-cid-mw7aashj> Settings </a><a class="studio__nav-tab" href="/__pyric/ui/docs" aria-current="page" data-astro-cid-mw7aashj> Docs </a> </nav> </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/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/cloud-firestore/"> Cloud Firestore </a> </li><li> <a href="/__pyric/ui/docs/build/realtime-database/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-storage/"> Cloud Storage </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-messaging/"> Cloud Messaging </a> </li><li> <a href="/__pyric/ui/docs/build/ai-logic/"> AI Logic </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Secure & debug</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/secure/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/secure/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/secure/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/secure/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/secure/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/secure/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/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" open> <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/storage-rules-stdlib-research/" aria-current="page"> Storage Rules modules: evidence and design </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/"> Public API coverage </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> </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-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-firestore-reference-api/"> pyric/sandbox/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-database-reference-api/"> pyric/sandbox/database </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-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> </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-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-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> </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-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> </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/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/cloud-firestore/"> Cloud Firestore </a> </li><li> <a href="/__pyric/ui/docs/build/realtime-database/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-storage/"> Cloud Storage </a> </li><li> <a href="/__pyric/ui/docs/build/cloud-messaging/"> Cloud Messaging </a> </li><li> <a href="/__pyric/ui/docs/build/ai-logic/"> AI Logic </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-secure-debug"> <summary>Secure & debug</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/secure/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/secure/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/secure/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/secure/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/secure/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/secure/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/secure/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/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" open> <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/storage-rules-stdlib-research/" aria-current="page"> Storage Rules modules: evidence and design </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/"> Public API coverage </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> </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-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-firestore-reference-api/"> pyric/sandbox/firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-database-reference-api/"> pyric/sandbox/database </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-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> </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-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-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> </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-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> </details> </nav> <main class="doc-main" data-astro-cid-mw7aashj> <nav class="docs-breadcrumbs" aria-label="Breadcrumb"> <ol> <li> <a href="/__pyric/ui/docs/trust/versioning-and-compatibility/">Trust</a> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span aria-current="page">Storage Rules modules: evidence and design</span> </li> </ol> </nav> <article class="prose" data-astro-cid-mw7aashj> <h1 id="storage-rules-2modules-and-a-service-aware-standard-library">Storage Rules, <code>2+modules</code>, and a service-aware standard library</h1>
|
|
3
|
+
<p><strong>Investigated:</strong> 2026-07-20 at <code>6e5ecd6e3718</code></p>
|
|
4
|
+
<p><strong>Primary sources:</strong> Firebase Security Rules documentation and REST API reference; this repository’s resolver, Storage evaluator, standard-library sources, and conformance inventory.</p>
|
|
5
|
+
<h2 id="implementation-status-on-this-branch">Implementation status on this branch</h2>
|
|
6
|
+
<p>The first trust slice recommended by this report is now implemented. Normal
|
|
7
|
+
Storage setup lowers <code>2+modules</code> through a service-aware resolver; <code>auth</code> and
|
|
8
|
+
<code>membership</code> are the only bundled modules admitted for both Firestore and
|
|
9
|
+
Storage; <code>storage/uploads</code>, <code>storage/metadata</code>, <code>storage/objects</code>, and
|
|
10
|
+
<code>storage/time</code> are Storage-only; every other bundled module is explicitly
|
|
11
|
+
Firestore-only; and caller modules are checked transitively against the target
|
|
12
|
+
service’s ambient bindings and functions, with unclassified requirements
|
|
13
|
+
failing closed. Three targeted <code>projects.test</code> requests captured 39 production
|
|
14
|
+
verdicts for the exact six shared bodies under both Firestore and Storage plus
|
|
15
|
+
the 13 Storage-only function bodies, and the local rules simulators match all
|
|
16
|
+
39. The observations are registered as <code>firestore-rules#189</code>,
|
|
17
|
+
<code>storage-rules#125</code>, and <code>storage-rules#132</code>.</p>
|
|
18
|
+
<p>The first P2 Storage-native and mocked P3 cross-service matrices are now
|
|
19
|
+
captured as <code>rules-storage-upload-primitives-boundaries</code> and
|
|
20
|
+
<code>rules-storage-firestore-lookup-budget</code>. They used two batched Rules Test API
|
|
21
|
+
requests (40 cases total) and no real Storage or Firestore data. Direct
|
|
22
|
+
<code>parseStorageRules()</code> remains a plain-v2 parser; module lowering occurs in the
|
|
23
|
+
resolver and normal Storage service setup.</p>
|
|
24
|
+
<p>The captures established inclusive size limits, exact/whole-string MIME
|
|
25
|
+
behavior, metadata <code>keys().hasAll()</code> and <code>get(default)</code>, generation and
|
|
26
|
+
metageneration integer comparisons, strict time boundaries, and lazy
|
|
27
|
+
cross-service lookup evaluation. The three local divergences they found are now
|
|
28
|
+
closed: metadata collection methods are implemented, missing
|
|
29
|
+
<code>request.resource</code> carries a Rules error, and anonymous-auth ternaries deny in
|
|
30
|
+
the same way as production.</p>
|
|
31
|
+
<p>The mocked API ALLOWed three distinct lookup calls and reported all three in its
|
|
32
|
+
function-call diagnostics. Therefore mocks do <strong>not</strong> prove the documented
|
|
33
|
+
real-resource access budget. The later real-resource rig proves the two-distinct
|
|
34
|
+
document limit, repeat-path caching, default-database and owning-project
|
|
35
|
+
boundaries, and independence from Firestore client rules (<code>storage-rules#131</code>).
|
|
36
|
+
Consistency remains bounded characterization rather than a latency guarantee.</p>
|
|
37
|
+
<h3 id="follow-up-discovery-captures-2026-07-21">Follow-up discovery captures (2026-07-21)</h3>
|
|
38
|
+
<p>The read-only <code>storage-stdlib-discovery</code> rig now records three additional
|
|
39
|
+
production boundaries. Paired Firestore/Storage requests reject braced imports
|
|
40
|
+
under both v2 and <code>2+modules</code>; the Rules Test API also rejects every two-file
|
|
41
|
+
source shape with <code>INVALID_ARGUMENT</code>, regardless of file order. The portable
|
|
42
|
+
deployment contract therefore remains Pyric-lowered, single-file v2 rather than
|
|
43
|
+
server-side linking.</p>
|
|
44
|
+
<p>Identical pure function bodies passed under both services for the tested string,
|
|
45
|
+
list, Map/MapDiff/Set, math, hashing, duration/timestamp, and LatLng families.
|
|
46
|
+
<code>math.isInfinite</code> denied under both services as an invalid function; the math
|
|
47
|
+
family passed after removing that control. These are candidate common-language
|
|
48
|
+
capabilities, not Pyric conformance credit, until each is implemented and
|
|
49
|
+
replayed locally.</p>
|
|
50
|
+
<p>The remaining synthetic Storage-native probe established metadata <code>diff()</code>
|
|
51
|
+
boundaries, timestamp-typed <code>resource.updated</code>, exact Unicode metadata equality,
|
|
52
|
+
and rule addressability of explicitly supplied md5/crc32c/etag fields. Synthetic
|
|
53
|
+
hash fields do not prove that real uploads populate them.</p>
|
|
54
|
+
<p>The first real-resource rig run restored the exact prior Storage release and
|
|
55
|
+
verified all run-scoped Firestore documents and Storage objects absent before
|
|
56
|
+
writing its capture. With cross-service IAM disabled, every executed
|
|
57
|
+
<code>firestore.get</code>/<code>exists</code> rule denied while a <code>true || lookup</code> rule allowed. The
|
|
58
|
+
original oracle service account and active human gcloud credential both lacked
|
|
59
|
+
<code>setIamPolicy</code>, so neither could run the enabled phase on <code>genkit-idx</code>; their
|
|
60
|
+
grant attempts failed before changing its policy. The separate <code>digame-mas</code>
|
|
61
|
+
credential had the complete bounded permission set and was used for the
|
|
62
|
+
temporary-IAM capture below. The rig also supports <code>--iam-enabled</code> when a
|
|
63
|
+
project administrator has enabled the role beforehand, without reading or
|
|
64
|
+
mutating IAM.</p>
|
|
65
|
+
<p>The IAM-enabled run on <code>digame-mas</code> established the core access contract: one
|
|
66
|
+
and two distinct existing-document lookups allowed, while three denied.
|
|
67
|
+
Repeating one path three times allowed, and combining <code>get</code> plus <code>exists</code> over
|
|
68
|
+
two distinct paths allowed, consistent with access-call caching. A negated
|
|
69
|
+
<code>exists</code> check for a missing document allowed; dereferencing a missing <code>get</code>
|
|
70
|
+
denied. The always-true short-circuit control allowed. IAM propagation required
|
|
71
|
+
a two-minute quiet interval; dense early retries incorrectly resembled a
|
|
72
|
+
disabled permission boundary. IAM removal also showed eventually consistent
|
|
73
|
+
reads, so the rig now performs delayed restoration verification and one bounded
|
|
74
|
+
repeat restoration before accepting cleanup.</p>
|
|
75
|
+
<p>The next IAM-enabled advanced matrix established:</p>
|
|
76
|
+
<ul>
|
|
77
|
+
<li><code>get</code> returns nested maps and lists with the expected Rules types; nested field
|
|
78
|
+
access and list membership allowed.</li>
|
|
79
|
+
<li>Direct access to an absent field and comparing an integer field with a string
|
|
80
|
+
denied instead of producing a false allow.</li>
|
|
81
|
+
<li>An anonymous <code>request.auth.uid</code> path interpolation and a named-database path
|
|
82
|
+
denied. The default-database path remained the only production-proven form.</li>
|
|
83
|
+
<li>Lookup calls composed through a helper, a <code>let</code>-bound <code>get</code>, <code>false || call</code>,
|
|
84
|
+
and the selected branch of a ternary expression all allowed.</li>
|
|
85
|
+
<li>A missing-document dereference on the left of <code>|| true</code> allowed, confirming
|
|
86
|
+
Storage shares the language’s error-absorption behavior; <code>false &&</code> the same
|
|
87
|
+
dereference denied without granting access.</li>
|
|
88
|
+
<li>An anonymous Firestore client was demonstrably denied and then allowed for
|
|
89
|
+
the run-scoped document as the temporary Firestore rules changed. The same
|
|
90
|
+
Storage lookup allowed in both states. This pins cross-service lookup as IAM
|
|
91
|
+
service-agent data access, not a request authorized through <code>firestore.rules</code>.</li>
|
|
92
|
+
</ul>
|
|
93
|
+
<p>The advanced rig restores both exact Rules release pointers, and an exclusive
|
|
94
|
+
local lock now rejects overlapping real-resource runs before network mutation.</p>
|
|
95
|
+
<p>The remaining high-value production probes established the server-owned and
|
|
96
|
+
project/database boundaries:</p>
|
|
97
|
+
<ul>
|
|
98
|
+
<li>Existing Storage objects exposed exact generation, metageneration, MD5,
|
|
99
|
+
CRC32C, etag, <code>timeCreated</code>, and <code>updated</code> values to Rules. Grouped mismatch
|
|
100
|
+
controls denied.</li>
|
|
101
|
+
<li>Incoming creates exposed computed MD5 and CRC32C values. Accessing incoming
|
|
102
|
+
generation, etag, or creation time denied, matching the documented
|
|
103
|
+
<code>request.resource</code> exclusions.</li>
|
|
104
|
+
<li>A metadata-only update preserved generation, hashes, and creation time while
|
|
105
|
+
advancing metageneration and <code>updated</code>. Byte overwrites guarded by changed MD5
|
|
106
|
+
or CRC32C allowed and advanced generation while changing both hashes.</li>
|
|
107
|
+
<li>Three <code>false -> true -> false</code> Firestore membership cycles all produced the
|
|
108
|
+
expected immediate Storage decision. The six requests began 106-457 ms after
|
|
109
|
+
their corresponding write began; no delayed confirmation was needed. This is
|
|
110
|
+
bounded characterization, not a latency guarantee.</li>
|
|
111
|
+
<li>A verified <code>allow: true</code> document in the existing <code>probes</code> named database
|
|
112
|
+
still denied through a named-database lookup, while the default-database
|
|
113
|
+
control tracked its document value. Storage-to-Firestore access remains
|
|
114
|
+
default-database-only.</li>
|
|
115
|
+
<li>With identical paths and opposite values in <code>digame-mas</code> and <code>genkit-idx</code>,
|
|
116
|
+
Storage hosted by <code>digame-mas</code> followed only the <code>digame-mas</code> value. The
|
|
117
|
+
lookup cannot escape into another project’s Firestore data.</li>
|
|
118
|
+
</ul>
|
|
119
|
+
<p>The two executions stayed within their authored caps: 38 Storage operations
|
|
120
|
+
for native fields, then 23 Storage operations and 22 Firestore writes for all
|
|
121
|
+
remaining cross-service cases combined. Both independently verified the prior
|
|
122
|
+
Storage release, empty object namespace, deleted documents, and—where used—the
|
|
123
|
+
restored IAM policy before writing observations.</p>
|
|
124
|
+
<h2 id="historical-baseline-at-the-investigation-fixed-point">Historical baseline at the investigation fixed point</h2>
|
|
125
|
+
<p>At the report’s original <code>6e5ecd6e3718</code> fixed point, <code>storage.rules</code> did <strong>not</strong>
|
|
126
|
+
work end to end with <code>rules_version = '2+modules'</code> in Pyric’s normal Storage
|
|
127
|
+
path. The implementation-status section above supersedes this historical
|
|
128
|
+
baseline: the normal Storage path now lowers modules through the checked
|
|
129
|
+
resolver, and only the production-proven <code>auth</code> and <code>membership</code> modules are
|
|
130
|
+
shared with Storage.</p>
|
|
131
|
+
<p>There were two distinct behaviors at that fixed point:</p>
|
|
132
|
+
<ol>
|
|
133
|
+
<li>The generic module compiler can structurally resolve a Storage source. It parses the service name, loads imports from one flat standard-library catalog, injects the requested functions, and rewrites <code>2+modules</code> to <code>2</code>. It does not check whether an imported function is compatible with <code>firebase.storage</code> (<a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/pyric/src/rules/modules/resolver-core.ts#L242-L354" target="_blank" rel="noopener noreferrer" class="external-link">resolver core</a>, <a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/pyric/src/rules/modules/resolver-browser.ts#L41-L69" target="_blank" rel="noopener noreferrer" class="external-link">browser catalog</a>).</li>
|
|
134
|
+
<li>The Storage service does not call that compiler. It passes the source directly to <code>parseStorageRules()</code>, which turns imports into unresolved stubs; calling one denies with an explicit “module resolution is not implemented” reason (<a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/pyric/src/storage/service.ts#L171-L204" target="_blank" rel="noopener noreferrer" class="external-link">Storage service</a>, <a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/pyric/src/storage/rules.ts#L436-L480" target="_blank" rel="noopener noreferrer" class="external-link">Storage parser</a>, <a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/pyric/src/storage/rules.ts#L1043-L1060" target="_blank" rel="noopener noreferrer" class="external-link">call behavior</a>).</li>
|
|
135
|
+
</ol>
|
|
136
|
+
<p>That mismatch is a Trust issue, not merely missing convenience. If Pyric simply wires the current resolver into Storage, <code>auth.isAuthenticated()</code> can plausibly work, but Firestore-bound helpers such as <code>lifecycle.immutableFields()</code> will also compile and then depend on <code>request.resource.data</code>, <code>resource.data</code>, and <code>MapDiff</code> semantics that Storage does not provide in that shape. A successful compile would overstate compatibility.</p>
|
|
137
|
+
<p>The recommendation is a <strong>service-aware, capability-checked module compiler</strong>:</p>
|
|
138
|
+
<pre class="astro-code one-dark-pro" style="background-color:#282c34;color:#abb2bf; overflow-x: auto;" tabindex="0" data-language="text"><code><span class="line"><span>parsed target service</span></span>
|
|
139
|
+
<span class="line"><span> |</span></span>
|
|
140
|
+
<span class="line"><span> v</span></span>
|
|
141
|
+
<span class="line"><span>common capability intersection + target-service capabilities</span></span>
|
|
142
|
+
<span class="line"><span> |</span></span>
|
|
143
|
+
<span class="line"><span> v</span></span>
|
|
144
|
+
<span class="line"><span>resolve imports and transitive private dependencies</span></span>
|
|
145
|
+
<span class="line"><span> |</span></span>
|
|
146
|
+
<span class="line"><span> v</span></span>
|
|
147
|
+
<span class="line"><span>reject incompatible exports before emitting plain v2</span></span>
|
|
148
|
+
<span class="line"><span> |</span></span>
|
|
149
|
+
<span class="line"><span> v</span></span>
|
|
150
|
+
<span class="line"><span>target evaluator + production-backed conformance evidence</span></span></code></pre>
|
|
151
|
+
<p>Ship no new Storage module merely because its source looks plausible. First run the proposed probes below, promote only production-observed behavior into the capability catalog, and keep unverified capability combinations fail-closed.</p>
|
|
152
|
+
<h2 id="what-firebase-itself-guarantees">What Firebase itself guarantees</h2>
|
|
153
|
+
<h3 id="one-language-family-separate-service-scopes">One language family, separate service scopes</h3>
|
|
154
|
+
<p>Firestore and Storage share the Rules language’s service/match/allow/function structure and the granular <code>get</code>, <code>list</code>, <code>create</code>, <code>update</code>, and <code>delete</code> methods plus <code>read</code>/<code>write</code> umbrellas (<a href="https://firebase.google.com/docs/rules/rules-language" target="_blank" rel="noopener noreferrer" class="external-link">Rules language</a>). They do <strong>not</strong> share one deployable rules source: Firebase permits one <code>service</code> declaration per source file and requires separate files for Firestore and Storage (<a href="https://firebase.google.com/docs/rules/rules-language#service" target="_blank" rel="noopener noreferrer" class="external-link">Rules language, Service</a>). Storage’s <code>service firebase.storage</code> scope exists specifically to prevent conflicts with rules for products such as Firestore (<a href="https://firebase.google.com/docs/storage/security/core-syntax#service_and_database_declaration" target="_blank" rel="noopener noreferrer" class="external-link">Storage core syntax</a>).</p>
|
|
155
|
+
<p>Firebase publicly documents the latest production syntax as v2, while Pyric’s resolver uses <code>rules_version = '2+modules'</code> plus braced <code>import</code>/<code>export</code> as an authoring format and lowers it to ordinary v2 before evaluation or deployment (<a href="https://firebase.google.com/docs/rules/rules-language#syntax_version" target="_blank" rel="noopener noreferrer" class="external-link">Firebase syntax version</a>, <a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/pyric/src/rules/modules/resolver-core.ts#L242-L354" target="_blank" rel="noopener noreferrer" class="external-link">Pyric resolver</a>). The repository says the grammar also models a server-gated modules preview: a live Rules Test API observation on the test project rejected braced imports even under <code>2+modules</code>, while the parser deliberately retained them for preview modeling (<a href="https://github.com/davideast/pyric/commit/d24ee1e5ae0de444963683bc053222c59c4aef14" target="_blank" rel="noopener noreferrer" class="external-link">commit <code>d24ee1e5</code></a>). Thus it is too broad to call every import construct purely invented, but it is equally unsafe to call it stock Firebase syntax. Preview parsing, Pyric’s local linker, and portable deployed v2 are separate contracts.</p>
|
|
156
|
+
<p>The Rules management API adds another layer: a <code>Source</code> is a bundle of one or more named <code>File</code> messages (<a href="https://firebase.google.com/docs/reference/rules/rest/v1/projects.rulesets#Source" target="_blank" rel="noopener noreferrer" class="external-link">Ruleset Source</a>). Multiple files in the transport do not, by themselves, prove that braced imports link between those files, that the Firebase CLI uploads the same bundle, or that either behavior is enabled for Storage. Those are probe questions, not conclusions available from the schema.</p>
|
|
157
|
+
<p>Therefore module portability is a contract Pyric must define and prove; it cannot be inferred from shared syntax, parser acceptance, or a multi-file REST payload.</p>
|
|
158
|
+
<h3 id="resolved-trust-contradiction">Resolved trust contradiction</h3>
|
|
159
|
+
<p>At the investigation fixed point, the Storage syntax-acceptance test said every
|
|
160
|
+
case was accepted by production while including a braced import. That claim is
|
|
161
|
+
now corrected: the test describes parser acceptance, and the P0 capture records
|
|
162
|
+
that production rejected braced imports under both v2 and <code>2+modules</code>, including
|
|
163
|
+
multi-file source bundles. Pyric’s portable contract is the resolver’s emitted
|
|
164
|
+
single-file v2 source; Firebase is not claimed to link Pyric modules.</p>
|
|
165
|
+
<h3 id="the-documented-shared-language-surface">The documented shared language surface</h3>
|
|
166
|
+
<p>The two service references overlap on core values and operations: null, Boolean, integer/float arithmetic, strings, paths, lists, maps, timestamps, durations, type checks, functions, and short-circuit error semantics. Storage additionally documents <code>math</code> helpers, string <code>matches</code>/<code>split</code>, list membership/<code>join</code>/<code>hasAll</code>, map <code>keys</code>/<code>values</code>, and timestamp accessors (<a href="https://firebase.google.com/docs/reference/security/storage" target="_blank" rel="noopener noreferrer" class="external-link">Storage reference</a>). Firestore’s reference is richer and separately lists Bytes, LatLng, MapDiff, Set, hashing, and additional methods and namespaces (<a href="https://firebase.google.com/docs/reference/rules" target="_blank" rel="noopener noreferrer" class="external-link">Firestore Rules API overview</a>).</p>
|
|
167
|
+
<p>Do <strong>not</strong> treat the union of those references as a universal surface. In particular, Firestore’s MapDiff/Set and hashing/Bytes/LatLng APIs are only candidates for paired probes unless the Storage reference or production observations establish them. Even the documented overlap is not proof that Pyric’s two evaluators implement every item. The current Storage evaluator implements the production-pinned subset needed by the shipped modules: string <code>matches</code>/<code>split</code>, collection <code>size</code>, map <code>keys</code>/<code>get</code>, list <code>hasAll</code>, <code>timestamp.date/value</code>, <code>duration.value</code>, and injected <code>firestore.get/exists</code>; unknown methods deny. Pyric’s Storage rules-language inventory labels it a “standalone subset” and records the injected-lookup qualification (<a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/conformance/rules-language/storage.json#L1-L190" target="_blank" rel="noopener noreferrer" class="external-link">inventory</a>).</p>
|
|
168
|
+
<h3 id="ambient-bindings-are-service-specific">Ambient bindings are service-specific</h3>
|
|
169
|
+
<p>Both services expose names such as <code>request</code>, <code>resource</code>, and <code>request.auth</code>, but the values behind those names differ materially:</p>
|
|
170
|
+
<div class="table-scroll">
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
<table><thead><tr><th>Surface</th><th>Firestore</th><th>Storage</th></tr></thead><tbody><tr><td>existing resource</td><td>document resource with <code>.data</code></td><td>object metadata (<code>name</code>, <code>bucket</code>, <code>size</code>, times, hashes, content fields, custom <code>metadata</code>)</td></tr><tr><td>incoming resource</td><td>document with <code>.data</code></td><td>proposed object metadata with the documented subset of object fields</td></tr><tr><td>path root</td><td><code>/databases/{database}/documents</code></td><td><code>/b/{bucket}/o</code></td></tr><tr><td>document access</td><td>bare <code>get</code>, <code>exists</code>, <code>getAfter</code></td><td>qualified <code>firestore.get</code>, <code>firestore.exists</code></td></tr><tr><td>query/batch semantics</td><td>Firestore query proof and atomic post-write access</td><td>object get/list/upload/metadata/delete semantics</td></tr></tbody></table></div>
|
|
206
|
+
<p>The Storage object-field contract is documented in the Storage reference (<a href="https://firebase.google.com/docs/reference/security/storage#request" target="_blank" rel="noopener noreferrer" class="external-link">request</a>, <a href="https://firebase.google.com/docs/reference/security/storage#resource" target="_blank" rel="noopener noreferrer" class="external-link">resource</a>); Firestore’s unqualified document functions are available only inside <code>service cloud.firestore</code> (<a href="https://firebase.google.com/docs/reference/rules/rules.firestore" target="_blank" rel="noopener noreferrer" class="external-link">Firestore namespace</a>). A helper that closes over <code>request.resource.data</code> is therefore Firestore-specific even if its arithmetic and map operations are universal.</p>
|
|
207
|
+
<h2 id="current-standard-library-cross-reference">Current standard-library cross-reference</h2>
|
|
208
|
+
<p>Before this branch, the manifest intentionally called itself the <strong>Firestore Rules Standard Library</strong> (<a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/pyric/src/rules/modules/stdlib/STDLIB.md" target="_blank" rel="noopener noreferrer" class="external-link">historical manifest</a>). The current <a href="../rules-standard-library/">stdlib reference</a> is service-aware: it separates common, Firestore-only, and Storage-only modules. The useful design lesson retained from the earlier catalog is the progression from small reusable primitives to advanced functions discovered and production-verified through probes, especially <code>timing</code>, <code>geometry</code>, <code>spaces</code>, <code>joining</code>, and <code>atomic</code>.</p>
|
|
209
|
+
<h3 id="existing-exports-by-portability">Existing exports by portability</h3>
|
|
210
|
+
<div class="table-scroll">
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
<table><thead><tr><th>Existing module/functions</th><th>Classification for Storage</th><th>Reason</th></tr></thead><tbody><tr><td><code>auth</code>: <code>isAuthenticated</code>, <code>isOwner(userId)</code></td><td>shipped common module; production-probed</td><td>Uses only <code>request.auth</code>; the exact bodies agree across the captured Firestore and Storage cases.</td></tr><tr><td><code>membership</code>: <code>hasClaim</code>, <code>hasClaimRole</code>, <code>isMemberOf(map)</code>, <code>hasRole(map, role)</code></td><td>shipped common module; production-probed</td><td>Uses auth plus explicit map parameters, not <code>.data</code>; the exact bodies agree across the captured Firestore and Storage cases.</td></tr><tr><td><code>atomic</code>: <code>companionChangedBy</code>, <code>consumedFlag</code></td><td>source-pure common candidate, executable now; production probe required</td><td>Inputs are explicit maps and the bodies use only indexing, equality, and arithmetic. The module name and Firestore batch examples are misleading for Storage, so portable value-transition helpers may deserve a neutral home rather than promoting <code>atomic</code> unchanged.</td></tr><tr><td><code>validation</code>, <code>lifecycle</code>, <code>content</code>, <code>counters</code>, <code>transitions</code>, <code>timing</code></td><td>Firestore-specific as written</td><td>Close over <code>request.resource.data</code> and/or <code>resource.data</code>. Storage analogues need object/metadata semantics, not blind reuse.</td></tr><tr><td><code>spaces</code></td><td>mixed</td><td>Read-side membership helpers accept explicit data and can be generalized; <code>validMemberCreate</code> closes over Firestore <code>.data</code>.</td></tr><tr><td><code>geometry</code>, <code>joining</code>, <code>lobby</code>, <code>turns</code>, <code>state</code></td><td>Firestore-specific/domain-specific</td><td>Depend on Firestore document shapes, MapDiff support, or game conventions.</td></tr></tbody></table></div>
|
|
251
|
+
<p>The safe rule is: <strong>a shared name is not a shared type</strong>. Only helpers whose full transitive body uses capabilities in the proven service intersection are universal.</p>
|
|
252
|
+
<h2 id="cross-service-behavior-what-it-is-and-is-not">Cross-service behavior: what it is and is not</h2>
|
|
253
|
+
<p>Storage Rules may read Cloud Firestore documents through <code>firestore.get()</code> and <code>firestore.exists()</code> with fully specified paths. Firebase caps a Storage evaluation at two Firestore document accesses, may cache repeated accesses, charges the reads, and limits access to the default Firestore database in multi-database projects (<a href="https://firebase.google.com/docs/storage/security/rules-conditions#enhance_with_cloud_firestore" target="_blank" rel="noopener noreferrer" class="external-link">Storage conditions</a>, <a href="https://firebase.google.com/docs/rules/rules-behavior#security_rule_limits" target="_blank" rel="noopener noreferrer" class="external-link">Rules limits</a>). Enabling this feature grants the Firebase Storage service account the <code>Firebase Rules Firestore Service Agent</code> IAM role; removing it makes such Storage evaluations fail (<a href="https://firebase.google.com/docs/rules/manage-deploy#manage_permissions_for_cross-service_cloud_storage_security_rules" target="_blank" rel="noopener noreferrer" class="external-link">cross-service permissions</a>).</p>
|
|
254
|
+
<p>This is cross-service <strong>data access</strong>, not cross-service rules composition. Firebase still deploys the two rulesets separately. The IAM-backed design implies that a Storage lookup is not a simulated client request authorized by the matched clauses in <code>firestore.rules</code>; the Storage condition itself decides how the returned document affects object access. The production rules-independence probe now pins that behavior: the same Storage lookup result held while the Firestore ruleset changed between deny-all and allow-all, with IAM and the document fixed.</p>
|
|
255
|
+
<p>Pyric already models the sanctioned direction: its Storage evaluator accepts an injected <code>FirestoreLookup</code>; sandbox enforcement supplies the project Firestore view, while pure evaluation without the capability denies (<a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/pyric/src/storage/rules.ts#L197-L221" target="_blank" rel="noopener noreferrer" class="external-link">interface and contract</a>, <a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/pyric/src/storage/rules.ts#L1266-L1320" target="_blank" rel="noopener noreferrer" class="external-link">evaluation</a>). That does not justify importing Firestore helpers. A Firestore helper that calls bare <code>get()</code> or reads <code>resource.data</code> remains incompatible inside Storage; a Storage-specific helper may call qualified <code>firestore.get()</code>, or preferably accept the looked-up <code>.data</code> as an explicit parameter so lookup count and path stay visible at the call site.</p>
|
|
256
|
+
<h2 id="proposed-module-model">Proposed module model</h2>
|
|
257
|
+
<h3 id="1-resolve-against-a-target-capability-contract">1. Resolve against a target capability contract</h3>
|
|
258
|
+
<p>Derive the target from <code>ast.service.name</code> and validate every requested export plus all transitive private helpers before injection.</p>
|
|
259
|
+
<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">type</span><span style="color:#E5C07B"> RulesService</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'firestore'</span><span style="color:#ABB2BF"> | </span><span style="color:#98C379">'storage'</span><span style="color:#ABB2BF">;</span></span>
|
|
260
|
+
<span class="line"></span>
|
|
261
|
+
<span class="line"><span style="color:#C678DD">interface</span><span style="color:#E5C07B"> FunctionContract</span><span style="color:#ABB2BF"> {</span></span>
|
|
262
|
+
<span class="line"><span style="color:#E06C75"> services</span><span style="color:#ABB2BF">: </span><span style="color:#C678DD">readonly</span><span style="color:#E5C07B"> RulesService</span><span style="color:#ABB2BF">[];</span></span>
|
|
263
|
+
<span class="line"><span style="color:#E06C75"> requires</span><span style="color:#ABB2BF">: </span><span style="color:#C678DD">readonly</span><span style="color:#E5C07B"> CapabilityId</span><span style="color:#ABB2BF">[];</span></span>
|
|
264
|
+
<span class="line"><span style="color:#E06C75"> evidence</span><span style="color:#ABB2BF">: </span><span style="color:#C678DD">readonly</span><span style="color:#E5C07B"> ConformanceNodeId</span><span style="color:#ABB2BF">[];</span></span>
|
|
265
|
+
<span class="line"><span style="color:#ABB2BF">}</span></span>
|
|
266
|
+
<span class="line"></span>
|
|
267
|
+
<span class="line"><span style="color:#C678DD">interface</span><span style="color:#E5C07B"> ModuleContract</span><span style="color:#ABB2BF"> {</span></span>
|
|
268
|
+
<span class="line"><span style="color:#E06C75"> key</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">string</span><span style="color:#ABB2BF">;</span></span>
|
|
269
|
+
<span class="line"><span style="color:#E06C75"> exports</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">Readonly</span><span style="color:#ABB2BF"><</span><span style="color:#E5C07B">Record</span><span style="color:#ABB2BF"><</span><span style="color:#E5C07B">string</span><span style="color:#ABB2BF">, </span><span style="color:#E5C07B">FunctionContract</span><span style="color:#ABB2BF">>>;</span></span>
|
|
270
|
+
<span class="line"><span style="color:#ABB2BF">}</span></span></code></pre>
|
|
271
|
+
<p>Capabilities should be semantic, not string heuristics: <code>binding.request.auth</code>, <code>binding.firestore.resource.data</code>, <code>binding.storage.request.resource.size</code>, <code>method.map.diff</code>, <code>namespace.storage.firestore.get</code>, and so on. Shipped modules carry reviewed contracts. Relative and caller-supplied modules must be statically analyzed over their complete transitive call graph; unknown/dynamic requirements fail closed until classified.</p>
|
|
272
|
+
<p>On mismatch, return <code>INCOMPATIBLE_FUNCTION</code> (or <code>INCOMPATIBLE_MODULE</code> when every requested export is incompatible) naming the target service and first missing capability. Do this before emitting plain v2. Keep the current duplicate/private/export checks.</p>
|
|
273
|
+
<h3 id="2-preserve-a-small-import-taxonomy">2. Preserve a small import taxonomy</h3>
|
|
274
|
+
<p>Avoid making users learn a matrix of package names:</p>
|
|
275
|
+
<ul>
|
|
276
|
+
<li><code>auth</code> and <code>membership</code> remain common, backward-compatible keys once Storage probes pass.</li>
|
|
277
|
+
<li>Firestore-only existing keys remain as-is for compatibility but their contracts reject Storage targets.</li>
|
|
278
|
+
<li>New service-specific modules use an explicit <code>storage/</code> prefix (<code>storage/uploads</code>, <code>storage/metadata</code>, <code>storage/objects</code>, <code>storage/firestore-access</code>).</li>
|
|
279
|
+
<li>Documentation may group modules as <strong>common</strong> and <strong>advanced</strong>, but compatibility is enforced per export because one mixed module can contain both portable and service-bound functions.</li>
|
|
280
|
+
</ul>
|
|
281
|
+
<h3 id="3-keep-lookup-wiring-explicit">3. Keep lookup wiring explicit</h3>
|
|
282
|
+
<p>Advanced cross-service helpers should prefer this shape:</p>
|
|
283
|
+
<pre class="astro-code one-dark-pro" style="background-color:#282c34;color:#abb2bf; overflow-x: auto;" tabindex="0" data-language="rules"><code><span class="line"><span style="color:#C678DD">function</span><span style="color:#ABB2BF"> membershipDoc(uid) {</span></span>
|
|
284
|
+
<span class="line"><span style="color:#C678DD"> return</span><span style="color:#ABB2BF"> firestore.</span><span style="color:#56B6C2">get</span><span style="color:#ABB2BF">(</span></span>
|
|
285
|
+
<span class="line"><span style="color:#ABB2BF"> /databases/(default)/documents/memberships/$(uid)</span></span>
|
|
286
|
+
<span class="line"><span style="color:#ABB2BF"> ).data;</span></span>
|
|
287
|
+
<span class="line"><span style="color:#ABB2BF">}</span></span>
|
|
288
|
+
<span class="line"></span>
|
|
289
|
+
<span class="line"><span style="color:#C678DD">allow</span><span style="color:#61AFEF"> read</span><span style="color:#ABB2BF">: </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> hasRole(membershipDoc(</span><span style="color:#E5C07B">request</span><span style="color:#ABB2BF">.auth.uid), </span><span style="color:#98C379">'editor'</span><span style="color:#ABB2BF">);</span></span></code></pre>
|
|
290
|
+
<p><code>hasRole(data, role)</code> is common policy; <code>firestore.get(...)</code> remains visibly Storage-specific, billable, limited, and path-bound. A convenience helper that hides the lookup should live under <code>storage/firestore-access</code>, declare the lookup capability and budget cost, and only ship after limit/caching probes.</p>
|
|
291
|
+
<h2 id="shipped-and-candidate-storage-modules">Shipped and candidate Storage modules</h2>
|
|
292
|
+
<p>The four Storage-native rows below are now shipped as Storage-only modules;
|
|
293
|
+
advanced-layer rows remain production-probed candidates. The only modules
|
|
294
|
+
admitted for both Firestore and Storage are <code>auth</code> and <code>membership</code>. A
|
|
295
|
+
candidate becomes shipped only after its function bodies
|
|
296
|
+
are implemented locally, replayed against the applicable observations, listed
|
|
297
|
+
in the service contract, and covered by executable stdlib fixtures.</p>
|
|
298
|
+
<h3 id="shipped-common-modules-and-remaining-candidate">Shipped common modules and remaining candidate</h3>
|
|
299
|
+
<div class="table-scroll">
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
<table><thead><tr><th>Module</th><th>Status and exports</th><th>Why</th></tr></thead><tbody><tr><td><code>auth</code></td><td>shipped: <code>isAuthenticated</code>, <code>isOwner(userId)</code></td><td>Same documented auth binding; exact bodies are production-probed on both services.</td></tr><tr><td><code>membership</code></td><td>shipped: existing claim and explicit-map helpers</td><td>Reuses explicit parameters, avoids ambient <code>.data</code>, and is production-probed on both services.</td></tr><tr><td><code>values</code> (possible extraction)</td><td>candidate: <code>validString(value,min,max)</code>, <code>isOneOf(value,values)</code>, <code>boundedNumber(value,min,max)</code></td><td>Value-oriented variants could be portable and avoid separate field conventions, but should ship only if probes show they reduce rather than duplicate the public concept set.</td></tr></tbody></table></div>
|
|
325
|
+
<h3 id="shipped-storage-layer">Shipped Storage layer</h3>
|
|
326
|
+
<div class="table-scroll">
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
<table><thead><tr><th>Module</th><th>Shipped exports</th><th>Production proof</th></tr></thead><tbody><tr><td><code>storage/uploads</code></td><td><code>sizeAtMost(bytes)</code>, <code>sizeBetween(min,max)</code>, <code>contentTypeMatches(re)</code>, <code>contentTypeIsOneOf(types)</code></td><td>Exact bodies and boundary cases in <code>rules-storage-stdlib-storage-modules</code>.</td></tr><tr><td><code>storage/metadata</code></td><td><code>hasRequiredMetadata(keys)</code>, <code>metadataString(key,min,max)</code>, <code>incomingMetadataOwner(key)</code>, <code>existingMetadataOwner(key)</code></td><td>Exact bodies, required-key failure, one in-range string execution, and incoming/existing owner cases in <code>rules-storage-stdlib-storage-modules</code>.</td></tr><tr><td><code>storage/objects</code></td><td><code>isCreate()</code>, <code>isUpdate()</code>, <code>isDelete()</code></td><td>Exact bodies on all three verbs in <code>rules-storage-stdlib-storage-modules</code>.</td></tr><tr><td><code>storage/time</code></td><td><code>createdWithin(seconds)</code>, <code>updatedWithin(seconds)</code></td><td>Exact bodies immediately before and at strict deadlines in <code>rules-storage-stdlib-storage-modules</code>.</td></tr></tbody></table></div>
|
|
357
|
+
<h3 id="storage-advanced-layer">Storage advanced layer</h3>
|
|
358
|
+
<div class="table-scroll">
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
<table><thead><tr><th>Module</th><th>Candidate exports</th><th>Why advanced</th></tr></thead><tbody><tr><td><code>storage/image-uploads</code></td><td><code>validImageUpload(maxBytes, allowedTypes)</code>, optional extension/content-type agreement</td><td>Composes path, size, and MIME claims; spoofed MIME/extension behavior must be explained rather than implied to inspect bytes.</td></tr><tr><td><code>storage/metadata-lifecycle</code></td><td><code>immutableMetadata(keys)</code>, <code>onlyMetadataChanged(keys)</code>, <code>ownerMetadataUnchanged(key)</code></td><td>Depends on whether <code>Map.diff</code> works on Storage custom metadata and how absent/server fields behave.</td></tr><tr><td><code>storage/firestore-access</code></td><td>membership/role policy over explicit lookup results; perhaps a narrowly named lookup wrapper</td><td>Cross-service IAM, two-read budget, caching, default-database restriction, and missing/type errors.</td></tr><tr><td><code>storage/integrity</code></td><td>hash/generation/metageneration guards</td><td><code>md5Hash</code>, <code>crc32c</code>, <code>etag</code>, generation fields are server-shaped and collision caveats matter; production request visibility must be established.</td></tr><tr><td><code>storage/path-policy</code></td><td>filename/extension/segment constraints</td><td>Storage has flat object names despite slash-like prefixes; wildcard type and <code>request.path</code> behavior need probes.</td></tr></tbody></table></div>
|
|
394
|
+
<p>Do not call MIME or hash helpers “content validation” unless the rule actually observes trusted content bytes. Firebase’s own examples validate metadata such as <code>contentType</code> and size (<a href="https://firebase.google.com/docs/storage/security/rules-conditions#validate_data" target="_blank" rel="noopener noreferrer" class="external-link">Storage data validation</a>); module names and docs should preserve that distinction.</p>
|
|
395
|
+
<h2 id="probe-program">Probe program</h2>
|
|
396
|
+
<p>The existing Storage oracle runner is the right base: it sends an inline Storage source and cases to the production <code>projects.test</code> endpoint, records verdicts, then replays them against Pyric (<a href="https://github.com/davideast/pyric/blob/6e5ecd6e3718/packages/conformance/src/run-rules-storage.ts#L1-L20" target="_blank" rel="noopener noreferrer" class="external-link">runner</a>). The official endpoint validates syntax and semantics before cases run, supports service-dependent request/resource values and service-function mocks, and can return visited expressions and function calls (<a href="https://firebase.google.com/docs/reference/rules/rest/v1/projects/test" target="_blank" rel="noopener noreferrer" class="external-link">Rules <code>projects.test</code></a>).</p>
|
|
397
|
+
<p>Each candidate should have three gates:</p>
|
|
398
|
+
<ol>
|
|
399
|
+
<li><strong>compiler isolation:</strong> resolver accepts the right service and rejects the wrong one, including transitive private dependencies and caller-supplied modules;</li>
|
|
400
|
+
<li><strong>oracle semantics:</strong> production <code>projects.test</code> verdict matrix with boundary and error cases;</li>
|
|
401
|
+
<li><strong>mirror replay:</strong> exact verdicts locally, with any unavailable real-resource behavior moved to a credentialed emulator/production probe rather than guessed.</li>
|
|
402
|
+
</ol>
|
|
403
|
+
<h3 id="p0--trust-boundary-and-module-wiring">P0 — trust boundary and module wiring</h3>
|
|
404
|
+
<div class="table-scroll">
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
<table><thead><tr><th>Probe</th><th>Matrix</th><th>Expected learning</th></tr></thead><tbody><tr><td>Import syntax/version acceptance</td><td>Firestore + Storage; v2 + <code>2+modules</code>; ordinary project + preview-entitled project if available</td><td>Separates public v2, server-gated preview syntax, and service entitlement. Record exact compile issue rather than only ALLOW/DENY.</td></tr><tr><td>Multi-file Rules API source</td><td>one file vs entry file + named helper file; with/without import; file-order permutations</td><td>Establishes whether <code>Source.files[]</code> is merely a bundle or a linker input, and how symbols resolve.</td></tr><tr><td>Firebase CLI deployment</td><td>equivalent <code>firebase.json</code> Firestore and Storage targets; inspect API request or retrieved ruleset</td><td>Establishes whether the CLI sends one file, a bundle, or preprocesses imports, separately from direct REST behavior.</td></tr><tr><td>Pyric compile then production test</td><td>module source, emitted plain-v2 source, both sent to <code>projects.test</code></td><td>Confirms Pyric’s portable contract is the emitted v2 artifact even when preview syntax is unavailable upstream.</td></tr><tr><td>Storage imports <code>auth.isAuthenticated</code></td><td>anon/authenticated; direct parse vs resolve-then-parse</td><td>Pins the current split and the intended end-to-end path.</td></tr><tr><td>Storage imports Firestore <code>lifecycle.immutableFields</code></td><td>compile only</td><td>Must fail <code>INCOMPATIBLE_FUNCTION</code>, not emit source that later denies.</td></tr><tr><td>Firestore imports <code>storage/uploads.sizeAtMost</code></td><td>compile only</td><td>Proves isolation is symmetric.</td></tr><tr><td>Mixed module exports one common and one service-specific function</td><td>import each alone, then both</td><td>Proves compatibility is export-level.</td></tr><tr><td>Private helper introduces incompatible binding</td><td>exported wrapper looks common but calls private <code>.data</code> helper</td><td>Proves transitive checks cannot be bypassed.</td></tr><tr><td>Relative/user module uses unknown method</td><td>Storage and Firestore targets</td><td>Unknown capability fails closed rather than trusting unreviewed code.</td></tr><tr><td>Same source through Node and browser resolver</td><td>built-in key, path alias, caller override</td><td>Pins catalog parity and prevents browser-only trust drift.</td></tr></tbody></table></div>
|
|
470
|
+
<h3 id="p1--universal-intersection">P1 — universal intersection</h3>
|
|
471
|
+
<p>Run identical ordinary-v2 function bodies under both service declarations where the request fixture permits it:</p>
|
|
472
|
+
<ul>
|
|
473
|
+
<li>auth null/UID/token claim access, including missing claims;</li>
|
|
474
|
+
<li>explicit map membership and bracket access, including absent keys and prototype-like strings;</li>
|
|
475
|
+
<li><code>Map.keys/get/diff</code>, List/Set conversion and membership;</li>
|
|
476
|
+
<li>string <code>size/matches/split/replace/trim/lower/upper/toUtf8</code> with empty, Unicode, and invalid RE2 cases;</li>
|
|
477
|
+
<li><code>duration</code>, <code>timestamp</code>, <code>math</code>, <code>hashing</code>, and <code>latlng</code> namespaces with type errors and numeric boundaries;</li>
|
|
478
|
+
<li>function lexical scope, let limits, recursion/call-depth failure, and short-circuit error absorption.</li>
|
|
479
|
+
</ul>
|
|
480
|
+
<p>The result should be a capability intersection backed by paired observations, not a hand-maintained “universal functions” list copied from the reference.</p>
|
|
481
|
+
<h3 id="p2--storage-upload-and-metadata-primitives">P2 — Storage upload and metadata primitives</h3>
|
|
482
|
+
<div class="table-scroll">
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
<table><thead><tr><th>Probe family</th><th>Cases that matter</th></tr></thead><tbody><tr><td>request/resource presence</td><td>create absent existing resource; update existing; delete missing <code>request.resource</code>; get/list behavior; negation of missing-field errors.</td></tr><tr><td>size</td><td>0, 1, exact maximum, maximum+1, large int arithmetic, updateMetadata where bytes do not change.</td></tr><tr><td>MIME</td><td>absent, exact type, parameterized type, case differences, whole-string regex anchoring, extension agrees/disagrees.</td></tr><tr><td>metadata shape</td><td>empty map, required/extra keys, missing key direct access vs <code>in</code> vs <code>get(default)</code>, Unicode strings, max practical key/value sizes.</td></tr><tr><td>metadata diff</td><td>added/removed/changed/unchanged keys; no-op update; compare only custom metadata versus whole request/resource maps.</td></tr><tr><td>object identity</td><td>full <code>resource.name</code>, bucket, path wildcard type, generation/metageneration increments, create/update/delete visibility.</td></tr><tr><td>time</td><td>exact cooldown boundary, just before/after, <code>timeCreated</code> vs <code>updated</code>, future values, missing resource, timestamp accessors.</td></tr><tr><td>hashes</td><td>visibility of md5/crc32c/etag on existing and incoming objects; overwrite equality; malformed/client-supplied values; document collision caveat.</td></tr></tbody></table></div>
|
|
524
|
+
<p>This is the Storage analogue of how Firestore timing emerged: probe the native server-owned values and error edges first, then wrap only the stable relationship.</p>
|
|
525
|
+
<h3 id="p3--advanced-cross-service-lookups">P3 — advanced cross-service lookups</h3>
|
|
526
|
+
<p>Use function mocks for fast Rules Test API shape discovery, then a real Firestore database + Storage request rig for IAM and consistency claims.</p>
|
|
527
|
+
<ol>
|
|
528
|
+
<li><strong>Path contract:</strong> fully qualified default path; named database; malformed prefix; odd collection/document segments; wildcard and auth interpolation; null/non-string interpolation.</li>
|
|
529
|
+
<li><strong>Return/error contract:</strong> existing document, missing <code>get</code>, missing <code>exists</code>, field absent, wrong field type, nested maps/lists, document reference/timestamp values.</li>
|
|
530
|
+
<li><strong>Budget:</strong> zero, one, two, and three distinct documents; repeat the same lookup; <code>get</code> then <code>exists</code> on the same path; short-circuited third lookup. Record function calls as well as allow/deny.</li>
|
|
531
|
+
<li><strong>Caching:</strong> repeated identical paths versus textually different paths resolving to the same document. Determine what actually counts toward two accesses.</li>
|
|
532
|
+
<li><strong>Evaluation order:</strong> <code>true || lookup</code>, <code>false && lookup</code>, <code>false || lookup</code>, ternary branches, helper-called lookup, lookup in <code>let</code> binding.</li>
|
|
533
|
+
<li><strong>Database boundary:</strong> <code>(default)</code> allowed; named database denied when multiple databases exist.</li>
|
|
534
|
+
<li><strong>IAM:</strong> role enabled/removed/restored; verify failures deny and surface no false allow.</li>
|
|
535
|
+
<li><strong>Rules independence:</strong> deploy Firestore deny-all versus allow-all while the IAM role and document stay fixed; execute the same Storage request. This pins the inference that Storage lookup is not authorized by the Firestore ruleset.</li>
|
|
536
|
+
<li><strong>Consistency:</strong> mutate a membership document immediately before a Storage request and observe old/new value; repeat to characterize, not promise, visibility.</li>
|
|
537
|
+
<li><strong>Pyric project isolation:</strong> two sandbox project IDs with identical paths and different documents; Storage must read only its owning project’s Firestore view.</li>
|
|
538
|
+
</ol>
|
|
539
|
+
<p>High-value module candidates emerge from these outcomes. For example, if repeated identical lookup calls are cached and explicit-map policy composes cleanly, keep only common <code>hasRole(data, role)</code> and teach a visible one-lookup caller pattern. If lookup wrappers obscure budget or caching, do not ship them.</p>
|
|
540
|
+
<h2 id="recommended-delivery-order">Recommended delivery order</h2>
|
|
541
|
+
<ol>
|
|
542
|
+
<li>Add compiler-level tests that pin today’s direct-parse denial and generic-resolver acceptance as separate facts.</li>
|
|
543
|
+
<li>Correct the Storage syntax test’s blanket production claim and probe version/import acceptance, multi-file REST linking, preview entitlement, and CLI preprocessing as distinct facts.</li>
|
|
544
|
+
<li>Introduce the service/capability contracts and fail-closed resolver errors, covering transitive and caller-supplied modules.</li>
|
|
545
|
+
<li>Run P1 paired probes; promote only <code>auth</code>/<code>membership</code> exports that pass into the common intersection.</li>
|
|
546
|
+
<li>Wire Storage service setup through the checked resolver. The resolved plain-v2 source, target service, modules, and evidence IDs should be inspectable for assurance.</li>
|
|
547
|
+
<li>Run P2; add the smallest Storage common modules whose functions are production-proven and broadly reusable.</li>
|
|
548
|
+
<li>Run P3 before adding advanced cross-service helpers. Record lookup-budget and IAM limitations in both module documentation and conformance nodes.</li>
|
|
549
|
+
<li>Keep every unsupported or unverified function queryable as such. A compiler rejection with a precise missing capability is more trustworthy than a module that resolves and silently denies at runtime.</li>
|
|
550
|
+
</ol>
|
|
551
|
+
<p>Item 2’s read-only Rules Test API work is complete for version/import
|
|
552
|
+
acceptance and multi-file/file-order behavior. Firebase CLI preprocessing is an
|
|
553
|
+
explicitly open probe: it requires a deployment/request-capture or retrieved
|
|
554
|
+
ruleset inspection, was not part of the read-only <code>projects.test</code> rig, and no
|
|
555
|
+
claim in this delivery depends on how the CLI preprocesses source files.</p>
|
|
556
|
+
<p>The delivered assurance seam for item 5 is <code>getStorageRulesResolution()</code> from
|
|
557
|
+
<code>pyric/storage/internal</code>. It returns an immutable descriptor containing the
|
|
558
|
+
target service, exact emitted plain-v2 source, resolved modules, and the
|
|
559
|
+
applicable Storage Rules evidence row IDs. Normal public Storage handles remain
|
|
560
|
+
opaque and rules-honest; assurance tooling opts into the internal inspection
|
|
561
|
+
subpath.</p>
|
|
562
|
+
<h2 id="answer-to-the-trust-question">Answer to the trust question</h2>
|
|
563
|
+
<p>On this branch, <code>2+modules</code> is trustworthy as a service-scoped authoring
|
|
564
|
+
contract. Normal Storage setup resolves admitted modules to portable v2;
|
|
565
|
+
<code>auth</code> and <code>membership</code> are production-proven under both services; Firestore-
|
|
566
|
+
only exports and incompatible transitive helpers fail before evaluation. This
|
|
567
|
+
is deliberately narrower than claiming the entire Firestore stdlib works in
|
|
568
|
+
Storage.</p>
|
|
569
|
+
<p>The real-resource P2/P3 captures expand the evidence available for future
|
|
570
|
+
Storage-specific modules, but they remain discovery evidence until local replay
|
|
571
|
+
and registry rows promote the exact behavior. In particular, a production
|
|
572
|
+
observation is not itself a shipped helper.</p>
|
|
573
|
+
<p>The smallest honest contract is:</p>
|
|
574
|
+
<ul>
|
|
575
|
+
<li>modules compile for an explicit service target;</li>
|
|
576
|
+
<li>every imported function and private dependency declares or derives its required capabilities;</li>
|
|
577
|
+
<li><code>common</code> means proven in both Firestore and Storage, not merely syntactically generic;</li>
|
|
578
|
+
<li>service-specific ambient bindings never cross the boundary;</li>
|
|
579
|
+
<li>Storage-to-Firestore access is modeled as a qualified, limited runtime capability, not permission to reuse Firestore-bound helpers;</li>
|
|
580
|
+
<li>production probes are attached to the exact export/capability claims that assurance relies on.</li>
|
|
581
|
+
</ul>
|
|
582
|
+
<p>That makes multi-module Storage support a visible, testable extension of the conformance graph instead of a flat catalog silently shared by two different evaluators.</p> </article> </main> <aside class="doc-toc" aria-label="On this page" data-astro-cid-mw7aashj> <h2 class="doc-toc-heading" data-astro-cid-mw7aashj>On this page</h2> <ul data-astro-cid-mw7aashj> <li data-depth="2" data-astro-cid-mw7aashj> <a href="#implementation-status-on-this-branch" data-astro-cid-mw7aashj>Implementation status on this branch</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#follow-up-discovery-captures-2026-07-21" data-astro-cid-mw7aashj>Follow-up discovery captures (2026-07-21)</a> </li><li data-depth="2" data-astro-cid-mw7aashj> <a href="#historical-baseline-at-the-investigation-fixed-point" data-astro-cid-mw7aashj>Historical baseline at the investigation fixed point</a> </li><li data-depth="2" data-astro-cid-mw7aashj> <a href="#what-firebase-itself-guarantees" data-astro-cid-mw7aashj>What Firebase itself guarantees</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#one-language-family-separate-service-scopes" data-astro-cid-mw7aashj>One language family, separate service scopes</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#resolved-trust-contradiction" data-astro-cid-mw7aashj>Resolved trust contradiction</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#the-documented-shared-language-surface" data-astro-cid-mw7aashj>The documented shared language surface</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#ambient-bindings-are-service-specific" data-astro-cid-mw7aashj>Ambient bindings are service-specific</a> </li><li data-depth="2" data-astro-cid-mw7aashj> <a href="#current-standard-library-cross-reference" data-astro-cid-mw7aashj>Current standard-library cross-reference</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#existing-exports-by-portability" data-astro-cid-mw7aashj>Existing exports by portability</a> </li><li data-depth="2" data-astro-cid-mw7aashj> <a href="#cross-service-behavior-what-it-is-and-is-not" data-astro-cid-mw7aashj>Cross-service behavior: what it is and is not</a> </li><li data-depth="2" data-astro-cid-mw7aashj> <a href="#proposed-module-model" data-astro-cid-mw7aashj>Proposed module model</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#1-resolve-against-a-target-capability-contract" data-astro-cid-mw7aashj>1. Resolve against a target capability contract</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#2-preserve-a-small-import-taxonomy" data-astro-cid-mw7aashj>2. Preserve a small import taxonomy</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#3-keep-lookup-wiring-explicit" data-astro-cid-mw7aashj>3. Keep lookup wiring explicit</a> </li><li data-depth="2" data-astro-cid-mw7aashj> <a href="#shipped-and-candidate-storage-modules" data-astro-cid-mw7aashj>Shipped and candidate Storage modules</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#shipped-common-modules-and-remaining-candidate" data-astro-cid-mw7aashj>Shipped common modules and remaining candidate</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#shipped-storage-layer" data-astro-cid-mw7aashj>Shipped Storage layer</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#storage-advanced-layer" data-astro-cid-mw7aashj>Storage advanced layer</a> </li><li data-depth="2" data-astro-cid-mw7aashj> <a href="#probe-program" data-astro-cid-mw7aashj>Probe program</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#p0--trust-boundary-and-module-wiring" data-astro-cid-mw7aashj>P0 — trust boundary and module wiring</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#p1--universal-intersection" data-astro-cid-mw7aashj>P1 — universal intersection</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#p2--storage-upload-and-metadata-primitives" data-astro-cid-mw7aashj>P2 — Storage upload and metadata primitives</a> </li><li data-depth="3" data-astro-cid-mw7aashj> <a href="#p3--advanced-cross-service-lookups" data-astro-cid-mw7aashj>P3 — advanced cross-service lookups</a> </li><li data-depth="2" data-astro-cid-mw7aashj> <a href="#recommended-delivery-order" data-astro-cid-mw7aashj>Recommended delivery order</a> </li><li data-depth="2" data-astro-cid-mw7aashj> <a href="#answer-to-the-trust-question" data-astro-cid-mw7aashj>Answer to the trust question</a> </li> </ul> </aside> </div> <script type="module">const a=document.querySelector("[data-api-symbol-filter]"),d=[...document.querySelectorAll("[data-api-symbol-group]")],n=document.querySelector("[data-api-symbol-empty]");a?.addEventListener("input",()=>{const t=a.value.trim().toLowerCase();let o=0;for(const i of d){let e=0;i.querySelectorAll("[data-api-symbol]").forEach(l=>{const r=!t||(l.dataset.apiSymbol??"").includes(t);l.hidden=!r,r&&e++}),i.hidden=e===0,o+=e}n&&(n.hidden=o>0)});</script> <script type="module">const s=new Map;document.querySelectorAll('.doc-toc a[href^="#"]').forEach(t=>s.set(decodeURIComponent(t.hash.slice(1)),t));if(s.size>0){const t=new Set,n=()=>{let o=null;for(const e of s.keys())if(t.has(e)){o=e;break}s.forEach((e,c)=>e.classList.toggle("active",c===o))},r=new IntersectionObserver(o=>{for(const e of o)e.isIntersecting?t.add(e.target.id):t.delete(e.target.id);n()},{rootMargin:"-72px 0px -60% 0px"});s.forEach((o,e)=>{const c=document.getElementById(e);c&&r.observe(c)})}</script> <script type="module">document.querySelector('.studio__nav [aria-current="page"]')?.scrollIntoView({block:"nearest",inline:"center"});</script> </body></html>
|