@pyric/cli 0.1.0-alpha.10 → 0.1.0-alpha.11
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 +1 -1
- 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 +2 -2
- 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 +800 -575
- 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-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 +123 -92
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +49 -20
- 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-firestore-values-reference-api/index.html +3 -2
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +1 -2
- 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 +374 -910
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +377 -911
- 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 +1 -0
- 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 +33 -8
- 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/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 +1 -1
- package/dist/serve/worker/index.d.ts.map +1 -1
- package/dist/serve/worker/index.js +2 -0
- 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.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 +8 -4
- 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,20 @@
|
|
|
1
|
+
import{s as f,a as o,b as d,d as s,G as h,c as n,e as w,f as A,u as m,r as p,T as g}from"./index-cpSfgQ7H.js";async function y(a){n.createUser(a,{uid:"alice",email:"alice@gmail.com",displayName:"Alice Nguyen",emailVerified:!0,photoUrl:"https://lh3.googleusercontent.com/a/alice",providerUserInfo:[{providerId:"google.com"}],customClaims:{plan:"pro"}}),n.createUser(a,{uid:"bob",email:"bob@example.com",password:"pyric-demo",displayName:"Bob Carter",emailVerified:!0,customClaims:{role:"editor"}}),n.createUser(a,{uid:"carol",email:"carol@example.com",displayName:"Carol Diaz",emailVerified:!1}),await w(a),await A(a)}const b=new h(37.7749,-122.4194);async function C(a){const r=Date.now(),i=e=>g.fromMillis(r-e*6e4),l=[{id:"alice",name:"Alice Nguyen",email:"alice@gmail.com",plan:"pro"},{id:"bob",name:"Bob Carter",email:"bob@example.com",plan:"free"},{id:"carol",name:"Carol Diaz",email:"carol@example.com",plan:"free"}];for(const e of l)await o(s(a,"users",e.id),{name:e.name,email:e.email,plan:e.plan,createdAt:d()});const t=["alice","bob","carol"],c=["Ship the redesign","Reply to carol","Buy milk","Draft the launch post","Review the rules","Plan offsite","Renew the domain","Read the spec","Fix the flaky test","Call the bank","Water the plants","Book the flights"];for(let e=0;e<c.length;e++){const u=t[e%t.length];await o(s(a,"notes",`note-${String(e+1).padStart(2,"0")}`),{title:c[e],done:e%3===0,pinned:e===0,priority:e%3+1,ownerId:u,ownerRef:`users/${u}`,tags:e%2===0?["work","urgent"]:["personal"],meta:{source:e%2===0?"app":"import",revision:e+1,flags:{starred:e%4===0,archived:!1}},location:e%3===0?b:null,createdAt:i(120-e*7),updatedAt:d()})}await o(s(a,"posts","post-hello"),{title:"Hello world",body:"First post from the seeded sandbox.",authorRef:"users/alice",published:!0,publishedAt:i(8)}),await o(s(a,"posts","post-draft"),{title:"Draft: roadmap",body:"Unpublished draft.",authorRef:"users/bob",published:!1})}async function R(a){const r=new TextEncoder,l=Uint8Array.from(atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="),t=>t.charCodeAt(0));await m(p(a,"avatars/alice.png"),l,{contentType:"image/png"}),await m(p(a,"notes/note-01/attachment.txt"),r.encode(`Attachment for the redesign note.
|
|
2
|
+
`),{contentType:"text/plain"})}const x=`rules_version = '2';
|
|
3
|
+
service cloud.firestore {
|
|
4
|
+
match /databases/{database}/documents {
|
|
5
|
+
match /users/{userId} {
|
|
6
|
+
allow read: if request.auth != null;
|
|
7
|
+
allow write: if request.auth != null && request.auth.uid == userId;
|
|
8
|
+
}
|
|
9
|
+
match /notes/{noteId} {
|
|
10
|
+
allow read: if request.auth != null;
|
|
11
|
+
allow create: if request.auth != null && request.resource.data.ownerId == request.auth.uid;
|
|
12
|
+
allow update, delete: if request.auth != null && resource.data.ownerId == request.auth.uid;
|
|
13
|
+
}
|
|
14
|
+
match /posts/{postId} {
|
|
15
|
+
allow read: if true;
|
|
16
|
+
allow write: if request.auth != null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`;function U(a){f(a,x)}async function q(a){await C(a.adminFirestore),await y(a.auth),await R(a.storage)}export{q as applySeed,U as deploySeedRules,y as seedAuth};
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
|
|
24
24
|
rel="stylesheet"
|
|
25
25
|
/>
|
|
26
|
-
<script type="module" crossorigin src="/__pyric/ui/assets/index-
|
|
26
|
+
<script type="module" crossorigin src="/__pyric/ui/assets/index-cpSfgQ7H.js"></script>
|
|
27
27
|
<link rel="stylesheet" crossorigin href="/__pyric/ui/assets/index-BlSGru_r.css">
|
|
28
28
|
</head>
|
|
29
29
|
<body>
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
|
-
|
|
2
|
+
import type { AiEngineConfigWire } from './worker/protocol.js';
|
|
3
|
+
import type { AIOptions } from 'pyric/ai';
|
|
4
|
+
/**
|
|
5
|
+
* The plugin-level engine config surface = `pyric/ai`'s `EngineConfig` (what an
|
|
6
|
+
* app passes to `getAI`), minus the custom `AnswerEngine` object variant — a
|
|
7
|
+
* live object cannot cross to the SharedWorker host or serialize into the page,
|
|
8
|
+
* so the plugin's declarative surface is the JSON-able `scripted` / `openai`
|
|
9
|
+
* configs only (the same restriction the worker path already enforces).
|
|
10
|
+
*/
|
|
11
|
+
export type PyricAiEngineConfig = Extract<NonNullable<AIOptions['engine']>, {
|
|
12
|
+
kind: string;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Node-side `EngineConfig` → JSON-safe {@link AiEngineConfigWire}. Mirrors the
|
|
16
|
+
* browser `toEngineWire` (entries/ai.ts): an openai config with no `baseUrl`
|
|
17
|
+
* targets the same-origin proxy; scripted `script` entries pass through (plain
|
|
18
|
+
* authoring shapes — function/RegExp matchers can't survive JSON and are not a
|
|
19
|
+
* plugin-config use case).
|
|
20
|
+
*/
|
|
21
|
+
export declare function engineConfigToWire(engine: PyricAiEngineConfig): AiEngineConfigWire;
|
|
22
|
+
export interface PyricOptions {
|
|
3
23
|
/** firestore.rules path (relative to `root`). Default: `firebase.json`'s
|
|
4
24
|
* `firestore.rules`, else `firestore.rules` in the project root. */
|
|
5
25
|
rules?: string;
|
|
@@ -21,10 +41,10 @@ export interface PyricSandboxOptions {
|
|
|
21
41
|
* + `GET /__pyric/health` + `WS /__pyric/sandbox`, all on Vite's port.
|
|
22
42
|
* `true` is shorthand for `{}`. The agent and the page share ONE sandbox.
|
|
23
43
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
44
|
+
* Does NOT change the sandbox topology: on the default SharedWorker path the
|
|
45
|
+
* page dials the bridge WS and relays agent tool-calls THROUGH the worker
|
|
46
|
+
* (`connectBridgePeer`), so multi-tab stays on. The in-page fallback engages
|
|
47
|
+
* only when the worker bundle itself fails, bridge or not. */
|
|
28
48
|
bridge?: boolean | {
|
|
29
49
|
project?: string;
|
|
30
50
|
disableAuditLog?: boolean;
|
|
@@ -32,26 +52,83 @@ export interface PyricSandboxOptions {
|
|
|
32
52
|
/** Serve the **Pyric Studio** app at `/__pyric/ui/` on Vite's dev origin (the
|
|
33
53
|
* `pyric dev --ui` equivalent). Mounts the disk-backed workspace/project
|
|
34
54
|
* routes Studio's `local` mode talks to AND serves the built Studio assets
|
|
35
|
-
* (vendored in this package at `dist/serve/studio-ui`). **On by default
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* live plane reads the SharedWorker, so Studio would observe nothing. Under
|
|
40
|
-
* `bridge` ui therefore defaults OFF (an explicit `ui: true` still works but
|
|
41
|
-
* warns). Use `ui` without `bridge`, or `pyric dev --ui`. */
|
|
55
|
+
* (vendored in this package at `dist/serve/studio-ui`). **On by default**,
|
|
56
|
+
* including under `bridge` (the bridge peer routes through the SharedWorker,
|
|
57
|
+
* so app, Studio, and agent all observe the one sandbox); pass `ui: false`
|
|
58
|
+
* to disable. */
|
|
42
59
|
ui?: boolean;
|
|
60
|
+
/** RTDB-triggered Cloud Functions under this dev server (the `pyric dev`
|
|
61
|
+
* parity fold). By default a `functions` block in `firebase.json` is
|
|
62
|
+
* discovered automatically: its `onValueCreated` triggers run in an isolated
|
|
63
|
+
* node child against the shared sandbox (other trigger kinds warn and are
|
|
64
|
+
* skipped), and the discovered codebase turns the MCP bridge mount on (the
|
|
65
|
+
* child dials the sandbox over the bridge WS — the page's sandbox topology
|
|
66
|
+
* is unchanged, see `bridge`). `functions: false` is the off switch: no
|
|
67
|
+
* discovery, no child, no functions-forced bridge mount.
|
|
68
|
+
*
|
|
69
|
+
* Field precedence: explicit option > env var > firebase files > default.
|
|
70
|
+
* - `region`: the trigger location. Beats `PYRIC_FUNCTIONS_RTDB_REGION`;
|
|
71
|
+
* default `us-central1`.
|
|
72
|
+
* - `instance`: the RTDB instance name. Default `<projectId>-default-rtdb`,
|
|
73
|
+
* where projectId is `PYRIC_PROJECT`, else `.firebaserc`'s default
|
|
74
|
+
* project, else `demo-project`.
|
|
75
|
+
* - `watch`: hot-reload the functions source (default `true`, matching
|
|
76
|
+
* rules). A save under the functions source dir stops the child and
|
|
77
|
+
* respawns it — redeploy semantics: in-flight executions in the old child
|
|
78
|
+
* may drop, and writes landing during the swap gap are consumed as the new
|
|
79
|
+
* child's baseline (they do not fire). Unlike rules, a broken save cannot
|
|
80
|
+
* keep last-good live — the old child is already gone — so functions stay
|
|
81
|
+
* down until the next good save. */
|
|
82
|
+
functions?: false | {
|
|
83
|
+
region?: string;
|
|
84
|
+
instance?: string;
|
|
85
|
+
watch?: boolean;
|
|
86
|
+
};
|
|
43
87
|
/** Force whether `vite build` runs the firebase→pyric swap, overriding the
|
|
44
88
|
* mode default. Unset (default): swap for any NON-production mode, keep real
|
|
45
89
|
* firebase for mode `production`. `true` = always produce a sandbox build;
|
|
46
90
|
* `false` = never swap in build (real firebase regardless of mode). `vite
|
|
47
91
|
* dev` is unaffected — the swap is always on there. */
|
|
48
92
|
swapInBuild?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Dev-server-level AI configuration for `pyric/ai` (the sanctioned
|
|
95
|
+
* replacement for threading `engine` through every app `getAI(...)` call,
|
|
96
|
+
* which is first-call-wins and easy to get wrong).
|
|
97
|
+
*
|
|
98
|
+
* pyric({
|
|
99
|
+
* ai: {
|
|
100
|
+
* engine: { kind: 'openai', model: 'llama3.2', baseUrl: '/__pyric/ai-proxy' },
|
|
101
|
+
* proxyUpstream: 'http://localhost:11434/v1', // your Ollama
|
|
102
|
+
* },
|
|
103
|
+
* })
|
|
104
|
+
*
|
|
105
|
+
* - `engine` is `pyric/ai`'s `EngineConfig` (scripted | openai), applied on
|
|
106
|
+
* both the SharedWorker and in-page paths. An openai `baseUrl` of
|
|
107
|
+
* `/__pyric/ai-proxy` (or omitted) routes through the same-origin proxy so a
|
|
108
|
+
* localhost upstream needs zero CORS setup.
|
|
109
|
+
* - `proxyUpstream` sets what `/__pyric/ai-proxy` forwards to (beats the
|
|
110
|
+
* `PYRIC_AI_PROXY_UPSTREAM` env var; default `http://localhost:11434/v1`).
|
|
111
|
+
*
|
|
112
|
+
* Precedence: a plugin-level `engine`, when set, always wins over an engine an
|
|
113
|
+
* app's own `getAI()` passes (host-side via `ctx.aiEngine` on the worker path,
|
|
114
|
+
* page-side via an injected global on the in-page fallback); with no plugin
|
|
115
|
+
* engine the first `getAI()` call's engine is honored (first-call-wins), and
|
|
116
|
+
* with neither the zero-config scripted default applies.
|
|
117
|
+
*/
|
|
118
|
+
ai?: {
|
|
119
|
+
/** Engine config (scripted | openai). Custom `AnswerEngine` objects are not
|
|
120
|
+
* supported at the plugin level — they can't cross to the worker/page. */
|
|
121
|
+
engine?: PyricAiEngineConfig;
|
|
122
|
+
/** OpenAI-compatible upstream `/__pyric/ai-proxy` forwards to. Beats
|
|
123
|
+
* `PYRIC_AI_PROXY_UPSTREAM`; default `http://localhost:11434/v1`. */
|
|
124
|
+
proxyUpstream?: string;
|
|
125
|
+
};
|
|
49
126
|
}
|
|
50
127
|
/**
|
|
51
128
|
* The dev-only Vite plugin. Add to `vite.config`:
|
|
52
129
|
*
|
|
53
|
-
* import {
|
|
54
|
-
* export default defineConfig({ plugins: [
|
|
130
|
+
* import { pyric } from '@pyric/cli/vite';
|
|
131
|
+
* export default defineConfig({ plugins: [pyric()] });
|
|
55
132
|
*/
|
|
56
|
-
export declare function
|
|
133
|
+
export declare function pyric(options?: PyricOptions): Plugin;
|
|
57
134
|
//# sourceMappingURL=vite-plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["../../src/serve/vite-plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["../../src/serve/vite-plugin.ts"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAAE,MAAM,EAAyB,MAAM,MAAM,CAAC;AAkB1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAiD1C;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9F;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,kBAAkB,CAelF;AAeD,MAAM,WAAW,YAAY;IAC3B;yEACqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;gEAC4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;qEACiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;iFAC6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;mEAQ+D;IAC/D,MAAM,CAAC,EAAE,OAAO,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACnE;;;;;;sBAMkB;IAClB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb;;;;;;;;;;;;;;;;;;;;;2CAqBuC;IACvC,SAAS,CAAC,EAAE,KAAK,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5E;;;;4DAIwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,EAAE,CAAC,EAAE;QACH;mFAC2E;QAC3E,MAAM,CAAC,EAAE,mBAAmB,CAAC;QAC7B;8EACsE;QACtE,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,MAAM,CAo0BxD"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* mode) produces a SANDBOX build that bundles pyric's in-page adapters instead
|
|
15
15
|
* of the real SDK: self-contained, meant to be previewed under `pyric dev`, and
|
|
16
16
|
* stamped with the sandbox-build marker so it can never be deployed (`pyric
|
|
17
|
-
* deploy hosting` refuses it). `
|
|
17
|
+
* deploy hosting` refuses it). `pyric({ swapInBuild })` forces the build
|
|
18
18
|
* behavior on/off regardless of mode. See `sandbox-marker.ts`.
|
|
19
19
|
*
|
|
20
20
|
* This is a thin adapter over serve's proven machinery. It REUSES, not reimplements:
|
|
@@ -30,8 +30,9 @@
|
|
|
30
30
|
* Scope = M1 (swap + rules) + M2 (SharedWorker multi-tab + persist/capture/seed)
|
|
31
31
|
* + M3 (the MCP bridge fold — `{ bridge }`). M3 reuses `createBridgeMount` (the
|
|
32
32
|
* proven serve-flavored bridge behind `pyric dev --bridge`), composing it into
|
|
33
|
-
* the same `/__pyric` middleware;
|
|
34
|
-
*
|
|
33
|
+
* the same `/__pyric` middleware; on the worker path the bridge peer routes
|
|
34
|
+
* agent tool-calls THROUGH the SharedWorker (`connectBridgePeer`), so the agent
|
|
35
|
+
* and the app share one backend without forcing the page in-page.
|
|
35
36
|
*
|
|
36
37
|
* Serving `worker.js` flips `runtime.ts` to the worker path (one backend across
|
|
37
38
|
* tabs, IndexedDB-durable); on that path the WORKER owns persist/capture/seed via
|
|
@@ -43,7 +44,8 @@ import { existsSync, readFileSync, rmSync, writeFileSync, mkdirSync } from 'node
|
|
|
43
44
|
import { homedir } from 'node:os';
|
|
44
45
|
import path from 'node:path';
|
|
45
46
|
import { SDK_MODULES, defaultSdkEntries, resolveStudioUiDir, pyricPackageRoot, bundleWorker, workerSourceHash, NODE_BUILTIN_RE, NODE_BUILTIN_SHIMS, } from './bundler.js';
|
|
46
|
-
import { createEventHub, createPyricNamespace } from './namespace.js';
|
|
47
|
+
import { createEventHub, createPyricNamespace, } from './namespace.js';
|
|
48
|
+
import { formatActivityWarning } from './activity-warning.js';
|
|
47
49
|
import { diskWorkspace, diskProjectStore } from './studio/index.js';
|
|
48
50
|
import { createBridgeMount } from './bridge-mount.js';
|
|
49
51
|
import { loadProjectDatabaseRules, loadProjectRules, loadProjectStorageRules, prepareRulesSource, rulesHashOf, } from './rules.js';
|
|
@@ -51,7 +53,10 @@ import { createStateStore, STATE_FILE_VERSION } from './state-store.js';
|
|
|
51
53
|
import { createCaptureStore } from './capture-store.js';
|
|
52
54
|
import { isAllowedHost } from './server.js';
|
|
53
55
|
import { SANDBOX_BUILD_META } from './sandbox-marker.js';
|
|
54
|
-
import { readFirebaseJson } from '../cli/firebase-json.js';
|
|
56
|
+
import { readFirebaseJson, readFirebaseRc } from '../cli/firebase-json.js';
|
|
57
|
+
import { discoverFunctionsRtdbProject, } from '../functions-rtdb/project.js';
|
|
58
|
+
import { spawnFunctionsRtdbChild, } from '../functions-rtdb/child.js';
|
|
59
|
+
import { buildChildEnv, createLinePrefixer, registerModuleUrl, } from '../cli/dev-runner.js';
|
|
55
60
|
/**
|
|
56
61
|
* Whether a `vite build` should run the firebase→pyric swap (produce a SANDBOX
|
|
57
62
|
* build). MODE-based with a plugin-config override:
|
|
@@ -68,6 +73,31 @@ function swapsInBuild(env, swapInBuild) {
|
|
|
68
73
|
}
|
|
69
74
|
/** Any `firebase/<sub>` specifier. */
|
|
70
75
|
const FB_ANY = /^firebase\/([a-z-]+(?:\/[a-z-]+)*)$/;
|
|
76
|
+
/** The serve proxy route the browser openai engine defaults to (#98.2). */
|
|
77
|
+
const AI_PROXY_PATH = '/__pyric/ai-proxy';
|
|
78
|
+
/**
|
|
79
|
+
* Node-side `EngineConfig` → JSON-safe {@link AiEngineConfigWire}. Mirrors the
|
|
80
|
+
* browser `toEngineWire` (entries/ai.ts): an openai config with no `baseUrl`
|
|
81
|
+
* targets the same-origin proxy; scripted `script` entries pass through (plain
|
|
82
|
+
* authoring shapes — function/RegExp matchers can't survive JSON and are not a
|
|
83
|
+
* plugin-config use case).
|
|
84
|
+
*/
|
|
85
|
+
export function engineConfigToWire(engine) {
|
|
86
|
+
if (engine.kind === 'openai') {
|
|
87
|
+
return {
|
|
88
|
+
kind: 'openai',
|
|
89
|
+
baseUrl: engine.baseUrl ?? AI_PROXY_PATH,
|
|
90
|
+
...(engine.model !== undefined ? { model: engine.model } : {}),
|
|
91
|
+
...(engine.modelMap !== undefined ? { modelMap: engine.modelMap } : {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
kind: 'scripted',
|
|
96
|
+
...(engine.script !== undefined
|
|
97
|
+
? { script: engine.script }
|
|
98
|
+
: {}),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
71
101
|
/** The firebase subpaths with swap entries. */
|
|
72
102
|
const SERVED = new Set(SDK_MODULES.map((specifier) => specifier.slice('firebase/'.length)));
|
|
73
103
|
const entryKey = (subpath) => subpath.replaceAll('/', '-');
|
|
@@ -83,10 +113,10 @@ function packageRootOf(file) {
|
|
|
83
113
|
/**
|
|
84
114
|
* The dev-only Vite plugin. Add to `vite.config`:
|
|
85
115
|
*
|
|
86
|
-
* import {
|
|
87
|
-
* export default defineConfig({ plugins: [
|
|
116
|
+
* import { pyric } from '@pyric/cli/vite';
|
|
117
|
+
* export default defineConfig({ plugins: [pyric()] });
|
|
88
118
|
*/
|
|
89
|
-
export function
|
|
119
|
+
export function pyric(options = {}) {
|
|
90
120
|
// Resolved once. `defaultSdkEntries()` prefers compiled dist `.js` and falls
|
|
91
121
|
// back to source `.ts` in the workspace.
|
|
92
122
|
const entries = defaultSdkEntries(); // { app, auth, firestore, init } → abs paths
|
|
@@ -177,6 +207,11 @@ export function pyricSandbox(options = {}) {
|
|
|
177
207
|
// sandbox path — the bridge peer is the in-page sandbox, never the SharedWorker,
|
|
178
208
|
// so multi-tab is disabled under bridge to keep agent + app on one backend.
|
|
179
209
|
const bridgeOpts = options.bridge === true ? {} : options.bridge || null;
|
|
210
|
+
// Plugin-level AI engine, normalized once to the JSON-safe wire shape. Travels
|
|
211
|
+
// to the worker host via the init payload (→ ctx.aiEngine) AND to the in-page
|
|
212
|
+
// fallback via an injected synchronous global (see transformIndexHtml). Undefined
|
|
213
|
+
// when the `ai.engine` option is unset.
|
|
214
|
+
const aiEngineWire = options.ai?.engine ? engineConfigToWire(options.ai.engine) : undefined;
|
|
180
215
|
return {
|
|
181
216
|
name: 'pyric:sandbox',
|
|
182
217
|
// Active for `vite dev` ALWAYS, and for `vite build` only when it is a
|
|
@@ -352,6 +387,30 @@ export function pyricSandbox(options = {}) {
|
|
|
352
387
|
catch (e) {
|
|
353
388
|
server.config.logger.warn(` ⚠ [pyric] SharedWorker bundle failed — using the in-page sandbox (single-tab, ephemeral): ${e instanceof Error ? e.message : String(e)}`);
|
|
354
389
|
}
|
|
390
|
+
// ── Functions (RTDB triggers) — the `pyric dev` parity fold ───────────
|
|
391
|
+
// Discover the one supported Functions codebase from the same resolved
|
|
392
|
+
// firebase.json the rules used (project.ts reads it itself). Reuses the
|
|
393
|
+
// exact serve module, so absent `functions` → null (silently off) and a
|
|
394
|
+
// malformed config throws serve's own error text — which, thrown from an
|
|
395
|
+
// async configureServer, fails the dev start the same way serve's
|
|
396
|
+
// `return 2` aborts. The Functions child connects to the sandbox over the
|
|
397
|
+
// bridge WS, so a discovered codebase forces the bridge mount on (mirrors
|
|
398
|
+
// serve's `bridgeEnabledFor(..., functionsProject)`). `functions: false`
|
|
399
|
+
// is the off switch: discovery never runs, so neither does the mount.
|
|
400
|
+
const functionsOpts = typeof options.functions === 'object' ? options.functions : {};
|
|
401
|
+
let functionsProject = null;
|
|
402
|
+
if (options.functions !== false) {
|
|
403
|
+
try {
|
|
404
|
+
functionsProject = discoverFunctionsRtdbProject(cwd);
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
// Malformed functions config: fail the start with serve's exact message.
|
|
408
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const functionsProjectId = functionsProject
|
|
412
|
+
? (process.env.PYRIC_PROJECT ?? (await readFirebaseRc(cwd))?.projects?.default ?? 'demo-project')
|
|
413
|
+
: null;
|
|
355
414
|
// ── M3 MCP bridge (mirrors serve.ts:221–274) ─────────────────────────
|
|
356
415
|
// The mount is long-lived (one bridge per dev session); its MCP transport
|
|
357
416
|
// is rebuilt per request (stateless). Composed into the /__pyric middleware
|
|
@@ -360,9 +419,12 @@ export function pyricSandbox(options = {}) {
|
|
|
360
419
|
// Guard the WS upgrade with the SAME allow rule Vite's own host check
|
|
361
420
|
// uses (host + allowedHosts, where `true` = opted into all hosts). Vite's
|
|
362
421
|
// upgrade path bypasses connect middleware, so this is the only guard on it.
|
|
363
|
-
const mount = bridgeOpts
|
|
422
|
+
const mount = bridgeOpts || functionsProject
|
|
364
423
|
? createBridgeMount({
|
|
365
|
-
...bridgeOpts,
|
|
424
|
+
...(bridgeOpts ?? {}),
|
|
425
|
+
// A functions-only session still needs a labeled bridge; prefer an
|
|
426
|
+
// explicit bridge project, else the resolved functions project id.
|
|
427
|
+
project: bridgeOpts?.project ?? functionsProjectId ?? undefined,
|
|
366
428
|
upgradeGuard: {
|
|
367
429
|
boundHost: typeof server.config.server.host === 'string' ? server.config.server.host : 'localhost',
|
|
368
430
|
allowedHosts: server.config.server.allowedHosts === true
|
|
@@ -384,6 +446,9 @@ export function pyricSandbox(options = {}) {
|
|
|
384
446
|
databaseUrl: live.databaseUrl,
|
|
385
447
|
storageRules: live.storageRules,
|
|
386
448
|
storageRulesHash: live.storageRulesHash,
|
|
449
|
+
// Project identity: scopes the storage IDB name per served project
|
|
450
|
+
// (issue #359). Local-only — a dev path never leaves the machine.
|
|
451
|
+
projectKey: cwd,
|
|
387
452
|
// The bound port is known only after `listen`; initPayload runs per
|
|
388
453
|
// request (after listen), so resolve it lazily here. Absolute ws://host:port
|
|
389
454
|
// mirrors serve (the browser reads this as the bridge peer URL).
|
|
@@ -406,6 +471,9 @@ export function pyricSandbox(options = {}) {
|
|
|
406
471
|
: seedUsers,
|
|
407
472
|
// Messaging is part of the canonical firebase/* sandbox swap.
|
|
408
473
|
messaging: true,
|
|
474
|
+
// Plugin-level engine → the worker host's ctx.aiEngine (host-ai.ts),
|
|
475
|
+
// which wins over any op-carried engine. Null when unset.
|
|
476
|
+
ai: aiEngineWire ? { engine: aiEngineWire } : null,
|
|
409
477
|
});
|
|
410
478
|
// Pyric Studio: mount the disk-backed workspace/project routes that
|
|
411
479
|
// Studio's `local` mode talks to + serve the built Studio app at
|
|
@@ -435,10 +503,22 @@ export function pyricSandbox(options = {}) {
|
|
|
435
503
|
sdkDir,
|
|
436
504
|
initPayload,
|
|
437
505
|
events,
|
|
506
|
+
activity: (incident) => server.config.logger.warn(formatActivityWarning(incident)),
|
|
438
507
|
state,
|
|
439
508
|
capture,
|
|
440
509
|
studio,
|
|
441
510
|
studioUiDir,
|
|
511
|
+
// `ai.proxyUpstream`: what `/__pyric/ai-proxy` forwards to (beats the
|
|
512
|
+
// PYRIC_AI_PROXY_UPSTREAM env var; falls back to the default when unset).
|
|
513
|
+
aiProxyUpstream: options.ai?.proxyUpstream,
|
|
514
|
+
// Adapt Vite's logger to the plain info/note shape the namespace's
|
|
515
|
+
// diagnostics (denial relay, future hot-reload lines) expect —
|
|
516
|
+
// matches the `↻`/`⚠ [pyric]` lines already logged elsewhere in this
|
|
517
|
+
// plugin via `server.config.logger` directly.
|
|
518
|
+
logger: {
|
|
519
|
+
info: (m) => server.config.logger.info(m),
|
|
520
|
+
note: (m) => server.config.logger.warn(m),
|
|
521
|
+
},
|
|
442
522
|
});
|
|
443
523
|
// DNS-rebinding guard for the /__pyric/* surface. Vite has its own host
|
|
444
524
|
// check, but a `configureServer` hook that doesn't return a function mounts
|
|
@@ -565,6 +645,187 @@ export function pyricSandbox(options = {}) {
|
|
|
565
645
|
}
|
|
566
646
|
});
|
|
567
647
|
}
|
|
648
|
+
// ── Functions child lifecycle (mirrors serve's runServe) ─────────────
|
|
649
|
+
// The Functions runtime executes in an isolated node child (child.ts),
|
|
650
|
+
// exactly as `pyric dev` runs it: the child loads the user's unchanged
|
|
651
|
+
// functions module, and `--import @pyric/cli/register` + `PYRIC_SANDBOX=
|
|
652
|
+
// remote:<serveUrl>` route its `firebase-admin/app` to a RemoteSandbox that
|
|
653
|
+
// dials the bridge WS (`/__pyric/sandbox`). onValueCreated triggers observe
|
|
654
|
+
// RTDB writes and write their effects back through that one shared sandbox.
|
|
655
|
+
// Started once a sandbox peer (a browser tab / SharedWorker relay) has
|
|
656
|
+
// connected — the trigger's baseline needs a live backend — and stopped on
|
|
657
|
+
// server close. Vite restarts re-run configureServer, so the child respawns
|
|
658
|
+
// with the new server. Unlike `pyric dev` (which does not watch functions
|
|
659
|
+
// source), the plugin hot-reloads it via Vite's own watcher — see the
|
|
660
|
+
// watch block below; `functions: { watch: false }` restores dev's
|
|
661
|
+
// restart-to-reload behavior.
|
|
662
|
+
if (functionsProject && functionsProjectId && mount && server.httpServer) {
|
|
663
|
+
const httpServer = server.httpServer;
|
|
664
|
+
const project = functionsProject;
|
|
665
|
+
const projectId = functionsProjectId;
|
|
666
|
+
const bridgeMount = mount;
|
|
667
|
+
const host = (typeof server.config.server.host === 'string' && server.config.server.host) || 'localhost';
|
|
668
|
+
// Prefer the compiled child (node cannot execute the .ts source when the
|
|
669
|
+
// plugin runs from source in tests); fall back to spawnFunctionsRtdbChild's
|
|
670
|
+
// own default (correct when the plugin runs from dist in production).
|
|
671
|
+
const builtChild = path.join(cliRoot, 'dist/functions-rtdb/child.js');
|
|
672
|
+
const childModuleUrl = existsSync(builtChild) ? builtChild : undefined;
|
|
673
|
+
let functionsChild = null;
|
|
674
|
+
let disposed = false;
|
|
675
|
+
const start = async (mode = 'initial') => {
|
|
676
|
+
const addr = httpServer.address();
|
|
677
|
+
const port = addr && typeof addr === 'object' ? addr.port : 0;
|
|
678
|
+
if (!port || disposed)
|
|
679
|
+
return;
|
|
680
|
+
const serveUrl = `http://${host}:${port}`;
|
|
681
|
+
// Wait (bounded) for a sandbox peer — the SharedWorker relay / browser
|
|
682
|
+
// tab that holds the backend. Poll the mount directly (no self-fetch).
|
|
683
|
+
// On a hot reload the peer is usually still connected (the loop exits
|
|
684
|
+
// immediately); when it dropped mid-session, wait briefly rather than
|
|
685
|
+
// the full initial 30s.
|
|
686
|
+
const deadline = Date.now() + (mode === 'reload' ? 5_000 : 30_000);
|
|
687
|
+
while (!disposed && !bridgeMount.sandboxConnected()) {
|
|
688
|
+
if (Date.now() >= deadline)
|
|
689
|
+
break;
|
|
690
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
691
|
+
}
|
|
692
|
+
if (disposed)
|
|
693
|
+
return;
|
|
694
|
+
if (!bridgeMount.sandboxConnected()) {
|
|
695
|
+
server.config.logger.warn(mode === 'reload'
|
|
696
|
+
? ` ✖ [pyric] functions not restarted — no sandbox peer connected. ` +
|
|
697
|
+
`Functions stay down until the next save with ${serveUrl} open.`
|
|
698
|
+
: ` ⚠ [pyric] functions not started — no browser tab connected after 30s. ` +
|
|
699
|
+
`Open ${serveUrl} and restart the dev server.`);
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
functionsChild = spawnFunctionsRtdbChild({
|
|
703
|
+
cwd: project.sourceDir,
|
|
704
|
+
entry: project.entry,
|
|
705
|
+
env: buildChildEnv(process.env, { serveUrl, registerUrl: registerModuleUrl() }),
|
|
706
|
+
// Precedence (per field): plugin option > env var > firebase files
|
|
707
|
+
// > default. projectId already folds PYRIC_PROJECT > .firebaserc >
|
|
708
|
+
// demo-project.
|
|
709
|
+
instance: functionsOpts.instance ?? `${projectId}-default-rtdb`,
|
|
710
|
+
location: functionsOpts.region ?? process.env.PYRIC_FUNCTIONS_RTDB_REGION ?? 'us-central1',
|
|
711
|
+
...(childModuleUrl ? { childModuleUrl } : {}),
|
|
712
|
+
onEvent(event) {
|
|
713
|
+
if (event.type === 'execution') {
|
|
714
|
+
const params = Object.entries(event.params)
|
|
715
|
+
.map(([name, value]) => `${name}=${value}`)
|
|
716
|
+
.join(', ');
|
|
717
|
+
const suffix = params ? ` (${params})` : '';
|
|
718
|
+
if (event.status === 'fulfilled') {
|
|
719
|
+
server.config.logger.info(` ✔ [pyric] function ${event.exportName} ← /${event.ref}${suffix}`);
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
server.config.logger.error(` ✖ [pyric] function ${event.exportName} ← /${event.ref}${suffix}: ${event.error.message}`);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
server.config.logger.error(` ✖ [pyric] functions delivery for ${event.exportName}: ${event.error.message}`);
|
|
727
|
+
}
|
|
728
|
+
},
|
|
729
|
+
});
|
|
730
|
+
const out = createLinePrefixer('[functions] ', (line) => server.config.logger.info(line.replace(/\n$/, '')));
|
|
731
|
+
const err = createLinePrefixer('[functions] ', (line) => server.config.logger.warn(line.replace(/\n$/, '')));
|
|
732
|
+
functionsChild.child.stdout?.setEncoding('utf8');
|
|
733
|
+
functionsChild.child.stderr?.setEncoding('utf8');
|
|
734
|
+
functionsChild.child.stdout?.on('data', (chunk) => out.push(chunk));
|
|
735
|
+
functionsChild.child.stderr?.on('data', (chunk) => err.push(chunk));
|
|
736
|
+
functionsChild.child.stdout?.once('end', () => out.flush());
|
|
737
|
+
functionsChild.child.stderr?.once('end', () => err.flush());
|
|
738
|
+
try {
|
|
739
|
+
const ready = await functionsChild.ready;
|
|
740
|
+
server.config.logger.info(mode === 'reload'
|
|
741
|
+
? ` ↻ [pyric] functions reloaded (${ready.triggerCount} trigger${ready.triggerCount === 1 ? '' : 's'})`
|
|
742
|
+
: ` ✔ [pyric] functions ${ready.triggerCount} onValueCreated ` +
|
|
743
|
+
`trigger${ready.triggerCount === 1 ? '' : 's'} from ${path.relative(cwd, project.entry)}`);
|
|
744
|
+
for (const unsupported of ready.unsupportedTriggers) {
|
|
745
|
+
server.config.logger.warn(` ⚠ [pyric] functions export ${unsupported.exportName} uses unsupported trigger ` +
|
|
746
|
+
`${unsupported.eventType}; it will not run.`);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
catch (error) {
|
|
750
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
751
|
+
server.config.logger.error(mode === 'reload'
|
|
752
|
+
? // Unlike rules, last-good cannot stay live — the old child is
|
|
753
|
+
// already stopped — so a broken save takes functions down.
|
|
754
|
+
` ✖ [pyric] functions failed to reload: ${message}\n` +
|
|
755
|
+
` ✖ [pyric] functions are down until the next good save.`
|
|
756
|
+
: ` ✖ [pyric] functions failed to start: ${message}`);
|
|
757
|
+
await functionsChild.stop().catch(() => undefined);
|
|
758
|
+
functionsChild = null;
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
let reloadDebounce = null;
|
|
762
|
+
httpServer.once('close', () => {
|
|
763
|
+
disposed = true;
|
|
764
|
+
if (reloadDebounce)
|
|
765
|
+
clearTimeout(reloadDebounce);
|
|
766
|
+
void functionsChild?.stop().catch(() => undefined);
|
|
767
|
+
});
|
|
768
|
+
if (httpServer.listening)
|
|
769
|
+
void start();
|
|
770
|
+
else
|
|
771
|
+
httpServer.once('listening', () => void start());
|
|
772
|
+
// Functions hot-reload from Vite's OWN watcher (mirrors the rules block
|
|
773
|
+
// below). Restart = redeploy: stop the old child, respawn via the same
|
|
774
|
+
// start path — there is no in-place swap, so in-flight executions in the
|
|
775
|
+
// old child may drop and writes landing in the swap gap become the new
|
|
776
|
+
// child's baseline (execution.ts consumes each trigger's first observed
|
|
777
|
+
// value as baseline; they do not fire). Debounced 300ms — a save fans
|
|
778
|
+
// out several fs events and a child respawn is far heavier than a rules
|
|
779
|
+
// re-parse. Restarts are serialized: a save landing mid-restart queues
|
|
780
|
+
// exactly one follow-up run.
|
|
781
|
+
if (functionsOpts.watch !== false) {
|
|
782
|
+
const sourceDir = project.sourceDir;
|
|
783
|
+
// Usually redundant (Vite watches its root, which contains the
|
|
784
|
+
// functions dir in the common layout) but load-bearing when the
|
|
785
|
+
// functions source lives outside Vite's root. node_modules stays
|
|
786
|
+
// ignored: Vite's watcher ignores `**/node_modules/**` globally, and
|
|
787
|
+
// the handler below filters it again for explicitly-added trees.
|
|
788
|
+
server.watcher.add(sourceDir);
|
|
789
|
+
let restarting = false;
|
|
790
|
+
let queued = false;
|
|
791
|
+
const restart = async () => {
|
|
792
|
+
if (restarting) {
|
|
793
|
+
queued = true;
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
restarting = true;
|
|
797
|
+
try {
|
|
798
|
+
do {
|
|
799
|
+
queued = false;
|
|
800
|
+
if (disposed)
|
|
801
|
+
return;
|
|
802
|
+
const old = functionsChild;
|
|
803
|
+
functionsChild = null;
|
|
804
|
+
if (old)
|
|
805
|
+
await old.stop().catch(() => undefined);
|
|
806
|
+
await start('reload');
|
|
807
|
+
} while (queued && !disposed);
|
|
808
|
+
}
|
|
809
|
+
finally {
|
|
810
|
+
restarting = false;
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
const onFunctionsFsEvent = (file) => {
|
|
814
|
+
const resolved = path.resolve(file);
|
|
815
|
+
const rel = path.relative(sourceDir, resolved);
|
|
816
|
+
if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel))
|
|
817
|
+
return;
|
|
818
|
+
if (rel.split(path.sep).includes('node_modules'))
|
|
819
|
+
return;
|
|
820
|
+
if (reloadDebounce)
|
|
821
|
+
clearTimeout(reloadDebounce);
|
|
822
|
+
reloadDebounce = setTimeout(() => void restart(), 300);
|
|
823
|
+
};
|
|
824
|
+
server.watcher.on('change', onFunctionsFsEvent);
|
|
825
|
+
server.watcher.on('add', onFunctionsFsEvent);
|
|
826
|
+
server.watcher.on('unlink', onFunctionsFsEvent);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
568
829
|
// Rules hot-reload from Vite's OWN watcher (no second fs watcher). Reuse
|
|
569
830
|
// prepareRulesSource (resolve + lint); last-good stays live on a broken save.
|
|
570
831
|
// Debounced (editors emit several change events per save) — matches
|
|
@@ -653,10 +914,19 @@ export function pyricSandbox(options = {}) {
|
|
|
653
914
|
const head = workerReady
|
|
654
915
|
? `<meta name="pyric-worker-v" content="${workerVersion}" ${MARKER}>`
|
|
655
916
|
: `<script ${MARKER}>globalThis.__PYRIC_FORCE_INPAGE__=true;</script>`;
|
|
917
|
+
// Plugin-level engine for the IN-PAGE path: a classic inline script runs
|
|
918
|
+
// before the deferred init module AND before app code's `getAI`, so the
|
|
919
|
+
// served `getAI` (entries/ai.ts) reads it synchronously — init.json can't
|
|
920
|
+
// be awaited there. Harmless on the worker path (that branch ignores the
|
|
921
|
+
// global; the worker reads ctx.aiEngine from init.json). `<` is escaped so
|
|
922
|
+
// an engine value can never break out of the script tag.
|
|
923
|
+
const aiEngineTag = aiEngineWire
|
|
924
|
+
? `<script ${MARKER}>globalThis.__PYRIC_AI_ENGINE__=${JSON.stringify(aiEngineWire).replace(/</g, '\\u003c')};</script>`
|
|
925
|
+
: '';
|
|
656
926
|
// Boot the sandbox by loading the real init entry as a module (Vite
|
|
657
927
|
// serves + transforms it). The init module's top-level await deploys rules
|
|
658
928
|
// before app code runs. Mirrors serve's injectServeTags.
|
|
659
|
-
const tag = head + `<script type="module" src="/@fs/${entries.init}" ${MARKER}></script>`;
|
|
929
|
+
const tag = head + aiEngineTag + `<script type="module" src="/@fs/${entries.init}" ${MARKER}></script>`;
|
|
660
930
|
return html.includes('</head>') ? html.replace('</head>', `${tag}</head>`) : tag + html;
|
|
661
931
|
},
|
|
662
932
|
};
|