@pyric/cli 0.1.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +216 -0
- package/README.md +156 -0
- package/README.md.orig +138 -0
- package/dist/assurance/attachment.d.ts +24 -0
- package/dist/assurance/attachment.d.ts.map +1 -0
- package/dist/assurance/attachment.js +138 -0
- package/dist/assurance/attachment.js.map +1 -0
- package/dist/assurance/browser.d.ts +7 -0
- package/dist/assurance/browser.d.ts.map +1 -0
- package/dist/assurance/browser.js +68 -0
- package/dist/assurance/browser.js.map +1 -0
- package/dist/assurance/campaign.d.ts +41 -0
- package/dist/assurance/campaign.d.ts.map +1 -0
- package/dist/assurance/campaign.js +364 -0
- package/dist/assurance/campaign.js.map +1 -0
- package/dist/assurance/capabilities.d.ts +7 -0
- package/dist/assurance/capabilities.d.ts.map +1 -0
- package/dist/assurance/capabilities.js +295 -0
- package/dist/assurance/capabilities.js.map +1 -0
- package/dist/assurance/cases.d.ts +14 -0
- package/dist/assurance/cases.d.ts.map +1 -0
- package/dist/assurance/cases.js +27 -0
- package/dist/assurance/cases.js.map +1 -0
- package/dist/assurance/generated-capabilities.d.ts +52 -0
- package/dist/assurance/generated-capabilities.d.ts.map +1 -0
- package/dist/assurance/generated-capabilities.js +329 -0
- package/dist/assurance/generated-capabilities.js.map +1 -0
- package/dist/assurance/index.d.ts +11 -0
- package/dist/assurance/index.d.ts.map +1 -0
- package/dist/assurance/index.js +9 -0
- package/dist/assurance/index.js.map +1 -0
- package/dist/assurance/runner.d.ts +3 -0
- package/dist/assurance/runner.d.ts.map +1 -0
- package/dist/assurance/runner.js +633 -0
- package/dist/assurance/runner.js.map +1 -0
- package/dist/assurance/tool-names.d.ts +4 -0
- package/dist/assurance/tool-names.d.ts.map +1 -0
- package/dist/assurance/tool-names.js +14 -0
- package/dist/assurance/tool-names.js.map +1 -0
- package/dist/assurance/tools.d.ts +19 -0
- package/dist/assurance/tools.d.ts.map +1 -0
- package/dist/assurance/tools.js +740 -0
- package/dist/assurance/tools.js.map +1 -0
- package/dist/assurance/types.d.ts +348 -0
- package/dist/assurance/types.d.ts.map +1 -0
- package/dist/assurance/types.js +7 -0
- package/dist/assurance/types.js.map +1 -0
- package/dist/assurance/validation.d.ts +8 -0
- package/dist/assurance/validation.d.ts.map +1 -0
- package/dist/assurance/validation.js +269 -0
- package/dist/assurance/validation.js.map +1 -0
- package/dist/bridge/client/bridge.d.ts +133 -0
- package/dist/bridge/client/bridge.d.ts.map +1 -0
- package/dist/bridge/client/bridge.js +429 -0
- package/dist/bridge/client/bridge.js.map +1 -0
- package/dist/bridge/client/dispatch.d.ts +41 -0
- package/dist/bridge/client/dispatch.d.ts.map +1 -0
- package/dist/bridge/client/dispatch.js +111 -0
- package/dist/bridge/client/dispatch.js.map +1 -0
- package/dist/bridge/client.d.ts +24 -0
- package/dist/bridge/client.d.ts.map +1 -0
- package/dist/bridge/client.js +26 -0
- package/dist/bridge/client.js.map +1 -0
- package/dist/bridge/protocol.d.ts +227 -0
- package/dist/bridge/protocol.d.ts.map +1 -0
- package/dist/bridge/protocol.js +131 -0
- package/dist/bridge/protocol.js.map +1 -0
- package/dist/bridge/server/audit.d.ts +19 -0
- package/dist/bridge/server/audit.d.ts.map +1 -0
- package/dist/bridge/server/audit.js +46 -0
- package/dist/bridge/server/audit.js.map +1 -0
- package/dist/bridge/server/bridge.d.ts +126 -0
- package/dist/bridge/server/bridge.d.ts.map +1 -0
- package/dist/bridge/server/bridge.js +383 -0
- package/dist/bridge/server/bridge.js.map +1 -0
- package/dist/bridge/server/headless.d.ts +36 -0
- package/dist/bridge/server/headless.d.ts.map +1 -0
- package/dist/bridge/server/headless.js +142 -0
- package/dist/bridge/server/headless.js.map +1 -0
- package/dist/bridge/server/json-schema-to-zod.d.ts +37 -0
- package/dist/bridge/server/json-schema-to-zod.d.ts.map +1 -0
- package/dist/bridge/server/json-schema-to-zod.js +93 -0
- package/dist/bridge/server/json-schema-to-zod.js.map +1 -0
- package/dist/bridge/server/local-bridge.d.ts +33 -0
- package/dist/bridge/server/local-bridge.d.ts.map +1 -0
- package/dist/bridge/server/local-bridge.js +41 -0
- package/dist/bridge/server/local-bridge.js.map +1 -0
- package/dist/bridge/server/logger.d.ts +28 -0
- package/dist/bridge/server/logger.d.ts.map +1 -0
- package/dist/bridge/server/logger.js +42 -0
- package/dist/bridge/server/logger.js.map +1 -0
- package/dist/bridge/server/mcp-contract.d.ts +21 -0
- package/dist/bridge/server/mcp-contract.d.ts.map +1 -0
- package/dist/bridge/server/mcp-contract.js +62 -0
- package/dist/bridge/server/mcp-contract.js.map +1 -0
- package/dist/bridge/server/mcp.d.ts +26 -0
- package/dist/bridge/server/mcp.d.ts.map +1 -0
- package/dist/bridge/server/mcp.js +102 -0
- package/dist/bridge/server/mcp.js.map +1 -0
- package/dist/bridge/server/peer.d.ts +39 -0
- package/dist/bridge/server/peer.d.ts.map +1 -0
- package/dist/bridge/server/peer.js +189 -0
- package/dist/bridge/server/peer.js.map +1 -0
- package/dist/bridge/server/standalone.d.ts +49 -0
- package/dist/bridge/server/standalone.d.ts.map +1 -0
- package/dist/bridge/server/standalone.js +267 -0
- package/dist/bridge/server/standalone.js.map +1 -0
- package/dist/bridge/server/tool-metadata.d.ts +38 -0
- package/dist/bridge/server/tool-metadata.d.ts.map +1 -0
- package/dist/bridge/server/tool-metadata.js +81 -0
- package/dist/bridge/server/tool-metadata.js.map +1 -0
- package/dist/bridge/server.d.ts +21 -0
- package/dist/bridge/server.d.ts.map +1 -0
- package/dist/bridge/server.js +18 -0
- package/dist/bridge/server.js.map +1 -0
- package/dist/cli/database-rules.d.ts +43 -0
- package/dist/cli/database-rules.d.ts.map +1 -0
- package/dist/cli/database-rules.js +261 -0
- package/dist/cli/database-rules.js.map +1 -0
- package/dist/cli/dev-runner.d.ts +112 -0
- package/dist/cli/dev-runner.d.ts.map +1 -0
- package/dist/cli/dev-runner.js +239 -0
- package/dist/cli/dev-runner.js.map +1 -0
- package/dist/cli/firebase-json.d.ts +66 -0
- package/dist/cli/firebase-json.d.ts.map +1 -0
- package/dist/cli/firebase-json.js +60 -0
- package/dist/cli/firebase-json.js.map +1 -0
- package/dist/cli/firestore-indexes.d.ts +21 -0
- package/dist/cli/firestore-indexes.d.ts.map +1 -0
- package/dist/cli/firestore-indexes.js +39 -0
- package/dist/cli/firestore-indexes.js.map +1 -0
- package/dist/cli/index.d.ts +56 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +379 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +50 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +182 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/mcp-proxy.d.ts +10 -0
- package/dist/cli/mcp-proxy.d.ts.map +1 -0
- package/dist/cli/mcp-proxy.js +129 -0
- package/dist/cli/mcp-proxy.js.map +1 -0
- package/dist/cli/parse-args.d.ts +20 -0
- package/dist/cli/parse-args.d.ts.map +1 -0
- package/dist/cli/parse-args.js +69 -0
- package/dist/cli/parse-args.js.map +1 -0
- package/dist/cli/rules.d.ts +55 -0
- package/dist/cli/rules.d.ts.map +1 -0
- package/dist/cli/rules.js +199 -0
- package/dist/cli/rules.js.map +1 -0
- package/dist/cli/scope.d.ts +12 -0
- package/dist/cli/scope.d.ts.map +1 -0
- package/dist/cli/scope.js +44 -0
- package/dist/cli/scope.js.map +1 -0
- package/dist/cli/serve.d.ts +122 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +844 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/service-commands.d.ts +8 -0
- package/dist/cli/service-commands.d.ts.map +1 -0
- package/dist/cli/service-commands.js +58 -0
- package/dist/cli/service-commands.js.map +1 -0
- package/dist/cli/snapshot.d.ts +22 -0
- package/dist/cli/snapshot.d.ts.map +1 -0
- package/dist/cli/snapshot.js +139 -0
- package/dist/cli/snapshot.js.map +1 -0
- package/dist/cli/storage-rules.d.ts +21 -0
- package/dist/cli/storage-rules.d.ts.map +1 -0
- package/dist/cli/storage-rules.js +121 -0
- package/dist/cli/storage-rules.js.map +1 -0
- package/dist/cli/verify.d.ts +23 -0
- package/dist/cli/verify.d.ts.map +1 -0
- package/dist/cli/verify.js +349 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/credentials/core/memoize-ttl.d.ts +58 -0
- package/dist/credentials/core/memoize-ttl.d.ts.map +1 -0
- package/dist/credentials/core/memoize-ttl.js +88 -0
- package/dist/credentials/core/memoize-ttl.js.map +1 -0
- package/dist/credentials/core/types.d.ts +11 -0
- package/dist/credentials/core/types.d.ts.map +1 -0
- package/dist/credentials/core/types.js +2 -0
- package/dist/credentials/core/types.js.map +1 -0
- package/dist/credentials/node/from-adc.d.ts +10 -0
- package/dist/credentials/node/from-adc.d.ts.map +1 -0
- package/dist/credentials/node/from-adc.js +76 -0
- package/dist/credentials/node/from-adc.js.map +1 -0
- package/dist/credentials/node/from-service-account.d.ts +24 -0
- package/dist/credentials/node/from-service-account.d.ts.map +1 -0
- package/dist/credentials/node/from-service-account.js +108 -0
- package/dist/credentials/node/from-service-account.js.map +1 -0
- package/dist/credentials/node/index.d.ts +7 -0
- package/dist/credentials/node/index.d.ts.map +1 -0
- package/dist/credentials/node/index.js +7 -0
- package/dist/credentials/node/index.js.map +1 -0
- package/dist/discover/concurrency.d.ts +42 -0
- package/dist/discover/concurrency.d.ts.map +1 -0
- package/dist/discover/concurrency.js +113 -0
- package/dist/discover/concurrency.js.map +1 -0
- package/dist/discover/crawler-adapter.d.ts +48 -0
- package/dist/discover/crawler-adapter.d.ts.map +1 -0
- package/dist/discover/crawler-adapter.js +92 -0
- package/dist/discover/crawler-adapter.js.map +1 -0
- package/dist/discover/crawler.d.ts +294 -0
- package/dist/discover/crawler.d.ts.map +1 -0
- package/dist/discover/crawler.js +764 -0
- package/dist/discover/crawler.js.map +1 -0
- package/dist/discover/credential-free.d.ts +19 -0
- package/dist/discover/credential-free.d.ts.map +1 -0
- package/dist/discover/credential-free.js +18 -0
- package/dist/discover/credential-free.js.map +1 -0
- package/dist/discover/findCollectionGroup.d.ts +44 -0
- package/dist/discover/findCollectionGroup.d.ts.map +1 -0
- package/dist/discover/findCollectionGroup.js +81 -0
- package/dist/discover/findCollectionGroup.js.map +1 -0
- package/dist/discover/firestore-source.d.ts +60 -0
- package/dist/discover/firestore-source.d.ts.map +1 -0
- package/dist/discover/firestore-source.js +11 -0
- package/dist/discover/firestore-source.js.map +1 -0
- package/dist/discover/index.d.ts +3 -0
- package/dist/discover/index.d.ts.map +1 -0
- package/dist/discover/index.js +5 -0
- package/dist/discover/index.js.map +1 -0
- package/dist/discover/merge.d.ts +108 -0
- package/dist/discover/merge.d.ts.map +1 -0
- package/dist/discover/merge.js +394 -0
- package/dist/discover/merge.js.map +1 -0
- package/dist/discover/session.d.ts +116 -0
- package/dist/discover/session.d.ts.map +1 -0
- package/dist/discover/session.js +331 -0
- package/dist/discover/session.js.map +1 -0
- package/dist/discover/tools.d.ts +58 -0
- package/dist/discover/tools.d.ts.map +1 -0
- package/dist/discover/tools.js +115 -0
- package/dist/discover/tools.js.map +1 -0
- package/dist/discover/types.d.ts +190 -0
- package/dist/discover/types.d.ts.map +1 -0
- package/dist/discover/types.js +12 -0
- package/dist/discover/types.js.map +1 -0
- package/dist/discover/wire.d.ts +70 -0
- package/dist/discover/wire.d.ts.map +1 -0
- package/dist/discover/wire.js +309 -0
- package/dist/discover/wire.js.map +1 -0
- package/dist/functions-rtdb/child.d.ts +52 -0
- package/dist/functions-rtdb/child.d.ts.map +1 -0
- package/dist/functions-rtdb/child.js +283 -0
- package/dist/functions-rtdb/child.js.map +1 -0
- package/dist/functions-rtdb/delivery.d.ts +4 -0
- package/dist/functions-rtdb/delivery.d.ts.map +1 -0
- package/dist/functions-rtdb/delivery.js +2 -0
- package/dist/functions-rtdb/delivery.js.map +1 -0
- package/dist/functions-rtdb/discovery.d.ts +41 -0
- package/dist/functions-rtdb/discovery.d.ts.map +1 -0
- package/dist/functions-rtdb/discovery.js +86 -0
- package/dist/functions-rtdb/discovery.js.map +1 -0
- package/dist/functions-rtdb/event.d.ts +20 -0
- package/dist/functions-rtdb/event.d.ts.map +1 -0
- package/dist/functions-rtdb/event.js +45 -0
- package/dist/functions-rtdb/event.js.map +1 -0
- package/dist/functions-rtdb/execution.d.ts +20 -0
- package/dist/functions-rtdb/execution.d.ts.map +1 -0
- package/dist/functions-rtdb/execution.js +70 -0
- package/dist/functions-rtdb/execution.js.map +1 -0
- package/dist/functions-rtdb/in-memory-delivery.d.ts +9 -0
- package/dist/functions-rtdb/in-memory-delivery.d.ts.map +1 -0
- package/dist/functions-rtdb/in-memory-delivery.js +36 -0
- package/dist/functions-rtdb/in-memory-delivery.js.map +1 -0
- package/dist/functions-rtdb/project.d.ts +7 -0
- package/dist/functions-rtdb/project.d.ts.map +1 -0
- package/dist/functions-rtdb/project.js +54 -0
- package/dist/functions-rtdb/project.js.map +1 -0
- package/dist/functions-rtdb/projection.d.ts +14 -0
- package/dist/functions-rtdb/projection.d.ts.map +1 -0
- package/dist/functions-rtdb/projection.js +65 -0
- package/dist/functions-rtdb/projection.js.map +1 -0
- package/dist/functions-rtdb/reference-pattern.d.ts +5 -0
- package/dist/functions-rtdb/reference-pattern.d.ts.map +1 -0
- package/dist/functions-rtdb/reference-pattern.js +14 -0
- package/dist/functions-rtdb/reference-pattern.js.map +1 -0
- package/dist/functions-rtdb/remote-delivery.d.ts +9 -0
- package/dist/functions-rtdb/remote-delivery.d.ts.map +1 -0
- package/dist/functions-rtdb/remote-delivery.js +11 -0
- package/dist/functions-rtdb/remote-delivery.js.map +1 -0
- package/dist/pkg-version.d.ts +2 -0
- package/dist/pkg-version.d.ts.map +1 -0
- package/dist/pkg-version.js +47 -0
- package/dist/pkg-version.js.map +1 -0
- package/dist/register/esm-exports.d.ts +26 -0
- package/dist/register/esm-exports.d.ts.map +1 -0
- package/dist/register/esm-exports.js +61 -0
- package/dist/register/esm-exports.js.map +1 -0
- package/dist/register/hooks.d.ts +13 -0
- package/dist/register/hooks.d.ts.map +1 -0
- package/dist/register/hooks.js +15 -0
- package/dist/register/hooks.js.map +1 -0
- package/dist/register/index.d.ts +5 -0
- package/dist/register/index.d.ts.map +1 -0
- package/dist/register/index.js +124 -0
- package/dist/register/index.js.map +1 -0
- package/dist/register/mapping.d.ts +19 -0
- package/dist/register/mapping.d.ts.map +1 -0
- package/dist/register/mapping.js +35 -0
- package/dist/register/mapping.js.map +1 -0
- package/dist/remote/index.d.ts +232 -0
- package/dist/remote/index.d.ts.map +1 -0
- package/dist/remote/index.js +720 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/rtdb/crawl-snapshot.d.ts +17 -0
- package/dist/rtdb/crawl-snapshot.d.ts.map +1 -0
- package/dist/rtdb/crawl-snapshot.js +72 -0
- package/dist/rtdb/crawl-snapshot.js.map +1 -0
- package/dist/rtdb/inspection.d.ts +8 -0
- package/dist/rtdb/inspection.d.ts.map +1 -0
- package/dist/rtdb/inspection.js +111 -0
- package/dist/rtdb/inspection.js.map +1 -0
- package/dist/rtdb/load-rules-document.d.ts +25 -0
- package/dist/rtdb/load-rules-document.d.ts.map +1 -0
- package/dist/rtdb/load-rules-document.js +38 -0
- package/dist/rtdb/load-rules-document.js.map +1 -0
- package/dist/rtdb/rules-generation-tool.d.ts +4 -0
- package/dist/rtdb/rules-generation-tool.d.ts.map +1 -0
- package/dist/rtdb/rules-generation-tool.js +35 -0
- package/dist/rtdb/rules-generation-tool.js.map +1 -0
- package/dist/rtdb/rules-json.d.ts +8 -0
- package/dist/rtdb/rules-json.d.ts.map +1 -0
- package/dist/rtdb/rules-json.js +17 -0
- package/dist/rtdb/rules-json.js.map +1 -0
- package/dist/serve/bridge-mount.d.ts +36 -0
- package/dist/serve/bridge-mount.d.ts.map +1 -0
- package/dist/serve/bridge-mount.js +162 -0
- package/dist/serve/bridge-mount.js.map +1 -0
- package/dist/serve/bundler.d.ts +110 -0
- package/dist/serve/bundler.d.ts.map +1 -0
- package/dist/serve/bundler.js +432 -0
- package/dist/serve/bundler.js.map +1 -0
- package/dist/serve/capture-store.d.ts +27 -0
- package/dist/serve/capture-store.d.ts.map +1 -0
- package/dist/serve/capture-store.js +47 -0
- package/dist/serve/capture-store.js.map +1 -0
- package/dist/serve/discovery.d.ts +71 -0
- package/dist/serve/discovery.d.ts.map +1 -0
- package/dist/serve/discovery.js +158 -0
- package/dist/serve/discovery.js.map +1 -0
- package/dist/serve/docs-ui/_astro/_slug_.CQYSemvw.css +1 -0
- package/dist/serve/docs-ui/docs/_rhythm/index.html +99 -0
- package/dist/serve/docs-ui/docs/_rhythm.md +101 -0
- package/dist/serve/docs-ui/docs/api-reference/index.html +64 -0
- package/dist/serve/docs-ui/docs/api-reference.md +67 -0
- package/dist/serve/docs-ui/docs/audit-your-rules/index.html +34 -0
- package/dist/serve/docs-ui/docs/audit-your-rules.md +50 -0
- package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +498 -0
- package/dist/serve/docs-ui/docs/create-pyric-reference-api.md +345 -0
- package/dist/serve/docs-ui/docs/firestore-rules-limits/index.html +59 -0
- package/dist/serve/docs-ui/docs/firestore-rules-limits.md +54 -0
- package/dist/serve/docs-ui/docs/how-the-swap-works/index.html +47 -0
- package/dist/serve/docs-ui/docs/how-the-swap-works.md +43 -0
- package/dist/serve/docs-ui/docs/how-we-know-it-matches-firebase/index.html +131 -0
- package/dist/serve/docs-ui/docs/how-we-know-it-matches-firebase.md +169 -0
- package/dist/serve/docs-ui/docs/index.html +2 -0
- package/dist/serve/docs-ui/docs/index.json +18637 -0
- package/dist/serve/docs-ui/docs/overview/index.html +23 -0
- package/dist/serve/docs-ui/docs/overview.md +40 -0
- package/dist/serve/docs-ui/docs/pyric-admin-app/index.html +19 -0
- package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +185 -0
- package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api.md +206 -0
- package/dist/serve/docs-ui/docs/pyric-admin-app.md +27 -0
- package/dist/serve/docs-ui/docs/pyric-admin-auth/index.html +24 -0
- package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +617 -0
- package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api.md +441 -0
- package/dist/serve/docs-ui/docs/pyric-admin-auth.md +29 -0
- package/dist/serve/docs-ui/docs/pyric-admin-database/index.html +26 -0
- package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +583 -0
- package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api.md +597 -0
- package/dist/serve/docs-ui/docs/pyric-admin-database.md +31 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore/index.html +38 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-error-translation/index.html +57 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-error-translation.md +95 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-per-call-delegate/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-per-call-delegate.md +94 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-run-a-transaction/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-run-a-transaction.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules/index.html +62 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules.md +96 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-translate-denials/index.html +80 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-translate-denials.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-use-onsnapshot/index.html +57 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-use-onsnapshot.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-write-a-batch/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-write-a-batch.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +32 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api.md +30 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-onsnapshot/index.html +68 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-onsnapshot.md +81 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-re-exported-types/index.html +76 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-re-exported-types.md +103 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-sandbox-firestore/index.html +40 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-sandbox-firestore.md +77 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session/index.html +118 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session.md +166 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore.md +53 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage/index.html +25 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +317 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api.md +285 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage.md +30 -0
- package/dist/serve/docs-ui/docs/pyric-ai-compat/index.html +436 -0
- package/dist/serve/docs-ui/docs/pyric-ai-compat.md +471 -0
- package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +5831 -0
- package/dist/serve/docs-ui/docs/pyric-ai-reference-api.md +5440 -0
- package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +159 -0
- package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api.md +122 -0
- package/dist/serve/docs-ui/docs/pyric-app-compat/index.html +180 -0
- package/dist/serve/docs-ui/docs/pyric-app-compat.md +199 -0
- package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +420 -0
- package/dist/serve/docs-ui/docs/pyric-app-reference-api.md +326 -0
- package/dist/serve/docs-ui/docs/pyric-auth/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-auth-compat/index.html +804 -0
- package/dist/serve/docs-ui/docs/pyric-auth-compat.md +847 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +5452 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api.md +5271 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-feature-matrix/index.html +781 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-feature-matrix.md +198 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-sandbox-test-driver/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-sandbox-test-driver.md +108 -0
- package/dist/serve/docs-ui/docs/pyric-auth.md +86 -0
- package/dist/serve/docs-ui/docs/pyric-cli/index.html +40 -0
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +98 -0
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +2355 -0
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api.md +1554 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge/index.html +69 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +546 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api.md +485 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +506 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api.md +419 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge.md +99 -0
- package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +67 -0
- package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api.md +59 -0
- package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +2355 -0
- package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api.md +2036 -0
- package/dist/serve/docs-ui/docs/pyric-cli-functions-rtdb-compat/index.html +112 -0
- package/dist/serve/docs-ui/docs/pyric-cli-functions-rtdb-compat.md +124 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-build-a-standalone-binary/index.html +91 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-build-a-standalone-binary.md +105 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-promote-sandbox-state-to-a-fixture/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-promote-sandbox-state-to-a-fixture.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated.md +100 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-serve-persistence-and-multi-tab/index.html +228 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-serve-persistence-and-multi-tab.md +179 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-use-the-vite-plugin/index.html +341 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-use-the-vite-plugin.md +309 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-verify-against-a-captured-session/index.html +128 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-verify-against-a-captured-session.md +207 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-cli/index.html +404 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-cli.md +249 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-package-and-resolution/index.html +93 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-package-and-resolution.md +65 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-verify/index.html +81 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-verify.md +110 -0
- package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +10 -0
- package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api.md +16 -0
- package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1044 -0
- package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api.md +952 -0
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +5041 -0
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +4739 -0
- package/dist/serve/docs-ui/docs/pyric-cli-tutorials-server-adoption/index.html +219 -0
- package/dist/serve/docs-ui/docs/pyric-cli-tutorials-server-adoption.md +251 -0
- package/dist/serve/docs-ui/docs/pyric-cli-tutorials-wire-claude-code/index.html +136 -0
- package/dist/serve/docs-ui/docs/pyric-cli-tutorials-wire-claude-code.md +217 -0
- package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +926 -0
- package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api.md +586 -0
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +102 -0
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-cli.md +42 -0
- package/dist/serve/docs-ui/docs/pyric-conformance-scores/index.html +180 -0
- package/dist/serve/docs-ui/docs/pyric-conformance-scores.md +184 -0
- package/dist/serve/docs-ui/docs/pyric-database/index.html +43 -0
- package/dist/serve/docs-ui/docs/pyric-database-compat/index.html +1224 -0
- package/dist/serve/docs-ui/docs/pyric-database-compat.md +1289 -0
- package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate/index.html +16 -0
- package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate.md +23 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +1851 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-api.md +1842 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-constraints/index.html +381 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-constraints.md +168 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling/index.html +218 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling.md +303 -0
- package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints/index.html +125 -0
- package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints.md +171 -0
- package/dist/serve/docs-ui/docs/pyric-database.md +26 -0
- package/dist/serve/docs-ui/docs/pyric-explanation-versioning-and-compatibility/index.html +40 -0
- package/dist/serve/docs-ui/docs/pyric-explanation-versioning-and-compatibility.md +68 -0
- package/dist/serve/docs-ui/docs/pyric-firestore/index.html +48 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-compat/index.html +868 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-compat.md +939 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate.md +70 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-target-symbol-opacity/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-target-symbol-opacity.md +91 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface/index.html +43 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface.md +58 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore.md +86 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend.md +83 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-run-a-transaction/index.html +42 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-run-a-transaction.md +59 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot.md +96 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops/index.html +61 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +3623 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api.md +3399 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix/index.html +80 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix.md +66 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore/index.html +46 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints/index.html +80 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints.md +129 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-tool-factories/index.html +51 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-tool-factories.md +71 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo/index.html +130 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo.md +180 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +30 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +30 -0
- package/dist/serve/docs-ui/docs/pyric-firestore.md +72 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-compat/index.html +300 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-compat.md +321 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +508 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-reference-api.md +374 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +482 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api.md +348 -0
- package/dist/serve/docs-ui/docs/pyric-rules/index.html +87 -0
- package/dist/serve/docs-ui/docs/pyric-rules-compat/index.html +328 -0
- package/dist/serve/docs-ui/docs/pyric-rules-compat.md +347 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-agent-failure-modes/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-agent-failure-modes.md +78 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test/index.html +79 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates/index.html +67 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates.md +75 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-sentinel-expression-engine/index.html +49 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-sentinel-expression-engine.md +74 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api/index.html +95 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api.md +80 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-the-2-plus-modules-extension/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-the-2-plus-modules-extension.md +79 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design.md +84 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-why-this-package-exists/index.html +34 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-why-this-package-exists.md +43 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening/index.html +55 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening.md +77 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast/index.html +90 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast.md +129 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source/index.html +55 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source.md +84 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time/index.html +49 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time.md +64 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-register-tools-with-an-agent/index.html +61 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-register-tools-with-an-agent.md +87 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports/index.html +93 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports.md +105 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-simulate-rules-locally/index.html +89 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-simulate-rules-locally.md +134 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase.md +102 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +2629 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api.md +2213 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-ast/index.html +85 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-ast.md +121 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-conformance-gaps/index.html +277 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-conformance-gaps.md +360 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-errors/index.html +76 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-errors.md +123 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-lint-rules/index.html +148 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-lint-rules.md +159 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-simulator-context/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-simulator-context.md +104 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules/index.html +241 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules.md +143 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema/index.html +94 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema.md +121 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings/index.html +87 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings.md +117 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers/index.html +102 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers.md +152 -0
- package/dist/serve/docs-ui/docs/pyric-rules.md +93 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox/index.html +67 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +120 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api.md +110 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-every-op-is-a-request/index.html +141 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-every-op-is-a-request.md +161 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-identity-is-a-context/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-identity-is-a-context.md +110 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-internal-adapter-protocol/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-internal-adapter-protocol.md +111 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-listener-re-evaluation/index.html +56 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-listener-re-evaluation.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline/index.html +64 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline.md +56 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings.md +90 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-this-package-exists/index.html +69 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-this-package-exists.md +57 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +202 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api.md +134 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes.md +89 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-observe-events/index.html +159 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-observe-events.md +168 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-pick-an-adapter/index.html +79 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-pick-an-adapter.md +75 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events/index.html +88 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-reset-between-tests/index.html +68 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-reset-between-tests.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-seed-data-and-rules/index.html +91 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-seed-data-and-rules.md +122 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-switch-users/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-switch-users.md +78 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-use-admin-reads/index.html +54 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-use-admin-reads.md +85 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +5019 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +4060 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-divergences/index.html +125 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-divergences.md +151 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-error-codes/index.html +110 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-error-codes.md +118 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-internal-protocol/index.html +72 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-internal-protocol.md +109 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-and-context/index.html +90 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-and-context.md +140 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-event/index.html +146 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-event.md +204 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-snapshot-and-admin/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-snapshot-and-admin.md +89 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session/index.html +115 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session.md +176 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-storage/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-compat/index.html +676 -0
- package/dist/serve/docs-ui/docs/pyric-storage-compat.md +699 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope.md +85 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-session-archive-use-case/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-session-archive-use-case.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-why-indexeddb/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-why-indexeddb.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-enforce-rules/index.html +120 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-enforce-rules.md +127 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-list-and-delete/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-list-and-delete.md +86 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends/index.html +43 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends.md +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-test-rule-expressions/index.html +70 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-test-rule-expressions.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +2120 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api.md +1687 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-conformance-gaps/index.html +137 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-conformance-gaps.md +171 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes/index.html +37 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes.md +57 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset/index.html +96 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset.md +134 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options/index.html +39 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options.md +61 -0
- package/dist/serve/docs-ui/docs/pyric-storage.md +67 -0
- package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +638 -0
- package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api.md +430 -0
- package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +813 -0
- package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api.md +634 -0
- package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +1708 -0
- package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api.md +1300 -0
- package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +177 -0
- package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api.md +111 -0
- package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +1542 -0
- package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api.md +903 -0
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1024 -0
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api.md +640 -0
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +2753 -0
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api.md +2171 -0
- package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +1005 -0
- package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api.md +693 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +1388 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api.md +1340 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +131 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +648 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api.md +508 -0
- package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1457 -0
- package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api.md +1029 -0
- package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +2476 -0
- package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api.md +1919 -0
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1241 -0
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api.md +817 -0
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +2289 -0
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api.md +1489 -0
- package/dist/serve/docs-ui/docs/read-a-denial/index.html +40 -0
- package/dist/serve/docs-ui/docs/read-a-denial.md +62 -0
- package/dist/serve/docs-ui/docs/receive-messages/index.html +28 -0
- package/dist/serve/docs-ui/docs/receive-messages.md +43 -0
- package/dist/serve/docs-ui/docs/rtdb-rules-in-typescript/index.html +67 -0
- package/dist/serve/docs-ui/docs/rtdb-rules-in-typescript.md +101 -0
- package/dist/serve/docs-ui/docs/rules-patterns/index.html +68 -0
- package/dist/serve/docs-ui/docs/rules-patterns.md +104 -0
- package/dist/serve/docs-ui/docs/rules-standard-library/index.html +87 -0
- package/dist/serve/docs-ui/docs/rules-standard-library.md +93 -0
- package/dist/serve/docs-ui/docs/run-ai-logic-locally/index.html +27 -0
- package/dist/serve/docs-ui/docs/run-ai-logic-locally.md +43 -0
- package/dist/serve/docs-ui/docs/secure-it-with-rules/index.html +69 -0
- package/dist/serve/docs-ui/docs/secure-it-with-rules.md +101 -0
- package/dist/serve/docs-ui/docs/see-whats-happening/index.html +73 -0
- package/dist/serve/docs-ui/docs/see-whats-happening.md +77 -0
- package/dist/serve/docs-ui/docs/set-up-the-project/index.html +14 -0
- package/dist/serve/docs-ui/docs/set-up-the-project.md +19 -0
- package/dist/serve/docs-ui/docs/set-up-your-agent/index.html +42 -0
- package/dist/serve/docs-ui/docs/set-up-your-agent.md +86 -0
- package/dist/serve/docs-ui/docs/shape-your-data/index.html +44 -0
- package/dist/serve/docs-ui/docs/shape-your-data.md +88 -0
- package/dist/serve/docs-ui/docs/ship-to-production/index.html +36 -0
- package/dist/serve/docs-ui/docs/ship-to-production.md +80 -0
- package/dist/serve/docs-ui/docs/sign-in-and-manage-users/index.html +31 -0
- package/dist/serve/docs-ui/docs/sign-in-and-manage-users.md +50 -0
- package/dist/serve/docs-ui/docs/simulate-and-lint/index.html +95 -0
- package/dist/serve/docs-ui/docs/simulate-and-lint.md +99 -0
- package/dist/serve/docs-ui/docs/skills/index.html +20 -0
- package/dist/serve/docs-ui/docs/skills.md +34 -0
- package/dist/serve/docs-ui/docs/start-building/index.html +32 -0
- package/dist/serve/docs-ui/docs/start-building.md +64 -0
- package/dist/serve/docs-ui/docs/store-and-query-data/index.html +16 -0
- package/dist/serve/docs-ui/docs/store-and-query-data.md +33 -0
- package/dist/serve/docs-ui/docs/store-files/index.html +13 -0
- package/dist/serve/docs-ui/docs/store-files.md +25 -0
- package/dist/serve/docs-ui/docs/sync-realtime-data/index.html +15 -0
- package/dist/serve/docs-ui/docs/sync-realtime-data.md +27 -0
- package/dist/serve/docs-ui/docs/test-in-node/index.html +74 -0
- package/dist/serve/docs-ui/docs/test-in-node.md +100 -0
- package/dist/serve/docs-ui/docs/ui/index.html +76 -0
- package/dist/serve/docs-ui/docs/ui-auth-authsigninhelper/index.html +194 -0
- package/dist/serve/docs-ui/docs/ui-auth-authsigninhelper.md +114 -0
- package/dist/serve/docs-ui/docs/ui-auth-authusers/index.html +263 -0
- package/dist/serve/docs-ui/docs/ui-auth-authusers.md +183 -0
- package/dist/serve/docs-ui/docs/ui-firestore-collectionlist/index.html +92 -0
- package/dist/serve/docs-ui/docs/ui-firestore-collectionlist.md +79 -0
- package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm/index.html +128 -0
- package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm.md +104 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documenteditor/index.html +154 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documenteditor.md +117 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentlist/index.html +132 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentlist.md +92 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentpreview/index.html +159 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentpreview.md +84 -0
- package/dist/serve/docs-ui/docs/ui-firestore-querybuilder/index.html +104 -0
- package/dist/serve/docs-ui/docs/ui-firestore-querybuilder.md +103 -0
- package/dist/serve/docs-ui/docs/ui-firestore-referencepicker/index.html +113 -0
- package/dist/serve/docs-ui/docs/ui-firestore-referencepicker.md +93 -0
- package/dist/serve/docs-ui/docs/ui-primitives-badge/index.html +56 -0
- package/dist/serve/docs-ui/docs/ui-primitives-badge.md +40 -0
- package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog/index.html +140 -0
- package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog.md +108 -0
- package/dist/serve/docs-ui/docs/ui-primitives-copybutton/index.html +58 -0
- package/dist/serve/docs-ui/docs/ui-primitives-copybutton.md +37 -0
- package/dist/serve/docs-ui/docs/ui-primitives-jsonview/index.html +58 -0
- package/dist/serve/docs-ui/docs/ui-primitives-jsonview.md +47 -0
- package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol/index.html +70 -0
- package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol.md +50 -0
- package/dist/serve/docs-ui/docs/ui-primitives-toast/index.html +87 -0
- package/dist/serve/docs-ui/docs/ui-primitives-toast.md +82 -0
- package/dist/serve/docs-ui/docs/ui-primitives-virtuallist/index.html +85 -0
- package/dist/serve/docs-ui/docs/ui-primitives-virtuallist.md +54 -0
- package/dist/serve/docs-ui/docs/ui-storage/index.html +150 -0
- package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm/index.html +126 -0
- package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm.md +88 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectbrowser/index.html +137 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectbrowser.md +90 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectinspector/index.html +139 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectinspector.md +93 -0
- package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb/index.html +72 -0
- package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb.md +57 -0
- package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances/index.html +60 -0
- package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances.md +52 -0
- package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone/index.html +93 -0
- package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone.md +78 -0
- package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate/index.html +144 -0
- package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate.md +101 -0
- package/dist/serve/docs-ui/docs/ui-storage.md +165 -0
- package/dist/serve/docs-ui/docs/ui-traffic/index.html +88 -0
- package/dist/serve/docs-ui/docs/ui-traffic-ruleheatmap/index.html +79 -0
- package/dist/serve/docs-ui/docs/ui-traffic-ruleheatmap.md +60 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail/index.html +78 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail.md +59 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficlog/index.html +118 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficlog.md +69 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficstats/index.html +51 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficstats.md +46 -0
- package/dist/serve/docs-ui/docs/ui-traffic.md +102 -0
- package/dist/serve/docs-ui/docs/ui.md +90 -0
- package/dist/serve/docs-ui/docs/watch-and-review/index.html +25 -0
- package/dist/serve/docs-ui/docs/watch-and-review.md +40 -0
- package/dist/serve/docs-ui/docs/what-your-agent-can-do/index.html +81 -0
- package/dist/serve/docs-ui/docs/what-your-agent-can-do.md +78 -0
- package/dist/serve/docs-ui/docs/whats-experimental/index.html +22 -0
- package/dist/serve/docs-ui/docs/whats-experimental.md +33 -0
- package/dist/serve/docs-ui/docs/whats-possible/index.html +63 -0
- package/dist/serve/docs-ui/docs/whats-possible.md +53 -0
- package/dist/serve/docs-ui/docs/which-data-service/index.html +8 -0
- package/dist/serve/docs-ui/docs/which-data-service.md +11 -0
- package/dist/serve/docs-ui/docs/write-a-rules-test-suite/index.html +85 -0
- package/dist/serve/docs-ui/docs/write-a-rules-test-suite.md +119 -0
- package/dist/serve/docs-ui/index.html +1 -0
- package/dist/serve/docs-ui/llms.txt +308 -0
- package/dist/serve/entries/ai.d.ts +4 -0
- package/dist/serve/entries/ai.d.ts.map +1 -0
- package/dist/serve/entries/ai.js +184 -0
- package/dist/serve/entries/ai.js.map +1 -0
- package/dist/serve/entries/app-backend.d.ts +2 -0
- package/dist/serve/entries/app-backend.d.ts.map +1 -0
- package/dist/serve/entries/app-backend.js +4 -0
- package/dist/serve/entries/app-backend.js.map +1 -0
- package/dist/serve/entries/app-client.d.ts +5 -0
- package/dist/serve/entries/app-client.d.ts.map +1 -0
- package/dist/serve/entries/app-client.js +23 -0
- package/dist/serve/entries/app-client.js.map +1 -0
- package/dist/serve/entries/app-session-store.d.ts +14 -0
- package/dist/serve/entries/app-session-store.d.ts.map +1 -0
- package/dist/serve/entries/app-session-store.js +37 -0
- package/dist/serve/entries/app-session-store.js.map +1 -0
- package/dist/serve/entries/app.d.ts +2 -0
- package/dist/serve/entries/app.d.ts.map +1 -0
- package/dist/serve/entries/app.js +10 -0
- package/dist/serve/entries/app.js.map +1 -0
- package/dist/serve/entries/auth-helper-core.d.ts +52 -0
- package/dist/serve/entries/auth-helper-core.d.ts.map +1 -0
- package/dist/serve/entries/auth-helper-core.js +118 -0
- package/dist/serve/entries/auth-helper-core.js.map +1 -0
- package/dist/serve/entries/auth-helper-dom.d.ts +14 -0
- package/dist/serve/entries/auth-helper-dom.d.ts.map +1 -0
- package/dist/serve/entries/auth-helper-dom.js +116 -0
- package/dist/serve/entries/auth-helper-dom.js.map +1 -0
- package/dist/serve/entries/auth-helper-runtime.d.ts +5 -0
- package/dist/serve/entries/auth-helper-runtime.d.ts.map +1 -0
- package/dist/serve/entries/auth-helper-runtime.js +11 -0
- package/dist/serve/entries/auth-helper-runtime.js.map +1 -0
- package/dist/serve/entries/auth.d.ts +77 -0
- package/dist/serve/entries/auth.d.ts.map +1 -0
- package/dist/serve/entries/auth.js +201 -0
- package/dist/serve/entries/auth.js.map +1 -0
- package/dist/serve/entries/bridge-url.d.ts +25 -0
- package/dist/serve/entries/bridge-url.d.ts.map +1 -0
- package/dist/serve/entries/bridge-url.js +30 -0
- package/dist/serve/entries/bridge-url.js.map +1 -0
- package/dist/serve/entries/database.d.ts +46 -0
- package/dist/serve/entries/database.d.ts.map +1 -0
- package/dist/serve/entries/database.js +80 -0
- package/dist/serve/entries/database.js.map +1 -0
- package/dist/serve/entries/firestore.d.ts +104 -0
- package/dist/serve/entries/firestore.d.ts.map +1 -0
- package/dist/serve/entries/firestore.js +202 -0
- package/dist/serve/entries/firestore.js.map +1 -0
- package/dist/serve/entries/init.d.ts +2 -0
- package/dist/serve/entries/init.d.ts.map +1 -0
- package/dist/serve/entries/init.js +40 -0
- package/dist/serve/entries/init.js.map +1 -0
- package/dist/serve/entries/keepalive.d.ts +20 -0
- package/dist/serve/entries/keepalive.d.ts.map +1 -0
- package/dist/serve/entries/keepalive.js +38 -0
- package/dist/serve/entries/keepalive.js.map +1 -0
- package/dist/serve/entries/messaging-sw.d.ts +10 -0
- package/dist/serve/entries/messaging-sw.d.ts.map +1 -0
- package/dist/serve/entries/messaging-sw.js +36 -0
- package/dist/serve/entries/messaging-sw.js.map +1 -0
- package/dist/serve/entries/messaging.d.ts +11 -0
- package/dist/serve/entries/messaging.d.ts.map +1 -0
- package/dist/serve/entries/messaging.js +53 -0
- package/dist/serve/entries/messaging.js.map +1 -0
- package/dist/serve/entries/runtime.d.ts +46 -0
- package/dist/serve/entries/runtime.d.ts.map +1 -0
- package/dist/serve/entries/runtime.js +435 -0
- package/dist/serve/entries/runtime.js.map +1 -0
- package/dist/serve/entries/session-store.d.ts +48 -0
- package/dist/serve/entries/session-store.d.ts.map +1 -0
- package/dist/serve/entries/session-store.js +82 -0
- package/dist/serve/entries/session-store.js.map +1 -0
- package/dist/serve/entries/storage.d.ts +25 -0
- package/dist/serve/entries/storage.d.ts.map +1 -0
- package/dist/serve/entries/storage.js +61 -0
- package/dist/serve/entries/storage.js.map +1 -0
- package/dist/serve/entries/tab-sync-wiring.d.ts +88 -0
- package/dist/serve/entries/tab-sync-wiring.d.ts.map +1 -0
- package/dist/serve/entries/tab-sync-wiring.js +217 -0
- package/dist/serve/entries/tab-sync-wiring.js.map +1 -0
- package/dist/serve/entries/worker-runtime.d.ts +10 -0
- package/dist/serve/entries/worker-runtime.d.ts.map +1 -0
- package/dist/serve/entries/worker-runtime.js +59 -0
- package/dist/serve/entries/worker-runtime.js.map +1 -0
- package/dist/serve/init-payload.d.ts +21 -0
- package/dist/serve/init-payload.d.ts.map +1 -0
- package/dist/serve/init-payload.js +2 -0
- package/dist/serve/init-payload.js.map +1 -0
- package/dist/serve/namespace.d.ts +73 -0
- package/dist/serve/namespace.d.ts.map +1 -0
- package/dist/serve/namespace.js +470 -0
- package/dist/serve/namespace.js.map +1 -0
- package/dist/serve/open-browser.d.ts +23 -0
- package/dist/serve/open-browser.d.ts.map +1 -0
- package/dist/serve/open-browser.js +58 -0
- package/dist/serve/open-browser.js.map +1 -0
- package/dist/serve/rules.d.ts +77 -0
- package/dist/serve/rules.d.ts.map +1 -0
- package/dist/serve/rules.js +202 -0
- package/dist/serve/rules.js.map +1 -0
- package/dist/serve/sandbox-marker.d.ts +9 -0
- package/dist/serve/sandbox-marker.d.ts.map +1 -0
- package/dist/serve/sandbox-marker.js +31 -0
- package/dist/serve/sandbox-marker.js.map +1 -0
- package/dist/serve/server.d.ts +135 -0
- package/dist/serve/server.d.ts.map +1 -0
- package/dist/serve/server.js +328 -0
- package/dist/serve/server.js.map +1 -0
- package/dist/serve/standalone-assets.d.ts +67 -0
- package/dist/serve/standalone-assets.d.ts.map +1 -0
- package/dist/serve/standalone-assets.js +134 -0
- package/dist/serve/standalone-assets.js.map +1 -0
- package/dist/serve/state-store.d.ts +45 -0
- package/dist/serve/state-store.d.ts.map +1 -0
- package/dist/serve/state-store.js +120 -0
- package/dist/serve/state-store.js.map +1 -0
- package/dist/serve/studio/disk-project-store.d.ts +9 -0
- package/dist/serve/studio/disk-project-store.d.ts.map +1 -0
- package/dist/serve/studio/disk-project-store.js +173 -0
- package/dist/serve/studio/disk-project-store.js.map +1 -0
- package/dist/serve/studio/disk-workspace.d.ts +14 -0
- package/dist/serve/studio/disk-workspace.d.ts.map +1 -0
- package/dist/serve/studio/disk-workspace.js +152 -0
- package/dist/serve/studio/disk-workspace.js.map +1 -0
- package/dist/serve/studio/index.d.ts +10 -0
- package/dist/serve/studio/index.d.ts.map +1 -0
- package/dist/serve/studio/index.js +9 -0
- package/dist/serve/studio/index.js.map +1 -0
- package/dist/serve/studio/routes.d.ts +40 -0
- package/dist/serve/studio/routes.d.ts.map +1 -0
- package/dist/serve/studio/routes.js +182 -0
- package/dist/serve/studio/routes.js.map +1 -0
- package/dist/serve/studio/store-types.d.ts +45 -0
- package/dist/serve/studio/store-types.d.ts.map +1 -0
- package/dist/serve/studio/store-types.js +11 -0
- package/dist/serve/studio/store-types.js.map +1 -0
- package/dist/serve/studio-ui/assets/RulesCodeEditor-BZpD57II.js +23 -0
- package/dist/serve/studio-ui/assets/index-Bsa-TQNK.css +1 -0
- package/dist/serve/studio-ui/assets/index-DGaVuOhE.js +1211 -0
- package/dist/serve/studio-ui/assets/seed-CTmn6YuO.js +2 -0
- package/dist/serve/studio-ui/index.html +32 -0
- package/dist/serve/studio-ui/pyric-logo.svg +76 -0
- package/dist/serve/vite-plugin.d.ts +57 -0
- package/dist/serve/vite-plugin.d.ts.map +1 -0
- package/dist/serve/vite-plugin.js +658 -0
- package/dist/serve/vite-plugin.js.map +1 -0
- package/dist/serve/worker/client/admin-firestore.d.ts +18 -0
- package/dist/serve/worker/client/admin-firestore.d.ts.map +1 -0
- package/dist/serve/worker/client/admin-firestore.js +26 -0
- package/dist/serve/worker/client/admin-firestore.js.map +1 -0
- package/dist/serve/worker/client/ai.d.ts +31 -0
- package/dist/serve/worker/client/ai.d.ts.map +1 -0
- package/dist/serve/worker/client/ai.js +89 -0
- package/dist/serve/worker/client/ai.js.map +1 -0
- package/dist/serve/worker/client/auth.d.ts +168 -0
- package/dist/serve/worker/client/auth.d.ts.map +1 -0
- package/dist/serve/worker/client/auth.js +322 -0
- package/dist/serve/worker/client/auth.js.map +1 -0
- package/dist/serve/worker/client/connection.d.ts +80 -0
- package/dist/serve/worker/client/connection.d.ts.map +1 -0
- package/dist/serve/worker/client/connection.js +148 -0
- package/dist/serve/worker/client/connection.js.map +1 -0
- package/dist/serve/worker/client/core.d.ts +109 -0
- package/dist/serve/worker/client/core.d.ts.map +1 -0
- package/dist/serve/worker/client/core.js +248 -0
- package/dist/serve/worker/client/core.js.map +1 -0
- package/dist/serve/worker/client/disconnect.d.ts +7 -0
- package/dist/serve/worker/client/disconnect.d.ts.map +1 -0
- package/dist/serve/worker/client/disconnect.js +26 -0
- package/dist/serve/worker/client/disconnect.js.map +1 -0
- package/dist/serve/worker/client/firestore-reads.d.ts +49 -0
- package/dist/serve/worker/client/firestore-reads.d.ts.map +1 -0
- package/dist/serve/worker/client/firestore-reads.js +139 -0
- package/dist/serve/worker/client/firestore-reads.js.map +1 -0
- package/dist/serve/worker/client/firestore-refs.d.ts +54 -0
- package/dist/serve/worker/client/firestore-refs.d.ts.map +1 -0
- package/dist/serve/worker/client/firestore-refs.js +167 -0
- package/dist/serve/worker/client/firestore-refs.js.map +1 -0
- package/dist/serve/worker/client/firestore-writes.d.ts +70 -0
- package/dist/serve/worker/client/firestore-writes.d.ts.map +1 -0
- package/dist/serve/worker/client/firestore-writes.js +169 -0
- package/dist/serve/worker/client/firestore-writes.js.map +1 -0
- package/dist/serve/worker/client/handles.d.ts +73 -0
- package/dist/serve/worker/client/handles.d.ts.map +1 -0
- package/dist/serve/worker/client/handles.js +4 -0
- package/dist/serve/worker/client/handles.js.map +1 -0
- package/dist/serve/worker/client/messaging.d.ts +16 -0
- package/dist/serve/worker/client/messaging.d.ts.map +1 -0
- package/dist/serve/worker/client/messaging.js +60 -0
- package/dist/serve/worker/client/messaging.js.map +1 -0
- package/dist/serve/worker/client/presence.d.ts +43 -0
- package/dist/serve/worker/client/presence.d.ts.map +1 -0
- package/dist/serve/worker/client/presence.js +132 -0
- package/dist/serve/worker/client/presence.js.map +1 -0
- package/dist/serve/worker/client/rtdb.d.ts +36 -0
- package/dist/serve/worker/client/rtdb.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb.js +241 -0
- package/dist/serve/worker/client/rtdb.js.map +1 -0
- package/dist/serve/worker/client/rules.d.ts +24 -0
- package/dist/serve/worker/client/rules.d.ts.map +1 -0
- package/dist/serve/worker/client/rules.js +44 -0
- package/dist/serve/worker/client/rules.js.map +1 -0
- package/dist/serve/worker/client/service-worker-connection.d.ts +3 -0
- package/dist/serve/worker/client/service-worker-connection.d.ts.map +1 -0
- package/dist/serve/worker/client/service-worker-connection.js +53 -0
- package/dist/serve/worker/client/service-worker-connection.js.map +1 -0
- package/dist/serve/worker/client/snapshots.d.ts +32 -0
- package/dist/serve/worker/client/snapshots.d.ts.map +1 -0
- package/dist/serve/worker/client/snapshots.js +46 -0
- package/dist/serve/worker/client/snapshots.js.map +1 -0
- package/dist/serve/worker/client/storage.d.ts +64 -0
- package/dist/serve/worker/client/storage.d.ts.map +1 -0
- package/dist/serve/worker/client/storage.js +125 -0
- package/dist/serve/worker/client/storage.js.map +1 -0
- package/dist/serve/worker/client/studio.d.ts +32 -0
- package/dist/serve/worker/client/studio.d.ts.map +1 -0
- package/dist/serve/worker/client/studio.js +61 -0
- package/dist/serve/worker/client/studio.js.map +1 -0
- package/dist/serve/worker/client.d.ts +43 -0
- package/dist/serve/worker/client.d.ts.map +1 -0
- package/dist/serve/worker/client.js +44 -0
- package/dist/serve/worker/client.js.map +1 -0
- package/dist/serve/worker/entry.d.ts +40 -0
- package/dist/serve/worker/entry.d.ts.map +1 -0
- package/dist/serve/worker/entry.js +144 -0
- package/dist/serve/worker/entry.js.map +1 -0
- package/dist/serve/worker/host/admin-firestore.d.ts +17 -0
- package/dist/serve/worker/host/admin-firestore.d.ts.map +1 -0
- package/dist/serve/worker/host/admin-firestore.js +92 -0
- package/dist/serve/worker/host/admin-firestore.js.map +1 -0
- package/dist/serve/worker/host/connection.d.ts +40 -0
- package/dist/serve/worker/host/connection.d.ts.map +1 -0
- package/dist/serve/worker/host/connection.js +153 -0
- package/dist/serve/worker/host/connection.js.map +1 -0
- package/dist/serve/worker/host/core.d.ts +159 -0
- package/dist/serve/worker/host/core.d.ts.map +1 -0
- package/dist/serve/worker/host/core.js +296 -0
- package/dist/serve/worker/host/core.js.map +1 -0
- package/dist/serve/worker/host/dispatch.d.ts +34 -0
- package/dist/serve/worker/host/dispatch.d.ts.map +1 -0
- package/dist/serve/worker/host/dispatch.js +267 -0
- package/dist/serve/worker/host/dispatch.js.map +1 -0
- package/dist/serve/worker/host/firestore-reads.d.ts +17 -0
- package/dist/serve/worker/host/firestore-reads.d.ts.map +1 -0
- package/dist/serve/worker/host/firestore-reads.js +108 -0
- package/dist/serve/worker/host/firestore-reads.js.map +1 -0
- package/dist/serve/worker/host/firestore-writes.d.ts +37 -0
- package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -0
- package/dist/serve/worker/host/firestore-writes.js +409 -0
- package/dist/serve/worker/host/firestore-writes.js.map +1 -0
- package/dist/serve/worker/host/presence.d.ts +38 -0
- package/dist/serve/worker/host/presence.d.ts.map +1 -0
- package/dist/serve/worker/host/presence.js +280 -0
- package/dist/serve/worker/host/presence.js.map +1 -0
- package/dist/serve/worker/host/rtdb.d.ts +18 -0
- package/dist/serve/worker/host/rtdb.d.ts.map +1 -0
- package/dist/serve/worker/host/rtdb.js +128 -0
- package/dist/serve/worker/host/rtdb.js.map +1 -0
- package/dist/serve/worker/host/rules.d.ts +17 -0
- package/dist/serve/worker/host/rules.d.ts.map +1 -0
- package/dist/serve/worker/host/rules.js +118 -0
- package/dist/serve/worker/host/rules.js.map +1 -0
- package/dist/serve/worker/host/storage.d.ts +19 -0
- package/dist/serve/worker/host/storage.d.ts.map +1 -0
- package/dist/serve/worker/host/storage.js +260 -0
- package/dist/serve/worker/host/storage.js.map +1 -0
- package/dist/serve/worker/host/studio.d.ts +13 -0
- package/dist/serve/worker/host/studio.d.ts.map +1 -0
- package/dist/serve/worker/host/studio.js +30 -0
- package/dist/serve/worker/host/studio.js.map +1 -0
- package/dist/serve/worker/host/subscriptions.d.ts +21 -0
- package/dist/serve/worker/host/subscriptions.d.ts.map +1 -0
- package/dist/serve/worker/host/subscriptions.js +162 -0
- package/dist/serve/worker/host/subscriptions.js.map +1 -0
- package/dist/serve/worker/host-ai.d.ts +59 -0
- package/dist/serve/worker/host-ai.d.ts.map +1 -0
- package/dist/serve/worker/host-ai.js +158 -0
- package/dist/serve/worker/host-ai.js.map +1 -0
- package/dist/serve/worker/host-auth.d.ts +47 -0
- package/dist/serve/worker/host-auth.d.ts.map +1 -0
- package/dist/serve/worker/host-auth.js +464 -0
- package/dist/serve/worker/host-auth.js.map +1 -0
- package/dist/serve/worker/host-context.d.ts +220 -0
- package/dist/serve/worker/host-context.d.ts.map +1 -0
- package/dist/serve/worker/host-context.js +45 -0
- package/dist/serve/worker/host-context.js.map +1 -0
- package/dist/serve/worker/host-events.d.ts +21 -0
- package/dist/serve/worker/host-events.d.ts.map +1 -0
- package/dist/serve/worker/host-events.js +87 -0
- package/dist/serve/worker/host-events.js.map +1 -0
- package/dist/serve/worker/host-messaging.d.ts +60 -0
- package/dist/serve/worker/host-messaging.d.ts.map +1 -0
- package/dist/serve/worker/host-messaging.js +226 -0
- package/dist/serve/worker/host-messaging.js.map +1 -0
- package/dist/serve/worker/host.d.ts +36 -0
- package/dist/serve/worker/host.d.ts.map +1 -0
- package/dist/serve/worker/host.js +39 -0
- package/dist/serve/worker/host.js.map +1 -0
- package/dist/serve/worker/index.d.ts +22 -0
- package/dist/serve/worker/index.d.ts.map +1 -0
- package/dist/serve/worker/index.js +61 -0
- package/dist/serve/worker/index.js.map +1 -0
- package/dist/serve/worker/presence-timing.d.ts +14 -0
- package/dist/serve/worker/presence-timing.d.ts.map +1 -0
- package/dist/serve/worker/presence-timing.js +14 -0
- package/dist/serve/worker/presence-timing.js.map +1 -0
- package/dist/serve/worker/protocol.d.ts +1150 -0
- package/dist/serve/worker/protocol.d.ts.map +1 -0
- package/dist/serve/worker/protocol.js +228 -0
- package/dist/serve/worker/protocol.js.map +1 -0
- package/dist/serve/worker/serve-init.d.ts +201 -0
- package/dist/serve/worker/serve-init.d.ts.map +1 -0
- package/dist/serve/worker/serve-init.js +579 -0
- package/dist/serve/worker/serve-init.js.map +1 -0
- package/dist/serve/worker/service-worker-channel.d.ts +23 -0
- package/dist/serve/worker/service-worker-channel.d.ts.map +1 -0
- package/dist/serve/worker/service-worker-channel.js +9 -0
- package/dist/serve/worker/service-worker-channel.js.map +1 -0
- package/dist/serve/worker/service-worker-relay.d.ts +22 -0
- package/dist/serve/worker/service-worker-relay.d.ts.map +1 -0
- package/dist/serve/worker/service-worker-relay.js +63 -0
- package/dist/serve/worker/service-worker-relay.js.map +1 -0
- package/dist/serve/writer-lock.d.ts +32 -0
- package/dist/serve/writer-lock.d.ts.map +1 -0
- package/dist/serve/writer-lock.js +43 -0
- package/dist/serve/writer-lock.js.map +1 -0
- package/dist/verify/cases.d.ts +37 -0
- package/dist/verify/cases.d.ts.map +1 -0
- package/dist/verify/cases.js +173 -0
- package/dist/verify/cases.js.map +1 -0
- package/dist/verify/fixture.d.ts +100 -0
- package/dist/verify/fixture.d.ts.map +1 -0
- package/dist/verify/fixture.js +156 -0
- package/dist/verify/fixture.js.map +1 -0
- package/dist/verify/index.d.ts +102 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +318 -0
- package/dist/verify/index.js.map +1 -0
- package/dist/verify/tools.d.ts +7 -0
- package/dist/verify/tools.d.ts.map +1 -0
- package/dist/verify/tools.js +83 -0
- package/dist/verify/tools.js.map +1 -0
- package/dist/version/compat-target.d.ts +18 -0
- package/dist/version/compat-target.d.ts.map +1 -0
- package/dist/version/compat-target.js +18 -0
- package/dist/version/compat-target.js.map +1 -0
- package/dist/vite.d.ts +12 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +16 -0
- package/dist/vite.js.map +1 -0
- package/package.json +133 -0
|
@@ -0,0 +1,939 @@
|
|
|
1
|
+
<!-- Generated from packages/conformance/registry/*.ts. Do not edit by hand; run bun run compat:generate. -->
|
|
2
|
+
|
|
3
|
+
# `pyric/firestore` compatibility matrix
|
|
4
|
+
|
|
5
|
+
<div class="compat-stat">
|
|
6
|
+
<p class="compat-stat-surface"><strong>Public surface:</strong> runtime 63.5% (66/104) <span aria-hidden="true">·</span> types 38.5% (30/78)</p>
|
|
7
|
+
<p class="compat-stat-figure">
|
|
8
|
+
<span class="compat-stat-pct">87.6%</span>
|
|
9
|
+
<span class="compat-stat-label">of tracked behaviors conform</span>
|
|
10
|
+
</p>
|
|
11
|
+
<p class="compat-stat-denom">141 of 161 tracked behaviors</p>
|
|
12
|
+
<div class="compat-stat-bar" role="img" aria-label="Behavior distribution: 141 conform, 20 documented divergences, 0 bugs, 0 unsupported, 0 unverified.">
|
|
13
|
+
<span class="compat-stat-seg" data-status="ok" style="flex-grow: 141" aria-hidden="true"></span>
|
|
14
|
+
<span class="compat-stat-seg" data-status="diverged" style="flex-grow: 20" aria-hidden="true"></span>
|
|
15
|
+
</div>
|
|
16
|
+
<ul class="compat-stat-key" aria-label="Behavior state counts">
|
|
17
|
+
<li class="compat-stat-item"><span class="compat-dot" data-status="ok" aria-hidden="true"></span><span><strong>141</strong> conform</span></li>
|
|
18
|
+
<li class="compat-stat-item"><span class="compat-dot" data-status="diverged" aria-hidden="true"></span><span><strong>20</strong> documented divergences</span></li>
|
|
19
|
+
<li class="compat-stat-item"><span class="compat-dot" data-status="bug" aria-hidden="true"></span><span><strong>0</strong> bugs</span></li>
|
|
20
|
+
<li class="compat-stat-item"><span class="compat-dot" data-status="unsupported" aria-hidden="true"></span><span><strong>0</strong> unsupported</span></li>
|
|
21
|
+
<li class="compat-stat-item"><span class="compat-dot" data-status="unverified" aria-hidden="true"></span><span><strong>0</strong> unverified</span></li>
|
|
22
|
+
</ul>
|
|
23
|
+
<p class="compat-stat-note">Public surface measures whether exports exist. Fidelity measures whether tracked behavior matches production.</p>
|
|
24
|
+
</div>
|
|
25
|
+
[Read how the axes differ.](../pyric-conformance-scores/)
|
|
26
|
+
|
|
27
|
+
The single readable contract for what the sandbox mirror guarantees compared
|
|
28
|
+
with the production `firebase/firestore` SDK.
|
|
29
|
+
|
|
30
|
+
See the design rationale for the methodology (vocabulary
|
|
31
|
+
of conformance / oracle / matrix; how to add rows; how the runner
|
|
32
|
+
attributes failures).
|
|
33
|
+
|
|
34
|
+
## Status legend
|
|
35
|
+
|
|
36
|
+
<div class="compat-key">
|
|
37
|
+
<span class="compat-key-item"><span class="compat-dot" data-status="ok"></span><strong>Conforming</strong> — sandbox matches prod, locked by a passing probe</span>
|
|
38
|
+
<span class="compat-key-item"><span class="compat-dot" data-status="diverged"></span><strong>Diverged (documented)</strong> — intentional difference with a written reason</span>
|
|
39
|
+
<span class="compat-key-item"><span class="compat-dot" data-status="bug"></span><strong>Bug</strong> — should match prod but doesn't; failing probe pins it</span>
|
|
40
|
+
<span class="compat-key-item"><span class="compat-dot" data-status="unsupported"></span><strong>Unsupported</strong> — not implemented yet (deliberately or pending)</span>
|
|
41
|
+
<span class="compat-key-item"><span class="compat-dot" data-status="unverified"></span><strong>Unverified</strong> — claim from docs that we haven't yet observed prod-side</span>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
Probe references: `playground:<name>` means a fixture under
|
|
45
|
+
`packages/playground/scripts/fixtures/<name>.tsx`. `unit:<file>`
|
|
46
|
+
means a Bun test in `packages/pyric/test/firestore/<file>`.
|
|
47
|
+
|
|
48
|
+
Targets:
|
|
49
|
+
- **sandbox** — frozen-ctx target built via `getFirestore(ctx: SandboxContext)`. Identity baked in at handle-construction.
|
|
50
|
+
- **sandbox-live** — live-identity target built via `getFirestore(sandbox: Sandbox)`. Every op re-reads `sandbox.currentUser`. The playground preview always uses this flavor.
|
|
51
|
+
|
|
52
|
+
Production is not a target inside this mirror. With sandbox activation off,
|
|
53
|
+
package resolution leaves `firebase/firestore` unchanged. With activation on,
|
|
54
|
+
canonical Firebase imports resolve to this sandbox-only package.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## `getFirestore(target)` — initializer
|
|
59
|
+
|
|
60
|
+
<div class="compat-list">
|
|
61
|
+
<details class="compat-row" data-status="ok">
|
|
62
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getFirestore(target)</code><span class="compat-sub"><span class="compat-behavior"><code>getFirestore(ctx)</code> returns a tagged sandbox-target handle (frozen identity)</span></span></span></summary>
|
|
63
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
64
|
+
</details>
|
|
65
|
+
<details class="compat-row" data-status="ok">
|
|
66
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getFirestore(target)</code><span class="compat-sub"><span class="compat-behavior"><code>getFirestore(sandbox)</code> returns a tagged sandbox-live handle (per-op identity)</span></span></span></summary>
|
|
67
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code></div></div>
|
|
68
|
+
</details>
|
|
69
|
+
<details class="compat-row" data-status="ok">
|
|
70
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getFirestore(target)</code><span class="compat-sub"><span class="compat-behavior">Package resolution owns production selection: direct <code>pyric/firestore</code> rejects a real <code>FirebaseApp</code>, while inactive canonical <code>firebase/firestore</code> imports remain the real Firebase SDK</span></span></span></summary>
|
|
71
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:package-resolution.test.ts</code>, <code>node-register:register-child.test.ts</code> (inactive canonical imports are not rewritten)</div></div>
|
|
72
|
+
</details>
|
|
73
|
+
<details class="compat-row" data-status="ok">
|
|
74
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getFirestore(target)</code><span class="compat-sub"><span class="compat-behavior"><code>getFirestore(undefined)</code> is wrapped in the playground preview to default to the sandbox; production's unactivated canonical SDK still throws <code>app/no-app</code>, while a direct mirror call rejects the missing sandbox owner</span></span></span></summary>
|
|
75
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:firestore-bare-getfirestore</code> — fix from PR #397 + oracle: <code>packages/conformance/observations/firestore/firestore-bare-getfirestore-no-default-app.json</code> (<code>code: 'app/no-app'</code> against blockingfun, fb-js-sdk 12.13.0 — confirms prod throw shape)</div>
|
|
76
|
+
<div class="compat-note">(wrap)</div></div>
|
|
77
|
+
</details>
|
|
78
|
+
<details class="compat-row" data-status="ok">
|
|
79
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getFirestore(target)</code><span class="compat-sub"><span class="compat-behavior">Two <code>getFirestore(sandbox)</code> calls share state (same underlying <code>LocalEnvironment</code>)</span></span></span></summary>
|
|
80
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("two handles share the same sandbox")</div></div>
|
|
81
|
+
</details>
|
|
82
|
+
<details class="compat-row" data-status="ok">
|
|
83
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getFirestore(target)</code><span class="compat-sub"><span class="compat-behavior">Handle dispatch by <code>TARGET_SYMBOL</code> brand — refs/queries route to their owning target via <code>refToTarget</code> WeakMap</span></span></span></summary>
|
|
84
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("throws TypeError for refs not produced by this package")</div></div>
|
|
85
|
+
</details>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
## Path constructors — `doc` / `collection` / `collectionGroup`
|
|
89
|
+
|
|
90
|
+
<div class="compat-list">
|
|
91
|
+
<details class="compat-row" data-status="ok">
|
|
92
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Path constructors</code><span class="compat-sub"><span class="compat-behavior"><code>doc(db, path)</code> returns a tagged <code>DocumentReference</code> with <code>id</code> / <code>path</code></span></span></span></summary>
|
|
93
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
94
|
+
</details>
|
|
95
|
+
<details class="compat-row" data-status="ok">
|
|
96
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Path constructors</code><span class="compat-sub"><span class="compat-behavior"><code>doc(db, 'a', 'b', 'c', 'd')</code> joins variadic path segments</span></span></span></summary>
|
|
97
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
98
|
+
</details>
|
|
99
|
+
<details class="compat-row" data-status="ok">
|
|
100
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Path constructors</code><span class="compat-sub"><span class="compat-behavior"><code>collection(db, path)</code> returns a tagged <code>CollectionReference</code></span></span></span></summary>
|
|
101
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
102
|
+
</details>
|
|
103
|
+
<details class="compat-row" data-status="ok">
|
|
104
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Path constructors</code><span class="compat-sub"><span class="compat-behavior"><code>doc(coll, id)</code> appends under a collection ref</span></span></span></summary>
|
|
105
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
106
|
+
</details>
|
|
107
|
+
<details class="compat-row" data-status="ok">
|
|
108
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Path constructors</code><span class="compat-sub"><span class="compat-behavior"><code>doc(coll)</code> (no id) mints an auto-id <code>DocumentReference</code></span></span></span></summary>
|
|
109
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
110
|
+
</details>
|
|
111
|
+
<details class="compat-row" data-status="ok">
|
|
112
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Path constructors</code><span class="compat-sub"><span class="compat-behavior"><code>collection(docRef, name)</code> builds a subcollection ref</span></span></span></summary>
|
|
113
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
114
|
+
</details>
|
|
115
|
+
<details class="compat-row" data-status="ok">
|
|
116
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Path constructors</code><span class="compat-sub"><span class="compat-behavior"><code>collectionGroup(db, id)</code> returns a query spanning every collection with that id</span></span></span></summary>
|
|
117
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("gathers documents across every parent collection")</div></div>
|
|
118
|
+
</details>
|
|
119
|
+
<details class="compat-row" data-status="ok">
|
|
120
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Path constructors</code><span class="compat-sub"><span class="compat-behavior">Unknown ref (not produced by this package) → <code>TypeError</code> with "unrecognized reference"</span></span></span></summary>
|
|
121
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
122
|
+
</details>
|
|
123
|
+
<details class="compat-row" data-status="ok">
|
|
124
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Path constructors</code><span class="compat-sub"><span class="compat-behavior">Held doc/coll ref under <code>sandbox-live</code> re-resolves to the chainable under the current user at op time (via rebuild closure)</span></span></span></summary>
|
|
125
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("held doc ref re-resolves under the current user")</div></div>
|
|
126
|
+
</details>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
## `getDoc(ref)` — single-doc read
|
|
130
|
+
|
|
131
|
+
<div class="compat-list">
|
|
132
|
+
<details class="compat-row" data-status="ok">
|
|
133
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDoc(ref)</code><span class="compat-sub"><span class="compat-behavior">Returns <code>DocumentSnapshot</code> with <code>id</code>, <code>exists</code> (method form), <code>data()</code></span></span></span></summary>
|
|
134
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
135
|
+
</details>
|
|
136
|
+
<details class="compat-row" data-status="ok">
|
|
137
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDoc(ref)</code><span class="compat-sub"><span class="compat-behavior"><code>snap.exists</code> is normalized to method form (<code>snap.exists()</code> returns boolean) to match the modular SDK</span></span></span></summary>
|
|
138
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:firestore-onsnapshot</code> (bundled, assertion-shape compat) + <code>playground:firestore-row-17-snap-exists-method</code> (one-claim)</div></div>
|
|
139
|
+
</details>
|
|
140
|
+
<details class="compat-row" data-status="ok">
|
|
141
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDoc(ref)</code><span class="compat-sub"><span class="compat-behavior"><code>snap.data()</code> returns <code>undefined</code> for missing doc</span></span></span></summary>
|
|
142
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
143
|
+
</details>
|
|
144
|
+
<details class="compat-row" data-status="ok">
|
|
145
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDoc(ref)</code><span class="compat-sub"><span class="compat-behavior"><code>snap.ref</code> is tagged so it routes through <code>targetOf</code> in follow-up ops</span></span></span></summary>
|
|
146
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
147
|
+
</details>
|
|
148
|
+
<details class="compat-row" data-status="ok">
|
|
149
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDoc(ref)</code><span class="compat-sub"><span class="compat-behavior">Re-evaluates rules under current user on every call (sandbox-live) — read denied throws <code>permission-denied</code></span></span></span></summary>
|
|
150
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("doc read denied when current user lacks read access"), oracle: <code>packages/conformance/observations/firestore/firestore-read-denied-error-code.json</code> (prod <code>getDoc</code> on a denied path throws a <code>FirebaseError</code> with <code>.code === 'permission-denied'</code>, <code>.message === 'Missing or insufficient permissions.'</code>, <code>instanceof Error</code>)</div></div>
|
|
151
|
+
</details>
|
|
152
|
+
<details class="compat-row" data-status="diverged">
|
|
153
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">getDoc(ref)</code><span class="compat-sub"><span class="compat-behavior">Rules denial throws <code>SandboxError('permission-denied', …)</code> on sandbox; <code>FirebaseError('permission-denied')</code> on prod</span></span></span></summary>
|
|
154
|
+
<div class="compat-evidence"><div class="compat-probe">divergence: same code, different class — both expose <code>.code === 'permission-denied'</code>. Oracle-locked: <code>packages/conformance/observations/firestore/firestore-rules-denied-error.json</code> — prod throws a <code>FirebaseError</code> (name + constructor name both <code>FirebaseError</code>), <code>.code === 'permission-denied'</code>, <code>.message === '7 PERMISSION_DENIED: Missing or insufficient permissions.'</code>, and the value is an <code>instanceof Error</code>.</div></div>
|
|
155
|
+
</details>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
## `getDocs(query)` — bulk read
|
|
159
|
+
|
|
160
|
+
<div class="compat-list">
|
|
161
|
+
<details class="compat-row" data-status="ok">
|
|
162
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDocs(query)</code><span class="compat-sub"><span class="compat-behavior">Returns <code>QuerySnapshot</code> with <code>size</code>, <code>empty</code>, <code>docs</code> (<code>QueryDocumentSnapshot[]</code>)</span></span></span></summary>
|
|
163
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-query</code></div></div>
|
|
164
|
+
</details>
|
|
165
|
+
<details class="compat-row" data-status="ok">
|
|
166
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDocs(query)</code><span class="compat-sub"><span class="compat-behavior">Each <code>snap.docs[i].ref</code> is tagged for follow-up ops</span></span></span></summary>
|
|
167
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
168
|
+
</details>
|
|
169
|
+
<details class="compat-row" data-status="ok">
|
|
170
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDocs(query)</code><span class="compat-sub"><span class="compat-behavior">Sandbox-live: re-evaluates filters under the current user (different docs visible per identity)</span></span></span></summary>
|
|
171
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("query results re-evaluate under the current user")</div></div>
|
|
172
|
+
</details>
|
|
173
|
+
<details class="compat-row" data-status="ok">
|
|
174
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDocs(query)</code><span class="compat-sub"><span class="compat-behavior"><strong>Query reads enforce security rules (FS-B1)</strong> — a deny-all / auth-gated rule set throws <code>permission-denied</code>. Pre-FS-B1 query reads went through the rules-bypassing <code>listDocuments</code> and returned the whole collection.</span></span></span></summary>
|
|
175
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:admin-compat/query-rules-enforcement.test.ts</code> (deny-all + auth-gated <code>getDocs</code>/aggregate), <code>unit:admin-compat/per-op-auth.test.ts</code> ("Query.get enforces rules")</div></div>
|
|
176
|
+
</details>
|
|
177
|
+
<details class="compat-row" data-status="ok">
|
|
178
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDocs(query)</code><span class="compat-sub"><span class="compat-behavior"><strong>Enforcement follows production's QUERY-PROOF model (RULES-B11)</strong> — "rules are not filters": a doc-data-dependent <code>list</code> rule (<code>resource.data.visibility == 'public'</code>, <code>resource.data.owner == request.auth.uid</code>) is ALLOWED when the query's <code>where()</code> equalities discharge it and the whole query is <code>permission-denied</code> otherwise — never silently truncated to the readable subset. Per-doc <code>get</code> rules do NOT filter query results (the <code>list</code> rule alone governs queries — granular-operations docs). Applies to <code>getDocs</code>, aggregates, and <code>onSnapshot</code> alike. Pre-fix: rules-as-filters (per-doc <code>get</code> omission) + blanket denial of every doc-data-dependent list, even provable ones.</span></span></span></summary>
|
|
179
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/query-proof-enforcement.test.ts</code> (provable/unprovable getDocs + onSnapshot, owner-pinned uid, get-rules-don't-filter, request.query.limit; verified failing pre-fix), <code>unit:simulator/local-environment.test.ts</code> (Slice 6 — flipped from per-doc-filter assertions); prod truth: firebase.google.com/docs/firestore/security/rules-query</div></div>
|
|
180
|
+
</details>
|
|
181
|
+
<details class="compat-row" data-status="diverged">
|
|
182
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">getDocs(query)</code><span class="compat-sub"><span class="compat-behavior">Query-proof <strong>prover scope is conservative</strong> — only top-level AND-conjunct <code>resource.data.<field> == <literal></code> predicates (with <code>request.auth.uid</code> pinned to the caller) are dischargeable by <code>where(field, '==', value)</code>. Disjunctions over doc data, inequality/range proofs (<code>resource.data.score > 10</code> + <code>where('score','>',10)</code>), <code>in</code>-operand proofs, and nested-path predicates conservatively DENY the whole query where production's prover may allow it. Never a false ALLOW — the conservative direction prod also takes for unprovable queries.</span></span></span></summary>
|
|
183
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:rules/simulator/query-proof.test.ts</code> (conservative-reject cases); divergence is deny-only (no rule-violating doc can leak)</div></div>
|
|
184
|
+
</details>
|
|
185
|
+
<details class="compat-row" data-status="ok">
|
|
186
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDocs(query)</code><span class="compat-sub"><span class="compat-behavior">Empty result for a collection with no docs (<code>size === 0</code>, <code>empty === true</code>)</span></span></span></summary>
|
|
187
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
188
|
+
</details>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
## `setDoc(ref, data[, options])` — full write
|
|
192
|
+
|
|
193
|
+
<div class="compat-list">
|
|
194
|
+
<details class="compat-row" data-status="ok">
|
|
195
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">setDoc(ref, data[, options])</code><span class="compat-sub"><span class="compat-behavior">No options → replaces the existing document entirely</span></span></span></summary>
|
|
196
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("setDoc default replaces")</div></div>
|
|
197
|
+
</details>
|
|
198
|
+
<details class="compat-row" data-status="ok">
|
|
199
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">setDoc(ref, data[, options])</code><span class="compat-sub"><span class="compat-behavior"><code>{ merge: true }</code> → <strong>deep-merges nested maps</strong> (FS-B6), preserving unspecified fields at every level: <code>setDoc({a:{b:2}}, {merge:true})</code> over <code>{a:{c:1}}</code> yields <code>{a:{b:2,c:1}}</code>. Pre-FS-B6 the wrapper shallow-replaced the whole <code>a</code> map.</span></span></span></summary>
|
|
200
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>unit:admin-compat/field-path-merge.test.ts</code> (FS-B6 nested deep-merge; verified failing pre-fix)</div></div>
|
|
201
|
+
</details>
|
|
202
|
+
<details class="compat-row" data-status="ok">
|
|
203
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">setDoc(ref, data[, options])</code><span class="compat-sub"><span class="compat-behavior"><code>{ mergeFields: [...] }</code> → writes only the listed <strong>dot-separated field paths</strong> into the existing doc (FS-B6); other keys in <code>data</code> are ignored, other fields in the existing doc preserved. <code>mergeFields: ['a.b']</code> reaches into a nested map.</span></span></span></summary>
|
|
204
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>unit:admin-compat/field-path-merge.test.ts</code> (dotted mergeField); mask edges (delete/transform outside mask, empty mask, deleteField in mask): <code>unit:upstream-write-aggregate-probes.test.ts</code></div></div>
|
|
205
|
+
</details>
|
|
206
|
+
<details class="compat-row" data-status="ok">
|
|
207
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">setDoc(ref, data[, options])</code><span class="compat-sub"><span class="compat-behavior">Passing both <code>merge</code> and <code>mergeFields</code> — <code>mergeFields</code> wins on sandbox (matches JS SDK effective behavior)</span></span></span></summary>
|
|
208
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
209
|
+
</details>
|
|
210
|
+
<details class="compat-row" data-status="ok">
|
|
211
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">setDoc(ref, data[, options])</code><span class="compat-sub"><span class="compat-behavior">Sentinels (<code>serverTimestamp</code>, <code>increment</code>, <code>arrayUnion</code>, <code>arrayRemove</code>, <code>deleteField</code>) resolve in the same call</span></span></span></summary>
|
|
212
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-sentinels</code>, oracle: <code>packages/conformance/observations/firestore/firestore-row-30-sentinels-in-setdoc.json</code> — <code>setDoc({createdAt: serverTimestamp(), count: 5, tags: ['a']})</code> followed by <code>getDoc</code> returns <code>createdAt</code> as a <code>Timestamp</code> instance (constructor name <code>Timestamp</code>, has <code>seconds</code> + <code>nanoseconds</code>), <code>count === 5</code> (number), <code>tags === ['a']</code>. Sentinels resolve server-side and the follow-up read sees concrete values, not the sentinel placeholders.</div></div>
|
|
213
|
+
</details>
|
|
214
|
+
<details class="compat-row" data-status="ok">
|
|
215
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">setDoc(ref, data[, options])</code><span class="compat-sub"><span class="compat-behavior">Converter (via <code>withConverter</code>) runs <code>toFirestore(data)</code> before the write</span></span></span></summary>
|
|
216
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("withConverter on a DocumentReference round-trips")</div></div>
|
|
217
|
+
</details>
|
|
218
|
+
<details class="compat-row" data-status="ok">
|
|
219
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">setDoc(ref, data[, options])</code><span class="compat-sub"><span class="compat-behavior">Rules-denied write throws <code>permission-denied</code> (sandbox) / <code>FirebaseError</code> (prod)</span></span></span></summary>
|
|
220
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("getDoc denies when rules reject"), <code>playground:rules-data-validation</code>, oracle: <code>packages/conformance/observations/firestore/firestore-write-denied-error-code.json</code> (prod <code>setDoc</code> on a denied path throws a <code>FirebaseError</code> with <code>.code === 'permission-denied'</code>, <code>.message === '7 PERMISSION_DENIED: Missing or insufficient permissions.'</code>, <code>instanceof Error</code>)</div></div>
|
|
221
|
+
</details>
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
## `updateDoc(ref, data)` — partial write
|
|
225
|
+
|
|
226
|
+
<div class="compat-list">
|
|
227
|
+
<details class="compat-row" data-status="ok">
|
|
228
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">updateDoc(ref, data)</code><span class="compat-sub"><span class="compat-behavior">Merges <code>data</code> into the existing doc; missing fields preserved. <strong>Top-level keys are dot-separated FieldPaths</strong> (FS-B5): <code>updateDoc({'a.b': 2})</code> sets the nested leaf <code>a.b</code> (preserving <code>a.c</code>), not a literal <code>"a.b"</code> key; a single-segment map value replaces that field wholesale; <code>deleteField()</code> at a dotted path removes the nested leaf.</span></span></span></summary>
|
|
229
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>unit:admin-compat/field-path-merge.test.ts</code> (FS-B5 dot-path nested write + delete; verified failing pre-fix)</div></div>
|
|
230
|
+
</details>
|
|
231
|
+
<details class="compat-row" data-status="ok">
|
|
232
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">updateDoc(ref, data)</code><span class="compat-sub"><span class="compat-behavior">Throws <code>not-found</code> (sandbox) / <code>FirebaseError('not-found')</code> (prod) on missing doc</span></span></span></summary>
|
|
233
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> (implicit in writes-fail-on-missing tests), oracle: <code>packages/conformance/observations/firestore/firestore-updatedoc-missing-error.json</code> (prod throws <code>FirebaseError</code> with <code>code: 'not-found'</code>, message <code>"5 NOT_FOUND: No document to update: …"</code>)</div></div>
|
|
234
|
+
</details>
|
|
235
|
+
<details class="compat-row" data-status="ok">
|
|
236
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">updateDoc(ref, data)</code><span class="compat-sub"><span class="compat-behavior">Does NOT run a converter — partial updates don't have a typed home (matches JS SDK)</span></span></span></summary>
|
|
237
|
+
<div class="compat-evidence"><div class="compat-probe">(documented in <code>withConverter</code> block)</div></div>
|
|
238
|
+
</details>
|
|
239
|
+
<details class="compat-row" data-status="ok">
|
|
240
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">updateDoc(ref, data)</code><span class="compat-sub"><span class="compat-behavior">Sentinels resolve mid-update (<code>increment(1)</code> against an existing numeric field, etc.)</span></span></span></summary>
|
|
241
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-sentinels</code>, oracle: <code>packages/conformance/observations/firestore/firestore-row-36-sentinels-in-updatedoc.json</code> — after <code>setDoc({count: 5, tags: ['a'], oldField: 'keep-then-remove'})</code> then <code>updateDoc({count: increment(3), tags: arrayUnion('b'), oldField: deleteField()})</code>, the follow-up <code>getDoc</code> returns <code>count: 8</code>, <code>tags: ['a', 'b']</code>, and <code>oldField</code> absent from the doc (the deleteField sentinel actually removes the key). All three sentinels apply in one mid-update commit.</div></div>
|
|
242
|
+
</details>
|
|
243
|
+
<details class="compat-row" data-status="ok">
|
|
244
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">updateDoc(ref, data)</code><span class="compat-sub"><span class="compat-behavior">Sandbox-live: each call re-evaluates auth (alice → bob between writes uses bob's auth)</span></span></span></summary>
|
|
245
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("updateDoc re-evaluates auth per call")</div></div>
|
|
246
|
+
</details>
|
|
247
|
+
</div>
|
|
248
|
+
|
|
249
|
+
## `deleteDoc(ref)`
|
|
250
|
+
|
|
251
|
+
<div class="compat-list">
|
|
252
|
+
<details class="compat-row" data-status="ok">
|
|
253
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">deleteDoc(ref)</code><span class="compat-sub"><span class="compat-behavior">Removes the document; subsequent <code>getDoc</code> returns <code>exists()===false</code></span></span></span></summary>
|
|
254
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
255
|
+
</details>
|
|
256
|
+
<details class="compat-row" data-status="ok">
|
|
257
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">deleteDoc(ref)</code><span class="compat-sub"><span class="compat-behavior">Idempotent — <code>deleteDoc</code> on missing doc resolves without throwing (matches JS SDK)</span></span></span></summary>
|
|
258
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:deletedoc-missing.test.ts</code>, <code>playground:firestore-deletedoc-missing</code>, oracle: <code>packages/conformance/observations/firestore/firestore-deletedoc-missing.json</code></div></div>
|
|
259
|
+
</details>
|
|
260
|
+
<details class="compat-row" data-status="ok">
|
|
261
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">deleteDoc(ref)</code><span class="compat-sub"><span class="compat-behavior">Rules-denied delete throws <code>permission-denied</code></span></span></span></summary>
|
|
262
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> (rules-reject branch), oracle: <code>packages/conformance/observations/firestore/firestore-delete-denied-error-code.json</code> (prod <code>deleteDoc</code> on a denied path throws a <code>FirebaseError</code> with <code>.code === 'permission-denied'</code>, <code>.message === '7 PERMISSION_DENIED: Missing or insufficient permissions.'</code>, <code>instanceof Error</code>)</div></div>
|
|
263
|
+
</details>
|
|
264
|
+
</div>
|
|
265
|
+
|
|
266
|
+
## `addDoc(coll, data)` — auto-id write
|
|
267
|
+
|
|
268
|
+
<div class="compat-list">
|
|
269
|
+
<details class="compat-row" data-status="ok">
|
|
270
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">addDoc(coll, data)</code><span class="compat-sub"><span class="compat-behavior">Returns a tagged <code>DocumentReference</code> with auto-id</span></span></span></summary>
|
|
271
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
272
|
+
</details>
|
|
273
|
+
<details class="compat-row" data-status="ok">
|
|
274
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">addDoc(coll, data)</code><span class="compat-sub"><span class="compat-behavior">Returned ref is usable in subsequent ops (<code>getDoc</code>, <code>setDoc</code>, <code>onSnapshot</code>)</span></span></span></summary>
|
|
275
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, oracle: <code>packages/conformance/observations/firestore/firestore-row-42-adddoc-returned-ref-usable.json</code> — <code>addDoc(coll, {v:1})</code> returned a ref whose <code>.id</code> is a 20-char auto-id; <code>getDoc(ref)</code> returned <code>{v:1}</code> (round-trip), <code>setDoc(ref, {v:2})</code> overwrote without error, follow-up <code>getDoc</code> returned <code>{v:2}</code>, and <code>onSnapshot(ref, cb)</code> registered cleanly and fired once with <code>{exists:true, v:2}</code>. All four follow-up ops succeed on the returned ref without re-tagging.</div></div>
|
|
276
|
+
</details>
|
|
277
|
+
<details class="compat-row" data-status="ok">
|
|
278
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">addDoc(coll, data)</code><span class="compat-sub"><span class="compat-behavior">Sandbox-live: returned ref is a <em>live</em> ref (rebuild closure recorded) so follow-ups re-resolve auth</span></span></span></summary>
|
|
279
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("addDoc result is a tagged live ref")</div></div>
|
|
280
|
+
</details>
|
|
281
|
+
<details class="compat-row" data-status="ok">
|
|
282
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">addDoc(coll, data)</code><span class="compat-sub"><span class="compat-behavior">Converter on the parent collection propagates onto the returned ref</span></span></span></summary>
|
|
283
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("addDoc through a converted collection")</div></div>
|
|
284
|
+
</details>
|
|
285
|
+
<details class="compat-row" data-status="diverged">
|
|
286
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">addDoc(coll, data)</code><span class="compat-sub"><span class="compat-behavior">Auto-id format — prod uses 20-char base64-ish IDs; sandbox uses <code>pyric-admin</code>'s auto-id (also opaque, distinct format)</span></span></span></summary>
|
|
287
|
+
<div class="compat-evidence"><div class="compat-probe">divergence: IDs are opaque on both sides; format differs but consumer code never parses them. Oracle-locked: <code>packages/conformance/observations/firestore/firestore-adddoc-autoid-format.json</code> — prod auto-ids are 20 characters, all alphanumeric (mixed upper, lower, digits; no other chars). Example: <code>S3PJENMPOk4qcDXol8Ez</code>.</div>
|
|
288
|
+
<div class="compat-note">format</div></div>
|
|
289
|
+
</details>
|
|
290
|
+
</div>
|
|
291
|
+
|
|
292
|
+
## `withConverter` — typed refs
|
|
293
|
+
|
|
294
|
+
<div class="compat-list">
|
|
295
|
+
<details class="compat-row" data-status="ok">
|
|
296
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">withConverter</code><span class="compat-sub"><span class="compat-behavior"><code>withConverter(docRef, converter)</code> returns a shell that runs <code>toFirestore</code> on writes, <code>fromFirestore</code> on reads</span></span></span></summary>
|
|
297
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
298
|
+
</details>
|
|
299
|
+
<details class="compat-row" data-status="ok">
|
|
300
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">withConverter</code><span class="compat-sub"><span class="compat-behavior"><code>withConverter(collRef, converter)</code> propagates onto <code>doc(typedColl, id)</code></span></span></span></summary>
|
|
301
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
302
|
+
</details>
|
|
303
|
+
<details class="compat-row" data-status="ok">
|
|
304
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">withConverter</code><span class="compat-sub"><span class="compat-behavior"><code>withConverter(collRef, converter)</code> propagates through <code>query(typedColl, …)</code> + <code>getDocs()</code></span></span></span></summary>
|
|
305
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
306
|
+
</details>
|
|
307
|
+
<details class="compat-row" data-status="ok">
|
|
308
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">withConverter</code><span class="compat-sub"><span class="compat-behavior"><code>withConverter(ref, null)</code> strips the converter, returns the underlying untyped view</span></span></span></summary>
|
|
309
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
310
|
+
</details>
|
|
311
|
+
<details class="compat-row" data-status="ok">
|
|
312
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">withConverter</code><span class="compat-sub"><span class="compat-behavior">Original untyped ref keeps its identity after <code>withConverter(ref, c)</code> (two views, one path)</span></span></span></summary>
|
|
313
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
314
|
+
</details>
|
|
315
|
+
<details class="compat-row" data-status="ok">
|
|
316
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">withConverter</code><span class="compat-sub"><span class="compat-behavior"><code>setDoc</code> through a converted ref invokes <code>toFirestore(data)</code></span></span></span></summary>
|
|
317
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
318
|
+
</details>
|
|
319
|
+
<details class="compat-row" data-status="ok">
|
|
320
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">withConverter</code><span class="compat-sub"><span class="compat-behavior"><code>getDoc</code> through a converted ref invokes <code>fromFirestore(snapshot)</code>; <code>.data()</code> returns the typed model</span></span></span></summary>
|
|
321
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
322
|
+
</details>
|
|
323
|
+
<details class="compat-row" data-status="ok">
|
|
324
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">withConverter</code><span class="compat-sub"><span class="compat-behavior"><code>updateDoc</code> through a converted ref does NOT invoke the converter</span></span></span></summary>
|
|
325
|
+
<div class="compat-evidence"><div class="compat-probe">(documented constraint; matches JS SDK)</div></div>
|
|
326
|
+
</details>
|
|
327
|
+
</div>
|
|
328
|
+
|
|
329
|
+
## Query construction — `query` / `where` / `or` / `and` / `orderBy` / `limit`
|
|
330
|
+
|
|
331
|
+
<div class="compat-list">
|
|
332
|
+
<details class="compat-row" data-status="ok">
|
|
333
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><code>query(coll, where(…), orderBy(…), limit(…))</code> composes constraints in order</span></span></span></summary>
|
|
334
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-query</code></div></div>
|
|
335
|
+
</details>
|
|
336
|
+
<details class="compat-row" data-status="ok">
|
|
337
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><code>where(field, op, value)</code> — all 10 ops: <code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>, <code>></code>, <code>!=</code>, <code>in</code>, <code>not-in</code>, <code>array-contains</code>, <code>array-contains-any</code></span></span></span></summary>
|
|
338
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> (canonical query test); membership ops + OR/<code>in</code>/<code>array-contains</code> composites: <code>unit:upstream-query-probes.test.ts</code></div></div>
|
|
339
|
+
</details>
|
|
340
|
+
<details class="compat-row" data-status="ok">
|
|
341
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><strong>Existence + null filter guards (FS-B7)</strong> — a doc missing the filter field is never returned by <code>==</code>/<code><</code>/<code><=</code>/<code>></code>/<code>>=</code>/<code>in</code>/<code>!=</code>/<code>not-in</code>; <code>!=</code> and <code>not-in</code> additionally exclude null-valued docs and require the field to exist; a <code>null</code> in a <code>not-in</code> operand list matches nothing. Pre-FS-B7, <code>!=</code>/<code>not-in</code> matched missing-field and null docs.</span></span></span></summary>
|
|
342
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:admin-compat/inequality-existence-guards.test.ts</code> (verified failing pre-fix)</div></div>
|
|
343
|
+
</details>
|
|
344
|
+
<details class="compat-row" data-status="ok">
|
|
345
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><code>or(...)</code> composite — at least one sub-filter matches</span></span></span></summary>
|
|
346
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("or() matches docs where any sub-filter matches"), oracle: <code>packages/conformance/observations/firestore/firestore-or-composite.json</code> (4 seeded docs; <code>or(where('x','==',1), where('y','==',2))</code> returned the exact union <code>{match-both, match-x, match-y}</code> — no implicit index required against cloud Firestore)</div></div>
|
|
347
|
+
</details>
|
|
348
|
+
<details class="compat-row" data-status="ok">
|
|
349
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><code>and(...)</code> composite — every sub-filter matches</span></span></span></summary>
|
|
350
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("and() requires every sub-filter"), oracle: <code>packages/conformance/observations/firestore/firestore-and-composite.json</code> (4 seeded docs; <code>and(where('x','==',1), where('y','==',2))</code> returned only the intersection <code>{match-both}</code>)</div></div>
|
|
351
|
+
</details>
|
|
352
|
+
<details class="compat-row" data-status="ok">
|
|
353
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior">Nested <code>or</code> / <code>and</code> — full composite tree</span></span></span></summary>
|
|
354
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("nested or/and — the canonical composite pattern"), oracle: <code>packages/conformance/observations/firestore/firestore-nested-or-and-composite.json</code> (6 seeded docs; <code>or(and(where('x','==',1), where('y','==',2)), where('z','==',3))</code> returned <code>{inner-and-match, outer-z-match, both-branches}</code> — exact boolean union as predicted)</div></div>
|
|
355
|
+
</details>
|
|
356
|
+
<details class="compat-row" data-status="ok">
|
|
357
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><code>orderBy(field, 'asc'|'desc')</code> — direction parameter</span></span></span></summary>
|
|
358
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
359
|
+
</details>
|
|
360
|
+
<details class="compat-row" data-status="ok">
|
|
361
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><strong>Canonical type-order comparison (FS-B3)</strong> — orderBy + range filters compare by Firestore's canonical type order (<code>null < bool < number < timestamp < string < bytes < ref < geopoint < array < map</code>), then within-type; numbers sort numerically (not lexicographically), NaN sorts as the smallest number, and range filters (<code><</code>/<code><=</code>/<code>></code>/<code>>=</code>) only match same-type values. Pre-FS-B3 the comparator fell back to <code>String(a).localeCompare(String(b))</code>.</span></span></span></summary>
|
|
362
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:admin-compat/canonical-type-order.test.ts</code> (cross-type ranking, numeric sort, NaN, timestamps, arrays; verified failing pre-fix)</div></div>
|
|
363
|
+
</details>
|
|
364
|
+
<details class="compat-row" data-status="ok">
|
|
365
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><strong>orderBy excludes missing-field docs (FS-B3)</strong> — a doc lacking an orderBy field is omitted from the result (matches prod); pre-fix it was sorted in via <code>compareValues(undefined, …)</code>.</span></span></span></summary>
|
|
366
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:admin-compat/canonical-type-order.test.ts</code> ("excludes the missing-field doc")</div></div>
|
|
367
|
+
</details>
|
|
368
|
+
<details class="compat-row" data-status="ok">
|
|
369
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><strong>Implicit orderBy + <code>__name__</code> tiebreak (FS-B8)</strong> — the query's sort is normalized to: explicit orderBy clauses, then an implicit order on each inequality-filtered field, then a final document-key (<code>__name__</code>) clause. Equal-valued docs sort deterministically by key; a <code>where('x','>',v)</code> with no explicit orderBy returns docs ordered by <code>x</code>. Mirrors <code>clones/.../core/query.ts:queryNormalizedOrderBy</code>. Pre-FS-B8 equal-valued docs were nondeterministic and inequality results came back in insertion order.</span></span></span></summary>
|
|
370
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:admin-compat/implicit-order-name.test.ts</code> (key tiebreak, snapshot-cursor disambiguation, implicit inequality order; verified failing pre-fix)</div></div>
|
|
371
|
+
</details>
|
|
372
|
+
<details class="compat-row" data-status="ok">
|
|
373
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><code>limit(n)</code> — caps result count</span></span></span></summary>
|
|
374
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
375
|
+
</details>
|
|
376
|
+
<details class="compat-row" data-status="diverged">
|
|
377
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior"><code>limitToLast(n)</code> — trailing n in ordered result (requires <code>orderBy</code>). Sandbox: the no-orderBy precondition throws a <code>FirestoreError</code> with <code>.code === 'invalid-argument'</code> (FS-B16; pre-fix plain <code>Error</code>s). Prod: the same precondition throws <code>.code === 'unimplemented'</code></span></span></span></summary>
|
|
378
|
+
<div class="compat-evidence"><div class="compat-probe">divergence, oracle-locked by <code>packages/conformance/observations/firestore/firestore-limittolast-preconditions.json</code>: prod's no-orderBy <code>limitToLast</code> throws code <code>unimplemented</code>, the sandbox throws <code>invalid-argument</code>. Trailing-window semantics with <code>orderBy</code> conform (observed <code>["b"]</code> matches). Both sides pinned in <code>oracle-conformance.test.ts</code>. Cursor composition + descending: <code>unit:upstream-query-probes.test.ts</code>. Cursor/empty-snapshot precondition codes remain per <code>unit:sandbox-target.test.ts</code> + <code>unit:admin-compat/cursors.test.ts</code> (verified failing pre-fix)</div></div>
|
|
379
|
+
</details>
|
|
380
|
+
<details class="compat-row" data-status="ok">
|
|
381
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior">Composite filters AND with other constraints — <code>query(coll, or(...), orderBy(...), limit(...))</code></span></span></span></summary>
|
|
382
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
383
|
+
</details>
|
|
384
|
+
<details class="compat-row" data-status="ok">
|
|
385
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior">Passing <code>orderBy</code> / <code>limit</code> into <code>or()</code> / <code>and()</code> → <code>TypeError</code></span></span></span></summary>
|
|
386
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
387
|
+
</details>
|
|
388
|
+
<details class="compat-row" data-status="ok">
|
|
389
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior">Zero-arg <code>or()</code> / <code>and()</code> → <code>TypeError</code></span></span></span></summary>
|
|
390
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
391
|
+
</details>
|
|
392
|
+
<details class="compat-row" data-status="ok">
|
|
393
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior">Chained queries re-tag for further constraints (<code>query(query(coll, where), orderBy)</code>)</span></span></span></summary>
|
|
394
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("chained queries are taggable")</div></div>
|
|
395
|
+
</details>
|
|
396
|
+
<details class="compat-row" data-status="diverged">
|
|
397
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><span class="compat-behavior">Index validation against <code>firestore.indexes.json</code> — sandbox uses <code>LocalEnvironment</code>'s lint pass; prod has its own server-side validation</span></span></span></summary>
|
|
398
|
+
<div class="compat-evidence"><div class="compat-probe">divergence: sandbox can mis-pass a query that prod would reject at the server with <code>failed-precondition</code> if no index exists</div></div>
|
|
399
|
+
</details>
|
|
400
|
+
</div>
|
|
401
|
+
|
|
402
|
+
## Cursor pagination — `startAt` / `startAfter` / `endAt` / `endBefore`
|
|
403
|
+
|
|
404
|
+
<div class="compat-list">
|
|
405
|
+
<details class="compat-row" data-status="ok">
|
|
406
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Cursor pagination</code><span class="compat-sub"><span class="compat-behavior"><code>startAt(...values)</code> — inclusive value cursor (one positional per <code>orderBy</code> clause)</span></span></span></summary>
|
|
407
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, oracle: <code>packages/conformance/observations/firestore/firestore-cursor-startat-inclusive.json</code> (5 seeded docs at pos=[1..5]; <code>query(c, orderBy('pos'), startAt(3))</code> returned exactly <code>[pos-3, pos-4, pos-5]</code> — the cursor doc IS included)</div></div>
|
|
408
|
+
</details>
|
|
409
|
+
<details class="compat-row" data-status="ok">
|
|
410
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Cursor pagination</code><span class="compat-sub"><span class="compat-behavior"><code>startAfter(...values)</code> — exclusive value cursor</span></span></span></summary>
|
|
411
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, oracle: <code>packages/conformance/observations/firestore/firestore-cursor-startafter-exclusive.json</code> (5 seeded docs at pos=[1..5]; <code>query(c, orderBy('pos'), startAfter(3))</code> returned exactly <code>[pos-4, pos-5]</code> — the cursor doc is EXCLUDED)</div></div>
|
|
412
|
+
</details>
|
|
413
|
+
<details class="compat-row" data-status="ok">
|
|
414
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Cursor pagination</code><span class="compat-sub"><span class="compat-behavior"><code>endAt(...values)</code> — inclusive end cursor</span></span></span></summary>
|
|
415
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, oracle: <code>packages/conformance/observations/firestore/firestore-cursor-endat-inclusive.json</code> (5 seeded docs at pos=[1..5]; <code>query(c, orderBy('pos'), endAt(3))</code> returned exactly <code>[pos-1, pos-2, pos-3]</code> — the cursor doc IS included)</div></div>
|
|
416
|
+
</details>
|
|
417
|
+
<details class="compat-row" data-status="ok">
|
|
418
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Cursor pagination</code><span class="compat-sub"><span class="compat-behavior"><code>endBefore(...values)</code> — exclusive end cursor</span></span></span></summary>
|
|
419
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, oracle: <code>packages/conformance/observations/firestore/firestore-cursor-endbefore-exclusive.json</code> (5 seeded docs at pos=[1..5]; <code>query(c, orderBy('pos'), endBefore(3))</code> returned exactly <code>[pos-1, pos-2]</code> — the cursor doc is EXCLUDED)</div></div>
|
|
420
|
+
</details>
|
|
421
|
+
<details class="compat-row" data-status="ok">
|
|
422
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Cursor pagination</code><span class="compat-sub"><span class="compat-behavior"><code>startAt(snapshot)</code> overload — extracts orderBy field values from the snapshot, positioning against the NORMALIZED orderBy (implicit <code>__name__</code>), so it disambiguates equal-valued docs and is <strong>legal without an explicit orderBy</strong> (FS-B8). A VALUE cursor with more values than explicit orderBy clauses throws <code>invalid-argument</code> ("Too many arguments").</span></span></span></summary>
|
|
423
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>unit:admin-compat/implicit-order-name.test.ts</code> (snapshot cursor w/o orderBy), <code>unit:admin-compat/cursors.test.ts</code> (value-cursor too-many-args throws with <code>.code</code>)</div></div>
|
|
424
|
+
</details>
|
|
425
|
+
<details class="compat-row" data-status="ok">
|
|
426
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Cursor pagination</code><span class="compat-sub"><span class="compat-behavior"><code>endAt(snapshot)</code> overload</span></span></span></summary>
|
|
427
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("endAt(snapshot) trims to-and-including the anchor")</div></div>
|
|
428
|
+
</details>
|
|
429
|
+
<details class="compat-row" data-status="ok">
|
|
430
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Cursor pagination</code><span class="compat-sub"><span class="compat-behavior"><code>startAfter + limit</code> — canonical pagination pattern</span></span></span></summary>
|
|
431
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
432
|
+
</details>
|
|
433
|
+
</div>
|
|
434
|
+
|
|
435
|
+
## Aggregates — `getCountFromServer` / `getAggregateFromServer` / `count` / `sum` / `average`
|
|
436
|
+
|
|
437
|
+
<div class="compat-list">
|
|
438
|
+
<details class="compat-row" data-status="ok">
|
|
439
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Aggregates</code><span class="compat-sub"><span class="compat-behavior"><code>getCountFromServer(query)</code> returns <code>{ data: () => ({ count: N }) }</code></span></span></span></summary>
|
|
440
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>; collectionGroup: <code>unit:upstream-write-aggregate-probes.test.ts</code></div></div>
|
|
441
|
+
</details>
|
|
442
|
+
<details class="compat-row" data-status="ok">
|
|
443
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Aggregates</code><span class="compat-sub"><span class="compat-behavior"><code>getCountFromServer</code> honors <code>where</code> filters</span></span></span></summary>
|
|
444
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
445
|
+
</details>
|
|
446
|
+
<details class="compat-row" data-status="ok">
|
|
447
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Aggregates</code><span class="compat-sub"><span class="compat-behavior"><code>getAggregateFromServer(query, spec)</code> returns <code>{ data: () => Record<alias, number|null> }</code></span></span></span></summary>
|
|
448
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>; collectionGroup + nested paths: <code>unit:upstream-write-aggregate-probes.test.ts</code></div></div>
|
|
449
|
+
</details>
|
|
450
|
+
<details class="compat-row" data-status="ok">
|
|
451
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Aggregates</code><span class="compat-sub"><span class="compat-behavior"><code>count()</code> / <code>sum(field)</code> / <code>average(field)</code> compose under one spec — <code>field</code> may be a dotted nested path</span></span></span></summary>
|
|
452
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>; nested <code>sum('metadata.pages')</code>: <code>unit:upstream-write-aggregate-probes.test.ts</code></div></div>
|
|
453
|
+
</details>
|
|
454
|
+
<details class="compat-row" data-status="ok">
|
|
455
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Aggregates</code><span class="compat-sub"><span class="compat-behavior"><code>average</code> returns <code>null</code> on empty input (matches JS SDK)</span></span></span></summary>
|
|
456
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
457
|
+
</details>
|
|
458
|
+
<details class="compat-row" data-status="diverged">
|
|
459
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">Aggregates</code><span class="compat-sub"><span class="compat-behavior">Aggregates count documents server-side without paying read cost per doc in prod; sandbox computes locally (no cost model)</span></span></span></summary>
|
|
460
|
+
<div class="compat-evidence"><div class="compat-probe">divergence: cost behavior differs, observable shape identical. Oracle-locked: <code>packages/conformance/observations/firestore/firestore-count-aggregate-shape.json</code> — <code>getCountFromServer().data()</code> returns <code>{ count: <number> }</code> (single key, no other fields). Empty query returns <code>count: 0</code> (not <code>null</code>/<code>undefined</code>); seeded 3 docs returns <code>count: 3</code>; filtered query honors the <code>where</code> constraint (<code>count: 2</code>).</div></div>
|
|
461
|
+
</details>
|
|
462
|
+
</div>
|
|
463
|
+
|
|
464
|
+
## `onSnapshot(refOrQuery, …)` — listeners
|
|
465
|
+
|
|
466
|
+
<div class="compat-list">
|
|
467
|
+
<details class="compat-row" data-status="ok">
|
|
468
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior"><code>onSnapshot(docRef, cb)</code> fires the initial snapshot <strong>asynchronously</strong> — never synchronously during the registering call. Prod empirically lands after a <code>setTimeout(0)</code> macrotask (the fire travels the network listener channel); the sandbox defers through its delivery scheduler (microtask). The matrix contract is "asynchronous, never during register", not "exactly the next microtask"</span></span></span></summary>
|
|
469
|
+
<div class="compat-evidence"><div class="compat-probe">Aligned via the listener delivery scheduler (<code>src/sandbox/firestore/local-environment.ts</code>): the initial fire is enqueued and delivered on a microtask, never during register — closing the divergence this row previously documented (the sandbox used to fire synchronously during registration; the sync-body tests were migrated to the flush/await idiom). Machine-checked against <code>packages/conformance/observations/firestore/firestore-row-80-onsnapshot-fires-initial.json</code> (<code>firstFireSyncDuringRegister: false</code>, fire count + contents) in <code>oracle-conformance.test.ts</code>; also <code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-onsnapshot</code> (bundled) + <code>playground:firestore-row-80-onsnapshot-fires-initial</code> (one-claim).</div></div>
|
|
470
|
+
</details>
|
|
471
|
+
<details class="compat-row" data-status="ok">
|
|
472
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior"><code>onSnapshot(query, cb)</code> fires on collection writes; <code>QuerySnapshot.docChanges()</code> reports <code>added</code> / <code>modified</code> / <code>removed</code> with <code>oldIndex</code> / <code>newIndex</code></span></span></span></summary>
|
|
473
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, oracle: <code>packages/conformance/observations/firestore/firestore-row-81-onsnapshot-query-fires-on-write.json</code> — listener on <code>query(coll)</code> saw 1 initial fire (empty, <code>size:0</code>), then one fire per write: <code>addDoc</code> → <code>size:1</code>, <code>setDoc(coll, 'known-id')</code> → <code>size:2</code>, <code>deleteDoc(addedRef)</code> → <code>size:1</code>. Total 4 fires, each reflecting the current collection state. Every collection-level write produces a distinct fire. (Note: this oracle used a <em>filterless</em> <code>query(coll)</code>, which masked FS-B2 — see row 81a.) Modular <code>docChanges</code> indexes: <code>unit:upstream-transform-txn-listener-probes.test.ts</code></div></div>
|
|
474
|
+
</details>
|
|
475
|
+
<details class="compat-row" data-status="ok">
|
|
476
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior"><strong>Filtered listeners honor <code>where</code> / <code>orderBy</code> / <code>limit</code> (FS-B2)</strong> — <code>onSnapshot(query(coll, where(…), orderBy(…), limit(…)), cb)</code> delivers the same membership as <code>getDocs(sameQuery)</code>: non-matching docs are excluded on the initial fire and on writes; ordering + limit are applied. Pre-FS-B2 the <code>SnapshotTarget</code> dropped all constraints and delivered the whole collection.</span></span></span></summary>
|
|
477
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:onsnapshot-query-constraints.test.ts</code> (filtered/ordered/limited listeners; verified failing pre-fix)</div></div>
|
|
478
|
+
</details>
|
|
479
|
+
<details class="compat-row" data-status="ok">
|
|
480
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior"><strong>Listener <code>.data()</code> matches <code>getDoc</code> shape (FS-B10)</strong> — the <code>onSnapshot</code> doc + query snapshot path runs the same read-path translation as <code>getDoc</code>/<code>getDocs</code>, so <code>snap.data().createdAt</code> is a compat <code>Timestamp</code> (<code>{seconds, nanoseconds}</code>), not the rules-internal wrapper (<code>{seconds, nanos}</code> + <code>typeName</code>, no <code>nanoseconds</code>). Pre-FS-B10 a listener leaked the internal shape while the single-doc read returned the compat shape.</span></span></span></summary>
|
|
481
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:simulator/listener-read-translation.test.ts</code> (doc + query listener Timestamp shape; verified failing pre-fix)</div></div>
|
|
482
|
+
</details>
|
|
483
|
+
<details class="compat-row" data-status="ok">
|
|
484
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior">Initial fire for a missing doc has <code>exists() === false</code> and <code>data() === undefined</code></span></span></span></summary>
|
|
485
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:firestore-onsnapshot</code> (bundled) + <code>playground:firestore-row-82-onsnapshot-missing-initial</code> (one-claim), oracle: <code>packages/conformance/observations/firestore/firestore-row-82-onsnapshot-missing-initial.json</code> — single initial fire with <code>snap.exists() === false</code>, <code>snap.data() === undefined</code>, <code>hasPendingWrites: false</code>, <code>fromCache: false</code>. The missing-doc fire is server-confirmed, not a cache speculation.</div></div>
|
|
486
|
+
</details>
|
|
487
|
+
<details class="compat-row" data-status="ok">
|
|
488
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior">Returned <code>Unsubscribe</code> stops further fires</span></span></span></summary>
|
|
489
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, oracle: <code>packages/conformance/observations/firestore/firestore-row-83-unsubscribe-stops-fires.json</code> — pre-unsubscribe write fired the listener (initial fire + write fire = 2 fires); after <code>unsub()</code>, a subsequent <code>setDoc</code> produced 0 additional fires (<code>postUnsubFireCount: 0</code>). Unsubscribe is durable; no fires arrive on the released callback after a 1.5s settle window.</div></div>
|
|
490
|
+
</details>
|
|
491
|
+
<details class="compat-row" data-status="ok">
|
|
492
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior">Observer object form <code>{next, error, complete}</code> works alongside the function form. <strong>Partial observers are accepted — <code>{ error: fn }</code> with no <code>next</code> registers and routes denials to <code>error</code> (FS-B14, <code>isPartialObserver</code> semantics from upstream <code>api/observer.ts</code>); pre-fix it was misrouted as <code>SnapshotListenOptions</code> and threw "missing next handler".</strong></span></span></span></summary>
|
|
493
|
+
<div class="compat-evidence"><div class="compat-probe">oracle: <code>packages/conformance/observations/firestore/firestore-row-84-observer-object-form.json</code> — registered two listeners on the same doc: one as a bare function <code>(snap) => …</code>, one as <code>{next, error, complete}</code>. Both fired once on initial (<code>{v:0}</code>) and again after a write (<code>{v:1}</code>), capturing identical data. <code>error</code> never fired (no rule denial), <code>complete</code> never fired on <code>unsub()</code> (Firebase treats unsubscribe as a teardown, not a "complete" signal — the observer's <code>complete</code> callback is reserved for terminal stream end, which <code>onSnapshot</code> does not produce). The two registration shapes are interchangeable for fire dispatch. <code>unit:onsnapshot-observer-discriminator.test.ts</code> (error-only observer; verified failing pre-fix)</div></div>
|
|
494
|
+
</details>
|
|
495
|
+
<details class="compat-row" data-status="ok">
|
|
496
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior"><code>SnapshotListenOptions.includeMetadataChanges</code> — one write yields the pending-write local echo (<code>hasPendingWrites: true</code>) then, for metadata listeners, the settled ack fire: default listener 2 fires, metadata listener 3</span></span></span></summary>
|
|
497
|
+
<div class="compat-evidence"><div class="compat-probe">Aligned via the listener delivery scheduler (<code>src/sandbox/firestore/local-environment.ts</code> + <code>snapshot-listeners.ts</code>): the write echo carries <code>hasPendingWrites: true</code> and <code>includeMetadataChanges</code> listeners receive the settled metadata-only ack, reproducing prod's recorded 2/3-fire sequences exactly. Machine-checked against <code>packages/conformance/observations/firestore/firestore-include-metadata-changes.json</code> in <code>oracle-conformance.test.ts</code> (fire counts and per-fire <code>hasPendingWrites</code> sequence asserted from the capture)</div></div>
|
|
498
|
+
</details>
|
|
499
|
+
<details class="compat-row" data-status="ok">
|
|
500
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior">Snapshot's <code>.ref</code> / <code>.docs[i].ref</code> are tagged so consumer code can pass them to follow-up ops</span></span></span></summary>
|
|
501
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
502
|
+
</details>
|
|
503
|
+
<details class="compat-row" data-status="ok">
|
|
504
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior">Sandbox-live: listener registered as alice keeps emitting alice's view after <code>setUser → bob</code> (identity frozen at subscribe)</span></span></span></summary>
|
|
505
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("listener registered as alice keeps emitting alice's view")</div></div>
|
|
506
|
+
</details>
|
|
507
|
+
<details class="compat-row" data-status="ok">
|
|
508
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior">Sandbox-live: listener registered as anonymous keeps firing after sign-in (anonymous → signed-in identity persists per listener)</span></span></span></summary>
|
|
509
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("listener registered as anonymous on /public keeps firing after sign-in")</div></div>
|
|
510
|
+
</details>
|
|
511
|
+
<details class="compat-row" data-status="ok">
|
|
512
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior">Snapshot's ref is usable in follow-up ops under the new user (the ref is live, the listener identity is frozen — distinct)</span></span></span></summary>
|
|
513
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("snapshot ref is usable in subsequent ops under the new user"), oracle: <code>packages/conformance/observations/firestore/firestore-row-89-snapshot-ref-usable.json</code> — captured <code>snap.ref</code> from a docRef listener's first fire and <code>snap.docs[0].ref</code> from a query listener's first fire; both refs round-trip via <code>getDoc</code> (returning the same data) and <code>setDoc</code> (writes succeed and a follow-up <code>getDoc</code> confirms the new payload). <code>snap.ref.path</code> equals the original <code>doc(coll, id).path</code>. Both snap-ref shapes are first-class refs in prod, matching sandbox's tagged-ref guarantee.</div></div>
|
|
514
|
+
</details>
|
|
515
|
+
<details class="compat-row" data-status="ok">
|
|
516
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">onSnapshot(refOrQuery, …)</code><span class="compat-sub"><span class="compat-behavior">Preview tree mounts the user's component exactly once per session load — no observer subscriptions leak across parallel <code>AppPreview</code> instances. Root cause: <code>PlaygroundPage</code> rendered both <code>WorkspacePanel</code>'s and the mobile <code>AppPanel</code>'s <code>AppPreview</code> unconditionally (the latter <code>md:hidden</code> on desktop but still mounted), producing two live preview trees subscribing in parallel. Fixed by gating <code>AppPanel</code> on <code>useIsMobile() && mobileTab === 'app'</code>.</span></span></span></summary>
|
|
517
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:preview-single-mount</code></div></div>
|
|
518
|
+
</details>
|
|
519
|
+
</div>
|
|
520
|
+
|
|
521
|
+
## `runTransaction(db, fn)`
|
|
522
|
+
|
|
523
|
+
<div class="compat-list">
|
|
524
|
+
<details class="compat-row" data-status="ok">
|
|
525
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">runTransaction(db, fn)</code><span class="compat-sub"><span class="compat-behavior">Atomic read-write — all reads in <code>fn</code> see a consistent snapshot, writes commit together</span></span></span></summary>
|
|
526
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-transaction</code>; get-missing/deleted + empty txn + nested update: <code>unit:upstream-transform-txn-listener-probes.test.ts</code></div></div>
|
|
527
|
+
</details>
|
|
528
|
+
<details class="compat-row" data-status="ok">
|
|
529
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">runTransaction(db, fn)</code><span class="compat-sub"><span class="compat-behavior">Identity is frozen at <code>runTransaction</code> start — mid-transaction <code>setUser</code> does NOT re-auth in-flight reads</span></span></span></summary>
|
|
530
|
+
<div class="compat-evidence"><div class="compat-probe">(documented invariant)</div></div>
|
|
531
|
+
</details>
|
|
532
|
+
<details class="compat-row" data-status="diverged">
|
|
533
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">runTransaction(db, fn)</code><span class="compat-sub"><span class="compat-behavior">Retry behavior — prod retries on contention up to 5 times; sandbox is single-threaded, no contention possible</span></span></span></summary>
|
|
534
|
+
<div class="compat-evidence"><div class="compat-probe">divergence: contention story not modeled; sandbox just runs once</div></div>
|
|
535
|
+
</details>
|
|
536
|
+
<details class="compat-row" data-status="ok">
|
|
537
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">runTransaction(db, fn)</code><span class="compat-sub"><span class="compat-behavior">Throws <code>FirebaseError('permission-denied')</code> on rule denial inside the transaction (the inner write's denial — not a generic <code>aborted</code>). Sandbox throws <code>FirestoreCompatError</code> with the same <code>code: 'permission-denied'</code></span></span></span></summary>
|
|
538
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> (writes-reject branch), oracle: <code>packages/conformance/observations/firestore/firestore-transaction-rules-denied-error.json</code> (prod throws <code>FirebaseError</code> with <code>code: 'permission-denied'</code>, NOT <code>aborted</code>; the inner callback ran once and the rules-rejected write surfaces as a regular permission-denied at commit)</div></div>
|
|
539
|
+
</details>
|
|
540
|
+
</div>
|
|
541
|
+
|
|
542
|
+
## `writeBatch(db)`
|
|
543
|
+
|
|
544
|
+
<div class="compat-list">
|
|
545
|
+
<details class="compat-row" data-status="ok">
|
|
546
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">writeBatch(db)</code><span class="compat-sub"><span class="compat-behavior"><code>batch.set</code> / <code>batch.update</code> / <code>batch.delete</code> queue mutations</span></span></span></summary>
|
|
547
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-batch</code></div></div>
|
|
548
|
+
</details>
|
|
549
|
+
<details class="compat-row" data-status="ok">
|
|
550
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">writeBatch(db)</code><span class="compat-sub"><span class="compat-behavior"><code>batch.commit()</code> applies all queued writes atomically — success path commits all queued mutations together; failure path (one write violating rules) rejects the <strong>whole</strong> batch with no partial application</span></span></span></summary>
|
|
551
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, oracle: <code>packages/conformance/observations/firestore/firestore-row-96-batch-commit-atomic.json</code> — success path: a batch with <code>set</code> (fresh doc), <code>update</code> (existing doc), and <code>delete</code> (existing doc) all land in a single commit (<code>allApplied: true</code>). Failure path: a batch with one write targeting a path <strong>outside</strong> <code>pyric_oracle/*</code> rejects with <code>code: 'permission-denied'</code> and leaves the would-have-set doc absent and the would-have-updated doc at its original value (<code>noPartialApply: true</code>) — atomicity verified end-to-end.</div></div>
|
|
552
|
+
</details>
|
|
553
|
+
<details class="compat-row" data-status="ok">
|
|
554
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">writeBatch(db)</code><span class="compat-sub"><span class="compat-behavior">Batch is tagged on construction and remains bound to the sandbox owner that created it</span></span></span></summary>
|
|
555
|
+
<div class="compat-evidence"><div class="compat-probe">(implementation invariant; cross-sandbox ownership is not directly probed)</div></div>
|
|
556
|
+
</details>
|
|
557
|
+
<details class="compat-row" data-status="ok">
|
|
558
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">writeBatch(db)</code><span class="compat-sub"><span class="compat-behavior">Batch identity is frozen at construction (per current implementation)</span></span></span></summary>
|
|
559
|
+
<div class="compat-evidence"><div class="compat-probe">(documented invariant)</div></div>
|
|
560
|
+
</details>
|
|
561
|
+
</div>
|
|
562
|
+
|
|
563
|
+
## Sentinels — `serverTimestamp` / `increment` / `arrayUnion` / `arrayRemove` / `deleteField` / `FieldValue` / `Timestamp`
|
|
564
|
+
|
|
565
|
+
<div class="compat-list">
|
|
566
|
+
<details class="compat-row" data-status="ok">
|
|
567
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><code>serverTimestamp()</code> resolves to a <code>Timestamp</code> after the write commits</span></span></span></summary>
|
|
568
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-sentinels</code> (bundled) + <code>playground:firestore-row-99-servertimestamp-resolves</code> (one-claim), oracle: <code>packages/conformance/observations/firestore/firestore-row-99-servertimestamp-resolves-to-timestamp.json</code> — <code>setDoc({at: serverTimestamp()})</code> then <code>getDoc</code> yields <code>at instanceof Timestamp === true</code>, <code>constructor.name === 'Timestamp'</code>, with both <code>.seconds</code> (number) and <code>.nanoseconds</code> (number) present.</div></div>
|
|
569
|
+
</details>
|
|
570
|
+
<details class="compat-row" data-status="ok">
|
|
571
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><code>increment(n)</code> atomically bumps a numeric field; <code>null</code>/missing field starts from 0</span></span></span></summary>
|
|
572
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-sentinels</code> (bundled) + <code>playground:firestore-row-100-increment-bumps-numeric</code> (one-claim), oracle: <code>packages/conformance/observations/firestore/firestore-row-100-increment-bumps-numeric.json</code> — <code>setDoc</code> with no <code>count</code> field then <code>updateDoc({count: increment(5)})</code> yields <code>count === 5</code> (starts from 0). Follow-up <code>increment(3)</code> → 8, then <code>increment(-2)</code> → 6 (negative deltas apply, increments accumulate). Merge-create + int↔double + batch-across-docs: <code>unit:upstream-transform-txn-listener-probes.test.ts</code></div></div>
|
|
573
|
+
</details>
|
|
574
|
+
<details class="compat-row" data-status="ok">
|
|
575
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><code>arrayUnion(...values)</code> de-dupes against existing members <strong>and</strong> against duplicate args within the same call</span></span></span></summary>
|
|
576
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-sentinels</code> (bundled) + <code>playground:firestore-row-101-arrayunion-dedupes</code> (one-claim), oracle: <code>packages/conformance/observations/firestore/firestore-row-101-arrayunion-dedupes.json</code> — <code>setDoc({tags: ['a','b']})</code> then <code>updateDoc({tags: arrayUnion('b','c')})</code> yields <code>['a','b','c']</code> (single <code>b</code>, not double). Follow-up <code>updateDoc({tags: arrayUnion('d','d','a')})</code> yields <code>['a','b','c','d']</code> — both inline duplicate args and existing-member duplicates are de-duped. Merge-path + object members: <code>unit:upstream-transform-txn-listener-probes.test.ts</code></div></div>
|
|
577
|
+
</details>
|
|
578
|
+
<details class="compat-row" data-status="ok">
|
|
579
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><code>arrayRemove(...values)</code> strips matching members; values not present in the array are silent no-ops</span></span></span></summary>
|
|
580
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-sentinels</code> (bundled) + <code>playground:firestore-row-102-arrayremove-strips</code> (one-claim), oracle: <code>packages/conformance/observations/firestore/firestore-row-102-arrayremove-strips.json</code> — <code>setDoc({tags: ['a','b','c']})</code> then <code>updateDoc({tags: arrayRemove('b','d')})</code> yields <code>['a','c']</code>: <code>'b'</code> removed, <code>'d'</code> (absent) was a silent no-op (no error). Merge-path: <code>unit:upstream-transform-txn-listener-probes.test.ts</code></div></div>
|
|
581
|
+
</details>
|
|
582
|
+
<details class="compat-row" data-status="ok">
|
|
583
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><code>deleteField()</code> removes a field on update — the field is fully absent from the returned data, not merely undefined-valued. Legal at the top level or via a <strong>dot-path</strong> (<code>{'a.b': deleteField()}</code> removes the nested leaf — FS-B5). <strong>Nested inside a map literal (<code>{a: {b: deleteField()}}</code>) it throws <code>invalid-argument</code> (FS-B13)</strong> instead of destroying the sibling map.</span></span></span></summary>
|
|
584
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:firestore-sentinels</code> (bundled) + <code>playground:firestore-row-103-deletefield-removes-field</code> (one-claim), oracle: <code>packages/conformance/observations/firestore/firestore-row-103-deletefield-removes-field.json</code> — <code>setDoc({keep:1, remove:2})</code> then <code>updateDoc({remove: deleteField()})</code> yields a doc whose <code>data()</code> has keys <code>['keep']</code> only, <code>keep === 1</code> preserved; <code>unit:admin-compat/nested-delete-field.test.ts</code> (nested → invalid-argument; dot-path + top-level still valid; verified failing pre-fix)</div></div>
|
|
585
|
+
</details>
|
|
586
|
+
<details class="compat-row" data-status="ok">
|
|
587
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><code>Timestamp</code> shape (<code>{seconds, nanoseconds}</code>) is identical between prod and sandbox — round-trips cleanly</span></span></span></summary>
|
|
588
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
589
|
+
</details>
|
|
590
|
+
<details class="compat-row" data-status="ok">
|
|
591
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><strong><code>Timestamp</code> nanos normalization + value API (FS-B12)</strong> — <code>fromMillis</code>/<code>fromDate</code>/<code>now</code> derive <code>nanoseconds</code> as <code>floor((ms - seconds<em>1000) </em> 1e6)</code> so it is always non-negative; <code>fromMillis(-500).toMillis()</code> round-trips to -500 (was -1500). The class ships <code>isEqual</code> / <code>toString</code> / <code>toJSON</code> / <code>valueOf</code>, mirroring <code>clones/.../lite-api/timestamp.ts</code>.</span></span></span></summary>
|
|
592
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:admin-compat/timestamp-api.test.ts</code> (negative-millis round-trip + value API; pre-fix lacked the methods and mis-normalized)</div></div>
|
|
593
|
+
</details>
|
|
594
|
+
<details class="compat-row" data-status="ok">
|
|
595
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><strong>Unified Timestamp storage (FS-B4)</strong> — a <code>Timestamp</code> written directly via the modular SDK (<code>setDoc({createdAt: Timestamp.now()})</code>) is stored as the same rules-internal <code>Timestamp</code> that <code>serverTimestamp()</code>/<code>Date</code> resolve to. Pre-FS-B4 a user-written <code>Timestamp</code> was the compat class only (not a <code>RulesValue</code>), so <code>request.resource.data.createdAt is timestamp</code> returned <strong>false</strong> for it while a <code>serverTimestamp()</code> write passed the same rule, and the two paths stored two different classes. A write-boundary converter now normalizes both.</span></span></span></summary>
|
|
596
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/sandbox-converters/user-timestamp.test.ts</code> (<code>is timestamp</code> passes for a user Timestamp; unified storage class; range-filter regression guard — verified failing pre-fix by removing the converter registration)</div></div>
|
|
597
|
+
</details>
|
|
598
|
+
<details class="compat-row" data-status="ok">
|
|
599
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><code>FieldValue</code> re-exported from <code>pyric-admin</code> (alias of <code>ChainFieldValue</code>)</span></span></span></summary>
|
|
600
|
+
<div class="compat-evidence"><div class="compat-probe">type-only smoke</div></div>
|
|
601
|
+
</details>
|
|
602
|
+
<details class="compat-row" data-status="ok">
|
|
603
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Sentinels</code><span class="compat-sub"><span class="compat-behavior"><strong>Sentinel overwrite on type mismatch (FS-B11)</strong> — <code>increment(n)</code> on a non-numeric (or absent) prior OVERWRITES using a base value of 0 (result <code>n</code>); <code>arrayUnion</code>/<code>arrayRemove</code> on a non-array prior coerce the base to <code>[]</code>. Pre-FS-B11 these threw and surfaced as <code>invalid-argument</code> denials. Mirrors <code>clones/.../model/transform_operation.ts</code> (<code>computeTransformOperationBaseValue</code>, <code>coercedFieldValuesArray</code>).</span></span></span></summary>
|
|
604
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:simulator/converters/fieldvalue.test.ts</code> (FS-B11 overwrite block + flipped unit/integration/batch cases; verified failing pre-fix)</div></div>
|
|
605
|
+
</details>
|
|
606
|
+
</div>
|
|
607
|
+
|
|
608
|
+
## Scalar types — `Bytes` / `GeoPoint` / `FieldPath` / `documentId`
|
|
609
|
+
|
|
610
|
+
<div class="compat-list">
|
|
611
|
+
<details class="compat-row" data-status="ok">
|
|
612
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Scalar types</code><span class="compat-sub"><span class="compat-behavior">The sandbox mirror owns compatible scalar constructors — <code>Bytes.fromUint8Array(...)</code>, <code>new GeoPoint(lat, lng)</code>, <code>new FieldPath(...)</code>, and <code>documentId()</code> — without importing <code>firebase/firestore</code></span></span></span></summary>
|
|
613
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> (constructibility + round trips), <code>package-edge:package-dependencies.test.ts</code></div></div>
|
|
614
|
+
</details>
|
|
615
|
+
<details class="compat-row" data-status="ok">
|
|
616
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Scalar types</code><span class="compat-sub"><span class="compat-behavior"><code>documentId()</code> works in <code>where(documentId(), …)</code> / <code>orderBy(documentId())</code> against the sandbox — string ids, DocumentReference operands, ranges, and id sort</span></span></span></summary>
|
|
617
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:upstream-query-probes.test.ts</code> (<code>documentId() filters + orderBy</code>); modular <code>where</code>/<code>orderBy</code> accept <code>FieldPath</code></div></div>
|
|
618
|
+
</details>
|
|
619
|
+
<details class="compat-row" data-status="ok">
|
|
620
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Scalar types</code><span class="compat-sub"><span class="compat-behavior"><code>FieldPath</code> (nested) works in queries against sandbox</span></span></span></summary>
|
|
621
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
622
|
+
</details>
|
|
623
|
+
<details class="compat-row" data-status="ok">
|
|
624
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Scalar types</code><span class="compat-sub"><span class="compat-behavior"><code>Bytes</code> round-trip through the sandbox wire encoder — <code>Bytes</code> written via <code>setDoc</code> reads back as a <code>Bytes</code> instance with the same base64 representation</span></span></span></summary>
|
|
625
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:packages/pyric/test/sandbox/firestore/wire-encoder-bytes-geopoint.test.ts</code> + <code>unit:packages/pyric/test/firestore/sandbox-target.test.ts</code> ("Bytes + GeoPoint round-trip"), oracle: <code>packages/conformance/observations/firestore/firestore-row-109-bytes-roundtrip.json</code> — <code>setDoc({payload: Bytes.fromUint8Array([1,2,3,4])})</code> then <code>getDoc</code> yields <code>payload instanceof Bytes === true</code>, <code>payload.constructor.name === 'Bytes'</code>, <code>payload.toBase64() === 'AQIDBA=='</code>, and <code>payload.toUint8Array()</code> returns <code>[1,2,3,4]</code> against blockingfun. The sandbox converter stores the rules <code>Bytes</code> wrapper; <code>pyric/firestore</code> finalizes reads into its locally owned <code>Bytes</code> class with the same observed methods and values.</div></div>
|
|
626
|
+
</details>
|
|
627
|
+
<details class="compat-row" data-status="ok">
|
|
628
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Scalar types</code><span class="compat-sub"><span class="compat-behavior"><code>GeoPoint</code> round-trip through the sandbox wire encoder — <code>GeoPoint</code> written via <code>setDoc</code> reads back as a <code>GeoPoint</code> instance with the same latitude / longitude</span></span></span></summary>
|
|
629
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:packages/pyric/test/sandbox/firestore/wire-encoder-bytes-geopoint.test.ts</code> + <code>unit:packages/pyric/test/firestore/sandbox-target.test.ts</code> ("Bytes + GeoPoint round-trip"), oracle: <code>packages/conformance/observations/firestore/firestore-row-110-geopoint-roundtrip.json</code> — <code>setDoc({loc: new GeoPoint(37.7749, -122.4194)})</code> then <code>getDoc</code> yields <code>loc instanceof GeoPoint === true</code>, <code>loc.constructor.name === 'GeoPoint'</code>, <code>loc.latitude === 37.7749</code>, <code>loc.longitude === -122.4194</code> against blockingfun. Sandbox storage uses the rules <code>LatLng</code> wrapper; <code>pyric/firestore</code> finalizes reads into its locally owned <code>GeoPoint</code> class.</div></div>
|
|
630
|
+
</details>
|
|
631
|
+
<details class="compat-row" data-status="ok">
|
|
632
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Scalar types</code><span class="compat-sub"><span class="compat-behavior">Vector value type (<code>vector()</code> + <code>VectorValue</code>) round-trip: a vector written via <code>setDoc</code> reads back as a <code>VectorValue</code> with the same components</span></span></span></summary>
|
|
633
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> ("Bytes + GeoPoint + VectorValue round-trip", top-level + nested). The locally owned <code>vector()</code> / <code>VectorValue</code> preserve Firebase's observable value shape; the sandbox converter stores the rules <code>Vector</code> wrapper and <code>pyric/firestore</code> finalizes reads back to <code>VectorValue</code>. Oracle observation to follow (cf. #109/#110). <strong>CLIENT surface only:</strong> the web SDK exposes <code>vector()</code> + <code>VectorValue</code> (read/write) but has NO <code>findNearest</code> and NO <code>FieldValue.vector</code>; vector SEARCH is admin/server-only (<code>firebase-admin</code> <code>Query</code>/<code>CollectionReference.findNearest</code> + <code>FieldValue.vector()</code>), out of scope for this client matrix; the admin surface is tracked in the design rationale.</div></div>
|
|
634
|
+
</details>
|
|
635
|
+
</div>
|
|
636
|
+
|
|
637
|
+
## Equality helpers — `refEqual` / `queryEqual` / `snapshotEqual`
|
|
638
|
+
|
|
639
|
+
<div class="compat-list">
|
|
640
|
+
<details class="compat-row" data-status="ok">
|
|
641
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Equality helpers</code><span class="compat-sub"><span class="compat-behavior"><code>refEqual(a, b)</code> — true when paths match under the same target</span></span></span></summary>
|
|
642
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
643
|
+
</details>
|
|
644
|
+
<details class="compat-row" data-status="ok">
|
|
645
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Equality helpers</code><span class="compat-sub"><span class="compat-behavior"><code>refEqual</code> is <code>true</code> for cross-flavor sandbox vs sandbox-live refs at the same path</span></span></span></summary>
|
|
646
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("refEqual returns true for live and frozen refs at the same path")</div></div>
|
|
647
|
+
</details>
|
|
648
|
+
<details class="compat-row" data-status="ok">
|
|
649
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Equality helpers</code><span class="compat-sub"><span class="compat-behavior"><code>refEqual</code> is <code>false</code> for refs at different paths</span></span></span></summary>
|
|
650
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code></div></div>
|
|
651
|
+
</details>
|
|
652
|
+
<details class="compat-row" data-status="ok">
|
|
653
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Equality helpers</code><span class="compat-sub"><span class="compat-behavior"><code>refEqual(sandboxRef, foreignRef)</code> throws <code>TypeError</code> — references not created by this sandbox mirror are unrecognized</span></span></span></summary>
|
|
654
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code> (foreign refs throw unrecognized-reference TypeError)</div></div>
|
|
655
|
+
</details>
|
|
656
|
+
<details class="compat-row" data-status="diverged">
|
|
657
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">Equality helpers</code><span class="compat-sub"><span class="compat-behavior"><code>queryEqual(a, b)</code> is identity-only in the sandbox mirror; production's untouched Firebase SDK uses structural equality</span></span></span></summary>
|
|
658
|
+
<div class="compat-evidence"><div class="compat-probe">divergence: sandbox does identity-only; prod does deep structural. Oracle-locked: <code>packages/conformance/observations/firestore/firestore-queryequal-structural.json</code> — two independently-built queries with the same <code>where('x','==',1)</code> constraint compare equal in prod (<code>sameQueryBuiltTwice: true</code>), confirming structural semantics. Common use case (caching the same returned query) works on both.</div></div>
|
|
659
|
+
</details>
|
|
660
|
+
<details class="compat-row" data-status="diverged">
|
|
661
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">Equality helpers</code><span class="compat-sub"><span class="compat-behavior"><code>snapshotEqual(a, b)</code>. Prod: returns a boolean — true on identity, false even for two fetches of the same data. Sandbox: <strong>throws</strong> (<code>unrecognized reference</code>) for sandbox-target snapshots instead of returning a boolean</span></span></span></summary>
|
|
662
|
+
<div class="compat-evidence"><div class="compat-probe">divergence, oracle-locked by <code>packages/conformance/observations/firestore/firestore-snapshotequal-structural.json</code> (<code>identity: true</code>, <code>twoFetchesSameData: false</code> — prod is identity-only, NOT structural; an earlier structural guess was corrected by the oracle). The sandbox routes both args through the ref-tagging path, which does not recognize sandbox <code>QuerySnapshot</code>s, so <code>snapshotEqual</code> throws rather than comparing. Both sides pinned in <code>oracle-conformance.test.ts</code>. Fix candidate: identity-compare sandbox snapshots before the ref-tagging dispatch.</div></div>
|
|
663
|
+
</details>
|
|
664
|
+
<details class="compat-row" data-status="ok">
|
|
665
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Equality helpers</code><span class="compat-sub"><span class="compat-behavior">Cross-flavor <code>refEqual</code> via <code>QuerySnapshot.docs[i].ref</code> works</span></span></span></summary>
|
|
666
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("cross-flavor refEqual via QuerySnapshot doc refs")</div></div>
|
|
667
|
+
</details>
|
|
668
|
+
</div>
|
|
669
|
+
|
|
670
|
+
## `connectFirestoreEmulator`
|
|
671
|
+
|
|
672
|
+
<div class="compat-list">
|
|
673
|
+
<details class="compat-row" data-status="ok">
|
|
674
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">connectFirestoreEmulator</code><span class="compat-sub"><span class="compat-behavior">No-op on sandbox-target handles (the sandbox already IS a local emulator)</span></span></span></summary>
|
|
675
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-target.test.ts</code></div></div>
|
|
676
|
+
</details>
|
|
677
|
+
<details class="compat-row" data-status="ok">
|
|
678
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">connectFirestoreEmulator</code><span class="compat-sub"><span class="compat-behavior">Production does not enter the mirror: inactive package resolution leaves Firebase's <code>connectFirestoreEmulator</code> implementation unchanged</span></span></span></summary>
|
|
679
|
+
<div class="compat-evidence"><div class="compat-probe"><code>node-register:register-child.test.ts</code> (inactive canonical Firestore is not rewritten)</div></div>
|
|
680
|
+
</details>
|
|
681
|
+
<details class="compat-row" data-status="ok">
|
|
682
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">connectFirestoreEmulator</code><span class="compat-sub"><span class="compat-behavior">The sandbox mirror accepts Firebase's <code>mockUserToken</code> option shape as an inert compatibility argument; production uses Firebase's untouched implementation</span></span></span></summary>
|
|
683
|
+
<div class="compat-evidence"><div class="compat-probe">type-only smoke</div></div>
|
|
684
|
+
</details>
|
|
685
|
+
</div>
|
|
686
|
+
|
|
687
|
+
## Offline / persistence / network family
|
|
688
|
+
|
|
689
|
+
`enableIndexedDbPersistence`, `enableMultiTabIndexedDbPersistence`,
|
|
690
|
+
`clearIndexedDbPersistence`, `enableNetwork`, `disableNetwork`, and
|
|
691
|
+
`waitForPendingWrites` are exported by the sandbox mirror so unchanged
|
|
692
|
+
application initialization code can run after package resolution selects
|
|
693
|
+
Pyric.
|
|
694
|
+
|
|
695
|
+
**Honest-mirror rationale**: the sandbox IS the backend, running
|
|
696
|
+
local-first with persistence on by default. There is no separate cache tier
|
|
697
|
+
to opt into and no network to gate. Each function resolves because its
|
|
698
|
+
promise is already true or is a documented no-op because the concept has no
|
|
699
|
+
local meaning. `disableNetwork` does not simulate an offline queue.
|
|
700
|
+
|
|
701
|
+
`terminate` maps to `Sandbox.dispose()` and therefore tears down the whole
|
|
702
|
+
sandbox rather than a Firestore-only slice. Production never enters these
|
|
703
|
+
implementations; inactive package resolution leaves Firebase unchanged.
|
|
704
|
+
|
|
705
|
+
## Offline / persistence / network family (continued)
|
|
706
|
+
|
|
707
|
+
<div class="compat-list">
|
|
708
|
+
<details class="compat-row" data-status="diverged">
|
|
709
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">enableIndexedDbPersistence</code><span class="compat-sub"><span class="compat-behavior">Resolves in the sandbox mirror — persistence is already the default; does not reject with <code>'failed-precondition'</code> when called after other ops (deliberately more lenient than the real SDK — no cache-init race to protect)</span></span></span></summary>
|
|
710
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/persistence-network.test.ts</code></div>
|
|
711
|
+
<div class="compat-note">no failed-precondition</div></div>
|
|
712
|
+
</details>
|
|
713
|
+
<details class="compat-row" data-status="diverged">
|
|
714
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">enableMultiTabIndexedDbPersistence</code><span class="compat-sub"><span class="compat-behavior">Resolves in the sandbox mirror — the SharedWorker path already is the one shared store every tab talks to</span></span></span></summary>
|
|
715
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/persistence-network.test.ts</code></div>
|
|
716
|
+
<div class="compat-note">no failed-precondition</div></div>
|
|
717
|
+
</details>
|
|
718
|
+
<details class="compat-row" data-status="ok">
|
|
719
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">clearIndexedDbPersistence</code><span class="compat-sub"><span class="compat-behavior">Maps to <code>Sandbox.clearPersistence()</code> — actually wipes the persisted blob (honest, not a no-op); already a no-op when persistence was never enabled</span></span></span></summary>
|
|
720
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/persistence-network.test.ts</code></div></div>
|
|
721
|
+
</details>
|
|
722
|
+
<details class="compat-row" data-status="diverged">
|
|
723
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">enableNetwork / disableNetwork</code><span class="compat-sub"><span class="compat-behavior">Resolve in the sandbox mirror — no network exists to toggle; writes issued while "disabled" still commit immediately (no offline queue is simulated)</span></span></span></summary>
|
|
724
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/persistence-network.test.ts</code></div>
|
|
725
|
+
<div class="compat-note">no offline queue</div></div>
|
|
726
|
+
</details>
|
|
727
|
+
<details class="compat-row" data-status="diverged">
|
|
728
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">waitForPendingWrites</code><span class="compat-sub"><span class="compat-behavior">Resolves immediately in the sandbox mirror — every accepted write is already committed locally by the time its own promise resolves, so there are never writes still pending a server round-trip</span></span></span></summary>
|
|
729
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/persistence-network.test.ts</code></div>
|
|
730
|
+
<div class="compat-note">always resolves; prod can hang offline</div></div>
|
|
731
|
+
</details>
|
|
732
|
+
<details class="compat-row" data-status="diverged">
|
|
733
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">terminate</code><span class="compat-sub"><span class="compat-behavior">Genuinely tears the sandbox target down by calling <code>Sandbox.dispose()</code>, which tears down listener registries on the sandbox's environment (idempotent, doesn't touch data). This differs from the real SDK in scope: <code>dispose()</code> operates on the whole <code>Sandbox</code>, not a Firestore-only slice, so if <code>pyric/database</code>/<code>pyric/storage</code> share the same <code>Sandbox</code> their listener registries are torn down too</span></span></span></summary>
|
|
734
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/terminate.test.ts</code></div>
|
|
735
|
+
<div class="compat-note">tears down the whole Sandbox, not a Firestore-only slice</div></div>
|
|
736
|
+
</details>
|
|
737
|
+
</div>
|
|
738
|
+
|
|
739
|
+
## Tier-1 cache-init + get-from-* family
|
|
740
|
+
|
|
741
|
+
`initializeFirestore`, the cache-factory tokens, the explicit cache/server
|
|
742
|
+
read variants, `setLogLevel`, and `onSnapshotsInSync` are exported from the
|
|
743
|
+
sandbox mirror so canonical application code remains import-compatible.
|
|
744
|
+
|
|
745
|
+
These are honest sandbox mappings, not production forwarding. Cache settings
|
|
746
|
+
are inert because persistence is already local; cache and server read variants
|
|
747
|
+
share the authoritative local read path; `setLogLevel` is a no-op; and
|
|
748
|
+
`onSnapshotsInSync` approximates local delivery settle. Inactive package
|
|
749
|
+
resolution leaves Firebase's production implementations unchanged.
|
|
750
|
+
|
|
751
|
+
## Tier-1 cache-init + get-from-* family (continued)
|
|
752
|
+
|
|
753
|
+
<div class="compat-list">
|
|
754
|
+
<details class="compat-row" data-status="diverged">
|
|
755
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">initializeFirestore</code><span class="compat-sub"><span class="compat-behavior">Delegates to sandbox <code>getFirestore(app)</code> and returns the same handle. Accepts the <code>settings</code> argument (so the explicit-init pattern doesn't crash at import) but no-ops the cache/network settings — persistence is always on</span></span></span></summary>
|
|
756
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/tier1-cache-init-align.test.ts</code></div>
|
|
757
|
+
<div class="compat-note">settings accepted but cache/network settings are no-ops</div></div>
|
|
758
|
+
</details>
|
|
759
|
+
<details class="compat-row" data-status="diverged">
|
|
760
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">persistentLocalCache / memoryLocalCache / persistentSingleTabManager / persistentMultipleTabManager / memoryEagerGarbageCollector / memoryLruGarbageCollector</code><span class="compat-sub"><span class="compat-behavior">Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure</span></span></span></summary>
|
|
761
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/tier1-cache-init-align.test.ts</code></div>
|
|
762
|
+
<div class="compat-note">inert config tokens; no cache tier to configure</div></div>
|
|
763
|
+
</details>
|
|
764
|
+
<details class="compat-row" data-status="ok">
|
|
765
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">getDocFromServer / getDocsFromServer</code><span class="compat-sub"><span class="compat-behavior">Delegates to <code>getDoc</code> / <code>getDocs</code> in the sandbox mirror — the sandbox store IS the authoritative source, so there is no separate server round-trip to force and no observable divergence from the default read</span></span></span></summary>
|
|
766
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/tier1-cache-init-align.test.ts</code></div></div>
|
|
767
|
+
</details>
|
|
768
|
+
<details class="compat-row" data-status="diverged">
|
|
769
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">getDocFromCache / getDocsFromCache</code><span class="compat-sub"><span class="compat-behavior">Delegates to <code>getDoc</code> / <code>getDocs</code> in the sandbox mirror. Real Firebase THROWS <code>'unavailable'</code> here on a genuine cache miss; pyric never misses — the local store always has the answer (or a non-existent snapshot) — so it never throws for that reason</span></span></span></summary>
|
|
770
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/tier1-cache-init-align.test.ts</code></div>
|
|
771
|
+
<div class="compat-note">never throws unavailable; sandbox has no cache miss</div></div>
|
|
772
|
+
</details>
|
|
773
|
+
<details class="compat-row" data-status="diverged">
|
|
774
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">setLogLevel</code><span class="compat-sub"><span class="compat-behavior">Accepted no-op — the sandbox has no modular-SDK-style logger to wire a level into; it uses host-level <code>console</code> logging directly, gated by <code>pyric dev</code>'s own flags, not this call</span></span></span></summary>
|
|
775
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/tier1-cache-init-align.test.ts</code></div>
|
|
776
|
+
<div class="compat-note">accepted no-op; no sandbox logger wired</div></div>
|
|
777
|
+
</details>
|
|
778
|
+
<details class="compat-row" data-status="diverged">
|
|
779
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">onSnapshotsInSync</code><span class="compat-sub"><span class="compat-behavior">Fires the callback once the current snapshot-delivery microtask queue settles — the closest honest approximation of "every active listener has delivered its latest state" available without a true cross-listener sync signal. Not scoped to real server round-trips like the real SDK's guarantee; scoped to local delivery only</span></span></span></summary>
|
|
780
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/tier1-cache-init-align.test.ts</code></div>
|
|
781
|
+
<div class="compat-note">approximated from local snapshot-delivery settle, not a true global in-sync signal</div></div>
|
|
782
|
+
</details>
|
|
783
|
+
</div>
|
|
784
|
+
|
|
785
|
+
## Rules engine (via `setRules` from `pyric/sandbox/firestore`)
|
|
786
|
+
|
|
787
|
+
Rules-engine behavior is technically `pyric-admin`'s `LocalEnvironment`,
|
|
788
|
+
but it's the most-tested surface for divergence — `request.auth`,
|
|
789
|
+
cross-doc reads via `get()`, data validation. These rows pin the
|
|
790
|
+
shape consumer code depends on.
|
|
791
|
+
|
|
792
|
+
<div class="compat-list">
|
|
793
|
+
<details class="compat-row" data-status="ok">
|
|
794
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior"><code>request.auth.uid</code> reads through to <code>sandbox.currentUser?.uid</code> on sandbox-live</span></span></summary>
|
|
795
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:auth-anonymous</code>, <code>playground:rules-cross-doc-get</code></div></div>
|
|
796
|
+
</details>
|
|
797
|
+
<details class="compat-row" data-status="ok">
|
|
798
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior"><code>request.auth == null</code> when sandbox.currentUser is null (anonymous path)</span></span></summary>
|
|
799
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:sandbox-live-identity.test.ts</code> ("anonymous fallback")</div></div>
|
|
800
|
+
</details>
|
|
801
|
+
<details class="compat-row" data-status="ok">
|
|
802
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior">Cross-doc <code>get(/databases/$(database)/documents/...)</code> in rules works under sandbox; <code>get()</code> of a <strong>missing</strong> doc ERRORS (guard with <code>exists()</code>), and <code>get(p).id</code> / <code>get(p).__name__</code> expose the doc identity (RULES-B8)</span></span></summary>
|
|
803
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:rules-cross-doc-get</code>, <code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B8 block)</div></div>
|
|
804
|
+
</details>
|
|
805
|
+
<details class="compat-row" data-status="ok">
|
|
806
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior"><code>request.resource.data.<field></code> field validation in rules works under sandbox; an <strong>undefined</strong> field read ERRORS (deny), it does NOT read as null (RULES-B2) — guard with <code>'f' in data</code> / <code>data.get('f', d)</code></span></span></summary>
|
|
807
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:rules-data-validation</code>, <code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B2 block)</div></div>
|
|
808
|
+
</details>
|
|
809
|
+
<details class="compat-row" data-status="ok">
|
|
810
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior"><code>resource.data.<field></code> (existing doc on writes) works under sandbox; undefined-field reads ERROR (RULES-B2)</span></span></summary>
|
|
811
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:rules-resource-data-field</code>, <code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B2 block)</div></div>
|
|
812
|
+
</details>
|
|
813
|
+
<details class="compat-row" data-status="ok">
|
|
814
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior">Custom claims in <code>request.auth.token.<claim></code></span></span></summary>
|
|
815
|
+
<div class="compat-evidence"><div class="compat-probe"><code>playground:rules-custom-claims</code></div></div>
|
|
816
|
+
</details>
|
|
817
|
+
<details class="compat-row" data-status="ok">
|
|
818
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior">Tri-state error semantics: DOTTED field access of a missing key (<code>resource.data.typo</code>), access on null/undefined, undefined variables, and <code>get()</code>-of-missing ERROR → deny; <code>&&</code>/<code>||</code> absorb operand errors <strong>commutatively</strong> (CEL: <code>error || true</code> → true, <code>error && false</code> → false). NOTE: DYNAMIC index access <code>data[expr]</code> stays null-on-miss (the documented may-be-absent-lookup idiom; only dotted access is doc-confirmed to error). (RULES-B2/B3/B8)</span></span></summary>
|
|
819
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B2 / RULES-B3 / RULES-B8 blocks)</div></div>
|
|
820
|
+
</details>
|
|
821
|
+
<details class="compat-row" data-status="ok">
|
|
822
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior"><code>matches()</code> is a <strong>full-string</strong> anchored RE2 test; <code>replace()</code>/<code>split()</code> take regexes (<code>replace</code> = all occurrences) (RULES-B4)</span></span></summary>
|
|
823
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B4 block)</div></div>
|
|
824
|
+
</details>
|
|
825
|
+
<details class="compat-row" data-status="ok">
|
|
826
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior">No JS prototype-chain leakage: <code>'toString' in data</code> → false, <code>data.constructor</code> errors; <code>in</code>/<code>hasAll</code>/<code>get</code> use own keys only (RULES-B7)</span></span></summary>
|
|
827
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B7 block)</div></div>
|
|
828
|
+
</details>
|
|
829
|
+
<details class="compat-row" data-status="ok">
|
|
830
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior">Type-strict operators: <code>+</code> requires matching operand types (<code>'a' + 1</code> errors; <code>[1]+[2]</code> concatenates); ordered compares (<code>< > <= >=</code>) error across types; list membership uses value equality; <code>is map</code> excludes MapDiff/Set (RULES-B6 partial / B9 / B12 partial)</span></span></summary>
|
|
831
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B6 / B9 / B12 blocks)</div></div>
|
|
832
|
+
</details>
|
|
833
|
+
<details class="compat-row" data-status="ok">
|
|
834
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior"><code>FirestoreSet</code> VALUE equality: <code>diff.addedKeys() == [uid].toSet()</code> compares set contents (order-insensitive); <code>set == list</code> is false, not an error (RULES-B13). Pre-fix, ANY two sets compared EQUAL (generic-object deep-equals saw no enumerable keys) — a false-PERMISSIVE divergence found by joining validation</span></span></summary>
|
|
835
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:rules/simulator/set-equality.test.ts</code>; live validation: 10/10 both engines</div></div>
|
|
836
|
+
</details>
|
|
837
|
+
<details class="compat-row" data-status="ok">
|
|
838
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior"><code>update</code> exposes <code>request.resource.data</code> / <code>getAfter()</code> as the existing doc <strong>merged</strong> with the payload via the <code>writeMode: { kind: 'update' }</code> path (the agent-facing <code>simulate()</code> opt-in); a sparse no-writeMode payload that drops a field now ERRORS on that field (RULES-B2) rather than silently reading null (RULES-B10)</span></span></summary>
|
|
839
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:rules/simulator/handler.test.ts</code> (RULES-B10 block)</div></div>
|
|
840
|
+
</details>
|
|
841
|
+
<details class="compat-row" data-status="ok">
|
|
842
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior">Int/float distinction (<code>1.5 is int</code>→false, <code>1 is float</code>→false, <code>1.0 is float</code>→true) + integer division (<code>10 / 4 == 2</code>) + int div/mod-by-zero ERRORS (RULES-B5); strict <code>int('12abc')</code>/<code>float('abc')</code>/<code>bool('false')</code>/<code>bool('yes')</code> parsing (RULES-B6 rest); <code>string(1.0)</code>→"1.0" (RULES-B12 rest)</span></span></summary>
|
|
843
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B5 + "RULES-B6 remainder" blocks); <code>unit:rules/simulator/handler.test.ts</code> ("RULES-B5 end-to-end" block)</div></div>
|
|
844
|
+
</details>
|
|
845
|
+
<details class="compat-row" data-status="diverged">
|
|
846
|
+
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><span class="compat-behavior">DEFERRED sub-items of row 138: strict bool in <code>&&</code>/<code>||</code>/ternary (<code>1 && true</code> should error) — corpus-coupled, needs emulator; a FLOAT stored in JSON test-data reads as int (<code>data.x is float</code>→false; prod uses the stored Firestore type tag) — needs a <code>__type:'float'</code> test-data revive marker; <code>resource</code>-null-on-create (RULES-B12 rest)</span></span></summary>
|
|
847
|
+
<div class="compat-evidence"><div class="compat-probe">DEFERRED — see the design rationale (limitation + sub-items); strict-bool also in <code>step-07</code>.</div></div>
|
|
848
|
+
</details>
|
|
849
|
+
<details class="compat-row" data-status="ok">
|
|
850
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior">Query-proof EVALUATION — the rules-side decision ("rules are not filters"): given a <code>list</code> rule + query constraints, decide provable-or-reject (a doc-dependent rule like <code>resource.data.visibility == 'public'</code> is provable ONLY with a matching <code>where('visibility','==','public')</code>; otherwise the whole query is rejected) (RULES-B11 rules-side)</span></span></summary>
|
|
851
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:rules/simulator/query-proof.test.ts</code></div></div>
|
|
852
|
+
</details>
|
|
853
|
+
<details class="compat-row" data-status="ok">
|
|
854
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><span class="compat-behavior">Query-proof ENFORCEMENT wiring — <code>silentReadCollection</code> + <code>readQueryCandidates</code> call <code>evaluateQueryProof</code> (via <code>sandbox/firestore/list-query-proof.ts</code>) instead of the per-doc silent-omission filter; structured <code>where</code>/<code>limit</code>/<code>orderBy</code> constraints are threaded from <code>QueryImpl.structuredConstraints()</code> through both the one-shot (<code>getDocs</code>/aggregate) and listener (<code>SnapshotTarget</code> applier <code>.structured</code>) paths, and <code>request.query.{limit,offset,orderBy}</code> is populated on list test cases (RULES-B11 cross-file)</span></span></summary>
|
|
855
|
+
<div class="compat-evidence"><div class="compat-probe"><code>unit:firestore/query-proof-enforcement.test.ts</code> (both paths; verified failing pre-fix); prover scope caveat: row 24c</div></div>
|
|
856
|
+
</details>
|
|
857
|
+
</div>
|
|
858
|
+
|
|
859
|
+
## Deny-list (intentionally not mirrored)
|
|
860
|
+
|
|
861
|
+
These Firebase exports have no honest sandbox equivalent and remain outside the mirror: persistent-cache index managers and mutation functions, `CACHE_SIZE_UNLIMITED`, `setIndexConfiguration`, `loadBundle`, and `namedQuery`. Production still receives them from the untouched Firebase SDK.
|
|
862
|
+
|
|
863
|
+
## Evidence and remaining gaps
|
|
864
|
+
|
|
865
|
+
Frozen production observations remain the answer key for error identity, auto-id format, aggregates, listener metadata, scalar round trips, and equality semantics. This repair does not edit those observations or change any row status, numerator, or denominator.
|
|
866
|
+
|
|
867
|
+
The principal documented divergences remain error class identity, auto-id format, index validation, aggregate cost, listener metadata, transaction contention, and structural `queryEqual`.
|
|
868
|
+
|
|
869
|
+
The Firestore unit suite covers the sandbox surface. Canonical Node-register and Vite tests cover package selection, while the compiled-isolation test proves the sandbox artifact has no `firebase/firestore` dependency.
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
## Current gaps
|
|
873
|
+
|
|
874
|
+
### Documented divergences
|
|
875
|
+
|
|
876
|
+
Known differences between Pyric and production Firebase. Each remains tracked as a non-conforming row.
|
|
877
|
+
|
|
878
|
+
<div class="compat-list compat-list--plain">
|
|
879
|
+
<div class="compat-row">
|
|
880
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">getDoc(ref)</code><span class="compat-sub">Rules denial throws <code>SandboxError('permission-denied', …)</code> on sandbox; <code>FirebaseError('permission-denied')</code> on prod</span></span></div>
|
|
881
|
+
</div>
|
|
882
|
+
<div class="compat-row">
|
|
883
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">getDocs(query)</code><span class="compat-sub">Query-proof <strong>prover scope is conservative</strong> — only top-level AND-conjunct <code>resource.data.<field> == <literal></code> predicates (with <code>request.auth.uid</code> pinned to the caller) are dischargeable by <code>where(field, '==', value)</code>. Disjunctions over doc data, inequality/range proofs (<code>resource.data.score > 10</code> + <code>where('score','>',10)</code>), <code>in</code>-operand proofs, and nested-path predicates conservatively DENY the whole query where production's prover may allow it. Never a false ALLOW — the conservative direction prod also takes for unprovable queries.</span></span></div>
|
|
884
|
+
</div>
|
|
885
|
+
<div class="compat-row">
|
|
886
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">addDoc(coll, data)</code><span class="compat-sub">Auto-id format — prod uses 20-char base64-ish IDs; sandbox uses <code>pyric-admin</code>'s auto-id (also opaque, distinct format)</span></span></div>
|
|
887
|
+
</div>
|
|
888
|
+
<div class="compat-row">
|
|
889
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub"><code>limitToLast(n)</code> — trailing n in ordered result (requires <code>orderBy</code>). Sandbox: the no-orderBy precondition throws a <code>FirestoreError</code> with <code>.code === 'invalid-argument'</code> (FS-B16; pre-fix plain <code>Error</code>s). Prod: the same precondition throws <code>.code === 'unimplemented'</code></span></span></div>
|
|
890
|
+
</div>
|
|
891
|
+
<div class="compat-row">
|
|
892
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">Query construction</code><span class="compat-sub">Index validation against <code>firestore.indexes.json</code> — sandbox uses <code>LocalEnvironment</code>'s lint pass; prod has its own server-side validation</span></span></div>
|
|
893
|
+
</div>
|
|
894
|
+
<div class="compat-row">
|
|
895
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">Aggregates</code><span class="compat-sub">Aggregates count documents server-side without paying read cost per doc in prod; sandbox computes locally (no cost model)</span></span></div>
|
|
896
|
+
</div>
|
|
897
|
+
<div class="compat-row">
|
|
898
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">runTransaction(db, fn)</code><span class="compat-sub">Retry behavior — prod retries on contention up to 5 times; sandbox is single-threaded, no contention possible</span></span></div>
|
|
899
|
+
</div>
|
|
900
|
+
<div class="compat-row">
|
|
901
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">Equality helpers</code><span class="compat-sub"><code>queryEqual(a, b)</code> is identity-only in the sandbox mirror; production's untouched Firebase SDK uses structural equality</span></span></div>
|
|
902
|
+
</div>
|
|
903
|
+
<div class="compat-row">
|
|
904
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">Equality helpers</code><span class="compat-sub"><code>snapshotEqual(a, b)</code>. Prod: returns a boolean — true on identity, false even for two fetches of the same data. Sandbox: <strong>throws</strong> (<code>unrecognized reference</code>) for sandbox-target snapshots instead of returning a boolean</span></span></div>
|
|
905
|
+
</div>
|
|
906
|
+
<div class="compat-row">
|
|
907
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">enableIndexedDbPersistence</code><span class="compat-sub">Resolves in the sandbox mirror — persistence is already the default; does not reject with <code>'failed-precondition'</code> when called after other ops (deliberately more lenient than the real SDK — no cache-init race to protect)</span></span></div>
|
|
908
|
+
</div>
|
|
909
|
+
<div class="compat-row">
|
|
910
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">enableMultiTabIndexedDbPersistence</code><span class="compat-sub">Resolves in the sandbox mirror — the SharedWorker path already is the one shared store every tab talks to</span></span></div>
|
|
911
|
+
</div>
|
|
912
|
+
<div class="compat-row">
|
|
913
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">enableNetwork / disableNetwork</code><span class="compat-sub">Resolve in the sandbox mirror — no network exists to toggle; writes issued while "disabled" still commit immediately (no offline queue is simulated)</span></span></div>
|
|
914
|
+
</div>
|
|
915
|
+
<div class="compat-row">
|
|
916
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">waitForPendingWrites</code><span class="compat-sub">Resolves immediately in the sandbox mirror — every accepted write is already committed locally by the time its own promise resolves, so there are never writes still pending a server round-trip</span></span></div>
|
|
917
|
+
</div>
|
|
918
|
+
<div class="compat-row">
|
|
919
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">terminate</code><span class="compat-sub">Genuinely tears the sandbox target down by calling <code>Sandbox.dispose()</code>, which tears down listener registries on the sandbox's environment (idempotent, doesn't touch data). This differs from the real SDK in scope: <code>dispose()</code> operates on the whole <code>Sandbox</code>, not a Firestore-only slice, so if <code>pyric/database</code>/<code>pyric/storage</code> share the same <code>Sandbox</code> their listener registries are torn down too</span></span></div>
|
|
920
|
+
</div>
|
|
921
|
+
<div class="compat-row">
|
|
922
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">initializeFirestore</code><span class="compat-sub">Delegates to sandbox <code>getFirestore(app)</code> and returns the same handle. Accepts the <code>settings</code> argument (so the explicit-init pattern doesn't crash at import) but no-ops the cache/network settings — persistence is always on</span></span></div>
|
|
923
|
+
</div>
|
|
924
|
+
<div class="compat-row">
|
|
925
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">persistentLocalCache / memoryLocalCache / persistentSingleTabManager / persistentMultipleTabManager / memoryEagerGarbageCollector / memoryLruGarbageCollector</code><span class="compat-sub">Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure</span></span></div>
|
|
926
|
+
</div>
|
|
927
|
+
<div class="compat-row">
|
|
928
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">getDocFromCache / getDocsFromCache</code><span class="compat-sub">Delegates to <code>getDoc</code> / <code>getDocs</code> in the sandbox mirror. Real Firebase THROWS <code>'unavailable'</code> here on a genuine cache miss; pyric never misses — the local store always has the answer (or a non-existent snapshot) — so it never throws for that reason</span></span></div>
|
|
929
|
+
</div>
|
|
930
|
+
<div class="compat-row">
|
|
931
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">setLogLevel</code><span class="compat-sub">Accepted no-op — the sandbox has no modular-SDK-style logger to wire a level into; it uses host-level <code>console</code> logging directly, gated by <code>pyric dev</code>'s own flags, not this call</span></span></div>
|
|
932
|
+
</div>
|
|
933
|
+
<div class="compat-row">
|
|
934
|
+
<div class="compat-line"><span class="compat-main"><code class="compat-api">onSnapshotsInSync</code><span class="compat-sub">Fires the callback once the current snapshot-delivery microtask queue settles — the closest honest approximation of "every active listener has delivered its latest state" available without a true cross-listener sync signal. Not scoped to real server round-trips like the real SDK's guarantee; scoped to local delivery only</span></span></div>
|
|
935
|
+
</div>
|
|
936
|
+
<div class="compat-row">
|
|
937
|
+
<div class="compat-line"><span class="compat-main"><span class="compat-behavior">DEFERRED sub-items of row 138: strict bool in <code>&&</code>/<code>||</code>/ternary (<code>1 && true</code> should error) — corpus-coupled, needs emulator; a FLOAT stored in JSON test-data reads as int (<code>data.x is float</code>→false; prod uses the stored Firestore type tag) — needs a <code>__type:'float'</code> test-data revive marker; <code>resource</code>-null-on-create (RULES-B12 rest)</span></span></div>
|
|
938
|
+
</div>
|
|
939
|
+
</div>
|