@pyric/cli 0.1.0-alpha.11 → 0.1.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/serve.js +4 -4
- package/dist/cli/serve.js.map +1 -1
- package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
- package/dist/conformance/.generated/can-i-use-browser.js +1 -1
- package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
- package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
- package/dist/conformance/.generated/can-i-use.js +2 -2
- package/dist/conformance/.generated/can-i-use.js.map +1 -1
- package/dist/serve/bundler.d.ts +13 -8
- package/dist/serve/bundler.d.ts.map +1 -1
- package/dist/serve/bundler.js +31 -36
- package/dist/serve/bundler.js.map +1 -1
- package/dist/serve/docs-ui/docs/_rhythm/index.html +1 -1
- package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +1 -1
- package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +1 -1
- package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +1 -1
- package/dist/serve/docs-ui/docs/ai-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/api-reference/index.html +2 -2
- package/dist/serve/docs-ui/docs/api-reference.md +1 -1
- package/dist/serve/docs-ui/docs/app-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/auth-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/ai-logic/index.html +44 -22
- package/dist/serve/docs-ui/docs/build/ai-logic.md +69 -21
- package/dist/serve/docs-ui/docs/build/authentication/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +1 -1
- package/dist/serve/docs-ui/docs/build/realtime-database/index.html +1 -1
- package/dist/serve/docs-ui/docs/conformance-scores/index.html +1 -1
- package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/database-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/firestore-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +2 -1
- package/dist/serve/docs-ui/docs/get-started/how-the-swap-works.md +2 -0
- package/dist/serve/docs-ui/docs/get-started/start-building/index.html +3 -2
- package/dist/serve/docs-ui/docs/get-started/start-building.md +3 -1
- package/dist/serve/docs-ui/docs/index.json +349 -29
- package/dist/serve/docs-ui/docs/messaging-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/observe/resolve-runtime-status/index.html +28 -0
- package/dist/serve/docs-ui/docs/observe/resolve-runtime-status.md +47 -0
- package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +1 -1
- package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +1 -1
- package/dist/serve/docs-ui/docs/overview/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api/index.html +916 -0
- package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api.md +706 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +168 -76
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +156 -73
- package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +11 -8
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +17 -4
- package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +37 -14
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +28 -8
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
- package/dist/serve/docs-ui/docs/rules-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +1 -1
- package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
- package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +1 -1
- package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +1 -1
- package/dist/serve/docs-ui/docs/storage-compat/index.html +1 -1
- package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
- package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
- package/dist/serve/docs-ui/docs/tutorial/index.html +429 -0
- package/dist/serve/docs-ui/docs/tutorial.md +701 -0
- package/dist/serve/docs-ui/llms.txt +3 -1
- package/dist/serve/entries/init.d.ts.map +1 -1
- package/dist/serve/entries/init.js +3 -0
- package/dist/serve/entries/init.js.map +1 -1
- package/dist/serve/entries/runtime.d.ts.map +1 -1
- package/dist/serve/entries/runtime.js +20 -5
- package/dist/serve/entries/runtime.js.map +1 -1
- package/dist/serve/entries/worker-runtime.d.ts +2 -2
- package/dist/serve/entries/worker-runtime.d.ts.map +1 -1
- package/dist/serve/entries/worker-runtime.js +45 -10
- package/dist/serve/entries/worker-runtime.js.map +1 -1
- package/dist/serve/runtime/chip-config.d.ts +19 -0
- package/dist/serve/runtime/chip-config.d.ts.map +1 -0
- package/dist/serve/runtime/chip-config.js +19 -0
- package/dist/serve/runtime/chip-config.js.map +1 -0
- package/dist/serve/runtime/chip-install.d.ts +10 -0
- package/dist/serve/runtime/chip-install.d.ts.map +1 -0
- package/dist/serve/runtime/chip-install.js +15 -0
- package/dist/serve/runtime/chip-install.js.map +1 -0
- package/dist/serve/runtime/chip.d.ts +17 -0
- package/dist/serve/runtime/chip.d.ts.map +1 -0
- package/dist/serve/runtime/chip.js +257 -0
- package/dist/serve/runtime/chip.js.map +1 -0
- package/dist/serve/runtime/manifest.d.ts +22 -0
- package/dist/serve/runtime/manifest.d.ts.map +1 -0
- package/dist/serve/runtime/manifest.js +20 -0
- package/dist/serve/runtime/manifest.js.map +1 -0
- package/dist/serve/runtime/status.d.ts +49 -0
- package/dist/serve/runtime/status.d.ts.map +1 -0
- package/dist/serve/runtime/status.js +164 -0
- package/dist/serve/runtime/status.js.map +1 -0
- package/dist/serve/runtime/worker-connection.d.ts +4 -0
- package/dist/serve/runtime/worker-connection.d.ts.map +1 -0
- package/dist/serve/runtime/worker-connection.js +11 -0
- package/dist/serve/runtime/worker-connection.js.map +1 -0
- package/dist/serve/runtime/worker-generation.d.ts +14 -0
- package/dist/serve/runtime/worker-generation.d.ts.map +1 -0
- package/dist/serve/runtime/worker-generation.js +56 -0
- package/dist/serve/runtime/worker-generation.js.map +1 -0
- package/dist/serve/runtime/worker-replacement.d.ts +18 -0
- package/dist/serve/runtime/worker-replacement.d.ts.map +1 -0
- package/dist/serve/runtime/worker-replacement.js +29 -0
- package/dist/serve/runtime/worker-replacement.js.map +1 -0
- package/dist/serve/standalone-assets.d.ts +2 -2
- package/dist/serve/standalone-assets.d.ts.map +1 -1
- package/dist/serve/standalone-assets.js +1 -1
- package/dist/serve/standalone-assets.js.map +1 -1
- package/dist/serve/studio-ui/assets/{RulesCodeEditor-CxVYcZXw.js → RulesCodeEditor-BDlH-5lp.js} +1 -1
- package/dist/serve/studio-ui/assets/{index-cpSfgQ7H.js → index-Bf9SSE8L.js} +5 -5
- package/dist/serve/studio-ui/assets/{seed-DeuFKi4J.js → seed-D_UjxfOU.js} +1 -1
- package/dist/serve/studio-ui/index.html +1 -1
- package/dist/serve/vite-ai-config.d.ts +25 -0
- package/dist/serve/vite-ai-config.d.ts.map +1 -0
- package/dist/serve/vite-ai-config.js +45 -0
- package/dist/serve/vite-ai-config.js.map +1 -0
- package/dist/serve/vite-plugin.d.ts +17 -36
- package/dist/serve/vite-plugin.d.ts.map +1 -1
- package/dist/serve/vite-plugin.js +38 -57
- package/dist/serve/vite-plugin.js.map +1 -1
- package/dist/serve/vite-rules-source.d.ts +8 -0
- package/dist/serve/vite-rules-source.d.ts.map +1 -0
- package/dist/serve/vite-rules-source.js +23 -0
- package/dist/serve/vite-rules-source.js.map +1 -0
- package/dist/serve/vite-worker-runtime.d.ts +20 -0
- package/dist/serve/vite-worker-runtime.d.ts.map +1 -0
- package/dist/serve/vite-worker-runtime.js +25 -0
- package/dist/serve/vite-worker-runtime.js.map +1 -0
- package/dist/serve/worker/client/connection.d.ts +7 -2
- package/dist/serve/worker/client/connection.d.ts.map +1 -1
- package/dist/serve/worker/client/connection.js +13 -16
- package/dist/serve/worker/client/connection.js.map +1 -1
- package/dist/serve/worker/client/core.d.ts +7 -0
- package/dist/serve/worker/client/core.d.ts.map +1 -1
- package/dist/serve/worker/client/core.js +28 -0
- package/dist/serve/worker/client/core.js.map +1 -1
- package/dist/serve/worker/client/runtime-control.d.ts +8 -0
- package/dist/serve/worker/client/runtime-control.d.ts.map +1 -0
- package/dist/serve/worker/client/runtime-control.js +11 -0
- package/dist/serve/worker/client/runtime-control.js.map +1 -0
- package/dist/serve/worker/entry.js +44 -2
- package/dist/serve/worker/entry.js.map +1 -1
- package/dist/serve/worker/host/core.js +1 -1
- package/dist/serve/worker/host/core.js.map +1 -1
- package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -1
- package/dist/serve/worker/host/firestore-writes.js +3 -2
- package/dist/serve/worker/host/firestore-writes.js.map +1 -1
- package/dist/serve/worker/host/studio.js +1 -1
- package/dist/serve/worker/host/studio.js.map +1 -1
- package/dist/serve/worker/host-context.d.ts +1 -1
- package/dist/serve/worker/host-context.d.ts.map +1 -1
- package/dist/serve/worker/index.d.ts +2 -1
- package/dist/serve/worker/index.d.ts.map +1 -1
- package/dist/serve/worker/index.js +2 -1
- package/dist/serve/worker/index.js.map +1 -1
- package/dist/serve/worker/protocol.d.ts +15 -1
- package/dist/serve/worker/protocol.d.ts.map +1 -1
- package/dist/serve/worker/protocol.js +2 -2
- package/dist/serve/worker/protocol.js.map +1 -1
- package/dist/serve/worker/retirement.d.ts +21 -0
- package/dist/serve/worker/retirement.d.ts.map +1 -0
- package/dist/serve/worker/retirement.js +97 -0
- package/dist/serve/worker/retirement.js.map +1 -0
- package/dist/serve/worker/serve-init.d.ts.map +1 -1
- package/dist/serve/worker/serve-init.js +5 -6
- package/dist/serve/worker/serve-init.js.map +1 -1
- package/dist/vite.d.ts +1 -0
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js.map +1 -1
- package/package.json +6 -4
- package/src/assurance/.generated/conformance-verdicts.ts +1090 -0
- package/src/assurance/attachment.ts +211 -0
- package/src/assurance/browser.ts +80 -0
- package/src/assurance/campaign.ts +496 -0
- package/src/assurance/capabilities.ts +446 -0
- package/src/assurance/cases.ts +43 -0
- package/src/assurance/index.ts +75 -0
- package/src/assurance/runner.ts +885 -0
- package/src/assurance/tool-names.ts +15 -0
- package/src/assurance/tools.ts +830 -0
- package/src/assurance/types.ts +352 -0
- package/src/assurance/validation.ts +434 -0
- package/src/bridge/client/bridge.ts +550 -0
- package/src/bridge/client/dispatch.ts +137 -0
- package/src/bridge/client.ts +45 -0
- package/src/bridge/protocol.ts +351 -0
- package/src/bridge/server/audit.ts +53 -0
- package/src/bridge/server/bridge.ts +597 -0
- package/src/bridge/server/headless.ts +160 -0
- package/src/bridge/server/json-schema-to-zod.ts +108 -0
- package/src/bridge/server/local-bridge.ts +66 -0
- package/src/bridge/server/logger.ts +50 -0
- package/src/bridge/server/mcp-contract.ts +93 -0
- package/src/bridge/server/mcp.ts +129 -0
- package/src/bridge/server/peer.ts +232 -0
- package/src/bridge/server/standalone.ts +347 -0
- package/src/bridge/server/tool-metadata.ts +99 -0
- package/src/bridge/server.ts +28 -0
- package/src/cli/can-i-use.ts +50 -0
- package/src/cli/cli.test.ts +493 -0
- package/src/cli/database-rules.ts +329 -0
- package/src/cli/dev-runner.ts +282 -0
- package/src/cli/firebase-json.ts +100 -0
- package/src/cli/firestore-indexes.ts +70 -0
- package/src/cli/index.ts +425 -0
- package/src/cli/init.ts +260 -0
- package/src/cli/mcp-proxy.ts +196 -0
- package/src/cli/parse-args.ts +80 -0
- package/src/cli/rules.ts +259 -0
- package/src/cli/scope.ts +67 -0
- package/src/cli/serve.ts +996 -0
- package/src/cli/service-commands.ts +73 -0
- package/src/cli/snapshot.ts +164 -0
- package/src/cli/storage-rules.ts +172 -0
- package/src/cli/verify.ts +416 -0
- package/src/conformance/.generated/can-i-use-browser.ts +113 -0
- package/src/conformance/.generated/can-i-use.ts +117 -0
- package/src/conformance/.generated/conformance-docs.ts +14 -0
- package/src/conformance/browser.ts +24 -0
- package/src/conformance/can-i-use-tool.ts +51 -0
- package/src/conformance/can-i-use.ts +18 -0
- package/src/conformance/docs.ts +8 -0
- package/src/conformance/index.ts +20 -0
- package/src/conformance/tools.ts +16 -0
- package/src/credentials/core/memoize-ttl.ts +142 -0
- package/src/credentials/core/types.ts +10 -0
- package/src/credentials/node/from-adc.ts +96 -0
- package/src/credentials/node/from-service-account.ts +133 -0
- package/src/credentials/node/index.ts +6 -0
- package/src/discover/concurrency.ts +127 -0
- package/src/discover/crawler-adapter.ts +142 -0
- package/src/discover/crawler.ts +1127 -0
- package/src/discover/credential-free.ts +27 -0
- package/src/discover/findCollectionGroup.ts +131 -0
- package/src/discover/firestore-source.ts +59 -0
- package/src/discover/index.ts +5 -0
- package/src/discover/merge.ts +523 -0
- package/src/discover/session.ts +402 -0
- package/src/discover/tools.ts +201 -0
- package/src/discover/types.ts +187 -0
- package/src/discover/wire.ts +324 -0
- package/src/functions-rtdb/child.ts +382 -0
- package/src/functions-rtdb/delivery.ts +7 -0
- package/src/functions-rtdb/discovery.ts +136 -0
- package/src/functions-rtdb/event.ts +64 -0
- package/src/functions-rtdb/execution.ts +111 -0
- package/src/functions-rtdb/in-memory-delivery.ts +40 -0
- package/src/functions-rtdb/project.ts +74 -0
- package/src/functions-rtdb/projection.ts +104 -0
- package/src/functions-rtdb/reference-pattern.ts +20 -0
- package/src/functions-rtdb/remote-delivery.ts +23 -0
- package/src/pkg-version.ts +49 -0
- package/src/register/esm-exports.ts +63 -0
- package/src/register/hooks.ts +30 -0
- package/src/register/index.ts +150 -0
- package/src/register/mapping.ts +33 -0
- package/src/remote/index.ts +1050 -0
- package/src/rtdb/crawl-snapshot.ts +118 -0
- package/src/rtdb/inspection.ts +137 -0
- package/src/rtdb/load-rules-document.ts +56 -0
- package/src/rtdb/rules-generation-tool.ts +38 -0
- package/src/rtdb/rules-json.ts +29 -0
- package/src/serve/activity-guard.ts +29 -0
- package/src/serve/activity-route.ts +164 -0
- package/src/serve/activity-warning.ts +26 -0
- package/src/serve/bridge-mount.ts +200 -0
- package/src/serve/bundler.ts +519 -0
- package/src/serve/capture-store.ts +65 -0
- package/src/serve/discovery.ts +199 -0
- package/src/serve/entries/ai.ts +292 -0
- package/src/serve/entries/app-backend.ts +4 -0
- package/src/serve/entries/app-client.ts +26 -0
- package/src/serve/entries/app-session-store.ts +47 -0
- package/src/serve/entries/app.ts +11 -0
- package/src/serve/entries/auth-helper-core.ts +181 -0
- package/src/serve/entries/auth-helper-dom.ts +134 -0
- package/src/serve/entries/auth-helper-runtime.ts +20 -0
- package/src/serve/entries/auth.ts +255 -0
- package/src/serve/entries/bridge-url.ts +31 -0
- package/src/serve/entries/database.ts +129 -0
- package/src/serve/entries/firestore.ts +232 -0
- package/src/serve/entries/init.ts +49 -0
- package/src/serve/entries/keepalive.ts +46 -0
- package/src/serve/entries/messaging-sw.ts +75 -0
- package/src/serve/entries/messaging.ts +96 -0
- package/src/serve/entries/runtime.ts +556 -0
- package/src/serve/entries/session-store.ts +97 -0
- package/src/serve/entries/storage.ts +92 -0
- package/src/serve/entries/tab-sync-wiring.ts +274 -0
- package/src/serve/entries/worker-runtime.ts +135 -0
- package/src/serve/init-payload.ts +42 -0
- package/src/serve/namespace.ts +675 -0
- package/src/serve/open-browser.ts +68 -0
- package/src/serve/rules.ts +272 -0
- package/src/serve/runtime/chip-config.ts +30 -0
- package/src/serve/runtime/chip-install.ts +27 -0
- package/src/serve/runtime/chip.ts +282 -0
- package/src/serve/runtime/manifest.ts +37 -0
- package/src/serve/runtime/status.ts +216 -0
- package/src/serve/runtime/worker-connection.ts +14 -0
- package/src/serve/runtime/worker-generation.ts +75 -0
- package/src/serve/runtime/worker-replacement.ts +42 -0
- package/src/serve/sandbox-marker.ts +31 -0
- package/src/serve/server.ts +428 -0
- package/src/serve/standalone-assets.ts +180 -0
- package/src/serve/state-store.ts +166 -0
- package/src/serve/studio/disk-project-store.ts +185 -0
- package/src/serve/studio/disk-workspace.ts +162 -0
- package/src/serve/studio/index.ts +20 -0
- package/src/serve/studio/routes.ts +237 -0
- package/src/serve/studio/store-types.ts +48 -0
- package/src/serve/studio/studio-storage.test.ts +289 -0
- package/src/serve/vite-ai-config.ts +77 -0
- package/src/serve/vite-plugin.ts +1075 -0
- package/src/serve/vite-rules-source.ts +28 -0
- package/src/serve/vite-worker-runtime.ts +51 -0
- package/src/serve/worker/activity-bootstrap.ts +24 -0
- package/src/serve/worker/client/admin-firestore.ts +38 -0
- package/src/serve/worker/client/ai.ts +124 -0
- package/src/serve/worker/client/auth.ts +489 -0
- package/src/serve/worker/client/connection.ts +227 -0
- package/src/serve/worker/client/core.ts +384 -0
- package/src/serve/worker/client/disconnect.ts +45 -0
- package/src/serve/worker/client/firestore-reads.ts +181 -0
- package/src/serve/worker/client/firestore-refs.ts +226 -0
- package/src/serve/worker/client/firestore-writes.ts +232 -0
- package/src/serve/worker/client/handles.ts +91 -0
- package/src/serve/worker/client/messaging.ts +119 -0
- package/src/serve/worker/client/presence.ts +174 -0
- package/src/serve/worker/client/rtdb.ts +311 -0
- package/src/serve/worker/client/rules.ts +63 -0
- package/src/serve/worker/client/runtime-control.ts +22 -0
- package/src/serve/worker/client/service-worker-connection.ts +59 -0
- package/src/serve/worker/client/snapshots.ts +86 -0
- package/src/serve/worker/client/storage.ts +195 -0
- package/src/serve/worker/client/studio.ts +88 -0
- package/src/serve/worker/client.ts +57 -0
- package/src/serve/worker/durable-persistence.ts +137 -0
- package/src/serve/worker/entry.ts +223 -0
- package/src/serve/worker/host/admin-firestore.ts +88 -0
- package/src/serve/worker/host/connection.ts +179 -0
- package/src/serve/worker/host/core.ts +387 -0
- package/src/serve/worker/host/dispatch.ts +316 -0
- package/src/serve/worker/host/firestore-reads.ts +117 -0
- package/src/serve/worker/host/firestore-writes.ts +456 -0
- package/src/serve/worker/host/presence.ts +312 -0
- package/src/serve/worker/host/rtdb.ts +136 -0
- package/src/serve/worker/host/rules.ts +128 -0
- package/src/serve/worker/host/storage.ts +312 -0
- package/src/serve/worker/host/studio.ts +75 -0
- package/src/serve/worker/host/subscriptions.ts +238 -0
- package/src/serve/worker/host-ai.ts +165 -0
- package/src/serve/worker/host-auth.ts +469 -0
- package/src/serve/worker/host-context.ts +273 -0
- package/src/serve/worker/host-events.ts +94 -0
- package/src/serve/worker/host-messaging.ts +240 -0
- package/src/serve/worker/host.ts +47 -0
- package/src/serve/worker/index.ts +196 -0
- package/src/serve/worker/presence-timing.ts +15 -0
- package/src/serve/worker/protocol.ts +1124 -0
- package/src/serve/worker/retirement.ts +125 -0
- package/src/serve/worker/serve-init.ts +605 -0
- package/src/serve/worker/service-worker-channel.ts +33 -0
- package/src/serve/worker/service-worker-relay.ts +86 -0
- package/src/serve/writer-lock.ts +53 -0
- package/src/verify/cases.ts +233 -0
- package/src/verify/fixture.ts +258 -0
- package/src/verify/index.ts +519 -0
- package/src/verify/tools.ts +108 -0
- package/src/version/compat-target.ts +17 -0
- package/src/vite.ts +18 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -31
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -29
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
import {
|
|
2
|
+
replay as replayFirestore,
|
|
3
|
+
type Divergence,
|
|
4
|
+
type EventService,
|
|
5
|
+
} from 'pyric/sandbox';
|
|
6
|
+
import {
|
|
7
|
+
replay as replayRtdb,
|
|
8
|
+
type RtdbReplayDivergence,
|
|
9
|
+
} from 'pyric/rules/internal/rtdb';
|
|
10
|
+
import {
|
|
11
|
+
SimulateFirestoreRulesHandler,
|
|
12
|
+
TestFirestoreRulesHandler,
|
|
13
|
+
type ExpressionReportLevel,
|
|
14
|
+
type TestCase,
|
|
15
|
+
type TestResult,
|
|
16
|
+
} from 'pyric/rules/internal';
|
|
17
|
+
import type { RtdbRulesDocument } from 'pyric/rules/internal/rtdb';
|
|
18
|
+
import type { ProjectScope } from '../credentials/core/types.js';
|
|
19
|
+
import {
|
|
20
|
+
isRtdbRulesDocument,
|
|
21
|
+
parseRtdbRulesJson,
|
|
22
|
+
type RtdbRulesJson,
|
|
23
|
+
} from '../rtdb/rules-json.js';
|
|
24
|
+
import {
|
|
25
|
+
fixtureVerifiableServices,
|
|
26
|
+
parseVerifyFixture,
|
|
27
|
+
VERIFY_FIXTURE_SCHEMA,
|
|
28
|
+
type PyricVerifyFixture,
|
|
29
|
+
} from './fixture.js';
|
|
30
|
+
import {
|
|
31
|
+
deriveRulesTestCases,
|
|
32
|
+
type DeriveRulesTestCasesOptions,
|
|
33
|
+
type DeriveRulesTestCasesResult,
|
|
34
|
+
type VerifyUnsupportedEvent,
|
|
35
|
+
} from './cases.js';
|
|
36
|
+
|
|
37
|
+
export {
|
|
38
|
+
buildVerifyFixture,
|
|
39
|
+
fixtureVerifiableServices,
|
|
40
|
+
parseVerifyFixture,
|
|
41
|
+
restoreStorageRulesFromFixture,
|
|
42
|
+
VERIFY_FIXTURE_SCHEMA,
|
|
43
|
+
type BuildVerifyFixtureInput,
|
|
44
|
+
type PyricVerifyFixture,
|
|
45
|
+
type VerifyFirestoreRulesBlock,
|
|
46
|
+
type VerifyRtdbRulesBlock,
|
|
47
|
+
type VerifyStorageRulesBlock,
|
|
48
|
+
} from './fixture.js';
|
|
49
|
+
export {
|
|
50
|
+
deriveRulesTestCases,
|
|
51
|
+
type DerivedRulesTestCase,
|
|
52
|
+
type DeriveRulesTestCasesOptions,
|
|
53
|
+
type DeriveRulesTestCasesResult,
|
|
54
|
+
type VerifyFixtureWarning,
|
|
55
|
+
type VerifyUnsupportedEvent,
|
|
56
|
+
} from './cases.js';
|
|
57
|
+
export { createVerifyTools, type VerifyToolDeps } from './tools.js';
|
|
58
|
+
|
|
59
|
+
export type VerifiableService = 'firestore' | 'rtdb';
|
|
60
|
+
export type VerifyEngine = 'sandbox' | 'rulesTestApi';
|
|
61
|
+
|
|
62
|
+
export type VerifyRulesInput = {
|
|
63
|
+
firestore?: string | { source: string };
|
|
64
|
+
rtdb?: { rules: Record<string, unknown> } | RtdbRulesDocument;
|
|
65
|
+
storage?: string | { source: string };
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export interface VerifyFixtureOptions {
|
|
69
|
+
rules: VerifyRulesInput;
|
|
70
|
+
services?: VerifiableService[];
|
|
71
|
+
engines?: VerifyEngine[];
|
|
72
|
+
rulesTestApi?: {
|
|
73
|
+
scope: ProjectScope;
|
|
74
|
+
expressionReportLevel?: ExpressionReportLevel;
|
|
75
|
+
};
|
|
76
|
+
caseDerivation?: Omit<DeriveRulesTestCasesOptions, 'service'>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface VerifyResult {
|
|
80
|
+
ok: boolean;
|
|
81
|
+
services: Partial<Record<VerifiableService, VerifyServiceResult>>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface VerifyServiceResult {
|
|
85
|
+
service: VerifiableService;
|
|
86
|
+
ok: boolean;
|
|
87
|
+
checkedEvents: number;
|
|
88
|
+
divergences: VerifyDivergence[];
|
|
89
|
+
engines?: Partial<Record<VerifyEngine, VerifyEngineResult>>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface VerifyEngineResult {
|
|
93
|
+
engine: VerifyEngine;
|
|
94
|
+
ok: boolean;
|
|
95
|
+
checkedEvents: number;
|
|
96
|
+
divergences: VerifyDivergence[];
|
|
97
|
+
testCases?: number;
|
|
98
|
+
passed?: number;
|
|
99
|
+
failed?: number;
|
|
100
|
+
unsupported?: number;
|
|
101
|
+
derivation?: DeriveRulesTestCasesResult;
|
|
102
|
+
results?: TestResult[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type VerifyDivergence =
|
|
106
|
+
| {
|
|
107
|
+
service: EventService | string;
|
|
108
|
+
kind: 'now-denied';
|
|
109
|
+
path?: string;
|
|
110
|
+
method?: string;
|
|
111
|
+
reason?: string;
|
|
112
|
+
}
|
|
113
|
+
| {
|
|
114
|
+
service: EventService | string;
|
|
115
|
+
kind: 'now-allowed';
|
|
116
|
+
path?: string;
|
|
117
|
+
method?: string;
|
|
118
|
+
reason?: string;
|
|
119
|
+
}
|
|
120
|
+
| {
|
|
121
|
+
service: EventService | string;
|
|
122
|
+
kind: 'state-drift';
|
|
123
|
+
path?: string;
|
|
124
|
+
field?: string;
|
|
125
|
+
before: unknown;
|
|
126
|
+
after: unknown;
|
|
127
|
+
}
|
|
128
|
+
| {
|
|
129
|
+
service: EventService | string;
|
|
130
|
+
kind: 'unsupported';
|
|
131
|
+
path?: string;
|
|
132
|
+
method?: string;
|
|
133
|
+
reason: string;
|
|
134
|
+
}
|
|
135
|
+
| {
|
|
136
|
+
service: EventService | string;
|
|
137
|
+
kind: 'expected-drift';
|
|
138
|
+
drift: string;
|
|
139
|
+
path?: string;
|
|
140
|
+
field?: string;
|
|
141
|
+
before?: unknown;
|
|
142
|
+
after?: unknown;
|
|
143
|
+
}
|
|
144
|
+
| {
|
|
145
|
+
service: EventService | string;
|
|
146
|
+
kind: 'engine-drift';
|
|
147
|
+
path?: string;
|
|
148
|
+
method?: string;
|
|
149
|
+
sandbox: string;
|
|
150
|
+
rulesTestApi: string;
|
|
151
|
+
reason?: string;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export class VerifyInputError extends Error {
|
|
155
|
+
constructor(message: string) {
|
|
156
|
+
super(message);
|
|
157
|
+
this.name = 'VerifyInputError';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function verifyFixture(
|
|
162
|
+
fixtureInput: PyricVerifyFixture | unknown,
|
|
163
|
+
opts: VerifyFixtureOptions,
|
|
164
|
+
): Promise<VerifyResult> {
|
|
165
|
+
const fixture = parseVerifyFixture(fixtureInput);
|
|
166
|
+
const selected = opts.services ?? fixtureVerifiableServices(fixture);
|
|
167
|
+
const engines = normalizeEngines(opts.engines);
|
|
168
|
+
if (selected.length === 0) {
|
|
169
|
+
throw new VerifyInputError(
|
|
170
|
+
`fixture ${fixture.schema} does not contain a verifiable rules service.`,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const services: Partial<Record<VerifiableService, VerifyServiceResult>> = {};
|
|
175
|
+
for (const service of selected) {
|
|
176
|
+
if (service === 'firestore') {
|
|
177
|
+
services.firestore = await verifyFirestore(fixture, requireFirestoreRules(opts.rules), engines, opts);
|
|
178
|
+
} else if (service === 'rtdb') {
|
|
179
|
+
services.rtdb = await verifyRtdb(fixture, requireRtdbRules(opts.rules), engines);
|
|
180
|
+
} else {
|
|
181
|
+
const exhaustive: never = service;
|
|
182
|
+
throw new VerifyInputError(`unsupported verify service: ${exhaustive}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
ok: Object.values(services).every((result) => result?.ok !== false),
|
|
187
|
+
services,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function verifyFirestore(
|
|
192
|
+
fixture: PyricVerifyFixture,
|
|
193
|
+
rules: string,
|
|
194
|
+
engines: VerifyEngine[],
|
|
195
|
+
opts: VerifyFixtureOptions,
|
|
196
|
+
): Promise<VerifyServiceResult> {
|
|
197
|
+
const firestore = fixture.services.firestore;
|
|
198
|
+
if (!firestore) {
|
|
199
|
+
throw new VerifyInputError('fixture does not contain services.firestore.');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const engineResults: Partial<Record<VerifyEngine, VerifyEngineResult>> = {};
|
|
203
|
+
if (engines.includes('sandbox')) {
|
|
204
|
+
engineResults.sandbox = verifyFirestoreSandbox(fixture, rules);
|
|
205
|
+
}
|
|
206
|
+
if (engines.includes('rulesTestApi')) {
|
|
207
|
+
engineResults.rulesTestApi = await verifyFirestoreRulesTestApi(fixture, rules, opts);
|
|
208
|
+
}
|
|
209
|
+
if (engineResults.sandbox && engineResults.rulesTestApi) {
|
|
210
|
+
addEngineDrift(rules, engineResults.rulesTestApi);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const divergences = collectEngineDivergences(engineResults);
|
|
214
|
+
return {
|
|
215
|
+
service: 'firestore',
|
|
216
|
+
ok: divergences.every(isInformational),
|
|
217
|
+
checkedEvents: serviceCheckedEvents(engineResults),
|
|
218
|
+
divergences,
|
|
219
|
+
engines: engineResults,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function verifyFirestoreSandbox(
|
|
224
|
+
fixture: PyricVerifyFixture,
|
|
225
|
+
rules: string,
|
|
226
|
+
): VerifyEngineResult {
|
|
227
|
+
const firestore = fixture.services.firestore;
|
|
228
|
+
if (!firestore) {
|
|
229
|
+
throw new VerifyInputError('fixture does not contain services.firestore.');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const { divergences } = replayFirestore(
|
|
233
|
+
fixture.events,
|
|
234
|
+
rules,
|
|
235
|
+
{},
|
|
236
|
+
firestore.state.documents,
|
|
237
|
+
);
|
|
238
|
+
const mapped = divergences.map(mapFirestoreDivergence);
|
|
239
|
+
return {
|
|
240
|
+
engine: 'sandbox',
|
|
241
|
+
ok: mapped.every(isInformational),
|
|
242
|
+
checkedEvents: fixture.events.filter(isProtectedFirestoreWrite).length,
|
|
243
|
+
divergences: mapped,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function isProtectedFirestoreWrite(event: PyricVerifyFixture['events'][number]): boolean {
|
|
248
|
+
return event.kind === 'write' && event.detail?.admin !== true;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function verifyFirestoreRulesTestApi(
|
|
252
|
+
fixture: PyricVerifyFixture,
|
|
253
|
+
rules: string,
|
|
254
|
+
opts: VerifyFixtureOptions,
|
|
255
|
+
): Promise<VerifyEngineResult> {
|
|
256
|
+
const scope = opts.rulesTestApi?.scope;
|
|
257
|
+
if (!scope) {
|
|
258
|
+
throw new VerifyInputError('rulesTestApi verification requires rulesTestApi.scope.');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const derivation = deriveRulesTestCases(fixture, {
|
|
262
|
+
service: 'firestore',
|
|
263
|
+
...opts.caseDerivation,
|
|
264
|
+
});
|
|
265
|
+
const divergences = derivation.unsupportedEvents.map(mapUnsupportedEvent);
|
|
266
|
+
if (derivation.testCases.length === 0) {
|
|
267
|
+
return {
|
|
268
|
+
engine: 'rulesTestApi',
|
|
269
|
+
ok: divergences.length === 0,
|
|
270
|
+
checkedEvents: 0,
|
|
271
|
+
testCases: 0,
|
|
272
|
+
passed: 0,
|
|
273
|
+
failed: 0,
|
|
274
|
+
unsupported: divergences.length,
|
|
275
|
+
derivation,
|
|
276
|
+
divergences,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const handler = new TestFirestoreRulesHandler();
|
|
281
|
+
const result = await handler.execute(scope, rules, derivation.testCases, {
|
|
282
|
+
expressionReportLevel: opts.rulesTestApi?.expressionReportLevel,
|
|
283
|
+
});
|
|
284
|
+
if (!result.success) {
|
|
285
|
+
divergences.push({
|
|
286
|
+
service: 'firestore',
|
|
287
|
+
kind: 'unsupported',
|
|
288
|
+
reason: `Rules Test API failed: ${result.error.message}`,
|
|
289
|
+
});
|
|
290
|
+
return {
|
|
291
|
+
engine: 'rulesTestApi',
|
|
292
|
+
ok: false,
|
|
293
|
+
checkedEvents: 0,
|
|
294
|
+
testCases: derivation.testCases.length,
|
|
295
|
+
passed: 0,
|
|
296
|
+
failed: derivation.testCases.length,
|
|
297
|
+
unsupported: divergences.length,
|
|
298
|
+
derivation,
|
|
299
|
+
divergences,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
for (const [index, testResult] of result.data.results.entries()) {
|
|
304
|
+
if (testResult.state !== 'FAILED') continue;
|
|
305
|
+
const tc = derivation.testCases[index];
|
|
306
|
+
divergences.push(mapFailedTestResult(testResult, tc));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
engine: 'rulesTestApi',
|
|
311
|
+
ok: divergences.every(isInformational),
|
|
312
|
+
checkedEvents: result.data.results.length,
|
|
313
|
+
testCases: derivation.testCases.length,
|
|
314
|
+
passed: result.data.passed,
|
|
315
|
+
failed: result.data.failed,
|
|
316
|
+
unsupported: result.data.unsupported + derivation.unsupportedEvents.length,
|
|
317
|
+
derivation,
|
|
318
|
+
results: result.data.results,
|
|
319
|
+
divergences,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async function verifyRtdb(
|
|
324
|
+
fixture: PyricVerifyFixture,
|
|
325
|
+
rulesJson: { rules: Record<string, unknown> },
|
|
326
|
+
engines: VerifyEngine[],
|
|
327
|
+
): Promise<VerifyServiceResult> {
|
|
328
|
+
const rtdb = fixture.services.rtdb;
|
|
329
|
+
if (!rtdb) {
|
|
330
|
+
throw new VerifyInputError('fixture does not contain services.rtdb.');
|
|
331
|
+
}
|
|
332
|
+
if (engines.includes('rulesTestApi')) {
|
|
333
|
+
throw new VerifyInputError('rulesTestApi verification is Firestore-only; select --service firestore or use the sandbox engine for RTDB.');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const replayed = await replayRtdb(fixture.events, {
|
|
337
|
+
rules: rulesJson,
|
|
338
|
+
capturedState: rtdb.state.tree,
|
|
339
|
+
...(rtdb.databaseUrl ? { databaseUrl: rtdb.databaseUrl } : {}),
|
|
340
|
+
});
|
|
341
|
+
const divergences = replayed.divergences.map(mapRtdbReplayDivergence);
|
|
342
|
+
const sandbox: VerifyEngineResult = {
|
|
343
|
+
engine: 'sandbox',
|
|
344
|
+
ok: divergences.every(isInformational),
|
|
345
|
+
checkedEvents: replayed.checkedEvents,
|
|
346
|
+
divergences,
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
service: 'rtdb',
|
|
351
|
+
ok: divergences.every(isInformational),
|
|
352
|
+
checkedEvents: replayed.checkedEvents,
|
|
353
|
+
divergences,
|
|
354
|
+
engines: { sandbox },
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function normalizeEngines(input: VerifyEngine[] | undefined): VerifyEngine[] {
|
|
359
|
+
const engines = input ?? ['sandbox'];
|
|
360
|
+
const out: VerifyEngine[] = [];
|
|
361
|
+
for (const engine of engines) {
|
|
362
|
+
if (engine !== 'sandbox' && engine !== 'rulesTestApi') {
|
|
363
|
+
throw new VerifyInputError(`unsupported verify engine: ${String(engine)}`);
|
|
364
|
+
}
|
|
365
|
+
if (!out.includes(engine)) out.push(engine);
|
|
366
|
+
}
|
|
367
|
+
return out.length > 0 ? out : ['sandbox'];
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function collectEngineDivergences(
|
|
371
|
+
engines: Partial<Record<VerifyEngine, VerifyEngineResult>>,
|
|
372
|
+
): VerifyDivergence[] {
|
|
373
|
+
return Object.values(engines).flatMap((result) => result?.divergences ?? []);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function serviceCheckedEvents(
|
|
377
|
+
engines: Partial<Record<VerifyEngine, VerifyEngineResult>>,
|
|
378
|
+
): number {
|
|
379
|
+
return engines.sandbox?.checkedEvents ?? engines.rulesTestApi?.checkedEvents ?? 0;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function mapUnsupportedEvent(event: VerifyUnsupportedEvent): VerifyDivergence {
|
|
383
|
+
return {
|
|
384
|
+
service: event.service,
|
|
385
|
+
kind: 'unsupported',
|
|
386
|
+
path: event.path,
|
|
387
|
+
method: event.method,
|
|
388
|
+
reason: event.reason,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function mapFailedTestResult(result: TestResult, tc: TestCase | undefined): VerifyDivergence {
|
|
393
|
+
const path = tc?.path;
|
|
394
|
+
const method = tc?.method;
|
|
395
|
+
const reason = result.notes.join('\n') || `expected ${result.expectation}, got ${result.decision}`;
|
|
396
|
+
if (result.expectation === 'ALLOW') {
|
|
397
|
+
return {
|
|
398
|
+
service: 'firestore',
|
|
399
|
+
kind: 'now-denied',
|
|
400
|
+
path,
|
|
401
|
+
method,
|
|
402
|
+
reason,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
service: 'firestore',
|
|
407
|
+
kind: 'now-allowed',
|
|
408
|
+
path,
|
|
409
|
+
method,
|
|
410
|
+
reason,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function addEngineDrift(
|
|
415
|
+
rules: string,
|
|
416
|
+
rulesTestApi: VerifyEngineResult,
|
|
417
|
+
): void {
|
|
418
|
+
const hostedCases = rulesTestApi.derivation?.testCases ?? [];
|
|
419
|
+
if (hostedCases.length === 0) return;
|
|
420
|
+
|
|
421
|
+
const simulator = new SimulateFirestoreRulesHandler();
|
|
422
|
+
const local = simulator.simulate(rules, hostedCases);
|
|
423
|
+
if (!local.success) return;
|
|
424
|
+
|
|
425
|
+
for (const [index, localResult] of local.data.results.entries()) {
|
|
426
|
+
const hostedResult = rulesTestApi.results?.[index];
|
|
427
|
+
if (!hostedResult) continue;
|
|
428
|
+
if (localResult.decision === hostedResult.decision) continue;
|
|
429
|
+
const tc = hostedCases[index];
|
|
430
|
+
rulesTestApi.divergences.push({
|
|
431
|
+
service: 'firestore',
|
|
432
|
+
kind: 'engine-drift',
|
|
433
|
+
path: tc?.path,
|
|
434
|
+
method: tc?.method,
|
|
435
|
+
sandbox: localResult.decision,
|
|
436
|
+
rulesTestApi: hostedResult.decision,
|
|
437
|
+
reason: `sandbox decided ${localResult.decision}; Rules Test API decided ${hostedResult.decision}.`,
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
rulesTestApi.ok = rulesTestApi.divergences.every(isInformational);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function requireFirestoreRules(input: VerifyRulesInput): string {
|
|
444
|
+
const rules = input.firestore;
|
|
445
|
+
if (typeof rules === 'string') return rules;
|
|
446
|
+
if (rules && typeof rules.source === 'string') return rules.source;
|
|
447
|
+
throw new VerifyInputError('missing candidate Firestore rules. Pass rules.firestore.');
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function requireRtdbRules(input: VerifyRulesInput): RtdbRulesJson {
|
|
451
|
+
const rules = input.rtdb;
|
|
452
|
+
if (isRtdbRulesDocument(rules)) {
|
|
453
|
+
return parseRtdbRulesJson(
|
|
454
|
+
rules.toJSON(),
|
|
455
|
+
() => new VerifyInputError('candidate RTDB rules document must compile to { rules: object }.'),
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
if (rules !== undefined) {
|
|
459
|
+
return parseRtdbRulesJson(
|
|
460
|
+
rules,
|
|
461
|
+
() => new VerifyInputError('candidate RTDB rules must be { rules: object }.'),
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
throw new VerifyInputError('missing candidate RTDB rules. Pass rules.rtdb.');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function mapFirestoreDivergence(divergence: Divergence): VerifyDivergence {
|
|
468
|
+
switch (divergence.kind) {
|
|
469
|
+
case 'real-divergence':
|
|
470
|
+
return {
|
|
471
|
+
service: 'firestore',
|
|
472
|
+
kind: 'state-drift',
|
|
473
|
+
path: divergence.path,
|
|
474
|
+
field: divergence.field,
|
|
475
|
+
before: divergence.before,
|
|
476
|
+
after: divergence.after,
|
|
477
|
+
};
|
|
478
|
+
case 'autoid-alias':
|
|
479
|
+
return {
|
|
480
|
+
service: 'firestore',
|
|
481
|
+
kind: 'expected-drift',
|
|
482
|
+
drift: 'autoid-alias',
|
|
483
|
+
path: divergence.originalPath,
|
|
484
|
+
before: divergence.originalPath,
|
|
485
|
+
after: divergence.replayedPath,
|
|
486
|
+
};
|
|
487
|
+
case 'sentinel-drift':
|
|
488
|
+
return {
|
|
489
|
+
service: 'firestore',
|
|
490
|
+
kind: 'expected-drift',
|
|
491
|
+
drift: 'sentinel-drift',
|
|
492
|
+
path: divergence.path,
|
|
493
|
+
field: divergence.field,
|
|
494
|
+
before: divergence.before,
|
|
495
|
+
after: divergence.after,
|
|
496
|
+
};
|
|
497
|
+
case 'time-drift':
|
|
498
|
+
return {
|
|
499
|
+
service: 'firestore',
|
|
500
|
+
kind: 'expected-drift',
|
|
501
|
+
drift: 'time-drift',
|
|
502
|
+
path: divergence.path,
|
|
503
|
+
field: divergence.field,
|
|
504
|
+
before: divergence.before,
|
|
505
|
+
after: divergence.after,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function mapRtdbReplayDivergence(divergence: RtdbReplayDivergence): VerifyDivergence {
|
|
511
|
+
return {
|
|
512
|
+
service: 'rtdb',
|
|
513
|
+
...divergence,
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function isInformational(divergence: VerifyDivergence): boolean {
|
|
518
|
+
return divergence.kind === 'expected-drift';
|
|
519
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { ToolHandler } from '@inbrowser/agent';
|
|
2
|
+
import type { ProjectScope } from '../credentials/core/types.js';
|
|
3
|
+
import {
|
|
4
|
+
deriveRulesTestCases,
|
|
5
|
+
verifyFixture,
|
|
6
|
+
type VerifyEngine,
|
|
7
|
+
type VerifyRulesInput,
|
|
8
|
+
type VerifiableService,
|
|
9
|
+
} from './index.js';
|
|
10
|
+
|
|
11
|
+
export interface VerifyToolDeps {
|
|
12
|
+
scope?: ProjectScope;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createVerifyTools(deps: VerifyToolDeps = {}): ToolHandler[] {
|
|
16
|
+
return [
|
|
17
|
+
{
|
|
18
|
+
name: 'pyric_verify_fixture',
|
|
19
|
+
description:
|
|
20
|
+
'Verify a pyric captured fixture against candidate rules. Uses local sandbox replay by default; rulesTestApi is Firestore-only and requires configured project credentials.',
|
|
21
|
+
parameters: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
fixture: { type: 'object' },
|
|
25
|
+
rules: { type: 'object' },
|
|
26
|
+
services: { type: 'array', items: { type: 'string', enum: ['firestore', 'rtdb'] } },
|
|
27
|
+
engines: { type: 'array', items: { type: 'string', enum: ['sandbox', 'rulesTestApi'] } },
|
|
28
|
+
expressionReportLevel: { type: 'string', enum: ['NONE', 'VISITED', 'FULL'] },
|
|
29
|
+
caseDerivation: { type: 'object' },
|
|
30
|
+
},
|
|
31
|
+
required: ['fixture', 'rules'],
|
|
32
|
+
},
|
|
33
|
+
async execute(args) {
|
|
34
|
+
const input = args as {
|
|
35
|
+
fixture: unknown;
|
|
36
|
+
rules: VerifyRulesInput;
|
|
37
|
+
services?: VerifiableService[];
|
|
38
|
+
engines?: VerifyEngine[];
|
|
39
|
+
expressionReportLevel?: 'NONE' | 'VISITED' | 'FULL';
|
|
40
|
+
caseDerivation?: { includeAllowed?: boolean; includeDenied?: boolean; mockReads?: 'strict' | 'omit' };
|
|
41
|
+
};
|
|
42
|
+
try {
|
|
43
|
+
if (input.engines?.includes('rulesTestApi') && !deps.scope) {
|
|
44
|
+
throw new Error('pyric_verify_fixture: rulesTestApi engine requires a ProjectScope.');
|
|
45
|
+
}
|
|
46
|
+
const result = await verifyFixture(input.fixture, {
|
|
47
|
+
rules: input.rules,
|
|
48
|
+
...(input.services ? { services: input.services } : {}),
|
|
49
|
+
...(input.engines ? { engines: input.engines } : {}),
|
|
50
|
+
...(input.caseDerivation ? { caseDerivation: input.caseDerivation } : {}),
|
|
51
|
+
...(input.engines?.includes('rulesTestApi') && deps.scope
|
|
52
|
+
? { rulesTestApi: { scope: deps.scope, expressionReportLevel: input.expressionReportLevel } }
|
|
53
|
+
: {}),
|
|
54
|
+
});
|
|
55
|
+
return {
|
|
56
|
+
ok: result.ok,
|
|
57
|
+
summary: result.ok ? 'Fixture verified' : 'Fixture verification found divergences',
|
|
58
|
+
data: result,
|
|
59
|
+
};
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return { ok: false, summary: e instanceof Error ? e.message : String(e) };
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'pyric_derive_rules_test_cases',
|
|
67
|
+
description:
|
|
68
|
+
'Derive Firestore Rules Test API test cases from a pyric captured fixture. This is inspection-only and does not call Firebase.',
|
|
69
|
+
parameters: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
fixture: { type: 'object' },
|
|
73
|
+
service: { type: 'string', enum: ['firestore'] },
|
|
74
|
+
includeAllowed: { type: 'boolean' },
|
|
75
|
+
includeDenied: { type: 'boolean' },
|
|
76
|
+
mockReads: { type: 'string', enum: ['strict', 'omit'] },
|
|
77
|
+
},
|
|
78
|
+
required: ['fixture'],
|
|
79
|
+
},
|
|
80
|
+
async execute(args) {
|
|
81
|
+
const input = args as {
|
|
82
|
+
fixture: unknown;
|
|
83
|
+
service?: 'firestore';
|
|
84
|
+
includeAllowed?: boolean;
|
|
85
|
+
includeDenied?: boolean;
|
|
86
|
+
mockReads?: 'strict' | 'omit';
|
|
87
|
+
};
|
|
88
|
+
try {
|
|
89
|
+
const result = deriveRulesTestCases(input.fixture, {
|
|
90
|
+
service: input.service ?? 'firestore',
|
|
91
|
+
includeAllowed: input.includeAllowed,
|
|
92
|
+
includeDenied: input.includeDenied,
|
|
93
|
+
mockReads: input.mockReads,
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
ok: result.ok,
|
|
97
|
+
summary: result.ok
|
|
98
|
+
? `Derived ${result.testCases.length} Firestore test case(s)`
|
|
99
|
+
: `Derived ${result.testCases.length} case(s), ${result.unsupportedEvents.length} unsupported event(s)`,
|
|
100
|
+
data: result,
|
|
101
|
+
};
|
|
102
|
+
} catch (e) {
|
|
103
|
+
return { ok: false, summary: e instanceof Error ? e.message : String(e) };
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for the Firebase version pyric is conformance-
|
|
3
|
+
* tested against — the number `pyric --version` prints alongside
|
|
4
|
+
* @pyric/cli' own version, and the number `scripts/publish-alpha.sh`
|
|
5
|
+
* reads to derive the `fb<major>.<minor>` dist-tag it moves on a green
|
|
6
|
+
* `compat:check` (see
|
|
7
|
+
* packages/site-docs/src/content/trust/versioning-and-compatibility.md).
|
|
8
|
+
*
|
|
9
|
+
* This is a pin, not @pyric/cli' own version: bumping it starts a
|
|
10
|
+
* re-snapshot of the upstream surface, and no release claims the new
|
|
11
|
+
* `fb` line until `compat:check` passes against it.
|
|
12
|
+
*
|
|
13
|
+
* TODO: once the upstream-surface snapshot lands, that snapshot becomes
|
|
14
|
+
* the source of truth for this value and this constant should read
|
|
15
|
+
* from it instead of being hand-set.
|
|
16
|
+
*/
|
|
17
|
+
export const FIREBASE_TESTED_AGAINST = '12.13.0';
|
package/src/vite.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@pyric/cli/vite` — the dev-only Vite plugin that swaps `firebase/*` to the
|
|
3
|
+
* in-process pyric sandbox during `vite dev` (the serve analog for source-driven
|
|
4
|
+
* apps). See `./serve/vite-plugin.ts` and the design rationale.
|
|
5
|
+
*
|
|
6
|
+
* import { pyric } from '@pyric/cli/vite';
|
|
7
|
+
* export default defineConfig({ plugins: [pyric()] });
|
|
8
|
+
*/
|
|
9
|
+
export { pyric } from './serve/vite-plugin.js';
|
|
10
|
+
export type { PyricOptions } from './serve/vite-plugin.js';
|
|
11
|
+
export type { PyricRuntimeChipOption } from './serve/runtime/chip-config.js';
|
|
12
|
+
|
|
13
|
+
// The benign node-builtin shims serve's bundler and this plugin apply when
|
|
14
|
+
// bundling pyric's browser graph (`fs`/`path`/`url` reached via the rules
|
|
15
|
+
// module resolver — see `serve/bundler.ts`). Exported so a browser app that
|
|
16
|
+
// bundles @pyric/cli' browser-side bridge client (Pyric Studio registers as
|
|
17
|
+
// the bridge peer) applies the SAME shims instead of re-deriving them.
|
|
18
|
+
export { NODE_BUILTIN_RE, NODE_BUILTIN_SHIMS } from './serve/bundler.js';
|