@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,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharedWorker host — worker-backed Cloud Storage ops.
|
|
3
|
+
*
|
|
4
|
+
* Object browse (`storage.listAll`/`getMetadata`), the MessagePort-only
|
|
5
|
+
* `getBlob`, and the relay-safe base64 byte transfer (`putBytes`/`getBytes`)
|
|
6
|
+
* plus idempotent `deleteObject`. Owns the storage lens resolver
|
|
7
|
+
* (`lensStorage` — the storage mirror of the firestore/rtdb lens resolvers),
|
|
8
|
+
* the lazily-created shared handle, and the wire → `SettableMetadata` mapper.
|
|
9
|
+
*
|
|
10
|
+
* Routed here by the host dispatcher. Storage dispatch is async, so the
|
|
11
|
+
* mutating ops thread the op's provenance EXPLICITLY (their events escape the
|
|
12
|
+
* dispatcher's synchronous ambient-provenance window). Never imports the
|
|
13
|
+
* dispatcher.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
getStorageSandbox,
|
|
18
|
+
ref as storageRef,
|
|
19
|
+
listAll as storageListAll,
|
|
20
|
+
getMetadata as storageGetMetadata,
|
|
21
|
+
getBlob as storageGetBlob,
|
|
22
|
+
getBytes as storageGetBytes,
|
|
23
|
+
uploadBytes as storageUploadBytes,
|
|
24
|
+
deleteObject as storageDeleteObject,
|
|
25
|
+
type FirebaseStorage,
|
|
26
|
+
type SettableMetadata,
|
|
27
|
+
} from 'pyric/storage';
|
|
28
|
+
// Host-only rules-bypass admin plane — the storage mirror of
|
|
29
|
+
// `getAdminFirestore`/`getAdminDatabase`, resolved for `actAs: { mode: 'admin' }`.
|
|
30
|
+
import {
|
|
31
|
+
bindStorageOperationContext,
|
|
32
|
+
getAdminStorageSandbox,
|
|
33
|
+
} from 'pyric/storage/internal';
|
|
34
|
+
import type { AuthLens } from 'pyric/sandbox';
|
|
35
|
+
import { bindOperationContext } from 'pyric/sandbox/internal';
|
|
36
|
+
|
|
37
|
+
import type { OpMessage } from '../protocol.js';
|
|
38
|
+
import {
|
|
39
|
+
bytesToBase64,
|
|
40
|
+
base64ToBytes,
|
|
41
|
+
storagePayloadTooLarge,
|
|
42
|
+
MAX_STORAGE_OP_BYTES,
|
|
43
|
+
MAX_STORAGE_OP_B64_LENGTH,
|
|
44
|
+
} from '../protocol.js';
|
|
45
|
+
import { type HostCtx, type PortLike, ok, fail } from '../host-context.js';
|
|
46
|
+
import { authStateForLens, lensCacheKey, opProvenance, sessionCacheKey } from './core.js';
|
|
47
|
+
import { portSession } from '../host-auth.js';
|
|
48
|
+
|
|
49
|
+
/** The shared Storage handle, lazily created (Pyric Studio data browse): one per
|
|
50
|
+
* worker, directly over the shared sandbox. The high-level
|
|
51
|
+
* `pyric/storage` ops enforce rules, so the host reads through them. */
|
|
52
|
+
function ensureStorage(ctx: HostCtx): FirebaseStorage {
|
|
53
|
+
return (ctx.storage ??= getStorageSandbox(bindOperationContext(ctx.sandbox.withAuth(null), {
|
|
54
|
+
source: { kind: 'app' },
|
|
55
|
+
authLens: { mode: 'app-session' },
|
|
56
|
+
})));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the Storage handle a storage op runs against, given its `actAs`
|
|
61
|
+
* lens — the storage mirror of {@link lensRtdb}:
|
|
62
|
+
*
|
|
63
|
+
* - absent / `app-session` → a handle carrying the initiating port's Auth
|
|
64
|
+
* session, or the shared anonymous handle when that port is signed out.
|
|
65
|
+
* Storage rules apply only when the HOST
|
|
66
|
+
* configured them on this sandbox's storage service (first call per
|
|
67
|
+
* sandbox wins) — the SERVED worker configures them via
|
|
68
|
+
* `applyServeInit` (`serve-init.ts`), which opens the storage service
|
|
69
|
+
* with `payload.storageRules` BEFORE any op can reach `ensureStorage`/
|
|
70
|
+
* `lensStorage`, so every lens on a served worker enforces the
|
|
71
|
+
* project's storage.rules (or runs open when the project has none,
|
|
72
|
+
* matching Firestore/RTDB's no-rules posture). The lens split still
|
|
73
|
+
* matters for embedding/test hosts that open the service directly.
|
|
74
|
+
* - `{ mode: 'admin' }` → the rules-BYPASS handle from
|
|
75
|
+
* `pyric/storage/internal`'s admin plane — same per-sandbox store +
|
|
76
|
+
* ruleset, rule evaluation skipped (firebase-admin semantics for the
|
|
77
|
+
* `pyric-admin` remote arm / Studio admin lens).
|
|
78
|
+
* - `{ mode: 'as', uid }` → a frozen-identity `getStorageSandbox(
|
|
79
|
+
* sandbox.withAuth({ uid, token? }))` handle; rules evaluate AS that
|
|
80
|
+
* user. Cached per uid/token key on `ctx.lensStorages`.
|
|
81
|
+
*/
|
|
82
|
+
function sessionStorage(ctx: HostCtx, port: PortLike): FirebaseStorage {
|
|
83
|
+
const session = portSession(ctx, port);
|
|
84
|
+
if (!session) return ensureStorage(ctx);
|
|
85
|
+
const key = sessionCacheKey(session);
|
|
86
|
+
const handles = (ctx.sessionStorages ??= new Map());
|
|
87
|
+
let handle = handles.get(key);
|
|
88
|
+
if (!handle) {
|
|
89
|
+
handle = getStorageSandbox(ctx.sandbox.withAuth(session.state));
|
|
90
|
+
handles.set(key, handle);
|
|
91
|
+
}
|
|
92
|
+
return handle;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function lensStorage(ctx: HostCtx, actAs: AuthLens | undefined, port: PortLike): FirebaseStorage {
|
|
96
|
+
if (!actAs || actAs.mode === 'app-session') {
|
|
97
|
+
return sessionStorage(ctx, port);
|
|
98
|
+
}
|
|
99
|
+
if (actAs.mode === 'admin') {
|
|
100
|
+
return (ctx.adminStorage ??= getAdminStorageSandbox(ctx.sandbox));
|
|
101
|
+
}
|
|
102
|
+
// Genuinely unauthenticated — see the `anon` note on lensDb. Distinct from
|
|
103
|
+
// the shared page handle only when the host configured storage rules, but
|
|
104
|
+
// pinning it keeps remote `withAuth(null)` semantics uniform across services.
|
|
105
|
+
if (actAs.mode === 'anon') {
|
|
106
|
+
return (ctx.anonStorage ??= getStorageSandbox(ctx.sandbox.withAuth(null)));
|
|
107
|
+
}
|
|
108
|
+
const handles = (ctx.lensStorages ??= new Map());
|
|
109
|
+
const key = lensCacheKey(actAs);
|
|
110
|
+
let handle = handles.get(key);
|
|
111
|
+
if (!handle) {
|
|
112
|
+
handle = getStorageSandbox(ctx.sandbox.withAuth(authStateForLens(actAs)));
|
|
113
|
+
handles.set(key, handle);
|
|
114
|
+
}
|
|
115
|
+
return handle;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Map a wire `storage.putBytes` payload to `pyric/storage`'s
|
|
120
|
+
* `SettableMetadata`. The explicit `contentType` field wins; recognized
|
|
121
|
+
* settable fields are lifted from `metadata`; a GCS-style nested custom map
|
|
122
|
+
* (`metadata.metadata`, as `@google-cloud/storage`'s `save` spells it) or a
|
|
123
|
+
* pyric-style `metadata.customMetadata` becomes `customMetadata` with
|
|
124
|
+
* values coerced to strings (the storage-rules `metadata` model).
|
|
125
|
+
*/
|
|
126
|
+
function toSettableMetadata(msg: {
|
|
127
|
+
contentType?: string;
|
|
128
|
+
metadata?: Record<string, unknown>;
|
|
129
|
+
}): SettableMetadata {
|
|
130
|
+
const md = msg.metadata ?? {};
|
|
131
|
+
const str = (key: string): string | undefined =>
|
|
132
|
+
typeof md[key] === 'string' ? (md[key] as string) : undefined;
|
|
133
|
+
const customSource = md['customMetadata'] ?? md['metadata'];
|
|
134
|
+
let customMetadata: Record<string, string> | undefined;
|
|
135
|
+
if (customSource !== null && typeof customSource === 'object' && !Array.isArray(customSource)) {
|
|
136
|
+
customMetadata = {};
|
|
137
|
+
for (const [k, v] of Object.entries(customSource as Record<string, unknown>)) {
|
|
138
|
+
customMetadata[k] = String(v);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const settable: SettableMetadata = {};
|
|
142
|
+
const contentType = msg.contentType ?? str('contentType');
|
|
143
|
+
if (contentType !== undefined) settable.contentType = contentType;
|
|
144
|
+
const cacheControl = str('cacheControl');
|
|
145
|
+
if (cacheControl !== undefined) settable.cacheControl = cacheControl;
|
|
146
|
+
const contentDisposition = str('contentDisposition');
|
|
147
|
+
if (contentDisposition !== undefined) settable.contentDisposition = contentDisposition;
|
|
148
|
+
const contentEncoding = str('contentEncoding');
|
|
149
|
+
if (contentEncoding !== undefined) settable.contentEncoding = contentEncoding;
|
|
150
|
+
const contentLanguage = str('contentLanguage');
|
|
151
|
+
if (contentLanguage !== undefined) settable.contentLanguage = contentLanguage;
|
|
152
|
+
if (customMetadata !== undefined) settable.customMetadata = customMetadata;
|
|
153
|
+
return settable;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** The storage op methods routed to {@link handleStorageOp}. */
|
|
157
|
+
const STORAGE_METHODS = new Set<string>([
|
|
158
|
+
'storage.listAll',
|
|
159
|
+
'storage.getMetadata',
|
|
160
|
+
'storage.getBlob',
|
|
161
|
+
'storage.putBytes',
|
|
162
|
+
'storage.getBytes',
|
|
163
|
+
'storage.deleteObject',
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
export function isStorageOp(method: OpMessage['method']): boolean {
|
|
167
|
+
return STORAGE_METHODS.has(method);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function handleStorageOp(
|
|
171
|
+
ctx: HostCtx,
|
|
172
|
+
port: PortLike,
|
|
173
|
+
msg: OpMessage,
|
|
174
|
+
): Promise<void> {
|
|
175
|
+
switch (msg.method) {
|
|
176
|
+
case 'storage.listAll': {
|
|
177
|
+
// Object browse. `listAll` enforces `read` rules on the scanned prefix
|
|
178
|
+
// under the op's lens (admin lens bypasses — see lensStorage).
|
|
179
|
+
try {
|
|
180
|
+
const storage = bindStorageOperationContext(
|
|
181
|
+
lensStorage(ctx, msg.actAs, port),
|
|
182
|
+
opProvenance(msg),
|
|
183
|
+
);
|
|
184
|
+
const result = await storageListAll(storageRef(storage, msg.path));
|
|
185
|
+
ok(port, msg.id, {
|
|
186
|
+
items: result.items.map((r) => ({ fullPath: r.fullPath, name: r.name })),
|
|
187
|
+
prefixes: result.prefixes.map((r) => ({ fullPath: r.fullPath, name: r.name })),
|
|
188
|
+
});
|
|
189
|
+
} catch (e) { fail(port, msg.id, e); }
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
case 'storage.getMetadata': {
|
|
194
|
+
try {
|
|
195
|
+
const storage = bindStorageOperationContext(
|
|
196
|
+
lensStorage(ctx, msg.actAs, port),
|
|
197
|
+
opProvenance(msg),
|
|
198
|
+
);
|
|
199
|
+
// FullMetadata is plain JSON (bucket/fullPath/name/size/contentType/...).
|
|
200
|
+
ok(
|
|
201
|
+
port,
|
|
202
|
+
msg.id,
|
|
203
|
+
await storageGetMetadata(storageRef(storage, msg.path)),
|
|
204
|
+
);
|
|
205
|
+
} catch (e) { fail(port, msg.id, e); }
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
case 'storage.getBlob': {
|
|
210
|
+
// MessagePort-ONLY: the Blob structured-clones to in-page callers
|
|
211
|
+
// (Studio previews) but silently corrupts under the JSON WS relay — the
|
|
212
|
+
// bridge client rejects relaying it (binary-payload guard). Remote
|
|
213
|
+
// callers use `storage.getBytes` (base64) instead.
|
|
214
|
+
try {
|
|
215
|
+
const storage = bindStorageOperationContext(
|
|
216
|
+
lensStorage(ctx, msg.actAs, port),
|
|
217
|
+
opProvenance(msg),
|
|
218
|
+
);
|
|
219
|
+
ok(
|
|
220
|
+
port,
|
|
221
|
+
msg.id,
|
|
222
|
+
await storageGetBlob(storageRef(storage, msg.path)),
|
|
223
|
+
);
|
|
224
|
+
} catch (e) { fail(port, msg.id, e); }
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
case 'storage.putBytes': {
|
|
229
|
+
// Byte upload (remote sandbox, slice 2). Decode-end size cap: reject an
|
|
230
|
+
// oversized base64 string BEFORE materializing its bytes, then re-check
|
|
231
|
+
// the exact decoded length. Rules enforce under the op's lens; the
|
|
232
|
+
// upload emits `service_mutation` events. Storage dispatch is async, so
|
|
233
|
+
// the event escapes the ambient-provenance window `handleMessage` opened;
|
|
234
|
+
// thread the op's provenance EXPLICITLY so a Studio-issued write is
|
|
235
|
+
// attributable end to end (issue #84 item 3).
|
|
236
|
+
try {
|
|
237
|
+
if (msg.dataB64.length > MAX_STORAGE_OP_B64_LENGTH) {
|
|
238
|
+
throw storagePayloadTooLarge(
|
|
239
|
+
Math.floor(msg.dataB64.length * 0.75),
|
|
240
|
+
`storage.putBytes payload for '${msg.path}'`,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
const bytes = base64ToBytes(msg.dataB64);
|
|
244
|
+
if (bytes.byteLength > MAX_STORAGE_OP_BYTES) {
|
|
245
|
+
throw storagePayloadTooLarge(bytes.byteLength, `storage.putBytes payload for '${msg.path}'`);
|
|
246
|
+
}
|
|
247
|
+
const storage = bindStorageOperationContext(
|
|
248
|
+
lensStorage(ctx, msg.actAs, port),
|
|
249
|
+
opProvenance(msg),
|
|
250
|
+
);
|
|
251
|
+
const result = await storageUploadBytes(
|
|
252
|
+
storageRef(storage, msg.path),
|
|
253
|
+
bytes,
|
|
254
|
+
toSettableMetadata(msg),
|
|
255
|
+
);
|
|
256
|
+
// FullMetadata — plain JSON, relay-safe.
|
|
257
|
+
ok(port, msg.id, result.metadata);
|
|
258
|
+
} catch (e) { fail(port, msg.id, e); }
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
case 'storage.getBytes': {
|
|
263
|
+
// JSON-safe byte download (remote sandbox, slice 2): base64 in the
|
|
264
|
+
// result. Encode-end size cap so a big browser-side object can't blow
|
|
265
|
+
// up the relay. Metadata is read alongside for contentType (both reads
|
|
266
|
+
// run under the same lens; rule-eval order keeps `unauthorized`
|
|
267
|
+
// superseding `not-found`, matching pyric/storage).
|
|
268
|
+
try {
|
|
269
|
+
const storage = bindStorageOperationContext(
|
|
270
|
+
lensStorage(ctx, msg.actAs, port),
|
|
271
|
+
opProvenance(msg),
|
|
272
|
+
);
|
|
273
|
+
const r = storageRef(storage, msg.path);
|
|
274
|
+
const meta = await storageGetMetadata(r);
|
|
275
|
+
if (meta.size > MAX_STORAGE_OP_BYTES) {
|
|
276
|
+
throw storagePayloadTooLarge(meta.size, `object '${msg.path}'`);
|
|
277
|
+
}
|
|
278
|
+
const buf = await storageGetBytes(r);
|
|
279
|
+
if (buf.byteLength > MAX_STORAGE_OP_BYTES) {
|
|
280
|
+
throw storagePayloadTooLarge(buf.byteLength, `object '${msg.path}'`);
|
|
281
|
+
}
|
|
282
|
+
ok(port, msg.id, {
|
|
283
|
+
dataB64: bytesToBase64(new Uint8Array(buf)),
|
|
284
|
+
contentType: meta.contentType,
|
|
285
|
+
size: buf.byteLength,
|
|
286
|
+
});
|
|
287
|
+
} catch (e) { fail(port, msg.id, e); }
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
case 'storage.deleteObject': {
|
|
292
|
+
// `pyric/storage`'s sandbox delete is idempotent (no-op on missing) —
|
|
293
|
+
// matching the pyric-admin local arm's delete semantics. Rules enforce
|
|
294
|
+
// `write` under the op's lens; deletes emit `service_mutation` events.
|
|
295
|
+
// Async dispatch escapes the ambient window — thread provenance
|
|
296
|
+
// explicitly (issue #84 item 3).
|
|
297
|
+
try {
|
|
298
|
+
const storage = bindStorageOperationContext(
|
|
299
|
+
lensStorage(ctx, msg.actAs, port),
|
|
300
|
+
opProvenance(msg),
|
|
301
|
+
);
|
|
302
|
+
await storageDeleteObject(storageRef(storage, msg.path));
|
|
303
|
+
ok(port, msg.id, null);
|
|
304
|
+
} catch (e) { fail(port, msg.id, e); }
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
default: {
|
|
309
|
+
fail(port, msg.id, new Error(`Unknown method: ${String((msg as { method: unknown }).method)}`));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharedWorker host — Pyric Studio control ops.
|
|
3
|
+
*
|
|
4
|
+
* The sandbox-snapshot export Studio forks for rules re-run (`getSnapshot`).
|
|
5
|
+
* Kept as its own family to mirror the client's `studio` module.
|
|
6
|
+
*
|
|
7
|
+
* Routed here by the host dispatcher. Never imports the dispatcher.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { setRules } from 'pyric/sandbox/firestore';
|
|
11
|
+
|
|
12
|
+
import type { OpMessage } from '../protocol.js';
|
|
13
|
+
import { type HostCtx, type PortLike, ok, fail } from '../host-context.js';
|
|
14
|
+
|
|
15
|
+
/** The Studio control op methods routed to {@link handleStudioOp}. */
|
|
16
|
+
const STUDIO_METHODS = new Set<string>([
|
|
17
|
+
'getSnapshot',
|
|
18
|
+
'resetAll',
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
export function isStudioOp(method: OpMessage['method']): boolean {
|
|
22
|
+
return STUDIO_METHODS.has(method);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function handleStudioOp(
|
|
26
|
+
ctx: HostCtx,
|
|
27
|
+
port: PortLike,
|
|
28
|
+
msg: OpMessage,
|
|
29
|
+
): Promise<void> {
|
|
30
|
+
switch (msg.method) {
|
|
31
|
+
case 'getSnapshot': {
|
|
32
|
+
// Export the current sandbox snapshot (Pyric Studio rules re-run): Studio
|
|
33
|
+
// forks it locally to test edited rules / re-issue as the user on a branch.
|
|
34
|
+
ok(port, msg.id, ctx.sandbox.snapshot());
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
case 'resetAll': {
|
|
39
|
+
// Sandbox-owned full reset (issue #359): the ONE wipe-everything path.
|
|
40
|
+
// `resetAll` iterates the worker sandbox's persistable-service registry,
|
|
41
|
+
// so auth users, the RTDB tree, AND storage objects clear along with the
|
|
42
|
+
// Firestore env — Studio can't forget a service the sandbox knows about.
|
|
43
|
+
// Awaited (storage clears IndexedDB stores) before the ack. Op-level
|
|
44
|
+
// failures reply as errors; per-service reset failures ride the reply
|
|
45
|
+
// payload's `errors` so Studio can surface a half-clear instead of
|
|
46
|
+
// reporting a clean reset.
|
|
47
|
+
try {
|
|
48
|
+
const { errors } = await ctx.sandbox.resetAll();
|
|
49
|
+
// `resetAll` swapped the env, wiping env-owned FIRESTORE rules (RTDB /
|
|
50
|
+
// storage rules live on their service objects and survive). Re-deploy
|
|
51
|
+
// the active project rules so a DATA reset never de-governs writes.
|
|
52
|
+
const firestoreRules = ctx.activeRules?.firestore;
|
|
53
|
+
const source =
|
|
54
|
+
firestoreRules?.status === 'active'
|
|
55
|
+
? firestoreRules.source
|
|
56
|
+
: firestoreRules?.lastKnownGood;
|
|
57
|
+
if (typeof source === 'string') setRules(ctx.sandbox, source);
|
|
58
|
+
// The server capture (`.pyric/last-session.json`) persists the event
|
|
59
|
+
// history a rebooting worker re-primes into Traffic. Flush it NOW —
|
|
60
|
+
// reset just emptied `sandbox.history()`, and waiting out the
|
|
61
|
+
// capture debounce leaves a window where a worker death resurrects
|
|
62
|
+
// the wiped session's events on the next boot.
|
|
63
|
+
ctx.captureFlush?.();
|
|
64
|
+
ok(port, msg.id, { errors });
|
|
65
|
+
} catch (e) {
|
|
66
|
+
fail(port, msg.id, e instanceof Error ? e : new Error(String(e)));
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
default: {
|
|
72
|
+
fail(port, msg.id, new Error(`Unknown method: ${String((msg as { method: unknown }).method)}`));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharedWorker host — Firestore + RTDB value-subscription registry.
|
|
3
|
+
*
|
|
4
|
+
* `onSnapshot` / RTDB `onValue` listeners registered against the op's
|
|
5
|
+
* lens-resolved handle, with cross-port snapshot fan-out. Owns the
|
|
6
|
+
* session-bound sub registry (#754) that re-establishes a port's lens-less
|
|
7
|
+
* listeners under its NEW identity on every auth transition, mirroring prod's
|
|
8
|
+
* stream re-establishment (a sign-out re-evaluates live listeners so an
|
|
9
|
+
* auth-gated stream loses access instead of leaking the previous user's data).
|
|
10
|
+
*
|
|
11
|
+
* Routed here by the host dispatcher. Never imports the dispatcher.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
onSnapshot,
|
|
16
|
+
type DocumentReference,
|
|
17
|
+
type CollectionReference,
|
|
18
|
+
type Query,
|
|
19
|
+
} from 'pyric/firestore';
|
|
20
|
+
import {
|
|
21
|
+
ref as rtdbRef,
|
|
22
|
+
onValue as rtdbOnValue,
|
|
23
|
+
type DatabaseReference,
|
|
24
|
+
} from 'pyric/database';
|
|
25
|
+
|
|
26
|
+
import type { FirestoreSubMessage, RtdbValueSubMessage, UnsubMessage } from '../protocol.js';
|
|
27
|
+
import { serializeError, isRtdbSub } from '../protocol.js';
|
|
28
|
+
import { activityJourneyId, type HostCtx, type PortLike, post } from '../host-context.js';
|
|
29
|
+
import {
|
|
30
|
+
lensDb,
|
|
31
|
+
sessionDb,
|
|
32
|
+
lensRtdb,
|
|
33
|
+
opProvenance,
|
|
34
|
+
resolveTarget,
|
|
35
|
+
serializeDocSnap,
|
|
36
|
+
} from './core.js';
|
|
37
|
+
import { rtdbSnapToWire } from './rtdb.js';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Session-bound sub registry (#754): the original sub message for every
|
|
41
|
+
* listener a port opened WITHOUT an explicit lens, so a port session change
|
|
42
|
+
* can re-establish it under the new identity (see resubscribeSessionSubs).
|
|
43
|
+
* Parallel to `ctx.subs` (which holds only the unsub fns).
|
|
44
|
+
*/
|
|
45
|
+
type SessionBoundSubMessage = FirestoreSubMessage | RtdbValueSubMessage;
|
|
46
|
+
|
|
47
|
+
const _sessionSubs = new WeakMap<HostCtx, Map<PortLike, Map<string, SessionBoundSubMessage>>>();
|
|
48
|
+
|
|
49
|
+
function sessionSubsFor(ctx: HostCtx, port: PortLike): Map<string, SessionBoundSubMessage> {
|
|
50
|
+
let byPort = _sessionSubs.get(ctx);
|
|
51
|
+
if (!byPort) {
|
|
52
|
+
byPort = new Map();
|
|
53
|
+
_sessionSubs.set(ctx, byPort);
|
|
54
|
+
}
|
|
55
|
+
let bySubId = byPort.get(port);
|
|
56
|
+
if (!bySubId) {
|
|
57
|
+
bySubId = new Map();
|
|
58
|
+
byPort.set(port, bySubId);
|
|
59
|
+
}
|
|
60
|
+
return bySubId;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Drop a port's session-bound sub records — invoked by the dispatcher's
|
|
64
|
+
* `cleanupPort` on port disconnect. */
|
|
65
|
+
export function dropPortSessionSubs(ctx: HostCtx, port: PortLike): void {
|
|
66
|
+
_sessionSubs.get(ctx)?.delete(port);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Re-establish a port's session-bound listeners under its CURRENT session —
|
|
71
|
+
* invoked (via the ctx hook) on every port session change. Mirrors prod's
|
|
72
|
+
* stream re-establishment on auth transitions: each listener is torn down and
|
|
73
|
+
* re-registered through `sessionDb`, so the fresh evaluation either delivers
|
|
74
|
+
* a snapshot (allowed) or a `permission-denied` snap-error (revoked). A
|
|
75
|
+
* signed-out page no longer keeps receiving auth-gated data.
|
|
76
|
+
*/
|
|
77
|
+
function resubscribeSessionSubs(ctx: HostCtx, port: PortLike): void {
|
|
78
|
+
const bound = _sessionSubs.get(ctx)?.get(port);
|
|
79
|
+
if (!bound || bound.size === 0) return;
|
|
80
|
+
const portSubs = ctx.subs.get(port);
|
|
81
|
+
for (const [subId, msg] of [...bound]) {
|
|
82
|
+
const unsub = portSubs?.get(subId);
|
|
83
|
+
if (isRtdbSub(msg)) {
|
|
84
|
+
if (unsub) unsub();
|
|
85
|
+
portSubs?.delete(subId);
|
|
86
|
+
bound.delete(subId); // handleRtdbSub re-records it
|
|
87
|
+
handleRtdbSub(ctx, port, msg);
|
|
88
|
+
} else {
|
|
89
|
+
// Auth transitions enter through host-auth rather than the dispatcher,
|
|
90
|
+
// so restore the original app/page provenance explicitly. The detach is
|
|
91
|
+
// correlated to the old accepted registration by listener id; this
|
|
92
|
+
// replacement attach must retain the same logical page attribution.
|
|
93
|
+
const provenance = {
|
|
94
|
+
...opProvenance(msg, activityJourneyId(ctx, port)),
|
|
95
|
+
activity: { listenerId: subId, listenerLifecycle: 'reauthorize' as const },
|
|
96
|
+
};
|
|
97
|
+
const reauthorize = (): void => {
|
|
98
|
+
if (unsub) unsub();
|
|
99
|
+
portSubs?.delete(subId);
|
|
100
|
+
bound.delete(subId); // handleSub re-records it
|
|
101
|
+
handleSub(ctx, port, msg);
|
|
102
|
+
};
|
|
103
|
+
if (provenance && ctx.sandbox.runWithProvenance) {
|
|
104
|
+
ctx.sandbox.runWithProvenance(provenance, reauthorize);
|
|
105
|
+
} else {
|
|
106
|
+
reauthorize();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function handleSub(ctx: HostCtx, port: PortLike, msg: FirestoreSubMessage): void {
|
|
113
|
+
// Resolve the listener's data handle through the SAME lens path ops use
|
|
114
|
+
// (Pyric Studio F4 "watch as user"): `{ mode: 'as', uid }` registers the
|
|
115
|
+
// listener as that user so its rule evals impersonate, `{ mode: 'admin' }`
|
|
116
|
+
// bypasses rules. Absent ⇒ the PORT'S SESSION (#754), so an app listener
|
|
117
|
+
// evaluates rules as whoever this tab signed in as.
|
|
118
|
+
const db = msg.actAs ? lensDb(ctx, msg.actAs) : sessionDb(ctx, port);
|
|
119
|
+
ensurePortSubs(ctx, port);
|
|
120
|
+
const portSubs = ctx.subs.get(port)!;
|
|
121
|
+
|
|
122
|
+
if (portSubs.has(msg.subId)) return; // idempotent
|
|
123
|
+
|
|
124
|
+
// Session-bound listeners re-establish on this port's auth transitions.
|
|
125
|
+
if (!msg.actAs) {
|
|
126
|
+
ctx.resubscribePortSubs ??= (p) => resubscribeSessionSubs(ctx, p);
|
|
127
|
+
sessionSubsFor(ctx, port).set(msg.subId, msg);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let target: DocumentReference | CollectionReference | Query;
|
|
131
|
+
let unsub: () => void;
|
|
132
|
+
try {
|
|
133
|
+
target = resolveTarget(db, msg.target);
|
|
134
|
+
unsub = registerListener(ctx, port, msg, target);
|
|
135
|
+
} catch (e) {
|
|
136
|
+
// resolveTarget / onSnapshot can throw synchronously (e.g. an invalid
|
|
137
|
+
// query or a rules-rejected target). Deliver it to the client's onSnapshot
|
|
138
|
+
// error callback as a snap-error instead of letting it escape handleMessage
|
|
139
|
+
// as an unhandled rejection (which would silently deliver NOTHING).
|
|
140
|
+
post(port, { t: 'snap', subId: msg.subId, value: { __error: serializeError(e) } });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
portSubs.set(msg.subId, unsub);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function handleRtdbSub(ctx: HostCtx, port: PortLike, msg: RtdbValueSubMessage): void {
|
|
148
|
+
ensurePortSubs(ctx, port);
|
|
149
|
+
const portSubs = ctx.subs.get(port)!;
|
|
150
|
+
if (portSubs.has(msg.subId)) return;
|
|
151
|
+
|
|
152
|
+
if (!msg.actAs) {
|
|
153
|
+
ctx.resubscribePortSubs ??= (p) => resubscribeSessionSubs(ctx, p);
|
|
154
|
+
sessionSubsFor(ctx, port).set(msg.subId, msg);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const ref = rtdbRef(lensRtdb(ctx, msg.actAs, port), msg.target.path);
|
|
159
|
+
const unsub = rtdbOnValue(
|
|
160
|
+
ref as DatabaseReference,
|
|
161
|
+
(snap) => post(port, { t: 'snap', subId: msg.subId, value: rtdbSnapToWire(snap) }),
|
|
162
|
+
);
|
|
163
|
+
portSubs.set(msg.subId, unsub);
|
|
164
|
+
} catch (e) {
|
|
165
|
+
post(port, { t: 'snap', subId: msg.subId, value: { __error: serializeError(e) } });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Register the real sandbox listener for a resolved target; returns its unsub.
|
|
170
|
+
* Split out of handleSub so the throwing surface (resolveTarget + onSnapshot)
|
|
171
|
+
* is inside handleSub's try/catch. */
|
|
172
|
+
function registerListener(
|
|
173
|
+
_ctx: HostCtx,
|
|
174
|
+
port: PortLike,
|
|
175
|
+
msg: FirestoreSubMessage,
|
|
176
|
+
target: DocumentReference | CollectionReference | Query,
|
|
177
|
+
): () => void {
|
|
178
|
+
return onSnapshot(
|
|
179
|
+
target as DocumentReference | Query,
|
|
180
|
+
(snap) => {
|
|
181
|
+
// Detect doc vs query snapshot by shape.
|
|
182
|
+
const snapAny = snap as {
|
|
183
|
+
id?: string;
|
|
184
|
+
path?: string;
|
|
185
|
+
exists?: boolean | (() => boolean);
|
|
186
|
+
data?: () => Record<string, unknown> | undefined;
|
|
187
|
+
docs?: Array<{
|
|
188
|
+
id: string;
|
|
189
|
+
path?: string;
|
|
190
|
+
exists: boolean | (() => boolean);
|
|
191
|
+
data(): Record<string, unknown>;
|
|
192
|
+
}>;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
if (Array.isArray(snapAny.docs)) {
|
|
196
|
+
// Query snapshot
|
|
197
|
+
const docs = snapAny.docs.map((d) =>
|
|
198
|
+
serializeDocSnap(d as Parameters<typeof serializeDocSnap>[0]),
|
|
199
|
+
);
|
|
200
|
+
post(port, { t: 'snap', subId: msg.subId, value: { docs } });
|
|
201
|
+
} else if (snapAny.id !== undefined) {
|
|
202
|
+
// Doc snapshot
|
|
203
|
+
post(port, {
|
|
204
|
+
t: 'snap',
|
|
205
|
+
subId: msg.subId,
|
|
206
|
+
value: serializeDocSnap(snapAny as Parameters<typeof serializeDocSnap>[0]),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
(err) => {
|
|
211
|
+
// Snapshot listener error (e.g. rules changed to deny).
|
|
212
|
+
// We forward as a snap with an __error field so the client can
|
|
213
|
+
// surface it to the original onSnapshot error callback.
|
|
214
|
+
post(port, { t: 'snap', subId: msg.subId, value: { __error: serializeError(err) } });
|
|
215
|
+
},
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function handleUnsub(ctx: HostCtx, port: PortLike, msg: UnsubMessage): void {
|
|
220
|
+
// Drop the session-bound record first — even when the live listener never
|
|
221
|
+
// registered (it errored at sub time), the record must not resurrect the
|
|
222
|
+
// sub on a later session change.
|
|
223
|
+
_sessionSubs.get(ctx)?.get(port)?.delete(msg.subId);
|
|
224
|
+
const portSubs = ctx.subs.get(port);
|
|
225
|
+
if (!portSubs) return;
|
|
226
|
+
const unsub = portSubs.get(msg.subId);
|
|
227
|
+
if (!unsub) return;
|
|
228
|
+
unsub();
|
|
229
|
+
portSubs.delete(msg.subId);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ─── Internal helpers ─────────────────────────────────────────────────────
|
|
233
|
+
|
|
234
|
+
function ensurePortSubs(ctx: HostCtx, port: PortLike): void {
|
|
235
|
+
if (!ctx.subs.has(port)) {
|
|
236
|
+
ctx.subs.set(port, new Map());
|
|
237
|
+
}
|
|
238
|
+
}
|