@pyric/cli 0.1.0-alpha.10 → 0.1.0-alpha.12
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.orig +2 -2
- package/dist/assurance/.generated/conformance-verdicts.d.ts +16 -0
- package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
- package/dist/assurance/.generated/conformance-verdicts.js +16 -0
- package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
- package/dist/bridge/server/peer.d.ts +1 -1
- package/dist/bridge/server.d.ts +1 -1
- package/dist/bridge/server.js +1 -1
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +13 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts +3 -3
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +5 -5
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/serve.d.ts.map +1 -1
- package/dist/cli/serve.js +8 -2
- 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/conformance/.generated/conformance-docs.d.ts +12 -0
- package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -0
- package/dist/conformance/.generated/conformance-docs.js +2 -0
- package/dist/conformance/.generated/conformance-docs.js.map +1 -0
- package/dist/conformance/docs.d.ts +6 -0
- package/dist/conformance/docs.d.ts.map +1 -0
- package/dist/conformance/docs.js +6 -0
- package/dist/conformance/docs.js.map +1 -0
- package/dist/remote/index.d.ts.map +1 -1
- package/dist/remote/index.js +1 -0
- package/dist/remote/index.js.map +1 -1
- package/dist/serve/activity-guard.d.ts +4 -0
- package/dist/serve/activity-guard.d.ts.map +1 -0
- package/dist/serve/activity-guard.js +22 -0
- package/dist/serve/activity-guard.js.map +1 -0
- package/dist/serve/activity-route.d.ts +4 -0
- package/dist/serve/activity-route.d.ts.map +1 -0
- package/dist/serve/activity-route.js +157 -0
- package/dist/serve/activity-route.js.map +1 -0
- package/dist/serve/activity-warning.d.ts +4 -0
- package/dist/serve/activity-warning.d.ts.map +1 -0
- package/dist/serve/activity-warning.js +21 -0
- package/dist/serve/activity-warning.js.map +1 -0
- package/dist/serve/bridge-mount.d.ts +5 -0
- package/dist/serve/bridge-mount.d.ts.map +1 -1
- package/dist/serve/bridge-mount.js +1 -0
- package/dist/serve/bridge-mount.js.map +1 -1
- package/dist/serve/docs-ui/404.html +3 -0
- package/dist/serve/docs-ui/_astro/{_slug_.DPUwShm2.css → _slug_.CXh9yTP1.css} +1 -1
- package/dist/serve/docs-ui/_astro/_slug_.DUci-duz.css +1 -0
- package/dist/serve/docs-ui/docs/_rhythm/index.html +2 -1
- package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +3 -2
- package/dist/serve/docs-ui/docs/agent/set-up-your-agent.md +1 -1
- package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +2 -1
- package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +2 -1
- package/dist/serve/docs-ui/docs/ai-compat/index.html +2 -1
- package/dist/serve/docs-ui/docs/api-reference/index.html +51 -49
- package/dist/serve/docs-ui/docs/api-reference.md +3 -3
- package/dist/serve/docs-ui/docs/app-compat/index.html +2 -1
- package/dist/serve/docs-ui/docs/auth-compat/index.html +2 -1
- package/dist/serve/docs-ui/docs/build/ai-logic/index.html +18 -3
- package/dist/serve/docs-ui/docs/build/ai-logic.md +30 -2
- package/dist/serve/docs-ui/docs/build/authentication/index.html +2 -1
- package/dist/serve/docs-ui/docs/build/authentication.md +1 -1
- package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +2 -1
- package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +46 -2
- package/dist/serve/docs-ui/docs/build/cloud-messaging.md +56 -1
- package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +2 -1
- package/dist/serve/docs-ui/docs/build/cloud-storage.md +1 -1
- package/dist/serve/docs-ui/docs/build/realtime-database/index.html +21 -3
- package/dist/serve/docs-ui/docs/build/realtime-database.md +25 -1
- package/dist/serve/docs-ui/docs/conformance-scores/index.html +2 -1
- package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +61 -28
- package/dist/serve/docs-ui/docs/create-pyric-reference-api.md +65 -20
- package/dist/serve/docs-ui/docs/database-compat/index.html +2 -1
- package/dist/serve/docs-ui/docs/firestore-compat/index.html +6 -5
- package/dist/serve/docs-ui/docs/firestore-compat.md +4 -4
- package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +2 -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/start-building/index.html +4 -3
- package/dist/serve/docs-ui/docs/get-started/start-building.md +2 -2
- package/dist/serve/docs-ui/docs/index.json +979 -579
- package/dist/serve/docs-ui/docs/messaging-compat/index.html +2 -1
- package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +2 -1
- package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +2 -1
- package/dist/serve/docs-ui/docs/overview/index.html +2 -1
- package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +5 -4
- package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api.md +3 -4
- package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +5 -4
- package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api.md +3 -4
- package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +5 -4
- package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api.md +3 -4
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +2503 -12
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api.md +2219 -8
- 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 +4 -3
- package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api.md +2 -3
- package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +16 -11
- package/dist/serve/docs-ui/docs/pyric-ai-reference-api.md +14 -13
- package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +4 -3
- package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api.md +2 -3
- package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +7 -2
- package/dist/serve/docs-ui/docs/pyric-app-reference-api.md +5 -2
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +23 -12
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api.md +15 -12
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +10 -48
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api.md +11 -24
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +87 -97
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api.md +53 -65
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +14 -15
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api.md +19 -28
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +4 -3
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api.md +2 -3
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +3 -2
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api.md +1 -2
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +51 -0
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api.md +36 -0
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +3 -2
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api.md +1 -2
- package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +3 -2
- package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api.md +1 -2
- package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +3 -2
- package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api.md +1 -2
- package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +3 -2
- package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api.md +1 -2
- package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1067 -83
- package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api.md +1291 -160
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +253 -157
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +179 -85
- package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +72 -7
- package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api.md +22 -7
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +33 -12
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +15 -12
- package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +18 -17
- package/dist/serve/docs-ui/docs/pyric-database-reference-api.md +19 -22
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1512 -545
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api.md +1311 -316
- package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +5 -4
- package/dist/serve/docs-ui/docs/pyric-messaging-reference-api.md +3 -4
- package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +69 -369
- package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api.md +103 -216
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +10 -9
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api.md +9 -10
- package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +8 -7
- package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api.md +6 -7
- package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +10 -9
- package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api.md +9 -10
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +371 -884
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +369 -883
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +25 -17
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api.md +21 -19
- package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +3 -2
- package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api.md +1 -2
- package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +63 -776
- package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api.md +69 -510
- package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +22 -21
- package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api.md +29 -30
- package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +15 -168
- package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api.md +17 -87
- package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +6 -5
- package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api.md +5 -6
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +82 -970
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api.md +104 -479
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +30 -29
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api.md +54 -55
- package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +3 -2
- package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api.md +1 -2
- package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +5 -4
- package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api.md +3 -4
- package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +9 -124
- package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api.md +7 -58
- package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +24 -23
- package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api.md +31 -34
- package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +104 -1385
- package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api.md +133 -817
- package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +34 -33
- package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api.md +37 -38
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +116 -1169
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api.md +142 -590
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +4 -3
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api.md +3 -4
- package/dist/serve/docs-ui/docs/rules-compat/index.html +34 -1
- package/dist/serve/docs-ui/docs/rules-compat.md +32 -0
- package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +19 -2
- package/dist/serve/docs-ui/docs/secure/audit-your-rules.md +32 -0
- package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +2 -1
- package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +2 -1
- package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +2 -1
- package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript.md +1 -1
- package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +2 -1
- package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +2 -1
- package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +2 -1
- package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +2 -1
- package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +2 -1
- package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +2 -1
- package/dist/serve/docs-ui/docs/storage-compat/index.html +2 -1
- package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +2 -1
- package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +2 -1
- package/dist/serve/docs-ui/llms.txt +2 -1
- package/dist/serve/entries/ai.d.ts.map +1 -1
- package/dist/serve/entries/ai.js +39 -1
- package/dist/serve/entries/ai.js.map +1 -1
- package/dist/serve/entries/messaging-sw.d.ts.map +1 -1
- package/dist/serve/entries/messaging-sw.js +5 -1
- package/dist/serve/entries/messaging-sw.js.map +1 -1
- package/dist/serve/entries/messaging.d.ts.map +1 -1
- package/dist/serve/entries/messaging.js +7 -1
- package/dist/serve/entries/messaging.js.map +1 -1
- package/dist/serve/entries/runtime.d.ts.map +1 -1
- package/dist/serve/entries/runtime.js +20 -1
- package/dist/serve/entries/runtime.js.map +1 -1
- package/dist/serve/init-payload.d.ts +25 -0
- package/dist/serve/init-payload.d.ts.map +1 -1
- package/dist/serve/namespace.d.ts +39 -0
- package/dist/serve/namespace.d.ts.map +1 -1
- package/dist/serve/namespace.js +80 -1
- package/dist/serve/namespace.js.map +1 -1
- package/dist/serve/standalone-assets.d.ts +11 -9
- package/dist/serve/standalone-assets.d.ts.map +1 -1
- package/dist/serve/standalone-assets.js +6 -5
- package/dist/serve/standalone-assets.js.map +1 -1
- package/dist/serve/studio-ui/assets/{RulesCodeEditor-CXdSLKhO.js → RulesCodeEditor-CxVYcZXw.js} +1 -1
- package/dist/serve/studio-ui/assets/index-cpSfgQ7H.js +1218 -0
- package/dist/serve/studio-ui/assets/seed-DeuFKi4J.js +20 -0
- package/dist/serve/studio-ui/index.html +1 -1
- package/dist/serve/vite-plugin.d.ts +92 -15
- package/dist/serve/vite-plugin.d.ts.map +1 -1
- package/dist/serve/vite-plugin.js +281 -11
- package/dist/serve/vite-plugin.js.map +1 -1
- package/dist/serve/worker/activity-bootstrap.d.ts +8 -0
- package/dist/serve/worker/activity-bootstrap.d.ts.map +1 -0
- package/dist/serve/worker/activity-bootstrap.js +11 -0
- package/dist/serve/worker/activity-bootstrap.js.map +1 -0
- package/dist/serve/worker/client/connection.d.ts.map +1 -1
- package/dist/serve/worker/client/connection.js +17 -5
- package/dist/serve/worker/client/connection.js.map +1 -1
- package/dist/serve/worker/client/core.d.ts +2 -2
- package/dist/serve/worker/client/core.d.ts.map +1 -1
- package/dist/serve/worker/client/core.js +33 -5
- package/dist/serve/worker/client/core.js.map +1 -1
- package/dist/serve/worker/client/firestore-writes.d.ts.map +1 -1
- package/dist/serve/worker/client/firestore-writes.js +1 -0
- package/dist/serve/worker/client/firestore-writes.js.map +1 -1
- package/dist/serve/worker/client/messaging.d.ts +9 -1
- package/dist/serve/worker/client/messaging.d.ts.map +1 -1
- package/dist/serve/worker/client/messaging.js +15 -0
- package/dist/serve/worker/client/messaging.js.map +1 -1
- package/dist/serve/worker/client/studio.d.ts +10 -0
- package/dist/serve/worker/client/studio.d.ts.map +1 -1
- package/dist/serve/worker/client/studio.js +11 -0
- package/dist/serve/worker/client/studio.js.map +1 -1
- package/dist/serve/worker/durable-persistence.d.ts +12 -0
- package/dist/serve/worker/durable-persistence.d.ts.map +1 -0
- package/dist/serve/worker/durable-persistence.js +118 -0
- package/dist/serve/worker/durable-persistence.js.map +1 -0
- package/dist/serve/worker/entry.d.ts +7 -3
- package/dist/serve/worker/entry.d.ts.map +1 -1
- package/dist/serve/worker/entry.js +7 -3
- package/dist/serve/worker/entry.js.map +1 -1
- package/dist/serve/worker/host/core.d.ts +9 -5
- package/dist/serve/worker/host/core.d.ts.map +1 -1
- package/dist/serve/worker/host/core.js +34 -9
- package/dist/serve/worker/host/core.js.map +1 -1
- package/dist/serve/worker/host/dispatch.d.ts.map +1 -1
- package/dist/serve/worker/host/dispatch.js +9 -2
- package/dist/serve/worker/host/dispatch.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.d.ts +1 -1
- package/dist/serve/worker/host/studio.d.ts.map +1 -1
- package/dist/serve/worker/host/studio.js +36 -1
- package/dist/serve/worker/host/studio.js.map +1 -1
- package/dist/serve/worker/host/subscriptions.d.ts.map +1 -1
- package/dist/serve/worker/host/subscriptions.js +27 -7
- package/dist/serve/worker/host/subscriptions.js.map +1 -1
- package/dist/serve/worker/host-context.d.ts +15 -0
- package/dist/serve/worker/host-context.d.ts.map +1 -1
- package/dist/serve/worker/host-context.js +10 -0
- package/dist/serve/worker/host-context.js.map +1 -1
- package/dist/serve/worker/host-messaging.d.ts.map +1 -1
- package/dist/serve/worker/host-messaging.js +9 -2
- package/dist/serve/worker/host-messaging.js.map +1 -1
- package/dist/serve/worker/index.d.ts +3 -2
- package/dist/serve/worker/index.d.ts.map +1 -1
- package/dist/serve/worker/index.js +4 -1
- package/dist/serve/worker/index.js.map +1 -1
- package/dist/serve/worker/protocol.d.ts +25 -3
- 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/serve-init.d.ts +23 -37
- package/dist/serve/worker/serve-init.d.ts.map +1 -1
- package/dist/serve/worker/serve-init.js +95 -172
- package/dist/serve/worker/serve-init.js.map +1 -1
- package/dist/vite.d.ts +4 -4
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +3 -3
- package/dist/vite.js.map +1 -1
- package/package.json +9 -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 +493 -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 +46 -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 +540 -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 +75 -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/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-plugin.ts +1102 -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 +202 -0
- package/src/serve/worker/client/core.ts +350 -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/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 +179 -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 +1112 -0
- package/src/serve/worker/serve-init.ts +606 -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 +17 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -30
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -30
- package/dist/serve/studio-ui/assets/index-BvtQIpGn.js +0 -1211
- package/dist/serve/studio-ui/assets/seed-3DMedLL3.js +0 -2
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-data schema merge / inference for `firestore_discover_paths`.
|
|
3
|
+
*
|
|
4
|
+
* Validation-grade implementation promoted to production with the following
|
|
5
|
+
* additions:
|
|
6
|
+
*
|
|
7
|
+
* 1. Enum-candidate tracking on string/integer/double scalar fields
|
|
8
|
+
* (Phase 3.2 lock — drives <select> codegen and discriminated unions).
|
|
9
|
+
* 2. Per-field example value (Phase 3.2 lock — drives form placeholders,
|
|
10
|
+
* fixtures, README payloads).
|
|
11
|
+
* 3. `null` is never a peer entry in `types[]`; only `nullable` carries the
|
|
12
|
+
* annotation (Phase 2.1 lock — suppresses redundant `type_expanded`
|
|
13
|
+
* events for null observations).
|
|
14
|
+
* 4. SchemaChange enum aligned with the Phase 5 frozen list (`field_added`
|
|
15
|
+
* replaces `new_key`; `array_grew` and `presence_dropped` removed —
|
|
16
|
+
* array element growth surfaces as `type_expanded` with `'[]'` path
|
|
17
|
+
* segment; presence shifts surface as `presence_changed`).
|
|
18
|
+
*
|
|
19
|
+
* Pure functions only — no Firestore SDK imports. Wire-format conversion
|
|
20
|
+
* lives in `wire.ts`; this module operates on already-typed observations.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type {
|
|
24
|
+
FieldDescriptor,
|
|
25
|
+
FieldPath,
|
|
26
|
+
FieldSchema,
|
|
27
|
+
FieldType,
|
|
28
|
+
FirestoreScalarType,
|
|
29
|
+
SchemaChange,
|
|
30
|
+
} from './types.js';
|
|
31
|
+
|
|
32
|
+
// ─── Constants ────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
/** Default enum-candidate distinct-value cap (Phase 3.2 lock). */
|
|
35
|
+
export const DEFAULT_ENUM_THRESHOLD = 10;
|
|
36
|
+
|
|
37
|
+
// ─── Empty schema ─────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
export function emptySchema(): FieldSchema {
|
|
40
|
+
return { fields: {}, samplesSeen: 0 };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ─── Type key (for dedup; NaN-safe by construction) ───────────────────────
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Stable key for FieldType used in dedup. NaN/±Infinity all collapse to
|
|
47
|
+
* `s:double` so no special handling needed (Phase 1.2 lock).
|
|
48
|
+
*/
|
|
49
|
+
export function fieldTypeKey(t: FieldType): string {
|
|
50
|
+
switch (t.kind) {
|
|
51
|
+
case 'scalar':
|
|
52
|
+
return `s:${t.type}`;
|
|
53
|
+
case 'reference':
|
|
54
|
+
return `r:${t.targetCollection}`;
|
|
55
|
+
case 'vector':
|
|
56
|
+
return `v:${t.dimension}`;
|
|
57
|
+
case 'array': {
|
|
58
|
+
const inner = t.elementTypes.map(fieldTypeKey).sort().join('|');
|
|
59
|
+
return `a:[${inner}]`;
|
|
60
|
+
}
|
|
61
|
+
case 'map': {
|
|
62
|
+
const keys = Object.keys(t.fields).sort().join(',');
|
|
63
|
+
return `m:{${keys}}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function dedupTypes(types: FieldType[]): FieldType[] {
|
|
69
|
+
const seen = new Map<string, FieldType>();
|
|
70
|
+
for (const t of types) seen.set(fieldTypeKey(t), t);
|
|
71
|
+
return Array.from(seen.values());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ─── Enum candidate helpers ───────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
/** True if a scalar field type is enum-eligible (string/int/double only). */
|
|
77
|
+
function isEnumEligibleScalar(t: FieldType): t is { kind: 'scalar'; type: FirestoreScalarType } {
|
|
78
|
+
if (t.kind !== 'scalar') return false;
|
|
79
|
+
return t.type === 'string' || t.type === 'integer' || t.type === 'double';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Extract a hashable enum-value sample from a typed observation. Only
|
|
84
|
+
* callable when `isEnumEligibleScalar(type)` is true; the actual value lives
|
|
85
|
+
* on the observation, not the type.
|
|
86
|
+
*/
|
|
87
|
+
type EnumSample = string | number;
|
|
88
|
+
|
|
89
|
+
// ─── Example-value helpers ────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Captured example for a field. JSON-serializable shallow projection of
|
|
93
|
+
* the wire-decoded value. Strict scalars only at the top level; map fields
|
|
94
|
+
* project recursively but skip vector/reference/bytes (those are wire-typed,
|
|
95
|
+
* not codegen-friendly placeholders).
|
|
96
|
+
*/
|
|
97
|
+
type ExampleValue =
|
|
98
|
+
| string
|
|
99
|
+
| number
|
|
100
|
+
| boolean
|
|
101
|
+
| null
|
|
102
|
+
| ExampleValue[]
|
|
103
|
+
| { [k: string]: ExampleValue };
|
|
104
|
+
|
|
105
|
+
// ─── Observation contract ─────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* A single field observation passed into `mergeDoc`. The wire layer
|
|
109
|
+
* (`wire.ts`) is responsible for producing this shape.
|
|
110
|
+
*/
|
|
111
|
+
export interface FieldObservation {
|
|
112
|
+
/** The inferred FieldType for this observation. `null` is allowed and is
|
|
113
|
+
* surfaced via `isNull`; the `type` itself is `{kind:'scalar', type:'null'}`
|
|
114
|
+
* by convention but is NOT added to the descriptor's types[] union. */
|
|
115
|
+
type: FieldType;
|
|
116
|
+
/** True iff the wire value was a null literal. */
|
|
117
|
+
isNull: boolean;
|
|
118
|
+
/** A JSON-safe sample of the wire value. Used to populate `example` on
|
|
119
|
+
* the descriptor when no example exists yet. Optional — wire layer omits
|
|
120
|
+
* for kinds with no codegen-friendly representation. */
|
|
121
|
+
example?: ExampleValue;
|
|
122
|
+
/** For enum-eligible scalars (string/int/double), the raw value. Used
|
|
123
|
+
* to update enumCandidate. */
|
|
124
|
+
enumSample?: EnumSample;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ─── Per-field merge ──────────────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
interface MergeFieldResult {
|
|
130
|
+
merged: FieldDescriptor;
|
|
131
|
+
changes: SchemaChange[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Merge a single field observation into an existing descriptor.
|
|
136
|
+
* `observation === 'absent'` means the field was missing from the doc.
|
|
137
|
+
* `newTotal` is the doc count after this observation.
|
|
138
|
+
*/
|
|
139
|
+
export function mergeDescriptorWithObservation(
|
|
140
|
+
prev: FieldDescriptor,
|
|
141
|
+
observation: FieldObservation | 'absent',
|
|
142
|
+
newTotal: number,
|
|
143
|
+
path: FieldPath,
|
|
144
|
+
): MergeFieldResult {
|
|
145
|
+
if (observation === 'absent') {
|
|
146
|
+
// Field absent — bump total only. presence_changed is NOT emitted on
|
|
147
|
+
// every absence (would be noisy); callers fold presence into a separate
|
|
148
|
+
// sweep at finalization if needed.
|
|
149
|
+
return { merged: { ...prev, presenceTotal: newTotal }, changes: [] };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const { type: obs, isNull, example, enumSample } = observation;
|
|
153
|
+
const changes: SchemaChange[] = [];
|
|
154
|
+
|
|
155
|
+
// Null observation: bump nullable + presenceSeen. Do NOT add `null` to
|
|
156
|
+
// types[] (Phase 2.1 lock). Emit `became_nullable` once, on the transition.
|
|
157
|
+
if (isNull) {
|
|
158
|
+
const becameNullable = !prev.nullable;
|
|
159
|
+
return {
|
|
160
|
+
merged: {
|
|
161
|
+
...prev,
|
|
162
|
+
presenceSeen: prev.presenceSeen + 1,
|
|
163
|
+
presenceTotal: newTotal,
|
|
164
|
+
nullable: true,
|
|
165
|
+
},
|
|
166
|
+
changes: becameNullable ? [{ kind: 'became_nullable', path }] : [],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Type union management (non-null observation).
|
|
171
|
+
//
|
|
172
|
+
// Container collapse rule: array and map kinds are SINGLETONS in the
|
|
173
|
+
// descriptor's types[] union — at most one array entry, at most one map
|
|
174
|
+
// entry. Element-type / field growth across observations merges into the
|
|
175
|
+
// existing container entry rather than creating a parallel union member.
|
|
176
|
+
// This is the Phase 5 lock: dropping `array_grew` in favor of
|
|
177
|
+
// `type_expanded` at `[..., '[]']` presumes arrays collapse this way.
|
|
178
|
+
// Vectors are NOT singletons — distinct dimensions stay distinct per
|
|
179
|
+
// Phase 1.2 vector-drift lock.
|
|
180
|
+
let mergedTypes = prev.types;
|
|
181
|
+
|
|
182
|
+
if (obs.kind === 'array') {
|
|
183
|
+
const existingIdx = prev.types.findIndex((t) => t.kind === 'array');
|
|
184
|
+
if (existingIdx !== -1) {
|
|
185
|
+
const existing = prev.types[existingIdx]!;
|
|
186
|
+
if (existing.kind === 'array') {
|
|
187
|
+
const result = mergeArrays(existing, obs, path);
|
|
188
|
+
const next = [...prev.types];
|
|
189
|
+
next[existingIdx] = result.merged;
|
|
190
|
+
mergedTypes = next;
|
|
191
|
+
changes.push(...result.changes);
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
mergedTypes = [...prev.types, obs];
|
|
195
|
+
changes.push({ kind: 'type_expanded', path, addedType: obs });
|
|
196
|
+
}
|
|
197
|
+
} else if (obs.kind === 'map') {
|
|
198
|
+
const existingIdx = prev.types.findIndex((t) => t.kind === 'map');
|
|
199
|
+
if (existingIdx !== -1) {
|
|
200
|
+
const existing = prev.types[existingIdx]!;
|
|
201
|
+
if (existing.kind === 'map') {
|
|
202
|
+
const result = mergeMaps(existing, obs, path);
|
|
203
|
+
const next = [...prev.types];
|
|
204
|
+
next[existingIdx] = result.merged;
|
|
205
|
+
mergedTypes = next;
|
|
206
|
+
changes.push(...result.changes);
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
mergedTypes = [...prev.types, obs];
|
|
210
|
+
changes.push({ kind: 'type_expanded', path, addedType: obs });
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
// Scalar / reference / vector union management. Vectors stay distinct
|
|
214
|
+
// per dimension (different keys for different dims) — that's the lock.
|
|
215
|
+
const obsKey = fieldTypeKey(obs);
|
|
216
|
+
const prevKeys = new Set(prev.types.map(fieldTypeKey));
|
|
217
|
+
if (!prevKeys.has(obsKey)) {
|
|
218
|
+
mergedTypes = dedupTypes([...prev.types, obs]);
|
|
219
|
+
if (obs.kind === 'vector' && prev.types.some((t) => t.kind === 'vector')) {
|
|
220
|
+
changes.push({
|
|
221
|
+
kind: 'vector_dim_drift',
|
|
222
|
+
path,
|
|
223
|
+
addedDimension: obs.dimension as number,
|
|
224
|
+
});
|
|
225
|
+
} else {
|
|
226
|
+
changes.push({ kind: 'type_expanded', path, addedType: obs });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Enum candidate update. Drop if the type union widened past enum
|
|
232
|
+
// eligibility (more than one type, or non-eligible type added).
|
|
233
|
+
let enumCandidate = prev.enumCandidate;
|
|
234
|
+
const stillEnumEligible =
|
|
235
|
+
mergedTypes.length === 1 && isEnumEligibleScalar(mergedTypes[0]!);
|
|
236
|
+
if (!stillEnumEligible && enumCandidate) {
|
|
237
|
+
changes.push({ kind: 'enum_dropped', path, reason: 'type_widened' });
|
|
238
|
+
enumCandidate = undefined;
|
|
239
|
+
} else if (stillEnumEligible && enumSample !== undefined) {
|
|
240
|
+
const result = updateEnumCandidate(enumCandidate, enumSample, path);
|
|
241
|
+
enumCandidate = result.next;
|
|
242
|
+
changes.push(...result.changes);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Example: capture on first non-null observation. Don't overwrite once set
|
|
246
|
+
// (deterministic for codegen).
|
|
247
|
+
const nextExample =
|
|
248
|
+
prev.example === undefined && example !== undefined ? example : prev.example;
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
merged: {
|
|
252
|
+
types: mergedTypes,
|
|
253
|
+
presenceSeen: prev.presenceSeen + 1,
|
|
254
|
+
presenceTotal: newTotal,
|
|
255
|
+
nullable: prev.nullable,
|
|
256
|
+
enumCandidate,
|
|
257
|
+
example: nextExample,
|
|
258
|
+
reservedReason: prev.reservedReason,
|
|
259
|
+
},
|
|
260
|
+
changes,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ─── Enum candidate state machine ─────────────────────────────────────────
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Progress an enum candidate by one observation. State transitions:
|
|
268
|
+
*
|
|
269
|
+
* undefined + new sample → tracking (1 value, no event)
|
|
270
|
+
* tracking(1) + same → tracking (no event)
|
|
271
|
+
* tracking(1) + new → tracking (2 values), emit `enum_added`
|
|
272
|
+
* tracking(N>1) + new (N+1<=threshold) → tracking, emit `enum_widened`
|
|
273
|
+
* tracking(N=threshold) + new → undefined, emit `enum_dropped(over_threshold)`
|
|
274
|
+
*/
|
|
275
|
+
function updateEnumCandidate(
|
|
276
|
+
prev: FieldDescriptor['enumCandidate'],
|
|
277
|
+
sample: EnumSample,
|
|
278
|
+
path: FieldPath,
|
|
279
|
+
): { next: FieldDescriptor['enumCandidate']; changes: SchemaChange[] } {
|
|
280
|
+
if (prev === undefined) {
|
|
281
|
+
// First sighting — start tracking silently. Single value isn't an enum yet.
|
|
282
|
+
return {
|
|
283
|
+
next: { qualifies: false, values: [sample], threshold: DEFAULT_ENUM_THRESHOLD },
|
|
284
|
+
changes: [],
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
if (prev.values.includes(sample)) {
|
|
288
|
+
return { next: prev, changes: [] };
|
|
289
|
+
}
|
|
290
|
+
// New value — does it fit?
|
|
291
|
+
if (prev.values.length >= prev.threshold) {
|
|
292
|
+
return {
|
|
293
|
+
next: undefined,
|
|
294
|
+
changes: [{ kind: 'enum_dropped', path, reason: 'over_threshold' }],
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
const nextValues = [...prev.values, sample];
|
|
298
|
+
const wasFirstAdd = prev.values.length === 1;
|
|
299
|
+
// Mark qualifies once we have 2+ distinct values (still under threshold).
|
|
300
|
+
const next = { qualifies: true, values: nextValues, threshold: prev.threshold };
|
|
301
|
+
if (wasFirstAdd) {
|
|
302
|
+
return {
|
|
303
|
+
next,
|
|
304
|
+
changes: [{ kind: 'enum_added', path, values: nextValues }],
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
next,
|
|
309
|
+
changes: [{ kind: 'enum_widened', path, addedValue: sample }],
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// ─── Container-type recursive merges ──────────────────────────────────────
|
|
314
|
+
|
|
315
|
+
function mergeArrays(
|
|
316
|
+
prev: { kind: 'array'; elementTypes: FieldType[] },
|
|
317
|
+
obs: { kind: 'array'; elementTypes: FieldType[] },
|
|
318
|
+
path: FieldPath,
|
|
319
|
+
): { merged: FieldType; changes: SchemaChange[] } {
|
|
320
|
+
// Empty array no-op merge (Phase 1.2 lock).
|
|
321
|
+
if (obs.elementTypes.length === 0) return { merged: prev, changes: [] };
|
|
322
|
+
if (prev.elementTypes.length === 0) {
|
|
323
|
+
return { merged: { kind: 'array', elementTypes: obs.elementTypes }, changes: [] };
|
|
324
|
+
}
|
|
325
|
+
const prevKeys = new Set(prev.elementTypes.map(fieldTypeKey));
|
|
326
|
+
const changes: SchemaChange[] = [];
|
|
327
|
+
const merged = [...prev.elementTypes];
|
|
328
|
+
const elementPath: FieldPath = [...path, '[]'];
|
|
329
|
+
for (const et of obs.elementTypes) {
|
|
330
|
+
if (!prevKeys.has(fieldTypeKey(et))) {
|
|
331
|
+
merged.push(et);
|
|
332
|
+
// Array element-type expansion surfaces as `type_expanded` at the
|
|
333
|
+
// `[]` path segment per Phase 5 SchemaChange enum.
|
|
334
|
+
changes.push({ kind: 'type_expanded', path: elementPath, addedType: et });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return { merged: { kind: 'array', elementTypes: dedupTypes(merged) }, changes };
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function mergeMaps(
|
|
341
|
+
prev: { kind: 'map'; fields: Record<string, FieldDescriptor> },
|
|
342
|
+
obs: { kind: 'map'; fields: Record<string, FieldDescriptor> },
|
|
343
|
+
path: FieldPath,
|
|
344
|
+
): { merged: FieldType; changes: SchemaChange[] } {
|
|
345
|
+
// Empty map no-op merge (Phase 1.2 lock).
|
|
346
|
+
if (Object.keys(obs.fields).length === 0) return { merged: prev, changes: [] };
|
|
347
|
+
if (Object.keys(prev.fields).length === 0) {
|
|
348
|
+
return { merged: { kind: 'map', fields: { ...obs.fields } }, changes: [] };
|
|
349
|
+
}
|
|
350
|
+
const changes: SchemaChange[] = [];
|
|
351
|
+
const fields: Record<string, FieldDescriptor> = { ...prev.fields };
|
|
352
|
+
for (const [k, obsDesc] of Object.entries(obs.fields)) {
|
|
353
|
+
const prevDesc = fields[k];
|
|
354
|
+
if (!prevDesc) {
|
|
355
|
+
fields[k] = obsDesc;
|
|
356
|
+
changes.push({ kind: 'field_added', path: [...path, k], type: obsDesc.types[0]! });
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
// Recurse on the single observed type.
|
|
360
|
+
const obsType = obsDesc.types[0]!;
|
|
361
|
+
const isNull = obsDesc.nullable && obsDesc.types.length === 0;
|
|
362
|
+
const subResult = mergeDescriptorWithObservation(
|
|
363
|
+
prevDesc,
|
|
364
|
+
{
|
|
365
|
+
type: obsType ?? { kind: 'scalar', type: 'null' },
|
|
366
|
+
isNull,
|
|
367
|
+
example: obsDesc.example,
|
|
368
|
+
enumSample: extractEnumSample(obsType, obsDesc.example),
|
|
369
|
+
},
|
|
370
|
+
prevDesc.presenceTotal + 1,
|
|
371
|
+
[...path, k],
|
|
372
|
+
);
|
|
373
|
+
fields[k] = subResult.merged;
|
|
374
|
+
changes.push(...subResult.changes);
|
|
375
|
+
}
|
|
376
|
+
return { merged: { kind: 'map', fields }, changes };
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** Best-effort extraction of an enum sample from a nested-map observation. */
|
|
380
|
+
function extractEnumSample(
|
|
381
|
+
type: FieldType | undefined,
|
|
382
|
+
example: ExampleValue | undefined,
|
|
383
|
+
): EnumSample | undefined {
|
|
384
|
+
if (!type || !isEnumEligibleScalar(type)) return undefined;
|
|
385
|
+
if (typeof example === 'string' || typeof example === 'number') return example;
|
|
386
|
+
return undefined;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// ─── Top-level mergeDoc ───────────────────────────────────────────────────
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Merge a single document's typed field observations into a collection-level
|
|
393
|
+
* schema. Returns the next schema and the changes emitted.
|
|
394
|
+
*
|
|
395
|
+
* The wire layer (`wire.ts`) is responsible for converting Firestore wire
|
|
396
|
+
* values into the `Record<string, FieldObservation>` shape expected here.
|
|
397
|
+
*/
|
|
398
|
+
export function mergeDoc(
|
|
399
|
+
prev: FieldSchema,
|
|
400
|
+
doc: Record<string, FieldObservation>,
|
|
401
|
+
): { next: FieldSchema; changes: SchemaChange[] } {
|
|
402
|
+
const newTotal = prev.samplesSeen + 1;
|
|
403
|
+
const allKeys = new Set([...Object.keys(prev.fields), ...Object.keys(doc)]);
|
|
404
|
+
const fields: Record<string, FieldDescriptor> = {};
|
|
405
|
+
const changes: SchemaChange[] = [];
|
|
406
|
+
|
|
407
|
+
for (const k of allKeys) {
|
|
408
|
+
const prevDesc = prev.fields[k];
|
|
409
|
+
const obs = doc[k];
|
|
410
|
+
|
|
411
|
+
if (!prevDesc && obs) {
|
|
412
|
+
// First time seeing this key.
|
|
413
|
+
const isNull = obs.isNull;
|
|
414
|
+
const enumEligible = !isNull && isEnumEligibleScalar(obs.type);
|
|
415
|
+
const enumCandidate =
|
|
416
|
+
enumEligible && obs.enumSample !== undefined
|
|
417
|
+
? {
|
|
418
|
+
qualifies: false,
|
|
419
|
+
values: [obs.enumSample],
|
|
420
|
+
threshold: DEFAULT_ENUM_THRESHOLD,
|
|
421
|
+
}
|
|
422
|
+
: undefined;
|
|
423
|
+
fields[k] = {
|
|
424
|
+
types: isNull ? [] : [obs.type],
|
|
425
|
+
presenceSeen: 1,
|
|
426
|
+
presenceTotal: newTotal,
|
|
427
|
+
nullable: isNull,
|
|
428
|
+
enumCandidate,
|
|
429
|
+
example: obs.example,
|
|
430
|
+
};
|
|
431
|
+
if (!isNull) {
|
|
432
|
+
changes.push({ kind: 'field_added', path: [k], type: obs.type });
|
|
433
|
+
} else {
|
|
434
|
+
// Null-only first observation: emit field_added with null kind so
|
|
435
|
+
// agents see the field surfaced; nullable annotation handles the
|
|
436
|
+
// rest. No became_nullable on first observation — there's no prior
|
|
437
|
+
// non-null state to flip from.
|
|
438
|
+
changes.push({
|
|
439
|
+
kind: 'field_added',
|
|
440
|
+
path: [k],
|
|
441
|
+
type: { kind: 'scalar', type: 'null' },
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (prevDesc && !obs) {
|
|
448
|
+
const result = mergeDescriptorWithObservation(prevDesc, 'absent', newTotal, [k]);
|
|
449
|
+
fields[k] = result.merged;
|
|
450
|
+
changes.push(...result.changes);
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (prevDesc && obs) {
|
|
455
|
+
const result = mergeDescriptorWithObservation(prevDesc, obs, newTotal, [k]);
|
|
456
|
+
fields[k] = result.merged;
|
|
457
|
+
changes.push(...result.changes);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return { next: { fields, samplesSeen: newTotal }, changes };
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// ─── Convergence runner ───────────────────────────────────────────────────
|
|
465
|
+
|
|
466
|
+
export interface ConvergenceResult {
|
|
467
|
+
/** Doc index where `stopOnStable` fired (0-based), or null if never. */
|
|
468
|
+
declaredAt: number | null;
|
|
469
|
+
/** Total docs consumed (≤ stream length). */
|
|
470
|
+
totalDocs: number;
|
|
471
|
+
/** Total change count across the stream. */
|
|
472
|
+
totalChanges: number;
|
|
473
|
+
/** Final accumulated schema. */
|
|
474
|
+
finalSchema: FieldSchema;
|
|
475
|
+
/** Changes emitted *after* convergence was declared — caller-visible
|
|
476
|
+
* for test-time assertion that `stopOnStable` would not have lost data. */
|
|
477
|
+
missedChangesAfterDeclared: SchemaChange[];
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Stream-driven convergence runner. Used by the production crawler's
|
|
482
|
+
* sampling loop and by Phase 2.x tests that replay corpus snapshots.
|
|
483
|
+
*
|
|
484
|
+
* `stopOnStable` is the optimistic early-exit signal (Phase 2.1 lock — must
|
|
485
|
+
* be paired with a `maxSamples` hard cap in the crawler, not here).
|
|
486
|
+
*/
|
|
487
|
+
export function runConvergence(
|
|
488
|
+
docs: Iterable<Record<string, FieldObservation>>,
|
|
489
|
+
stopOnStable: number,
|
|
490
|
+
): ConvergenceResult {
|
|
491
|
+
let schema = emptySchema();
|
|
492
|
+
let consecutiveStable = 0;
|
|
493
|
+
let declaredAt: number | null = null;
|
|
494
|
+
let totalChanges = 0;
|
|
495
|
+
const missedChangesAfterDeclared: SchemaChange[] = [];
|
|
496
|
+
let i = 0;
|
|
497
|
+
|
|
498
|
+
for (const doc of docs) {
|
|
499
|
+
const { next, changes } = mergeDoc(schema, doc);
|
|
500
|
+
schema = next;
|
|
501
|
+
totalChanges += changes.length;
|
|
502
|
+
if (changes.length === 0) {
|
|
503
|
+
consecutiveStable++;
|
|
504
|
+
if (declaredAt === null && consecutiveStable >= stopOnStable) {
|
|
505
|
+
declaredAt = i;
|
|
506
|
+
}
|
|
507
|
+
} else {
|
|
508
|
+
consecutiveStable = 0;
|
|
509
|
+
if (declaredAt !== null) {
|
|
510
|
+
missedChangesAfterDeclared.push(...changes);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
i++;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return {
|
|
517
|
+
declaredAt,
|
|
518
|
+
totalDocs: i,
|
|
519
|
+
totalChanges,
|
|
520
|
+
finalSchema: schema,
|
|
521
|
+
missedChangesAfterDeclared,
|
|
522
|
+
};
|
|
523
|
+
}
|