@particle-academy/agent-integrations 0.44.0 → 0.46.0
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 +42 -3
- package/dist/bridges/artboard.d.cts +3 -3
- package/dist/bridges/artboard.d.ts +3 -3
- package/dist/bridges/catalog.d.cts +3 -3
- package/dist/bridges/catalog.d.ts +3 -3
- package/dist/bridges/charts.d.cts +3 -3
- package/dist/bridges/charts.d.ts +3 -3
- package/dist/bridges/cms.d.cts +3 -3
- package/dist/bridges/cms.d.ts +3 -3
- package/dist/bridges/code.d.cts +3 -3
- package/dist/bridges/code.d.ts +3 -3
- package/dist/bridges/doc.d.cts +3 -3
- package/dist/bridges/doc.d.ts +3 -3
- package/dist/bridges/features.d.cts +3 -3
- package/dist/bridges/features.d.ts +3 -3
- package/dist/bridges/files.d.cts +3 -3
- package/dist/bridges/files.d.ts +3 -3
- package/dist/bridges/flow.d.cts +3 -3
- package/dist/bridges/flow.d.ts +3 -3
- package/dist/bridges/forms.d.cts +3 -3
- package/dist/bridges/forms.d.ts +3 -3
- package/dist/bridges/git.d.cts +3 -3
- package/dist/bridges/git.d.ts +3 -3
- package/dist/bridges/grid.d.cts +3 -3
- package/dist/bridges/grid.d.ts +3 -3
- package/dist/bridges/map.d.cts +3 -3
- package/dist/bridges/map.d.ts +3 -3
- package/dist/bridges/passkeys.d.cts +3 -3
- package/dist/bridges/passkeys.d.ts +3 -3
- package/dist/bridges/scene.d.cts +3 -3
- package/dist/bridges/scene.d.ts +3 -3
- package/dist/bridges/screens.d.cts +3 -3
- package/dist/bridges/screens.d.ts +3 -3
- package/dist/bridges/sheets.d.cts +3 -3
- package/dist/bridges/sheets.d.ts +3 -3
- package/dist/bridges/slides.d.cts +3 -3
- package/dist/bridges/slides.d.ts +3 -3
- package/dist/bridges/terminal.d.cts +3 -3
- package/dist/bridges/terminal.d.ts +3 -3
- package/dist/bridges/tui.d.cts +2 -2
- package/dist/bridges/tui.d.ts +2 -2
- package/dist/bridges/whiteboard.d.cts +3 -3
- package/dist/bridges/whiteboard.d.ts +3 -3
- package/dist/bridges-artboard.cjs.map +1 -1
- package/dist/bridges-artboard.js +2 -2
- package/dist/bridges-catalog.cjs.map +1 -1
- package/dist/bridges-catalog.js +3 -3
- package/dist/bridges-charts.cjs.map +1 -1
- package/dist/bridges-charts.js +3 -3
- package/dist/bridges-cms.cjs.map +1 -1
- package/dist/bridges-cms.js +4 -4
- package/dist/bridges-code.cjs.map +1 -1
- package/dist/bridges-code.js +3 -3
- package/dist/bridges-doc.cjs.map +1 -1
- package/dist/bridges-doc.js +3 -3
- package/dist/bridges-features.cjs.map +1 -1
- package/dist/bridges-features.js +3 -3
- package/dist/bridges-files.cjs.map +1 -1
- package/dist/bridges-files.js +3 -3
- package/dist/bridges-flow.cjs.map +1 -1
- package/dist/bridges-flow.js +2 -2
- package/dist/bridges-forms.cjs.map +1 -1
- package/dist/bridges-forms.js +3 -3
- package/dist/bridges-git.cjs.map +1 -1
- package/dist/bridges-git.js +3 -3
- package/dist/bridges-grid.cjs.map +1 -1
- package/dist/bridges-grid.js +3 -3
- package/dist/bridges-map.cjs.map +1 -1
- package/dist/bridges-map.js +3 -3
- package/dist/bridges-passkeys.cjs.map +1 -1
- package/dist/bridges-passkeys.js +3 -3
- package/dist/bridges-scene.cjs.map +1 -1
- package/dist/bridges-scene.js +3 -3
- package/dist/bridges-screens.cjs.map +1 -1
- package/dist/bridges-screens.js +3 -3
- package/dist/bridges-sheets.cjs.map +1 -1
- package/dist/bridges-sheets.js +3 -3
- package/dist/bridges-slides.cjs.map +1 -1
- package/dist/bridges-slides.js +3 -3
- package/dist/bridges-terminal.cjs.map +1 -1
- package/dist/bridges-terminal.js +3 -3
- package/dist/bridges-tui.cjs.map +1 -1
- package/dist/bridges-tui.js +2 -2
- package/dist/bridges-whiteboard.cjs.map +1 -1
- package/dist/bridges-whiteboard.js +3 -3
- package/dist/{chunk-5W6YOXLT.js → chunk-36MKPTVD.js} +4 -4
- package/dist/{chunk-5W6YOXLT.js.map → chunk-36MKPTVD.js.map} +1 -1
- package/dist/{chunk-SXVRIIXW.js → chunk-3HVYUMQF.js} +4 -4
- package/dist/{chunk-SXVRIIXW.js.map → chunk-3HVYUMQF.js.map} +1 -1
- package/dist/{chunk-MZ74LLDS.js → chunk-3UUF5KKZ.js} +4 -4
- package/dist/{chunk-MZ74LLDS.js.map → chunk-3UUF5KKZ.js.map} +1 -1
- package/dist/{chunk-WEXMZMJH.js → chunk-3WVXAB3D.js} +3 -3
- package/dist/{chunk-WEXMZMJH.js.map → chunk-3WVXAB3D.js.map} +1 -1
- package/dist/{chunk-OZBUPO4K.js → chunk-5W34X4EY.js} +263 -58
- package/dist/chunk-5W34X4EY.js.map +1 -0
- package/dist/{chunk-Z4L2GOAK.js → chunk-5ZWNCHZS.js} +4 -4
- package/dist/{chunk-Z4L2GOAK.js.map → chunk-5ZWNCHZS.js.map} +1 -1
- package/dist/{chunk-TEB5U6Y5.js → chunk-7NVATRLE.js} +4 -4
- package/dist/{chunk-TEB5U6Y5.js.map → chunk-7NVATRLE.js.map} +1 -1
- package/dist/{chunk-PUMQDV67.js → chunk-AXWMWYH5.js} +4 -4
- package/dist/{chunk-PUMQDV67.js.map → chunk-AXWMWYH5.js.map} +1 -1
- package/dist/{chunk-NKAH67JK.js → chunk-CS3CHGYC.js} +4 -4
- package/dist/{chunk-NKAH67JK.js.map → chunk-CS3CHGYC.js.map} +1 -1
- package/dist/{chunk-QJYRWEXD.js → chunk-CZV3WUW5.js} +35 -8
- package/dist/chunk-CZV3WUW5.js.map +1 -0
- package/dist/{chunk-PCFRBVKS.js → chunk-FCXSR7I5.js} +4 -4
- package/dist/{chunk-PCFRBVKS.js.map → chunk-FCXSR7I5.js.map} +1 -1
- package/dist/{chunk-NIFPRC7P.js → chunk-GVTBMJU6.js} +4 -4
- package/dist/{chunk-NIFPRC7P.js.map → chunk-GVTBMJU6.js.map} +1 -1
- package/dist/{chunk-E2I3YVKC.js → chunk-JLHVQWOV.js} +3 -3
- package/dist/{chunk-E2I3YVKC.js.map → chunk-JLHVQWOV.js.map} +1 -1
- package/dist/{chunk-2LSU3NFO.js → chunk-LQB42OSA.js} +4 -4
- package/dist/{chunk-2LSU3NFO.js.map → chunk-LQB42OSA.js.map} +1 -1
- package/dist/{chunk-VJD3Y7E5.js → chunk-MIDZWKIF.js} +4 -4
- package/dist/{chunk-VJD3Y7E5.js.map → chunk-MIDZWKIF.js.map} +1 -1
- package/dist/{chunk-LOD77NCD.js → chunk-PWYEW6NL.js} +4 -4
- package/dist/{chunk-LOD77NCD.js.map → chunk-PWYEW6NL.js.map} +1 -1
- package/dist/{chunk-HVDHT7DM.js → chunk-R4XXOGQH.js} +3 -3
- package/dist/{chunk-HVDHT7DM.js.map → chunk-R4XXOGQH.js.map} +1 -1
- package/dist/{chunk-7LLMILTM.js → chunk-RVMM4BHK.js} +4 -4
- package/dist/{chunk-7LLMILTM.js.map → chunk-RVMM4BHK.js.map} +1 -1
- package/dist/{chunk-NIXOY473.js → chunk-SWWJUOCY.js} +3 -3
- package/dist/{chunk-NIXOY473.js.map → chunk-SWWJUOCY.js.map} +1 -1
- package/dist/{chunk-EIBV76IB.js → chunk-VFWFT3OK.js} +4 -4
- package/dist/{chunk-EIBV76IB.js.map → chunk-VFWFT3OK.js.map} +1 -1
- package/dist/{chunk-2Q4EGZHJ.js → chunk-VMRUW4B4.js} +4 -4
- package/dist/{chunk-2Q4EGZHJ.js.map → chunk-VMRUW4B4.js.map} +1 -1
- package/dist/{chunk-GT63LSPJ.js → chunk-VOCUGTZB.js} +4 -4
- package/dist/{chunk-GT63LSPJ.js.map → chunk-VOCUGTZB.js.map} +1 -1
- package/dist/{chunk-N5VOPV64.js → chunk-Z5NL5D4J.js} +4 -4
- package/dist/{chunk-N5VOPV64.js.map → chunk-Z5NL5D4J.js.map} +1 -1
- package/dist/components-shared-whiteboard.cjs +33 -6
- package/dist/components-shared-whiteboard.cjs.map +1 -1
- package/dist/components-shared-whiteboard.js +3 -3
- package/dist/index.cjs +33 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +27 -27
- package/dist/mcp/index.d.cts +5 -5
- package/dist/mcp/index.d.ts +5 -5
- package/dist/mcp/stdio.d.cts +94 -0
- package/dist/mcp/stdio.d.ts +94 -0
- package/dist/mcp-stdio.cjs +120 -0
- package/dist/mcp-stdio.cjs.map +1 -0
- package/dist/mcp-stdio.js +117 -0
- package/dist/mcp-stdio.js.map +1 -0
- package/dist/mcp.cjs +33 -6
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/presence/index.d.cts +1 -1
- package/dist/presence/index.d.ts +1 -1
- package/dist/relay-server/index.d.cts +110 -26
- package/dist/relay-server/index.d.ts +110 -26
- package/dist/relay-server-cli.cjs +374 -89
- package/dist/relay-server-cli.cjs.map +1 -1
- package/dist/relay-server-cli.js +120 -38
- package/dist/relay-server-cli.js.map +1 -1
- package/dist/relay-server.cjs +255 -51
- package/dist/relay-server.cjs.map +1 -1
- package/dist/relay-server.js +1 -1
- package/dist/{server-BJNF7pQe.d.cts → server-BIcA3ZtK.d.cts} +32 -3
- package/dist/{server-Dt97UxuD.d.ts → server-DnUyeavY.d.ts} +32 -3
- package/dist/sharing/index.d.cts +3 -3
- package/dist/sharing/index.d.ts +3 -3
- package/dist/sheets-adapter.d.cts +3 -3
- package/dist/sheets-adapter.d.ts +3 -3
- package/dist/{tool-host-BpEBqf5u.d.cts → tool-host-LVBgCN5m.d.cts} +1 -1
- package/dist/{tool-host-xY5F-eqG.d.ts → tool-host-Wo0pkY83.d.ts} +1 -1
- package/dist/{types-DSwsNTBG.d.ts → types-BxNRKSVd.d.ts} +1 -1
- package/dist/{types-C58ZXs4K.d.cts → types-C2DtnHIn.d.cts} +25 -1
- package/dist/{types-C58ZXs4K.d.ts → types-C2DtnHIn.d.ts} +25 -1
- package/dist/{types-C4NaIW6B.d.cts → types-EcElKOlk.d.cts} +1 -1
- package/dist/undo/index.d.cts +2 -2
- package/dist/undo/index.d.ts +2 -2
- package/dist/undo.cjs.map +1 -1
- package/dist/undo.js +3 -3
- package/docs/relay-protocol.md +41 -5
- package/docs/relay-server.md +102 -15
- package/package.json +19 -2
- package/dist/chunk-OZBUPO4K.js.map +0 -1
- package/dist/chunk-QJYRWEXD.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bridges/map.ts"],"names":[],"mappings":"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","file":"chunk-MZ74LLDS.js","sourcesContent":["// Loose types so this bridge builds standalone without a hard dep on\n// @particle-academy/fancy-map. Hosts that use fancy-map pass its own\n// MapMarker / MapView values straight through — the shapes match.\ntype LatLng = { lat: number; lng: number };\ntype MapView = { center: LatLng; zoom: number; bearing?: number; pitch?: number };\ntype MapMarker = {\n id: string;\n position: LatLng;\n label?: string;\n color?: string;\n icon?: string;\n draggable?: boolean;\n data?: Record<string, unknown>;\n};\n\nimport { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget as MapAgentTarget } from \"../presence/types\";\nimport { pushUndoEntry } from \"../undo/undo-stack\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\n/**\n * Adapter the host provides — getters/setters over the SAME controlled state it\n * passes to fancy-map's `<Map>` (view, markers, selection), plus optional\n * `fitBounds` (from the map's onReady handle) and `setFollow` (drives the map's\n * `follow` prop so an agent can make the camera track a moving marker).\n */\nexport type MapBridgeAdapter = {\n getView: () => MapView;\n setView: (next: MapView) => void;\n getMarkers: () => MapMarker[];\n setMarkers: (next: MapMarker[] | ((prev: MapMarker[]) => MapMarker[])) => void;\n getSelected: () => string | null;\n setSelected: (id: string | null) => void;\n /** Fit the camera to points (wire to the `MapHandle.fitBounds` from `<Map onReady>`). */\n fitBounds?: (points: LatLng[], padding?: number) => void;\n /** Make the camera follow a marker as it moves (drives the map's `follow` prop). */\n setFollow?: (id: string | null) => void;\n};\n\nexport type MapBridgeOptions = {\n adapter: MapBridgeAdapter;\n /** Identity tagged onto agent-authored markers. */\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\nconst num = (v: unknown, fallback?: number): number =>\n typeof v === \"number\" && Number.isFinite(v) ? v : fallback ?? 0;\nconst str = (v: unknown, fallback = \"\"): string => (typeof v === \"string\" ? v : fallback);\nconst newId = (prefix: string) =>\n `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`;\n\n/**\n * registerMapBridge — an MCP tool set over a fancy-map `<Map>`'s controlled\n * state, so a human and an agent cohabit one map. The agent moves the camera,\n * drops/updates/removes markers, selects, fits bounds, and follows a live\n * track; every mutation broadcasts AgentActivity (for presence) and pushes an\n * undo entry (so the human can step the agent back). Mirrors the whiteboard /\n * flow bridges in shape.\n */\nexport function registerMapBridge(host: ToolHost, options: MapBridgeOptions): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n // Register agent_undo / agent_redo / agent_history once per host. Idempotent.\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const mTarget = (args: any, result: any): MapAgentTarget => ({\n kind: \"map\",\n elementId:\n (result?.structuredContent?.id as string | undefined) ?? (args?.id as string | undefined),\n });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n resolveTarget?: (args: JsonObject, result: any) => MapAgentTarget | null,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = resolveTarget\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent: { id: agent.id, name: agent.name, color: agent.color },\n kind: \"map\",\n resolveTarget: ({ args, result }) => resolveTarget(args, result),\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: {\n type: \"object\",\n properties: properties as any,\n required,\n additionalProperties: false,\n },\n },\n final as any,\n ),\n );\n };\n\n // ───────────── Read ─────────────\n\n reg(\"map_get_state\", \"Get the map's camera, markers, and current selection.\", {}, [], () => {\n const state = {\n view: adapter.getView(),\n markers: adapter.getMarkers(),\n selectedId: adapter.getSelected(),\n };\n return textResult(JSON.stringify(state, null, 2), state);\n });\n\n // ───────────── Camera ─────────────\n\n reg(\n \"map_set_view\",\n \"Move the camera to an absolute position. Any omitted field is left unchanged.\",\n {\n lat: { type: \"number\", description: \"New center latitude.\" },\n lng: { type: \"number\", description: \"New center longitude.\" },\n zoom: { type: \"number\", description: \"New zoom level (higher = closer).\" },\n },\n [],\n (args) => {\n const prev = adapter.getView();\n const next: MapView = {\n center: {\n lat: args.lat !== undefined ? num(args.lat) : prev.center.lat,\n lng: args.lng !== undefined ? num(args.lng) : prev.center.lng,\n },\n zoom: args.zoom !== undefined ? num(args.zoom) : prev.zoom,\n };\n adapter.setView(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_set_view\",\n label: `Moved camera to ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)} z${next.zoom}`,\n undo: () => adapter.setView(prev),\n redo: () => adapter.setView(next),\n });\n return textResult(`Camera → ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)} z${next.zoom}`, next);\n },\n mTarget,\n );\n\n reg(\n \"map_pan\",\n \"Pan the camera by a relative offset in degrees (positive dLat = north, positive dLng = east).\",\n { dLat: { type: \"number\" }, dLng: { type: \"number\" } },\n [],\n (args) => {\n const prev = adapter.getView();\n const next: MapView = {\n ...prev,\n center: { lat: prev.center.lat + num(args.dLat), lng: prev.center.lng + num(args.dLng) },\n };\n adapter.setView(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_pan\",\n label: \"Panned camera\",\n undo: () => adapter.setView(prev),\n redo: () => adapter.setView(next),\n });\n return textResult(`Panned to ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)}`, next);\n },\n mTarget,\n );\n\n reg(\n \"map_zoom\",\n \"Zoom the camera by a relative delta (e.g. +1 zooms in one level, -2 out two).\",\n { delta: { type: \"number\" } },\n [\"delta\"],\n (args) => {\n const prev = adapter.getView();\n const next: MapView = { ...prev, zoom: prev.zoom + num(args.delta) };\n adapter.setView(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_zoom\",\n label: `Zoom → ${next.zoom}`,\n undo: () => adapter.setView(prev),\n redo: () => adapter.setView(next),\n });\n return textResult(`Zoom → ${next.zoom}`, next);\n },\n );\n\n reg(\n \"map_fit_bounds\",\n \"Fit the camera to enclose points. Pass `points`, or omit to fit all current markers.\",\n {\n points: {\n type: \"array\",\n description: \"Points to enclose, e.g. [{lat,lng},…].\",\n items: {\n type: \"object\",\n properties: { lat: { type: \"number\" }, lng: { type: \"number\" } },\n required: [\"lat\", \"lng\"],\n },\n },\n padding: { type: \"number\", description: \"Padding in pixels (default 40).\" },\n },\n [],\n (args) => {\n if (!adapter.fitBounds) {\n return errorResult(\"Host did not wire fitBounds (pass the <Map onReady> handle's fitBounds).\");\n }\n const points: LatLng[] = Array.isArray(args.points)\n ? (args.points as any[]).map((p) => ({ lat: num(p?.lat), lng: num(p?.lng) }))\n : adapter.getMarkers().map((m) => m.position);\n if (!points.length) {\n return errorResult(\"No points to fit (map has no markers).\");\n }\n adapter.fitBounds(points, args.padding !== undefined ? num(args.padding) : undefined);\n return textResult(`Fit camera to ${points.length} point(s).`);\n },\n );\n\n // ───────────── Markers ─────────────\n\n reg(\n \"map_add_marker\",\n \"Drop a marker. `id` is optional (auto-generated); `icon` is an emoji or 1–2 chars.\",\n {\n id: { type: \"string\" },\n lat: { type: \"number\" },\n lng: { type: \"number\" },\n label: { type: \"string\" },\n color: { type: \"string\", description: \"CSS color, e.g. #2563eb.\" },\n icon: { type: \"string\", description: \"Emoji / short text in the pin.\" },\n draggable: { type: \"boolean\" },\n data: { type: \"object\", description: \"Arbitrary JSON payload carried with the marker.\" },\n },\n [\"lat\", \"lng\"],\n (args) => {\n const id = args.id ? str(args.id) : newId(\"m\");\n if (adapter.getMarkers().some((m) => m.id === id)) {\n return errorResult(`A marker with id ${id} already exists — use map_update_marker.`);\n }\n const marker: MapMarker = {\n id,\n position: { lat: num(args.lat), lng: num(args.lng) },\n ...(args.label !== undefined ? { label: str(args.label) } : {}),\n ...(args.color !== undefined ? { color: str(args.color) } : {}),\n ...(args.icon !== undefined ? { icon: str(args.icon) } : {}),\n ...(args.draggable !== undefined ? { draggable: !!args.draggable } : {}),\n ...(args.data && typeof args.data === \"object\"\n ? { data: args.data as Record<string, unknown> }\n : {}),\n };\n adapter.setMarkers((all) => [...all, marker]);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_add_marker\",\n label: `Added marker ${id}`,\n undo: () => adapter.setMarkers((all) => all.filter((m) => m.id !== id)),\n redo: () => adapter.setMarkers((all) => [...all, marker]),\n });\n return textResult(`Added marker ${id} at ${marker.position.lat.toFixed(4)},${marker.position.lng.toFixed(4)}`, marker);\n },\n mTarget,\n );\n\n reg(\n \"map_update_marker\",\n \"Update a marker. Only provided fields change — update lat/lng repeatedly to drive a live track.\",\n {\n id: { type: \"string\" },\n lat: { type: \"number\" },\n lng: { type: \"number\" },\n label: { type: \"string\" },\n color: { type: \"string\" },\n icon: { type: \"string\" },\n draggable: { type: \"boolean\" },\n },\n [\"id\"],\n (args) => {\n const id = str(args.id);\n const prev = adapter.getMarkers().find((m) => m.id === id);\n if (!prev) {\n return errorResult(`No marker with id ${id}`);\n }\n const next: MapMarker = {\n ...prev,\n position: {\n lat: args.lat !== undefined ? num(args.lat) : prev.position.lat,\n lng: args.lng !== undefined ? num(args.lng) : prev.position.lng,\n },\n ...(args.label !== undefined ? { label: str(args.label) } : {}),\n ...(args.color !== undefined ? { color: str(args.color) } : {}),\n ...(args.icon !== undefined ? { icon: str(args.icon) } : {}),\n ...(args.draggable !== undefined ? { draggable: !!args.draggable } : {}),\n };\n adapter.setMarkers((all) => all.map((m) => (m.id === id ? next : m)));\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_update_marker\",\n label: `Updated marker ${id}`,\n undo: () => adapter.setMarkers((all) => all.map((m) => (m.id === id ? prev : m))),\n redo: () => adapter.setMarkers((all) => all.map((m) => (m.id === id ? next : m))),\n });\n return textResult(`Updated marker ${id}`, next);\n },\n mTarget,\n );\n\n reg(\n \"map_remove_marker\",\n \"Remove a marker by id.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const id = str(args.id);\n const prev = adapter.getMarkers().find((m) => m.id === id);\n if (!prev) {\n return errorResult(`No marker with id ${id}`);\n }\n adapter.setMarkers((all) => all.filter((m) => m.id !== id));\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_remove_marker\",\n label: `Removed marker ${id}`,\n undo: () => adapter.setMarkers((all) => [...all, prev]),\n redo: () => adapter.setMarkers((all) => all.filter((m) => m.id !== id)),\n });\n return textResult(`Removed marker ${id}`);\n },\n mTarget,\n );\n\n reg(\n \"map_select\",\n \"Select a marker (or pass no id / null to clear the selection).\",\n { id: { type: \"string\" } },\n [],\n (args) => {\n const prev = adapter.getSelected();\n const id = args.id === undefined || args.id === null ? null : str(args.id);\n if (id !== null && !adapter.getMarkers().some((m) => m.id === id)) {\n return errorResult(`No marker with id ${id}`);\n }\n adapter.setSelected(id);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_select\",\n label: id ? `Selected ${id}` : \"Cleared selection\",\n undo: () => adapter.setSelected(prev),\n redo: () => adapter.setSelected(id),\n });\n return textResult(id ? `Selected marker ${id}` : \"Cleared selection\", { selectedId: id });\n },\n mTarget,\n );\n\n // ───────────── Live tracking (camera follow) ─────────────\n\n reg(\n \"map_start_track\",\n \"Make the camera follow a marker as its position updates (live tracking). Requires the host to wire setFollow.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n if (!adapter.setFollow) {\n return errorResult(\"Host did not wire setFollow (pass the map's `follow` setter).\");\n }\n const id = str(args.id);\n if (!adapter.getMarkers().some((m) => m.id === id)) {\n return errorResult(`No marker with id ${id}`);\n }\n adapter.setFollow(id);\n return textResult(`Camera now following ${id}`, { follow: id });\n },\n mTarget,\n );\n\n reg(\n \"map_stop_track\",\n \"Stop following any marker (releases the camera). Requires the host to wire setFollow.\",\n {},\n [],\n () => {\n if (!adapter.setFollow) {\n return errorResult(\"Host did not wire setFollow.\");\n }\n adapter.setFollow(null);\n return textResult(\"Camera released (no longer following).\", { follow: null });\n },\n );\n\n return {\n id: \"map\",\n title: \"Map\",\n dispose: () => {\n for (const d of disposers) d();\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/bridges/map.ts"],"names":[],"mappings":"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","file":"chunk-3UUF5KKZ.js","sourcesContent":["// Loose types so this bridge builds standalone without a hard dep on\n// @particle-academy/fancy-map. Hosts that use fancy-map pass its own\n// MapMarker / MapView values straight through — the shapes match.\ntype LatLng = { lat: number; lng: number };\ntype MapView = { center: LatLng; zoom: number; bearing?: number; pitch?: number };\ntype MapMarker = {\n id: string;\n position: LatLng;\n label?: string;\n color?: string;\n icon?: string;\n draggable?: boolean;\n data?: Record<string, unknown>;\n};\n\nimport { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget as MapAgentTarget } from \"../presence/types\";\nimport { pushUndoEntry } from \"../undo/undo-stack\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\n/**\n * Adapter the host provides — getters/setters over the SAME controlled state it\n * passes to fancy-map's `<Map>` (view, markers, selection), plus optional\n * `fitBounds` (from the map's onReady handle) and `setFollow` (drives the map's\n * `follow` prop so an agent can make the camera track a moving marker).\n */\nexport type MapBridgeAdapter = {\n getView: () => MapView;\n setView: (next: MapView) => void;\n getMarkers: () => MapMarker[];\n setMarkers: (next: MapMarker[] | ((prev: MapMarker[]) => MapMarker[])) => void;\n getSelected: () => string | null;\n setSelected: (id: string | null) => void;\n /** Fit the camera to points (wire to the `MapHandle.fitBounds` from `<Map onReady>`). */\n fitBounds?: (points: LatLng[], padding?: number) => void;\n /** Make the camera follow a marker as it moves (drives the map's `follow` prop). */\n setFollow?: (id: string | null) => void;\n};\n\nexport type MapBridgeOptions = {\n adapter: MapBridgeAdapter;\n /** Identity tagged onto agent-authored markers. */\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\nconst num = (v: unknown, fallback?: number): number =>\n typeof v === \"number\" && Number.isFinite(v) ? v : fallback ?? 0;\nconst str = (v: unknown, fallback = \"\"): string => (typeof v === \"string\" ? v : fallback);\nconst newId = (prefix: string) =>\n `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`;\n\n/**\n * registerMapBridge — an MCP tool set over a fancy-map `<Map>`'s controlled\n * state, so a human and an agent cohabit one map. The agent moves the camera,\n * drops/updates/removes markers, selects, fits bounds, and follows a live\n * track; every mutation broadcasts AgentActivity (for presence) and pushes an\n * undo entry (so the human can step the agent back). Mirrors the whiteboard /\n * flow bridges in shape.\n */\nexport function registerMapBridge(host: ToolHost, options: MapBridgeOptions): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n // Register agent_undo / agent_redo / agent_history once per host. Idempotent.\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const mTarget = (args: any, result: any): MapAgentTarget => ({\n kind: \"map\",\n elementId:\n (result?.structuredContent?.id as string | undefined) ?? (args?.id as string | undefined),\n });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n resolveTarget?: (args: JsonObject, result: any) => MapAgentTarget | null,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = resolveTarget\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent: { id: agent.id, name: agent.name, color: agent.color },\n kind: \"map\",\n resolveTarget: ({ args, result }) => resolveTarget(args, result),\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: {\n type: \"object\",\n properties: properties as any,\n required,\n additionalProperties: false,\n },\n },\n final as any,\n ),\n );\n };\n\n // ───────────── Read ─────────────\n\n reg(\"map_get_state\", \"Get the map's camera, markers, and current selection.\", {}, [], () => {\n const state = {\n view: adapter.getView(),\n markers: adapter.getMarkers(),\n selectedId: adapter.getSelected(),\n };\n return textResult(JSON.stringify(state, null, 2), state);\n });\n\n // ───────────── Camera ─────────────\n\n reg(\n \"map_set_view\",\n \"Move the camera to an absolute position. Any omitted field is left unchanged.\",\n {\n lat: { type: \"number\", description: \"New center latitude.\" },\n lng: { type: \"number\", description: \"New center longitude.\" },\n zoom: { type: \"number\", description: \"New zoom level (higher = closer).\" },\n },\n [],\n (args) => {\n const prev = adapter.getView();\n const next: MapView = {\n center: {\n lat: args.lat !== undefined ? num(args.lat) : prev.center.lat,\n lng: args.lng !== undefined ? num(args.lng) : prev.center.lng,\n },\n zoom: args.zoom !== undefined ? num(args.zoom) : prev.zoom,\n };\n adapter.setView(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_set_view\",\n label: `Moved camera to ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)} z${next.zoom}`,\n undo: () => adapter.setView(prev),\n redo: () => adapter.setView(next),\n });\n return textResult(`Camera → ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)} z${next.zoom}`, next);\n },\n mTarget,\n );\n\n reg(\n \"map_pan\",\n \"Pan the camera by a relative offset in degrees (positive dLat = north, positive dLng = east).\",\n { dLat: { type: \"number\" }, dLng: { type: \"number\" } },\n [],\n (args) => {\n const prev = adapter.getView();\n const next: MapView = {\n ...prev,\n center: { lat: prev.center.lat + num(args.dLat), lng: prev.center.lng + num(args.dLng) },\n };\n adapter.setView(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_pan\",\n label: \"Panned camera\",\n undo: () => adapter.setView(prev),\n redo: () => adapter.setView(next),\n });\n return textResult(`Panned to ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)}`, next);\n },\n mTarget,\n );\n\n reg(\n \"map_zoom\",\n \"Zoom the camera by a relative delta (e.g. +1 zooms in one level, -2 out two).\",\n { delta: { type: \"number\" } },\n [\"delta\"],\n (args) => {\n const prev = adapter.getView();\n const next: MapView = { ...prev, zoom: prev.zoom + num(args.delta) };\n adapter.setView(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_zoom\",\n label: `Zoom → ${next.zoom}`,\n undo: () => adapter.setView(prev),\n redo: () => adapter.setView(next),\n });\n return textResult(`Zoom → ${next.zoom}`, next);\n },\n );\n\n reg(\n \"map_fit_bounds\",\n \"Fit the camera to enclose points. Pass `points`, or omit to fit all current markers.\",\n {\n points: {\n type: \"array\",\n description: \"Points to enclose, e.g. [{lat,lng},…].\",\n items: {\n type: \"object\",\n properties: { lat: { type: \"number\" }, lng: { type: \"number\" } },\n required: [\"lat\", \"lng\"],\n },\n },\n padding: { type: \"number\", description: \"Padding in pixels (default 40).\" },\n },\n [],\n (args) => {\n if (!adapter.fitBounds) {\n return errorResult(\"Host did not wire fitBounds (pass the <Map onReady> handle's fitBounds).\");\n }\n const points: LatLng[] = Array.isArray(args.points)\n ? (args.points as any[]).map((p) => ({ lat: num(p?.lat), lng: num(p?.lng) }))\n : adapter.getMarkers().map((m) => m.position);\n if (!points.length) {\n return errorResult(\"No points to fit (map has no markers).\");\n }\n adapter.fitBounds(points, args.padding !== undefined ? num(args.padding) : undefined);\n return textResult(`Fit camera to ${points.length} point(s).`);\n },\n );\n\n // ───────────── Markers ─────────────\n\n reg(\n \"map_add_marker\",\n \"Drop a marker. `id` is optional (auto-generated); `icon` is an emoji or 1–2 chars.\",\n {\n id: { type: \"string\" },\n lat: { type: \"number\" },\n lng: { type: \"number\" },\n label: { type: \"string\" },\n color: { type: \"string\", description: \"CSS color, e.g. #2563eb.\" },\n icon: { type: \"string\", description: \"Emoji / short text in the pin.\" },\n draggable: { type: \"boolean\" },\n data: { type: \"object\", description: \"Arbitrary JSON payload carried with the marker.\" },\n },\n [\"lat\", \"lng\"],\n (args) => {\n const id = args.id ? str(args.id) : newId(\"m\");\n if (adapter.getMarkers().some((m) => m.id === id)) {\n return errorResult(`A marker with id ${id} already exists — use map_update_marker.`);\n }\n const marker: MapMarker = {\n id,\n position: { lat: num(args.lat), lng: num(args.lng) },\n ...(args.label !== undefined ? { label: str(args.label) } : {}),\n ...(args.color !== undefined ? { color: str(args.color) } : {}),\n ...(args.icon !== undefined ? { icon: str(args.icon) } : {}),\n ...(args.draggable !== undefined ? { draggable: !!args.draggable } : {}),\n ...(args.data && typeof args.data === \"object\"\n ? { data: args.data as Record<string, unknown> }\n : {}),\n };\n adapter.setMarkers((all) => [...all, marker]);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_add_marker\",\n label: `Added marker ${id}`,\n undo: () => adapter.setMarkers((all) => all.filter((m) => m.id !== id)),\n redo: () => adapter.setMarkers((all) => [...all, marker]),\n });\n return textResult(`Added marker ${id} at ${marker.position.lat.toFixed(4)},${marker.position.lng.toFixed(4)}`, marker);\n },\n mTarget,\n );\n\n reg(\n \"map_update_marker\",\n \"Update a marker. Only provided fields change — update lat/lng repeatedly to drive a live track.\",\n {\n id: { type: \"string\" },\n lat: { type: \"number\" },\n lng: { type: \"number\" },\n label: { type: \"string\" },\n color: { type: \"string\" },\n icon: { type: \"string\" },\n draggable: { type: \"boolean\" },\n },\n [\"id\"],\n (args) => {\n const id = str(args.id);\n const prev = adapter.getMarkers().find((m) => m.id === id);\n if (!prev) {\n return errorResult(`No marker with id ${id}`);\n }\n const next: MapMarker = {\n ...prev,\n position: {\n lat: args.lat !== undefined ? num(args.lat) : prev.position.lat,\n lng: args.lng !== undefined ? num(args.lng) : prev.position.lng,\n },\n ...(args.label !== undefined ? { label: str(args.label) } : {}),\n ...(args.color !== undefined ? { color: str(args.color) } : {}),\n ...(args.icon !== undefined ? { icon: str(args.icon) } : {}),\n ...(args.draggable !== undefined ? { draggable: !!args.draggable } : {}),\n };\n adapter.setMarkers((all) => all.map((m) => (m.id === id ? next : m)));\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_update_marker\",\n label: `Updated marker ${id}`,\n undo: () => adapter.setMarkers((all) => all.map((m) => (m.id === id ? prev : m))),\n redo: () => adapter.setMarkers((all) => all.map((m) => (m.id === id ? next : m))),\n });\n return textResult(`Updated marker ${id}`, next);\n },\n mTarget,\n );\n\n reg(\n \"map_remove_marker\",\n \"Remove a marker by id.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const id = str(args.id);\n const prev = adapter.getMarkers().find((m) => m.id === id);\n if (!prev) {\n return errorResult(`No marker with id ${id}`);\n }\n adapter.setMarkers((all) => all.filter((m) => m.id !== id));\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_remove_marker\",\n label: `Removed marker ${id}`,\n undo: () => adapter.setMarkers((all) => [...all, prev]),\n redo: () => adapter.setMarkers((all) => all.filter((m) => m.id !== id)),\n });\n return textResult(`Removed marker ${id}`);\n },\n mTarget,\n );\n\n reg(\n \"map_select\",\n \"Select a marker (or pass no id / null to clear the selection).\",\n { id: { type: \"string\" } },\n [],\n (args) => {\n const prev = adapter.getSelected();\n const id = args.id === undefined || args.id === null ? null : str(args.id);\n if (id !== null && !adapter.getMarkers().some((m) => m.id === id)) {\n return errorResult(`No marker with id ${id}`);\n }\n adapter.setSelected(id);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_select\",\n label: id ? `Selected ${id}` : \"Cleared selection\",\n undo: () => adapter.setSelected(prev),\n redo: () => adapter.setSelected(id),\n });\n return textResult(id ? `Selected marker ${id}` : \"Cleared selection\", { selectedId: id });\n },\n mTarget,\n );\n\n // ───────────── Live tracking (camera follow) ─────────────\n\n reg(\n \"map_start_track\",\n \"Make the camera follow a marker as its position updates (live tracking). Requires the host to wire setFollow.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n if (!adapter.setFollow) {\n return errorResult(\"Host did not wire setFollow (pass the map's `follow` setter).\");\n }\n const id = str(args.id);\n if (!adapter.getMarkers().some((m) => m.id === id)) {\n return errorResult(`No marker with id ${id}`);\n }\n adapter.setFollow(id);\n return textResult(`Camera now following ${id}`, { follow: id });\n },\n mTarget,\n );\n\n reg(\n \"map_stop_track\",\n \"Stop following any marker (releases the camera). Requires the host to wire setFollow.\",\n {},\n [],\n () => {\n if (!adapter.setFollow) {\n return errorResult(\"Host did not wire setFollow.\");\n }\n adapter.setFollow(null);\n return textResult(\"Camera released (no longer following).\", { follow: null });\n },\n );\n\n return {\n id: \"map\",\n title: \"Map\",\n dispose: () => {\n for (const d of disposers) d();\n },\n };\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readHistory } from './chunk-
|
|
1
|
+
import { readHistory } from './chunk-R4XXOGQH.js';
|
|
2
2
|
import { useState, useEffect, useCallback } from 'react';
|
|
3
3
|
|
|
4
4
|
function useUndoStack(agentId, intervalMs = 500) {
|
|
@@ -21,5 +21,5 @@ function useUndoStack(agentId, intervalMs = 500) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export { useUndoStack };
|
|
24
|
-
//# sourceMappingURL=chunk-
|
|
25
|
-
//# sourceMappingURL=chunk-
|
|
24
|
+
//# sourceMappingURL=chunk-3WVXAB3D.js.map
|
|
25
|
+
//# sourceMappingURL=chunk-3WVXAB3D.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/undo/use-undo-stack.ts"],"names":[],"mappings":";;;AASO,SAAS,YAAA,CAAa,OAAA,EAAiB,UAAA,GAAa,GAAA,EAAK;AAC9D,EAAA,MAAM,CAAC,SAAS,UAAU,CAAA,GAAI,SAAS,MAAM,WAAA,CAAY,OAAO,CAAC,CAAA;AAEjE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,UAAA,CAAW,WAAA,CAAY,OAAO,CAAC,CAAA;AAAA,IACjC,CAAA;AACA,IAAA,MAAM,EAAA,GAAK,WAAA,CAAY,IAAA,EAAM,UAAU,CAAA;AACvC,IAAA,IAAA,EAAK;AACL,IAAA,OAAO,MAAM;AAAE,MAAA,SAAA,GAAY,IAAA;AAAM,MAAA,aAAA,CAAc,EAAE,CAAA;AAAA,IAAG,CAAA;AAAA,EACtD,CAAA,EAAG,CAAC,OAAA,EAAS,UAAU,CAAC,CAAA;AAExB,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,MAAM,UAAA,CAAW,WAAA,CAAY,OAAO,CAAC,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAC7E,EAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAC5B","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/undo/use-undo-stack.ts"],"names":[],"mappings":";;;AASO,SAAS,YAAA,CAAa,OAAA,EAAiB,UAAA,GAAa,GAAA,EAAK;AAC9D,EAAA,MAAM,CAAC,SAAS,UAAU,CAAA,GAAI,SAAS,MAAM,WAAA,CAAY,OAAO,CAAC,CAAA;AAEjE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,UAAA,CAAW,WAAA,CAAY,OAAO,CAAC,CAAA;AAAA,IACjC,CAAA;AACA,IAAA,MAAM,EAAA,GAAK,WAAA,CAAY,IAAA,EAAM,UAAU,CAAA;AACvC,IAAA,IAAA,EAAK;AACL,IAAA,OAAO,MAAM;AAAE,MAAA,SAAA,GAAY,IAAA;AAAM,MAAA,aAAA,CAAc,EAAE,CAAA;AAAA,IAAG,CAAA;AAAA,EACtD,CAAA,EAAG,CAAC,OAAA,EAAS,UAAU,CAAC,CAAA;AAExB,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,MAAM,UAAA,CAAW,WAAA,CAAY,OAAO,CAAC,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAC7E,EAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAC5B","file":"chunk-3WVXAB3D.js","sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { readHistory } from \"./undo-stack\";\n\n/**\n * useUndoStack — minimal React snapshot of an agent's history. Polls every\n * `intervalMs` (default 500). Use this to render an inline \"agent timeline\"\n * in a sidebar or activity panel. No subscription model in v1 — keeping it\n * simple; bridge mutations are infrequent enough that polling is fine.\n */\nexport function useUndoStack(agentId: string, intervalMs = 500) {\n const [history, setHistory] = useState(() => readHistory(agentId));\n\n useEffect(() => {\n let cancelled = false;\n const tick = () => {\n if (cancelled) return;\n setHistory(readHistory(agentId));\n };\n const id = setInterval(tick, intervalMs);\n tick();\n return () => { cancelled = true; clearInterval(id); };\n }, [agentId, intervalMs]);\n\n const refresh = useCallback(() => setHistory(readHistory(agentId)), [agentId]);\n return { history, refresh };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomBytes, createHash, timingSafeEqual } from 'crypto';
|
|
2
|
-
import { URL } from 'url';
|
|
2
|
+
import { URL as URL$1 } from 'url';
|
|
3
3
|
|
|
4
4
|
// src/relay-server/core.ts
|
|
5
5
|
var MemoryStore = class {
|
|
@@ -22,6 +22,7 @@ var MemoryStore = class {
|
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
var SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{4,64}$/;
|
|
25
|
+
var SUBSCRIBER_ID_PATTERN = /^[a-f0-9]{16}$/;
|
|
25
26
|
var RelayBroker = class {
|
|
26
27
|
constructor(opts = {}) {
|
|
27
28
|
/** Per-session, per-direction subscriber list. */
|
|
@@ -29,6 +30,7 @@ var RelayBroker = class {
|
|
|
29
30
|
/** Per-session map of JSON-RPC request id -> the client that asked. */
|
|
30
31
|
this.callers = /* @__PURE__ */ new Map();
|
|
31
32
|
this.ttlMs = opts.ttlMs ?? 4 * 60 * 60 * 1e3;
|
|
33
|
+
this.pollIdleMs = opts.pollIdleMs ?? 6e4;
|
|
32
34
|
this.store = opts.store ?? new MemoryStore();
|
|
33
35
|
const tick = opts.reapIntervalMs ?? 6e4;
|
|
34
36
|
if (tick > 0) {
|
|
@@ -40,6 +42,7 @@ var RelayBroker = class {
|
|
|
40
42
|
}
|
|
41
43
|
dispose() {
|
|
42
44
|
if (this.reaper) clearInterval(this.reaper);
|
|
45
|
+
for (const id of [...this.subs.keys()]) this.endSubscribers(id);
|
|
43
46
|
this.subs.clear();
|
|
44
47
|
this.callers.clear();
|
|
45
48
|
}
|
|
@@ -64,6 +67,7 @@ var RelayBroker = class {
|
|
|
64
67
|
unregister(id, token) {
|
|
65
68
|
if (!this.validate(id, token)) return false;
|
|
66
69
|
this.store.deleteSession(id);
|
|
70
|
+
this.endSubscribers(id);
|
|
67
71
|
this.subs.delete(id);
|
|
68
72
|
this.callers.delete(id);
|
|
69
73
|
return true;
|
|
@@ -113,6 +117,7 @@ var RelayBroker = class {
|
|
|
113
117
|
/** Drop a session — the page closed, or a test needs it gone. */
|
|
114
118
|
dropSession(id) {
|
|
115
119
|
this.store.deleteSession(id);
|
|
120
|
+
this.endSubscribers(id);
|
|
116
121
|
this.subs.delete(id);
|
|
117
122
|
this.callers.delete(id);
|
|
118
123
|
}
|
|
@@ -143,7 +148,8 @@ var RelayBroker = class {
|
|
|
143
148
|
* the caller (an HTTP handler) pumps as SSE.
|
|
144
149
|
*/
|
|
145
150
|
subscribe(id, token, direction, opts = {}) {
|
|
146
|
-
|
|
151
|
+
const auth = this.check(id, token);
|
|
152
|
+
if (!auth.ok) return auth;
|
|
147
153
|
const subscriberId = randomBytes(8).toString("hex");
|
|
148
154
|
const subscriber = {
|
|
149
155
|
id: subscriberId,
|
|
@@ -153,31 +159,7 @@ var RelayBroker = class {
|
|
|
153
159
|
client: opts.client
|
|
154
160
|
};
|
|
155
161
|
this.getDirSubs(id, direction).set(subscriberId, subscriber);
|
|
156
|
-
if (direction === "outbound")
|
|
157
|
-
this.fanOut(
|
|
158
|
-
id,
|
|
159
|
-
"inbound",
|
|
160
|
-
JSON.stringify({
|
|
161
|
-
jsonrpc: "2.0",
|
|
162
|
-
method: "notifications/peer_joined",
|
|
163
|
-
params: { subscriberId, ts: Date.now() }
|
|
164
|
-
})
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
const unsubscribe = () => {
|
|
168
|
-
this.getDirSubs(id, direction).delete(subscriberId);
|
|
169
|
-
if (direction === "outbound") {
|
|
170
|
-
this.fanOut(
|
|
171
|
-
id,
|
|
172
|
-
"inbound",
|
|
173
|
-
JSON.stringify({
|
|
174
|
-
jsonrpc: "2.0",
|
|
175
|
-
method: "notifications/peer_left",
|
|
176
|
-
params: { subscriberId, ts: Date.now() }
|
|
177
|
-
})
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
};
|
|
162
|
+
if (direction === "outbound") this.announcePeer(id, "notifications/peer_joined", subscriberId);
|
|
181
163
|
const frames = async function* () {
|
|
182
164
|
while (true) {
|
|
183
165
|
if (this.queue.length > 0) {
|
|
@@ -185,6 +167,7 @@ var RelayBroker = class {
|
|
|
185
167
|
if (next2 !== void 0) yield next2;
|
|
186
168
|
continue;
|
|
187
169
|
}
|
|
170
|
+
if (this.ended) return;
|
|
188
171
|
const next = await new Promise((resolve) => {
|
|
189
172
|
this.resolveNext = resolve;
|
|
190
173
|
});
|
|
@@ -198,8 +181,88 @@ var RelayBroker = class {
|
|
|
198
181
|
subscriberId,
|
|
199
182
|
frames: frames(),
|
|
200
183
|
unsubscribe: () => {
|
|
201
|
-
|
|
202
|
-
|
|
184
|
+
this.endSubscriber(subscriber);
|
|
185
|
+
this.removeSubscriber(id, subscriber);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Attach a LONG-POLL subscriber, or re-attach the one a previous poll created.
|
|
191
|
+
*
|
|
192
|
+
* The CDN-safe receive leg: a series of short requests instead of one open
|
|
193
|
+
* stream, because Cloudflare's HTTP/3 edge resets long-lived SSE. Same
|
|
194
|
+
* contract as the PHP relay in px-ui-sandbox and the one
|
|
195
|
+
* `@particle-academy/fancy-cf-relay` and `mcp-relay-client` speak:
|
|
196
|
+
*
|
|
197
|
+
* - The first poll gets a fresh 16-hex subscriber id; the client echoes it back
|
|
198
|
+
* as `subscriber` on every later poll and reads the same queue.
|
|
199
|
+
* - An id in that shape that this session does not know (pruned, say) is
|
|
200
|
+
* adopted as a NEW subscriber under that id, as the PHP relay does, so a
|
|
201
|
+
* client that went quiet and came back keeps its identity.
|
|
202
|
+
* - An id belonging to a STREAMING subscriber is never adopted: one queue read
|
|
203
|
+
* by two consumers splits its frames between them.
|
|
204
|
+
*
|
|
205
|
+
* Frames queue on the subscriber between polls, so nothing is lost in the gap
|
|
206
|
+
* between one request ending and the next arriving. A poller that stops is
|
|
207
|
+
* pruned after `pollIdleMs`.
|
|
208
|
+
*/
|
|
209
|
+
poll(id, token, direction, opts = {}) {
|
|
210
|
+
const auth = this.check(id, token);
|
|
211
|
+
if (!auth.ok) return auth;
|
|
212
|
+
const dir = this.getDirSubs(id, direction);
|
|
213
|
+
const requested = opts.subscriber && SUBSCRIBER_ID_PATTERN.test(opts.subscriber) ? opts.subscriber : void 0;
|
|
214
|
+
const existing = requested ? dir.get(requested) : void 0;
|
|
215
|
+
let subscriber;
|
|
216
|
+
let created;
|
|
217
|
+
if (existing?.poll) {
|
|
218
|
+
subscriber = existing;
|
|
219
|
+
created = false;
|
|
220
|
+
} else {
|
|
221
|
+
const subscriberId = requested && !existing ? requested : randomBytes(8).toString("hex");
|
|
222
|
+
subscriber = {
|
|
223
|
+
id: subscriberId,
|
|
224
|
+
direction,
|
|
225
|
+
queue: [],
|
|
226
|
+
resolveNext: null,
|
|
227
|
+
client: opts.client,
|
|
228
|
+
poll: { lastSeen: Date.now(), parked: 0, wakers: /* @__PURE__ */ new Set() }
|
|
229
|
+
};
|
|
230
|
+
dir.set(subscriberId, subscriber);
|
|
231
|
+
created = true;
|
|
232
|
+
if (direction === "outbound") this.announcePeer(id, "notifications/peer_joined", subscriberId);
|
|
233
|
+
}
|
|
234
|
+
const state = subscriber.poll;
|
|
235
|
+
state.lastSeen = Date.now();
|
|
236
|
+
return {
|
|
237
|
+
ok: true,
|
|
238
|
+
subscriberId: subscriber.id,
|
|
239
|
+
created,
|
|
240
|
+
wait: async (ms, signal) => {
|
|
241
|
+
state.parked++;
|
|
242
|
+
state.lastSeen = Date.now();
|
|
243
|
+
try {
|
|
244
|
+
if (subscriber.queue.length === 0 && ms > 0 && !subscriber.ended && !signal?.aborted) {
|
|
245
|
+
await new Promise((resolve) => {
|
|
246
|
+
const done = () => {
|
|
247
|
+
clearTimeout(timer);
|
|
248
|
+
signal?.removeEventListener("abort", done);
|
|
249
|
+
state.wakers.delete(done);
|
|
250
|
+
resolve();
|
|
251
|
+
};
|
|
252
|
+
const timer = setTimeout(done, ms);
|
|
253
|
+
state.wakers.add(done);
|
|
254
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
if (signal?.aborted) return [];
|
|
258
|
+
return subscriber.queue.splice(0);
|
|
259
|
+
} finally {
|
|
260
|
+
state.parked--;
|
|
261
|
+
state.lastSeen = Date.now();
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
requeue: (frames) => {
|
|
265
|
+
if (frames.length > 0 && !subscriber.ended) subscriber.queue.unshift(...frames);
|
|
203
266
|
}
|
|
204
267
|
};
|
|
205
268
|
}
|
|
@@ -292,16 +355,78 @@ var RelayBroker = class {
|
|
|
292
355
|
if (!dir) return;
|
|
293
356
|
for (const sub of dir.values()) {
|
|
294
357
|
if (sub.client !== client) continue;
|
|
295
|
-
|
|
296
|
-
sub.resolveNext?.(sub.queue.shift() ?? null);
|
|
358
|
+
this.deliver(sub, payload);
|
|
297
359
|
}
|
|
298
360
|
}
|
|
299
361
|
fanOut(sessionId, direction, payload) {
|
|
300
362
|
const dir = this.subs.get(sessionId)?.get(direction);
|
|
301
363
|
if (!dir) return;
|
|
302
|
-
for (const sub of dir.values())
|
|
303
|
-
|
|
304
|
-
|
|
364
|
+
for (const sub of dir.values()) this.deliver(sub, payload);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Hand one frame to one subscriber.
|
|
368
|
+
*
|
|
369
|
+
* The resolver is CLEARED before it is called. It used to stay set until the
|
|
370
|
+
* generator resumed on a later microtask, so a second frame in the same tick
|
|
371
|
+
* called an already-settled resolver — a no-op — after shifting its frame out
|
|
372
|
+
* of the queue, and that frame was lost. Cleared first, the second frame just
|
|
373
|
+
* waits in the queue for the generator to come back for it.
|
|
374
|
+
*/
|
|
375
|
+
deliver(sub, payload) {
|
|
376
|
+
if (sub.ended) return;
|
|
377
|
+
sub.queue.push(payload);
|
|
378
|
+
const resolve = sub.resolveNext;
|
|
379
|
+
if (resolve) {
|
|
380
|
+
sub.resolveNext = null;
|
|
381
|
+
resolve(sub.queue.shift() ?? null);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (sub.poll) for (const wake of [...sub.poll.wakers]) wake();
|
|
385
|
+
}
|
|
386
|
+
/** Tell the page (the inbound side) that an agent arrived or left. */
|
|
387
|
+
announcePeer(sessionId, method, subscriberId) {
|
|
388
|
+
this.fanOut(sessionId, "inbound", JSON.stringify({ jsonrpc: "2.0", method, params: { subscriberId, ts: Date.now() } }));
|
|
389
|
+
}
|
|
390
|
+
/** End one subscriber: close its stream, or release its parked polls. Idempotent. */
|
|
391
|
+
endSubscriber(sub) {
|
|
392
|
+
if (sub.ended) return;
|
|
393
|
+
sub.ended = true;
|
|
394
|
+
const resolve = sub.resolveNext;
|
|
395
|
+
sub.resolveNext = null;
|
|
396
|
+
resolve?.(null);
|
|
397
|
+
if (sub.poll) for (const wake of [...sub.poll.wakers]) wake();
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* End every subscriber of a session whose session is going away.
|
|
401
|
+
*
|
|
402
|
+
* Streams used to be dropped from the map WITHOUT being woken, so an SSE leg
|
|
403
|
+
* stayed open, heartbeating, for a session that no longer existed — and its
|
|
404
|
+
* client could not learn the page had closed. Ended, the stream closes, the
|
|
405
|
+
* client reconnects, and `events` answers 410.
|
|
406
|
+
*/
|
|
407
|
+
endSubscribers(sessionId) {
|
|
408
|
+
const dirs = this.subs.get(sessionId);
|
|
409
|
+
if (!dirs) return;
|
|
410
|
+
for (const dir of dirs.values()) for (const sub of dir.values()) this.endSubscriber(sub);
|
|
411
|
+
}
|
|
412
|
+
/** Remove a subscriber from its session, announcing an agent's departure once. */
|
|
413
|
+
removeSubscriber(sessionId, sub) {
|
|
414
|
+
const dir = this.subs.get(sessionId)?.get(sub.direction);
|
|
415
|
+
if (!dir || dir.get(sub.id) !== sub) return;
|
|
416
|
+
dir.delete(sub.id);
|
|
417
|
+
if (sub.direction === "outbound") this.announcePeer(sessionId, "notifications/peer_left", sub.id);
|
|
418
|
+
}
|
|
419
|
+
/** Drop long-poll subscribers that stopped polling. Never one with a poll parked. */
|
|
420
|
+
prunePollers(now) {
|
|
421
|
+
for (const [sessionId, dirs] of this.subs) {
|
|
422
|
+
for (const dir of dirs.values()) {
|
|
423
|
+
for (const sub of [...dir.values()]) {
|
|
424
|
+
if (!sub.poll || sub.poll.parked > 0) continue;
|
|
425
|
+
if (now - sub.poll.lastSeen <= this.pollIdleMs) continue;
|
|
426
|
+
this.endSubscriber(sub);
|
|
427
|
+
this.removeSubscriber(sessionId, sub);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
305
430
|
}
|
|
306
431
|
}
|
|
307
432
|
/**
|
|
@@ -337,18 +462,15 @@ var RelayBroker = class {
|
|
|
337
462
|
return "id" in o && hasResult !== hasError;
|
|
338
463
|
}
|
|
339
464
|
reap() {
|
|
340
|
-
const
|
|
465
|
+
const now = Date.now();
|
|
466
|
+
const cutoff = now - this.ttlMs;
|
|
341
467
|
for (const id of this.store.expiredSessionIds(cutoff)) {
|
|
342
|
-
|
|
343
|
-
if (dirs) {
|
|
344
|
-
for (const dir of dirs.values()) {
|
|
345
|
-
for (const sub of dir.values()) sub.resolveNext?.(null);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
468
|
+
this.endSubscribers(id);
|
|
348
469
|
this.subs.delete(id);
|
|
349
470
|
this.callers.delete(id);
|
|
350
471
|
this.store.deleteSession(id);
|
|
351
472
|
}
|
|
473
|
+
this.prunePollers(now);
|
|
352
474
|
}
|
|
353
475
|
};
|
|
354
476
|
function sha256Hex(input) {
|
|
@@ -358,19 +480,69 @@ function timingSafeEqualHex(a, b) {
|
|
|
358
480
|
if (a.length !== b.length) return false;
|
|
359
481
|
return timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
|
|
360
482
|
}
|
|
483
|
+
|
|
484
|
+
// src/relay-server/cors.ts
|
|
485
|
+
function parseCorsOrigins(value) {
|
|
486
|
+
const entries = (typeof value === "string" ? value.split(",") : [...value]).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
487
|
+
if (entries.length === 0) {
|
|
488
|
+
throw new Error("CORS origin list is empty: pass `*` or one or more origins, e.g. https://example.com");
|
|
489
|
+
}
|
|
490
|
+
if (entries.includes("*")) {
|
|
491
|
+
if (entries.length === 1) return { kind: "any" };
|
|
492
|
+
throw new Error(
|
|
493
|
+
"CORS `*` cannot be combined with named origins \u2014 `*` already allows every origin, so the list would mean nothing. Pass either `*` or the origins."
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
const origins = [];
|
|
497
|
+
for (const entry of entries) {
|
|
498
|
+
const origin = normalizeOrigin(entry);
|
|
499
|
+
if (!origins.includes(origin)) origins.push(origin);
|
|
500
|
+
}
|
|
501
|
+
return { kind: "list", origins };
|
|
502
|
+
}
|
|
503
|
+
function normalizeOrigin(raw) {
|
|
504
|
+
if (raw.toLowerCase() === "null") {
|
|
505
|
+
throw new Error("CORS origin `null` is refused: it is what sandboxed iframes and file:// pages send.");
|
|
506
|
+
}
|
|
507
|
+
let url;
|
|
508
|
+
try {
|
|
509
|
+
url = new URL(raw);
|
|
510
|
+
} catch {
|
|
511
|
+
throw new Error(`CORS origin "${raw}" is not an origin \u2014 expected scheme://host[:port], e.g. https://example.com`);
|
|
512
|
+
}
|
|
513
|
+
if (url.pathname !== "/" && url.pathname !== "" || url.search || url.hash || url.username || url.password) {
|
|
514
|
+
throw new Error(`CORS origin "${raw}" has a path, query or credentials \u2014 an origin is only scheme://host[:port]`);
|
|
515
|
+
}
|
|
516
|
+
if (url.origin !== "null") return url.origin;
|
|
517
|
+
if (url.host) return `${url.protocol}//${url.host}`;
|
|
518
|
+
throw new Error(`CORS origin "${raw}" is not an origin \u2014 expected scheme://host[:port], e.g. https://example.com`);
|
|
519
|
+
}
|
|
520
|
+
function allowOriginFor(policy, requestOrigin) {
|
|
521
|
+
if (policy.kind === "any") return "*";
|
|
522
|
+
return requestOrigin !== void 0 && policy.origins.includes(requestOrigin) ? requestOrigin : null;
|
|
523
|
+
}
|
|
524
|
+
function describeCorsPolicy(policy) {
|
|
525
|
+
return policy.kind === "any" ? "*" : policy.origins.join(",");
|
|
526
|
+
}
|
|
527
|
+
var POLL_MAX_WAIT_MS = 25e3;
|
|
528
|
+
var POLL_DEFAULT_WAIT_MS = 2e4;
|
|
529
|
+
function pollWaitMs(raw) {
|
|
530
|
+
if (raw === null || raw === void 0) return POLL_DEFAULT_WAIT_MS;
|
|
531
|
+
const n = Number.parseInt(raw, 10);
|
|
532
|
+
if (!Number.isFinite(n)) return 0;
|
|
533
|
+
return Math.min(Math.max(n, 0), POLL_MAX_WAIT_MS);
|
|
534
|
+
}
|
|
361
535
|
function createNodeRelay(opts = {}) {
|
|
362
536
|
const broker = new RelayBroker(opts);
|
|
363
537
|
const prefix = (opts.pathPrefix ?? "").replace(/\/$/, "");
|
|
364
|
-
const cors = opts.corsAllowOrigin ?? "*";
|
|
365
|
-
const allowedOrigins = opts.allowedOrigins;
|
|
538
|
+
const cors = opts.allowedOrigins && opts.allowedOrigins.length > 0 ? parseCorsOrigins(opts.allowedOrigins) : parseCorsOrigins(opts.corsAllowOrigin ?? "*");
|
|
366
539
|
function setCorsHeaders(res, req) {
|
|
367
|
-
if (
|
|
368
|
-
|
|
369
|
-
res.setHeader("access-control-allow-origin", origin && allowedOrigins.includes(origin) ? origin : "null");
|
|
370
|
-
res.setHeader("vary", "origin");
|
|
371
|
-
} else {
|
|
372
|
-
res.setHeader("access-control-allow-origin", cors);
|
|
540
|
+
if (cors.kind === "list") {
|
|
541
|
+
res.setHeader("vary", "Origin");
|
|
373
542
|
}
|
|
543
|
+
const origin = req?.headers.origin;
|
|
544
|
+
const allow = allowOriginFor(cors, typeof origin === "string" ? origin : void 0);
|
|
545
|
+
if (allow !== null) res.setHeader("access-control-allow-origin", allow);
|
|
374
546
|
res.setHeader("access-control-allow-methods", "GET, POST, OPTIONS");
|
|
375
547
|
res.setHeader("access-control-allow-headers", "content-type, x-csrf-token, accept, authorization");
|
|
376
548
|
res.setHeader("access-control-max-age", "86400");
|
|
@@ -399,12 +571,12 @@ function createNodeRelay(opts = {}) {
|
|
|
399
571
|
}
|
|
400
572
|
function getQuery(req) {
|
|
401
573
|
const host = req.headers.host || "x";
|
|
402
|
-
const u = new URL(req.url || "/", `http://${host}`);
|
|
574
|
+
const u = new URL$1(req.url || "/", `http://${host}`);
|
|
403
575
|
return u.searchParams;
|
|
404
576
|
}
|
|
405
577
|
function getPathname(req) {
|
|
406
578
|
const host = req.headers.host || "x";
|
|
407
|
-
const u = new URL(req.url || "/", `http://${host}`);
|
|
579
|
+
const u = new URL$1(req.url || "/", `http://${host}`);
|
|
408
580
|
return u.pathname;
|
|
409
581
|
}
|
|
410
582
|
const register = async (req, res) => {
|
|
@@ -487,7 +659,7 @@ function createNodeRelay(opts = {}) {
|
|
|
487
659
|
client: getQuery(req).get("client") ?? void 0
|
|
488
660
|
});
|
|
489
661
|
if (!sub.ok) {
|
|
490
|
-
res.statusCode = 401;
|
|
662
|
+
res.statusCode = sub.reason === "session_gone" ? 410 : 401;
|
|
491
663
|
res.setHeader("content-type", "text/event-stream");
|
|
492
664
|
res.write(`event: error
|
|
493
665
|
data: ${sub.reason}
|
|
@@ -532,6 +704,38 @@ data: ${frame}
|
|
|
532
704
|
res.end();
|
|
533
705
|
}
|
|
534
706
|
};
|
|
707
|
+
const poll = async (req, res) => {
|
|
708
|
+
setCorsHeaders(res, req);
|
|
709
|
+
if (req.method === "OPTIONS") {
|
|
710
|
+
res.statusCode = 204;
|
|
711
|
+
return res.end();
|
|
712
|
+
}
|
|
713
|
+
if (req.method !== "GET") return json(res, 405, { error: "method_not_allowed" });
|
|
714
|
+
const session = extractSession(req, prefix);
|
|
715
|
+
if (!session) return json(res, 400, { error: "missing_session" });
|
|
716
|
+
const q = getQuery(req);
|
|
717
|
+
const direction = q.get("direction") === "outbound" ? "outbound" : "inbound";
|
|
718
|
+
const attached = broker.poll(session, q.get("token") ?? "", direction, {
|
|
719
|
+
subscriber: q.get("subscriber") ?? void 0,
|
|
720
|
+
client: q.get("client") ?? void 0
|
|
721
|
+
});
|
|
722
|
+
if (!attached.ok) {
|
|
723
|
+
return json(res, attached.reason === "session_gone" ? 410 : 401, { error: attached.reason });
|
|
724
|
+
}
|
|
725
|
+
const gone = new AbortController();
|
|
726
|
+
const onClose = () => {
|
|
727
|
+
if (!res.writableEnded) gone.abort();
|
|
728
|
+
};
|
|
729
|
+
res.on("close", onClose);
|
|
730
|
+
const frames = await attached.wait(pollWaitMs(q.get("wait")), gone.signal);
|
|
731
|
+
res.off("close", onClose);
|
|
732
|
+
if (gone.signal.aborted || res.destroyed) {
|
|
733
|
+
attached.requeue(frames);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
res.setHeader("cache-control", "no-store");
|
|
737
|
+
return json(res, 200, { subscriber: attached.subscriberId, frames });
|
|
738
|
+
};
|
|
535
739
|
const handler = async (req, res) => {
|
|
536
740
|
const pathname = getPathname(req);
|
|
537
741
|
if (!pathname.startsWith(prefix + "/")) {
|
|
@@ -539,20 +743,21 @@ data: ${frame}
|
|
|
539
743
|
}
|
|
540
744
|
const rest = pathname.slice(prefix.length);
|
|
541
745
|
if (rest === "/register") return register(req, res);
|
|
542
|
-
const m = /^\/([A-Za-z0-9_-]{4,64})\/(inbox|outbox|events|unregister)$/.exec(rest);
|
|
746
|
+
const m = /^\/([A-Za-z0-9_-]{4,64})\/(inbox|outbox|events|poll|unregister)$/.exec(rest);
|
|
543
747
|
if (!m) return json(res, 404, { error: "not_found" });
|
|
544
748
|
const route = m[2];
|
|
545
749
|
if (route === "inbox") return inbox(req, res);
|
|
546
750
|
if (route === "outbox") return outbox(req, res);
|
|
547
751
|
if (route === "events") return events(req, res);
|
|
752
|
+
if (route === "poll") return poll(req, res);
|
|
548
753
|
if (route === "unregister") return unregister(req, res);
|
|
549
754
|
return json(res, 404, { error: "not_found" });
|
|
550
755
|
};
|
|
551
|
-
return { broker, handler, register, inbox, outbox, events, unregister };
|
|
756
|
+
return { broker, handler, register, inbox, outbox, events, poll, unregister };
|
|
552
757
|
}
|
|
553
758
|
function extractSession(req, prefix) {
|
|
554
759
|
const host = req.headers.host || "x";
|
|
555
|
-
const u = new URL(req.url || "/", `http://${host}`);
|
|
760
|
+
const u = new URL$1(req.url || "/", `http://${host}`);
|
|
556
761
|
const path = u.pathname;
|
|
557
762
|
if (prefix && !path.startsWith(prefix + "/")) return null;
|
|
558
763
|
const rest = prefix ? path.slice(prefix.length) : path;
|
|
@@ -564,6 +769,6 @@ function flush(res) {
|
|
|
564
769
|
r.flush?.();
|
|
565
770
|
}
|
|
566
771
|
|
|
567
|
-
export { RelayBroker, createNodeRelay };
|
|
568
|
-
//# sourceMappingURL=chunk-
|
|
569
|
-
//# sourceMappingURL=chunk-
|
|
772
|
+
export { RelayBroker, createNodeRelay, describeCorsPolicy, parseCorsOrigins };
|
|
773
|
+
//# sourceMappingURL=chunk-5W34X4EY.js.map
|
|
774
|
+
//# sourceMappingURL=chunk-5W34X4EY.js.map
|