@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,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker-client connection + lifecycle — open the SharedWorker port, query the
|
|
3
|
+
* worker's version/instance, drive state export/import + named branches, forward
|
|
4
|
+
* agent tool-calls, and relay raw worker-protocol frames from the bridge peer.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { InboundMessage } from '../protocol.js';
|
|
8
|
+
import type { WorkerOpPayload, WorkerSubPayload } from '../../../bridge/protocol.js';
|
|
9
|
+
import {
|
|
10
|
+
nextId,
|
|
11
|
+
nextSubId,
|
|
12
|
+
wirePort,
|
|
13
|
+
rpc,
|
|
14
|
+
rawRpc,
|
|
15
|
+
openSnapshotSubscription,
|
|
16
|
+
closeSubscription,
|
|
17
|
+
} from './core.js';
|
|
18
|
+
import type { ClientDb } from './handles.js';
|
|
19
|
+
|
|
20
|
+
// ─── Public API ────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Connect to the SharedWorker and return a client Firestore handle.
|
|
24
|
+
*
|
|
25
|
+
* Pass the URL of the SharedWorker script as `workerUrl`. Under `pyric dev`
|
|
26
|
+
* this is `/__pyric/sdk/worker.js`; for tests or standalone use, pass the path
|
|
27
|
+
* explicitly.
|
|
28
|
+
*
|
|
29
|
+
* `getFirestore` mirrors `pyric/firestore`'s `getFirestore(sandbox)` shape
|
|
30
|
+
* but returns a `ClientDb` backed by a `MessagePort` instead of a sandbox.
|
|
31
|
+
*/
|
|
32
|
+
export function getFirestore(workerUrl: string | URL, name?: string): ClientDb {
|
|
33
|
+
if (typeof SharedWorker === 'undefined') {
|
|
34
|
+
throw new Error(
|
|
35
|
+
'SharedWorker is not available. ' +
|
|
36
|
+
'Open this page over http:// (not file://) and use a supported browser ' +
|
|
37
|
+
'(Chrome 4+, Firefox 29+, Safari 16.4+).',
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
const worker = new SharedWorker(workerUrl, {
|
|
41
|
+
type: 'classic',
|
|
42
|
+
name: name ?? 'pyric-shared-worker',
|
|
43
|
+
});
|
|
44
|
+
const port = worker.port;
|
|
45
|
+
port.start();
|
|
46
|
+
wirePort(port);
|
|
47
|
+
return { __kind: 'client-db', port };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Ask the worker for its baked build version (staleness guard). The page
|
|
52
|
+
* compares it to the served bundle version and warns when a still-running OLD
|
|
53
|
+
* worker is older than what's served (a SharedWorker can't hot-update).
|
|
54
|
+
*/
|
|
55
|
+
export async function getWorkerVersion(db: ClientDb): Promise<string> {
|
|
56
|
+
const r = (await rpc(db.port, { t: 'op', id: nextId(), method: 'getVersion' })) as { version: string };
|
|
57
|
+
return r.version;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Ask the worker for its stable per-instance id (see host `INSTANCE_ID_KEY`).
|
|
62
|
+
* Studio renders a human-friendly form so a user can tell which sandbox instance
|
|
63
|
+
* they're looking at — the same `localhost:<port>` in a different browser profile
|
|
64
|
+
* is a SEPARATE sandbox (a separate SharedWorker + IndexedDB), and this is how
|
|
65
|
+
* the two are told apart.
|
|
66
|
+
*/
|
|
67
|
+
export async function getWorkerInstanceId(db: ClientDb): Promise<string> {
|
|
68
|
+
const r = (await rpc(db.port, { t: 'op', id: nextId(), method: 'getVersion' })) as { instanceId?: string };
|
|
69
|
+
return r.instanceId ?? '';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Phase 2 (transfer): export the FULL sandbox state as a portable bundle string
|
|
74
|
+
* (the chunk format the persist layer uses, so wrapper types round-trip). Save
|
|
75
|
+
* it to a file and {@link importWorkerState} it into another instance.
|
|
76
|
+
*/
|
|
77
|
+
export async function exportWorkerState(db: ClientDb): Promise<string> {
|
|
78
|
+
const r = (await rpc(db.port, { t: 'op', id: nextId(), method: 'exportState' })) as { bundle: string };
|
|
79
|
+
return r.bundle;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Phase 2 (clobber): replace this sandbox's ENTIRE state with `bundle`. */
|
|
83
|
+
export async function importWorkerState(db: ClientDb, bundle: string): Promise<void> {
|
|
84
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'importState', bundle });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Phase 3: save the live sandbox as a named branch (a saved state bundle). */
|
|
88
|
+
export async function saveWorkerBranch(db: ClientDb, name: string): Promise<void> {
|
|
89
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'saveBranch', name });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Phase 3: list this instance's saved branch names. */
|
|
93
|
+
export async function listWorkerBranches(db: ClientDb): Promise<string[]> {
|
|
94
|
+
const r = (await rpc(db.port, { t: 'op', id: nextId(), method: 'listBranches' })) as { branches?: string[] };
|
|
95
|
+
return r.branches ?? [];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Phase 3 (clobber): switch the live sandbox to a named branch's state. */
|
|
99
|
+
export async function switchWorkerBranch(db: ClientDb, name: string): Promise<void> {
|
|
100
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'switchBranch', name });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Phase 3: delete a named branch. */
|
|
104
|
+
export async function deleteWorkerBranch(db: ClientDb, name: string): Promise<void> {
|
|
105
|
+
await rpc(db.port, { t: 'op', id: nextId(), method: 'deleteBranch', name });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Forward an agent tool-call to the worker so it executes against the SAME
|
|
110
|
+
* sandbox the app + Studio use. The worker runs the canonical tool dispatcher
|
|
111
|
+
* (`buildSandboxDispatcher`) and replies with the `{ ok, summary, data }`
|
|
112
|
+
* result. Used by the bridge peer on the worker path (`connectBridgePeer` in
|
|
113
|
+
* `entries/runtime.ts`) so the agent shares the one authoritative sandbox.
|
|
114
|
+
*/
|
|
115
|
+
export async function callTool(
|
|
116
|
+
db: ClientDb,
|
|
117
|
+
name: string,
|
|
118
|
+
args: Record<string, unknown>,
|
|
119
|
+
): Promise<{ ok: boolean; summary: string; data?: unknown }> {
|
|
120
|
+
return (await rpc(db.port, { t: 'tool', id: nextId(), name, args })) as {
|
|
121
|
+
ok: boolean;
|
|
122
|
+
summary: string;
|
|
123
|
+
data?: unknown;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ─── Generic worker relay (remote sandbox, slice 1) ────────────────────────
|
|
128
|
+
//
|
|
129
|
+
// The bridge peer forwards `worker-op` / `worker-sub` frames from the Node
|
|
130
|
+
// side (`connectRemoteSandbox`) into the SharedWorker through these two
|
|
131
|
+
// functions (see `workerRelay` in `bridge/client/bridge.ts` + the wiring in
|
|
132
|
+
// `entries/runtime.ts`). Ids are re-minted LOCALLY (`nextId`/`nextSubId`) so
|
|
133
|
+
// relayed traffic shares this page's pending/sub maps without any chance of
|
|
134
|
+
// colliding with the page's own ids — the bridge correlates by ITS frame id.
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Relay one raw worker-protocol op into the SharedWorker. `op` is the op
|
|
138
|
+
* message minus `t`/`id` (the `WorkerOpPayload` wire shape); resolves with
|
|
139
|
+
* the worker's `res.value`, rejects with an Error carrying `.code`.
|
|
140
|
+
*/
|
|
141
|
+
export function relayWorkerOp(db: ClientDb, op: WorkerOpPayload): Promise<unknown> {
|
|
142
|
+
// rawRpc, NOT rpc: the relay owns provenance and must not inherit this
|
|
143
|
+
// browser page's Studio issuer. Override any untrusted incoming marker so
|
|
144
|
+
// Node/agent/system traffic can never be attributed to page app activity.
|
|
145
|
+
return rawRpc(db.port, {
|
|
146
|
+
...op,
|
|
147
|
+
issuer: undefined,
|
|
148
|
+
relaySource: 'remote',
|
|
149
|
+
t: 'op',
|
|
150
|
+
id: nextId(),
|
|
151
|
+
} as InboundMessage);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Relay a raw worker-protocol subscription into the SharedWorker. `sub` is
|
|
156
|
+
* the sub message minus `t`/`subId` (the `WorkerSubPayload` wire shape).
|
|
157
|
+
* `onValue` receives every snap value VERBATIM — including the worker host's
|
|
158
|
+
* `{ __error: { code, message } }` establishment-failure convention (listener
|
|
159
|
+
* errors are re-wrapped into the same shape so the far side sees one form).
|
|
160
|
+
* Returns the unsubscribe function.
|
|
161
|
+
*
|
|
162
|
+
* The unified event stream (`target: 'events'`) is NOT relayable yet — its
|
|
163
|
+
* history batches aren't coalescible, so it needs bounded backpressure first
|
|
164
|
+
* (slice 2).
|
|
165
|
+
*/
|
|
166
|
+
export function relayWorkerSub(
|
|
167
|
+
db: ClientDb,
|
|
168
|
+
sub: WorkerSubPayload,
|
|
169
|
+
onValue: (value: unknown) => void,
|
|
170
|
+
): () => void {
|
|
171
|
+
if (sub.target === 'events') {
|
|
172
|
+
throw new Error(
|
|
173
|
+
'event-stream subscriptions cannot be relayed over the bridge yet (needs bounded backpressure — slice 2)',
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
const subId = nextSubId();
|
|
177
|
+
const opened = openSnapshotSubscription(db.port, subId, {
|
|
178
|
+
port: db.port,
|
|
179
|
+
next: onValue,
|
|
180
|
+
error: (err) =>
|
|
181
|
+
onValue({
|
|
182
|
+
__error: {
|
|
183
|
+
code: (err as { code?: string }).code ?? 'unknown',
|
|
184
|
+
message: err instanceof Error ? err.message : String(err),
|
|
185
|
+
},
|
|
186
|
+
}),
|
|
187
|
+
}, {
|
|
188
|
+
...sub,
|
|
189
|
+
issuer: undefined,
|
|
190
|
+
relaySource: 'remote',
|
|
191
|
+
t: 'sub',
|
|
192
|
+
subId,
|
|
193
|
+
} as InboundMessage);
|
|
194
|
+
if (!opened) {
|
|
195
|
+
queueMicrotask(() => onValue({
|
|
196
|
+
__error: { code: 'app/app-deleted', message: 'Firebase App was deleted' },
|
|
197
|
+
}));
|
|
198
|
+
}
|
|
199
|
+
return () => {
|
|
200
|
+
closeSubscription(db.port, subId);
|
|
201
|
+
};
|
|
202
|
+
}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker-client transport core — the shared singleton machinery every API
|
|
3
|
+
* family (firestore, auth, rtdb, storage) rides on: port wiring, RPC
|
|
4
|
+
* correlation, the pending/subscriber maps, the Pyric Studio auth-lens default,
|
|
5
|
+
* and the op-source (issuer) stamp.
|
|
6
|
+
*
|
|
7
|
+
* This module owns the client's mutable module state. Because ES module
|
|
8
|
+
* bindings are live, family modules import `_defaultLens` (and the maps) and
|
|
9
|
+
* observe every `setLens(...)` update through the same singleton — exactly as
|
|
10
|
+
* they did when all of this lived inline in `client.ts`.
|
|
11
|
+
*/
|
|
12
|
+
import type { InboundMessage, OutboundMessage } from '../protocol.js';
|
|
13
|
+
// TYPE-ONLY — the auth-lens contract + the cross-service event envelope, shared
|
|
14
|
+
// with the worker host + the sandbox's event provenance. Erased at build, so the
|
|
15
|
+
// leaf client bundle stays engine-free.
|
|
16
|
+
import type { AuthLens, SandboxEvent } from 'pyric/sandbox';
|
|
17
|
+
import { FirebaseError } from 'pyric/app';
|
|
18
|
+
import type { ClientPort } from './handles.js';
|
|
19
|
+
|
|
20
|
+
// ─── Port + correlation machinery ─────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
let _opCounter = 0;
|
|
23
|
+
let _subCounter = 0;
|
|
24
|
+
|
|
25
|
+
export function nextId(): string { return `op-${++_opCounter}`; }
|
|
26
|
+
export function nextSubId(): string { return `sub-${++_subCounter}`; }
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Pending RPC resolvers. Keyed by correlation id.
|
|
30
|
+
* Resolves with the `value` field on success; rejects with a typed error
|
|
31
|
+
* on failure.
|
|
32
|
+
*/
|
|
33
|
+
export const _pending = new Map<string, {
|
|
34
|
+
port: ClientPort;
|
|
35
|
+
resolve: (v: unknown) => void;
|
|
36
|
+
reject: (e: Error & { code: string }) => void;
|
|
37
|
+
}>();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Active snapshot subscribers. Keyed by subId.
|
|
41
|
+
* `next` is the user-supplied callback; `error` is the optional error handler.
|
|
42
|
+
*/
|
|
43
|
+
export const _snapSubs = new Map<string, {
|
|
44
|
+
port: ClientPort;
|
|
45
|
+
next: (snap: unknown) => void;
|
|
46
|
+
error?: (err: unknown) => void;
|
|
47
|
+
/** Firestore listeners abort on app deletion; RTDB/Auth stop silently. */
|
|
48
|
+
service?: 'firestore';
|
|
49
|
+
}>();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Active event-stream subscribers (Pyric Studio keystone). Keyed by subId.
|
|
53
|
+
* `next` receives each delivered BATCH of `SandboxEvent`s — the first batch is
|
|
54
|
+
* the initial `history()` snapshot, subsequent batches are single live events.
|
|
55
|
+
*/
|
|
56
|
+
export const _eventSubs = new Map<string, {
|
|
57
|
+
port: ClientPort;
|
|
58
|
+
next: (events: readonly SandboxEvent[]) => void;
|
|
59
|
+
}>();
|
|
60
|
+
const disconnectedPorts = new WeakSet<ClientPort>();
|
|
61
|
+
|
|
62
|
+
function appDeletedError(): Error & { code: string } {
|
|
63
|
+
return Object.assign(new Error('Firebase App was deleted'), { code: 'app/app-deleted' });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function isDisconnectedPort(port: ClientPort): boolean {
|
|
67
|
+
return disconnectedPorts.has(port);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Atomically register and post a subscription unless its app port is closed. */
|
|
71
|
+
export function openSnapshotSubscription(
|
|
72
|
+
port: ClientPort,
|
|
73
|
+
subId: string,
|
|
74
|
+
subscription: (typeof _snapSubs extends Map<string, infer T> ? T : never),
|
|
75
|
+
message: InboundMessage,
|
|
76
|
+
): boolean {
|
|
77
|
+
if (disconnectedPorts.has(port)) return false;
|
|
78
|
+
_snapSubs.set(subId, subscription);
|
|
79
|
+
port.postMessage(message);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Atomically register an event-stream subscription unless its port is closed. */
|
|
84
|
+
export function openEventSubscription(
|
|
85
|
+
port: ClientPort,
|
|
86
|
+
subId: string,
|
|
87
|
+
next: (events: readonly SandboxEvent[]) => void,
|
|
88
|
+
message: InboundMessage,
|
|
89
|
+
): boolean {
|
|
90
|
+
if (disconnectedPorts.has(port)) return false;
|
|
91
|
+
_eventSubs.set(subId, { port, next });
|
|
92
|
+
port.postMessage(message);
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Remove a local subscription and notify only a live app port. */
|
|
97
|
+
export function closeSubscription(port: ClientPort, subId: string): void {
|
|
98
|
+
_snapSubs.delete(subId);
|
|
99
|
+
_eventSubs.delete(subId);
|
|
100
|
+
if (!disconnectedPorts.has(port)) {
|
|
101
|
+
port.postMessage({ t: 'unsub', subId } satisfies InboundMessage);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Drop every client-side correlation owned by a closing app port. */
|
|
106
|
+
export function disconnectPort(port: ClientPort): void {
|
|
107
|
+
disconnectedPorts.add(port);
|
|
108
|
+
const error = appDeletedError();
|
|
109
|
+
for (const [id, pending] of [..._pending]) {
|
|
110
|
+
if (pending.port !== port) continue;
|
|
111
|
+
_pending.delete(id);
|
|
112
|
+
pending.reject(error);
|
|
113
|
+
}
|
|
114
|
+
for (const [id, subscription] of [..._snapSubs]) {
|
|
115
|
+
if (subscription.port !== port) continue;
|
|
116
|
+
_snapSubs.delete(id);
|
|
117
|
+
if (subscription.service === 'firestore') {
|
|
118
|
+
subscription.error?.(new FirebaseError('aborted', 'The operation was aborted.'));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
for (const [id, subscription] of [..._eventSubs]) {
|
|
122
|
+
if (subscription.port !== port) continue;
|
|
123
|
+
_eventSubs.delete(id);
|
|
124
|
+
}
|
|
125
|
+
port.onmessage = null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ─── Denial relay (headless dev visibility) ────────────────────────────────
|
|
129
|
+
//
|
|
130
|
+
// An agent driving `pyric dev` headlessly never sees the browser console, so
|
|
131
|
+
// a rules denial is otherwise invisible to it. Relay every denial (an error
|
|
132
|
+
// carrying `denialContext`) to the dev server, which prints it to the
|
|
133
|
+
// terminal — regardless of whether the app itself catches/handles the
|
|
134
|
+
// error. Fire-and-forget: never throws, never awaited into app flow, and a
|
|
135
|
+
// relay failure (dev server down, no `fetch`, non-pyric host) is swallowed
|
|
136
|
+
// silently — this is a diagnostics side channel, not a correctness path.
|
|
137
|
+
|
|
138
|
+
/** Shape POSTed to the dev server's `/__pyric/denials` endpoint. */
|
|
139
|
+
interface DenialRelayPayload {
|
|
140
|
+
kind: 'listener' | 'read';
|
|
141
|
+
code: string;
|
|
142
|
+
message: string;
|
|
143
|
+
denialContext: unknown;
|
|
144
|
+
/** Sibling of denialContext on the sandbox error (query-proof denials
|
|
145
|
+
* attach the suggested where() fix there); forwarded when present. */
|
|
146
|
+
remediation?: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** POST a denial to the dev server for terminal visibility. No-op when the
|
|
150
|
+
* error carries no `denialContext` (only rules denials are relayed) or when
|
|
151
|
+
* `fetch` isn't available (non-browser host). */
|
|
152
|
+
function relayDenial(
|
|
153
|
+
kind: 'listener' | 'read',
|
|
154
|
+
err: { message: string; code: string; denialContext?: unknown; remediation?: unknown },
|
|
155
|
+
): void {
|
|
156
|
+
if (err.denialContext === undefined) return;
|
|
157
|
+
if (typeof fetch !== 'function') return;
|
|
158
|
+
const payload: DenialRelayPayload = {
|
|
159
|
+
kind,
|
|
160
|
+
code: err.code,
|
|
161
|
+
message: err.message,
|
|
162
|
+
denialContext: err.denialContext,
|
|
163
|
+
...(typeof err.remediation === 'string' ? { remediation: err.remediation } : {}),
|
|
164
|
+
};
|
|
165
|
+
try {
|
|
166
|
+
void fetch('/__pyric/denials', {
|
|
167
|
+
method: 'POST',
|
|
168
|
+
headers: { 'content-type': 'application/json' },
|
|
169
|
+
body: JSON.stringify(payload),
|
|
170
|
+
}).catch(() => {});
|
|
171
|
+
} catch {
|
|
172
|
+
/* fire-and-forget — never let the relay disturb app flow */
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Wire up the port's onmessage handler (idempotent per-port). */
|
|
177
|
+
export function wirePort(port: ClientPort): void {
|
|
178
|
+
port.onmessage = (ev: MessageEvent<OutboundMessage>) => {
|
|
179
|
+
const msg = ev.data;
|
|
180
|
+
if (msg.t === 'res') {
|
|
181
|
+
const pending = _pending.get(msg.id);
|
|
182
|
+
if (!pending) return;
|
|
183
|
+
_pending.delete(msg.id);
|
|
184
|
+
if (msg.ok) {
|
|
185
|
+
pending.resolve(msg.value);
|
|
186
|
+
} else {
|
|
187
|
+
const err = new Error(msg.error.message) as Error & {
|
|
188
|
+
code: string;
|
|
189
|
+
denialContext?: unknown;
|
|
190
|
+
aiEnvelope?: unknown;
|
|
191
|
+
};
|
|
192
|
+
err.code = msg.error.code;
|
|
193
|
+
// Structured denial context (spike gap 6): re-attach so consumers —
|
|
194
|
+
// and the bridge relay, which re-serializes thrown errors — see the
|
|
195
|
+
// same shape a local SandboxError carries.
|
|
196
|
+
if (msg.error.denialContext !== undefined) {
|
|
197
|
+
err.denialContext = msg.error.denialContext;
|
|
198
|
+
}
|
|
199
|
+
// AI wire error envelope (pyric/ai): re-attach so the served
|
|
200
|
+
// `firebase/ai` entry can mint the exact SDK AIError decoration the
|
|
201
|
+
// in-process plane applies (see entries/ai.ts).
|
|
202
|
+
if (msg.error.aiEnvelope !== undefined) {
|
|
203
|
+
err.aiEnvelope = msg.error.aiEnvelope;
|
|
204
|
+
}
|
|
205
|
+
relayDenial('read', err);
|
|
206
|
+
pending.reject(err);
|
|
207
|
+
}
|
|
208
|
+
} else if (msg.t === 'snap') {
|
|
209
|
+
const sub = _snapSubs.get(msg.subId);
|
|
210
|
+
if (!sub) return;
|
|
211
|
+
// Auth snaps carry `SerializedUser | null` — a null value is a valid
|
|
212
|
+
// "signed out" payload, not an error, so guard the __error sniff.
|
|
213
|
+
const value = (msg.value ?? {}) as Record<string, unknown>;
|
|
214
|
+
if (value.__error) {
|
|
215
|
+
const errPayload = value.__error as { code: string; message: string; denialContext?: unknown; aiEnvelope?: unknown };
|
|
216
|
+
const err = new Error(errPayload.message) as Error & { code: string; denialContext?: unknown; aiEnvelope?: unknown };
|
|
217
|
+
err.code = errPayload.code;
|
|
218
|
+
if (errPayload.denialContext !== undefined) err.denialContext = errPayload.denialContext;
|
|
219
|
+
if (errPayload.aiEnvelope !== undefined) err.aiEnvelope = errPayload.aiEnvelope;
|
|
220
|
+
relayDenial('listener', err);
|
|
221
|
+
// Surface an unobserved listener error instead of swallowing it — the
|
|
222
|
+
// worker-path twin of the in-page default (a denied listener after a
|
|
223
|
+
// rules change / sign-out must not fail silently on the page console).
|
|
224
|
+
if (sub.error) sub.error(err);
|
|
225
|
+
else console.error('pyric/firestore: Uncaught Error in snapshot listener:', err);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
sub.next(msg.value);
|
|
229
|
+
} else if (msg.t === 'event') {
|
|
230
|
+
// Event-stream batch (Pyric Studio keystone). Plain JSON SandboxEvents —
|
|
231
|
+
// no rehydration. Deliver the whole batch to the registered subscriber.
|
|
232
|
+
const subscription = _eventSubs.get(msg.subId);
|
|
233
|
+
if (subscription) subscription.next(msg.events);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ─── Auth lens (Pyric Studio) ──────────────────────────────────────────────
|
|
239
|
+
//
|
|
240
|
+
// The default per-op auth lens carried on every FIRESTORE DATA op this client
|
|
241
|
+
// sends. The host resolves a data handle from it (`lensDb` in host.ts):
|
|
242
|
+
// - `{ mode: 'app-session' }` (the default): the served app's own session.
|
|
243
|
+
// - `{ mode: 'as', uid }`: impersonate — rules evaluate as that user.
|
|
244
|
+
// - `{ mode: 'admin' }`: admin lens (rule bypass; see host.ts gap note).
|
|
245
|
+
//
|
|
246
|
+
// Studio sets this so its data grids / rules-debug "re-run as user" views run
|
|
247
|
+
// under the chosen identity without threading `actAs` through every call. AUTH
|
|
248
|
+
// ops (`auth.*`) and `getVersion` are NEVER lensed — they operate the worker's
|
|
249
|
+
// session, not data — so the lens is stamped only on the data-op path.
|
|
250
|
+
|
|
251
|
+
/** Module-level default lens. `undefined` ⇒ the worker treats the op as the
|
|
252
|
+
* app's session (the additive default — existing senders omit `actAs`).
|
|
253
|
+
*
|
|
254
|
+
* Exported as a LIVE binding: family modules read it to stamp the lens onto
|
|
255
|
+
* subscriptions (`onSnapshot`, `rtdbOnValue`), and see `setLens(...)` updates
|
|
256
|
+
* through this one singleton. */
|
|
257
|
+
export let _defaultLens: AuthLens | undefined;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Set the default auth lens applied to subsequent Firestore DATA ops from this
|
|
261
|
+
* client (Pyric Studio). Pass `{ mode: 'as', uid }` to read/write AS a user
|
|
262
|
+
* (rules apply), `{ mode: 'admin' }` for the admin lens, or
|
|
263
|
+
* `{ mode: 'app-session' }` / `undefined` to revert to the app's own session.
|
|
264
|
+
*
|
|
265
|
+
* The lens is process-wide for this client module (one served page = one
|
|
266
|
+
* worker port), mirroring how Studio drives a single active identity at a time.
|
|
267
|
+
* Auth ops are unaffected — they always operate the real session.
|
|
268
|
+
*/
|
|
269
|
+
export function setLens(lens: AuthLens | undefined): void {
|
|
270
|
+
_defaultLens = lens && lens.mode === 'app-session' ? undefined : lens;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** The active default lens (read-only view), for Studio UI to reflect state. */
|
|
274
|
+
export function getLens(): AuthLens | undefined {
|
|
275
|
+
return _defaultLens;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Module-level op-source declaration (Pyric Studio traffic attribution).
|
|
280
|
+
* When set, every op/sub message THIS CLIENT MODULE CONSTRUCTS is stamped
|
|
281
|
+
* `source: 'studio'` on the wire; the host maps that onto the unified
|
|
282
|
+
* event stream's `actor` field so Traffic can filter Studio's own
|
|
283
|
+
* viewer/editor ops out of the app's stream.
|
|
284
|
+
*
|
|
285
|
+
* Studio's live plane sets this once at connect (`connectWorkerLive`);
|
|
286
|
+
* the served APP page never calls it (its service handles remain the source
|
|
287
|
+
* of app attribution), and RELAYED frames bypass Studio stamping entirely —
|
|
288
|
+
* the bridge relay ({@link relayWorkerOp} / {@link relayWorkerSub}) clears the
|
|
289
|
+
* Studio issuer and marks remote frames through {@link rawRpc} / a direct postMessage, so a
|
|
290
|
+
* user's own admin-SDK traffic through the remote bridge is never
|
|
291
|
+
* mislabeled as Studio's even though it rides the same port.
|
|
292
|
+
*/
|
|
293
|
+
let _opIssuer: 'studio' | undefined;
|
|
294
|
+
|
|
295
|
+
/** Declare who issues the ops this client module constructs. See {@link _opIssuer}. */
|
|
296
|
+
export function setOpIssuer(source: 'studio' | undefined): void {
|
|
297
|
+
_opIssuer = source;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Stamp the declared op source onto a client-constructed message. Ops and
|
|
301
|
+
* subscriptions only — control frames (`tool`, `unsub`) never carry it
|
|
302
|
+
* (agent tool-calls dispatched through this port must not inherit
|
|
303
|
+
* Studio's source; their inner ops are attributed by the host). */
|
|
304
|
+
export function stampIssuer<T extends { t?: string }>(msg: T): T {
|
|
305
|
+
return _opIssuer && (msg.t === 'op' || msg.t === 'sub')
|
|
306
|
+
? { ...msg, issuer: _opIssuer }
|
|
307
|
+
: msg;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Send an already-final message and return a promise for its result — no
|
|
312
|
+
* implicit stamping. The RELAY path ({@link relayWorkerOp}) explicitly owns
|
|
313
|
+
* the final remote provenance fields before sending through this function.
|
|
314
|
+
*/
|
|
315
|
+
export function rawRpc(port: ClientPort, msg: InboundMessage): Promise<unknown> {
|
|
316
|
+
if (disconnectedPorts.has(port)) return Promise.reject(appDeletedError());
|
|
317
|
+
return new Promise<unknown>((resolve, reject) => {
|
|
318
|
+
const opMsg = msg as { id: string };
|
|
319
|
+
_pending.set(opMsg.id, {
|
|
320
|
+
port,
|
|
321
|
+
resolve,
|
|
322
|
+
reject: reject as (e: Error & { code: string }) => void,
|
|
323
|
+
});
|
|
324
|
+
port.postMessage(msg);
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** Send a CLIENT-CONSTRUCTED message: stamps the declared op source, then sends. */
|
|
329
|
+
export function rpc(port: ClientPort, msg: InboundMessage): Promise<unknown> {
|
|
330
|
+
return rawRpc(port, stampIssuer(msg));
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Like {@link rpc} but stamps the active default auth lens onto the op message
|
|
335
|
+
* (Pyric Studio). Used by data-service ops so a `setLens(...)` choice
|
|
336
|
+
* carries per op without every call site threading `actAs`. Auth ops + version
|
|
337
|
+
* use the bare {@link rpc} so they never carry a lens.
|
|
338
|
+
*
|
|
339
|
+
* `actAs` is only attached when a lens is active — when none is set the wire
|
|
340
|
+
* message is byte-identical to before, preserving the additive contract.
|
|
341
|
+
*/
|
|
342
|
+
export function dataRpc(port: ClientPort, msg: InboundMessage & { t: 'op' }): Promise<unknown> {
|
|
343
|
+
if (disconnectedPorts.has(port) && !msg.method.startsWith('rtdb.')) {
|
|
344
|
+
return Promise.reject(
|
|
345
|
+
new FirebaseError('failed-precondition', 'The client has already been terminated.'),
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
const withLens = _defaultLens ? { ...msg, actAs: _defaultLens } : msg;
|
|
349
|
+
return rpc(port, withLens);
|
|
350
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Internal app-port teardown; intentionally absent from the public worker-client barrel. */
|
|
2
|
+
import type { InboundMessage } from '../protocol.js';
|
|
3
|
+
import { disconnectPort, nextId, rawRpc } from './core.js';
|
|
4
|
+
import type { ClientDb } from './handles.js';
|
|
5
|
+
|
|
6
|
+
export interface DisconnectClientOptions {
|
|
7
|
+
/** Bound version-skew and worker-crash cases where no disconnect reply arrives. */
|
|
8
|
+
ackTimeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const DEFAULT_ACK_TIMEOUT_MS = 5_000;
|
|
12
|
+
|
|
13
|
+
function deleteTimeoutError(): Error & { code: string } {
|
|
14
|
+
return Object.assign(
|
|
15
|
+
new Error(
|
|
16
|
+
'Timed out waiting for SharedWorker app cleanup acknowledgment. ' +
|
|
17
|
+
'Close all tabs using this pyric dev origin so the worker can restart.',
|
|
18
|
+
),
|
|
19
|
+
{ code: 'app/delete-timeout' },
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function disconnectClient(
|
|
24
|
+
db: ClientDb,
|
|
25
|
+
options: DisconnectClientOptions = {},
|
|
26
|
+
): Promise<void> {
|
|
27
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
28
|
+
try {
|
|
29
|
+
const acknowledged = rawRpc(db.port, {
|
|
30
|
+
t: 'disconnect',
|
|
31
|
+
id: nextId(),
|
|
32
|
+
} satisfies InboundMessage);
|
|
33
|
+
const timedOut = new Promise<never>((_resolve, reject) => {
|
|
34
|
+
timeout = setTimeout(
|
|
35
|
+
() => reject(deleteTimeoutError()),
|
|
36
|
+
options.ackTimeoutMs ?? DEFAULT_ACK_TIMEOUT_MS,
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
await Promise.race([acknowledged, timedOut]);
|
|
40
|
+
} finally {
|
|
41
|
+
if (timeout !== undefined) clearTimeout(timeout);
|
|
42
|
+
disconnectPort(db.port);
|
|
43
|
+
db.port.close();
|
|
44
|
+
}
|
|
45
|
+
}
|