pyric-tools 0.1.0-alpha.7
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/README.md +125 -0
- package/dist/auth/domains/handler.d.ts +6 -0
- package/dist/auth/domains/handler.d.ts.map +1 -0
- package/dist/auth/domains/handler.js +75 -0
- package/dist/auth/domains/handler.js.map +1 -0
- package/dist/auth/domains/spec.d.ts +25 -0
- package/dist/auth/domains/spec.d.ts.map +1 -0
- package/dist/auth/domains/spec.js +6 -0
- package/dist/auth/domains/spec.js.map +1 -0
- package/dist/auth/index.d.ts +34 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +30 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/mapper.d.ts +5 -0
- package/dist/auth/mapper.d.ts.map +1 -0
- package/dist/auth/mapper.js +49 -0
- package/dist/auth/mapper.js.map +1 -0
- package/dist/auth/provider/handler.d.ts +9 -0
- package/dist/auth/provider/handler.d.ts.map +1 -0
- package/dist/auth/provider/handler.js +128 -0
- package/dist/auth/provider/handler.js.map +1 -0
- package/dist/auth/provider/spec.d.ts +29 -0
- package/dist/auth/provider/spec.d.ts.map +1 -0
- package/dist/auth/provider/spec.js +12 -0
- package/dist/auth/provider/spec.js.map +1 -0
- package/dist/auth/resolver.d.ts +16 -0
- package/dist/auth/resolver.d.ts.map +1 -0
- package/dist/auth/resolver.js +32 -0
- package/dist/auth/resolver.js.map +1 -0
- package/dist/auth/tools.d.ts +23 -0
- package/dist/auth/tools.d.ts.map +1 -0
- package/dist/auth/tools.js +71 -0
- package/dist/auth/tools.js.map +1 -0
- package/dist/auth/types.d.ts +37 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +17 -0
- package/dist/auth/types.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 +430 -0
- package/dist/bridge/client/bridge.js.map +1 -0
- package/dist/bridge/client/dispatch.d.ts +49 -0
- package/dist/bridge/client/dispatch.d.ts.map +1 -0
- package/dist/bridge/client/dispatch.js +103 -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 +228 -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 +165 -0
- package/dist/bridge/server/bridge.d.ts.map +1 -0
- package/dist/bridge/server/bridge.js +410 -0
- package/dist/bridge/server/bridge.js.map +1 -0
- package/dist/bridge/server/confirm-policy.d.ts +56 -0
- package/dist/bridge/server/confirm-policy.d.ts.map +1 -0
- package/dist/bridge/server/confirm-policy.js +107 -0
- package/dist/bridge/server/confirm-policy.js.map +1 -0
- package/dist/bridge/server/confirm-prompt.d.ts +73 -0
- package/dist/bridge/server/confirm-prompt.d.ts.map +1 -0
- package/dist/bridge/server/confirm-prompt.js +199 -0
- package/dist/bridge/server/confirm-prompt.js.map +1 -0
- package/dist/bridge/server/confirm.d.ts +92 -0
- package/dist/bridge/server/confirm.d.ts.map +1 -0
- package/dist/bridge/server/confirm.js +210 -0
- package/dist/bridge/server/confirm.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 +132 -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 +42 -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.d.ts +33 -0
- package/dist/bridge/server/mcp.d.ts.map +1 -0
- package/dist/bridge/server/mcp.js +159 -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 +102 -0
- package/dist/bridge/server/standalone.d.ts.map +1 -0
- package/dist/bridge/server/standalone.js +352 -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 +79 -0
- package/dist/bridge/server/tool-metadata.js.map +1 -0
- package/dist/bridge/server.d.ts +25 -0
- package/dist/bridge/server.d.ts.map +1 -0
- package/dist/bridge/server.js +23 -0
- package/dist/bridge/server.js.map +1 -0
- package/dist/cli/auth.d.ts +37 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +119 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/database-rules.d.ts +25 -0
- package/dist/cli/database-rules.d.ts.map +1 -0
- package/dist/cli/database-rules.js +215 -0
- package/dist/cli/database-rules.js.map +1 -0
- package/dist/cli/deploy-progress.d.ts +35 -0
- package/dist/cli/deploy-progress.d.ts.map +1 -0
- package/dist/cli/deploy-progress.js +69 -0
- package/dist/cli/deploy-progress.js.map +1 -0
- package/dist/cli/deploy.d.ts +81 -0
- package/dist/cli/deploy.d.ts.map +1 -0
- package/dist/cli/deploy.js +413 -0
- package/dist/cli/deploy.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 +227 -0
- package/dist/cli/dev-runner.js.map +1 -0
- package/dist/cli/discover.d.ts +47 -0
- package/dist/cli/discover.d.ts.map +1 -0
- package/dist/cli/discover.js +77 -0
- package/dist/cli/discover.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/index.d.ts +55 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +500 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-templates.d.ts +37 -0
- package/dist/cli/init-templates.d.ts.map +1 -0
- package/dist/cli/init-templates.js +638 -0
- package/dist/cli/init-templates.js.map +1 -0
- package/dist/cli/init.d.ts +124 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +423 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/login.d.ts +18 -0
- package/dist/cli/login.d.ts.map +1 -0
- package/dist/cli/login.js +59 -0
- package/dist/cli/login.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 +126 -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 +40 -0
- package/dist/cli/rules.d.ts.map +1 -0
- package/dist/cli/rules.js +162 -0
- package/dist/cli/rules.js.map +1 -0
- package/dist/cli/scope.d.ts +38 -0
- package/dist/cli/scope.d.ts.map +1 -0
- package/dist/cli/scope.js +63 -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 +685 -0
- package/dist/cli/serve.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/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/authorize.d.ts +22 -0
- package/dist/credentials/core/authorize.d.ts.map +1 -0
- package/dist/credentials/core/authorize.js +39 -0
- package/dist/credentials/core/authorize.js.map +1 -0
- package/dist/credentials/core/client.d.ts +14 -0
- package/dist/credentials/core/client.d.ts.map +1 -0
- package/dist/credentials/core/client.js +13 -0
- package/dist/credentials/core/client.js.map +1 -0
- package/dist/credentials/core/exchange.d.ts +24 -0
- package/dist/credentials/core/exchange.d.ts.map +1 -0
- package/dist/credentials/core/exchange.js +46 -0
- package/dist/credentials/core/exchange.js.map +1 -0
- package/dist/credentials/core/flow.d.ts +15 -0
- package/dist/credentials/core/flow.d.ts.map +1 -0
- package/dist/credentials/core/flow.js +40 -0
- package/dist/credentials/core/flow.js.map +1 -0
- package/dist/credentials/core/from-user-credential.d.ts +3 -0
- package/dist/credentials/core/from-user-credential.d.ts.map +1 -0
- package/dist/credentials/core/from-user-credential.js +19 -0
- package/dist/credentials/core/from-user-credential.js.map +1 -0
- package/dist/credentials/core/scopes.d.ts +26 -0
- package/dist/credentials/core/scopes.d.ts.map +1 -0
- package/dist/credentials/core/scopes.js +32 -0
- package/dist/credentials/core/scopes.js.map +1 -0
- package/dist/credentials/core/types.d.ts +72 -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/index.d.ts +14 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +13 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/node/ensure-scope.d.ts +29 -0
- package/dist/credentials/node/ensure-scope.d.ts.map +1 -0
- package/dist/credentials/node/ensure-scope.js +42 -0
- package/dist/credentials/node/ensure-scope.js.map +1 -0
- package/dist/credentials/node/file-store.d.ts +4 -0
- package/dist/credentials/node/file-store.d.ts.map +1 -0
- package/dist/credentials/node/file-store.js +52 -0
- package/dist/credentials/node/file-store.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 +60 -0
- package/dist/credentials/node/from-adc.js.map +1 -0
- package/dist/credentials/node/index.d.ts +10 -0
- package/dist/credentials/node/index.d.ts.map +1 -0
- package/dist/credentials/node/index.js +10 -0
- package/dist/credentials/node/index.js.map +1 -0
- package/dist/credentials/node/loopback-authorizer.d.ts +12 -0
- package/dist/credentials/node/loopback-authorizer.d.ts.map +1 -0
- package/dist/credentials/node/loopback-authorizer.js +61 -0
- package/dist/credentials/node/loopback-authorizer.js.map +1 -0
- package/dist/credentials/node/resolve-local-token.d.ts +20 -0
- package/dist/credentials/node/resolve-local-token.d.ts.map +1 -0
- package/dist/credentials/node/resolve-local-token.js +97 -0
- package/dist/credentials/node/resolve-local-token.js.map +1 -0
- package/dist/credentials/server/bff.d.ts +44 -0
- package/dist/credentials/server/bff.d.ts.map +1 -0
- package/dist/credentials/server/bff.js +43 -0
- package/dist/credentials/server/bff.js.map +1 -0
- package/dist/deploy/api-enablement.d.ts +45 -0
- package/dist/deploy/api-enablement.d.ts.map +1 -0
- package/dist/deploy/api-enablement.js +125 -0
- package/dist/deploy/api-enablement.js.map +1 -0
- package/dist/deploy/firestore/databases.d.ts +41 -0
- package/dist/deploy/firestore/databases.d.ts.map +1 -0
- package/dist/deploy/firestore/databases.js +63 -0
- package/dist/deploy/firestore/databases.js.map +1 -0
- package/dist/deploy/firestore/indexes.d.ts +120 -0
- package/dist/deploy/firestore/indexes.d.ts.map +1 -0
- package/dist/deploy/firestore/indexes.js +243 -0
- package/dist/deploy/firestore/indexes.js.map +1 -0
- package/dist/deploy/firestore/recipes.d.ts +21 -0
- package/dist/deploy/firestore/recipes.d.ts.map +1 -0
- package/dist/deploy/firestore/recipes.js +34 -0
- package/dist/deploy/firestore/recipes.js.map +1 -0
- package/dist/deploy/firestore/rules.d.ts +76 -0
- package/dist/deploy/firestore/rules.d.ts.map +1 -0
- package/dist/deploy/firestore/rules.js +180 -0
- package/dist/deploy/firestore/rules.js.map +1 -0
- package/dist/deploy/from-admin-app.d.ts +20 -0
- package/dist/deploy/from-admin-app.d.ts.map +1 -0
- package/dist/deploy/from-admin-app.js +18 -0
- package/dist/deploy/from-admin-app.js.map +1 -0
- package/dist/deploy/from-service-account.d.ts +29 -0
- package/dist/deploy/from-service-account.d.ts.map +1 -0
- package/dist/deploy/from-service-account.js +115 -0
- package/dist/deploy/from-service-account.js.map +1 -0
- package/dist/deploy/functions/bundle.d.ts +37 -0
- package/dist/deploy/functions/bundle.d.ts.map +1 -0
- package/dist/deploy/functions/bundle.js +181 -0
- package/dist/deploy/functions/bundle.js.map +1 -0
- package/dist/deploy/functions/core.d.ts +18 -0
- package/dist/deploy/functions/core.d.ts.map +1 -0
- package/dist/deploy/functions/core.js +211 -0
- package/dist/deploy/functions/core.js.map +1 -0
- package/dist/deploy/functions/iam.d.ts +17 -0
- package/dist/deploy/functions/iam.d.ts.map +1 -0
- package/dist/deploy/functions/iam.js +40 -0
- package/dist/deploy/functions/iam.js.map +1 -0
- package/dist/deploy/functions/operation.d.ts +39 -0
- package/dist/deploy/functions/operation.d.ts.map +1 -0
- package/dist/deploy/functions/operation.js +37 -0
- package/dist/deploy/functions/operation.js.map +1 -0
- package/dist/deploy/functions/spec.d.ts +69 -0
- package/dist/deploy/functions/spec.d.ts.map +1 -0
- package/dist/deploy/functions/spec.js +7 -0
- package/dist/deploy/functions/spec.js.map +1 -0
- package/dist/deploy/functions/types.d.ts +50 -0
- package/dist/deploy/functions/types.d.ts.map +1 -0
- package/dist/deploy/functions/types.js +3 -0
- package/dist/deploy/functions/types.js.map +1 -0
- package/dist/deploy/hosting/channels.d.ts +93 -0
- package/dist/deploy/hosting/channels.d.ts.map +1 -0
- package/dist/deploy/hosting/channels.js +134 -0
- package/dist/deploy/hosting/channels.js.map +1 -0
- package/dist/deploy/hosting/config.d.ts +28 -0
- package/dist/deploy/hosting/config.d.ts.map +1 -0
- package/dist/deploy/hosting/config.js +261 -0
- package/dist/deploy/hosting/config.js.map +1 -0
- package/dist/deploy/hosting/core.d.ts +38 -0
- package/dist/deploy/hosting/core.d.ts.map +1 -0
- package/dist/deploy/hosting/core.js +311 -0
- package/dist/deploy/hosting/core.js.map +1 -0
- package/dist/deploy/hosting/gzip.d.ts +11 -0
- package/dist/deploy/hosting/gzip.d.ts.map +1 -0
- package/dist/deploy/hosting/gzip.js +20 -0
- package/dist/deploy/hosting/gzip.js.map +1 -0
- package/dist/deploy/hosting/hash.d.ts +6 -0
- package/dist/deploy/hosting/hash.d.ts.map +1 -0
- package/dist/deploy/hosting/hash.js +17 -0
- package/dist/deploy/hosting/hash.js.map +1 -0
- package/dist/deploy/hosting/sites.d.ts +77 -0
- package/dist/deploy/hosting/sites.d.ts.map +1 -0
- package/dist/deploy/hosting/sites.js +73 -0
- package/dist/deploy/hosting/sites.js.map +1 -0
- package/dist/deploy/hosting/spec.d.ts +140 -0
- package/dist/deploy/hosting/spec.d.ts.map +1 -0
- package/dist/deploy/hosting/spec.js +8 -0
- package/dist/deploy/hosting/spec.js.map +1 -0
- package/dist/deploy/hosting/types.d.ts +71 -0
- package/dist/deploy/hosting/types.d.ts.map +1 -0
- package/dist/deploy/hosting/types.js +3 -0
- package/dist/deploy/hosting/types.js.map +1 -0
- package/dist/deploy/hosting/walk.d.ts +31 -0
- package/dist/deploy/hosting/walk.d.ts.map +1 -0
- package/dist/deploy/hosting/walk.js +167 -0
- package/dist/deploy/hosting/walk.js.map +1 -0
- package/dist/deploy/index.d.ts +51 -0
- package/dist/deploy/index.d.ts.map +1 -0
- package/dist/deploy/index.js +50 -0
- package/dist/deploy/index.js.map +1 -0
- package/dist/deploy/memoize-ttl.d.ts +58 -0
- package/dist/deploy/memoize-ttl.d.ts.map +1 -0
- package/dist/deploy/memoize-ttl.js +88 -0
- package/dist/deploy/memoize-ttl.js.map +1 -0
- package/dist/deploy/namespaces.d.ts +119 -0
- package/dist/deploy/namespaces.d.ts.map +1 -0
- package/dist/deploy/namespaces.js +192 -0
- package/dist/deploy/namespaces.js.map +1 -0
- package/dist/deploy/preflight.d.ts +119 -0
- package/dist/deploy/preflight.d.ts.map +1 -0
- package/dist/deploy/preflight.js +440 -0
- package/dist/deploy/preflight.js.map +1 -0
- package/dist/deploy/provider.d.ts +130 -0
- package/dist/deploy/provider.d.ts.map +1 -0
- package/dist/deploy/provider.js +21 -0
- package/dist/deploy/provider.js.map +1 -0
- package/dist/deploy/providers/database.d.ts +8 -0
- package/dist/deploy/providers/database.d.ts.map +1 -0
- package/dist/deploy/providers/database.js +37 -0
- package/dist/deploy/providers/database.js.map +1 -0
- package/dist/deploy/providers/firestore.d.ts +11 -0
- package/dist/deploy/providers/firestore.d.ts.map +1 -0
- package/dist/deploy/providers/firestore.js +43 -0
- package/dist/deploy/providers/firestore.js.map +1 -0
- package/dist/deploy/providers/functions.d.ts +9 -0
- package/dist/deploy/providers/functions.d.ts.map +1 -0
- package/dist/deploy/providers/functions.js +49 -0
- package/dist/deploy/providers/functions.js.map +1 -0
- package/dist/deploy/providers/hosting.d.ts +13 -0
- package/dist/deploy/providers/hosting.d.ts.map +1 -0
- package/dist/deploy/providers/hosting.js +149 -0
- package/dist/deploy/providers/hosting.js.map +1 -0
- package/dist/deploy/providers/storage.d.ts +9 -0
- package/dist/deploy/providers/storage.d.ts.map +1 -0
- package/dist/deploy/providers/storage.js +46 -0
- package/dist/deploy/providers/storage.js.map +1 -0
- package/dist/deploy/registry.d.ts +17 -0
- package/dist/deploy/registry.d.ts.map +1 -0
- package/dist/deploy/registry.js +15 -0
- package/dist/deploy/registry.js.map +1 -0
- package/dist/deploy/rtdb/rules.d.ts +21 -0
- package/dist/deploy/rtdb/rules.d.ts.map +1 -0
- package/dist/deploy/rtdb/rules.js +104 -0
- package/dist/deploy/rtdb/rules.js.map +1 -0
- package/dist/deploy/scope.d.ts +81 -0
- package/dist/deploy/scope.d.ts.map +1 -0
- package/dist/deploy/scope.js +44 -0
- package/dist/deploy/scope.js.map +1 -0
- package/dist/deploy/tools.d.ts +55 -0
- package/dist/deploy/tools.d.ts.map +1 -0
- package/dist/deploy/tools.js +329 -0
- package/dist/deploy/tools.js.map +1 -0
- package/dist/deploy/with-resolved-scope.d.ts +31 -0
- package/dist/deploy/with-resolved-scope.d.ts.map +1 -0
- package/dist/deploy/with-resolved-scope.js +73 -0
- package/dist/deploy/with-resolved-scope.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 +49 -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 +333 -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/findCollectionGroup.d.ts +80 -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/index.d.ts +15 -0
- package/dist/discover/index.d.ts.map +1 -0
- package/dist/discover/index.js +24 -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/rest-crawler-firestore.d.ts +51 -0
- package/dist/discover/rest-crawler-firestore.d.ts.map +1 -0
- package/dist/discover/rest-crawler-firestore.js +154 -0
- package/dist/discover/rest-crawler-firestore.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 +59 -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 +191 -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 +81 -0
- package/dist/discover/wire.d.ts.map +1 -0
- package/dist/discover/wire.js +308 -0
- package/dist/discover/wire.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/exempt.d.ts +11 -0
- package/dist/register/exempt.d.ts.map +1 -0
- package/dist/register/exempt.js +74 -0
- package/dist/register/exempt.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 +126 -0
- package/dist/register/index.js.map +1 -0
- package/dist/register/mapping.d.ts +17 -0
- package/dist/register/mapping.d.ts.map +1 -0
- package/dist/register/mapping.js +31 -0
- package/dist/register/mapping.js.map +1 -0
- package/dist/registry/admin-deps.d.ts +17 -0
- package/dist/registry/admin-deps.d.ts.map +1 -0
- package/dist/registry/admin-deps.js +68 -0
- package/dist/registry/admin-deps.js.map +1 -0
- package/dist/registry/compose.d.ts +68 -0
- package/dist/registry/compose.d.ts.map +1 -0
- package/dist/registry/compose.js +113 -0
- package/dist/registry/compose.js.map +1 -0
- package/dist/registry/index.d.ts +11 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +11 -0
- package/dist/registry/index.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 +719 -0
- package/dist/remote/index.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 +38 -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 +134 -0
- package/dist/serve/bundler.d.ts.map +1 -0
- package/dist/serve/bundler.js +452 -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_.BsN3bPok.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/index.html +1 -0
- package/dist/serve/docs-ui/docs/index.json +9914 -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 +87 -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 +86 -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 +82 -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 +70 -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 +86 -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 +92 -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 +78 -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 +67 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api.md +73 -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 +75 -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 +95 -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 +73 -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 +146 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore.md +49 -0
- package/dist/serve/docs-ui/docs/pyric-auth/index.html +64 -0
- package/dist/serve/docs-ui/docs/pyric-auth-compat/index.html +874 -0
- package/dist/serve/docs-ui/docs/pyric-auth-compat.md +265 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +112 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api.md +129 -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 +80 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-sandbox-test-driver.md +107 -0
- package/dist/serve/docs-ui/docs/pyric-auth.md +84 -0
- package/dist/serve/docs-ui/docs/pyric-database/index.html +36 -0
- package/dist/serve/docs-ui/docs/pyric-database-compat/index.html +2428 -0
- package/dist/serve/docs-ui/docs/pyric-database-compat.md +850 -0
- package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate/index.html +23 -0
- package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate.md +29 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling/index.html +263 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling.md +288 -0
- package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints/index.html +116 -0
- package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints.md +142 -0
- package/dist/serve/docs-ui/docs/pyric-database.md +18 -0
- package/dist/serve/docs-ui/docs/pyric-firestore/index.html +54 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-compat/index.html +1345 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-compat.md +366 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate/index.html +79 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate.md +62 -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 +85 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface/index.html +61 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface.md +87 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-build-queries/index.html +105 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-build-queries.md +138 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore.md +93 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend/index.html +112 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend.md +100 -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 +55 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot/index.html +61 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot.md +83 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +132 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api.md +160 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix/index.html +793 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix.md +239 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore/index.html +55 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints/index.html +78 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints.md +115 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops.md +76 -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 +65 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo/index.html +127 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo.md +157 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend/index.html +85 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend.md +122 -0
- package/dist/serve/docs-ui/docs/pyric-firestore.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-rules/index.html +93 -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 +74 -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 +71 -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 +70 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api/index.html +96 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api.md +76 -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 +75 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design/index.html +62 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design.md +80 -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 +54 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast/index.html +89 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast.md +113 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time/index.html +47 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time.md +58 -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 +78 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports.md +93 -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 +117 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase/index.html +70 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase.md +93 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +129 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api.md +176 -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 +105 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-errors/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-errors.md +89 -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 +98 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules/index.html +239 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules.md +135 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema/index.html +93 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema.md +109 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings/index.html +86 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings.md +113 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers/index.html +101 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers.md +134 -0
- package/dist/serve/docs-ui/docs/pyric-rules-tutorials-01-lint-your-first-rules-file/index.html +107 -0
- package/dist/serve/docs-ui/docs/pyric-rules-tutorials-01-lint-your-first-rules-file.md +142 -0
- package/dist/serve/docs-ui/docs/pyric-rules-tutorials-02-write-a-test-suite-for-your-rules/index.html +151 -0
- package/dist/serve/docs-ui/docs/pyric-rules-tutorials-02-write-a-test-suite-for-your-rules.md +194 -0
- package/dist/serve/docs-ui/docs/pyric-rules.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox/index.html +67 -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 +157 -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 +98 -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 +105 -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 +80 -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 +88 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings.md +87 -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-how-to-multiple-isolated-sandboxes/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes.md +83 -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 +154 -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 +69 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events/index.html +89 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events.md +87 -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 +86 -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 +112 -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 +70 -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 +73 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +77 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +117 -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 +137 -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 +114 -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 +99 -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 +128 -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 +188 -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 +77 -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 +154 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-02-use-the-sandbox-in-a-test-harness/index.html +191 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-02-use-the-sandbox-in-a-test-harness.md +222 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-03-build-a-traffic-monitor/index.html +163 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-03-build-a-traffic-monitor.md +192 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox.md +63 -0
- package/dist/serve/docs-ui/docs/pyric-storage/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-compat/index.html +1076 -0
- package/dist/serve/docs-ui/docs/pyric-storage-compat.md +337 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope.md +104 -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 +80 -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 +104 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-enforce-rules.md +111 -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 +76 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-round-trip-metadata/index.html +77 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-round-trip-metadata.md +100 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends.md +82 -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 +82 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api.md +152 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes/index.html +46 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes.md +66 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset/index.html +73 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset.md +90 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options/index.html +45 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options.md +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-tutorials-01-upload-and-download/index.html +114 -0
- package/dist/serve/docs-ui/docs/pyric-storage-tutorials-01-upload-and-download.md +141 -0
- package/dist/serve/docs-ui/docs/pyric-storage.md +63 -0
- package/dist/serve/docs-ui/docs/pyric-tools/index.html +45 -0
- package/dist/serve/docs-ui/docs/pyric-tools-bridge/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-tools-bridge.md +90 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-primitives-vs-orchestrators/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-primitives-vs-orchestrators.md +83 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-token-caching/index.html +47 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-token-caching.md +70 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-why-no-firebase-cli/index.html +36 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-why-no-firebase-cli.md +50 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-why-this-package-exists/index.html +47 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-explanation-why-this-package-exists.md +60 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-firebase-auth/index.html +55 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-firebase-auth.md +68 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-service-account/index.html +35 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-service-account.md +52 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-bundle-and-deploy-a-function/index.html +81 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-bundle-and-deploy-a-function.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-firestore-indexes/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-firestore-indexes.md +91 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-firestore-rules/index.html +100 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-firestore-rules.md +105 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-hosting-rewrites/index.html +86 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-hosting-rewrites.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-realtime-database-rules/index.html +132 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-realtime-database-rules.md +165 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-to-a-preview-channel/index.html +46 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-deploy-to-a-preview-channel.md +62 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-handle-errors-and-outcomes/index.html +75 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-handle-errors-and-outcomes.md +94 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-provision-a-firestore-database/index.html +48 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-provision-a-firestore-database.md +65 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-register-tools-with-an-agent/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-how-to-register-tools-with-an-agent.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-api/index.html +155 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-api.md +190 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-cli-agent-io/index.html +84 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-cli-agent-io.md +66 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-error-codes/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-error-codes.md +102 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-firestore-namespace/index.html +138 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-firestore-namespace.md +175 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-functions-namespace/index.html +105 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-functions-namespace.md +133 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-hosting-config/index.html +194 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-hosting-config.md +95 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-hosting-namespace/index.html +99 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-hosting-namespace.md +126 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-rtdb-namespace/index.html +110 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-rtdb-namespace.md +133 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-scope-and-outcome/index.html +68 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-scope-and-outcome.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-tool-factories/index.html +160 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-reference-tool-factories.md +104 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-tutorials-01-deploy-a-cloud-function/index.html +88 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy-tutorials-01-deploy-a-cloud-function.md +119 -0
- package/dist/serve/docs-ui/docs/pyric-tools-deploy.md +52 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-build-a-standalone-binary/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-build-a-standalone-binary.md +95 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-configure-auth-providers-and-domains/index.html +101 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-configure-auth-providers-and-domains.md +126 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-discover-a-schema-from-firestore/index.html +95 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-discover-a-schema-from-firestore.md +119 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-promote-sandbox-state-to-a-fixture/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-promote-sandbox-state-to-a-fixture.md +83 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-serve-persistence-and-multi-tab/index.html +232 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-serve-persistence-and-multi-tab.md +178 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-use-the-vite-plugin/index.html +340 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-use-the-vite-plugin.md +288 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-verify-against-a-captured-session/index.html +128 -0
- package/dist/serve/docs-ui/docs/pyric-tools-how-to-verify-against-a-captured-session.md +173 -0
- package/dist/serve/docs-ui/docs/pyric-tools-reference-cli/index.html +433 -0
- package/dist/serve/docs-ui/docs/pyric-tools-reference-cli.md +252 -0
- package/dist/serve/docs-ui/docs/pyric-tools-reference-verify/index.html +81 -0
- package/dist/serve/docs-ui/docs/pyric-tools-reference-verify.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-getting-started/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-getting-started.md +117 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-server-adoption/index.html +221 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-server-adoption.md +239 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-wire-claude-code/index.html +205 -0
- package/dist/serve/docs-ui/docs/pyric-tools-tutorials-wire-claude-code.md +250 -0
- package/dist/serve/docs-ui/docs/pyric-tools.md +47 -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 +108 -0
- package/dist/serve/docs-ui/docs/ui-auth-authusers/index.html +258 -0
- package/dist/serve/docs-ui/docs/ui-auth-authusers.md +174 -0
- package/dist/serve/docs-ui/docs/ui-firestore-collectionlist/index.html +92 -0
- package/dist/serve/docs-ui/docs/ui-firestore-collectionlist.md +71 -0
- package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm/index.html +128 -0
- package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm.md +94 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documenteditor/index.html +154 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documenteditor.md +107 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentlist/index.html +132 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentlist.md +86 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentpreview/index.html +159 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentpreview.md +78 -0
- package/dist/serve/docs-ui/docs/ui-firestore-querybuilder/index.html +104 -0
- package/dist/serve/docs-ui/docs/ui-firestore-querybuilder.md +95 -0
- package/dist/serve/docs-ui/docs/ui-firestore-referencepicker/index.html +113 -0
- package/dist/serve/docs-ui/docs/ui-firestore-referencepicker.md +85 -0
- package/dist/serve/docs-ui/docs/ui-primitives-badge/index.html +56 -0
- package/dist/serve/docs-ui/docs/ui-primitives-badge.md +34 -0
- package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog/index.html +140 -0
- package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog.md +98 -0
- package/dist/serve/docs-ui/docs/ui-primitives-copybutton/index.html +58 -0
- package/dist/serve/docs-ui/docs/ui-primitives-copybutton.md +31 -0
- package/dist/serve/docs-ui/docs/ui-primitives-jsonview/index.html +58 -0
- package/dist/serve/docs-ui/docs/ui-primitives-jsonview.md +41 -0
- package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol/index.html +70 -0
- package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol.md +44 -0
- package/dist/serve/docs-ui/docs/ui-primitives-toast/index.html +87 -0
- package/dist/serve/docs-ui/docs/ui-primitives-toast.md +74 -0
- package/dist/serve/docs-ui/docs/ui-primitives-virtuallist/index.html +85 -0
- package/dist/serve/docs-ui/docs/ui-primitives-virtuallist.md +48 -0
- package/dist/serve/docs-ui/docs/ui-storage/index.html +154 -0
- package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm/index.html +127 -0
- package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm.md +83 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectbrowser/index.html +137 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectbrowser.md +84 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectinspector/index.html +139 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectinspector.md +87 -0
- package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb/index.html +72 -0
- package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb.md +51 -0
- package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances/index.html +65 -0
- package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances.md +53 -0
- package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone/index.html +93 -0
- package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone.md +72 -0
- package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate/index.html +153 -0
- package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate.md +105 -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 +54 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail/index.html +78 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail.md +53 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficlog/index.html +118 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficlog.md +63 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficstats/index.html +51 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficstats.md +40 -0
- package/dist/serve/docs-ui/docs/ui-traffic.md +96 -0
- package/dist/serve/docs-ui/docs/ui.md +88 -0
- package/dist/serve/docs-ui/index.html +1 -0
- package/dist/serve/docs-ui/llms.txt +221 -0
- package/dist/serve/entries/app.d.ts +26 -0
- package/dist/serve/entries/app.d.ts.map +1 -0
- package/dist/serve/entries/app.js +51 -0
- package/dist/serve/entries/app.js.map +1 -0
- package/dist/serve/entries/auth-helper-core.d.ts +47 -0
- package/dist/serve/entries/auth-helper-core.d.ts.map +1 -0
- package/dist/serve/entries/auth-helper-core.js +121 -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.d.ts +62 -0
- package/dist/serve/entries/auth.d.ts.map +1 -0
- package/dist/serve/entries/auth.js +128 -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 +34 -0
- package/dist/serve/entries/database.d.ts.map +1 -0
- package/dist/serve/entries/database.js +42 -0
- package/dist/serve/entries/database.js.map +1 -0
- package/dist/serve/entries/firestore.d.ts +68 -0
- package/dist/serve/entries/firestore.d.ts.map +1 -0
- package/dist/serve/entries/firestore.js +115 -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 +14 -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/runtime.d.ts +60 -0
- package/dist/serve/entries/runtime.d.ts.map +1 -0
- package/dist/serve/entries/runtime.js +555 -0
- package/dist/serve/entries/runtime.js.map +1 -0
- package/dist/serve/entries/session-store.d.ts +45 -0
- package/dist/serve/entries/session-store.d.ts.map +1 -0
- package/dist/serve/entries/session-store.js +71 -0
- package/dist/serve/entries/session-store.js.map +1 -0
- package/dist/serve/entries/storage.d.ts +23 -0
- package/dist/serve/entries/storage.d.ts.map +1 -0
- package/dist/serve/entries/storage.js +49 -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/namespace.d.ts +93 -0
- package/dist/serve/namespace.d.ts.map +1 -0
- package/dist/serve/namespace.js +367 -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/playground-ui/_astro/HomePage.BFOjZGZp.js +2 -0
- package/dist/serve/playground-ui/_astro/PlaygroundPage.3jki8il0.js +3300 -0
- package/dist/serve/playground-ui/_astro/PlaygroundPage.MhP_vFvK.css +32 -0
- package/dist/serve/playground-ui/_astro/TopBar.ChifCjLD.js +5025 -0
- package/dist/serve/playground-ui/_astro/client.D61DpmEZ.js +274 -0
- package/dist/serve/playground-ui/_astro/client.GCK88uRs.js +1 -0
- package/dist/serve/playground-ui/_astro/esbuild.BHljloGq.wasm +0 -0
- package/dist/serve/playground-ui/_astro/index.B9aLOeXL.js +29 -0
- package/dist/serve/playground-ui/_astro/index.BTKE7uRF.js +1227 -0
- package/dist/serve/playground-ui/_astro/index.BfCthstx.css +1 -0
- package/dist/serve/playground-ui/_astro/index.Mr0Dtjih.js +342 -0
- package/dist/serve/playground-ui/_astro/ort-wasm-simd-threaded.asyncify.DMmc6YqF.wasm +0 -0
- package/dist/serve/playground-ui/favicon.svg +4 -0
- package/dist/serve/playground-ui/index.html +2 -0
- package/dist/serve/playground-ui/playground/index.html +2 -0
- package/dist/serve/rules.d.ts +45 -0
- package/dist/serve/rules.d.ts.map +1 -0
- package/dist/serve/rules.js +139 -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 +32 -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 +66 -0
- package/dist/serve/standalone-assets.d.ts.map +1 -0
- package/dist/serve/standalone-assets.js +144 -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-Bncteb8z.js +23 -0
- package/dist/serve/studio-ui/assets/index-CmkJxFcG.js +4577 -0
- package/dist/serve/studio-ui/assets/index-DNK39P6C.css +1 -0
- package/dist/serve/studio-ui/assets/seed-Bab4ArXQ.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 +687 -0
- package/dist/serve/vite-plugin.js.map +1 -0
- package/dist/serve/worker/client.d.ts +668 -0
- package/dist/serve/worker/client.d.ts.map +1 -0
- package/dist/serve/worker/client.js +1635 -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 +122 -0
- package/dist/serve/worker/entry.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 +434 -0
- package/dist/serve/worker/host-auth.js.map +1 -0
- package/dist/serve/worker/host-context.d.ts +180 -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.d.ts +81 -0
- package/dist/serve/worker/host.d.ts.map +1 -0
- package/dist/serve/worker/host.js +1605 -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/protocol.d.ts +955 -0
- package/dist/serve/worker/protocol.d.ts.map +1 -0
- package/dist/serve/worker/protocol.js +197 -0
- package/dist/serve/worker/protocol.js.map +1 -0
- package/dist/serve/worker/serve-init.d.ts +192 -0
- package/dist/serve/worker/serve-init.d.ts.map +1 -0
- package/dist/serve/worker/serve-init.js +555 -0
- package/dist/serve/worker/serve-init.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 +79 -0
- package/dist/verify/fixture.d.ts.map +1 -0
- package/dist/verify/fixture.js +114 -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/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 +127 -0
|
@@ -0,0 +1,1345 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>pyric/firestore compatibility matrix · Pyric Studio</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link rel="stylesheet" href="/__pyric/ui/_astro/_slug_.BsN3bPok.css"></head> <body> <header class="studio__bar"> <div class="studio__bar-inner"> <a class="studio__brand" href="/__pyric/ui/" aria-label="Pyric Studio">Pyric</a> <nav class="studio__nav" aria-label="Studio tabs"> <a class="studio__nav-tab" href="/__pyric/ui/"> Home </a><a class="studio__nav-tab" href="/__pyric/ui/firestore"> Firestore </a><a class="studio__nav-tab" href="/__pyric/ui/auth"> Auth </a><a class="studio__nav-tab" href="/__pyric/ui/rtdb"> RTDB </a><a class="studio__nav-tab" href="/__pyric/ui/storage"> Storage </a><a class="studio__nav-tab" href="/__pyric/ui/traffic"> Traffic </a><a class="studio__nav-tab" href="/__pyric/ui/prototype"> Prototype </a><a class="studio__nav-tab" href="/__pyric/ui/settings"> Settings </a><a class="studio__nav-tab" href="/__pyric/ui/docs" aria-current="page"> Docs </a> </nav> </div> </header> <div class="docs-shell"> <details class="docs-nav-drawer"> <summary>Navigate</summary> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <script type="module">let i=null;function d(t){return i||(i=fetch(t).then(e=>e.json())),i}function l(t,e){return t.title.toLowerCase().includes(e)||t.excerpt.toLowerCase().includes(e)?!0:t.headings.some(r=>r.text.toLowerCase().includes(e))}function u(t,e,r){if(e.innerHTML="",t.length===0){e.hidden=!1;{const n=document.createElement("li");n.className="docs-search-empty",n.textContent="No matches",e.appendChild(n)}return}e.hidden=!1;for(const n of t.slice(0,8)){const s=document.createElement("li"),c=document.createElement("a");c.href=n.path;const o=document.createElement("span");o.className="docs-search-result-title",o.textContent=n.title;const a=document.createElement("span");a.className="docs-search-result-meta",a.textContent=[n.group,n.section].filter(Boolean).join(" / "),c.append(o,a),s.appendChild(c),e.appendChild(s)}}document.querySelectorAll(".docs-search").forEach(t=>{const e=t.dataset.indexUrl,r=t.querySelector(".docs-search-input"),n=t.querySelector(".docs-search-results");r.addEventListener("input",async()=>{const s=r.value.trim().toLowerCase();if(!s){n.hidden=!0,n.innerHTML="";return}const{pages:c}=await d(e);r.value.trim().toLowerCase()===s&&u(c.filter(o=>l(o,s)),n)}),r.addEventListener("focus",()=>{d(e),n.childElementCount>0&&(n.hidden=!1)}),r.addEventListener("keydown",s=>{s.key==="Escape"&&(r.value="",n.hidden=!0,n.innerHTML="",r.blur())}),r.addEventListener("blur",()=>{window.setTimeout(()=>{n.hidden=!0},150)})});document.addEventListener("keydown",t=>{if(!(t.metaKey||t.ctrlKey)||t.key.toLowerCase()!=="k")return;const e=[...document.querySelectorAll(".docs-search-input")].find(r=>r.offsetParent!==null);e&&(t.preventDefault(),e.focus(),e.select())});</script> <details class="docs-nav-group"> <summary>pyric-tools</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-tutorials-getting-started/"> Getting started </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-tutorials-server-adoption/"> Server adoption </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-tutorials-wire-claude-code/"> Wire Claude Code </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-how-to-build-a-standalone-binary/"> Build a standalone binary </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-configure-auth-providers-and-domains/"> Configure auth providers </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-discover-a-schema-from-firestore/"> Infer a schema </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-promote-sandbox-state-to-a-fixture/"> Promote sandbox state </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-serve-persistence-and-multi-tab/"> Persistence & multi-tab </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-use-the-vite-plugin/"> Use the Vite plugin </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-verify-against-a-captured-session/"> Verify rules against prod </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-reference-cli/"> pyric CLI reference </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-reference-verify/"> Verify API </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Bridge </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-bridge/"> pyric-tools/bridge </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>pyric-tools / deploy</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy-tutorials-01-deploy-a-cloud-function/"> Deploy a Cloud Function </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-firebase-auth/"> Scope from Firebase Auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-service-account/"> Scope from service account </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-bundle-and-deploy-a-function/"> Bundle & deploy a function </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-firestore-indexes/"> Deploy Firestore indexes </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-firestore-rules/"> Deploy Firestore rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-hosting-rewrites/"> Deploy Hosting rewrites </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-realtime-database-rules/"> Deploy RTDB rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-to-a-preview-channel/"> Deploy to a preview channel </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-handle-errors-and-outcomes/"> Handle errors and outcomes </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-provision-a-firestore-database/"> Provision a database </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-register-tools-with-an-agent/"> Register deploy tools </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-cli-agent-io/"> pyric deploy agent I/O </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-error-codes/"> Error codes by operation </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-firestore-namespace/"> firestore namespace </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-functions-namespace/"> functions namespace </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-hosting-config/"> firebase.json hosting config </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-hosting-namespace/"> hosting namespace </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-rtdb-namespace/"> rtdb namespace </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-scope-and-outcome/"> Scope and Outcome </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-tool-factories/"> Tool factories </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy-explanation-primitives-vs-orchestrators/"> Primitives vs. orchestrators </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-explanation-token-caching/"> Token caching and memoizeTtl </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-explanation-why-no-firebase-cli/"> Why no Firebase CLI </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-explanation-why-this-package-exists/"> Why this package exists </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" open> <summary>pyric / firestore</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo/"> Sandbox-backed demo </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend/"> Swap to prod backend </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-build-queries/"> Build queries </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore/"> Migrate from Firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-pick-a-backend/"> Pick a backend </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-run-a-transaction/"> Run a transaction </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-use-onsnapshot/"> Use onSnapshot </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-use-sandbox-ops/"> Use sandbox-only ops </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-feature-matrix/"> Feature matrix </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-getfirestore/"> getFirestore overloads </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-query-constraints/"> Query constraints </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-sandbox-ops/"> Sandbox-only operations </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-tool-factories/"> Tool factories </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-explanation-rules-tooling-is-separate/"> Rules tooling is separate </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-explanation-target-symbol-opacity/"> TARGET_SYMBOL opacity </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-explanation-two-backends-one-surface/"> Two backends, one surface </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Compat </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-compat/" aria-current="page"> Compatibility matrix </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>pyric / rules</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules-tutorials-01-lint-your-first-rules-file/"> Lint your first rules file </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-tutorials-02-write-a-test-suite-for-your-rules/"> Write a rules test suite </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening/"> Compare rulesets </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast/"> Inspect rules via the AST </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-lint-rules-source/"> Lint a rules source </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-pin-request-time/"> Pin request.time </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-register-tools-with-an-agent/"> Register rules tools </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-resolve-module-imports/"> Resolve 2+modules imports </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-simulate-rules-locally/"> Simulate rules locally </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-test-rules-against-firebase/"> Test rules against Firebase </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-ast/"> AST </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-errors/"> Errors </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-lint-rules/"> Lint rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-simulator-context/"> Simulator context </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-stdlib-modules/"> Standard library modules </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-test-case-schema/"> TestCase schema </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-validator-findings/"> Validator findings </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-value-wrappers/"> Value wrappers </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules-explanation-agent-failure-modes/"> Agent failure modes </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test/"> Lint vs validate vs test </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates/"> Runtime budget and gates </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-sentinel-expression-engine/"> Sentinel expression engine </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api/"> Simulator vs Rules Test API </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-the-2-plus-modules-extension/"> The 2+modules extension </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-value-wrappers-design/"> Value wrapper design </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-why-this-package-exists/"> Why this package exists </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>pyric / sandbox</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session/"> Your first sandbox session </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-tutorials-02-use-the-sandbox-in-a-test-harness/"> Sandbox in a test harness </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-tutorials-03-build-a-traffic-monitor/"> Traffic monitor </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes/"> Run isolated sandboxes </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-observe-events/"> Observe sandbox events </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-pick-an-adapter/"> Pick an adapter </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-replay-events/"> Replay events </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-reset-between-tests/"> Reset between tests </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-seed-data-and-rules/"> Seed data and rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-switch-users/"> Switch users </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-use-admin-reads/"> Use admin reads </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-divergences/"> Divergence </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-error-codes/"> SandboxError codes </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-internal-protocol/"> The /internal protocol </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-sandbox-and-context/"> Sandbox and context </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-sandbox-event/"> SandboxEvent </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-snapshot-and-admin/"> Snapshot and admin reads </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-every-op-is-a-request/"> Every operation is a request </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-identity-is-a-context/"> Identity is a context </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-internal-adapter-protocol/"> The /internal protocol </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-listener-re-evaluation/"> Listener re-evaluation </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline/"> Local backend vs. offline </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings/"> Why adapters are siblings </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-why-this-package-exists/"> Why this package exists </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>pyric / storage</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-tutorials-01-upload-and-download/"> Upload and download </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-how-to-enforce-rules/"> Enforce Storage rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-how-to-list-and-delete/"> List and delete objects </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-how-to-round-trip-metadata/"> Round-trip metadata </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-how-to-switch-backends/"> Switch backends </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-how-to-test-rule-expressions/"> Test rule expressions </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-error-codes/"> Error codes </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-rules-subset/"> Storage rules subset </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-storage-options/"> StorageOptions </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-explanation-implementation-scope/"> Implementation scope </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-explanation-session-archive-use-case/"> The session-archive driver </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-explanation-why-indexeddb/"> Why IndexedDB </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Compat </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-compat/"> Compatibility matrix </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>pyric / auth</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-auth/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-auth-reference-api/"> API reference </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-reference-feature-matrix/"> Feature matrix </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-reference-sandbox-test-driver/"> Sandbox test driver </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Compat </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-auth-compat/"> Compatibility matrix </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>pyric / database</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-database/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints/"> Author RTDB rules </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-database-reference-rules-tooling/"> RTDB rules tooling </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate/"> Authoring vs. deploy </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Compat </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-database-compat/"> Compatibility matrix </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>pyric-admin / firestore</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session/"> First admin session </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-run-a-transaction/"> Run a transaction </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules/"> Seed and set rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-translate-denials/"> Translate denials </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-use-onsnapshot/"> Use onSnapshot </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-write-a-batch/"> Write a batch </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-onsnapshot/"> onSnapshot overloads </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-re-exported-types/"> Re-exported types </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-sandbox-firestore/"> SandboxFirestore surface </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore-explanation-error-translation/"> Error translation </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-explanation-per-call-delegate/"> Per-call delegate </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape/"> Why mirror the admin SDK </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>@pyric/ui</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ui/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Primitives </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-primitives-badge/"> <Badge> </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-confirmdialog/"> <ConfirmDialog> + useConfirm </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-copybutton/"> <CopyButton> </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-jsonview/"> <JsonView> </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-segmentedcontrol/"> <SegmentedControl> </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-toast/"> <ToastProvider> + useToast </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-virtuallist/"> <VirtualList> </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Firestore </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-firestore-collectionlist/"> <CollectionList> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-deletewithconfirm/"> <DeleteWithConfirm> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-documenteditor/"> <DocumentEditor> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-documentlist/"> <DocumentList> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-documentpreview/"> <DocumentPreview> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-querybuilder/"> <QueryBuilder> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-referencepicker/"> <ReferencePicker> </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Storage </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-storage-deleteselectionwithconfirm/"> <DeleteSelectionWithConfirm> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-objectbrowser/"> <ObjectBrowser> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-objectinspector/"> <ObjectInspector> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-pathbreadcrumb/"> <PathBreadcrumb> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage/"> @pyric/ui/storage </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-uploaddropzone/"> <UploadDropzone> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-rules-aware-affordances/"> Rules-aware affordances </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-usestoragerulesgate/"> useStorageRulesGate </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Traffic </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-traffic/"> @pyric/ui/traffic </a> </li><li> <a href="/__pyric/ui/docs/ui-traffic-ruleheatmap/"> <RuleHeatmap> </a> </li><li> <a href="/__pyric/ui/docs/ui-traffic-trafficdetail/"> <TrafficDetail> </a> </li><li> <a href="/__pyric/ui/docs/ui-traffic-trafficlog/"> TrafficLog components </a> </li><li> <a href="/__pyric/ui/docs/ui-traffic-trafficstats/"> <TrafficStats> </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Auth </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-auth-authsigninhelper/"> AuthSignInHelper </a> </li><li> <a href="/__pyric/ui/docs/ui-auth-authusers/"> Auth users admin </a> </li> </ul> </div> </div> </details> </nav> </details> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <details class="docs-nav-group" id="nav-group-pyric-tools"> <summary>pyric-tools</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-tools-tutorials"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-tutorials-getting-started/"> Getting started </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-tutorials-server-adoption/"> Server adoption </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-tutorials-wire-claude-code/"> Wire Claude Code </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-tools-how-to"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-how-to-build-a-standalone-binary/"> Build a standalone binary </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-configure-auth-providers-and-domains/"> Configure auth providers </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-discover-a-schema-from-firestore/"> Infer a schema </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-promote-sandbox-state-to-a-fixture/"> Promote sandbox state </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-serve-persistence-and-multi-tab/"> Persistence & multi-tab </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-use-the-vite-plugin/"> Use the Vite plugin </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-how-to-verify-against-a-captured-session/"> Verify rules against prod </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-tools-reference"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-reference-cli/"> pyric CLI reference </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-reference-verify/"> Verify API </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-tools-bridge"> Bridge </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-bridge/"> pyric-tools/bridge </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-pyric-tools-deploy"> <summary>pyric-tools / deploy</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-tools-deploy-tutorials"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy-tutorials-01-deploy-a-cloud-function/"> Deploy a Cloud Function </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-tools-deploy-how-to"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-firebase-auth/"> Scope from Firebase Auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-build-projectscope-from-service-account/"> Scope from service account </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-bundle-and-deploy-a-function/"> Bundle & deploy a function </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-firestore-indexes/"> Deploy Firestore indexes </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-firestore-rules/"> Deploy Firestore rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-hosting-rewrites/"> Deploy Hosting rewrites </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-realtime-database-rules/"> Deploy RTDB rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-deploy-to-a-preview-channel/"> Deploy to a preview channel </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-handle-errors-and-outcomes/"> Handle errors and outcomes </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-provision-a-firestore-database/"> Provision a database </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-how-to-register-tools-with-an-agent/"> Register deploy tools </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-tools-deploy-reference"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-cli-agent-io/"> pyric deploy agent I/O </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-error-codes/"> Error codes by operation </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-firestore-namespace/"> firestore namespace </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-functions-namespace/"> functions namespace </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-hosting-config/"> firebase.json hosting config </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-hosting-namespace/"> hosting namespace </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-rtdb-namespace/"> rtdb namespace </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-scope-and-outcome/"> Scope and Outcome </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-reference-tool-factories/"> Tool factories </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-tools-deploy-explanation"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-tools-deploy-explanation-primitives-vs-orchestrators/"> Primitives vs. orchestrators </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-explanation-token-caching/"> Token caching and memoizeTtl </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-explanation-why-no-firebase-cli/"> Why no Firebase CLI </a> </li><li> <a href="/__pyric/ui/docs/pyric-tools-deploy-explanation-why-this-package-exists/"> Why this package exists </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-pyric-firestore" open> <summary>pyric / firestore</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-firestore-tutorials"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo/"> Sandbox-backed demo </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend/"> Swap to prod backend </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-firestore-how-to"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-build-queries/"> Build queries </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore/"> Migrate from Firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-pick-a-backend/"> Pick a backend </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-run-a-transaction/"> Run a transaction </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-use-onsnapshot/"> Use onSnapshot </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-how-to-use-sandbox-ops/"> Use sandbox-only ops </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-firestore-reference"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-feature-matrix/"> Feature matrix </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-getfirestore/"> getFirestore overloads </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-query-constraints/"> Query constraints </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-sandbox-ops/"> Sandbox-only operations </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-reference-tool-factories/"> Tool factories </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-firestore-explanation"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-explanation-rules-tooling-is-separate/"> Rules tooling is separate </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-explanation-target-symbol-opacity/"> TARGET_SYMBOL opacity </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-explanation-two-backends-one-surface/"> Two backends, one surface </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-firestore-compat"> Compat </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-firestore-compat/" aria-current="page"> Compatibility matrix </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-pyric-rules"> <summary>pyric / rules</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-rules-tutorials"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules-tutorials-01-lint-your-first-rules-file/"> Lint your first rules file </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-tutorials-02-write-a-test-suite-for-your-rules/"> Write a rules test suite </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-rules-how-to"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening/"> Compare rulesets </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast/"> Inspect rules via the AST </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-lint-rules-source/"> Lint a rules source </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-pin-request-time/"> Pin request.time </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-register-tools-with-an-agent/"> Register rules tools </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-resolve-module-imports/"> Resolve 2+modules imports </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-simulate-rules-locally/"> Simulate rules locally </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-how-to-test-rules-against-firebase/"> Test rules against Firebase </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-rules-reference"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-ast/"> AST </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-errors/"> Errors </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-lint-rules/"> Lint rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-simulator-context/"> Simulator context </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-stdlib-modules/"> Standard library modules </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-test-case-schema/"> TestCase schema </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-validator-findings/"> Validator findings </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-reference-value-wrappers/"> Value wrappers </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-rules-explanation"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-rules-explanation-agent-failure-modes/"> Agent failure modes </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test/"> Lint vs validate vs test </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates/"> Runtime budget and gates </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-sentinel-expression-engine/"> Sentinel expression engine </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api/"> Simulator vs Rules Test API </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-the-2-plus-modules-extension/"> The 2+modules extension </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-value-wrappers-design/"> Value wrapper design </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-explanation-why-this-package-exists/"> Why this package exists </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-pyric-sandbox"> <summary>pyric / sandbox</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-sandbox-tutorials"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session/"> Your first sandbox session </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-tutorials-02-use-the-sandbox-in-a-test-harness/"> Sandbox in a test harness </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-tutorials-03-build-a-traffic-monitor/"> Traffic monitor </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-sandbox-how-to"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes/"> Run isolated sandboxes </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-observe-events/"> Observe sandbox events </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-pick-an-adapter/"> Pick an adapter </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-replay-events/"> Replay events </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-reset-between-tests/"> Reset between tests </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-seed-data-and-rules/"> Seed data and rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-switch-users/"> Switch users </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-how-to-use-admin-reads/"> Use admin reads </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-sandbox-reference"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-divergences/"> Divergence </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-error-codes/"> SandboxError codes </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-internal-protocol/"> The /internal protocol </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-sandbox-and-context/"> Sandbox and context </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-sandbox-event/"> SandboxEvent </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-reference-snapshot-and-admin/"> Snapshot and admin reads </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-sandbox-explanation"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-every-op-is-a-request/"> Every operation is a request </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-identity-is-a-context/"> Identity is a context </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-internal-adapter-protocol/"> The /internal protocol </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-listener-re-evaluation/"> Listener re-evaluation </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline/"> Local backend vs. offline </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings/"> Why adapters are siblings </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox-explanation-why-this-package-exists/"> Why this package exists </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-pyric-storage"> <summary>pyric / storage</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-storage-tutorials"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-tutorials-01-upload-and-download/"> Upload and download </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-storage-how-to"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-how-to-enforce-rules/"> Enforce Storage rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-how-to-list-and-delete/"> List and delete objects </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-how-to-round-trip-metadata/"> Round-trip metadata </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-how-to-switch-backends/"> Switch backends </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-how-to-test-rule-expressions/"> Test rule expressions </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-storage-reference"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-error-codes/"> Error codes </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-rules-subset/"> Storage rules subset </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-reference-storage-options/"> StorageOptions </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-storage-explanation"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-explanation-implementation-scope/"> Implementation scope </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-explanation-session-archive-use-case/"> The session-archive driver </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-explanation-why-indexeddb/"> Why IndexedDB </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-storage-compat"> Compat </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-storage-compat/"> Compatibility matrix </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-pyric-auth"> <summary>pyric / auth</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-auth/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-auth-reference"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-auth-reference-api/"> API reference </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-reference-feature-matrix/"> Feature matrix </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-reference-sandbox-test-driver/"> Sandbox test driver </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-auth-compat"> Compat </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-auth-compat/"> Compatibility matrix </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-pyric-database"> <summary>pyric / database</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-database/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-database-tutorials"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints/"> Author RTDB rules </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-database-reference"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-database-reference-rules-tooling/"> RTDB rules tooling </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-database-explanation"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate/"> Authoring vs. deploy </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-database-compat"> Compat </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-database-compat/"> Compatibility matrix </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-pyric-admin-firestore"> <summary>pyric-admin / firestore</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-admin-firestore-tutorials"> Tutorials </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session/"> First admin session </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-admin-firestore-how-to"> How-to </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-run-a-transaction/"> Run a transaction </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules/"> Seed and set rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-translate-denials/"> Translate denials </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-use-onsnapshot/"> Use onSnapshot </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-how-to-write-a-batch/"> Write a batch </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-admin-firestore-reference"> Reference </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-api/"> Public API </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-onsnapshot/"> onSnapshot overloads </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-re-exported-types/"> Re-exported types </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-reference-sandbox-firestore/"> SandboxFirestore surface </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-admin-firestore-explanation"> Explanation </h2> <ul> <li> <a href="/__pyric/ui/docs/pyric-admin-firestore-explanation-error-translation/"> Error translation </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-explanation-per-call-delegate/"> Per-call delegate </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape/"> Why mirror the admin SDK </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-pyric-ui"> <summary>@pyric/ui</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ui/"> Overview </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-ui-primitives"> Primitives </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-primitives-badge/"> <Badge> </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-confirmdialog/"> <ConfirmDialog> + useConfirm </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-copybutton/"> <CopyButton> </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-jsonview/"> <JsonView> </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-segmentedcontrol/"> <SegmentedControl> </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-toast/"> <ToastProvider> + useToast </a> </li><li> <a href="/__pyric/ui/docs/ui-primitives-virtuallist/"> <VirtualList> </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-ui-firestore"> Firestore </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-firestore-collectionlist/"> <CollectionList> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-deletewithconfirm/"> <DeleteWithConfirm> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-documenteditor/"> <DocumentEditor> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-documentlist/"> <DocumentList> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-documentpreview/"> <DocumentPreview> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-querybuilder/"> <QueryBuilder> </a> </li><li> <a href="/__pyric/ui/docs/ui-firestore-referencepicker/"> <ReferencePicker> </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-ui-storage"> Storage </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-storage-deleteselectionwithconfirm/"> <DeleteSelectionWithConfirm> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-objectbrowser/"> <ObjectBrowser> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-objectinspector/"> <ObjectInspector> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-pathbreadcrumb/"> <PathBreadcrumb> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage/"> @pyric/ui/storage </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-uploaddropzone/"> <UploadDropzone> </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-rules-aware-affordances/"> Rules-aware affordances </a> </li><li> <a href="/__pyric/ui/docs/ui-storage-usestoragerulesgate/"> useStorageRulesGate </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-ui-traffic"> Traffic </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-traffic/"> @pyric/ui/traffic </a> </li><li> <a href="/__pyric/ui/docs/ui-traffic-ruleheatmap/"> <RuleHeatmap> </a> </li><li> <a href="/__pyric/ui/docs/ui-traffic-trafficdetail/"> <TrafficDetail> </a> </li><li> <a href="/__pyric/ui/docs/ui-traffic-trafficlog/"> TrafficLog components </a> </li><li> <a href="/__pyric/ui/docs/ui-traffic-trafficstats/"> <TrafficStats> </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-pyric-ui-auth"> Auth </h2> <ul> <li> <a href="/__pyric/ui/docs/ui-auth-authsigninhelper/"> AuthSignInHelper </a> </li><li> <a href="/__pyric/ui/docs/ui-auth-authusers/"> Auth users admin </a> </li> </ul> </div> </div> </details> </nav> <main class="doc-main"> <nav class="docs-breadcrumbs" aria-label="Breadcrumb"> <ol> <li> <a href="/__pyric/ui/docs/pyric-firestore/">pyric / firestore</a> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <a href="#nav-section-pyric-firestore-compat">Compat</a> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span aria-current="page">Compatibility matrix</span> </li> </ol> </nav> <article class="prose"> <!-- Generated from scripts/compat/registry/*.ts. Do not edit by hand; run bun run compat:generate. -->
|
|
2
|
+
<h1 id="pyricfirestore-compatibility-matrix"><code>pyric/firestore</code> compatibility matrix</h1>
|
|
3
|
+
<p>The single readable contract for “what this shim guarantees vs the
|
|
4
|
+
production <code>firebase/firestore</code> SDK.”</p>
|
|
5
|
+
<p>See the design rationale for the methodology (vocabulary
|
|
6
|
+
of conformance / oracle / matrix; how to add rows; how the runner
|
|
7
|
+
attributes failures).</p>
|
|
8
|
+
<h2 id="status-legend">Status legend</h2>
|
|
9
|
+
<div class="table-scroll">
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
<table><thead><tr><th>Status</th><th>Meaning</th></tr></thead><tbody><tr><td>✓</td><td><strong>Conforming</strong> — sandbox matches prod, locked by a passing probe</td></tr><tr><td>⚠</td><td><strong>Diverged (documented)</strong> — intentional difference with a written reason</td></tr><tr><td>✗</td><td><strong>Bug</strong> — should match prod but doesn’t; failing probe pins it</td></tr><tr><td>—</td><td><strong>Unsupported</strong> — not implemented yet (deliberately or pending)</td></tr><tr><td>?</td><td><strong>Unverified</strong> — claim from docs that we haven’t yet observed prod-side</td></tr></tbody></table></div>
|
|
39
|
+
<p>Probe references: <code>playground:<name></code> means a fixture under
|
|
40
|
+
<code>packages/playground/scripts/fixtures/<name>.tsx</code>. <code>unit:<file></code>
|
|
41
|
+
means a Bun test in <code>packages/pyric/test/firestore/<file></code>.</p>
|
|
42
|
+
<p>Targets:</p>
|
|
43
|
+
<ul>
|
|
44
|
+
<li><strong>sandbox</strong> — frozen-ctx target built via <code>getFirestore(ctx: SandboxContext)</code>. Identity baked in at handle-construction.</li>
|
|
45
|
+
<li><strong>sandbox-live</strong> — live-identity target built via <code>getFirestore(sandbox: Sandbox)</code>. Every op re-reads <code>sandbox.currentUser</code>. The playground preview always uses this flavor.</li>
|
|
46
|
+
<li><strong>prod</strong> — <code>firebase/firestore</code> target built via <code>getFirestore(app: FirebaseApp)</code>. Identity comes from <code>firebase/auth</code>’s <code>currentUser</code>.</li>
|
|
47
|
+
</ul>
|
|
48
|
+
<hr>
|
|
49
|
+
<h2 id="getfirestoretarget--initializer"><code>getFirestore(target)</code> — initializer</h2>
|
|
50
|
+
<div class="table-scroll">
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>1</td><td><code>getFirestore(ctx)</code> returns a tagged sandbox-target handle (frozen identity)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>2</td><td><code>getFirestore(sandbox)</code> returns a tagged sandbox-live handle (per-op identity)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code></td></tr><tr><td>3</td><td><code>getFirestore(app)</code> returns a tagged prod target</td><td>✓</td><td><code>unit:prod-target.test.ts</code></td></tr><tr><td>4</td><td><code>getFirestore(undefined)</code> — wrapped in the playground preview to default to the sandbox; raw call delegates to prod which throws <code>app/no-app</code></td><td>✓ (wrap)</td><td><code>playground:firestore-bare-getfirestore</code> — fix from PR #397 + oracle: <code>scripts/oracle/observations/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)</td></tr><tr><td>5</td><td>Two <code>getFirestore(sandbox)</code> calls share state (same underlying <code>LocalEnvironment</code>)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“two handles share the same sandbox”)</td></tr><tr><td>6</td><td>Handle dispatch by <code>TARGET_SYMBOL</code> brand — refs/queries route to their owning target via <code>refToTarget</code> WeakMap</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“throws TypeError for refs not produced by this package”)</td></tr></tbody></table></div>
|
|
98
|
+
<h2 id="path-constructors--doc--collection--collectiongroup">Path constructors — <code>doc</code> / <code>collection</code> / <code>collectionGroup</code></h2>
|
|
99
|
+
<div class="table-scroll">
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>7</td><td><code>doc(db, path)</code> returns a tagged <code>DocumentReference</code> with <code>id</code> / <code>path</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>8</td><td><code>doc(db, 'a', 'b', 'c', 'd')</code> joins variadic path segments</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>9</td><td><code>collection(db, path)</code> returns a tagged <code>CollectionReference</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>10</td><td><code>doc(coll, id)</code> appends under a collection ref</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>11</td><td><code>doc(coll)</code> (no id) mints an auto-id <code>DocumentReference</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>12</td><td><code>collection(docRef, name)</code> builds a subcollection ref</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>13</td><td><code>collectionGroup(db, id)</code> returns a query spanning every collection with that id</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“gathers documents across every parent collection”)</td></tr><tr><td>14</td><td>Unknown ref (not produced by this package) → <code>TypeError</code> with “unrecognized reference”</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>15</td><td>Held doc/coll ref under <code>sandbox-live</code> re-resolves to the chainable under the current user at op time (via rebuild closure)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“held doc ref re-resolves under the current user”)</td></tr></tbody></table></div>
|
|
165
|
+
<h2 id="getdocref--single-doc-read"><code>getDoc(ref)</code> — single-doc read</h2>
|
|
166
|
+
<div class="table-scroll">
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>16</td><td>Returns <code>DocumentSnapshot</code> with <code>id</code>, <code>exists</code> (method form), <code>data()</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>17</td><td><code>snap.exists</code> is normalized to method form (<code>snap.exists()</code> returns boolean) to match the modular SDK</td><td>✓</td><td><code>playground:firestore-onsnapshot</code> (bundled, assertion-shape compat) + <code>playground:firestore-row-17-snap-exists-method</code> (one-claim)</td></tr><tr><td>18</td><td><code>snap.data()</code> returns <code>undefined</code> for missing doc</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>19</td><td><code>snap.ref</code> is tagged so it routes through <code>targetOf</code> in follow-up ops</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>20</td><td>Re-evaluates rules under current user on every call (sandbox-live) — read denied throws <code>permission-denied</code></td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“doc read denied when current user lacks read access”), oracle: <code>scripts/oracle/observations/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>)</td></tr><tr><td>21</td><td>Rules denial throws <code>SandboxError('permission-denied', …)</code> on sandbox; <code>FirebaseError('permission-denied')</code> on prod</td><td>⚠</td><td>divergence: same code, different class — both expose <code>.code === 'permission-denied'</code>. Oracle-locked: <code>scripts/oracle/observations/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>.</td></tr></tbody></table></div>
|
|
214
|
+
<h2 id="getdocsquery--bulk-read"><code>getDocs(query)</code> — bulk read</h2>
|
|
215
|
+
<div class="table-scroll">
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>22</td><td>Returns <code>QuerySnapshot</code> with <code>size</code>, <code>empty</code>, <code>docs</code> (<code>QueryDocumentSnapshot[]</code>)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-query</code></td></tr><tr><td>23</td><td>Each <code>snap.docs[i].ref</code> is tagged for follow-up ops</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>24</td><td>Sandbox-live: re-evaluates filters under the current user (different docs visible per identity)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“query results re-evaluate under the current user”)</td></tr><tr><td>24a</td><td><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.</td><td>✓</td><td><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”)</td></tr><tr><td>24b</td><td><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.</td><td>✓</td><td><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</td></tr><tr><td>24c</td><td>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.</td><td>⚠</td><td><code>unit:rules/simulator/query-proof.test.ts</code> (conservative-reject cases); divergence is deny-only (no rule-violating doc can leak)</td></tr><tr><td>25</td><td>Empty result for a collection with no docs (<code>size === 0</code>, <code>empty === true</code>)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr></tbody></table></div>
|
|
269
|
+
<h2 id="setdocref-data-options--full-write"><code>setDoc(ref, data[, options])</code> — full write</h2>
|
|
270
|
+
<div class="table-scroll">
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>26</td><td>No options → replaces the existing document entirely</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“setDoc default replaces”)</td></tr><tr><td>27</td><td><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.</td><td>✓</td><td><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)</td></tr><tr><td>28</td><td><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.</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, <code>unit:admin-compat/field-path-merge.test.ts</code> (dotted mergeField)</td></tr><tr><td>29</td><td>Passing both <code>merge</code> and <code>mergeFields</code> — <code>mergeFields</code> wins on sandbox (matches JS SDK effective behavior)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>30</td><td>Sentinels (<code>serverTimestamp</code>, <code>increment</code>, <code>arrayUnion</code>, <code>arrayRemove</code>, <code>deleteField</code>) resolve in the same call</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-sentinels</code>, oracle: <code>scripts/oracle/observations/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.</td></tr><tr><td>31</td><td>Converter (via <code>withConverter</code>) runs <code>toFirestore(data)</code> before the write</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“withConverter on a DocumentReference round-trips”)</td></tr><tr><td>32</td><td>Rules-denied write throws <code>permission-denied</code> (sandbox) / <code>FirebaseError</code> (prod)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“getDoc denies when rules reject”), <code>playground:rules-data-validation</code>, oracle: <code>scripts/oracle/observations/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>)</td></tr></tbody></table></div>
|
|
324
|
+
<h2 id="updatedocref-data--partial-write"><code>updateDoc(ref, data)</code> — partial write</h2>
|
|
325
|
+
<div class="table-scroll">
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>33</td><td>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.</td><td>✓</td><td><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)</td></tr><tr><td>34</td><td>Throws <code>not-found</code> (sandbox) / <code>FirebaseError('not-found')</code> (prod) on missing doc</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (implicit in writes-fail-on-missing tests), oracle: <code>scripts/oracle/observations/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>)</td></tr><tr><td>35</td><td>Does NOT run a converter — partial updates don’t have a typed home (matches JS SDK)</td><td>✓</td><td>(documented in <code>withConverter</code> block)</td></tr><tr><td>36</td><td>Sentinels resolve mid-update (<code>increment(1)</code> against an existing numeric field, etc.)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-sentinels</code>, oracle: <code>scripts/oracle/observations/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.</td></tr><tr><td>37</td><td>Sandbox-live: each call re-evaluates auth (alice → bob between writes uses bob’s auth)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“updateDoc re-evaluates auth per call”)</td></tr></tbody></table></div>
|
|
367
|
+
<h2 id="deletedocref"><code>deleteDoc(ref)</code></h2>
|
|
368
|
+
<div class="table-scroll">
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>38</td><td>Removes the document; subsequent <code>getDoc</code> returns <code>exists()===false</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>39</td><td>Idempotent — <code>deleteDoc</code> on missing doc resolves without throwing (matches JS SDK)</td><td>✓</td><td><code>unit:deletedoc-missing.test.ts</code>, <code>playground:firestore-deletedoc-missing</code>, oracle: <code>scripts/oracle/observations/firestore-deletedoc-missing.json</code></td></tr><tr><td>40</td><td>Rules-denied delete throws <code>permission-denied</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (rules-reject branch), oracle: <code>scripts/oracle/observations/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>)</td></tr></tbody></table></div>
|
|
398
|
+
<h2 id="adddoccoll-data--auto-id-write"><code>addDoc(coll, data)</code> — auto-id write</h2>
|
|
399
|
+
<div class="table-scroll">
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>41</td><td>Returns a tagged <code>DocumentReference</code> with auto-id</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>42</td><td>Returned ref is usable in subsequent ops (<code>getDoc</code>, <code>setDoc</code>, <code>onSnapshot</code>)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, oracle: <code>scripts/oracle/observations/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.</td></tr><tr><td>43</td><td>Sandbox-live: returned ref is a <em>live</em> ref (rebuild closure recorded) so follow-ups re-resolve auth</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“addDoc result is a tagged live ref”)</td></tr><tr><td>44</td><td>Converter on the parent collection propagates onto the returned ref</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“addDoc through a converted collection”)</td></tr><tr><td>45</td><td>Auto-id format — prod uses 20-char base64-ish IDs; sandbox uses <code>pyric-admin</code>’s auto-id (also opaque, distinct format)</td><td>⚠ format</td><td>divergence: IDs are opaque on both sides; format differs but consumer code never parses them. Oracle-locked: <code>scripts/oracle/observations/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>.</td></tr></tbody></table></div>
|
|
441
|
+
<h2 id="withconverter--typed-refs"><code>withConverter</code> — typed refs</h2>
|
|
442
|
+
<div class="table-scroll">
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>46</td><td><code>withConverter(docRef, converter)</code> returns a shell that runs <code>toFirestore</code> on writes, <code>fromFirestore</code> on reads</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>47</td><td><code>withConverter(collRef, converter)</code> propagates onto <code>doc(typedColl, id)</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>48</td><td><code>withConverter(collRef, converter)</code> propagates through <code>query(typedColl, …)</code> + <code>getDocs()</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>49</td><td><code>withConverter(ref, null)</code> strips the converter, returns the underlying untyped view</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>50</td><td>Original untyped ref keeps its identity after <code>withConverter(ref, c)</code> (two views, one path)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>51</td><td><code>setDoc</code> through a converted ref invokes <code>toFirestore(data)</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>52</td><td><code>getDoc</code> through a converted ref invokes <code>fromFirestore(snapshot)</code>; <code>.data()</code> returns the typed model</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>53</td><td><code>updateDoc</code> through a converted ref does NOT invoke the converter</td><td>✓</td><td>(documented constraint; matches JS SDK)</td></tr></tbody></table></div>
|
|
502
|
+
<h2 id="query-construction--query--where--or--and--orderby--limit">Query construction — <code>query</code> / <code>where</code> / <code>or</code> / <code>and</code> / <code>orderBy</code> / <code>limit</code></h2>
|
|
503
|
+
<div class="table-scroll">
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>54</td><td><code>query(coll, where(…), orderBy(…), limit(…))</code> composes constraints in order</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-query</code></td></tr><tr><td>55</td><td><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></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (canonical query test)</td></tr><tr><td>55a</td><td><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.</td><td>✓</td><td><code>unit:admin-compat/inequality-existence-guards.test.ts</code> (verified failing pre-fix)</td></tr><tr><td>56</td><td><code>or(...)</code> composite — at least one sub-filter matches</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“or() matches docs where any sub-filter matches”), oracle: <code>scripts/oracle/observations/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)</td></tr><tr><td>57</td><td><code>and(...)</code> composite — every sub-filter matches</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“and() requires every sub-filter”), oracle: <code>scripts/oracle/observations/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>)</td></tr><tr><td>58</td><td>Nested <code>or</code> / <code>and</code> — full composite tree</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“nested or/and — the canonical composite pattern”), oracle: <code>scripts/oracle/observations/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)</td></tr><tr><td>59</td><td><code>orderBy(field, 'asc'|'desc')</code> — direction parameter</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>59a</td><td><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>.</td><td>✓</td><td><code>unit:admin-compat/canonical-type-order.test.ts</code> (cross-type ranking, numeric sort, NaN, timestamps, arrays; verified failing pre-fix)</td></tr><tr><td>59b</td><td><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>.</td><td>✓</td><td><code>unit:admin-compat/canonical-type-order.test.ts</code> (“excludes the missing-field doc”)</td></tr><tr><td>59c</td><td><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.</td><td>✓</td><td><code>unit:admin-compat/implicit-order-name.test.ts</code> (key tiebreak, snapshot-cursor disambiguation, implicit inequality order; verified failing pre-fix)</td></tr><tr><td>60</td><td><code>limit(n)</code> — caps result count</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>61</td><td><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></td><td>⚠</td><td>divergence, oracle-locked by <code>scripts/oracle/observations/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/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)</td></tr><tr><td>62</td><td>Composite filters AND with other constraints — <code>query(coll, or(...), orderBy(...), limit(...))</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>63</td><td>Passing <code>orderBy</code> / <code>limit</code> into <code>or()</code> / <code>and()</code> → <code>TypeError</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>64</td><td>Zero-arg <code>or()</code> / <code>and()</code> → <code>TypeError</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>65</td><td>Chained queries re-tag for further constraints (<code>query(query(coll, where), orderBy)</code>)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“chained queries are taggable”)</td></tr><tr><td>66</td><td>Index validation against <code>firestore.indexes.json</code> — sandbox uses <code>LocalEnvironment</code>’s lint pass; prod has its own server-side validation</td><td>⚠</td><td>divergence: sandbox can mis-pass a query that prod would reject at the server with <code>failed-precondition</code> if no index exists</td></tr></tbody></table></div>
|
|
617
|
+
<h2 id="cursor-pagination--startat--startafter--endat--endbefore">Cursor pagination — <code>startAt</code> / <code>startAfter</code> / <code>endAt</code> / <code>endBefore</code></h2>
|
|
618
|
+
<div class="table-scroll">
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>67</td><td><code>startAt(...values)</code> — inclusive value cursor (one positional per <code>orderBy</code> clause)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, oracle: <code>scripts/oracle/observations/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)</td></tr><tr><td>68</td><td><code>startAfter(...values)</code> — exclusive value cursor</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, oracle: <code>scripts/oracle/observations/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)</td></tr><tr><td>69</td><td><code>endAt(...values)</code> — inclusive end cursor</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, oracle: <code>scripts/oracle/observations/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)</td></tr><tr><td>70</td><td><code>endBefore(...values)</code> — exclusive end cursor</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, oracle: <code>scripts/oracle/observations/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)</td></tr><tr><td>71</td><td><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”).</td><td>✓</td><td><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>)</td></tr><tr><td>72</td><td><code>endAt(snapshot)</code> overload</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“endAt(snapshot) trims to-and-including the anchor”)</td></tr><tr><td>73</td><td><code>startAfter + limit</code> — canonical pagination pattern</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr></tbody></table></div>
|
|
672
|
+
<h2 id="aggregates--getcountfromserver--getaggregatefromserver--count--sum--average">Aggregates — <code>getCountFromServer</code> / <code>getAggregateFromServer</code> / <code>count</code> / <code>sum</code> / <code>average</code></h2>
|
|
673
|
+
<div class="table-scroll">
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>74</td><td><code>getCountFromServer(query)</code> returns <code>{ data: () => ({ count: N }) }</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>75</td><td><code>getCountFromServer</code> honors <code>where</code> filters</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>76</td><td><code>getAggregateFromServer(query, spec)</code> returns <code>{ data: () => Record<alias, number|null> }</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>77</td><td><code>count()</code> / <code>sum(field)</code> / <code>average(field)</code> compose under one spec</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>78</td><td><code>average</code> returns <code>null</code> on empty input (matches JS SDK)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>79</td><td>Aggregates count documents server-side without paying read cost per doc in prod; sandbox computes locally (no cost model)</td><td>⚠</td><td>divergence: cost behavior differs, observable shape identical. Oracle-locked: <code>scripts/oracle/observations/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>).</td></tr></tbody></table></div>
|
|
721
|
+
<h2 id="onsnapshotreforquery---listeners"><code>onSnapshot(refOrQuery, …)</code> — listeners</h2>
|
|
722
|
+
<div class="table-scroll">
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>80</td><td><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”</td><td>✓</td><td>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>scripts/oracle/observations/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).</td></tr><tr><td>81</td><td><code>onSnapshot(query, cb)</code> fires on collection writes</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, oracle: <code>scripts/oracle/observations/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.)</td></tr><tr><td>81a</td><td><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.</td><td>✓</td><td><code>unit:onsnapshot-query-constraints.test.ts</code> (filtered/ordered/limited listeners; verified failing pre-fix)</td></tr><tr><td>81b</td><td><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.</td><td>✓</td><td><code>unit:simulator/listener-read-translation.test.ts</code> (doc + query listener Timestamp shape; verified failing pre-fix)</td></tr><tr><td>82</td><td>Initial fire for a missing doc has <code>exists() === false</code> and <code>data() === undefined</code></td><td>✓</td><td><code>playground:firestore-onsnapshot</code> (bundled) + <code>playground:firestore-row-82-onsnapshot-missing-initial</code> (one-claim), oracle: <code>scripts/oracle/observations/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.</td></tr><tr><td>83</td><td>Returned <code>Unsubscribe</code> stops further fires</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, oracle: <code>scripts/oracle/observations/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.</td></tr><tr><td>84</td><td>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></td><td>✓</td><td>oracle: <code>scripts/oracle/observations/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)</td></tr><tr><td>85</td><td><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</td><td>✓</td><td>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>scripts/oracle/observations/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)</td></tr><tr><td>86</td><td>Snapshot’s <code>.ref</code> / <code>.docs[i].ref</code> are tagged so consumer code can pass them to follow-up ops</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>87</td><td>Sandbox-live: listener registered as alice keeps emitting alice’s view after <code>setUser → bob</code> (identity frozen at subscribe)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“listener registered as alice keeps emitting alice’s view”)</td></tr><tr><td>88</td><td>Sandbox-live: listener registered as anonymous keeps firing after sign-in (anonymous → signed-in identity persists per listener)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“listener registered as anonymous on /public keeps firing after sign-in”)</td></tr><tr><td>89</td><td>Snapshot’s ref is usable in follow-up ops under the new user (the ref is live, the listener identity is frozen — distinct)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“snapshot ref is usable in subsequent ops under the new user”), oracle: <code>scripts/oracle/observations/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.</td></tr><tr><td>90</td><td>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>.</td><td>✓</td><td><code>playground:preview-single-mount</code></td></tr></tbody></table></div>
|
|
812
|
+
<h2 id="runtransactiondb-fn"><code>runTransaction(db, fn)</code></h2>
|
|
813
|
+
<div class="table-scroll">
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>91</td><td>Atomic read-write — all reads in <code>fn</code> see a consistent snapshot, writes commit together</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-transaction</code></td></tr><tr><td>92</td><td>Identity is frozen at <code>runTransaction</code> start — mid-transaction <code>setUser</code> does NOT re-auth in-flight reads</td><td>✓</td><td>(documented invariant)</td></tr><tr><td>93</td><td>Retry behavior — prod retries on contention up to 5 times; sandbox is single-threaded, no contention possible</td><td>⚠</td><td>divergence: contention story not modeled; sandbox just runs once</td></tr><tr><td>94</td><td>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></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (writes-reject branch), oracle: <code>scripts/oracle/observations/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)</td></tr></tbody></table></div>
|
|
849
|
+
<h2 id="writebatchdb"><code>writeBatch(db)</code></h2>
|
|
850
|
+
<div class="table-scroll">
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>95</td><td><code>batch.set</code> / <code>batch.update</code> / <code>batch.delete</code> queue mutations</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, <code>playground:firestore-batch</code></td></tr><tr><td>96</td><td><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</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, oracle: <code>scripts/oracle/observations/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.</td></tr><tr><td>97</td><td>Batch is tagged on construction — passing a prod-target batch into a sandbox op (or vice-versa) is a type error</td><td>✓</td><td>(route table consistency)</td></tr><tr><td>98</td><td>Batch identity is frozen at construction (per current implementation)</td><td>✓</td><td>(documented invariant)</td></tr></tbody></table></div>
|
|
886
|
+
<h2 id="sentinels--servertimestamp--increment--arrayunion--arrayremove--deletefield--fieldvalue--timestamp">Sentinels — <code>serverTimestamp</code> / <code>increment</code> / <code>arrayUnion</code> / <code>arrayRemove</code> / <code>deleteField</code> / <code>FieldValue</code> / <code>Timestamp</code></h2>
|
|
887
|
+
<div class="table-scroll">
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>99</td><td><code>serverTimestamp()</code> resolves to a <code>Timestamp</code> after the write commits</td><td>✓</td><td><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>scripts/oracle/observations/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.</td></tr><tr><td>100</td><td><code>increment(n)</code> atomically bumps a numeric field; <code>null</code>/missing field starts from 0</td><td>✓</td><td><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>scripts/oracle/observations/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).</td></tr><tr><td>101</td><td><code>arrayUnion(...values)</code> de-dupes against existing members <strong>and</strong> against duplicate args within the same call</td><td>✓</td><td><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>scripts/oracle/observations/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.</td></tr><tr><td>102</td><td><code>arrayRemove(...values)</code> strips matching members; values not present in the array are silent no-ops</td><td>✓</td><td><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>scripts/oracle/observations/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).</td></tr><tr><td>103</td><td><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.</td><td>✓</td><td><code>playground:firestore-sentinels</code> (bundled) + <code>playground:firestore-row-103-deletefield-removes-field</code> (one-claim), oracle: <code>scripts/oracle/observations/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)</td></tr><tr><td>104</td><td><code>Timestamp</code> shape (<code>{seconds, nanoseconds}</code>) is identical between prod and sandbox — round-trips cleanly</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>104b</td><td><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*1000) * 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>.</td><td>✓</td><td><code>unit:admin-compat/timestamp-api.test.ts</code> (negative-millis round-trip + value API; pre-fix lacked the methods and mis-normalized)</td></tr><tr><td>104a</td><td><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.</td><td>✓</td><td><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)</td></tr><tr><td>105</td><td><code>FieldValue</code> re-exported from <code>pyric-admin</code> (alias of <code>ChainFieldValue</code>)</td><td>✓</td><td>type-only smoke</td></tr><tr><td>105a</td><td><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>).</td><td>✓</td><td><code>unit:simulator/converters/fieldvalue.test.ts</code> (FS-B11 overwrite block + flipped unit/integration/batch cases; verified failing pre-fix)</td></tr></tbody></table></div>
|
|
959
|
+
<h2 id="scalar-types--bytes--geopoint--fieldpath--documentid">Scalar types — <code>Bytes</code> / <code>GeoPoint</code> / <code>FieldPath</code> / <code>documentId</code></h2>
|
|
960
|
+
<div class="table-scroll">
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
|
|
977
|
+
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
|
|
992
|
+
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
|
|
1007
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>106</td><td>Constructors are re-exported from <code>firebase/firestore</code> — <code>new Bytes(…)</code>, <code>new GeoPoint(lat, lng)</code>, <code>new FieldPath(...)</code>, <code>documentId()</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“Bytes / GeoPoint / FieldPath / documentId are re-exported”)</td></tr><tr><td>107</td><td><code>documentId()</code> works in <code>where(documentId(), 'in', [...])</code> against the sandbox</td><td>✓</td><td>(chainable adapter recognizes the FieldPath sentinel)</td></tr><tr><td>108</td><td><code>FieldPath</code> (nested) works in queries against sandbox</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>109</td><td><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</td><td>✓</td><td><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>scripts/oracle/observations/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. Sandbox converters at <code>packages/pyric/src/sandbox/firestore/converters/bytes-geopoint.ts</code> duck-type-detect <code>fb.Bytes</code> and store as the rules <code>Bytes</code> wrapper; <code>pyric/firestore</code> finalizes the read back to <code>fb.Bytes</code> so consumer code matches prod’s <code>instanceof</code> semantics.</td></tr><tr><td>110</td><td><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</td><td>✓</td><td><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>scripts/oracle/observations/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 the read back to <code>fb.GeoPoint</code>.</td></tr><tr><td>111</td><td>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</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code> (“Bytes + GeoPoint + VectorValue round-trip”, top-level + nested). <code>vector()</code> / <code>VectorValue</code> re-exported from <code>firebase/firestore</code>; the sandbox converter at <code>converters/vector.ts</code> duck-types the VectorValue and stores the rules <code>Vector</code> wrapper; <code>pyric/firestore</code> finalizes the read back to <code>fb.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.</td></tr></tbody></table></div>
|
|
1008
|
+
<h2 id="equality-helpers--refequal--queryequal--snapshotequal">Equality helpers — <code>refEqual</code> / <code>queryEqual</code> / <code>snapshotEqual</code></h2>
|
|
1009
|
+
<div class="table-scroll">
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>112</td><td><code>refEqual(a, b)</code> — true when paths match under the same target</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>113</td><td><code>refEqual</code> is <code>true</code> for cross-flavor sandbox vs sandbox-live refs at the same path</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“refEqual returns true for live and frozen refs at the same path”)</td></tr><tr><td>114</td><td><code>refEqual</code> is <code>false</code> for refs at different paths</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code></td></tr><tr><td>115</td><td><code>refEqual(sandboxRef, prodRef)</code> throws <code>TypeError</code> — crossing targets is a programming error</td><td>✓</td><td>(documented invariant in <code>targetMatch</code>)</td></tr><tr><td>116</td><td><code>queryEqual(a, b)</code> — true on identity for sandbox; structural for prod via <code>fb.queryEqual</code></td><td>⚠</td><td>divergence: sandbox does identity-only; prod does deep structural. Oracle-locked: <code>scripts/oracle/observations/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.</td></tr><tr><td>117</td><td><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</td><td>⚠</td><td>divergence, oracle-locked by <code>scripts/oracle/observations/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.</td></tr><tr><td>118</td><td>Cross-flavor <code>refEqual</code> via <code>QuerySnapshot.docs[i].ref</code> works</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“cross-flavor refEqual via QuerySnapshot doc refs”)</td></tr></tbody></table></div>
|
|
1063
|
+
<h2 id="connectfirestoreemulator"><code>connectFirestoreEmulator</code></h2>
|
|
1064
|
+
<div class="table-scroll">
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
|
|
1070
|
+
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
|
|
1083
|
+
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>119</td><td>No-op on sandbox-target handles (the sandbox already IS a local emulator)</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>120</td><td>Forwards to <code>fb.connectFirestoreEmulator</code> on prod-target handles</td><td>✓</td><td><code>unit:prod-target.test.ts</code></td></tr><tr><td>121</td><td><code>mockUserToken</code> option pass-through on prod</td><td>✓</td><td>type-only smoke</td></tr></tbody></table></div>
|
|
1094
|
+
<h2 id="sandbox--sandbox-only-ops"><code>sandbox.*</code> — sandbox-only ops</h2>
|
|
1095
|
+
<div class="table-scroll">
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>122</td><td><code>sandbox.setRules(db, rules)</code> loads rules into the underlying <code>LocalEnvironment</code>; returns <code>LintResult</code></td><td>✓</td><td><code>unit:sandbox-target.test.ts</code>, <code>playground:rules-data-validation</code>, <code>playground:rules-cross-doc-get</code></td></tr><tr><td>123</td><td><code>sandbox.seedDocuments(db, {path: data, ...})</code> bulk-loads bypassing rules</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>124</td><td><code>sandbox.snapshotState(db)</code> dumps every document the LocalEnvironment has stored</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>125</td><td>All <code>sandbox.*</code> methods throw <code>SandboxError('failed-precondition')</code> on prod-target handles</td><td>✓</td><td><code>unit:sandbox-target.test.ts</code></td></tr><tr><td>126</td><td>All <code>sandbox.*</code> methods work on a sandbox-live handle (route through <code>sandboxDb</code>)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“sandboxOps.setRules + seedDocuments + snapshotState work on a live handle”)</td></tr></tbody></table></div>
|
|
1137
|
+
<h2 id="rules-engine-via-sandboxsetrules">Rules engine (via <code>sandbox.setRules</code>)</h2>
|
|
1138
|
+
<p>Rules-engine behavior is technically <code>pyric-admin</code>’s <code>LocalEnvironment</code>,
|
|
1139
|
+
but it’s the most-tested surface for divergence — <code>request.auth</code>,
|
|
1140
|
+
cross-doc reads via <code>get()</code>, data validation. These rows pin the
|
|
1141
|
+
shape consumer code depends on.</p>
|
|
1142
|
+
<div class="table-scroll">
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
|
|
1153
|
+
|
|
1154
|
+
|
|
1155
|
+
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
|
|
1162
|
+
|
|
1163
|
+
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
|
|
1173
|
+
|
|
1174
|
+
|
|
1175
|
+
|
|
1176
|
+
|
|
1177
|
+
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
|
|
1186
|
+
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
|
|
1190
|
+
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
|
|
1194
|
+
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
|
|
1204
|
+
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
|
|
1212
|
+
|
|
1213
|
+
|
|
1214
|
+
|
|
1215
|
+
|
|
1216
|
+
|
|
1217
|
+
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
|
|
1230
|
+
|
|
1231
|
+
|
|
1232
|
+
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
|
|
1248
|
+
|
|
1249
|
+
<table><thead><tr><th>#</th><th>Behavior</th><th>Status</th><th>Probe</th></tr></thead><tbody><tr><td>127</td><td><code>request.auth.uid</code> reads through to <code>sandbox.currentUser?.uid</code> on sandbox-live</td><td>✓</td><td><code>playground:auth-anonymous</code>, <code>playground:rules-cross-doc-get</code></td></tr><tr><td>128</td><td><code>request.auth == null</code> when sandbox.currentUser is null (anonymous path)</td><td>✓</td><td><code>unit:sandbox-live-identity.test.ts</code> (“anonymous fallback”)</td></tr><tr><td>129</td><td>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)</td><td>✓</td><td><code>playground:rules-cross-doc-get</code>, <code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B8 block)</td></tr><tr><td>130</td><td><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></td><td>✓</td><td><code>playground:rules-data-validation</code>, <code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B2 block)</td></tr><tr><td>131</td><td><code>resource.data.<field></code> (existing doc on writes) works under sandbox; undefined-field reads ERROR (RULES-B2)</td><td>✓</td><td><code>playground:rules-resource-data-field</code>, <code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B2 block)</td></tr><tr><td>132</td><td>Custom claims in <code>request.auth.token.<claim></code></td><td>✓</td><td><code>playground:rules-custom-claims</code></td></tr><tr><td>133</td><td>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)</td><td>✓</td><td><code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B2 / RULES-B3 / RULES-B8 blocks)</td></tr><tr><td>134</td><td><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)</td><td>✓</td><td><code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B4 block)</td></tr><tr><td>135</td><td>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)</td><td>✓</td><td><code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B7 block)</td></tr><tr><td>136</td><td>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)</td><td>✓</td><td><code>unit:rules/simulator/evaluator.test.ts</code> (RULES-B6 / B9 / B12 blocks)</td></tr><tr><td>136b</td><td><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</td><td>✓</td><td><code>unit:rules/simulator/set-equality.test.ts</code>; live validation: 10/10 both engines</td></tr><tr><td>137</td><td><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)</td><td>✓</td><td><code>unit:rules/simulator/handler.test.ts</code> (RULES-B10 block)</td></tr><tr><td>138</td><td>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)</td><td>✓</td><td><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)</td></tr><tr><td>138a</td><td>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)</td><td>⚠</td><td>DEFERRED — see the design rationale (limitation + sub-items); strict-bool also in <code>step-07</code>.</td></tr><tr><td>139</td><td>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)</td><td>✓</td><td><code>unit:rules/simulator/query-proof.test.ts</code></td></tr><tr><td>139a</td><td>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)</td><td>✓</td><td><code>unit:firestore/query-proof-enforcement.test.ts</code> (both paths; verified failing pre-fix); prover scope caveat: row 24c</td></tr></tbody></table></div>
|
|
1250
|
+
<h2 id="deny-list-intentionally-not-shimmed">Deny-list (intentionally NOT shimmed)</h2>
|
|
1251
|
+
<p>These exist in <code>firebase/firestore</code> but the sandbox refuses to
|
|
1252
|
+
import/use them. The agent’s writeApp prompt and the deploy
|
|
1253
|
+
bundle’s metafile gate enforce the deny-list at build time.</p>
|
|
1254
|
+
<div class="table-scroll">
|
|
1255
|
+
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
|
|
1268
|
+
|
|
1269
|
+
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
|
|
1273
|
+
|
|
1274
|
+
|
|
1275
|
+
|
|
1276
|
+
|
|
1277
|
+
|
|
1278
|
+
|
|
1279
|
+
|
|
1280
|
+
|
|
1281
|
+
|
|
1282
|
+
|
|
1283
|
+
|
|
1284
|
+
|
|
1285
|
+
|
|
1286
|
+
|
|
1287
|
+
|
|
1288
|
+
|
|
1289
|
+
|
|
1290
|
+
|
|
1291
|
+
|
|
1292
|
+
|
|
1293
|
+
|
|
1294
|
+
|
|
1295
|
+
<table><thead><tr><th>Name</th><th>Reason</th></tr></thead><tbody><tr><td><code>enableIndexedDbPersistence</code> / <code>enableMultiTabIndexedDbPersistence</code> / <code>persistentLocalCache</code> / <code>memoryLocalCache</code></td><td>Persistence story is owned by <code>pyric/sandbox</code> (IndexedDB + memory backends); the modular SDK’s cache APIs would conflict</td></tr><tr><td><code>clearIndexedDbPersistence</code></td><td>Same as above</td></tr><tr><td><code>waitForPendingWrites</code> / <code>disableNetwork</code> / <code>enableNetwork</code></td><td>No network in the sandbox; semantically vacuous</td></tr><tr><td><code>terminate</code></td><td>Handled by <code>Sandbox.dispose()</code> at the host level</td></tr><tr><td><code>loadBundle</code> / <code>namedQuery</code></td><td>Bundle-loading depends on server-side packaging not modeled in sandbox</td></tr><tr><td><code>getDocFromCache</code> / <code>getDocFromServer</code> / <code>getDocsFromCache</code> / <code>getDocsFromServer</code></td><td>No cache/server split in sandbox</td></tr><tr><td><code>onSnapshotsInSync</code></td><td>Cross-listener sync semantics not modeled</td></tr><tr><td><code>setLogLevel</code></td><td>Sandbox uses host-level logging, not the modular SDK’s logger</td></tr></tbody></table></div>
|
|
1296
|
+
<hr>
|
|
1297
|
+
<h2 id="visible-gaps-to-address-next">Visible gaps to address next</h2>
|
|
1298
|
+
<p>Rows currently marked <strong>?</strong> (need explicit probes): none — #132
|
|
1299
|
+
landed with <code>playground:rules-custom-claims</code> after the preview-scope
|
|
1300
|
+
expansion exposed <code>sandbox.seedUsers</code> via the <code>firebase/auth</code> virtual
|
|
1301
|
+
re-export.</p>
|
|
1302
|
+
<p>Rows <strong>locked by the empirical oracle harness</strong> (committed observations under <code>scripts/oracle/observations/</code>, captured against the <code>blockingfun</code> project):</p>
|
|
1303
|
+
<ul>
|
|
1304
|
+
<li>#21 rules-denied error class — oracle confirmed prod throws <code>FirebaseError</code> with <code>.code === 'permission-denied'</code>.</li>
|
|
1305
|
+
<li>#39 <code>deleteDoc</code> on missing doc — oracle confirmed prod no-ops; sandbox fix landed (see below).</li>
|
|
1306
|
+
<li>#45 <code>addDoc</code> auto-id format — oracle confirmed prod mints 20-char alphanumeric (mixed upper/lower/digits, no other chars).</li>
|
|
1307
|
+
<li>#79 aggregate cost / shape — oracle confirmed <code>data()</code> returns <code>{ count: number }</code> only; empty query returns <code>count: 0</code>.</li>
|
|
1308
|
+
<li>#85 <code>includeMetadataChanges</code> — oracle confirmed prod fires +1 extra time per write (the server-confirmed transition); default listener fires twice for one write (initial + pending).</li>
|
|
1309
|
+
<li>#109 <code>Bytes</code> round-trip — oracle confirmed prod <code>setDoc</code>+<code>getDoc</code> round-trips as a <code>Bytes</code> instance with the same base64; sandbox now matches via the converter + read finalization (see row).</li>
|
|
1310
|
+
<li>#110 <code>GeoPoint</code> round-trip — oracle confirmed prod <code>setDoc</code>+<code>getDoc</code> round-trips as a <code>GeoPoint</code> instance with the same lat/lng; sandbox now matches via the converter + read finalization (see row).</li>
|
|
1311
|
+
<li>#116 <code>queryEqual</code> semantics — oracle confirmed structural in prod.</li>
|
|
1312
|
+
<li>#117 <code>snapshotEqual</code> semantics — oracle showed identity-only in prod; row corrected from ⚠ to ✓.</li>
|
|
1313
|
+
</ul>
|
|
1314
|
+
<p>Rows currently marked <strong>⚠</strong> that we might want to upgrade to <strong>✓</strong>
|
|
1315
|
+
(by aligning the sandbox to prod or by formally documenting the
|
|
1316
|
+
divergence in <code>feature-matrix.md</code>):</p>
|
|
1317
|
+
<ul>
|
|
1318
|
+
<li>#21 rules-denied error class (<code>SandboxError</code> vs <code>FirebaseError</code>)</li>
|
|
1319
|
+
<li>#45 auto-id format</li>
|
|
1320
|
+
<li>#66 index validation parity (sandbox would benefit from a strict mode that errors when no index would exist in prod)</li>
|
|
1321
|
+
<li>#79 aggregate cost model</li>
|
|
1322
|
+
<li>#85 <code>includeMetadataChanges</code></li>
|
|
1323
|
+
<li>#93 transaction retry / contention model</li>
|
|
1324
|
+
<li>#116 <code>queryEqual</code> structural equality (sandbox identity-only; prod structural per oracle)</li>
|
|
1325
|
+
</ul>
|
|
1326
|
+
<p>Rows currently marked <strong>—</strong> that we might want to fill (rough priority):</p>
|
|
1327
|
+
<ol>
|
|
1328
|
+
<li>Admin/server vector surface: <code>FieldValue.vector()</code> write + <code>findNearest</code>
|
|
1329
|
+
search live on <code>firebase-admin</code> / <code>pyric-admin</code>, NOT this client matrix (the
|
|
1330
|
+
web client SDK has neither). The client value type (#111) now conforms; the
|
|
1331
|
+
admin surface has no COMPAT matrix yet, and vector search is staged for Phase
|
|
1332
|
+
5b. See the design rationale.</li>
|
|
1333
|
+
</ol>
|
|
1334
|
+
<h2 id="probe-coverage-summary">Probe coverage summary</h2>
|
|
1335
|
+
<ul>
|
|
1336
|
+
<li><strong>Unit (<code>packages/pyric/test/firestore/</code>):</strong> ~80 tests across 4 files cover the bulk of the surface. The two main files are <code>sandbox-target.test.ts</code> (frozen-ctx, the API-shape conformance suite) and <code>sandbox-live-identity.test.ts</code> (per-op identity behavior). <code>prod-target.test.ts</code> runs against an emulator; <code>prod-integration.test.ts</code> requires a real project (gated).</li>
|
|
1337
|
+
<li><strong>Playground fixtures (<code>packages/playground/scripts/fixtures/</code>):</strong> 8 firestore-related fixtures: <code>firestore-bare-getfirestore</code>, <code>firestore-onsnapshot</code>, <code>firestore-query</code>, <code>firestore-transaction</code>, <code>firestore-batch</code>, <code>firestore-sentinels</code>, <code>rules-cross-doc-get</code>, <code>rules-data-validation</code>. Run via <code>bun run debug:fixtures</code>.</li>
|
|
1338
|
+
</ul>
|
|
1339
|
+
<h2 id="next-refactors-per-the-methodology">Next refactors per the methodology</h2>
|
|
1340
|
+
<p>Per the design rationale’s “What’s next” section:</p>
|
|
1341
|
+
<ol>
|
|
1342
|
+
<li><strong>Probe-per-matrix-row.</strong> Today’s fixtures + unit tests cover 3-5 behaviors each. Splitting into one probe per row makes failures point at exactly one violation. The current bundled probes stay as integration tests; the new probe-per-row set becomes the conformance gate.</li>
|
|
1343
|
+
<li><strong>Empirical oracle harness.</strong> Several rows marked <strong>?</strong> are ambiguous from docs alone. The harness at <code>scripts/oracle/run.ts</code> runs the probes against a real Firebase project and writes observations to <code>scripts/oracle/observations/<name>.json</code>. Initial coverage locks #39, #116, #117 (above). Extend with additional probes for the remaining <code>?</code> and <code>⚠</code> rows.</li>
|
|
1344
|
+
<li><strong>CI gate.</strong> <code>bun run debug:fixtures</code> becomes a required check on every PR that touches <code>packages/firestore</code>.</li>
|
|
1345
|
+
</ol> </article> </main> <aside class="doc-toc" aria-label="On this page"> <h2 class="doc-toc-heading">On this page</h2> <ul> <li data-depth="2"> <a href="#status-legend">Status legend</a> </li><li data-depth="2"> <a href="#getfirestoretarget--initializer">getFirestore(target) — initializer</a> </li><li data-depth="2"> <a href="#path-constructors--doc--collection--collectiongroup">Path constructors — doc / collection / collectionGroup</a> </li><li data-depth="2"> <a href="#getdocref--single-doc-read">getDoc(ref) — single-doc read</a> </li><li data-depth="2"> <a href="#getdocsquery--bulk-read">getDocs(query) — bulk read</a> </li><li data-depth="2"> <a href="#setdocref-data-options--full-write">setDoc(ref, data[, options]) — full write</a> </li><li data-depth="2"> <a href="#updatedocref-data--partial-write">updateDoc(ref, data) — partial write</a> </li><li data-depth="2"> <a href="#deletedocref">deleteDoc(ref)</a> </li><li data-depth="2"> <a href="#adddoccoll-data--auto-id-write">addDoc(coll, data) — auto-id write</a> </li><li data-depth="2"> <a href="#withconverter--typed-refs">withConverter — typed refs</a> </li><li data-depth="2"> <a href="#query-construction--query--where--or--and--orderby--limit">Query construction — query / where / or / and / orderBy / limit</a> </li><li data-depth="2"> <a href="#cursor-pagination--startat--startafter--endat--endbefore">Cursor pagination — startAt / startAfter / endAt / endBefore</a> </li><li data-depth="2"> <a href="#aggregates--getcountfromserver--getaggregatefromserver--count--sum--average">Aggregates — getCountFromServer / getAggregateFromServer / count / sum / average</a> </li><li data-depth="2"> <a href="#onsnapshotreforquery---listeners">onSnapshot(refOrQuery, …) — listeners</a> </li><li data-depth="2"> <a href="#runtransactiondb-fn">runTransaction(db, fn)</a> </li><li data-depth="2"> <a href="#writebatchdb">writeBatch(db)</a> </li><li data-depth="2"> <a href="#sentinels--servertimestamp--increment--arrayunion--arrayremove--deletefield--fieldvalue--timestamp">Sentinels — serverTimestamp / increment / arrayUnion / arrayRemove / deleteField / FieldValue / Timestamp</a> </li><li data-depth="2"> <a href="#scalar-types--bytes--geopoint--fieldpath--documentid">Scalar types — Bytes / GeoPoint / FieldPath / documentId</a> </li><li data-depth="2"> <a href="#equality-helpers--refequal--queryequal--snapshotequal">Equality helpers — refEqual / queryEqual / snapshotEqual</a> </li><li data-depth="2"> <a href="#connectfirestoreemulator">connectFirestoreEmulator</a> </li><li data-depth="2"> <a href="#sandbox--sandbox-only-ops">sandbox.* — sandbox-only ops</a> </li><li data-depth="2"> <a href="#rules-engine-via-sandboxsetrules">Rules engine (via sandbox.setRules)</a> </li><li data-depth="2"> <a href="#deny-list-intentionally-not-shimmed">Deny-list (intentionally NOT shimmed)</a> </li><li data-depth="2"> <a href="#visible-gaps-to-address-next">Visible gaps to address next</a> </li><li data-depth="2"> <a href="#probe-coverage-summary">Probe coverage summary</a> </li><li data-depth="2"> <a href="#next-refactors-per-the-methodology">Next refactors per the methodology</a> </li> </ul> </aside> </div> <script type="module">const s=new Map;document.querySelectorAll('.doc-toc a[href^="#"]').forEach(t=>s.set(decodeURIComponent(t.hash.slice(1)),t));if(s.size>0){const t=new Set,n=()=>{let o=null;for(const e of s.keys())if(t.has(e)){o=e;break}s.forEach((e,c)=>e.classList.toggle("active",c===o))},r=new IntersectionObserver(o=>{for(const e of o)e.isIntersecting?t.add(e.target.id):t.delete(e.target.id);n()},{rootMargin:"-72px 0px -60% 0px"});s.forEach((o,e)=>{const c=document.getElementById(e);c&&r.observe(c)})}</script> </body> </html>
|