@pyric/cli 0.1.0-alpha.11 → 0.1.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/serve.js +4 -4
- package/dist/cli/serve.js.map +1 -1
- package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
- package/dist/conformance/.generated/can-i-use-browser.js +1 -1
- package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
- package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
- package/dist/conformance/.generated/can-i-use.js +2 -2
- package/dist/conformance/.generated/can-i-use.js.map +1 -1
- package/dist/serve/bundler.d.ts +13 -8
- package/dist/serve/bundler.d.ts.map +1 -1
- package/dist/serve/bundler.js +31 -36
- package/dist/serve/bundler.js.map +1 -1
- package/dist/serve/docs-ui/docs/_rhythm/index.html +1 -1
- package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +1 -1
- package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +1 -1
- package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +1 -1
- package/dist/serve/docs-ui/docs/ai-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/api-reference/index.html +2 -2
- package/dist/serve/docs-ui/docs/api-reference.md +1 -1
- package/dist/serve/docs-ui/docs/app-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/auth-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/ai-logic/index.html +44 -22
- package/dist/serve/docs-ui/docs/build/ai-logic.md +69 -21
- package/dist/serve/docs-ui/docs/build/authentication/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/realtime-database/index.html +1 -1
- package/dist/serve/docs-ui/docs/conformance-scores/index.html +1 -1
- package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/database-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/firestore-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +2 -1
- package/dist/serve/docs-ui/docs/get-started/how-the-swap-works.md +2 -0
- package/dist/serve/docs-ui/docs/get-started/start-building/index.html +3 -2
- package/dist/serve/docs-ui/docs/get-started/start-building.md +3 -1
- package/dist/serve/docs-ui/docs/index.json +349 -29
- package/dist/serve/docs-ui/docs/messaging-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/observe/resolve-runtime-status/index.html +28 -0
- package/dist/serve/docs-ui/docs/observe/resolve-runtime-status.md +47 -0
- package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +1 -1
- package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +1 -1
- package/dist/serve/docs-ui/docs/overview/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api/index.html +916 -0
- package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api.md +706 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +168 -76
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +156 -73
- package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +11 -8
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +17 -4
- package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +37 -14
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +28 -8
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/rules-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
- package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +1 -1
- package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +1 -1
- package/dist/serve/docs-ui/docs/storage-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
- package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
- package/dist/serve/docs-ui/docs/tutorial/index.html +429 -0
- package/dist/serve/docs-ui/docs/tutorial.md +701 -0
- package/dist/serve/docs-ui/llms.txt +3 -1
- package/dist/serve/entries/init.d.ts.map +1 -1
- package/dist/serve/entries/init.js +3 -0
- package/dist/serve/entries/init.js.map +1 -1
- package/dist/serve/entries/runtime.d.ts.map +1 -1
- package/dist/serve/entries/runtime.js +20 -5
- package/dist/serve/entries/runtime.js.map +1 -1
- package/dist/serve/entries/worker-runtime.d.ts +2 -2
- package/dist/serve/entries/worker-runtime.d.ts.map +1 -1
- package/dist/serve/entries/worker-runtime.js +45 -10
- package/dist/serve/entries/worker-runtime.js.map +1 -1
- package/dist/serve/runtime/chip-config.d.ts +19 -0
- package/dist/serve/runtime/chip-config.d.ts.map +1 -0
- package/dist/serve/runtime/chip-config.js +19 -0
- package/dist/serve/runtime/chip-config.js.map +1 -0
- package/dist/serve/runtime/chip-install.d.ts +10 -0
- package/dist/serve/runtime/chip-install.d.ts.map +1 -0
- package/dist/serve/runtime/chip-install.js +15 -0
- package/dist/serve/runtime/chip-install.js.map +1 -0
- package/dist/serve/runtime/chip.d.ts +17 -0
- package/dist/serve/runtime/chip.d.ts.map +1 -0
- package/dist/serve/runtime/chip.js +257 -0
- package/dist/serve/runtime/chip.js.map +1 -0
- package/dist/serve/runtime/manifest.d.ts +22 -0
- package/dist/serve/runtime/manifest.d.ts.map +1 -0
- package/dist/serve/runtime/manifest.js +20 -0
- package/dist/serve/runtime/manifest.js.map +1 -0
- package/dist/serve/runtime/status.d.ts +49 -0
- package/dist/serve/runtime/status.d.ts.map +1 -0
- package/dist/serve/runtime/status.js +164 -0
- package/dist/serve/runtime/status.js.map +1 -0
- package/dist/serve/runtime/worker-connection.d.ts +4 -0
- package/dist/serve/runtime/worker-connection.d.ts.map +1 -0
- package/dist/serve/runtime/worker-connection.js +11 -0
- package/dist/serve/runtime/worker-connection.js.map +1 -0
- package/dist/serve/runtime/worker-generation.d.ts +14 -0
- package/dist/serve/runtime/worker-generation.d.ts.map +1 -0
- package/dist/serve/runtime/worker-generation.js +56 -0
- package/dist/serve/runtime/worker-generation.js.map +1 -0
- package/dist/serve/runtime/worker-replacement.d.ts +18 -0
- package/dist/serve/runtime/worker-replacement.d.ts.map +1 -0
- package/dist/serve/runtime/worker-replacement.js +29 -0
- package/dist/serve/runtime/worker-replacement.js.map +1 -0
- package/dist/serve/standalone-assets.d.ts +2 -2
- package/dist/serve/standalone-assets.d.ts.map +1 -1
- package/dist/serve/standalone-assets.js +1 -1
- package/dist/serve/standalone-assets.js.map +1 -1
- package/dist/serve/studio-ui/assets/{RulesCodeEditor-CxVYcZXw.js → RulesCodeEditor-BDlH-5lp.js} +1 -1
- package/dist/serve/studio-ui/assets/{index-cpSfgQ7H.js → index-Bf9SSE8L.js} +5 -5
- package/dist/serve/studio-ui/assets/{seed-DeuFKi4J.js → seed-D_UjxfOU.js} +1 -1
- package/dist/serve/studio-ui/index.html +1 -1
- package/dist/serve/vite-ai-config.d.ts +25 -0
- package/dist/serve/vite-ai-config.d.ts.map +1 -0
- package/dist/serve/vite-ai-config.js +45 -0
- package/dist/serve/vite-ai-config.js.map +1 -0
- package/dist/serve/vite-plugin.d.ts +17 -36
- package/dist/serve/vite-plugin.d.ts.map +1 -1
- package/dist/serve/vite-plugin.js +38 -57
- package/dist/serve/vite-plugin.js.map +1 -1
- package/dist/serve/vite-rules-source.d.ts +8 -0
- package/dist/serve/vite-rules-source.d.ts.map +1 -0
- package/dist/serve/vite-rules-source.js +23 -0
- package/dist/serve/vite-rules-source.js.map +1 -0
- package/dist/serve/vite-worker-runtime.d.ts +20 -0
- package/dist/serve/vite-worker-runtime.d.ts.map +1 -0
- package/dist/serve/vite-worker-runtime.js +25 -0
- package/dist/serve/vite-worker-runtime.js.map +1 -0
- package/dist/serve/worker/client/connection.d.ts +7 -2
- package/dist/serve/worker/client/connection.d.ts.map +1 -1
- package/dist/serve/worker/client/connection.js +13 -16
- package/dist/serve/worker/client/connection.js.map +1 -1
- package/dist/serve/worker/client/core.d.ts +7 -0
- package/dist/serve/worker/client/core.d.ts.map +1 -1
- package/dist/serve/worker/client/core.js +28 -0
- package/dist/serve/worker/client/core.js.map +1 -1
- package/dist/serve/worker/client/runtime-control.d.ts +8 -0
- package/dist/serve/worker/client/runtime-control.d.ts.map +1 -0
- package/dist/serve/worker/client/runtime-control.js +11 -0
- package/dist/serve/worker/client/runtime-control.js.map +1 -0
- package/dist/serve/worker/entry.js +44 -2
- package/dist/serve/worker/entry.js.map +1 -1
- package/dist/serve/worker/host/core.js +1 -1
- package/dist/serve/worker/host/core.js.map +1 -1
- package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -1
- package/dist/serve/worker/host/firestore-writes.js +3 -2
- package/dist/serve/worker/host/firestore-writes.js.map +1 -1
- package/dist/serve/worker/host/studio.js +1 -1
- package/dist/serve/worker/host/studio.js.map +1 -1
- package/dist/serve/worker/host-context.d.ts +1 -1
- package/dist/serve/worker/host-context.d.ts.map +1 -1
- package/dist/serve/worker/index.d.ts +2 -1
- package/dist/serve/worker/index.d.ts.map +1 -1
- package/dist/serve/worker/index.js +2 -1
- package/dist/serve/worker/index.js.map +1 -1
- package/dist/serve/worker/protocol.d.ts +15 -1
- package/dist/serve/worker/protocol.d.ts.map +1 -1
- package/dist/serve/worker/protocol.js +2 -2
- package/dist/serve/worker/protocol.js.map +1 -1
- package/dist/serve/worker/retirement.d.ts +21 -0
- package/dist/serve/worker/retirement.d.ts.map +1 -0
- package/dist/serve/worker/retirement.js +97 -0
- package/dist/serve/worker/retirement.js.map +1 -0
- package/dist/serve/worker/serve-init.d.ts.map +1 -1
- package/dist/serve/worker/serve-init.js +5 -6
- package/dist/serve/worker/serve-init.js.map +1 -1
- package/dist/vite.d.ts +1 -0
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js.map +1 -1
- package/package.json +6 -4
- package/src/assurance/.generated/conformance-verdicts.ts +1090 -0
- package/src/assurance/attachment.ts +211 -0
- package/src/assurance/browser.ts +80 -0
- package/src/assurance/campaign.ts +496 -0
- package/src/assurance/capabilities.ts +446 -0
- package/src/assurance/cases.ts +43 -0
- package/src/assurance/index.ts +75 -0
- package/src/assurance/runner.ts +885 -0
- package/src/assurance/tool-names.ts +15 -0
- package/src/assurance/tools.ts +830 -0
- package/src/assurance/types.ts +352 -0
- package/src/assurance/validation.ts +434 -0
- package/src/bridge/client/bridge.ts +550 -0
- package/src/bridge/client/dispatch.ts +137 -0
- package/src/bridge/client.ts +45 -0
- package/src/bridge/protocol.ts +351 -0
- package/src/bridge/server/audit.ts +53 -0
- package/src/bridge/server/bridge.ts +597 -0
- package/src/bridge/server/headless.ts +160 -0
- package/src/bridge/server/json-schema-to-zod.ts +108 -0
- package/src/bridge/server/local-bridge.ts +66 -0
- package/src/bridge/server/logger.ts +50 -0
- package/src/bridge/server/mcp-contract.ts +93 -0
- package/src/bridge/server/mcp.ts +129 -0
- package/src/bridge/server/peer.ts +232 -0
- package/src/bridge/server/standalone.ts +347 -0
- package/src/bridge/server/tool-metadata.ts +99 -0
- package/src/bridge/server.ts +28 -0
- package/src/cli/can-i-use.ts +50 -0
- package/src/cli/cli.test.ts +493 -0
- package/src/cli/database-rules.ts +329 -0
- package/src/cli/dev-runner.ts +282 -0
- package/src/cli/firebase-json.ts +100 -0
- package/src/cli/firestore-indexes.ts +70 -0
- package/src/cli/index.ts +425 -0
- package/src/cli/init.ts +260 -0
- package/src/cli/mcp-proxy.ts +196 -0
- package/src/cli/parse-args.ts +80 -0
- package/src/cli/rules.ts +259 -0
- package/src/cli/scope.ts +67 -0
- package/src/cli/serve.ts +996 -0
- package/src/cli/service-commands.ts +73 -0
- package/src/cli/snapshot.ts +164 -0
- package/src/cli/storage-rules.ts +172 -0
- package/src/cli/verify.ts +416 -0
- package/src/conformance/.generated/can-i-use-browser.ts +113 -0
- package/src/conformance/.generated/can-i-use.ts +117 -0
- package/src/conformance/.generated/conformance-docs.ts +14 -0
- package/src/conformance/browser.ts +24 -0
- package/src/conformance/can-i-use-tool.ts +51 -0
- package/src/conformance/can-i-use.ts +18 -0
- package/src/conformance/docs.ts +8 -0
- package/src/conformance/index.ts +20 -0
- package/src/conformance/tools.ts +16 -0
- package/src/credentials/core/memoize-ttl.ts +142 -0
- package/src/credentials/core/types.ts +10 -0
- package/src/credentials/node/from-adc.ts +96 -0
- package/src/credentials/node/from-service-account.ts +133 -0
- package/src/credentials/node/index.ts +6 -0
- package/src/discover/concurrency.ts +127 -0
- package/src/discover/crawler-adapter.ts +142 -0
- package/src/discover/crawler.ts +1127 -0
- package/src/discover/credential-free.ts +27 -0
- package/src/discover/findCollectionGroup.ts +131 -0
- package/src/discover/firestore-source.ts +59 -0
- package/src/discover/index.ts +5 -0
- package/src/discover/merge.ts +523 -0
- package/src/discover/session.ts +402 -0
- package/src/discover/tools.ts +201 -0
- package/src/discover/types.ts +187 -0
- package/src/discover/wire.ts +324 -0
- package/src/functions-rtdb/child.ts +382 -0
- package/src/functions-rtdb/delivery.ts +7 -0
- package/src/functions-rtdb/discovery.ts +136 -0
- package/src/functions-rtdb/event.ts +64 -0
- package/src/functions-rtdb/execution.ts +111 -0
- package/src/functions-rtdb/in-memory-delivery.ts +40 -0
- package/src/functions-rtdb/project.ts +74 -0
- package/src/functions-rtdb/projection.ts +104 -0
- package/src/functions-rtdb/reference-pattern.ts +20 -0
- package/src/functions-rtdb/remote-delivery.ts +23 -0
- package/src/pkg-version.ts +49 -0
- package/src/register/esm-exports.ts +63 -0
- package/src/register/hooks.ts +30 -0
- package/src/register/index.ts +150 -0
- package/src/register/mapping.ts +33 -0
- package/src/remote/index.ts +1050 -0
- package/src/rtdb/crawl-snapshot.ts +118 -0
- package/src/rtdb/inspection.ts +137 -0
- package/src/rtdb/load-rules-document.ts +56 -0
- package/src/rtdb/rules-generation-tool.ts +38 -0
- package/src/rtdb/rules-json.ts +29 -0
- package/src/serve/activity-guard.ts +29 -0
- package/src/serve/activity-route.ts +164 -0
- package/src/serve/activity-warning.ts +26 -0
- package/src/serve/bridge-mount.ts +200 -0
- package/src/serve/bundler.ts +519 -0
- package/src/serve/capture-store.ts +65 -0
- package/src/serve/discovery.ts +199 -0
- package/src/serve/entries/ai.ts +292 -0
- package/src/serve/entries/app-backend.ts +4 -0
- package/src/serve/entries/app-client.ts +26 -0
- package/src/serve/entries/app-session-store.ts +47 -0
- package/src/serve/entries/app.ts +11 -0
- package/src/serve/entries/auth-helper-core.ts +181 -0
- package/src/serve/entries/auth-helper-dom.ts +134 -0
- package/src/serve/entries/auth-helper-runtime.ts +20 -0
- package/src/serve/entries/auth.ts +255 -0
- package/src/serve/entries/bridge-url.ts +31 -0
- package/src/serve/entries/database.ts +129 -0
- package/src/serve/entries/firestore.ts +232 -0
- package/src/serve/entries/init.ts +49 -0
- package/src/serve/entries/keepalive.ts +46 -0
- package/src/serve/entries/messaging-sw.ts +75 -0
- package/src/serve/entries/messaging.ts +96 -0
- package/src/serve/entries/runtime.ts +556 -0
- package/src/serve/entries/session-store.ts +97 -0
- package/src/serve/entries/storage.ts +92 -0
- package/src/serve/entries/tab-sync-wiring.ts +274 -0
- package/src/serve/entries/worker-runtime.ts +135 -0
- package/src/serve/init-payload.ts +42 -0
- package/src/serve/namespace.ts +675 -0
- package/src/serve/open-browser.ts +68 -0
- package/src/serve/rules.ts +272 -0
- package/src/serve/runtime/chip-config.ts +30 -0
- package/src/serve/runtime/chip-install.ts +27 -0
- package/src/serve/runtime/chip.ts +282 -0
- package/src/serve/runtime/manifest.ts +37 -0
- package/src/serve/runtime/status.ts +216 -0
- package/src/serve/runtime/worker-connection.ts +14 -0
- package/src/serve/runtime/worker-generation.ts +75 -0
- package/src/serve/runtime/worker-replacement.ts +42 -0
- package/src/serve/sandbox-marker.ts +31 -0
- package/src/serve/server.ts +428 -0
- package/src/serve/standalone-assets.ts +180 -0
- package/src/serve/state-store.ts +166 -0
- package/src/serve/studio/disk-project-store.ts +185 -0
- package/src/serve/studio/disk-workspace.ts +162 -0
- package/src/serve/studio/index.ts +20 -0
- package/src/serve/studio/routes.ts +237 -0
- package/src/serve/studio/store-types.ts +48 -0
- package/src/serve/studio/studio-storage.test.ts +289 -0
- package/src/serve/vite-ai-config.ts +77 -0
- package/src/serve/vite-plugin.ts +1075 -0
- package/src/serve/vite-rules-source.ts +28 -0
- package/src/serve/vite-worker-runtime.ts +51 -0
- package/src/serve/worker/activity-bootstrap.ts +24 -0
- package/src/serve/worker/client/admin-firestore.ts +38 -0
- package/src/serve/worker/client/ai.ts +124 -0
- package/src/serve/worker/client/auth.ts +489 -0
- package/src/serve/worker/client/connection.ts +227 -0
- package/src/serve/worker/client/core.ts +384 -0
- package/src/serve/worker/client/disconnect.ts +45 -0
- package/src/serve/worker/client/firestore-reads.ts +181 -0
- package/src/serve/worker/client/firestore-refs.ts +226 -0
- package/src/serve/worker/client/firestore-writes.ts +232 -0
- package/src/serve/worker/client/handles.ts +91 -0
- package/src/serve/worker/client/messaging.ts +119 -0
- package/src/serve/worker/client/presence.ts +174 -0
- package/src/serve/worker/client/rtdb.ts +311 -0
- package/src/serve/worker/client/rules.ts +63 -0
- package/src/serve/worker/client/runtime-control.ts +22 -0
- package/src/serve/worker/client/service-worker-connection.ts +59 -0
- package/src/serve/worker/client/snapshots.ts +86 -0
- package/src/serve/worker/client/storage.ts +195 -0
- package/src/serve/worker/client/studio.ts +88 -0
- package/src/serve/worker/client.ts +57 -0
- package/src/serve/worker/durable-persistence.ts +137 -0
- package/src/serve/worker/entry.ts +223 -0
- package/src/serve/worker/host/admin-firestore.ts +88 -0
- package/src/serve/worker/host/connection.ts +179 -0
- package/src/serve/worker/host/core.ts +387 -0
- package/src/serve/worker/host/dispatch.ts +316 -0
- package/src/serve/worker/host/firestore-reads.ts +117 -0
- package/src/serve/worker/host/firestore-writes.ts +456 -0
- package/src/serve/worker/host/presence.ts +312 -0
- package/src/serve/worker/host/rtdb.ts +136 -0
- package/src/serve/worker/host/rules.ts +128 -0
- package/src/serve/worker/host/storage.ts +312 -0
- package/src/serve/worker/host/studio.ts +75 -0
- package/src/serve/worker/host/subscriptions.ts +238 -0
- package/src/serve/worker/host-ai.ts +165 -0
- package/src/serve/worker/host-auth.ts +469 -0
- package/src/serve/worker/host-context.ts +273 -0
- package/src/serve/worker/host-events.ts +94 -0
- package/src/serve/worker/host-messaging.ts +240 -0
- package/src/serve/worker/host.ts +47 -0
- package/src/serve/worker/index.ts +196 -0
- package/src/serve/worker/presence-timing.ts +15 -0
- package/src/serve/worker/protocol.ts +1124 -0
- package/src/serve/worker/retirement.ts +125 -0
- package/src/serve/worker/serve-init.ts +605 -0
- package/src/serve/worker/service-worker-channel.ts +33 -0
- package/src/serve/worker/service-worker-relay.ts +86 -0
- package/src/serve/writer-lock.ts +53 -0
- package/src/verify/cases.ts +233 -0
- package/src/verify/fixture.ts +258 -0
- package/src/verify/index.ts +519 -0
- package/src/verify/tools.ts +108 -0
- package/src/version/compat-target.ts +17 -0
- package/src/vite.ts +18 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -31
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -29
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type system for `firestore_discover_paths`.
|
|
3
|
+
*
|
|
4
|
+
* Locked by the design rationale Decisions Log.
|
|
5
|
+
* Do not change shape without updating that file first; v2's `diff_schemas`
|
|
6
|
+
* tool depends on these types JSON-roundtripping cleanly.
|
|
7
|
+
*
|
|
8
|
+
* Pure types — no runtime imports. Both the merge module and the agent-facing
|
|
9
|
+
* tool surface depend on this file.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ─── Wire-derived field types ─────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Firestore scalar wire types. Matches the discriminator emitted by
|
|
16
|
+
* `_fieldsProto.<field>.valueType` (Phase 0.1 lock).
|
|
17
|
+
*
|
|
18
|
+
* `null` is represented as a scalar so descriptors can carry a single union
|
|
19
|
+
* shape; the merge layer separately tracks `nullable` per descriptor.
|
|
20
|
+
*/
|
|
21
|
+
export type FirestoreScalarType =
|
|
22
|
+
| 'null'
|
|
23
|
+
| 'boolean'
|
|
24
|
+
| 'integer'
|
|
25
|
+
| 'double'
|
|
26
|
+
| 'timestamp'
|
|
27
|
+
| 'string'
|
|
28
|
+
| 'bytes'
|
|
29
|
+
| 'geopoint';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* One observed type for a field. Vector kept distinct from map per Phase 1.2
|
|
33
|
+
* vector-sentinel lock; reference target is the **template-form full path**
|
|
34
|
+
* per Phase 3.1 lock (`users/{userId}/posts`, not `posts`).
|
|
35
|
+
*/
|
|
36
|
+
export type FieldType =
|
|
37
|
+
| { kind: 'scalar'; type: FirestoreScalarType }
|
|
38
|
+
| { kind: 'reference'; targetCollection: string }
|
|
39
|
+
| { kind: 'array'; elementTypes: FieldType[] }
|
|
40
|
+
| { kind: 'map'; fields: Record<string, FieldDescriptor> }
|
|
41
|
+
| { kind: 'vector'; dimension: number | 'mixed' };
|
|
42
|
+
|
|
43
|
+
// ─── Per-field descriptor ─────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Per-field descriptor accumulated across a sampled stream.
|
|
47
|
+
*
|
|
48
|
+
* - `types` is a deduped union; vector-dim drift keeps each dimension as a
|
|
49
|
+
* distinct entry by default (Phase 1.2 lock).
|
|
50
|
+
* - `presenceSeen / presenceTotal` ratio drives presence-based agent UX; the
|
|
51
|
+
* denominator includes docs where the field was absent.
|
|
52
|
+
* - `nullable` is an annotation, not a peer type (Phase 2.1 lock — `null`
|
|
53
|
+
* never appears as a `FieldType` in this descriptor's types[]).
|
|
54
|
+
* - `enumCandidate` populated when the field qualifies per Phase 3.2 lock
|
|
55
|
+
* (`distinct ≤ 10 AND distinct ≤ samplesSeen / 2`); otherwise `undefined`.
|
|
56
|
+
* Tracked only for `scalar:string` and `scalar:integer/double`; other kinds
|
|
57
|
+
* are not enum candidates.
|
|
58
|
+
* - `example` is one observed non-null value per Phase 3.2 lock. Drives form
|
|
59
|
+
* placeholders, fixtures, README payloads. JSON-stringifiable (wire-typed
|
|
60
|
+
* primitives + arrays + plain-object maps).
|
|
61
|
+
* - `reservedReason` populated by the wire layer when the field name matches
|
|
62
|
+
* a reserved-name pattern per 0.B; agents/codegen use it to skip or
|
|
63
|
+
* sanitize the field.
|
|
64
|
+
*/
|
|
65
|
+
export interface FieldDescriptor {
|
|
66
|
+
types: FieldType[];
|
|
67
|
+
presenceSeen: number;
|
|
68
|
+
presenceTotal: number;
|
|
69
|
+
nullable: boolean;
|
|
70
|
+
enumCandidate?: EnumCandidate;
|
|
71
|
+
example?: ExampleValue;
|
|
72
|
+
reservedReason?: ReservedFieldReason;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Captured low-cardinality value set for enum-candidate fields. */
|
|
76
|
+
export interface EnumCandidate {
|
|
77
|
+
/** Whether the field still passes the threshold; flips to false if widened past it. */
|
|
78
|
+
qualifies: boolean;
|
|
79
|
+
/** Distinct values observed so far (string/number); ordered by first-seen. */
|
|
80
|
+
values: Array<string | number>;
|
|
81
|
+
/** Distinct count after which the candidate is dropped (default 10). */
|
|
82
|
+
threshold: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** A representative observed value, JSON-safe. */
|
|
86
|
+
export type ExampleValue =
|
|
87
|
+
| string
|
|
88
|
+
| number
|
|
89
|
+
| boolean
|
|
90
|
+
| null
|
|
91
|
+
| ExampleValue[]
|
|
92
|
+
| { [k: string]: ExampleValue };
|
|
93
|
+
|
|
94
|
+
/** Why a field name is flagged reserved per 0.B. */
|
|
95
|
+
export type ReservedFieldReason =
|
|
96
|
+
| 'firestore_reserved_name' // __name__ etc.
|
|
97
|
+
| 'dotted_field_name' // contains '.', breaks dot-path access
|
|
98
|
+
| 'numeric_field_name' // looks like an array index
|
|
99
|
+
| 'double_underscore_wrap'; // __foo__, conflicts with sentinels
|
|
100
|
+
|
|
101
|
+
// ─── Collection-level schema ──────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Per-collection accumulated schema. `samplesSeen` is the doc count fed
|
|
105
|
+
* through `mergeDoc`, used as the presence denominator.
|
|
106
|
+
*/
|
|
107
|
+
export interface FieldSchema {
|
|
108
|
+
fields: Record<string, FieldDescriptor>;
|
|
109
|
+
samplesSeen: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 4-state classification for sampling termination per Phase 2.2 lock.
|
|
114
|
+
*
|
|
115
|
+
* - `converged_via_stable`: hit `stopOnStable` consecutive no-change docs.
|
|
116
|
+
* Schema is *probably* complete — known false-negative is mid-stream drift
|
|
117
|
+
* later than `stopOnStable` docs into the stable region (out of scope per
|
|
118
|
+
* Phase 2.1 lock; deferred to a future `firestore_re_crawl`).
|
|
119
|
+
* - `converged_via_exhausted`: iterator returned empty before `maxSamples`.
|
|
120
|
+
* Schema is *provably* complete — we read every doc.
|
|
121
|
+
* - `converged_via_max`: hit `maxSamples` cap without converging. Schema may
|
|
122
|
+
* be incomplete; agent should treat with caution.
|
|
123
|
+
* - `sampling_open`: crawl interrupted (continuation boundary). Resume with
|
|
124
|
+
* the returned continuation handle to keep sampling.
|
|
125
|
+
*/
|
|
126
|
+
export type SamplingComplete =
|
|
127
|
+
| 'converged_via_stable'
|
|
128
|
+
| 'converged_via_exhausted'
|
|
129
|
+
| 'converged_via_max'
|
|
130
|
+
| 'sampling_open';
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Schema for a single collection as surfaced in the tool output's
|
|
134
|
+
* `finalizedSchemas`.
|
|
135
|
+
*/
|
|
136
|
+
export interface CollectionSchema {
|
|
137
|
+
templatePath: string; // e.g. "users/{userId}/posts"
|
|
138
|
+
examplePath?: string; // e.g. "users/uid_42/posts" — secondary-tier per 3.2
|
|
139
|
+
schema: FieldSchema;
|
|
140
|
+
samplingComplete: SamplingComplete;
|
|
141
|
+
declaredAt: number | null; // doc index where convergence declared, null if not
|
|
142
|
+
subcollectionTemplatePaths: string[]; // discovered child template paths
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ─── Field path + change events ───────────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Path within a doc to a field. `'[]'` segment denotes array element scope,
|
|
149
|
+
* used for nested-array/map descriptors.
|
|
150
|
+
*/
|
|
151
|
+
export type FieldPath = ReadonlyArray<string | '[]'>;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Frozen `SchemaChange` enum per Phase 5 implementation plan lock. Emitted
|
|
155
|
+
* by the merge layer; carried in `schema_updated` events.
|
|
156
|
+
*
|
|
157
|
+
* Renamed from v1 scope's `ChangeReason` to match the agent-facing terminology
|
|
158
|
+
* in the validation plan's event-model lock.
|
|
159
|
+
*/
|
|
160
|
+
export type SchemaChange =
|
|
161
|
+
| { kind: 'field_added'; path: FieldPath; type: FieldType }
|
|
162
|
+
| { kind: 'type_expanded'; path: FieldPath; addedType: FieldType }
|
|
163
|
+
| { kind: 'presence_changed'; path: FieldPath; presenceSeen: number; presenceTotal: number }
|
|
164
|
+
| { kind: 'enum_added'; path: FieldPath; values: Array<string | number> }
|
|
165
|
+
| { kind: 'enum_widened'; path: FieldPath; addedValue: string | number }
|
|
166
|
+
| { kind: 'enum_dropped'; path: FieldPath; reason: 'over_threshold' | 'type_widened' }
|
|
167
|
+
| { kind: 'vector_dim_drift'; path: FieldPath; addedDimension: number }
|
|
168
|
+
| { kind: 'became_nullable'; path: FieldPath };
|
|
169
|
+
|
|
170
|
+
// ─── Discover events (agent-facing) ───────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Event stream emitted by `firestore_discover_paths`. Frozen enum per
|
|
174
|
+
* Phase 3.3 lock. Order within a batch is meaningful — agents may rely on
|
|
175
|
+
* `collection_discovered` arriving before `schema_updated` for the same path.
|
|
176
|
+
*/
|
|
177
|
+
export type DiscoverEvent =
|
|
178
|
+
| { kind: 'collection_discovered'; templatePath: string; depth: number; parentPath?: string }
|
|
179
|
+
| { kind: 'schema_updated'; templatePath: string; changes: SchemaChange[] }
|
|
180
|
+
| {
|
|
181
|
+
kind: 'sampling_complete';
|
|
182
|
+
templatePath: string;
|
|
183
|
+
samplingComplete: SamplingComplete;
|
|
184
|
+
samplesSeen: number;
|
|
185
|
+
declaredAt: number | null;
|
|
186
|
+
}
|
|
187
|
+
| { kind: 'error'; templatePath: string; code: string; message: string };
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firestore wire-format → FieldObservation conversion.
|
|
3
|
+
*
|
|
4
|
+
* The SDK boundary for `firestore_discover_paths`. Reads the private
|
|
5
|
+
* `DocumentSnapshot._fieldsProto` representation per the Phase 0.1 lock
|
|
6
|
+
* (numberTypeStrategy: "wire" — preserves integerValue/doubleValue
|
|
7
|
+
* distinction at the value boundary).
|
|
8
|
+
*
|
|
9
|
+
* Three responsibilities:
|
|
10
|
+
* 1. Validate `_fieldsProto` is present and shaped as expected. Fail
|
|
11
|
+
* loud if absent (prerequisite 0.A — silent fallback to data() would
|
|
12
|
+
* collapse all numeric types and corrupt downstream codegen).
|
|
13
|
+
* 2. Convert each wire value into a FieldObservation suitable for
|
|
14
|
+
* `mergeDoc` — including the example projection and the enum sample.
|
|
15
|
+
* 3. Flag reserved field names (prerequisite 0.B) so codegen layers can
|
|
16
|
+
* skip or sanitize.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { FieldObservation } from './merge.js';
|
|
20
|
+
import { fieldTypeKey } from './merge.js';
|
|
21
|
+
import type { WireDocumentSnapshot } from './firestore-source.js';
|
|
22
|
+
import type {
|
|
23
|
+
ExampleValue,
|
|
24
|
+
FieldType,
|
|
25
|
+
ReservedFieldReason,
|
|
26
|
+
} from './types.js';
|
|
27
|
+
|
|
28
|
+
// ─── Error type for 0.A ───────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Thrown when `DocumentSnapshot._fieldsProto` is unavailable or malformed.
|
|
32
|
+
* Per prerequisite 0.A, the wire reader does NOT silently fall back to
|
|
33
|
+
* `data()` — that would collapse integer/double at the value boundary
|
|
34
|
+
* and corrupt every downstream codegen consumer.
|
|
35
|
+
*/
|
|
36
|
+
export class WireProtoUnavailableError extends Error {
|
|
37
|
+
override readonly name = 'WireProtoUnavailableError';
|
|
38
|
+
constructor(opts: { docPath: string; reason: string }) {
|
|
39
|
+
super(
|
|
40
|
+
`firestore_discover_paths could not read wire types from document ` +
|
|
41
|
+
`"${opts.docPath}": ${opts.reason}. The discover_paths tool depends on ` +
|
|
42
|
+
`firebase-admin DocumentSnapshot._fieldsProto for accurate ` +
|
|
43
|
+
`integer/double type inference (Phase 0.1 lock). If this is a ` +
|
|
44
|
+
`firebase-admin upgrade incompatibility, set ` +
|
|
45
|
+
`numberTypeStrategy: "heuristic" to opt into the lossy fallback ` +
|
|
46
|
+
`knowingly. Otherwise file an issue with the admin SDK version.`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ─── Reserved-name detection (0.B) ────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
const FIRESTORE_RESERVED_NAMES = new Set(['__name__']);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Classify a field name. Returns undefined for normal names, or a
|
|
57
|
+
* specific ReservedFieldReason for names that codegen must skip/sanitize.
|
|
58
|
+
*
|
|
59
|
+
* Rules ordered by specificity (most specific first):
|
|
60
|
+
* - exact `__name__` etc. → firestore_reserved_name
|
|
61
|
+
* - contains '.' → dotted_field_name (breaks dot-path access)
|
|
62
|
+
* - pure-numeric → numeric_field_name (looks like array index)
|
|
63
|
+
* - __foo__ → double_underscore_wrap (sentinel collision)
|
|
64
|
+
*/
|
|
65
|
+
export function classifyFieldName(name: string): ReservedFieldReason | undefined {
|
|
66
|
+
if (FIRESTORE_RESERVED_NAMES.has(name)) return 'firestore_reserved_name';
|
|
67
|
+
if (name.includes('.')) return 'dotted_field_name';
|
|
68
|
+
if (/^-?\d+$/.test(name)) return 'numeric_field_name';
|
|
69
|
+
if (name.length >= 4 && name.startsWith('__') && name.endsWith('__')) {
|
|
70
|
+
return 'double_underscore_wrap';
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ─── Wire value → FieldType ───────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
|
+
export type WireValue = any;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Pure type extraction. Does not extract examples or enum samples — use
|
|
82
|
+
* `wireValueToObservation` for the full observation.
|
|
83
|
+
*/
|
|
84
|
+
export function wireValueToFieldType(v: WireValue): FieldType {
|
|
85
|
+
if ('nullValue' in v) return { kind: 'scalar', type: 'null' };
|
|
86
|
+
if ('booleanValue' in v) return { kind: 'scalar', type: 'boolean' };
|
|
87
|
+
if ('integerValue' in v) return { kind: 'scalar', type: 'integer' };
|
|
88
|
+
if ('doubleValue' in v) return { kind: 'scalar', type: 'double' };
|
|
89
|
+
if ('timestampValue' in v) return { kind: 'scalar', type: 'timestamp' };
|
|
90
|
+
if ('stringValue' in v) return { kind: 'scalar', type: 'string' };
|
|
91
|
+
if ('bytesValue' in v) return { kind: 'scalar', type: 'bytes' };
|
|
92
|
+
if ('geoPointValue' in v) return { kind: 'scalar', type: 'geopoint' };
|
|
93
|
+
|
|
94
|
+
if ('referenceValue' in v) {
|
|
95
|
+
return {
|
|
96
|
+
kind: 'reference',
|
|
97
|
+
targetCollection: parseRefTargetCollectionPath(v.referenceValue),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if ('arrayValue' in v) {
|
|
102
|
+
const values: WireValue[] = v.arrayValue?.values ?? [];
|
|
103
|
+
const elementTypes = values.map(wireValueToFieldType);
|
|
104
|
+
const seen = new Set<string>();
|
|
105
|
+
const deduped = elementTypes.filter((t) => {
|
|
106
|
+
const k = fieldTypeKey(t);
|
|
107
|
+
if (seen.has(k)) return false;
|
|
108
|
+
seen.add(k);
|
|
109
|
+
return true;
|
|
110
|
+
});
|
|
111
|
+
return { kind: 'array', elementTypes: deduped };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if ('mapValue' in v) {
|
|
115
|
+
const fieldsObj: Record<string, WireValue> = v.mapValue?.fields ?? {};
|
|
116
|
+
// Vector sentinel detection (Phase 1.2 lock)
|
|
117
|
+
const sentinel = fieldsObj['__type__'];
|
|
118
|
+
if (sentinel?.stringValue === '__vector__') {
|
|
119
|
+
const arr = fieldsObj['value']?.arrayValue?.values ?? [];
|
|
120
|
+
return { kind: 'vector', dimension: arr.length };
|
|
121
|
+
}
|
|
122
|
+
const fields: Record<string, ReturnType<typeof descriptorFromObservation>> = {};
|
|
123
|
+
for (const [k, sub] of Object.entries(fieldsObj)) {
|
|
124
|
+
fields[k] = descriptorFromObservation(wireValueToObservation(sub));
|
|
125
|
+
}
|
|
126
|
+
return { kind: 'map', fields };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
throw new Error(`Unrecognized wire value: ${JSON.stringify(Object.keys(v))}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ─── Wire value → FieldObservation ────────────────────────────────────────
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Full observation including JSON-safe example projection and enum sample
|
|
136
|
+
* extraction. The merge layer consumes this shape.
|
|
137
|
+
*/
|
|
138
|
+
export function wireValueToObservation(v: WireValue): FieldObservation {
|
|
139
|
+
const type = wireValueToFieldType(v);
|
|
140
|
+
const isNull = type.kind === 'scalar' && type.type === 'null';
|
|
141
|
+
const example = exampleFromWire(v);
|
|
142
|
+
const enumSample = enumSampleFromWire(v, type);
|
|
143
|
+
return { type, isNull, example, enumSample };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Project a wire value into a JSON-safe example. */
|
|
147
|
+
function exampleFromWire(v: WireValue): ExampleValue | undefined {
|
|
148
|
+
if ('nullValue' in v) return null;
|
|
149
|
+
if ('booleanValue' in v) return v.booleanValue as boolean;
|
|
150
|
+
if ('stringValue' in v) return v.stringValue as string;
|
|
151
|
+
if ('integerValue' in v) {
|
|
152
|
+
const raw = v.integerValue as string | number;
|
|
153
|
+
// integerValue is wire-encoded as a string (int64). Parse but cap at
|
|
154
|
+
// safe integer range; outside that, return as-string to preserve.
|
|
155
|
+
const n = typeof raw === 'string' ? Number(raw) : raw;
|
|
156
|
+
if (Number.isSafeInteger(n)) return n;
|
|
157
|
+
return String(raw);
|
|
158
|
+
}
|
|
159
|
+
if ('doubleValue' in v) return v.doubleValue as number;
|
|
160
|
+
// timestamp/bytes/geopoint/reference: not codegen-friendly placeholders;
|
|
161
|
+
// omit so descriptor.example stays undefined and codegen knows to skip.
|
|
162
|
+
if ('timestampValue' in v) return undefined;
|
|
163
|
+
if ('bytesValue' in v) return undefined;
|
|
164
|
+
if ('geoPointValue' in v) return undefined;
|
|
165
|
+
if ('referenceValue' in v) return undefined;
|
|
166
|
+
|
|
167
|
+
if ('arrayValue' in v) {
|
|
168
|
+
const values: WireValue[] = v.arrayValue?.values ?? [];
|
|
169
|
+
const projected: ExampleValue[] = [];
|
|
170
|
+
for (const e of values) {
|
|
171
|
+
const proj = exampleFromWire(e);
|
|
172
|
+
// Skip elements that don't project (e.g., bytes inside an array).
|
|
173
|
+
// Better than nulling them out — keeps the example shape useful.
|
|
174
|
+
if (proj !== undefined) projected.push(proj);
|
|
175
|
+
}
|
|
176
|
+
return projected;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if ('mapValue' in v) {
|
|
180
|
+
const fieldsObj: Record<string, WireValue> = v.mapValue?.fields ?? {};
|
|
181
|
+
if (fieldsObj['__type__']?.stringValue === '__vector__') return undefined;
|
|
182
|
+
const out: { [k: string]: ExampleValue } = {};
|
|
183
|
+
for (const [k, sub] of Object.entries(fieldsObj)) {
|
|
184
|
+
const proj = exampleFromWire(sub);
|
|
185
|
+
if (proj !== undefined) out[k] = proj;
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Extract an enum sample if the type is enum-eligible (string/int/double). */
|
|
194
|
+
function enumSampleFromWire(v: WireValue, type: FieldType): string | number | undefined {
|
|
195
|
+
if (type.kind !== 'scalar') return undefined;
|
|
196
|
+
if (type.type === 'string') return v.stringValue as string;
|
|
197
|
+
if (type.type === 'integer') {
|
|
198
|
+
const raw = v.integerValue as string | number;
|
|
199
|
+
const n = typeof raw === 'string' ? Number(raw) : raw;
|
|
200
|
+
return Number.isSafeInteger(n) ? n : undefined;
|
|
201
|
+
}
|
|
202
|
+
if (type.type === 'double') return v.doubleValue as number;
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Tiny adapter — turns a single observation into a one-shot descriptor for
|
|
207
|
+
* nested map fields. Mirrors what mergeDoc does for first-time keys. */
|
|
208
|
+
function descriptorFromObservation(obs: FieldObservation) {
|
|
209
|
+
const isNull = obs.isNull;
|
|
210
|
+
return {
|
|
211
|
+
types: isNull ? [] : [obs.type],
|
|
212
|
+
presenceSeen: 1,
|
|
213
|
+
presenceTotal: 1,
|
|
214
|
+
nullable: isNull,
|
|
215
|
+
enumCandidate:
|
|
216
|
+
!isNull &&
|
|
217
|
+
obs.type.kind === 'scalar' &&
|
|
218
|
+
(obs.type.type === 'string' ||
|
|
219
|
+
obs.type.type === 'integer' ||
|
|
220
|
+
obs.type.type === 'double') &&
|
|
221
|
+
obs.enumSample !== undefined
|
|
222
|
+
? { qualifies: false, values: [obs.enumSample], threshold: 10 }
|
|
223
|
+
: undefined,
|
|
224
|
+
example: obs.example,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ─── Reference path parsing ───────────────────────────────────────────────
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Parse a referenceValue string into the full collection path of the target.
|
|
232
|
+
*
|
|
233
|
+
* Format: projects/<p>/databases/<d>/documents/<coll>/<doc>[/<coll>/<doc>...]
|
|
234
|
+
* For `projects/x/databases/(default)/documents/users/uid_1/posts/p_1`,
|
|
235
|
+
* returns `users/uid_1/posts` (full path, Phase 1.2 lock for unambiguity).
|
|
236
|
+
*
|
|
237
|
+
* Note: this is the *literal* path of the observed reference. Callers that
|
|
238
|
+
* want the template form must substitute doc IDs into wildcards based on
|
|
239
|
+
* the parent collection's template path.
|
|
240
|
+
*/
|
|
241
|
+
function parseRefTargetCollectionPath(refPath: string): string {
|
|
242
|
+
const idx = refPath.indexOf('/documents/');
|
|
243
|
+
if (idx === -1) return refPath; // unparseable; preserve raw
|
|
244
|
+
const tail = refPath.slice(idx + '/documents/'.length);
|
|
245
|
+
const segments = tail.split('/');
|
|
246
|
+
if (segments.length < 2 || segments.length % 2 !== 0) return tail;
|
|
247
|
+
return segments.slice(0, -1).join('/');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ─── Document snapshot → observations ─────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Convert a Firestore document snapshot into a FieldObservation map.
|
|
254
|
+
* Detects reserved field names per 0.B — they appear in the output but
|
|
255
|
+
* the descriptor returned by the merge layer carries `reservedReason`
|
|
256
|
+
* so codegen can skip them.
|
|
257
|
+
*
|
|
258
|
+
* Throws `WireProtoUnavailableError` if `_fieldsProto` is absent (0.A
|
|
259
|
+
* fail-loud contract). Empty docs (proto present but zero keys) return
|
|
260
|
+
* an empty record without throwing.
|
|
261
|
+
*/
|
|
262
|
+
export function snapshotToObservations(snap: WireDocumentSnapshot): {
|
|
263
|
+
observations: Record<string, FieldObservation>;
|
|
264
|
+
reservedNames: Record<string, ReservedFieldReason>;
|
|
265
|
+
} {
|
|
266
|
+
const proto = snap._fieldsProto;
|
|
267
|
+
const docPath = snap.ref?.path ?? '<unknown>';
|
|
268
|
+
|
|
269
|
+
if (proto === undefined || proto === null) {
|
|
270
|
+
throw new WireProtoUnavailableError({
|
|
271
|
+
docPath,
|
|
272
|
+
reason: '_fieldsProto is undefined; firebase-admin SDK contract may have changed',
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const observations: Record<string, FieldObservation> = {};
|
|
277
|
+
const reservedNames: Record<string, ReservedFieldReason> = {};
|
|
278
|
+
|
|
279
|
+
for (const [k, v] of Object.entries(proto)) {
|
|
280
|
+
// Sanity check: every value must have a valueType discriminator (or
|
|
281
|
+
// one of the explicit *Value keys). If neither is present, we're
|
|
282
|
+
// looking at a shape we don't recognize — fail loud.
|
|
283
|
+
if (v == null || (typeof v !== 'object')) {
|
|
284
|
+
throw new WireProtoUnavailableError({
|
|
285
|
+
docPath,
|
|
286
|
+
reason: `field "${k}" has non-object proto value (${typeof v}); SDK contract may have changed`,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
if (!hasAnyKnownValueKey(v)) {
|
|
290
|
+
throw new WireProtoUnavailableError({
|
|
291
|
+
docPath,
|
|
292
|
+
reason: `field "${k}" has no recognizable valueType discriminator; SDK contract may have changed`,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const reason = classifyFieldName(k);
|
|
297
|
+
if (reason) reservedNames[k] = reason;
|
|
298
|
+
observations[k] = wireValueToObservation(v);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return { observations, reservedNames };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const KNOWN_VALUE_KEYS = [
|
|
305
|
+
'nullValue',
|
|
306
|
+
'booleanValue',
|
|
307
|
+
'integerValue',
|
|
308
|
+
'doubleValue',
|
|
309
|
+
'timestampValue',
|
|
310
|
+
'stringValue',
|
|
311
|
+
'bytesValue',
|
|
312
|
+
'geoPointValue',
|
|
313
|
+
'referenceValue',
|
|
314
|
+
'arrayValue',
|
|
315
|
+
'mapValue',
|
|
316
|
+
] as const;
|
|
317
|
+
|
|
318
|
+
function hasAnyKnownValueKey(v: Record<string, unknown>): boolean {
|
|
319
|
+
for (const k of KNOWN_VALUE_KEYS) if (k in v) return true;
|
|
320
|
+
// valueType discriminator alone (without a peer *Value key) is NOT
|
|
321
|
+
// sufficient — some SDK versions emit it but still need the parallel
|
|
322
|
+
// key for value access.
|
|
323
|
+
return false;
|
|
324
|
+
}
|