@pyric/cli 0.1.0-alpha.19 → 0.1.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -89
- package/dist/assurance/.generated/conformance-verdicts.d.ts +68 -1
- package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
- package/dist/assurance/.generated/conformance-verdicts.js +68 -1
- package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
- package/dist/bridge/client/dispatch.d.ts +25 -19
- package/dist/bridge/client/dispatch.d.ts.map +1 -1
- package/dist/bridge/client/dispatch.js +41 -48
- package/dist/bridge/client/dispatch.js.map +1 -1
- package/dist/bridge/client/tool-family-factories.d.ts +26 -0
- package/dist/bridge/client/tool-family-factories.d.ts.map +1 -0
- package/dist/bridge/client/tool-family-factories.js +10 -0
- package/dist/bridge/client/tool-family-factories.js.map +1 -0
- package/dist/bridge/server/mcp-contract.d.ts +7 -6
- package/dist/bridge/server/mcp-contract.d.ts.map +1 -1
- package/dist/bridge/server/mcp-contract.js +9 -48
- package/dist/bridge/server/mcp-contract.js.map +1 -1
- package/dist/bridge/server/peer.d.ts +11 -1
- package/dist/bridge/server/peer.d.ts.map +1 -1
- package/dist/bridge/server/peer.js +22 -1
- package/dist/bridge/server/peer.js.map +1 -1
- package/dist/bridge/server/tool-family-factories.d.ts +30 -0
- package/dist/bridge/server/tool-family-factories.d.ts.map +1 -0
- package/dist/bridge/server/tool-family-factories.js +22 -0
- package/dist/bridge/server/tool-family-factories.js.map +1 -0
- package/dist/bridge/server/tool-metadata.d.ts +17 -18
- package/dist/bridge/server/tool-metadata.d.ts.map +1 -1
- package/dist/bridge/server/tool-metadata.js +24 -59
- package/dist/bridge/server/tool-metadata.js.map +1 -1
- package/dist/bridge/tool-families.d.ts +48 -0
- package/dist/bridge/tool-families.d.ts.map +1 -0
- package/dist/bridge/tool-families.generated.d.ts +32 -0
- package/dist/bridge/tool-families.generated.d.ts.map +1 -0
- package/dist/bridge/tool-families.generated.js +15 -0
- package/dist/bridge/tool-families.generated.js.map +1 -0
- package/dist/bridge/tool-families.js +51 -0
- package/dist/bridge/tool-families.js.map +1 -0
- package/dist/bridge/tool-family-records/conformance.d.ts +7 -0
- package/dist/bridge/tool-family-records/conformance.d.ts.map +1 -0
- package/dist/bridge/tool-family-records/conformance.js +6 -0
- package/dist/bridge/tool-family-records/conformance.js.map +1 -0
- package/dist/bridge/tool-family-records/firestore-data.d.ts +7 -0
- package/dist/bridge/tool-family-records/firestore-data.d.ts.map +1 -0
- package/dist/bridge/tool-family-records/firestore-data.js +15 -0
- package/dist/bridge/tool-family-records/firestore-data.js.map +1 -0
- package/dist/bridge/tool-family-records/firestore-inspect.d.ts +7 -0
- package/dist/bridge/tool-family-records/firestore-inspect.d.ts.map +1 -0
- package/dist/bridge/tool-family-records/firestore-inspect.js +6 -0
- package/dist/bridge/tool-family-records/firestore-inspect.js.map +1 -0
- package/dist/bridge/tool-family-records/firestore-rules.d.ts +7 -0
- package/dist/bridge/tool-family-records/firestore-rules.d.ts.map +1 -0
- package/dist/bridge/tool-family-records/firestore-rules.js +15 -0
- package/dist/bridge/tool-family-records/firestore-rules.js.map +1 -0
- package/dist/bridge/tool-family-records/firestore-simulator.d.ts +7 -0
- package/dist/bridge/tool-family-records/firestore-simulator.d.ts.map +1 -0
- package/dist/bridge/tool-family-records/firestore-simulator.js +16 -0
- package/dist/bridge/tool-family-records/firestore-simulator.js.map +1 -0
- package/dist/bridge/tool-family-records/rtdb-inspection.d.ts +7 -0
- package/dist/bridge/tool-family-records/rtdb-inspection.d.ts.map +1 -0
- package/dist/bridge/tool-family-records/rtdb-inspection.js +6 -0
- package/dist/bridge/tool-family-records/rtdb-inspection.js.map +1 -0
- package/dist/bundler/externals.d.ts +37 -0
- package/dist/bundler/externals.d.ts.map +1 -0
- package/dist/bundler/externals.js +52 -0
- package/dist/bundler/externals.js.map +1 -0
- package/dist/bundler/index.d.ts +17 -0
- package/dist/bundler/index.d.ts.map +1 -0
- package/dist/bundler/index.js +17 -0
- package/dist/bundler/index.js.map +1 -0
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +48 -42
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/inlined-sdk-scanner.d.ts +6 -0
- package/dist/cli/inlined-sdk-scanner.d.ts.map +1 -0
- package/dist/cli/inlined-sdk-scanner.js +82 -0
- package/dist/cli/inlined-sdk-scanner.js.map +1 -0
- package/dist/cli/mcp-proxy.js +3 -3
- package/dist/cli/mcp-proxy.js.map +1 -1
- package/dist/cli/parse-args.d.ts +1 -1
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +51 -15
- package/dist/cli/parse-args.js.map +1 -1
- package/dist/cli/pyric-config.d.ts +24 -0
- package/dist/cli/pyric-config.d.ts.map +1 -0
- package/dist/cli/pyric-config.js +28 -0
- package/dist/cli/pyric-config.js.map +1 -0
- package/dist/cli/sandbox-interlock.d.ts +97 -0
- package/dist/cli/sandbox-interlock.d.ts.map +1 -0
- package/dist/cli/sandbox-interlock.js +112 -0
- package/dist/cli/sandbox-interlock.js.map +1 -0
- package/dist/cli/{dev-runner.d.ts → sandbox-runner.d.ts} +53 -48
- package/dist/cli/sandbox-runner.d.ts.map +1 -0
- package/dist/cli/{dev-runner.js → sandbox-runner.js} +105 -67
- package/dist/cli/sandbox-runner.js.map +1 -0
- package/dist/cli/serve.d.ts +12 -14
- package/dist/cli/serve.d.ts.map +1 -1
- package/dist/cli/serve.js +155 -116
- package/dist/cli/serve.js.map +1 -1
- package/dist/cli/snapshot.js +5 -5
- package/dist/cli/snapshot.js.map +1 -1
- package/dist/cli/unsupported-runtime.d.ts +27 -0
- package/dist/cli/unsupported-runtime.d.ts.map +1 -0
- package/dist/cli/unsupported-runtime.js +63 -0
- package/dist/cli/unsupported-runtime.js.map +1 -0
- package/dist/cli/verify.js +1 -1
- package/dist/cli/verify.js.map +1 -1
- package/dist/conformance/.generated/can-i-use-browser.d.ts +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 +1 -1
- package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
- package/dist/conformance/.generated/can-i-use.js +1 -1
- package/dist/conformance/.generated/can-i-use.js.map +1 -1
- package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
- package/dist/conformance/.generated/conformance-docs.js +1 -1
- package/dist/conformance/.generated/conformance-docs.js.map +1 -1
- package/dist/functions-rtdb/child.d.ts +37 -0
- package/dist/functions-rtdb/child.d.ts.map +1 -1
- package/dist/functions-rtdb/child.js +90 -21
- package/dist/functions-rtdb/child.js.map +1 -1
- package/dist/functions-rtdb/development-runtime.d.ts +3 -0
- package/dist/functions-rtdb/development-runtime.d.ts.map +1 -1
- package/dist/functions-rtdb/development-runtime.js +2 -1
- package/dist/functions-rtdb/development-runtime.js.map +1 -1
- package/dist/functions-rtdb/project.js +8 -8
- package/dist/functions-rtdb/project.js.map +1 -1
- package/dist/google-endpoints.d.ts +67 -0
- package/dist/google-endpoints.d.ts.map +1 -0
- package/dist/google-endpoints.js +119 -0
- package/dist/google-endpoints.js.map +1 -0
- package/dist/next/guard.js +1 -1
- package/dist/next/guard.js.map +1 -1
- package/dist/next/runtime-env.d.ts.map +1 -1
- package/dist/next/runtime-env.js +5 -0
- package/dist/next/runtime-env.js.map +1 -1
- package/dist/next/with-pyric.d.ts +1 -1
- package/dist/next/with-pyric.js +1 -1
- package/dist/register/beacon.d.ts +69 -0
- package/dist/register/beacon.d.ts.map +1 -0
- package/dist/register/beacon.js +199 -0
- package/dist/register/beacon.js.map +1 -0
- package/dist/register/index.d.ts.map +1 -1
- package/dist/register/index.js +65 -6
- package/dist/register/index.js.map +1 -1
- package/dist/register/net-guard.d.ts +110 -0
- package/dist/register/net-guard.d.ts.map +1 -0
- package/dist/register/net-guard.js +462 -0
- package/dist/register/net-guard.js.map +1 -0
- package/dist/remote/index.d.ts +1 -1
- package/dist/remote/index.js +9 -9
- package/dist/remote/index.js.map +1 -1
- package/dist/serve/ai-diagnostics-relay.d.ts +63 -0
- package/dist/serve/ai-diagnostics-relay.d.ts.map +1 -0
- package/dist/serve/ai-diagnostics-relay.js +125 -0
- package/dist/serve/ai-diagnostics-relay.js.map +1 -0
- package/dist/serve/ai-proxy.d.ts +92 -0
- package/dist/serve/ai-proxy.d.ts.map +1 -0
- package/dist/serve/ai-proxy.js +269 -0
- package/dist/serve/ai-proxy.js.map +1 -0
- package/dist/serve/ai-status.d.ts +44 -0
- package/dist/serve/ai-status.d.ts.map +1 -0
- package/dist/serve/ai-status.js +77 -0
- package/dist/serve/ai-status.js.map +1 -0
- package/dist/serve/ai-terminal-blocks.d.ts +97 -0
- package/dist/serve/ai-terminal-blocks.d.ts.map +1 -0
- package/dist/serve/ai-terminal-blocks.js +128 -0
- package/dist/serve/ai-terminal-blocks.js.map +1 -0
- package/dist/serve/ai-terminal-text.d.ts +36 -0
- package/dist/serve/ai-terminal-text.d.ts.map +1 -0
- package/dist/serve/ai-terminal-text.js +48 -0
- package/dist/serve/ai-terminal-text.js.map +1 -0
- package/dist/serve/beacon-route.d.ts +53 -0
- package/dist/serve/beacon-route.d.ts.map +1 -0
- package/dist/serve/beacon-route.js +101 -0
- package/dist/serve/beacon-route.js.map +1 -0
- package/dist/serve/bundler.js +10 -10
- package/dist/serve/bundler.js.map +1 -1
- package/dist/serve/entries/active-auth-registry.d.ts +16 -0
- package/dist/serve/entries/active-auth-registry.d.ts.map +1 -0
- package/dist/serve/entries/active-auth-registry.js +48 -0
- package/dist/serve/entries/active-auth-registry.js.map +1 -0
- package/dist/serve/entries/active-auth.d.ts +18 -0
- package/dist/serve/entries/active-auth.d.ts.map +1 -0
- package/dist/serve/entries/active-auth.js +84 -0
- package/dist/serve/entries/active-auth.js.map +1 -0
- package/dist/serve/entries/ai.d.ts.map +1 -1
- package/dist/serve/entries/ai.js +27 -1
- package/dist/serve/entries/ai.js.map +1 -1
- package/dist/serve/entries/auth-helper-core.d.ts +1 -0
- package/dist/serve/entries/auth-helper-core.d.ts.map +1 -1
- package/dist/serve/entries/auth-helper-core.js +4 -0
- package/dist/serve/entries/auth-helper-core.js.map +1 -1
- package/dist/serve/entries/auth-helper-dom.d.ts.map +1 -1
- package/dist/serve/entries/auth-helper-dom.js +29 -3
- package/dist/serve/entries/auth-helper-dom.js.map +1 -1
- package/dist/serve/entries/auth-helper-runtime.js +1 -1
- package/dist/serve/entries/auth-helper-runtime.js.map +1 -1
- package/dist/serve/entries/auth.d.ts.map +1 -1
- package/dist/serve/entries/auth.js +8 -0
- package/dist/serve/entries/auth.js.map +1 -1
- package/dist/serve/entries/bridge-url.d.ts +1 -1
- package/dist/serve/entries/bridge-url.js +1 -1
- package/dist/serve/entries/firestore.js +3 -3
- package/dist/serve/entries/firestore.js.map +1 -1
- package/dist/serve/entries/init.d.ts.map +1 -1
- package/dist/serve/entries/init.js +70 -4
- package/dist/serve/entries/init.js.map +1 -1
- package/dist/serve/entries/keepalive.js +1 -1
- package/dist/serve/entries/keepalive.js.map +1 -1
- package/dist/serve/entries/runtime.d.ts.map +1 -1
- package/dist/serve/entries/runtime.js +30 -14
- package/dist/serve/entries/runtime.js.map +1 -1
- package/dist/serve/entries/storage.js +1 -1
- package/dist/serve/entries/storage.js.map +1 -1
- package/dist/serve/entries/worker-runtime.js +1 -1
- package/dist/serve/entries/worker-runtime.js.map +1 -1
- package/dist/serve/init-payload.d.ts +4 -0
- package/dist/serve/init-payload.d.ts.map +1 -1
- package/dist/serve/namespace.d.ts +20 -5
- package/dist/serve/namespace.d.ts.map +1 -1
- package/dist/serve/namespace.js +93 -129
- package/dist/serve/namespace.js.map +1 -1
- package/dist/serve/rules.d.ts.map +1 -1
- package/dist/serve/rules.js +44 -21
- package/dist/serve/rules.js.map +1 -1
- package/dist/serve/runtime/chip-config.d.ts.map +1 -1
- package/dist/serve/runtime/chip-config.js +16 -2
- package/dist/serve/runtime/chip-config.js.map +1 -1
- package/dist/serve/runtime/chip-dialog.d.ts +18 -0
- package/dist/serve/runtime/chip-dialog.d.ts.map +1 -0
- package/dist/serve/runtime/chip-dialog.js +315 -0
- package/dist/serve/runtime/chip-dialog.js.map +1 -0
- package/dist/serve/runtime/chip-install.d.ts +2 -0
- package/dist/serve/runtime/chip-install.d.ts.map +1 -1
- package/dist/serve/runtime/chip-install.js +9 -4
- package/dist/serve/runtime/chip-install.js.map +1 -1
- package/dist/serve/runtime/chip-user-search.d.ts +16 -0
- package/dist/serve/runtime/chip-user-search.d.ts.map +1 -0
- package/dist/serve/runtime/chip-user-search.js +354 -0
- package/dist/serve/runtime/chip-user-search.js.map +1 -0
- package/dist/serve/runtime/chip.d.ts +10 -0
- package/dist/serve/runtime/chip.d.ts.map +1 -1
- package/dist/serve/runtime/chip.js +149 -15
- package/dist/serve/runtime/chip.js.map +1 -1
- package/dist/serve/runtime/identity.d.ts +17 -0
- package/dist/serve/runtime/identity.d.ts.map +1 -0
- package/dist/serve/runtime/identity.js +10 -0
- package/dist/serve/runtime/identity.js.map +1 -0
- package/dist/serve/runtime/manifest.d.ts +1 -1
- package/dist/serve/runtime/manifest.d.ts.map +1 -1
- package/dist/serve/runtime/manifest.js +1 -1
- package/dist/serve/runtime/manifest.js.map +1 -1
- package/dist/serve/runtime/status.d.ts.map +1 -1
- package/dist/serve/runtime/status.js +23 -0
- package/dist/serve/runtime/status.js.map +1 -1
- package/dist/serve/sandbox-session.d.ts +8 -0
- package/dist/serve/sandbox-session.d.ts.map +1 -1
- package/dist/serve/sandbox-session.js +12 -4
- package/dist/serve/sandbox-session.js.map +1 -1
- package/dist/serve/server.d.ts +7 -0
- package/dist/serve/server.d.ts.map +1 -1
- package/dist/serve/server.js +15 -1
- package/dist/serve/server.js.map +1 -1
- package/dist/serve/site-ui/404.html +1 -1
- package/dist/serve/site-ui/_astro/{RulesCodeEditor.Bl-XMkhD.js → RulesCodeEditor.DsTAsKIa.js} +1 -1
- package/dist/serve/site-ui/_astro/_slug_.Da5VLhW1.css +1 -0
- package/dist/serve/site-ui/_astro/_studio_.BnfYCKoI.css +1 -0
- package/dist/serve/site-ui/_astro/app.BOr2kwae.js +115 -0
- package/dist/serve/site-ui/_astro/app.DhAcImFD.js +1 -0
- package/dist/serve/site-ui/_astro/app.pMSnN6Qw.css +1 -0
- package/dist/serve/site-ui/_astro/{chess-showcase.Dh5D8kqe.js → chess-showcase.Bn_pP6UJ.js} +2 -2
- package/dist/serve/site-ui/_astro/{example-runtime.CuyAjjiG.js → example-runtime.CXopTGv7.js} +1 -1
- package/dist/serve/site-ui/_astro/index.Tb-31efc.css +1 -0
- package/dist/serve/site-ui/_astro/index.UkCBr-_0.css +1 -0
- package/dist/serve/site-ui/_astro/sandbox-controls.rOuZTOUG.js +510 -0
- package/dist/serve/site-ui/_astro/{seed.CSUkloMi.js → seed.03a08f9t.js} +2 -2
- package/dist/serve/site-ui/_astro/writes.BsPBG3dp.js +653 -0
- package/dist/serve/site-ui/auth/index.html +5 -3
- package/dist/serve/site-ui/david-east.jpg +0 -0
- package/dist/serve/site-ui/docs/_rhythm/index.html +6 -3
- package/dist/serve/site-ui/docs/_rhythm.md +1 -1
- package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +18 -15
- package/dist/serve/site-ui/docs/agent/set-up-your-agent.md +16 -16
- package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +6 -5
- package/dist/serve/site-ui/docs/agent/watch-and-review.md +1 -5
- package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +8 -5
- package/dist/serve/site-ui/docs/agent/work-with-an-agent.md +4 -4
- package/dist/serve/site-ui/docs/ai-compat/index.html +5 -2
- package/dist/serve/site-ui/docs/api-reference/index.html +13 -2
- package/dist/serve/site-ui/docs/api-reference.md +8 -0
- package/dist/serve/site-ui/docs/app-compat/index.html +5 -2
- package/dist/serve/site-ui/docs/auth-compat/index.html +7 -4
- package/dist/serve/site-ui/docs/auth-compat.md +2 -2
- package/dist/serve/site-ui/docs/build/ai-logic/index.html +10 -2
- package/dist/serve/site-ui/docs/build/ai-logic.md +6 -0
- package/dist/serve/site-ui/docs/build/authentication/index.html +7 -4
- package/dist/serve/site-ui/docs/build/authentication.md +2 -2
- package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +5 -2
- package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +5 -2
- package/dist/serve/site-ui/docs/build/cloud-storage/index.html +6 -3
- package/dist/serve/site-ui/docs/build/cloud-storage.md +1 -1
- package/dist/serve/site-ui/docs/build/realtime-database/index.html +9 -6
- package/dist/serve/site-ui/docs/build/realtime-database.md +4 -4
- package/dist/serve/site-ui/docs/conformance-scores/index.html +10 -3
- package/dist/serve/site-ui/docs/conformance-scores.md +5 -1
- package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +6 -3
- package/dist/serve/site-ui/docs/create-pyric-reference-api.md +1 -1
- package/dist/serve/site-ui/docs/database-compat/index.html +48 -45
- package/dist/serve/site-ui/docs/database-compat.md +43 -43
- package/dist/serve/site-ui/docs/examples/chess/index.html +5 -2
- package/dist/serve/site-ui/docs/examples/index.html +5 -2
- package/dist/serve/site-ui/docs/firestore-compat/index.html +8 -5
- package/dist/serve/site-ui/docs/firestore-compat.md +3 -3
- package/dist/serve/site-ui/docs/firestore-flutter-compat/index.html +319 -0
- package/dist/serve/site-ui/docs/firestore-flutter-compat.md +344 -0
- package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +5 -2
- package/dist/serve/site-ui/docs/get-started/backend-bundlers/index.html +105 -0
- package/dist/serve/site-ui/docs/get-started/backend-bundlers.md +165 -0
- package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +9 -6
- package/dist/serve/site-ui/docs/get-started/how-the-swap-works.md +5 -5
- package/dist/serve/site-ui/docs/get-started/nextjs/index.html +9 -6
- package/dist/serve/site-ui/docs/get-started/nextjs.md +4 -4
- package/dist/serve/site-ui/docs/get-started/start-building/index.html +14 -9
- package/dist/serve/site-ui/docs/get-started/start-building.md +16 -10
- package/dist/serve/site-ui/docs/get-started/vite/index.html +6 -3
- package/dist/serve/site-ui/docs/get-started/vite.md +1 -1
- package/dist/serve/site-ui/docs/index.json +3128 -1613
- package/dist/serve/site-ui/docs/messaging-compat/index.html +5 -2
- package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +5 -2
- package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +6 -4
- package/dist/serve/site-ui/docs/observe/see-whats-happening.md +2 -4
- package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +9 -6
- package/dist/serve/site-ui/docs/observe/shape-your-data.md +4 -4
- package/dist/serve/site-ui/docs/overview/index.html +16 -10
- package/dist/serve/site-ui/docs/overview.md +19 -11
- package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +8 -5
- package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api.md +3 -3
- package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-admin-reference-api/index.html +501 -0
- package/dist/serve/site-ui/docs/pyric-admin-reference-api.md +587 -0
- package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-analytics-reference-api/index.html +124 -0
- package/dist/serve/site-ui/docs/pyric-analytics-reference-api.md +287 -0
- package/dist/serve/site-ui/docs/pyric-app-check-reference-api/index.html +87 -0
- package/dist/serve/site-ui/docs/pyric-app-check-reference-api.md +199 -0
- package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +10 -3
- package/dist/serve/site-ui/docs/pyric-auth-reference-api.md +2 -1
- package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +6 -3
- package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api.md +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api/index.html +56 -0
- package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api.md +72 -0
- package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +6 -2
- package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api.md +1 -0
- package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +6 -2
- package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api.md +1 -0
- package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +6 -3
- package/dist/serve/site-ui/docs/pyric-cli-next-reference-api.md +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +39 -11
- package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api.md +17 -9
- package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +137 -94
- package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api.md +61 -1
- package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +6 -3
- package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api.md +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +6 -3
- package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api.md +2 -2
- package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +167 -96
- package/dist/serve/site-ui/docs/pyric-database-reference-api.md +108 -2
- package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api/index.html +559 -0
- package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api.md +1240 -0
- package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +44 -12
- package/dist/serve/site-ui/docs/pyric-firestore-reference-api.md +18 -8
- package/dist/serve/site-ui/docs/pyric-functions-reference-api/index.html +67 -0
- package/dist/serve/site-ui/docs/pyric-functions-reference-api.md +149 -0
- package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +10 -4
- package/dist/serve/site-ui/docs/pyric-messaging-reference-api.md +5 -2
- package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +10 -4
- package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api.md +5 -2
- package/dist/serve/site-ui/docs/pyric-performance-reference-api/index.html +35 -0
- package/dist/serve/site-ui/docs/pyric-performance-reference-api.md +69 -0
- package/dist/serve/site-ui/docs/pyric-remote-config-reference-api/index.html +132 -0
- package/dist/serve/site-ui/docs/pyric-remote-config-reference-api.md +307 -0
- package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +56 -18
- package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api.md +48 -9
- package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +6 -3
- package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api.md +2 -2
- package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +243 -50
- package/dist/serve/site-ui/docs/pyric-sandbox-reference-api.md +148 -31
- package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +26 -5
- package/dist/serve/site-ui/docs/pyric-storage-reference-api.md +24 -2
- package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +30 -97
- package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api.md +20 -51
- package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +6 -3
- package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api.md +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +6 -3
- package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api.md +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +128 -27
- package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api.md +58 -5
- package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +8 -6
- package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api.md +3 -4
- package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +5 -2
- package/dist/serve/site-ui/docs/reference/cli/index.html +156 -0
- package/dist/serve/site-ui/docs/reference/cli.md +120 -0
- package/dist/serve/site-ui/docs/rules-compat/index.html +14 -3
- package/dist/serve/site-ui/docs/rules-compat.md +9 -1
- package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +5 -2
- package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +5 -2
- package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +6 -3
- package/dist/serve/site-ui/docs/secure/read-a-denial.md +1 -1
- package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +5 -2
- package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +5 -2
- package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +5 -2
- package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +5 -2
- package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +5 -2
- package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +7 -4
- package/dist/serve/site-ui/docs/ship/ship-to-production.md +2 -2
- package/dist/serve/site-ui/docs/ship/test-in-node/index.html +9 -6
- package/dist/serve/site-ui/docs/ship/test-in-node.md +4 -4
- package/dist/serve/site-ui/docs/storage-compat/index.html +17 -14
- package/dist/serve/site-ui/docs/storage-compat.md +12 -12
- package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +5 -2
- package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +5 -2
- package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +5 -2
- package/dist/serve/site-ui/docs/tutorial/index.html +10 -7
- package/dist/serve/site-ui/docs/tutorial.md +4 -4
- package/dist/serve/site-ui/examples/chess/index.html +4 -2
- package/dist/serve/site-ui/firestore/index.html +5 -3
- package/dist/serve/site-ui/hero-charcoal.jpg +0 -0
- package/dist/serve/site-ui/index.html +9 -7
- package/dist/serve/site-ui/llms.txt +13 -3
- package/dist/serve/site-ui/pyric-campfire-full.png +0 -0
- package/dist/serve/site-ui/pyric-campfire.png +0 -0
- package/dist/serve/site-ui/rtdb/index.html +5 -3
- package/dist/serve/site-ui/settings/index.html +5 -3
- package/dist/serve/site-ui/storage/index.html +5 -3
- package/dist/serve/site-ui/studio/index.html +13 -0
- package/dist/serve/site-ui/studio-routes.json +1 -1
- package/dist/serve/site-ui/traffic/index.html +5 -3
- package/dist/serve/studio/disk-workspace.d.ts.map +1 -1
- package/dist/serve/studio/disk-workspace.js +64 -2
- package/dist/serve/studio/disk-workspace.js.map +1 -1
- package/dist/serve/studio/routes.d.ts +9 -0
- package/dist/serve/studio/routes.d.ts.map +1 -1
- package/dist/serve/studio/routes.js +47 -7
- package/dist/serve/studio/routes.js.map +1 -1
- package/dist/serve/vite-ai-config.d.ts.map +1 -1
- package/dist/serve/vite-ai-config.js +38 -8
- package/dist/serve/vite-ai-config.js.map +1 -1
- package/dist/serve/vite-module-swap.d.ts.map +1 -1
- package/dist/serve/vite-module-swap.js +0 -28
- package/dist/serve/vite-module-swap.js.map +1 -1
- package/dist/serve/vite-plugin.d.ts +7 -7
- package/dist/serve/vite-plugin.js +1 -1
- package/dist/serve/vite-plugin.js.map +1 -1
- package/dist/serve/vite-sandbox-generation.d.ts +1 -1
- package/dist/serve/vite-sandbox-generation.d.ts.map +1 -1
- package/dist/serve/vite-sandbox-generation.js +13 -1
- package/dist/serve/vite-sandbox-generation.js.map +1 -1
- package/dist/serve/worker/client/auth.js +1 -2
- package/dist/serve/worker/client/auth.js.map +1 -1
- package/dist/serve/worker/client/core.d.ts +21 -1
- package/dist/serve/worker/client/core.d.ts.map +1 -1
- package/dist/serve/worker/client/core.js +79 -3
- package/dist/serve/worker/client/core.js.map +1 -1
- package/dist/serve/worker/client/disconnect.js +1 -1
- package/dist/serve/worker/client/disconnect.js.map +1 -1
- package/dist/serve/worker/client/presence.d.ts.map +1 -1
- package/dist/serve/worker/client/presence.js +18 -5
- package/dist/serve/worker/client/presence.js.map +1 -1
- package/dist/serve/worker/client.d.ts +1 -1
- package/dist/serve/worker/client.d.ts.map +1 -1
- package/dist/serve/worker/client.js +1 -1
- package/dist/serve/worker/client.js.map +1 -1
- package/dist/serve/worker/context-resolver.d.ts +30 -0
- package/dist/serve/worker/context-resolver.d.ts.map +1 -0
- package/dist/serve/worker/context-resolver.js +44 -0
- package/dist/serve/worker/context-resolver.js.map +1 -0
- package/dist/serve/worker/entry.js +23 -19
- package/dist/serve/worker/entry.js.map +1 -1
- package/dist/serve/worker/host/core.d.ts +1 -0
- package/dist/serve/worker/host/core.d.ts.map +1 -1
- package/dist/serve/worker/host/core.js +12 -6
- package/dist/serve/worker/host/core.js.map +1 -1
- package/dist/serve/worker/host/storage.js +2 -2
- package/dist/serve/worker/host-ai.d.ts.map +1 -1
- package/dist/serve/worker/host-ai.js +15 -0
- package/dist/serve/worker/host-ai.js.map +1 -1
- package/dist/serve/worker/host-auth.js +1 -2
- package/dist/serve/worker/host-auth.js.map +1 -1
- package/dist/serve/worker/index.d.ts +1 -1
- package/dist/serve/worker/index.d.ts.map +1 -1
- package/dist/serve/worker/index.js +2 -2
- package/dist/serve/worker/index.js.map +1 -1
- package/dist/serve/worker/port-lifecycle.d.ts +18 -0
- package/dist/serve/worker/port-lifecycle.d.ts.map +1 -0
- package/dist/serve/worker/port-lifecycle.js +28 -0
- package/dist/serve/worker/port-lifecycle.js.map +1 -0
- package/dist/serve/worker/protocol.d.ts +4 -0
- package/dist/serve/worker/protocol.d.ts.map +1 -1
- package/dist/serve/worker/protocol.js.map +1 -1
- package/dist/serve/worker/serve-init.d.ts.map +1 -1
- package/dist/serve/worker/serve-init.js +15 -3
- package/dist/serve/worker/serve-init.js.map +1 -1
- package/dist/verify/fixture.d.ts +1 -1
- package/package.json +17 -6
- package/src/assurance/.generated/conformance-verdicts.ts +68 -1
- package/src/bridge/client/dispatch.ts +52 -56
- package/src/bridge/client/tool-family-factories.ts +34 -0
- package/src/bridge/server/mcp-contract.ts +15 -59
- package/src/bridge/server/peer.ts +24 -1
- package/src/bridge/server/tool-family-factories.ts +40 -0
- package/src/bridge/server/tool-metadata.ts +29 -61
- package/src/bridge/tool-families.generated.ts +17 -0
- package/src/bridge/tool-families.ts +87 -0
- package/src/bridge/tool-family-records/conformance.ts +6 -0
- package/src/bridge/tool-family-records/firestore-data.ts +15 -0
- package/src/bridge/tool-family-records/firestore-inspect.ts +6 -0
- package/src/bridge/tool-family-records/firestore-rules.ts +15 -0
- package/src/bridge/tool-family-records/firestore-simulator.ts +16 -0
- package/src/bridge/tool-family-records/rtdb-inspection.ts +6 -0
- package/src/bundler/externals.ts +55 -0
- package/src/bundler/index.ts +21 -0
- package/src/cli/cli.test.ts +2 -46
- package/src/cli/index.ts +48 -42
- package/src/cli/inlined-sdk-scanner.ts +77 -0
- package/src/cli/mcp-proxy.ts +4 -4
- package/src/cli/parse-args.ts +61 -15
- package/src/cli/pyric-config.ts +45 -0
- package/src/cli/sandbox-interlock.ts +167 -0
- package/src/cli/{dev-runner.ts → sandbox-runner.ts} +142 -86
- package/src/cli/serve.ts +182 -115
- package/src/cli/snapshot.ts +5 -5
- package/src/cli/unsupported-runtime.ts +68 -0
- package/src/cli/verify.ts +1 -1
- package/src/conformance/.generated/can-i-use-browser.ts +2 -2
- package/src/conformance/.generated/can-i-use.ts +2 -2
- package/src/conformance/.generated/conformance-docs.ts +1 -1
- package/src/functions-rtdb/child.ts +115 -21
- package/src/functions-rtdb/development-runtime.ts +5 -1
- package/src/functions-rtdb/project.ts +8 -8
- package/src/google-endpoints.ts +155 -0
- package/src/next/guard.ts +1 -1
- package/src/next/runtime-env.ts +5 -0
- package/src/next/with-pyric.ts +1 -1
- package/src/register/beacon.ts +232 -0
- package/src/register/index.ts +68 -6
- package/src/register/net-guard.ts +567 -0
- package/src/remote/index.ts +9 -9
- package/src/serve/ai-diagnostics-relay.ts +243 -0
- package/src/serve/ai-proxy.ts +327 -0
- package/src/serve/ai-status.ts +109 -0
- package/src/serve/ai-terminal-blocks.ts +210 -0
- package/src/serve/ai-terminal-text.ts +52 -0
- package/src/serve/beacon-route.ts +141 -0
- package/src/serve/bundler.ts +10 -10
- package/src/serve/entries/active-auth-registry.ts +56 -0
- package/src/serve/entries/active-auth.ts +100 -0
- package/src/serve/entries/ai.ts +27 -1
- package/src/serve/entries/auth-helper-core.ts +5 -0
- package/src/serve/entries/auth-helper-dom.ts +27 -3
- package/src/serve/entries/auth-helper-runtime.ts +1 -1
- package/src/serve/entries/auth.ts +8 -0
- package/src/serve/entries/bridge-url.ts +1 -1
- package/src/serve/entries/firestore.ts +3 -3
- package/src/serve/entries/init.ts +78 -3
- package/src/serve/entries/keepalive.ts +1 -1
- package/src/serve/entries/runtime.ts +29 -14
- package/src/serve/entries/storage.ts +1 -1
- package/src/serve/entries/worker-runtime.ts +1 -1
- package/src/serve/init-payload.ts +4 -0
- package/src/serve/namespace.ts +117 -145
- package/src/serve/rules.ts +47 -22
- package/src/serve/runtime/chip-config.ts +16 -2
- package/src/serve/runtime/chip-dialog.ts +366 -0
- package/src/serve/runtime/chip-install.ts +10 -4
- package/src/serve/runtime/chip-user-search.ts +391 -0
- package/src/serve/runtime/chip.ts +177 -15
- package/src/serve/runtime/identity.ts +26 -0
- package/src/serve/runtime/manifest.ts +1 -1
- package/src/serve/runtime/status.ts +24 -0
- package/src/serve/sandbox-session.ts +19 -4
- package/src/serve/server.ts +18 -1
- package/src/serve/studio/disk-workspace.ts +76 -2
- package/src/serve/studio/routes.ts +63 -7
- package/src/serve/vite-ai-config.ts +37 -7
- package/src/serve/vite-module-swap.ts +0 -28
- package/src/serve/vite-plugin.ts +8 -8
- package/src/serve/vite-sandbox-generation.ts +16 -1
- package/src/serve/worker/client/auth.ts +1 -1
- package/src/serve/worker/client/core.ts +80 -3
- package/src/serve/worker/client/disconnect.ts +1 -1
- package/src/serve/worker/client/presence.ts +25 -5
- package/src/serve/worker/client.ts +1 -1
- package/src/serve/worker/context-resolver.ts +60 -0
- package/src/serve/worker/entry.ts +22 -18
- package/src/serve/worker/host/core.ts +9 -7
- package/src/serve/worker/host/storage.ts +2 -2
- package/src/serve/worker/host-ai.ts +15 -0
- package/src/serve/worker/host-auth.ts +1 -1
- package/src/serve/worker/index.ts +4 -1
- package/src/serve/worker/port-lifecycle.ts +45 -0
- package/src/serve/worker/protocol.ts +2 -1
- package/src/serve/worker/serve-init.ts +14 -3
- package/src/verify/fixture.ts +1 -1
- package/README.md.orig +0 -145
- package/dist/cli/dev-runner.d.ts.map +0 -1
- package/dist/cli/dev-runner.js.map +0 -1
- package/dist/serve/site-ui/_astro/_slug_.CXh9yTP1.css +0 -1
- package/dist/serve/site-ui/_astro/_slug_.CupVK4TM.css +0 -1
- package/dist/serve/site-ui/_astro/_studio_.CfxiQWkk.css +0 -1
- package/dist/serve/site-ui/_astro/app.BsFsMjn0.css +0 -1
- package/dist/serve/site-ui/_astro/app.Ce3MTLQm.js +0 -1
- package/dist/serve/site-ui/_astro/app.taqzyjD0.js +0 -11
- package/dist/serve/site-ui/_astro/sandbox-controls.BP4M5f1M.js +0 -1169
- package/dist/serve/site-ui/_astro/writes.C57paAj2.js +0 -99
- package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research/index.html +0 -582
- package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research.md +0 -448
|
@@ -97,34 +97,128 @@ function isChildMessage(value: unknown): value is FunctionsRtdbChildMessage {
|
|
|
97
97
|
return typeof value === 'object' && value !== null && 'type' in value;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
export interface FunctionsChildEnvOptions {
|
|
101
|
+
baseEnv: NodeJS.ProcessEnv;
|
|
102
|
+
entry: string;
|
|
103
|
+
instance: string;
|
|
104
|
+
location: string;
|
|
105
|
+
databaseHost: string;
|
|
106
|
+
projectId: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Resolve the project identifier for the functions child process.
|
|
111
|
+
*
|
|
112
|
+
* Precedence:
|
|
113
|
+
* 1. Explicit options.projectId
|
|
114
|
+
* 2. baseEnv.PYRIC_PROJECT
|
|
115
|
+
* 3. Instance prefix when formatted as `<projectId>-default-rtdb`
|
|
116
|
+
* 4. Default fallback to 'demo-project'
|
|
117
|
+
*/
|
|
118
|
+
export function resolveChildProjectId(
|
|
119
|
+
explicitProjectId?: string,
|
|
120
|
+
instance?: string,
|
|
121
|
+
baseEnv?: NodeJS.ProcessEnv,
|
|
122
|
+
): string {
|
|
123
|
+
if (typeof explicitProjectId === 'string' && explicitProjectId.length > 0) {
|
|
124
|
+
return explicitProjectId;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const pyricProject = baseEnv?.PYRIC_PROJECT;
|
|
128
|
+
if (typeof pyricProject === 'string' && pyricProject.length > 0) {
|
|
129
|
+
return pyricProject;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (typeof instance === 'string' && instance.length > 0) {
|
|
133
|
+
const stripped = instance.replace(/-default-rtdb$/, '');
|
|
134
|
+
if (stripped.length > 0) {
|
|
135
|
+
return stripped;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return 'demo-project';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Resolve the database host, defaulting to 'firebasedatabase.app'.
|
|
144
|
+
*/
|
|
145
|
+
export function resolveChildDatabaseHost(databaseHost?: string): string {
|
|
146
|
+
if (typeof databaseHost === 'string' && databaseHost.length > 0) {
|
|
147
|
+
return databaseHost;
|
|
148
|
+
}
|
|
149
|
+
return 'firebasedatabase.app';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Resolve the filesystem path to the child entrypoint module.
|
|
154
|
+
*/
|
|
155
|
+
export function resolveChildModulePath(childModuleUrl?: string | URL): string {
|
|
156
|
+
if (!childModuleUrl) {
|
|
157
|
+
return fileURLToPath(new URL('./child.js', import.meta.url));
|
|
158
|
+
}
|
|
159
|
+
if (typeof childModuleUrl === 'string' && !childModuleUrl.startsWith('file:')) {
|
|
160
|
+
return resolve(childModuleUrl);
|
|
161
|
+
}
|
|
162
|
+
return fileURLToPath(childModuleUrl);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Assemble the child process environment variables.
|
|
167
|
+
*
|
|
168
|
+
* Guaranteed child-only synthetic sandbox metadata:
|
|
169
|
+
* - GCLOUD_PROJECT is set to the resolved sandbox project ID
|
|
170
|
+
* - FIREBASE_CONFIG is set to synthetic JSON with projectId, databaseURL, and storageBucket
|
|
171
|
+
*
|
|
172
|
+
* Explicit control flow ensures that host environment cannot pollute or route
|
|
173
|
+
* sandbox functions execution to a production Firebase/GCP project.
|
|
174
|
+
*/
|
|
175
|
+
export function buildFunctionsChildEnv(options: FunctionsChildEnvOptions): NodeJS.ProcessEnv {
|
|
176
|
+
const { baseEnv, entry, instance, location, databaseHost, projectId } = options;
|
|
177
|
+
|
|
178
|
+
const resolvedEntry = resolve(entry);
|
|
179
|
+
const databaseURL = `https://${instance}.${databaseHost}`;
|
|
180
|
+
const storageBucket = `${projectId}.appspot.com`;
|
|
181
|
+
|
|
182
|
+
const syntheticFirebaseConfig = JSON.stringify({
|
|
183
|
+
projectId,
|
|
184
|
+
databaseURL,
|
|
185
|
+
storageBucket,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const childEnv: NodeJS.ProcessEnv = {
|
|
189
|
+
...baseEnv,
|
|
190
|
+
PYRIC_FUNCTIONS_RTDB_CHILD: '1',
|
|
191
|
+
PYRIC_FUNCTIONS_ENTRY: resolvedEntry,
|
|
192
|
+
PYRIC_FUNCTIONS_INSTANCE: instance,
|
|
193
|
+
PYRIC_FUNCTIONS_LOCATION: location,
|
|
194
|
+
PYRIC_FUNCTIONS_DATABASE_HOST: databaseHost,
|
|
195
|
+
GCLOUD_PROJECT: projectId,
|
|
196
|
+
FIREBASE_CONFIG: syntheticFirebaseConfig,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
return childEnv;
|
|
200
|
+
}
|
|
201
|
+
|
|
100
202
|
/** Spawn the real Firebase Functions SDK in an isolated Node process. */
|
|
101
203
|
export function spawnFunctionsRtdbChild(
|
|
102
204
|
options: SpawnFunctionsRtdbChildOptions,
|
|
103
205
|
): FunctionsRtdbChildHandle {
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
206
|
+
const childModulePath = resolveChildModulePath(options.childModuleUrl);
|
|
207
|
+
const projectId = resolveChildProjectId(options.projectId, options.instance, options.env);
|
|
208
|
+
const databaseHost = resolveChildDatabaseHost(options.databaseHost);
|
|
209
|
+
const childEnv = buildFunctionsChildEnv({
|
|
210
|
+
baseEnv: options.env,
|
|
211
|
+
entry: options.entry,
|
|
212
|
+
instance: options.instance,
|
|
213
|
+
location: options.location,
|
|
214
|
+
databaseHost,
|
|
112
215
|
projectId,
|
|
113
|
-
databaseURL,
|
|
114
|
-
storageBucket: `${projectId}.appspot.com`,
|
|
115
216
|
});
|
|
116
|
-
|
|
217
|
+
|
|
218
|
+
const nodeExecutable = options.nodeExecutable ?? 'node';
|
|
219
|
+
const child = spawn(nodeExecutable, [childModulePath], {
|
|
117
220
|
cwd: options.cwd,
|
|
118
|
-
env:
|
|
119
|
-
...options.env,
|
|
120
|
-
PYRIC_FUNCTIONS_RTDB_CHILD: '1',
|
|
121
|
-
PYRIC_FUNCTIONS_ENTRY: resolve(options.entry),
|
|
122
|
-
PYRIC_FUNCTIONS_INSTANCE: options.instance,
|
|
123
|
-
PYRIC_FUNCTIONS_LOCATION: options.location,
|
|
124
|
-
PYRIC_FUNCTIONS_DATABASE_HOST: databaseHost,
|
|
125
|
-
GCLOUD_PROJECT: options.env.GCLOUD_PROJECT ?? projectId,
|
|
126
|
-
FIREBASE_CONFIG: options.env.FIREBASE_CONFIG ?? firebaseConfig,
|
|
127
|
-
},
|
|
221
|
+
env: childEnv,
|
|
128
222
|
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
129
223
|
});
|
|
130
224
|
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type FunctionsRtdbChildReady,
|
|
7
7
|
type SpawnFunctionsRtdbChildOptions,
|
|
8
8
|
} from './child.js';
|
|
9
|
-
import { buildChildEnv, createLinePrefixer } from '../cli/
|
|
9
|
+
import { buildChildEnv, createLinePrefixer } from '../cli/sandbox-runner.js';
|
|
10
10
|
|
|
11
11
|
const INITIAL_PEER_TIMEOUT_MS = 30_000;
|
|
12
12
|
const RELOAD_PEER_TIMEOUT_MS = 5_000;
|
|
@@ -38,6 +38,9 @@ export interface FunctionsDevelopmentRuntimeOptions {
|
|
|
38
38
|
baseEnv: NodeJS.ProcessEnv;
|
|
39
39
|
serveUrl: string;
|
|
40
40
|
registerUrl: string;
|
|
41
|
+
/** The per-launch secret this child's handshake beacon must present.
|
|
42
|
+
* Absent when the host runs no beacon receiver. */
|
|
43
|
+
beaconToken?: string | undefined;
|
|
41
44
|
instance: string;
|
|
42
45
|
location: string;
|
|
43
46
|
projectId?: string;
|
|
@@ -216,6 +219,7 @@ export function createFunctionsDevelopmentRuntime(
|
|
|
216
219
|
env: buildChildEnv(options.baseEnv, {
|
|
217
220
|
serveUrl: options.serveUrl,
|
|
218
221
|
registerUrl: options.registerUrl,
|
|
222
|
+
beaconToken: options.beaconToken,
|
|
219
223
|
}),
|
|
220
224
|
instance: options.instance,
|
|
221
225
|
location: options.location,
|
|
@@ -22,7 +22,7 @@ export function discoverFunctionsRtdbProject(cwd: string): FunctionsRtdbProject
|
|
|
22
22
|
config = JSON.parse(readFileSync(firebaseJsonPath, 'utf8')) as FirebaseJson;
|
|
23
23
|
} catch (error) {
|
|
24
24
|
throw new Error(
|
|
25
|
-
`pyric
|
|
25
|
+
`pyric sandbox: failed to parse firebase.json while discovering Functions: ` +
|
|
26
26
|
`${error instanceof Error ? error.message : String(error)}`,
|
|
27
27
|
);
|
|
28
28
|
}
|
|
@@ -33,23 +33,23 @@ export function discoverFunctionsRtdbProject(cwd: string): FunctionsRtdbProject
|
|
|
33
33
|
: [config.functions as FunctionsConfig];
|
|
34
34
|
if (declared.length !== 1) {
|
|
35
35
|
throw new Error(
|
|
36
|
-
'pyric
|
|
36
|
+
'pyric sandbox: multiple Functions codebases are not supported by the first ' +
|
|
37
37
|
'onValueCreated slice; configure one source for this development session.',
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
const functions = declared[0];
|
|
41
41
|
if (typeof functions !== 'object' || functions === null) {
|
|
42
|
-
throw new Error('pyric
|
|
42
|
+
throw new Error('pyric sandbox: firebase.json `functions` must be an object with a source.');
|
|
43
43
|
}
|
|
44
44
|
if (functions.source !== undefined && typeof functions.source !== 'string') {
|
|
45
|
-
throw new Error('pyric
|
|
45
|
+
throw new Error('pyric sandbox: firebase.json `functions.source` must be a string.');
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
const sourceDir = resolve(cwd, functions.source ?? 'functions');
|
|
49
49
|
const packageJsonPath = join(sourceDir, 'package.json');
|
|
50
50
|
if (!existsSync(packageJsonPath)) {
|
|
51
51
|
throw new Error(
|
|
52
|
-
`pyric
|
|
52
|
+
`pyric sandbox: Functions source is declared but ${packageJsonPath} does not exist.`,
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -58,17 +58,17 @@ export function discoverFunctionsRtdbProject(cwd: string): FunctionsRtdbProject
|
|
|
58
58
|
packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { main?: unknown };
|
|
59
59
|
} catch (error) {
|
|
60
60
|
throw new Error(
|
|
61
|
-
`pyric
|
|
61
|
+
`pyric sandbox: failed to parse ${packageJsonPath}: ` +
|
|
62
62
|
`${error instanceof Error ? error.message : String(error)}`,
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
if (packageJson.main !== undefined && typeof packageJson.main !== 'string') {
|
|
66
|
-
throw new Error(`pyric
|
|
66
|
+
throw new Error(`pyric sandbox: ${packageJsonPath} \`main\` must be a string.`);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
const entry = resolve(sourceDir, packageJson.main ?? 'index.js');
|
|
70
70
|
if (!existsSync(entry) || !statSync(entry).isFile()) {
|
|
71
|
-
throw new Error(`pyric
|
|
71
|
+
throw new Error(`pyric sandbox: Functions entry does not exist: ${entry}`);
|
|
72
72
|
}
|
|
73
73
|
return { sourceDir, entry };
|
|
74
74
|
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single shared source of Google/Firebase production endpoint hosts.
|
|
3
|
+
*
|
|
4
|
+
* Two readers consume this table and they must never drift apart:
|
|
5
|
+
* - the runtime net guard (`register/net-guard.ts`), which matches every
|
|
6
|
+
* catalog host on egress from a pyric-launched child;
|
|
7
|
+
* - the throwing frontend build check (`cli/inlined-sdk-scanner.ts`), which
|
|
8
|
+
* greps served assets for the narrower SDK fingerprint subset below.
|
|
9
|
+
*
|
|
10
|
+
* It lives at the package root, not under `cli/` or `register/`, so both
|
|
11
|
+
* import it without a cycle, and it has zero imports so the `--import`ed
|
|
12
|
+
* register entry stays cheap.
|
|
13
|
+
*
|
|
14
|
+
* Membership rule: a host belongs here only if it is real-SDK-only, meaning it
|
|
15
|
+
* can never legitimately be contacted by a sandbox-clean app (whose Firebase
|
|
16
|
+
* traffic all routes to the local `/__pyric/*` namespace). User-configured
|
|
17
|
+
* upstreams (BYOK AI base URLs, app APIs) are handled by the guard's
|
|
18
|
+
* allowlist, not by omission from this table.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** One production endpoint host and the service it belongs to. */
|
|
22
|
+
export interface GoogleEndpoint {
|
|
23
|
+
/** Registrable host or host suffix. Matched by label-boundary suffix. */
|
|
24
|
+
readonly host: string;
|
|
25
|
+
/** Human-readable service name, used verbatim in guard and scanner messages. */
|
|
26
|
+
readonly service: string;
|
|
27
|
+
/**
|
|
28
|
+
* Blocked from day one rather than warn-first. Reserved for egress that is
|
|
29
|
+
* never explainable as a false positive, currently only the GCE/GKE metadata
|
|
30
|
+
* server, whose only purpose here would be credential theft.
|
|
31
|
+
*/
|
|
32
|
+
readonly alwaysBlock?: true;
|
|
33
|
+
/**
|
|
34
|
+
* True when the host string is evidence that real Firebase SDK code was
|
|
35
|
+
* compiled into a build artifact. Only these hosts feed the throwing
|
|
36
|
+
* frontend build check, because that check fails a build outright.
|
|
37
|
+
*
|
|
38
|
+
* False for a host an ordinary app can carry without any SDK: a public Cloud
|
|
39
|
+
* Storage asset URL, a bare callable URL on `cloudfunctions.net`, a
|
|
40
|
+
* `databaseURL` config literal on `firebaseio.com`, a Vertex AI call from a
|
|
41
|
+
* hand-written client, a server-side FCM send, an admin control plane, or an
|
|
42
|
+
* infrastructure reference to the metadata server. The net guard still
|
|
43
|
+
* matches all of them on the wire.
|
|
44
|
+
*/
|
|
45
|
+
readonly fingerprint: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const GOOGLE_ENDPOINT_CATALOG: readonly GoogleEndpoint[] = [
|
|
49
|
+
// Identity. Both are reached by the Auth SDK and by nothing else.
|
|
50
|
+
{ host: 'identitytoolkit.googleapis.com', service: 'Firebase Authentication', fingerprint: true },
|
|
51
|
+
{
|
|
52
|
+
host: 'securetoken.googleapis.com',
|
|
53
|
+
service: 'Firebase Authentication (token refresh)',
|
|
54
|
+
fingerprint: true,
|
|
55
|
+
},
|
|
56
|
+
// Firestore.
|
|
57
|
+
{ host: 'firestore.googleapis.com', service: 'Cloud Firestore', fingerprint: true },
|
|
58
|
+
// Realtime Database. `firebaseio.com` is the legacy/us-central1 host and is
|
|
59
|
+
// also the shape of a `databaseURL` config literal, so it does not
|
|
60
|
+
// fingerprint a build; `firebasedatabase.app` is the regional host.
|
|
61
|
+
{ host: 'firebaseio.com', service: 'Realtime Database', fingerprint: false },
|
|
62
|
+
{ host: 'firebasedatabase.app', service: 'Realtime Database', fingerprint: true },
|
|
63
|
+
// Cloud Storage. Both hosts appear in ordinary download and asset URLs, so
|
|
64
|
+
// neither fingerprints a build.
|
|
65
|
+
{
|
|
66
|
+
host: 'firebasestorage.googleapis.com',
|
|
67
|
+
service: 'Cloud Storage for Firebase',
|
|
68
|
+
fingerprint: false,
|
|
69
|
+
},
|
|
70
|
+
{ host: 'storage.googleapis.com', service: 'Cloud Storage', fingerprint: false },
|
|
71
|
+
// Cloud Functions: `cloudfunctions.net` is the data plane the callable SDK
|
|
72
|
+
// hits (`https://<region>-<project>.cloudfunctions.net/<fn>`) and is equally
|
|
73
|
+
// the shape of a hand-written fetch; `cloudfunctions.googleapis.com` is the
|
|
74
|
+
// admin/control plane, reached by deployment tooling.
|
|
75
|
+
{ host: 'cloudfunctions.net', service: 'Cloud Functions', fingerprint: false },
|
|
76
|
+
{
|
|
77
|
+
host: 'cloudfunctions.googleapis.com',
|
|
78
|
+
service: 'Cloud Functions (control plane)',
|
|
79
|
+
fingerprint: false,
|
|
80
|
+
},
|
|
81
|
+
// Messaging. `fcmregistrations` issues the token and only the SDK calls it;
|
|
82
|
+
// `fcm.googleapis.com` is the server-side send endpoint. Installations is
|
|
83
|
+
// the ID prerequisite every FCM/Remote Config bundle carries.
|
|
84
|
+
{
|
|
85
|
+
host: 'fcmregistrations.googleapis.com',
|
|
86
|
+
service: 'Firebase Cloud Messaging (registration)',
|
|
87
|
+
fingerprint: true,
|
|
88
|
+
},
|
|
89
|
+
{ host: 'fcm.googleapis.com', service: 'Firebase Cloud Messaging', fingerprint: false },
|
|
90
|
+
{
|
|
91
|
+
host: 'firebaseinstallations.googleapis.com',
|
|
92
|
+
service: 'Firebase Installations',
|
|
93
|
+
fingerprint: true,
|
|
94
|
+
},
|
|
95
|
+
// AI. The Firebase AI Logic host is SDK-only; raw Vertex AI is reachable
|
|
96
|
+
// from any HTTP client.
|
|
97
|
+
{ host: 'firebasevertexai.googleapis.com', service: 'Firebase AI Logic', fingerprint: true },
|
|
98
|
+
{ host: 'aiplatform.googleapis.com', service: 'Vertex AI', fingerprint: false },
|
|
99
|
+
// Credential exfiltration target. Never a false positive on the wire, and
|
|
100
|
+
// never evidence that an SDK was inlined.
|
|
101
|
+
{
|
|
102
|
+
host: '169.254.169.254',
|
|
103
|
+
service: 'GCE metadata server',
|
|
104
|
+
alwaysBlock: true,
|
|
105
|
+
fingerprint: false,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
host: 'metadata.google.internal',
|
|
109
|
+
service: 'GCE metadata server',
|
|
110
|
+
alwaysBlock: true,
|
|
111
|
+
fingerprint: false,
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The subset that is evidence of inlined SDK code, and the only set the
|
|
117
|
+
* throwing frontend build check may grep for. See
|
|
118
|
+
* {@link GoogleEndpoint.fingerprint}.
|
|
119
|
+
*/
|
|
120
|
+
export const SDK_FINGERPRINT_HOSTS: readonly string[] = GOOGLE_ENDPOINT_CATALOG.filter(
|
|
121
|
+
(e) => e.fingerprint,
|
|
122
|
+
).map((e) => e.host);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Catalog entries longest host first, so the narrowest suffix wins regardless
|
|
126
|
+
* of the order the entries are authored in
|
|
127
|
+
* (`firebasestorage.googleapis.com` before `storage.googleapis.com`).
|
|
128
|
+
*/
|
|
129
|
+
const CATALOG_BY_SPECIFICITY: readonly GoogleEndpoint[] = [...GOOGLE_ENDPOINT_CATALOG].sort(
|
|
130
|
+
(a, b) => b.host.length - a.host.length,
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
/** Trim, lowercase, and drop a trailing root dot. The one spelling of a
|
|
134
|
+
* hostname that every comparison in the guard and the catalog uses. */
|
|
135
|
+
export function normalizeHostname(value: string): string {
|
|
136
|
+
return value.trim().toLowerCase().replace(/\.$/, '');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Label-boundary suffix match: `x.example.com` matches `example.com`,
|
|
141
|
+
* `notexample.com` does not.
|
|
142
|
+
*/
|
|
143
|
+
export function matchesHostSuffix(hostname: string, suffix: string): boolean {
|
|
144
|
+
return hostname === suffix || hostname.endsWith(`.${suffix}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resolve a hostname to its catalog entry, or `undefined` when it is not a
|
|
149
|
+
* known production endpoint. Matches the exact host or a subdomain of it, on
|
|
150
|
+
* label boundaries, narrowest suffix first.
|
|
151
|
+
*/
|
|
152
|
+
export function lookupGoogleEndpoint(hostname: string): GoogleEndpoint | undefined {
|
|
153
|
+
const host = normalizeHostname(hostname);
|
|
154
|
+
return CATALOG_BY_SPECIFICITY.find((e) => matchesHostSuffix(host, e.host));
|
|
155
|
+
}
|
package/src/next/guard.ts
CHANGED
|
@@ -54,7 +54,7 @@ export function enforceSandboxGuard(options?: PyricNextOptions): void {
|
|
|
54
54
|
const errorMessage =
|
|
55
55
|
'[Pyric] Next.js development server started without active Pyric sandbox environment variables.\n' +
|
|
56
56
|
'To prevent accidental connections to production Firebase databases, launch this server using:\n' +
|
|
57
|
-
' pyric
|
|
57
|
+
' pyric sandbox -- next dev\n' +
|
|
58
58
|
'or source environment keys via `pyric env`.\n' +
|
|
59
59
|
'To disable this guard, pass { guard: false } to withPyric(config, options).';
|
|
60
60
|
throw new Error(errorMessage);
|
package/src/next/runtime-env.ts
CHANGED
|
@@ -12,6 +12,11 @@ export function augmentRuntimeEnv(config: NextConfigObject, options?: PyricNextO
|
|
|
12
12
|
const updatedConfig: NextConfigObject = Object.assign({}, config);
|
|
13
13
|
const existingEnv = updatedConfig.env !== undefined ? Object.assign({}, updatedConfig.env) : {};
|
|
14
14
|
const chipValue = runtimeChipMetaValue(options.runtimeChip);
|
|
15
|
+
// Next.js only inlines `.env`-sourced values into the browser bundle when the
|
|
16
|
+
// key carries the `NEXT_PUBLIC_` prefix, so client components must read the
|
|
17
|
+
// prefixed name. The unprefixed name is kept for backwards compatibility with
|
|
18
|
+
// any existing server-side or bundler-level readers of `PYRIC_RUNTIME_CHIP`.
|
|
19
|
+
existingEnv.NEXT_PUBLIC_PYRIC_RUNTIME_CHIP = chipValue;
|
|
15
20
|
existingEnv.PYRIC_RUNTIME_CHIP = chipValue;
|
|
16
21
|
updatedConfig.env = existingEnv;
|
|
17
22
|
return updatedConfig;
|
package/src/next/with-pyric.ts
CHANGED
|
@@ -25,7 +25,7 @@ function applyPyricEnhancements(config: NextConfigObject, options?: PyricNextOpt
|
|
|
25
25
|
/**
|
|
26
26
|
* Higher-order configuration wrapper for Next.js (`next.config.js` or `next.config.mjs`).
|
|
27
27
|
*
|
|
28
|
-
* During development mode (`pyric
|
|
28
|
+
* During development mode (`pyric sandbox` or non-production NODE_ENV):
|
|
29
29
|
* - Applies Webpack and Turbopack alias mappings to swap `firebase/*` imports
|
|
30
30
|
* for Pyric local sandbox mirrors on client components.
|
|
31
31
|
* - Adds `firebase` and `firebase-admin` to `serverExternalPackages` to prevent
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The handshake beacon: register's proof that interception is live in this
|
|
3
|
+
* process.
|
|
4
|
+
*
|
|
5
|
+
* `pyric sandbox` sets `PYRIC_SANDBOX` and appends `--import
|
|
6
|
+
* @pyric/cli/register` to the child's `NODE_OPTIONS`, and then assumes the
|
|
7
|
+
* rest. Every link in that chain is silently breakable by the user's own
|
|
8
|
+
* command: a `bun`/`deno` runner that never evaluates Node loader hooks, a
|
|
9
|
+
* script that overwrites `NODE_OPTIONS` wholesale, a `NODE_ENV=production`
|
|
10
|
+
* that trips the activation refusal, an intermediate process that strips the
|
|
11
|
+
* env. In every one of those cases the child comes up looking perfectly
|
|
12
|
+
* healthy while its `firebase-admin` and `firebase` imports resolve to the
|
|
13
|
+
* real SDKs and reach live Firebase.
|
|
14
|
+
*
|
|
15
|
+
* The beacon closes that gap the only honest way: the child says so itself,
|
|
16
|
+
* after the hooks and the net-guard are actually installed.
|
|
17
|
+
*
|
|
18
|
+
* Two channels, on purpose
|
|
19
|
+
* ------------------------
|
|
20
|
+
* 1. A fire-and-forget `POST <bridge>/__pyric/beacon`, whenever a bridge URL
|
|
21
|
+
* is knowable from the child's own env. That is the machine channel: it
|
|
22
|
+
* reaches the dev server across an arbitrary depth of intermediate
|
|
23
|
+
* processes (npm, then next, then its worker), where stderr scraping stops
|
|
24
|
+
* being attributable. It carries the per-launch secret from
|
|
25
|
+
* `PYRIC_BEACON_TOKEN`, which is what the route authorizes on.
|
|
26
|
+
* 2. One structured stderr line, printed when the developer asked for detail
|
|
27
|
+
* or when the report is bad news (see {@link beaconLineIsPrinted}). It is
|
|
28
|
+
* the fallback for a process with no reachable server, no port, no network.
|
|
29
|
+
*
|
|
30
|
+
* Where the bridge URL comes from
|
|
31
|
+
* -------------------------------
|
|
32
|
+
* `cli/sandbox-runner.ts:buildChildEnv` sets
|
|
33
|
+
* `PYRIC_SANDBOX=remote:<serveUrl>`, so the activator is the address. Nothing
|
|
34
|
+
* else needs to be plumbed, and the beacon works for any descendant that
|
|
35
|
+
* inherited the env, not just the direct child. When the activator carries no
|
|
36
|
+
* URL (`PYRIC_SANDBOX=local`, or a hand-set value), there is no endpoint and
|
|
37
|
+
* the line says `bridge=none` rather than guessing.
|
|
38
|
+
*
|
|
39
|
+
* The POST must never be able to hurt the child
|
|
40
|
+
* ---------------------------------------------
|
|
41
|
+
* It is diagnostics. A refused connection, a 500, an unreachable host: every
|
|
42
|
+
* one of those is swallowed. `emitBeacon` is `void`, never awaited.
|
|
43
|
+
*
|
|
44
|
+
* It is sent over a raw `node:http` request, an unref'd socket under a hard
|
|
45
|
+
* one-second bound (see {@link BEACON_TIMEOUT_MS}), rather than `fetch`, whose
|
|
46
|
+
* pending promise has neither knob. A short `node seed.js` child must not sit
|
|
47
|
+
* around after finishing its work just to deliver a diagnostic. A child that
|
|
48
|
+
* exits before the beacon lands simply loses the machine channel, which is
|
|
49
|
+
* exactly why the watchdog on the other end is warn-only.
|
|
50
|
+
*
|
|
51
|
+
* The POST targets loopback, which is not in the shared Google endpoint
|
|
52
|
+
* catalog, so it passes the net-guard installed moments earlier without a
|
|
53
|
+
* verdict.
|
|
54
|
+
*/
|
|
55
|
+
import { createRequire } from 'node:module';
|
|
56
|
+
import type { GuardMode } from './net-guard.js';
|
|
57
|
+
|
|
58
|
+
/** The dev server route that receives beacons (`serve/beacon-route.ts`). */
|
|
59
|
+
export const BEACON_PATH = '/__pyric/beacon';
|
|
60
|
+
|
|
61
|
+
/** Header carrying the per-launch secret from `PYRIC_BEACON_TOKEN`. The route
|
|
62
|
+
* rejects a beacon that does not present it. */
|
|
63
|
+
export const BEACON_TOKEN_HEADER = 'x-pyric-beacon-token';
|
|
64
|
+
|
|
65
|
+
const LOG_PREFIX = '@pyric/cli/register: beacon';
|
|
66
|
+
|
|
67
|
+
/** What one activated child asserts about itself. Wire shape of the POST body
|
|
68
|
+
* and the fields of the stderr line, kept identical on purpose. */
|
|
69
|
+
export interface BeaconReport {
|
|
70
|
+
/** The child's own pid, the only durable handle a parent has on it. */
|
|
71
|
+
readonly pid: number;
|
|
72
|
+
/** Net-guard mode actually in force in this process. */
|
|
73
|
+
readonly guard: GuardMode;
|
|
74
|
+
/** Whether module resolution hooks were installed. `false` means imports
|
|
75
|
+
* are NOT being rewritten, which is the whole thing worth knowing. */
|
|
76
|
+
readonly hooks: boolean;
|
|
77
|
+
/** The activator verbatim, so the parent can attribute the beacon. */
|
|
78
|
+
readonly sandbox: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface BeaconHooks {
|
|
82
|
+
readonly write?: (line: string) => void;
|
|
83
|
+
/** Delivery seam for the machine channel. Defaults to
|
|
84
|
+
* {@link sendBeaconRequest}. */
|
|
85
|
+
readonly send?: (endpoint: string, body: string, token: string) => void;
|
|
86
|
+
/** Environment read for the beacon secret and the stderr gate. Defaults to
|
|
87
|
+
* `process.env`. */
|
|
88
|
+
readonly env?: Record<string, string | undefined>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The hard bound on how long a beacon may delay a child's exit.
|
|
93
|
+
*
|
|
94
|
+
* One second, because this is loopback: the bridge is the dev server that
|
|
95
|
+
* launched us. If it has not accepted a connection in a second it is not
|
|
96
|
+
* going to, and no diagnostic is worth more of the child's life than that.
|
|
97
|
+
*/
|
|
98
|
+
const BEACON_TIMEOUT_MS = 1_000;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* POST one beacon body, fire and forget, over an unref'd socket. See the
|
|
102
|
+
* module header for why this is `node:http` and not `fetch`.
|
|
103
|
+
*
|
|
104
|
+
* `token` is the per-launch secret from `PYRIC_BEACON_TOKEN`; the route
|
|
105
|
+
* rejects a beacon without it.
|
|
106
|
+
*/
|
|
107
|
+
export function sendBeaconRequest(endpoint: string, body: string, token: string): void {
|
|
108
|
+
const require = createRequire(import.meta.url);
|
|
109
|
+
const secure = endpoint.startsWith('https:');
|
|
110
|
+
const http = require(secure ? 'node:https' : 'node:http') as {
|
|
111
|
+
request: (url: string, options: unknown) => {
|
|
112
|
+
on(event: string, listener: (arg: unknown) => void): unknown;
|
|
113
|
+
destroy(): void;
|
|
114
|
+
end(chunk: string): void;
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
const req = http.request(endpoint, {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
headers: {
|
|
120
|
+
'content-type': 'application/json',
|
|
121
|
+
'content-length': Buffer.byteLength(body),
|
|
122
|
+
[BEACON_TOKEN_HEADER]: token,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// The bound on how long this can delay the child's exit is the unref'd timer
|
|
127
|
+
// below, not the socket and not a request timeout. A pending connect holds
|
|
128
|
+
// the event loop open regardless of `socket.unref()`, and `req.setTimeout()`
|
|
129
|
+
// does not arm until the `connect` event, so against a blackholed loopback
|
|
130
|
+
// address a 300 ms request timeout was measured firing at 5006 ms, when the
|
|
131
|
+
// kernel reset the connection. The timer destroys the request instead: it
|
|
132
|
+
// cannot hold the loop by itself, and it always gets to run.
|
|
133
|
+
const abort = setTimeout(() => req.destroy(), BEACON_TIMEOUT_MS);
|
|
134
|
+
abort.unref?.();
|
|
135
|
+
const settle = (): void => clearTimeout(abort);
|
|
136
|
+
|
|
137
|
+
req.on('socket', (socket) => {
|
|
138
|
+
(socket as { unref?: () => void }).unref?.();
|
|
139
|
+
});
|
|
140
|
+
// A refused/reset connection is an expected outcome, not an error the child
|
|
141
|
+
// should ever hear about.
|
|
142
|
+
req.on('error', settle);
|
|
143
|
+
req.on('close', settle);
|
|
144
|
+
req.on('response', (res) => {
|
|
145
|
+
(res as { resume?: () => void }).resume?.();
|
|
146
|
+
settle();
|
|
147
|
+
});
|
|
148
|
+
req.end(body);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The beacon endpoint implied by an activator value, or `null` when none is.
|
|
153
|
+
* Accepts `remote:<url>` (what `buildChildEnv` writes) and a bare URL; any
|
|
154
|
+
* non-http(s) scheme, and anything unparseable, is `null`: an unfetchable
|
|
155
|
+
* guess is worse than an honest absence.
|
|
156
|
+
*/
|
|
157
|
+
export function beaconEndpoint(sandbox: string | undefined): string | null {
|
|
158
|
+
if (sandbox === undefined) return null;
|
|
159
|
+
const raw = sandbox.trim();
|
|
160
|
+
if (raw.length === 0) return null;
|
|
161
|
+
const value = raw.startsWith('remote:') ? raw.slice('remote:'.length).trim() : raw;
|
|
162
|
+
if (value.length === 0) return null;
|
|
163
|
+
let url: URL;
|
|
164
|
+
try {
|
|
165
|
+
url = new URL(value);
|
|
166
|
+
} catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') return null;
|
|
170
|
+
return `${url.origin}${BEACON_PATH}`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* One stderr line, structured the way net-guard's verdict lines are: fixed
|
|
175
|
+
* leading fields first so it is greppable (`beacon ACTIVE pid= guard= hooks=
|
|
176
|
+
* bridge=`), then the explanation.
|
|
177
|
+
*/
|
|
178
|
+
export function formatBeaconLine(report: BeaconReport, endpoint: string | null): string {
|
|
179
|
+
const head =
|
|
180
|
+
`${LOG_PREFIX} ACTIVE pid=${report.pid} guard=${report.guard} ` +
|
|
181
|
+
`hooks=${report.hooks ? 1 : 0} bridge=${endpoint ?? 'none'}`;
|
|
182
|
+
let hooksNote: string;
|
|
183
|
+
if (report.hooks) {
|
|
184
|
+
hooksNote = 'firebase-admin/firebase imports in this process are rewritten to the pyric sandbox';
|
|
185
|
+
} else {
|
|
186
|
+
hooksNote =
|
|
187
|
+
'module hooks did NOT install, so firebase-admin/firebase imports in this process are NOT rewritten';
|
|
188
|
+
}
|
|
189
|
+
return `${head}: ${hooksNote}, net-guard mode ${report.guard}.\n`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Whether the stderr channel prints.
|
|
194
|
+
*
|
|
195
|
+
* Quiet by default: a healthy first run should not carry a line per launched
|
|
196
|
+
* process, and the POST already tells the dev server what happened. The line
|
|
197
|
+
* prints when the developer asked for detail (`PYRIC_GUARD` set explicitly,
|
|
198
|
+
* `PYRIC_DEBUG`, or `PYRIC_VERBOSE`), and always when the report itself is bad
|
|
199
|
+
* news, since a child whose hooks did not install may have no other way to say
|
|
200
|
+
* so.
|
|
201
|
+
*/
|
|
202
|
+
export function beaconLineIsPrinted(
|
|
203
|
+
report: BeaconReport,
|
|
204
|
+
env: Record<string, string | undefined>,
|
|
205
|
+
): boolean {
|
|
206
|
+
if (!report.hooks) return true;
|
|
207
|
+
if ((env.PYRIC_GUARD ?? '').trim().length > 0) return true;
|
|
208
|
+
if (env.PYRIC_DEBUG) return true;
|
|
209
|
+
return Boolean(env.PYRIC_VERBOSE);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Emit the beacon. Never throws, never returns a promise: the caller is the
|
|
214
|
+
* `--import` hot path of every pyric-launched process.
|
|
215
|
+
*
|
|
216
|
+
* The POST always goes out. The stderr line is conditional, see
|
|
217
|
+
* {@link beaconLineIsPrinted}.
|
|
218
|
+
*/
|
|
219
|
+
export function emitBeacon(report: BeaconReport, hooks: BeaconHooks = {}): void {
|
|
220
|
+
const env = hooks.env ?? process.env;
|
|
221
|
+
const write = hooks.write ?? ((line: string) => void process.stderr.write(line));
|
|
222
|
+
const endpoint = beaconEndpoint(report.sandbox);
|
|
223
|
+
if (beaconLineIsPrinted(report, env)) write(formatBeaconLine(report, endpoint));
|
|
224
|
+
if (endpoint === null) return;
|
|
225
|
+
const token = env.PYRIC_BEACON_TOKEN ?? '';
|
|
226
|
+
try {
|
|
227
|
+
(hooks.send ?? sendBeaconRequest)(endpoint, JSON.stringify(report), token);
|
|
228
|
+
} catch {
|
|
229
|
+
// A runtime with no usable http module, or an endpoint that slipped the
|
|
230
|
+
// URL parse, loses the machine channel only.
|
|
231
|
+
}
|
|
232
|
+
}
|