@pyric/cli 0.1.0-alpha.11 → 0.1.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/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 +1 -1
- 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 +1 -1
- package/dist/serve/docs-ui/docs/get-started/start-building/index.html +1 -1
- package/dist/serve/docs-ui/docs/index.json +200 -25
- package/dist/serve/docs-ui/docs/messaging-compat/index.html +1 -1
- 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 +131 -66
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +130 -65
- 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 +1 -1
- 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/llms.txt +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/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.js +2 -2
- package/dist/serve/worker/protocol.js.map +1 -1
- package/package.json +5 -4
- package/src/assurance/.generated/conformance-verdicts.ts +1090 -0
- package/src/assurance/attachment.ts +211 -0
- package/src/assurance/browser.ts +80 -0
- package/src/assurance/campaign.ts +496 -0
- package/src/assurance/capabilities.ts +446 -0
- package/src/assurance/cases.ts +43 -0
- package/src/assurance/index.ts +75 -0
- package/src/assurance/runner.ts +885 -0
- package/src/assurance/tool-names.ts +15 -0
- package/src/assurance/tools.ts +830 -0
- package/src/assurance/types.ts +352 -0
- package/src/assurance/validation.ts +434 -0
- package/src/bridge/client/bridge.ts +550 -0
- package/src/bridge/client/dispatch.ts +137 -0
- package/src/bridge/client.ts +45 -0
- package/src/bridge/protocol.ts +351 -0
- package/src/bridge/server/audit.ts +53 -0
- package/src/bridge/server/bridge.ts +597 -0
- package/src/bridge/server/headless.ts +160 -0
- package/src/bridge/server/json-schema-to-zod.ts +108 -0
- package/src/bridge/server/local-bridge.ts +66 -0
- package/src/bridge/server/logger.ts +50 -0
- package/src/bridge/server/mcp-contract.ts +93 -0
- package/src/bridge/server/mcp.ts +129 -0
- package/src/bridge/server/peer.ts +232 -0
- package/src/bridge/server/standalone.ts +347 -0
- package/src/bridge/server/tool-metadata.ts +99 -0
- package/src/bridge/server.ts +28 -0
- package/src/cli/can-i-use.ts +50 -0
- package/src/cli/cli.test.ts +493 -0
- package/src/cli/database-rules.ts +329 -0
- package/src/cli/dev-runner.ts +282 -0
- package/src/cli/firebase-json.ts +100 -0
- package/src/cli/firestore-indexes.ts +70 -0
- package/src/cli/index.ts +425 -0
- package/src/cli/init.ts +260 -0
- package/src/cli/mcp-proxy.ts +196 -0
- package/src/cli/parse-args.ts +80 -0
- package/src/cli/rules.ts +259 -0
- package/src/cli/scope.ts +67 -0
- package/src/cli/serve.ts +996 -0
- package/src/cli/service-commands.ts +73 -0
- package/src/cli/snapshot.ts +164 -0
- package/src/cli/storage-rules.ts +172 -0
- package/src/cli/verify.ts +416 -0
- package/src/conformance/.generated/can-i-use-browser.ts +113 -0
- package/src/conformance/.generated/can-i-use.ts +117 -0
- package/src/conformance/.generated/conformance-docs.ts +14 -0
- package/src/conformance/browser.ts +24 -0
- package/src/conformance/can-i-use-tool.ts +51 -0
- package/src/conformance/can-i-use.ts +18 -0
- package/src/conformance/docs.ts +8 -0
- package/src/conformance/index.ts +20 -0
- package/src/conformance/tools.ts +16 -0
- package/src/credentials/core/memoize-ttl.ts +142 -0
- package/src/credentials/core/types.ts +10 -0
- package/src/credentials/node/from-adc.ts +96 -0
- package/src/credentials/node/from-service-account.ts +133 -0
- package/src/credentials/node/index.ts +6 -0
- package/src/discover/concurrency.ts +127 -0
- package/src/discover/crawler-adapter.ts +142 -0
- package/src/discover/crawler.ts +1127 -0
- package/src/discover/credential-free.ts +27 -0
- package/src/discover/findCollectionGroup.ts +131 -0
- package/src/discover/firestore-source.ts +59 -0
- package/src/discover/index.ts +5 -0
- package/src/discover/merge.ts +523 -0
- package/src/discover/session.ts +402 -0
- package/src/discover/tools.ts +201 -0
- package/src/discover/types.ts +187 -0
- package/src/discover/wire.ts +324 -0
- package/src/functions-rtdb/child.ts +382 -0
- package/src/functions-rtdb/delivery.ts +7 -0
- package/src/functions-rtdb/discovery.ts +136 -0
- package/src/functions-rtdb/event.ts +64 -0
- package/src/functions-rtdb/execution.ts +111 -0
- package/src/functions-rtdb/in-memory-delivery.ts +40 -0
- package/src/functions-rtdb/project.ts +74 -0
- package/src/functions-rtdb/projection.ts +104 -0
- package/src/functions-rtdb/reference-pattern.ts +20 -0
- package/src/functions-rtdb/remote-delivery.ts +23 -0
- package/src/pkg-version.ts +49 -0
- package/src/register/esm-exports.ts +63 -0
- package/src/register/hooks.ts +30 -0
- package/src/register/index.ts +150 -0
- package/src/register/mapping.ts +33 -0
- package/src/remote/index.ts +1050 -0
- package/src/rtdb/crawl-snapshot.ts +118 -0
- package/src/rtdb/inspection.ts +137 -0
- package/src/rtdb/load-rules-document.ts +56 -0
- package/src/rtdb/rules-generation-tool.ts +38 -0
- package/src/rtdb/rules-json.ts +29 -0
- package/src/serve/activity-guard.ts +29 -0
- package/src/serve/activity-route.ts +164 -0
- package/src/serve/activity-warning.ts +26 -0
- package/src/serve/bridge-mount.ts +200 -0
- package/src/serve/bundler.ts +493 -0
- package/src/serve/capture-store.ts +65 -0
- package/src/serve/discovery.ts +199 -0
- package/src/serve/entries/ai.ts +292 -0
- package/src/serve/entries/app-backend.ts +4 -0
- package/src/serve/entries/app-client.ts +26 -0
- package/src/serve/entries/app-session-store.ts +47 -0
- package/src/serve/entries/app.ts +11 -0
- package/src/serve/entries/auth-helper-core.ts +181 -0
- package/src/serve/entries/auth-helper-dom.ts +134 -0
- package/src/serve/entries/auth-helper-runtime.ts +20 -0
- package/src/serve/entries/auth.ts +255 -0
- package/src/serve/entries/bridge-url.ts +31 -0
- package/src/serve/entries/database.ts +129 -0
- package/src/serve/entries/firestore.ts +232 -0
- package/src/serve/entries/init.ts +46 -0
- package/src/serve/entries/keepalive.ts +46 -0
- package/src/serve/entries/messaging-sw.ts +75 -0
- package/src/serve/entries/messaging.ts +96 -0
- package/src/serve/entries/runtime.ts +540 -0
- package/src/serve/entries/session-store.ts +97 -0
- package/src/serve/entries/storage.ts +92 -0
- package/src/serve/entries/tab-sync-wiring.ts +274 -0
- package/src/serve/entries/worker-runtime.ts +75 -0
- package/src/serve/init-payload.ts +42 -0
- package/src/serve/namespace.ts +675 -0
- package/src/serve/open-browser.ts +68 -0
- package/src/serve/rules.ts +272 -0
- package/src/serve/sandbox-marker.ts +31 -0
- package/src/serve/server.ts +428 -0
- package/src/serve/standalone-assets.ts +180 -0
- package/src/serve/state-store.ts +166 -0
- package/src/serve/studio/disk-project-store.ts +185 -0
- package/src/serve/studio/disk-workspace.ts +162 -0
- package/src/serve/studio/index.ts +20 -0
- package/src/serve/studio/routes.ts +237 -0
- package/src/serve/studio/store-types.ts +48 -0
- package/src/serve/studio/studio-storage.test.ts +289 -0
- package/src/serve/vite-plugin.ts +1102 -0
- package/src/serve/worker/activity-bootstrap.ts +24 -0
- package/src/serve/worker/client/admin-firestore.ts +38 -0
- package/src/serve/worker/client/ai.ts +124 -0
- package/src/serve/worker/client/auth.ts +489 -0
- package/src/serve/worker/client/connection.ts +202 -0
- package/src/serve/worker/client/core.ts +350 -0
- package/src/serve/worker/client/disconnect.ts +45 -0
- package/src/serve/worker/client/firestore-reads.ts +181 -0
- package/src/serve/worker/client/firestore-refs.ts +226 -0
- package/src/serve/worker/client/firestore-writes.ts +232 -0
- package/src/serve/worker/client/handles.ts +91 -0
- package/src/serve/worker/client/messaging.ts +119 -0
- package/src/serve/worker/client/presence.ts +174 -0
- package/src/serve/worker/client/rtdb.ts +311 -0
- package/src/serve/worker/client/rules.ts +63 -0
- package/src/serve/worker/client/service-worker-connection.ts +59 -0
- package/src/serve/worker/client/snapshots.ts +86 -0
- package/src/serve/worker/client/storage.ts +195 -0
- package/src/serve/worker/client/studio.ts +88 -0
- package/src/serve/worker/client.ts +57 -0
- package/src/serve/worker/durable-persistence.ts +137 -0
- package/src/serve/worker/entry.ts +179 -0
- package/src/serve/worker/host/admin-firestore.ts +88 -0
- package/src/serve/worker/host/connection.ts +179 -0
- package/src/serve/worker/host/core.ts +387 -0
- package/src/serve/worker/host/dispatch.ts +316 -0
- package/src/serve/worker/host/firestore-reads.ts +117 -0
- package/src/serve/worker/host/firestore-writes.ts +456 -0
- package/src/serve/worker/host/presence.ts +312 -0
- package/src/serve/worker/host/rtdb.ts +136 -0
- package/src/serve/worker/host/rules.ts +128 -0
- package/src/serve/worker/host/storage.ts +312 -0
- package/src/serve/worker/host/studio.ts +75 -0
- package/src/serve/worker/host/subscriptions.ts +238 -0
- package/src/serve/worker/host-ai.ts +165 -0
- package/src/serve/worker/host-auth.ts +469 -0
- package/src/serve/worker/host-context.ts +273 -0
- package/src/serve/worker/host-events.ts +94 -0
- package/src/serve/worker/host-messaging.ts +240 -0
- package/src/serve/worker/host.ts +47 -0
- package/src/serve/worker/index.ts +196 -0
- package/src/serve/worker/presence-timing.ts +15 -0
- package/src/serve/worker/protocol.ts +1112 -0
- package/src/serve/worker/serve-init.ts +606 -0
- package/src/serve/worker/service-worker-channel.ts +33 -0
- package/src/serve/worker/service-worker-relay.ts +86 -0
- package/src/serve/writer-lock.ts +53 -0
- package/src/verify/cases.ts +233 -0
- package/src/verify/fixture.ts +258 -0
- package/src/verify/index.ts +519 -0
- package/src/verify/tools.ts +108 -0
- package/src/version/compat-target.ts +17 -0
- package/src/vite.ts +17 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -31
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -29
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@pyric/cli/bridge` — browser-side entry.
|
|
3
|
+
*
|
|
4
|
+
* Resolved by the `browser` condition in `package.json`'s exports map.
|
|
5
|
+
* Exports `connectBridge`, which the host app calls to register its
|
|
6
|
+
* in-page sandbox with a running pyric bridge process. After
|
|
7
|
+
* registration, MCP tool calls reaching the bridge are forwarded over
|
|
8
|
+
* WebSocket and dispatched into the local sandbox.
|
|
9
|
+
*
|
|
10
|
+
* The Node-side server entry lives in `./server.ts`. Wire format
|
|
11
|
+
* shared by both lives in `./protocol.ts`.
|
|
12
|
+
*
|
|
13
|
+
* ALSO reachable as `@pyric/cli/bridge/client` — an explicit, condition-free
|
|
14
|
+
* subpath for browser apps whose TYPE resolution doesn't apply the `browser`
|
|
15
|
+
* condition (Pyric Studio's `moduleResolution: bundler` tsconfig resolves the
|
|
16
|
+
* `./bridge` subpath's top-level `types` to the SERVER entry). Same file,
|
|
17
|
+
* same surface.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export type {
|
|
21
|
+
BridgeMessage,
|
|
22
|
+
HelloFromClient,
|
|
23
|
+
HelloFromBridge,
|
|
24
|
+
ToolCallRequest,
|
|
25
|
+
ToolCallResponse,
|
|
26
|
+
} from './protocol.js';
|
|
27
|
+
export {
|
|
28
|
+
DEFAULT_BRIDGE_PORT,
|
|
29
|
+
DEFAULT_SANDBOX_PATH,
|
|
30
|
+
} from './protocol.js';
|
|
31
|
+
|
|
32
|
+
export { connectBridge } from './client/bridge.js';
|
|
33
|
+
export type {
|
|
34
|
+
ConnectBridgeOptions,
|
|
35
|
+
ConnectedBridge,
|
|
36
|
+
ConnectedBridgeState,
|
|
37
|
+
SandboxToolDispatcher,
|
|
38
|
+
WorkerRelay,
|
|
39
|
+
} from './client/bridge.js';
|
|
40
|
+
|
|
41
|
+
// Re-anchor a served bridge URL to the page's own origin. The served app page
|
|
42
|
+
// and Pyric Studio both do this before connecting as the bridge peer (see
|
|
43
|
+
// `serve/entries/bridge-url.ts` for why the baked host can be the wrong
|
|
44
|
+
// machine). Pure + browser-safe; exported here so Studio reuses it verbatim.
|
|
45
|
+
export { toPageOriginWsUrl } from '../serve/entries/bridge-url.js';
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire protocol shared by `@pyric/cli/bridge` (Node bridge) and
|
|
3
|
+
* `@pyric/cli/bridge` (in-browser sandbox connector).
|
|
4
|
+
*
|
|
5
|
+
* The bridge process speaks MCP HTTP to external agents (Claude Code,
|
|
6
|
+
* Cursor) on `/mcp` and WebSocket to the in-browser sandbox on
|
|
7
|
+
* `/sandbox`. Data-plane and sandbox-management tool calls received
|
|
8
|
+
* over MCP are forwarded to whichever browser tab is currently
|
|
9
|
+
* connected; the browser dispatches them into the local
|
|
10
|
+
* `LocalEnvironment` and returns the result.
|
|
11
|
+
*
|
|
12
|
+
* This module has NO runtime imports — only types — so it can be
|
|
13
|
+
* referenced from both the `node` and `browser` builds without
|
|
14
|
+
* pulling Node-specific or DOM-specific modules into the wrong
|
|
15
|
+
* environment.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// TYPE-ONLY imports (erased at build) — the wire payloads for the generic
|
|
19
|
+
// worker relay are the SharedWorker protocol's own op/sub messages, minus
|
|
20
|
+
// the port-level `t`/`id`/`subId` fields the relay re-mints per hop.
|
|
21
|
+
import type { OpMessage, SubMessage } from '../serve/worker/protocol.js';
|
|
22
|
+
|
|
23
|
+
/** Health report returned by the bridge's `GET /health` endpoint. */
|
|
24
|
+
export interface HealthReport {
|
|
25
|
+
status: 'ok';
|
|
26
|
+
/** Constant provenance marker: the programmatic bridge is sandbox-only. */
|
|
27
|
+
mode: 'sandbox';
|
|
28
|
+
/** Sandbox identifier surfaced in health and audit metadata. */
|
|
29
|
+
project: string;
|
|
30
|
+
/** Whether a browser tab is currently connected over `/sandbox`. */
|
|
31
|
+
sandboxConnected: boolean;
|
|
32
|
+
/** Bridge package version. */
|
|
33
|
+
version: string;
|
|
34
|
+
/** ISO timestamp the bridge started. */
|
|
35
|
+
startedAt: string;
|
|
36
|
+
/**
|
|
37
|
+
* Random identity, stable for this bridge process's lifetime. The discovery
|
|
38
|
+
* pointer (`.pyric/serve.json`) records the same value, so a proxy can confirm
|
|
39
|
+
* it reached the SAME server the pointer names — two sandboxes can collide on
|
|
40
|
+
* one port across loopback families (IPv4 `*:P` + IPv6 `[::1]:P`), and `mode`
|
|
41
|
+
* alone can't tell them apart. (Not `version` — that's hardcoded.)
|
|
42
|
+
*/
|
|
43
|
+
instanceId: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Default port the standalone bridge binds to. */
|
|
47
|
+
export const DEFAULT_BRIDGE_PORT = 5174;
|
|
48
|
+
|
|
49
|
+
/** Default WS path the browser connects to. */
|
|
50
|
+
export const DEFAULT_SANDBOX_PATH = '/sandbox';
|
|
51
|
+
|
|
52
|
+
/** Default HTTP path the MCP client connects to. */
|
|
53
|
+
export const DEFAULT_MCP_PATH = '/mcp';
|
|
54
|
+
|
|
55
|
+
/** Default health endpoint path. */
|
|
56
|
+
export const DEFAULT_HEALTH_PATH = '/health';
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* WS close code the transport sends a sandbox peer when a NEWER registration
|
|
60
|
+
* displaces it (last-connection-wins). Application-defined (4000–4999 per RFC
|
|
61
|
+
* 6455 §7.4.2) so it survives every WS stack verbatim. The browser client
|
|
62
|
+
* treats this close as "the slot is legitimately held by another tab" and
|
|
63
|
+
* enters STANDBY (poll the health endpoint, reconnect only when the slot is
|
|
64
|
+
* vacant) instead of re-helloing — two open tabs used to kick each other in a
|
|
65
|
+
* perpetual last-wins fight, re-firing every relayed subscription and failing
|
|
66
|
+
* all in-flight worker ops once per cycle. Any OTHER close (server restart,
|
|
67
|
+
* network drop, tab-refresh takeover) keeps the immediate-reconnect loop.
|
|
68
|
+
*/
|
|
69
|
+
export const PEER_REPLACED_CLOSE_CODE = 4001;
|
|
70
|
+
|
|
71
|
+
/** Human-readable reason sent with {@link PEER_REPLACED_CLOSE_CODE}. */
|
|
72
|
+
export const PEER_REPLACED_CLOSE_REASON = 'replaced by a newer sandbox peer';
|
|
73
|
+
|
|
74
|
+
// ── Bridge ↔ browser WebSocket protocol ──────────────────────────────
|
|
75
|
+
//
|
|
76
|
+
// All messages are JSON. Each message has a `type` discriminator.
|
|
77
|
+
// Both directions share the same envelope shape so the wire can be
|
|
78
|
+
// audited with a single parser.
|
|
79
|
+
|
|
80
|
+
/** Browser → bridge: "I'm here and ready to receive tool calls." */
|
|
81
|
+
export interface HelloFromClient {
|
|
82
|
+
type: 'hello';
|
|
83
|
+
/** Protocol version. Bump if the wire format changes incompatibly. */
|
|
84
|
+
protocol: 1;
|
|
85
|
+
/** Tool names the browser can dispatch. Bridge uses this to size MCP tool surface. */
|
|
86
|
+
tools: string[];
|
|
87
|
+
/** Stable identifier for this sandbox session (for audit log). */
|
|
88
|
+
sandboxId: string;
|
|
89
|
+
/**
|
|
90
|
+
* Optional peer capabilities (additive). The bridge only sends `worker-*`
|
|
91
|
+
* frames to a peer that declared {@link WORKER_RELAY_CAPABILITY} — an old
|
|
92
|
+
* peer that omits it simply never receives them, and worker ops against it
|
|
93
|
+
* fail fast with a clear error instead of timing out.
|
|
94
|
+
*/
|
|
95
|
+
capabilities?: string[];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Bridge → browser: acknowledge connection. */
|
|
99
|
+
export interface HelloFromBridge {
|
|
100
|
+
type: 'hello-ack';
|
|
101
|
+
protocol: 1;
|
|
102
|
+
/** Bridge version, for compatibility checks. */
|
|
103
|
+
bridgeVersion: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Bridge → browser: please dispatch this tool call into the sandbox. */
|
|
107
|
+
export interface ToolCallRequest {
|
|
108
|
+
type: 'tool-call';
|
|
109
|
+
/** Correlation id — browser must echo in `ToolCallResponse`. */
|
|
110
|
+
id: string;
|
|
111
|
+
/** Tool name (e.g. `firestore_simulator_create`). */
|
|
112
|
+
name: string;
|
|
113
|
+
/** Tool arguments (JSON-serializable). */
|
|
114
|
+
args: Record<string, unknown>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Browser → bridge: tool call result. */
|
|
118
|
+
export interface ToolCallResponse {
|
|
119
|
+
type: 'tool-result';
|
|
120
|
+
/** Correlation id from the matching request. */
|
|
121
|
+
id: string;
|
|
122
|
+
/** When `ok===false`, `error` is populated and `result` is omitted. */
|
|
123
|
+
ok: boolean;
|
|
124
|
+
/** Tool result (matches `ToolResult` shape from `@inbrowser/agent`). */
|
|
125
|
+
result?: {
|
|
126
|
+
ok: boolean;
|
|
127
|
+
summary: string;
|
|
128
|
+
data?: unknown;
|
|
129
|
+
};
|
|
130
|
+
error?: {
|
|
131
|
+
code: string;
|
|
132
|
+
message: string;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ── Generic worker relay (remote sandbox, slice 1) ───────────────────
|
|
137
|
+
//
|
|
138
|
+
// Beyond `tool-call`, the bridge can relay ANY SharedWorker-protocol op or
|
|
139
|
+
// (snap-delivering) subscription between a Node consumer and the browser
|
|
140
|
+
// peer. The SAME frame shapes travel both legs:
|
|
141
|
+
//
|
|
142
|
+
// Node consumer ──ws──> bridge ──ws──> browser tab ──port──> worker
|
|
143
|
+
//
|
|
144
|
+
// Correlation ids/subIds are re-minted per hop (consumer-minted on the
|
|
145
|
+
// consumer leg, bridge-minted UUIDs on the peer leg, page-local ids on the
|
|
146
|
+
// worker port) so each hop's pending/registry maps stay collision-free.
|
|
147
|
+
|
|
148
|
+
/** Peer capability flag: "I can relay worker-op / worker-sub frames". */
|
|
149
|
+
export const WORKER_RELAY_CAPABILITY = 'worker-relay';
|
|
150
|
+
|
|
151
|
+
/** `Omit` distributed over a union (plain `Omit` collapses union members). */
|
|
152
|
+
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown
|
|
153
|
+
? Omit<T, K>
|
|
154
|
+
: never;
|
|
155
|
+
|
|
156
|
+
/** A worker one-shot op, minus the port-level `t`/`id` the relay re-mints. */
|
|
157
|
+
export type WorkerOpPayload = DistributiveOmit<OpMessage, 't' | 'id'>;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* A worker subscription, minus the port-level `t`/`subId`. Slice 1 relays
|
|
161
|
+
* snap-delivering subs (RTDB value, auth state, Firestore); the unified
|
|
162
|
+
* event stream (`target: 'events'`) is NOT relayable yet — it needs bounded
|
|
163
|
+
* backpressure first (slice 2).
|
|
164
|
+
*/
|
|
165
|
+
export type WorkerSubPayload = DistributiveOmit<SubMessage, 't' | 'subId'>;
|
|
166
|
+
|
|
167
|
+
/** Node consumer → bridge: attach as a worker-relay consumer (NOT a peer —
|
|
168
|
+
* a consumer never replaces the browser tab in last-connection-wins). */
|
|
169
|
+
export interface AttachFromConsumer {
|
|
170
|
+
type: 'attach';
|
|
171
|
+
protocol: 1;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Bridge → Node consumer: attach acknowledged. */
|
|
175
|
+
export interface AttachAckFromBridge {
|
|
176
|
+
type: 'attach-ack';
|
|
177
|
+
protocol: 1;
|
|
178
|
+
bridgeVersion: string;
|
|
179
|
+
/** Whether a browser tab is currently registered as the sandbox peer. */
|
|
180
|
+
peerConnected: boolean;
|
|
181
|
+
/**
|
|
182
|
+
* The `@pyric/cli` package version the serve/bridge process runs
|
|
183
|
+
* (version-skew stamp). ADDITIVE + OPTIONAL: old servers omit it and
|
|
184
|
+
* the client stays silent. When present and different from the
|
|
185
|
+
* client's own version, the client warns once at attach and enriches
|
|
186
|
+
* op-timeout errors — a skewed old worker can accept a newer op frame
|
|
187
|
+
* and die mid-handling, which otherwise surfaces as a bare timeout.
|
|
188
|
+
*/
|
|
189
|
+
serveVersion?: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Toward the worker: dispatch this one-shot op. (consumer→bridge and
|
|
193
|
+
* bridge→browser use the same shape; `id` is per-leg.) */
|
|
194
|
+
export interface WorkerOpFrame {
|
|
195
|
+
type: 'worker-op';
|
|
196
|
+
/** Correlation id — echoed back in the matching `worker-res`. */
|
|
197
|
+
id: string;
|
|
198
|
+
op: WorkerOpPayload;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Away from the worker: the relayed op result. */
|
|
202
|
+
export interface WorkerResFrame {
|
|
203
|
+
type: 'worker-res';
|
|
204
|
+
id: string;
|
|
205
|
+
/** When `ok === false`, `error` is populated and `value` omitted. */
|
|
206
|
+
ok: boolean;
|
|
207
|
+
value?: unknown;
|
|
208
|
+
/** `denialContext` (additive, spike gap 6): the structured "why did this
|
|
209
|
+
* deny" frame a `SandboxError` carries on `permission-denied` — plain
|
|
210
|
+
* JSON, so it rides the WS legs verbatim and the Node side re-attaches it. */
|
|
211
|
+
error?: { code: string; message: string; denialContext?: unknown };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Toward the worker: register a subscription. Re-issued by the bridge to a
|
|
215
|
+
* NEW peer on reconnect/replacement (value subs re-deliver a fresh initial
|
|
216
|
+
* snapshot, so replay is cursor-free and last-value-wins-safe). */
|
|
217
|
+
export interface WorkerSubFrame {
|
|
218
|
+
type: 'worker-sub';
|
|
219
|
+
subId: string;
|
|
220
|
+
sub: WorkerSubPayload;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Toward the worker: tear a subscription down. */
|
|
224
|
+
export interface WorkerUnsubFrame {
|
|
225
|
+
type: 'worker-unsub';
|
|
226
|
+
subId: string;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Away from the worker: one streamed snapshot for a subscription. A failed
|
|
230
|
+
* ESTABLISHMENT also arrives here as `value: { __error: { code, message } }`
|
|
231
|
+
* (the worker host's snap-error convention) — relays forward it verbatim. */
|
|
232
|
+
export interface WorkerSnapFrame {
|
|
233
|
+
type: 'worker-snap';
|
|
234
|
+
subId: string;
|
|
235
|
+
value: unknown;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Either direction: ping for keepalive / liveness detection. */
|
|
239
|
+
export interface Ping {
|
|
240
|
+
type: 'ping';
|
|
241
|
+
/** Echo back as `pong.id`. */
|
|
242
|
+
id: string;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Pong response to a Ping. */
|
|
246
|
+
export interface Pong {
|
|
247
|
+
type: 'pong';
|
|
248
|
+
id: string;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export type BridgeMessage =
|
|
252
|
+
| HelloFromClient
|
|
253
|
+
| HelloFromBridge
|
|
254
|
+
| AttachFromConsumer
|
|
255
|
+
| AttachAckFromBridge
|
|
256
|
+
| ToolCallRequest
|
|
257
|
+
| ToolCallResponse
|
|
258
|
+
| WorkerOpFrame
|
|
259
|
+
| WorkerResFrame
|
|
260
|
+
| WorkerSubFrame
|
|
261
|
+
| WorkerUnsubFrame
|
|
262
|
+
| WorkerSnapFrame
|
|
263
|
+
| Ping
|
|
264
|
+
| Pong;
|
|
265
|
+
|
|
266
|
+
/** Type guard for runtime parsing. */
|
|
267
|
+
export function isBridgeMessage(value: unknown): value is BridgeMessage {
|
|
268
|
+
if (value === null || typeof value !== 'object') return false;
|
|
269
|
+
const t = (value as { type?: unknown }).type;
|
|
270
|
+
return (
|
|
271
|
+
t === 'hello' ||
|
|
272
|
+
t === 'hello-ack' ||
|
|
273
|
+
t === 'attach' ||
|
|
274
|
+
t === 'attach-ack' ||
|
|
275
|
+
t === 'tool-call' ||
|
|
276
|
+
t === 'tool-result' ||
|
|
277
|
+
t === 'worker-op' ||
|
|
278
|
+
t === 'worker-res' ||
|
|
279
|
+
t === 'worker-sub' ||
|
|
280
|
+
t === 'worker-unsub' ||
|
|
281
|
+
t === 'worker-snap' ||
|
|
282
|
+
t === 'ping' ||
|
|
283
|
+
t === 'pong'
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** Error returned by MCP when no browser tab is currently connected. */
|
|
288
|
+
export const NO_SANDBOX_ERROR_MESSAGE =
|
|
289
|
+
'sandbox not connected. Open your dev server in a browser and refresh the page so the bridge client can register.';
|
|
290
|
+
|
|
291
|
+
/** Error for worker ops against a peer that predates the worker relay. */
|
|
292
|
+
export const NO_WORKER_RELAY_ERROR_MESSAGE =
|
|
293
|
+
'the connected browser tab does not support the worker relay — reload the tab (and update pyric if reloading does not help).';
|
|
294
|
+
|
|
295
|
+
// ─── Binary-payload guard (worker-op relay boundary) ────────────────────────
|
|
296
|
+
//
|
|
297
|
+
// Both WS legs of the worker relay are `JSON.stringify` — a `Blob` or
|
|
298
|
+
// `ArrayBuffer` in a relayed value silently becomes `{}` and a TypedArray /
|
|
299
|
+
// Buffer becomes an index-keyed object. Nothing errors; the far side just
|
|
300
|
+
// receives garbage (the live failure mode: relaying `storage.getBlob` yields
|
|
301
|
+
// `{}`). This guard turns that silent corruption into a loud, remediable
|
|
302
|
+
// rejection at the relay boundary. It is a cheap explicit TYPE check
|
|
303
|
+
// (Blob/ArrayBuffer/TypedArray/DataView), NOT a full JSON round-trip.
|
|
304
|
+
|
|
305
|
+
/** Human label for a non-JSON-safe binary value, or null when `value` (and
|
|
306
|
+
* every nested array/plain-object member) is free of binary containers. */
|
|
307
|
+
export function findBinaryPayload(value: unknown): string | null {
|
|
308
|
+
if (value === null || typeof value !== 'object') return null;
|
|
309
|
+
if (typeof Blob !== 'undefined' && value instanceof Blob) return 'Blob';
|
|
310
|
+
if (value instanceof ArrayBuffer) return 'ArrayBuffer';
|
|
311
|
+
if (ArrayBuffer.isView(value)) {
|
|
312
|
+
return (value as { constructor?: { name?: string } }).constructor?.name ?? 'TypedArray';
|
|
313
|
+
}
|
|
314
|
+
if (Array.isArray(value)) {
|
|
315
|
+
for (const item of value) {
|
|
316
|
+
const hit = findBinaryPayload(item);
|
|
317
|
+
if (hit) return hit;
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
for (const item of Object.values(value as Record<string, unknown>)) {
|
|
322
|
+
const hit = findBinaryPayload(item);
|
|
323
|
+
if (hit) return hit;
|
|
324
|
+
}
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Assert a worker-op result (or subscription snap value) is safe to
|
|
330
|
+
* serialize onto the JSON relay. Throws (code `invalid-argument`) naming
|
|
331
|
+
* the offending type and the base64 storage ops to use instead — so a
|
|
332
|
+
* future caller relaying `storage.getBlob` gets a clear error, not `{}`.
|
|
333
|
+
*
|
|
334
|
+
* `context` is a human label for the message: `op '<method>'` for op
|
|
335
|
+
* results, `subscription '<subId>'` for snap values.
|
|
336
|
+
*/
|
|
337
|
+
export function assertJsonSafeRelayValue(
|
|
338
|
+
context: string,
|
|
339
|
+
value: unknown,
|
|
340
|
+
): void {
|
|
341
|
+
const kind = findBinaryPayload(value);
|
|
342
|
+
if (!kind) return;
|
|
343
|
+
const err = new Error(
|
|
344
|
+
`worker ${context} produced a binary payload (${kind}) that cannot cross the ` +
|
|
345
|
+
'JSON bridge relay — it would be silently corrupted by JSON.stringify. Use the ' +
|
|
346
|
+
"base64 storage ops instead ('storage.getBytes' / 'storage.putBytes'), which carry " +
|
|
347
|
+
"bytes as JSON-safe 'dataB64' strings; 'storage.getBlob' is MessagePort-only.",
|
|
348
|
+
) as Error & { code: string };
|
|
349
|
+
err.code = 'invalid-argument';
|
|
350
|
+
throw err;
|
|
351
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit log writer. Every sandbox bridge tool call appends
|
|
3
|
+
* one JSON line to the project's events.ndjson file.
|
|
4
|
+
*
|
|
5
|
+
* Audit events land at the project's conventional location:
|
|
6
|
+
* `~/.pyric/projects/<projectId>/events.ndjson`
|
|
7
|
+
*
|
|
8
|
+
* The bridge passes its `BridgeToolEvent` here through `onToolEvent`.
|
|
9
|
+
* Writes are best-effort — failure to log must not break tool
|
|
10
|
+
* dispatch.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { homedir } from 'node:os';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { mkdirSync, appendFileSync } from 'node:fs';
|
|
16
|
+
import type { BridgeToolEvent } from './bridge.js';
|
|
17
|
+
|
|
18
|
+
export interface AuditWriter {
|
|
19
|
+
write(event: BridgeToolEvent): void;
|
|
20
|
+
/** Filesystem path of the active log. */
|
|
21
|
+
readonly path: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createAuditWriter(project: string): AuditWriter {
|
|
25
|
+
const dir = join(homedir(), '.pyric', 'projects', sanitiseProjectId(project));
|
|
26
|
+
const path = join(dir, 'events.ndjson');
|
|
27
|
+
try {
|
|
28
|
+
mkdirSync(dir, { recursive: true });
|
|
29
|
+
} catch (err) {
|
|
30
|
+
// If we can't create the directory, fall back to silent no-op.
|
|
31
|
+
return {
|
|
32
|
+
write: () => {},
|
|
33
|
+
path,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
path,
|
|
38
|
+
write(event: BridgeToolEvent) {
|
|
39
|
+
try {
|
|
40
|
+
const line = JSON.stringify(event) + '\n';
|
|
41
|
+
appendFileSync(path, line, { encoding: 'utf8' });
|
|
42
|
+
} catch {
|
|
43
|
+
// Drop the entry; tool dispatch continues.
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function sanitiseProjectId(value: string): string {
|
|
50
|
+
// Project ids are normally alphanumeric + dash; defend against
|
|
51
|
+
// path traversal just in case (someone passes `../etc` etc.).
|
|
52
|
+
return value.replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 128) || 'unknown';
|
|
53
|
+
}
|