@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,40 @@
|
|
|
1
|
+
import type { RtdbTriggerDelivery } from './delivery.js';
|
|
2
|
+
|
|
3
|
+
function canonicalPath(path: string): string {
|
|
4
|
+
const normalized = path.split('/').filter(Boolean).join('/');
|
|
5
|
+
return normalized ? `/${normalized}` : '/';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Deterministic test adapter for the snapshot-delivery seam. */
|
|
9
|
+
export class InMemoryRtdbTriggerDelivery implements RtdbTriggerDelivery {
|
|
10
|
+
readonly #values = new Map<string, unknown>();
|
|
11
|
+
readonly #listeners = new Map<string, Set<(value: unknown) => void>>();
|
|
12
|
+
|
|
13
|
+
seed(path: string, value: unknown): void {
|
|
14
|
+
this.#values.set(canonicalPath(path), structuredClone(value));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
emit(path: string, value: unknown): void {
|
|
18
|
+
const key = canonicalPath(path);
|
|
19
|
+
const snapshot = structuredClone(value);
|
|
20
|
+
this.#values.set(key, snapshot);
|
|
21
|
+
for (const listener of this.#listeners.get(key) ?? []) {
|
|
22
|
+
listener(structuredClone(snapshot));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
subscribe(path: string, listener: (value: unknown) => void): () => void {
|
|
27
|
+
const key = canonicalPath(path);
|
|
28
|
+
let listeners = this.#listeners.get(key);
|
|
29
|
+
if (!listeners) {
|
|
30
|
+
listeners = new Set();
|
|
31
|
+
this.#listeners.set(key, listeners);
|
|
32
|
+
}
|
|
33
|
+
listeners.add(listener);
|
|
34
|
+
listener(structuredClone(this.#values.get(key) ?? null));
|
|
35
|
+
return () => {
|
|
36
|
+
listeners?.delete(listener);
|
|
37
|
+
if (listeners?.size === 0) this.#listeners.delete(key);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import type { FirebaseJson } from '../cli/firebase-json.js';
|
|
4
|
+
|
|
5
|
+
export interface FunctionsRtdbProject {
|
|
6
|
+
sourceDir: string;
|
|
7
|
+
entry: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface FunctionsConfig {
|
|
11
|
+
source?: unknown;
|
|
12
|
+
codebase?: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Discover the one Node Functions source supported by the first RTDB slice. */
|
|
16
|
+
export function discoverFunctionsRtdbProject(cwd: string): FunctionsRtdbProject | null {
|
|
17
|
+
const firebaseJsonPath = join(cwd, 'firebase.json');
|
|
18
|
+
if (!existsSync(firebaseJsonPath)) return null;
|
|
19
|
+
|
|
20
|
+
let config: FirebaseJson;
|
|
21
|
+
try {
|
|
22
|
+
config = JSON.parse(readFileSync(firebaseJsonPath, 'utf8')) as FirebaseJson;
|
|
23
|
+
} catch (error) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`pyric dev: failed to parse firebase.json while discovering Functions: ` +
|
|
26
|
+
`${error instanceof Error ? error.message : String(error)}`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
if (config.functions === undefined || config.functions === null) return null;
|
|
30
|
+
|
|
31
|
+
const declared = Array.isArray(config.functions)
|
|
32
|
+
? config.functions as FunctionsConfig[]
|
|
33
|
+
: [config.functions as FunctionsConfig];
|
|
34
|
+
if (declared.length !== 1) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
'pyric dev: multiple Functions codebases are not supported by the first ' +
|
|
37
|
+
'onValueCreated slice; configure one source for this development session.',
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
const functions = declared[0];
|
|
41
|
+
if (typeof functions !== 'object' || functions === null) {
|
|
42
|
+
throw new Error('pyric dev: firebase.json `functions` must be an object with a source.');
|
|
43
|
+
}
|
|
44
|
+
if (functions.source !== undefined && typeof functions.source !== 'string') {
|
|
45
|
+
throw new Error('pyric dev: firebase.json `functions.source` must be a string.');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const sourceDir = resolve(cwd, functions.source ?? 'functions');
|
|
49
|
+
const packageJsonPath = join(sourceDir, 'package.json');
|
|
50
|
+
if (!existsSync(packageJsonPath)) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`pyric dev: Functions source is declared but ${packageJsonPath} does not exist.`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let packageJson: { main?: unknown };
|
|
57
|
+
try {
|
|
58
|
+
packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { main?: unknown };
|
|
59
|
+
} catch (error) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`pyric dev: failed to parse ${packageJsonPath}: ` +
|
|
62
|
+
`${error instanceof Error ? error.message : String(error)}`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
if (packageJson.main !== undefined && typeof packageJson.main !== 'string') {
|
|
66
|
+
throw new Error(`pyric dev: ${packageJsonPath} \`main\` must be a string.`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const entry = resolve(sourceDir, packageJson.main ?? 'index.js');
|
|
70
|
+
if (!existsSync(entry) || !statSync(entry).isFile()) {
|
|
71
|
+
throw new Error(`pyric dev: Functions entry does not exist: ${entry}`);
|
|
72
|
+
}
|
|
73
|
+
return { sourceDir, entry };
|
|
74
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeRtdbReference,
|
|
3
|
+
rtdbReferenceParamName,
|
|
4
|
+
rtdbReferenceParts,
|
|
5
|
+
} from './reference-pattern.js';
|
|
6
|
+
|
|
7
|
+
export interface RtdbSnapshotCommit {
|
|
8
|
+
path: string;
|
|
9
|
+
before: unknown;
|
|
10
|
+
after: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CreatedValueProjection {
|
|
14
|
+
ref: string;
|
|
15
|
+
params: Record<string, string>;
|
|
16
|
+
value: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function canonicalPath(path: string): string {
|
|
20
|
+
const normalized = normalizeRtdbReference(path);
|
|
21
|
+
return normalized ? `/${normalized}` : '/';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function exists(value: unknown): boolean {
|
|
25
|
+
return value !== null && value !== undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function child(value: unknown, key: string): unknown {
|
|
29
|
+
if (typeof value !== 'object' || value === null) return undefined;
|
|
30
|
+
return Object.prototype.hasOwnProperty.call(value, key)
|
|
31
|
+
? (value as Record<string, unknown>)[key]
|
|
32
|
+
: undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function childKeys(value: unknown): string[] {
|
|
36
|
+
if (typeof value !== 'object' || value === null) return [];
|
|
37
|
+
return Object.keys(value).filter((key) => exists(child(value, key))).sort();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function watchPath(reference: string): string {
|
|
41
|
+
const literal: string[] = [];
|
|
42
|
+
for (const segment of rtdbReferenceParts(reference)) {
|
|
43
|
+
if (rtdbReferenceParamName(segment)) break;
|
|
44
|
+
literal.push(segment);
|
|
45
|
+
}
|
|
46
|
+
return canonicalPath(literal.join('/'));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Project absent-to-present values for one v2 RTDB trigger reference. */
|
|
50
|
+
export function projectValueCreates(
|
|
51
|
+
reference: string,
|
|
52
|
+
commit: RtdbSnapshotCommit,
|
|
53
|
+
): CreatedValueProjection[] {
|
|
54
|
+
const pattern = rtdbReferenceParts(reference);
|
|
55
|
+
const committed = rtdbReferenceParts(commit.path);
|
|
56
|
+
if (committed.length > pattern.length) return [];
|
|
57
|
+
|
|
58
|
+
const params: Record<string, string> = {};
|
|
59
|
+
for (let index = 0; index < committed.length; index += 1) {
|
|
60
|
+
const capture = rtdbReferenceParamName(pattern[index]);
|
|
61
|
+
if (capture) params[capture] = committed[index];
|
|
62
|
+
else if (pattern[index] !== committed[index]) return [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const projected: CreatedValueProjection[] = [];
|
|
66
|
+
const visit = (
|
|
67
|
+
depth: number,
|
|
68
|
+
before: unknown,
|
|
69
|
+
after: unknown,
|
|
70
|
+
concrete: string[],
|
|
71
|
+
captures: Record<string, string>,
|
|
72
|
+
): void => {
|
|
73
|
+
if (depth === pattern.length) {
|
|
74
|
+
if (!exists(before) && exists(after)) {
|
|
75
|
+
projected.push({ ref: concrete.join('/'), params: captures, value: after });
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const segment = pattern[depth];
|
|
80
|
+
const capture = rtdbReferenceParamName(segment);
|
|
81
|
+
if (capture) {
|
|
82
|
+
for (const key of childKeys(after)) {
|
|
83
|
+
visit(
|
|
84
|
+
depth + 1,
|
|
85
|
+
child(before, key),
|
|
86
|
+
child(after, key),
|
|
87
|
+
[...concrete, key],
|
|
88
|
+
{ ...captures, [capture]: key },
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
visit(
|
|
94
|
+
depth + 1,
|
|
95
|
+
child(before, segment),
|
|
96
|
+
child(after, segment),
|
|
97
|
+
[...concrete, segment],
|
|
98
|
+
captures,
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
visit(committed.length, commit.before, commit.after, committed, params);
|
|
103
|
+
return projected;
|
|
104
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function normalizeRtdbReference(reference: string): string {
|
|
2
|
+
return reference.split('/').filter(Boolean).join('/');
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function rtdbReferenceParts(reference: string): string[] {
|
|
6
|
+
const normalized = normalizeRtdbReference(reference);
|
|
7
|
+
return normalized ? normalized.split('/') : [];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function rtdbReferenceParamName(segment: string): string | null {
|
|
11
|
+
return /^\{([A-Za-z0-9_]+)(?:=\*)?\}$/.exec(segment)?.[1] ?? null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function supportsRtdbReference(reference: string): boolean {
|
|
15
|
+
return rtdbReferenceParts(reference).every((segment) =>
|
|
16
|
+
rtdbReferenceParamName(segment) !== null || (
|
|
17
|
+
!segment.includes('{') && !segment.includes('}') && !segment.includes('*')
|
|
18
|
+
),
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { RemoteRtdb } from '../remote/index.js';
|
|
2
|
+
import type { RtdbTriggerDelivery } from './delivery.js';
|
|
3
|
+
|
|
4
|
+
/** Existing remote RTDB value subscriptions adapted to the execution seam. */
|
|
5
|
+
export class RemoteRtdbTriggerDelivery implements RtdbTriggerDelivery {
|
|
6
|
+
readonly #rtdb: Pick<RemoteRtdb, 'onValue'>;
|
|
7
|
+
|
|
8
|
+
constructor(rtdb: Pick<RemoteRtdb, 'onValue'>) {
|
|
9
|
+
this.#rtdb = rtdb;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
subscribe(
|
|
13
|
+
path: string,
|
|
14
|
+
listener: (value: unknown) => void,
|
|
15
|
+
onError?: (error: unknown) => void,
|
|
16
|
+
): () => void {
|
|
17
|
+
return this.#rtdb.onValue(
|
|
18
|
+
path,
|
|
19
|
+
(snapshot) => listener(snapshot.value),
|
|
20
|
+
onError,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pyric/cli' OWN package version, resolved at runtime — the version-skew
|
|
3
|
+
* stamp both ends of the worker relay compare (integration-smoke fix: an old
|
|
4
|
+
* `pyric dev` accepting a newer client's frame and dying mid-handling used to
|
|
5
|
+
* surface as a bare 30s timeout with no hint).
|
|
6
|
+
*
|
|
7
|
+
* Resolution order:
|
|
8
|
+
* 1. A standalone `bun build --compile` binary's baked version
|
|
9
|
+
* (`globalThis.__PYRIC_EMBEDDED__.version` — see serve/standalone-assets).
|
|
10
|
+
* 2. The nearest `package.json` walking up from THIS module (dist/ or src/),
|
|
11
|
+
* i.e. the @pyric/cli install actually executing.
|
|
12
|
+
* 3. `'0.0.0'` when neither resolves (never throws).
|
|
13
|
+
*
|
|
14
|
+
* Node-only (node:fs / node:url) — do NOT import from browser-bundled modules
|
|
15
|
+
* (`bridge/protocol.ts`, the bridge client, worker code). The server
|
|
16
|
+
* (`bridge/server/peer.ts`) and the Node remote client (`remote/index.ts`)
|
|
17
|
+
* are the intended consumers.
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
20
|
+
import { dirname, join } from 'node:path';
|
|
21
|
+
import { fileURLToPath } from 'node:url';
|
|
22
|
+
|
|
23
|
+
let cached: string | null = null;
|
|
24
|
+
|
|
25
|
+
export function cliVersion(): string {
|
|
26
|
+
if (cached !== null) return cached;
|
|
27
|
+
const embedded = (
|
|
28
|
+
globalThis as { __PYRIC_EMBEDDED__?: { version?: string } }
|
|
29
|
+
).__PYRIC_EMBEDDED__;
|
|
30
|
+
if (typeof embedded?.version === 'string' && embedded.version.length > 0) {
|
|
31
|
+
cached = embedded.version;
|
|
32
|
+
return cached;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
36
|
+
while (!existsSync(join(dir, 'package.json'))) {
|
|
37
|
+
const parent = dirname(dir);
|
|
38
|
+
if (parent === dir) break; // filesystem root
|
|
39
|
+
dir = parent;
|
|
40
|
+
}
|
|
41
|
+
const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as {
|
|
42
|
+
version?: string;
|
|
43
|
+
};
|
|
44
|
+
cached = pkg.version ?? '0.0.0';
|
|
45
|
+
} catch {
|
|
46
|
+
cached = '0.0.0';
|
|
47
|
+
}
|
|
48
|
+
return cached;
|
|
49
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal `exports`-field walker for the CJS→ESM seam in
|
|
3
|
+
* `@pyric/cli/register`.
|
|
4
|
+
*
|
|
5
|
+
* Why it exists: a rewritten CJS `require('firebase-admin/app')` resolves
|
|
6
|
+
* `pyric-admin/app` under the `require` condition, but the pyric mirrors are
|
|
7
|
+
* ESM-only (`import`-condition exports) — Node's CJS resolver throws
|
|
8
|
+
* ERR_PACKAGE_PATH_NOT_EXPORTED and ignores hook-supplied condition
|
|
9
|
+
* overrides. `require(esm)` (Node ≥ 22.12) can LOAD the module fine once we
|
|
10
|
+
* hand it the file, so the register hook locates the package
|
|
11
|
+
* (`Module.findPackageJSON`) and resolves the subpath here under import
|
|
12
|
+
* conditions.
|
|
13
|
+
*
|
|
14
|
+
* Deliberately narrow, matching what the pyric packages actually publish:
|
|
15
|
+
* literal subpaths only (no `*` patterns), string targets, and nested
|
|
16
|
+
* condition objects tried in `node` → `import` → `default` order (`types`
|
|
17
|
+
* and unknown conditions are skipped).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
type ExportsValue = string | { [key: string]: ExportsValue } | null;
|
|
21
|
+
|
|
22
|
+
const CONDITION_ORDER = ['node', 'import', 'default'] as const;
|
|
23
|
+
|
|
24
|
+
/** Resolve one condition object/string to its file target, or null. */
|
|
25
|
+
function resolveTarget(value: ExportsValue): string | null {
|
|
26
|
+
if (typeof value === 'string') return value;
|
|
27
|
+
if (value === null || typeof value !== 'object') return null;
|
|
28
|
+
for (const condition of CONDITION_ORDER) {
|
|
29
|
+
if (condition in value) {
|
|
30
|
+
const resolved = resolveTarget(value[condition] ?? null);
|
|
31
|
+
if (resolved !== null) return resolved;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolve `subpath` (e.g. `'./app'`, or `'.'` for the root) against a
|
|
39
|
+
* package's `exports` field under import conditions. Returns the relative
|
|
40
|
+
* file target (e.g. `'./dist/app/index.js'`) or null when the subpath is
|
|
41
|
+
* not exported.
|
|
42
|
+
*/
|
|
43
|
+
export function resolveEsmOnlySubpath(
|
|
44
|
+
exportsField: unknown,
|
|
45
|
+
subpath: string,
|
|
46
|
+
): string | null {
|
|
47
|
+
if (exportsField === null || exportsField === undefined) return null;
|
|
48
|
+
if (typeof exportsField === 'string') {
|
|
49
|
+
return subpath === '.' ? exportsField : null;
|
|
50
|
+
}
|
|
51
|
+
if (typeof exportsField !== 'object') return null;
|
|
52
|
+
const map = exportsField as Record<string, ExportsValue>;
|
|
53
|
+
|
|
54
|
+
const keys = Object.keys(map);
|
|
55
|
+
const isSubpathMap = keys.every((k) => k === '.' || k.startsWith('./'));
|
|
56
|
+
if (!isSubpathMap) {
|
|
57
|
+
// Bare conditions object — describes the root subpath only.
|
|
58
|
+
return subpath === '.' ? resolveTarget(map as ExportsValue) : null;
|
|
59
|
+
}
|
|
60
|
+
const entry = map[subpath];
|
|
61
|
+
if (entry === undefined) return null;
|
|
62
|
+
return resolveTarget(entry);
|
|
63
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `module.register()` fallback hooks — the ASYNC (loader-thread) variant of
|
|
3
|
+
* the specifier rewrite, used only on Node 22.x older than 22.15 where the
|
|
4
|
+
* sync `module.registerHooks` API doesn't exist yet.
|
|
5
|
+
*
|
|
6
|
+
* Runs on Node's loader thread, so it intercepts ESM `import` ONLY — CJS
|
|
7
|
+
* `require('firebase-admin')` is NOT rewritten on this path (index.ts logs
|
|
8
|
+
* a warning saying exactly that). Keep this module free of side effects and
|
|
9
|
+
* heavy imports: the loader thread re-instantiates it in isolation.
|
|
10
|
+
*/
|
|
11
|
+
import { mapFirebaseSpecifier } from './mapping.js';
|
|
12
|
+
|
|
13
|
+
interface ResolveContext {
|
|
14
|
+
parentURL?: string;
|
|
15
|
+
conditions: string[];
|
|
16
|
+
importAttributes: Record<string, string>;
|
|
17
|
+
}
|
|
18
|
+
interface ResolveResult {
|
|
19
|
+
url: string;
|
|
20
|
+
format?: string | null;
|
|
21
|
+
shortCircuit?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function resolve(
|
|
25
|
+
specifier: string,
|
|
26
|
+
context: ResolveContext,
|
|
27
|
+
nextResolve: (specifier: string, context?: ResolveContext) => Promise<ResolveResult>,
|
|
28
|
+
): Promise<ResolveResult> {
|
|
29
|
+
return nextResolve(mapFirebaseSpecifier(specifier) ?? specifier, context);
|
|
30
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@pyric/cli/register` — the Node substitution seam (adoption layer 2).
|
|
3
|
+
*
|
|
4
|
+
* Loaded via `node --import @pyric/cli/register` (which `pyric dev` injects
|
|
5
|
+
* through NODE_OPTIONS), it makes the user's UNCHANGED `firebase-admin` /
|
|
6
|
+
* `firebase` imports resolve to `pyric-admin` / `pyric`, every subpath 1:1,
|
|
7
|
+
* and installs the sandbox-factory global that `pyric-admin`'s ambient
|
|
8
|
+
* `initializeApp()` consumes.
|
|
9
|
+
*
|
|
10
|
+
* ACTIVATOR, NOT LOCATOR (adoption-experience design): activation is purely
|
|
11
|
+
* the `PYRIC_SANDBOX` env var injected at invocation — never file presence,
|
|
12
|
+
* never app code. Without it this module is INERT (import it freely; nothing
|
|
13
|
+
* happens). Under `NODE_ENV=production` it REFUSES with one stderr line
|
|
14
|
+
* unless `PYRIC_SANDBOX_FORCE=1`. On activation it logs one stderr line.
|
|
15
|
+
*
|
|
16
|
+
* Hooks API: `module.registerHooks` (sync, Node ≥ 22.15) intercepts BOTH
|
|
17
|
+
* `require()` and `import`. On older 22.x it falls back to
|
|
18
|
+
* `module.register()` (ESM-only) with a warning that CJS require() is not
|
|
19
|
+
* rewritten.
|
|
20
|
+
*/
|
|
21
|
+
import Module from 'node:module';
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
import { dirname, join } from 'node:path';
|
|
24
|
+
import { pathToFileURL } from 'node:url';
|
|
25
|
+
import { mapFirebaseSpecifier } from './mapping.js';
|
|
26
|
+
import { resolveEsmOnlySubpath } from './esm-exports.js';
|
|
27
|
+
import { remoteSandbox } from '../remote/index.js';
|
|
28
|
+
|
|
29
|
+
/** The shared seam with pyric-admin's ambient init: a synchronous factory
|
|
30
|
+
* returning the lazy branded handle. `Symbol.for` so both packages agree
|
|
31
|
+
* without importing each other's types. */
|
|
32
|
+
const SANDBOX_FACTORY = Symbol.for('pyric.remote.sandboxFactory');
|
|
33
|
+
|
|
34
|
+
interface SyncResolveContext {
|
|
35
|
+
parentURL?: string;
|
|
36
|
+
conditions?: string[];
|
|
37
|
+
}
|
|
38
|
+
interface SyncResolveResult {
|
|
39
|
+
url: string;
|
|
40
|
+
format?: string | null;
|
|
41
|
+
shortCircuit?: boolean;
|
|
42
|
+
}
|
|
43
|
+
type SyncResolve = (
|
|
44
|
+
specifier: string,
|
|
45
|
+
context: SyncResolveContext,
|
|
46
|
+
nextResolve: (specifier: string, context?: SyncResolveContext) => SyncResolveResult,
|
|
47
|
+
) => SyncResolveResult;
|
|
48
|
+
|
|
49
|
+
/** `module.registerHooks` landed in Node 22.15 / 23.5 — feature-detect
|
|
50
|
+
* (typed locally: the repo's ambient node types predate it). */
|
|
51
|
+
const moduleApi = Module as unknown as {
|
|
52
|
+
registerHooks?: (hooks: { resolve: SyncResolve }) => void;
|
|
53
|
+
register?: (specifier: string | URL) => void;
|
|
54
|
+
findPackageJSON?: (specifier: string, base: string | URL) => string | undefined;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* CJS→ESM seam: a rewritten `require()` fails against the pyric mirrors'
|
|
59
|
+
* `import`-condition-only exports (the CJS resolver ignores hook-supplied
|
|
60
|
+
* condition overrides), even though `require(esm)` can load them fine.
|
|
61
|
+
* Locate the package from this installed CLI and resolve the subpath under
|
|
62
|
+
* import conditions ourselves. The user's function package is not required
|
|
63
|
+
* to install Pyric's mapped targets. Returns the resolved file URL, or null
|
|
64
|
+
* to rethrow the original error.
|
|
65
|
+
*/
|
|
66
|
+
function resolveEsmOnlyForRequire(mapped: string): string | null {
|
|
67
|
+
if (typeof moduleApi.findPackageJSON !== 'function') return null;
|
|
68
|
+
const slash = mapped.indexOf('/');
|
|
69
|
+
const pkgName = slash === -1 ? mapped : mapped.slice(0, slash);
|
|
70
|
+
const subpath = slash === -1 ? '.' : `.${mapped.slice(slash)}`;
|
|
71
|
+
let pkgJsonPath: string | undefined;
|
|
72
|
+
try {
|
|
73
|
+
pkgJsonPath = moduleApi.findPackageJSON(
|
|
74
|
+
pkgName,
|
|
75
|
+
import.meta.url,
|
|
76
|
+
);
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
if (!pkgJsonPath) return null;
|
|
81
|
+
try {
|
|
82
|
+
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8')) as { exports?: unknown };
|
|
83
|
+
const target = resolveEsmOnlySubpath(pkg.exports, subpath);
|
|
84
|
+
if (!target) return null;
|
|
85
|
+
return pathToFileURL(join(dirname(pkgJsonPath), target)).href;
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function activate(): void {
|
|
92
|
+
if (typeof moduleApi.registerHooks === 'function') {
|
|
93
|
+
moduleApi.registerHooks({
|
|
94
|
+
resolve(specifier, context, nextResolve) {
|
|
95
|
+
const mapped = mapFirebaseSpecifier(specifier);
|
|
96
|
+
if (mapped === null) return nextResolve(specifier, context);
|
|
97
|
+
try {
|
|
98
|
+
return nextResolve(mapped, { ...context, parentURL: import.meta.url });
|
|
99
|
+
} catch (err) {
|
|
100
|
+
// CJS `require('firebase-admin/app')` resolves under the `require`
|
|
101
|
+
// condition, but the pyric mirrors are ESM-only. Resolve the file
|
|
102
|
+
// under import conditions ourselves — require(esm) (Node ≥ 22.12)
|
|
103
|
+
// loads it fine once given the URL.
|
|
104
|
+
const code = (err as { code?: string }).code;
|
|
105
|
+
if (code === 'ERR_PACKAGE_PATH_NOT_EXPORTED' || code === 'MODULE_NOT_FOUND') {
|
|
106
|
+
const url = resolveEsmOnlyForRequire(mapped);
|
|
107
|
+
if (url) return { url, shortCircuit: true };
|
|
108
|
+
}
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
} else {
|
|
114
|
+
process.stderr.write(
|
|
115
|
+
'@pyric/cli/register: this Node version lacks module.registerHooks (needs >= 22.15) — ' +
|
|
116
|
+
'falling back to module.register: ESM imports of firebase-admin/firebase are rewritten, ' +
|
|
117
|
+
"but CJS require('firebase-admin') is NOT intercepted. Upgrade Node to >= 22.15 for full coverage.\n",
|
|
118
|
+
);
|
|
119
|
+
moduleApi.register?.(new URL('./hooks.js', import.meta.url));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// The factory global — exact contract shared with pyric-admin's ambient
|
|
123
|
+
// init: synchronous, returns the lazy branded handle.
|
|
124
|
+
(globalThis as Record<symbol, unknown>)[SANDBOX_FACTORY] = (opts?: { url?: string }) =>
|
|
125
|
+
remoteSandbox(opts);
|
|
126
|
+
|
|
127
|
+
process.stderr.write(
|
|
128
|
+
`@pyric/cli/register: active — firebase-admin/firebase imports now resolve to the ` +
|
|
129
|
+
`pyric sandbox (PYRIC_SANDBOX=${process.env.PYRIC_SANDBOX}).\n`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Whether this process's firebase-admin/firebase imports are being rewritten
|
|
134
|
+
* to the pyric sandbox — true only when `PYRIC_SANDBOX` was set (and not
|
|
135
|
+
* refused by the production guard) at the moment this module loaded. */
|
|
136
|
+
export let active = false;
|
|
137
|
+
|
|
138
|
+
if (process.env.PYRIC_SANDBOX) {
|
|
139
|
+
if (process.env.NODE_ENV === 'production' && process.env.PYRIC_SANDBOX_FORCE !== '1') {
|
|
140
|
+
process.stderr.write(
|
|
141
|
+
'@pyric/cli/register: refusing to activate under NODE_ENV=production — ' +
|
|
142
|
+
'firebase-admin/firebase imports are NOT rewritten. ' +
|
|
143
|
+
'Set PYRIC_SANDBOX_FORCE=1 to override (dev/CI only).\n',
|
|
144
|
+
);
|
|
145
|
+
} else {
|
|
146
|
+
activate();
|
|
147
|
+
active = true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// No PYRIC_SANDBOX → inert by design: importing this module rewrites nothing.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The specifier map behind `@pyric/cli/register`: unmodified Firebase
|
|
3
|
+
* imports resolve to their pyric mirrors. Most subpaths map 1:1
|
|
4
|
+
* (`firebase-admin/app` → `pyric-admin/app`, `firebase/firestore` →
|
|
5
|
+
* `pyric/firestore`, …). `firebase/app` maps to the Node register adapter,
|
|
6
|
+
* which translates FirebaseOptions into the process sandbox before entering
|
|
7
|
+
* the strict `pyric/app` mirror.
|
|
8
|
+
*
|
|
9
|
+
* Pure — the resolution hooks (index.ts / hooks.ts) call this and the unit
|
|
10
|
+
* suite exercises it directly. Deliberately narrow: only the two package
|
|
11
|
+
* roots match. `@firebase/*` internals, `firebase-functions`, and anything
|
|
12
|
+
* merely *containing* "firebase" pass through untouched.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const MAPPINGS: ReadonlyArray<readonly [from: string, to: string]> = [
|
|
16
|
+
// firebase-admin first — `firebase-admin` must never match the bare
|
|
17
|
+
// `firebase` root (it can't today, but the order documents the intent).
|
|
18
|
+
['firebase-admin', 'pyric-admin'],
|
|
19
|
+
['firebase', 'pyric'],
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Map a Firebase specifier to its pyric mirror, or return `null` when the
|
|
24
|
+
* specifier is not a Firebase package (leave it for the default resolver).
|
|
25
|
+
*/
|
|
26
|
+
export function mapFirebaseSpecifier(specifier: string): string | null {
|
|
27
|
+
if (specifier === 'firebase/app') return 'pyric/app/register';
|
|
28
|
+
for (const [from, to] of MAPPINGS) {
|
|
29
|
+
if (specifier === from) return to;
|
|
30
|
+
if (specifier.startsWith(`${from}/`)) return to + specifier.slice(from.length);
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|