@sxl-studio/bridge 1.2.0 → 1.3.2

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.
Files changed (63) hide show
  1. package/README.md +122 -48
  2. package/dist/audit.d.ts +21 -0
  3. package/dist/audit.js +24 -0
  4. package/dist/audit.js.map +1 -0
  5. package/dist/auth.d.ts +18 -0
  6. package/dist/auth.js +39 -0
  7. package/dist/auth.js.map +1 -0
  8. package/dist/http-api.d.ts +13 -0
  9. package/dist/http-api.js +101 -5
  10. package/dist/http-api.js.map +1 -1
  11. package/dist/idempotency.d.ts +13 -0
  12. package/dist/idempotency.js +47 -0
  13. package/dist/idempotency.js.map +1 -0
  14. package/dist/mcp-factory.d.ts +1 -1
  15. package/dist/mcp-factory.js +19 -3
  16. package/dist/mcp-factory.js.map +1 -1
  17. package/dist/mcp-server.d.ts +1 -1
  18. package/dist/mcp-server.js +1 -1
  19. package/dist/mcp-server.js.map +1 -1
  20. package/dist/sxl-mcp-instructions.d.ts +1 -1
  21. package/dist/sxl-mcp-instructions.js +123 -23
  22. package/dist/sxl-mcp-instructions.js.map +1 -1
  23. package/dist/tools/catalogue-bootstrap.d.ts +9 -0
  24. package/dist/tools/catalogue-bootstrap.js +168 -0
  25. package/dist/tools/catalogue-bootstrap.js.map +1 -0
  26. package/dist/tools/composition.d.ts +1 -1
  27. package/dist/tools/composition.js +30 -2
  28. package/dist/tools/composition.js.map +1 -1
  29. package/dist/tools/data.d.ts +1 -1
  30. package/dist/tools/diagnostics.d.ts +1 -1
  31. package/dist/tools/diagnostics.js +7 -5
  32. package/dist/tools/diagnostics.js.map +1 -1
  33. package/dist/tools/figma-nodes.d.ts +1 -1
  34. package/dist/tools/figma-rc-extended.d.ts +1 -1
  35. package/dist/tools/figma-url.d.ts +20 -0
  36. package/dist/tools/figma-url.js +52 -0
  37. package/dist/tools/figma-url.js.map +1 -0
  38. package/dist/tools/git.d.ts +1 -1
  39. package/dist/tools/meta.d.ts +10 -0
  40. package/dist/tools/meta.js +36 -0
  41. package/dist/tools/meta.js.map +1 -0
  42. package/dist/tools/orchestration.d.ts +11 -0
  43. package/dist/tools/orchestration.js +112 -0
  44. package/dist/tools/orchestration.js.map +1 -0
  45. package/dist/tools/registry.d.ts +22 -0
  46. package/dist/tools/registry.js +26 -0
  47. package/dist/tools/registry.js.map +1 -0
  48. package/dist/tools/resources.d.ts +17 -0
  49. package/dist/tools/resources.js +92 -0
  50. package/dist/tools/resources.js.map +1 -0
  51. package/dist/tools/shared.d.ts +20 -0
  52. package/dist/tools/shared.js +61 -0
  53. package/dist/tools/shared.js.map +1 -0
  54. package/dist/tools/styles.d.ts +8 -0
  55. package/dist/tools/styles.js +55 -0
  56. package/dist/tools/styles.js.map +1 -0
  57. package/dist/tools/tokens.d.ts +2 -2
  58. package/dist/tools/tokens.js +65 -34
  59. package/dist/tools/tokens.js.map +1 -1
  60. package/dist/tools/variables.d.ts +11 -0
  61. package/dist/tools/variables.js +55 -0
  62. package/dist/tools/variables.js.map +1 -0
  63. package/package.json +3 -2
package/README.md CHANGED
@@ -5,86 +5,93 @@ Node.js process that connects **Cursor (or any MCP client)** and **HTTP clients*
5
5
  ## What it does
6
6
 
7
7
  1. **WebSocket** — plugin UI iframe connects here and forwards `remote-command` / results.
8
- 2. **MCP (stdio)** — Cursor Agent calls tools (`export_variables`, `inspect_selection`, …); each tool maps to one plugin command.
9
- 3. **HTTP** — same command queue for scripts and other tools.
8
+ 2. **MCP (Streamable HTTP + stdio)** — Cursor / Claude Desktop / any MCP client calls typed tools (`export_variables`, `export_composition_json`, `get_codegen`, `compose_from_url`, …); each tool maps to one plugin command or an orchestration that chains several.
9
+ 3. **HTTP** — same command queue for scripts, CI, curl, idempotency-safe retries, audit log.
10
10
 
11
- Official [Figma MCP](https://developers.figma.com/docs/figma-mcp-server/) does not run your plugin code. Use **both**: Figma MCP for file/design context; **this bridge** for SXL-specific operations (compositions, token export, mappings, etc.).
11
+ Official [Figma MCP](https://developers.figma.com/docs/figma-mcp-server/) does not run your plugin code. Use **both**: Figma MCP for file/design context; **this bridge** for SXL-specific operations (compositions, token export, mappings, Git, Dev Mode codegen).
12
12
 
13
13
  ### Figma MCP vs SXL Bridge (product split)
14
14
 
15
- Figma documents the hosted and desktop MCP in the Help Center: [Guide to the Figma MCP server](https://help.figma.com/hc/en-us/articles/32132100833559-Guide-to-the-Figma-MCP-server). **Remote** MCP is the default in their guidance; some client features (for example write-to-canvas flows in their compatibility matrix) are oriented toward **remote** MCP rather than a local-only server.
16
-
17
15
  | Need | Use |
18
16
  |------|-----|
19
- | Native file operations where Figma’s MCP tools are enough (context, many canvas writes, variables in supported flows) | **Official Figma MCP** (often remote `https://mcp.figma.com/mcp` per Figma docs) |
20
- | Plugin-only workflows: compositions, plugin token/Git APIs, whitelisted node helpers that run in **this** plugin | **SXL Studio Bridge** + plugin Remote Connect |
17
+ | Native file operations where Figma’s MCP tools are enough (context, many canvas writes, variables in supported flows) | **Official Figma MCP** (often remote `https://mcp.figma.com/mcp`) |
18
+ | Plugin-only workflows: compositions, plugin token/Git APIs, whitelisted node helpers, Dev Mode codegen parity | **SXL Studio Bridge** + plugin Remote Connect |
21
19
 
22
- Bridge forwards `commandType` + `payload` over WebSocket; **execution is always in the plugin** (whitelist + handlers). Adding an MCP tool in Bridge without the matching plugin handler will not work.
20
+ Bridge forwards `commandType` + `payload` over WebSocket; **execution is always in the plugin** (whitelist + handlers). Adding an MCP tool in Bridge without the matching plugin handler will return `not_whitelisted`.
23
21
 
24
22
  ### Version compatibility (npm Bridge ⟷ plugin)
25
23
 
26
- When you add or change remote commands:
27
-
28
- 1. Implement the command in the **plugin** (`WHITELISTED_COMMANDS`, `remote/canvas/` or `remote/sxl/`, etc.).
29
- 2. Register the matching MCP tool (and payload shape) in **Bridge** `src/tools/`.
30
- 3. Bump **Bridge** semver (`package.json`) and document the minimum **plugin** build users need.
31
-
32
- | `@sxl-studio/bridge` (npm) | SXL Studio plugin |
33
- |---------------------------|-------------------|
34
- | `1.0.x` | Same-era plugin with base remote node tools (`create_frame`, `set_node_fill`, …) |
35
- | `1.1.x` | Plugin build that includes `set_node_fill_variable` and extended `create_frame` / `create_text` (`parentId`, Auto Layout–related optional fields) |
36
- | `1.2.x` | Plugin build that includes Remote module split (`dispatch/`, `canvas/`, `sxl/`), MCP `instructions`, base canvas tools (`create_rectangle`, `set_auto_layout`, `duplicate_subtree`, `create_component_instance`, `apply_documentation_payload`), plus **extended** Remote Connect canvas tools registered from `src/tools/figma-rc-extended.ts`. Bridge **1.2.0+** reads `package.json` for startup version, aligns **timeouts** with plugin `COMMAND_TIMEOUTS`, and validates **`POST /api/command`** bodies (`commandType` + object `payload`). |
24
+ | `@sxl-studio/bridge` (npm) | SXL Studio plugin | Highlights |
25
+ |---------------------------|-------------------|------------|
26
+ | `1.0.x` | same-era | Base remote node tools (`create_frame`, `set_node_fill`, …) |
27
+ | `1.1.x` | same-era | `set_node_fill_variable`, extended `create_frame` / `create_text` (`parentId`, Auto Layout fields) |
28
+ | `1.2.x` | same-era | Remote module split (`dispatch/`, `canvas/`, `sxl/`), MCP instructions, base canvas tools, validated `POST /api/command`, aligned `COMMAND_TIMEOUTS` |
29
+ | **`1.3.x`** | **`2.1.0+`** | Dev Mode codegen bridge (`get_codegen`, `export_composition_json`), **full token workspace CRUD** (`create_token_file`, `delete_token_file`, `move_token_file`, `save_tokens_config`, upsert `save_token_file`), **Variables CRUD** (modes, scopes, codeSyntax), **Styles CRUD**, **orchestration** (`compose_from_url`, `generate_code_from_url`, `document_component`), **MCP Resources** (`sxl://…`), typed errors (`EDITOR_MODE_READONLY` + structured envelope), `BRIDGE_AUTH_TOKEN`, **Idempotency-Key** on `/api/command`, `/api/log` audit trail, `/api/tools` + `list_tools` meta-tool, editor-mode write-guard with typed propagation. |
37
30
 
38
- The plugin’s own `version` in `Plugin/package.json` may differ from marketing labels; treat **feature alignment** by changelog or release tag, not npm name alone.
39
-
40
- ### Remote node API strategy
41
-
42
- New canvas automation is shipped as **small atomic** remote commands (variable-bound fills, optional `parentId`, Auto Layout fields) so Bridge and HTTP clients stay in sync with the whitelist. A single high-level command such as `generate_palette_documentation` remains a possible future optimization if you want fewer round-trips for one specific workflow.
31
+ Treat feature alignment by changelog or release tag, not npm name alone.
43
32
 
44
33
  ## Ports
45
34
 
46
- **One TCP port** (`BRIDGE_PORT`, default **`37830`** — avoids many apps that bind `3100` on macOS): plugin **WebSocket**, **HTTP REST** (`/api/*`), and **MCP Streamable HTTP** (`/mcp`) share it. Override with `BRIDGE_PORT=3100 npm start` if you need the legacy port (update plugin build + `mcp.json` to match).
35
+ **One TCP port** (`BRIDGE_PORT`, default **`37830`**): plugin **WebSocket**, **HTTP REST** (`/api/*`), and **MCP Streamable HTTP** (`/mcp`) share it. Override with `BRIDGE_PORT=3100 npm start` if needed (update plugin build + `mcp.json` to match).
47
36
 
48
37
  | On port `BRIDGE_PORT` | URL (default) |
49
38
  |----------------------|---------------|
50
39
  | Plugin UI | `ws://127.0.0.1:37830` |
51
- | REST | `http://127.0.0.1:37830/api/status`, `POST …/api/command`, … |
40
+ | REST | `http://127.0.0.1:37830/api/{status,session,tools,log,command,disconnect}` |
52
41
  | Cursor MCP | `http://127.0.0.1:37830/mcp` |
53
42
 
43
+ ### Optional: shared-secret auth
44
+
45
+ Set `BRIDGE_AUTH_TOKEN` in the environment and every `/api/*` and `/mcp` request must send `Authorization: Bearer <token>`. Requests without the header return `401 BRIDGE_UNAUTHORIZED`. Useful when running Bridge on a shared machine, or behind a local proxy.
46
+
47
+ ```bash
48
+ BRIDGE_AUTH_TOKEN=s3cret npm start
49
+ ```
50
+
54
51
  ### Cursor MCP (recommended)
55
52
 
56
- Same pattern as [Figma’s MCP URL](https://developers.figma.com/docs/figma-mcp-server/local-server-installation/): add **`http://127.0.0.1:37830/mcp`** (or `http://127.0.0.1:{BRIDGE_PORT}/mcp`). **Start Bridge first** (`cd Bridge && npm run build && npm start`, or from repo root `npm run bridge` after `npm run bridge:build`). Then enable Remote Connect in the SXL Studio plugin.
53
+ Add `http://127.0.0.1:37830/mcp` to `.cursor/mcp.json`. Start Bridge **first** (`cd Utils/bridge && npm run build && npm start`). Then enable Remote Connect in the SXL Studio plugin.
57
54
 
58
- Official **Figma MCP** (`http://127.0.0.1:3845/mcp`) reads design context from the file; it does **not** run SXL Studio plugin commands. For `create_frame`, `export_variables`, compositions, etc., use **this** Bridge MCP (or `POST /api/command`).
55
+ Official **Figma MCP** (`http://127.0.0.1:3845/mcp`) reads design context from the file; it does **not** run SXL Studio plugin commands.
59
56
 
60
57
  ## Run locally
61
58
 
62
59
  ```bash
63
- cd Bridge
60
+ cd Utils/bridge
64
61
  npm install
65
62
  npm run build
66
63
  node dist/index.js
67
64
  ```
68
65
 
69
- If you see **`EADDRINUSE`**, pick a free port: `BRIDGE_PORT=39999 npm start`, then use **`http://127.0.0.1:39999/mcp`** in Cursor and rebuild the plugin so `remoteBridge.ts` default matches (or keep defaults in sync via env in your workflow). Check listeners: `lsof -nP -iTCP:37830 -sTCP:LISTEN`.
66
+ If you see `EADDRINUSE`, pick a free port: `BRIDGE_PORT=39999 npm start`, then use `http://127.0.0.1:39999/mcp` in Cursor and rebuild the plugin so `remoteBridge.ts` default matches.
70
67
 
71
- The repo **`.cursor/mcp.json`** points Cursor at **`http://127.0.0.1:37830/mcp`**. You must **run Bridge** before opening Agent chat. Optional: stdio spawn via `node scripts/run-sxl-bridge.mjs`. See `Plugin/docs/ru/60-remote-connect.md`.
68
+ The repo `.cursor/mcp.json` points Cursor at `http://127.0.0.1:37830/mcp`. Bridge must run **before** opening Agent chat.
72
69
 
73
- **MCP + stdout:** the Model Context Protocol uses **stdout** for JSON-RPC. Do not use `console.log` in this process (it corrupts the stream). Use **`console.error`** for diagnostics.
70
+ **MCP + stdout:** the Model Context Protocol uses **stdout** for JSON-RPC. Do not use `console.log` in this process (it corrupts the stream). Use `console.error` for diagnostics.
74
71
 
75
72
  ## MCP configuration (Cursor)
76
73
 
77
74
  Example `.cursor/mcp.json`:
78
75
 
76
+ ```json
77
+ {
78
+ "mcpServers": {
79
+ "sxl-studio": {
80
+ "url": "http://127.0.0.1:37830/mcp"
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ stdio variant (if preferred):
87
+
79
88
  ```json
80
89
  {
81
90
  "mcpServers": {
82
91
  "sxl-studio": {
83
92
  "command": "node",
84
- "args": ["/absolute/path/to/repo/Bridge/dist/index.js"],
85
- "env": {
86
- "BRIDGE_PORT": "37830"
87
- }
93
+ "args": ["/absolute/path/to/repo/Utils/bridge/dist/index.js"],
94
+ "env": { "BRIDGE_PORT": "37830" }
88
95
  }
89
96
  }
90
97
  }
@@ -92,31 +99,59 @@ Example `.cursor/mcp.json`:
92
99
 
93
100
  ## HTTP API examples
94
101
 
95
- Requires the plugin open in Figma, Remote Connect enabled, and bridge running.
102
+ Requires the plugin open in Figma, Remote Connect enabled, and Bridge running.
96
103
 
97
- **Status** (JSON includes `mcpStreamableHttp` and `ports`; WebSocket and HTTP use the **same** port number)
104
+ ### Status
98
105
 
99
106
  ```bash
100
107
  curl -s http://127.0.0.1:37830/api/status
101
108
  ```
102
109
 
103
- **Read token file (after you know `fileId` from MCP `list_token_files`)**
110
+ Returns `ports`, `mcpStreamableHttp`, `session`, `queueLength`, `currentCommand`, `authEnabled`.
111
+
112
+ ### Tool catalogue
113
+
114
+ ```bash
115
+ curl -s 'http://127.0.0.1:37830/api/tools?category=tokens'
116
+ curl -s 'http://127.0.0.1:37830/api/tools?devModeReadableOnly=true'
117
+ ```
118
+
119
+ Returns entries `{ name, category, description, requiresDesignMode, requiresComposition }`. MCP clients can call the equivalent `list_tools` meta-tool.
120
+
121
+ ### Audit trail
122
+
123
+ ```bash
124
+ curl -s 'http://127.0.0.1:37830/api/log?limit=50'
125
+ ```
126
+
127
+ Ring buffer of executed commands: `commandType`, `status`, `durationMs`, `payloadKeys`, `idempotencyKey`, `timestamp`.
128
+
129
+ ### Read token file (after `list_token_files`)
104
130
 
105
131
  ```bash
106
132
  curl -s -X POST http://127.0.0.1:37830/api/command \
107
133
  -H "Content-Type: application/json" \
134
+ -H "Authorization: Bearer $BRIDGE_AUTH_TOKEN" \
135
+ -H "Idempotency-Key: 01HXYZ1234" \
108
136
  -d '{"commandType":"get_token_file_content","payload":{"fileId":"tf_..."}}'
109
137
  ```
110
138
 
111
- **Save token file**
139
+ Repeat requests with the same `Idempotency-Key` (within 10 minutes) return the cached response without touching the plugin — safe for retries.
140
+
141
+ ### Save token file (upsert)
112
142
 
113
143
  ```bash
114
144
  curl -s -X POST http://127.0.0.1:37830/api/command \
115
145
  -H "Content-Type: application/json" \
116
- -d '{"commandType":"save_token_file","payload":{"fileId":"tf_...","content":"{}"}}'
146
+ -d '{
147
+ "commandType": "save_token_file",
148
+ "payload": { "name": "buttons", "folder": "components", "content": "{\"$type\":\"composition\"}" }
149
+ }'
117
150
  ```
118
151
 
119
- **Export composition JSON from current selection**
152
+ If a file with that `name`+`folder` exists, it is updated. Otherwise it is created.
153
+
154
+ ### Export composition JSON from current selection
120
155
 
121
156
  ```bash
122
157
  curl -s -X POST http://127.0.0.1:37830/api/command \
@@ -126,15 +161,54 @@ curl -s -X POST http://127.0.0.1:37830/api/command \
126
161
 
127
162
  Optional `payload.nodeId` selects a specific node instead of the first selected node.
128
163
 
164
+ ### Typed errors
165
+
166
+ Failures return a structured envelope:
167
+
168
+ ```json
169
+ {
170
+ "status": "failed",
171
+ "error": "{\"code\":\"EDITOR_MODE_READONLY\",\"message\":\"Command \\\"create_frame\\\" requires Figma Design mode.\",\"retryable\":false,\"details\":{\"editorType\":\"dev\",\"mode\":\"default\",\"isDevMode\":true}}"
172
+ }
173
+ ```
174
+
175
+ Known codes: `EDITOR_MODE_READONLY`, `BRIDGE_TIMEOUT`, `BRIDGE_CANCELLED`, `BRIDGE_UNAUTHORIZED`, `BRIDGE_ERROR`. MCP tools decode the envelope before returning to the agent.
176
+
129
177
  ## MCP tools (summary)
130
178
 
131
- Registered in `src/mcp-server.ts` via `tools/*.ts`, including:
179
+ Registered in `src/mcp-factory.ts` via `tools/*.ts`:
180
+
181
+ - **Diagnostics / meta:** `get_plugin_status`, `is_dev_mode`, `get_selection_summary`, `get_drift_status`, `list_tools`.
182
+ - **Tokens / workspace:** `list_token_files`, `get_token_file_content`, `save_token_file` (upsert), `create_token_file`, `delete_token_file`, `move_token_file`, `rename_token_file`, `get_tokens_config`, `save_tokens_config`, `export_variables`, `reset_diff*`, `reapply_token_bindings`, `cross_file_sync_*`, `get_applied_tokens`.
183
+ - **Composition:** `export_composition_json`, `get_codegen`, `list_compositions`, `generate_composition`, `apply_composition`, `preview_composition`, `check_composition_linked`, `inspect_selection`.
184
+ - **Variables:** `get_variables`, `create_variable_collection`, `create_variable`, `bind_variable`, `rename_variable`, `delete_variable`, `rename_variable_collection`, `delete_variable_collection`, `add_variable_mode`, `remove_variable_mode`, `rename_variable_mode`, `set_variable_mode_value`, `set_variable_scopes`, `set_variable_code_syntax`.
185
+ - **Styles:** `get_local_styles`, `create_paint_style`, `create_text_style`, `create_effect_style`, `set_text_style`, `set_effect_style`, `set_stroke_style`, `set_fill_style`, `import_style_by_key`.
186
+ - **Data / nodes:** `apply_mapping`, `apply_all_mappings`, `count_apply_targets`, `generate_instances`, `apply_image`, plus direct node helpers in `data.ts` / `figma-nodes.ts` (`set_node_fill_variable`, `create_rectangle`, `set_auto_layout`, `duplicate_subtree`, `create_component_instance`, `apply_documentation_payload`, extended `create_frame` / `create_text`).
187
+ - **Git:** `git_pull`, `git_hard_pull`, `git_push`.
188
+ - **Orchestration:** `generate_code_from_url`, `compose_from_url`, `document_component`.
189
+
190
+ ### MCP Resources
191
+
192
+ | URI | Contents |
193
+ |-----|----------|
194
+ | `sxl://figma/status` | Plugin status snapshot |
195
+ | `sxl://figma/selection` | Current Figma selection |
196
+ | `sxl://tokens/config` | Raw `config.json` |
197
+ | `sxl://tokens/files` | Token file index |
198
+ | `sxl://tokens/files/{fileId}` | Raw token file body |
199
+ | `sxl://compositions/index` | Composition JSON index |
200
+
201
+ Cursor / Claude can attach these as context without calling tools.
202
+
203
+ ## Dev Mode support
204
+
205
+ | Context | Reads | Canvas writes | Token/config/git writes |
206
+ |---------|-------|---------------|--------------------------|
207
+ | Figma Design | ✔︎ | ✔︎ | ✔︎ |
208
+ | Figma Dev Mode (UI, `mode: "default"`) | ✔︎ | ✘ (plugin returns `EDITOR_MODE_READONLY`) | ✔︎ |
209
+ | Figma Dev Mode (Inspect → Code sandbox) | read-only codegen callback; Remote Connect unavailable | ✘ | ✘ |
132
210
 
133
- - **Tokens:** `export_variables`, `reset_diff*`, `reapply_token_bindings`, `cross_file_sync_*`, `get_token_file_content`, `save_token_file`
134
- - **Composition:** `generate_composition`, `apply_composition`, `preview_composition`, `check_composition_linked`, `inspect_selection`, `export_composition_json`
135
- - **Data / nodes:** `apply_mapping`, `apply_all_mappings`, `count_apply_targets`, `generate_instances`, `apply_image`, direct node helpers in `data.ts` / `figma-nodes.ts` (including `set_node_fill_variable`, `create_rectangle`, `set_auto_layout`, `duplicate_subtree`, `create_component_instance`, `apply_documentation_payload`, extended `create_frame` / `create_text`)
136
- - **Git:** `git_pull`, `git_hard_pull`, `git_push`
137
- - **Diagnostics:** plugin status, selection, drift, Code Connect, etc.
211
+ `get_codegen` (Bridge) and the Dev Mode Inspect → Code panel (plugin) share the exact same `routeCodegenGenerate` pipeline. Output is byte-identical.
138
212
 
139
213
  ## Development
140
214
 
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Audit ring buffer for Bridge commands.
3
+ *
4
+ * Every command dispatched via POST /api/command is recorded with its
5
+ * commandType, status, duration and a short payload-keys preview (no values
6
+ * — to avoid leaking secrets). GET /api/log returns the most recent entries.
7
+ * This is in-memory, per-process, and capped to 200 entries.
8
+ */
9
+ import type { CommandResult } from "./types.js";
10
+ export type AuditEntry = {
11
+ at: number;
12
+ commandId: string;
13
+ commandType: string;
14
+ status: CommandResult["status"];
15
+ durationMs: number | null;
16
+ error: string | null;
17
+ payloadKeys: string[];
18
+ idempotencyKey: string | null;
19
+ };
20
+ export declare function recordAudit(entry: AuditEntry): void;
21
+ export declare function getAuditSnapshot(limit?: number): AuditEntry[];
package/dist/audit.js ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Audit ring buffer for Bridge commands.
3
+ *
4
+ * Every command dispatched via POST /api/command is recorded with its
5
+ * commandType, status, duration and a short payload-keys preview (no values
6
+ * — to avoid leaking secrets). GET /api/log returns the most recent entries.
7
+ * This is in-memory, per-process, and capped to 200 entries.
8
+ */
9
+ const BUFFER_SIZE = 200;
10
+ const buffer = [];
11
+ export function recordAudit(entry) {
12
+ buffer.push(entry);
13
+ if (buffer.length > BUFFER_SIZE) {
14
+ buffer.splice(0, buffer.length - BUFFER_SIZE);
15
+ }
16
+ // Structured log line for operators tailing the console.
17
+ // eslint-disable-next-line no-console
18
+ console.error(`[Audit] ${new Date(entry.at).toISOString()} ${entry.commandType} -> ${entry.status}${typeof entry.durationMs === "number" ? ` (${entry.durationMs}ms)` : ""}${entry.error ? ` — ${entry.error}` : ""}`);
19
+ }
20
+ export function getAuditSnapshot(limit = 50) {
21
+ const clamped = Math.max(1, Math.min(limit, BUFFER_SIZE));
22
+ return buffer.slice(-clamped).reverse();
23
+ }
24
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,MAAM,GAAiB,EAAE,CAAC;AAEhC,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnB,IAAI,MAAM,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC;IAChD,CAAC;IACD,yDAAyD;IACzD,sCAAsC;IACtC,OAAO,CAAC,KAAK,CACX,WAAW,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,WAAW,OAAO,KAAK,CAAC,MAAM,GACjF,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,EACtE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAK,GAAG,EAAE;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC;IAC1D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;AAC1C,CAAC"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Bridge authentication — optional shared-token gate.
3
+ *
4
+ * Activated when BRIDGE_AUTH_TOKEN env var is set. Requests must then carry
5
+ * `Authorization: Bearer <token>` (case-insensitive header name, case-sensitive token).
6
+ * Applies to both REST /api/* and MCP Streamable HTTP at /mcp.
7
+ *
8
+ * Disabled by default to preserve zero-config "run and connect Cursor" UX.
9
+ */
10
+ import type { IncomingMessage } from "node:http";
11
+ export declare function getBridgeAuthToken(): string | null;
12
+ export declare function checkAuth(req: IncomingMessage): {
13
+ ok: true;
14
+ } | {
15
+ ok: false;
16
+ reason: string;
17
+ };
18
+ export declare function isAuthEnabled(): boolean;
package/dist/auth.js ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Bridge authentication — optional shared-token gate.
3
+ *
4
+ * Activated when BRIDGE_AUTH_TOKEN env var is set. Requests must then carry
5
+ * `Authorization: Bearer <token>` (case-insensitive header name, case-sensitive token).
6
+ * Applies to both REST /api/* and MCP Streamable HTTP at /mcp.
7
+ *
8
+ * Disabled by default to preserve zero-config "run and connect Cursor" UX.
9
+ */
10
+ export function getBridgeAuthToken() {
11
+ const raw = process.env["BRIDGE_AUTH_TOKEN"];
12
+ if (!raw)
13
+ return null;
14
+ const trimmed = raw.trim();
15
+ return trimmed.length > 0 ? trimmed : null;
16
+ }
17
+ export function checkAuth(req) {
18
+ const token = getBridgeAuthToken();
19
+ if (!token)
20
+ return { ok: true };
21
+ const header = req.headers["authorization"] ??
22
+ req.headers["Authorization"];
23
+ if (!header) {
24
+ return { ok: false, reason: "Missing Authorization header" };
25
+ }
26
+ const [scheme, ...rest] = header.split(" ");
27
+ if (scheme?.toLowerCase() !== "bearer") {
28
+ return { ok: false, reason: "Authorization header must use Bearer scheme" };
29
+ }
30
+ const provided = rest.join(" ").trim();
31
+ if (provided !== token) {
32
+ return { ok: false, reason: "Invalid bearer token" };
33
+ }
34
+ return { ok: true };
35
+ }
36
+ export function isAuthEnabled() {
37
+ return getBridgeAuthToken() !== null;
38
+ }
39
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,UAAU,kBAAkB;IAChC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC7C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAoB;IAC5C,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACnC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IAChC,MAAM,MAAM,GACT,GAAG,CAAC,OAAO,CAAC,eAAe,CAAwB;QACnD,GAAG,CAAC,OAAO,CAAC,eAAe,CAAmC,CAAC;IAClE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC;IAC/D,CAAC;IACD,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,MAAM,EAAE,WAAW,EAAE,KAAK,QAAQ,EAAE,CAAC;QACvC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;IAC9E,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACvC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;QACvB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACvD,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,kBAAkB,EAAE,KAAK,IAAI,CAAC;AACvC,CAAC"}
@@ -3,6 +3,19 @@
3
3
  *
4
4
  * Also serves MCP Streamable HTTP at GET|POST /mcp (recommended for Cursor — same pattern
5
5
  * as Figma's official MCP: add server URL in Cursor settings).
6
+ *
7
+ * Endpoints:
8
+ * GET /api/status — server + plugin session snapshot
9
+ * GET /api/session — detailed session info
10
+ * GET /api/tools — authoritative catalogue of MCP tools
11
+ * GET /api/log?limit=N — audit trail of recent commands (ring buffer)
12
+ * POST /api/command — execute a plugin command (with optional Idempotency-Key)
13
+ * POST /api/disconnect — close the current plugin socket
14
+ * ANY /mcp — MCP Streamable HTTP
15
+ *
16
+ * Security:
17
+ * When BRIDGE_AUTH_TOKEN is set, all /api/* and /mcp requests require
18
+ * `Authorization: Bearer <token>`.
6
19
  */
7
20
  import type { BridgeWSServer } from "./ws-server.js";
8
21
  export declare function startHttpApi(bridgePort: number, wsServer: BridgeWSServer): Promise<void>;
package/dist/http-api.js CHANGED
@@ -3,11 +3,29 @@
3
3
  *
4
4
  * Also serves MCP Streamable HTTP at GET|POST /mcp (recommended for Cursor — same pattern
5
5
  * as Figma's official MCP: add server URL in Cursor settings).
6
+ *
7
+ * Endpoints:
8
+ * GET /api/status — server + plugin session snapshot
9
+ * GET /api/session — detailed session info
10
+ * GET /api/tools — authoritative catalogue of MCP tools
11
+ * GET /api/log?limit=N — audit trail of recent commands (ring buffer)
12
+ * POST /api/command — execute a plugin command (with optional Idempotency-Key)
13
+ * POST /api/disconnect — close the current plugin socket
14
+ * ANY /mcp — MCP Streamable HTTP
15
+ *
16
+ * Security:
17
+ * When BRIDGE_AUTH_TOKEN is set, all /api/* and /mcp requests require
18
+ * `Authorization: Bearer <token>`.
6
19
  */
7
20
  import { createServer } from "node:http";
8
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
9
- import { createBridgeMcpServer } from "./mcp-factory.js";
21
+ import { StreamableHTTPServerTransport } from "../node_modules/@modelcontextprotocol/sdk/dist/cjs/server/streamableHttp.js";
22
+ import { getAuditSnapshot, recordAudit } from "./audit.js";
23
+ import { checkAuth, isAuthEnabled } from "./auth.js";
10
24
  import { parseHttpCommandBody } from "./command-http.js";
25
+ import { getIdempotent, putIdempotent } from "./idempotency.js";
26
+ import { createBridgeMcpServer } from "./mcp-factory.js";
27
+ import { bootstrapBridgeToolCatalogue } from "./tools/catalogue-bootstrap.js";
28
+ import { getBridgeToolCatalogue } from "./tools/registry.js";
11
29
  function readBody(req) {
12
30
  return new Promise((resolve, reject) => {
13
31
  let body = "";
@@ -23,7 +41,7 @@ function sendJson(res, status, data) {
23
41
  "Content-Type": "application/json",
24
42
  "Access-Control-Allow-Origin": "*",
25
43
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
26
- "Access-Control-Allow-Headers": "Content-Type, Accept, Authorization, Mcp-Session-Id, mcp-protocol-version",
44
+ "Access-Control-Allow-Headers": "Content-Type, Accept, Authorization, Mcp-Session-Id, mcp-protocol-version, Idempotency-Key",
27
45
  });
28
46
  res.end(JSON.stringify(data, null, 2));
29
47
  }
@@ -35,9 +53,19 @@ function pathnameOnly(reqUrl) {
35
53
  return "/";
36
54
  }
37
55
  }
56
+ function searchParamsOf(reqUrl) {
57
+ try {
58
+ return new URL(reqUrl || "/", "http://127.0.0.1").searchParams;
59
+ }
60
+ catch {
61
+ return new URLSearchParams();
62
+ }
63
+ }
38
64
  export async function startHttpApi(bridgePort, wsServer) {
39
65
  const queue = wsServer.commandQueue;
40
66
  const session = wsServer.session;
67
+ // Keep catalogue + MCP server init symmetric for both stdio and HTTP.
68
+ bootstrapBridgeToolCatalogue();
41
69
  const mcpHttpServer = createBridgeMcpServer(queue);
42
70
  const mcpTransport = new StreamableHTTPServerTransport({
43
71
  sessionIdGenerator: undefined,
@@ -56,11 +84,21 @@ export async function startHttpApi(bridgePort, wsServer) {
56
84
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
57
85
  "Access-Control-Allow-Headers": typeof reqHdr === "string" && reqHdr.length > 0
58
86
  ? reqHdr
59
- : "Content-Type, Accept, Authorization, Mcp-Session-Id, mcp-protocol-version",
87
+ : "Content-Type, Accept, Authorization, Mcp-Session-Id, mcp-protocol-version, Idempotency-Key",
60
88
  });
61
89
  res.end();
62
90
  return;
63
91
  }
92
+ // Optional shared-secret auth (BRIDGE_AUTH_TOKEN).
93
+ const auth = checkAuth(req);
94
+ if (!auth.ok) {
95
+ sendJson(res, 401, {
96
+ code: "BRIDGE_UNAUTHORIZED",
97
+ message: auth.reason,
98
+ retryable: false,
99
+ });
100
+ return;
101
+ }
64
102
  try {
65
103
  // MCP Streamable HTTP (Cursor, same idea as Figma MCP URL in docs)
66
104
  if (pathname === "/mcp") {
@@ -91,7 +129,7 @@ export async function startHttpApi(bridgePort, wsServer) {
91
129
  queueLength: queue.queueLength,
92
130
  currentCommand: queue.currentCommand,
93
131
  };
94
- sendJson(res, 200, status);
132
+ sendJson(res, 200, { ...status, authEnabled: isAuthEnabled() });
95
133
  return;
96
134
  }
97
135
  // GET /api/session
@@ -99,6 +137,31 @@ export async function startHttpApi(bridgePort, wsServer) {
99
137
  sendJson(res, 200, session.info);
100
138
  return;
101
139
  }
140
+ // GET /api/tools — authoritative catalogue (same as list_tools MCP tool)
141
+ if (req.method === "GET" && pathname === "/api/tools") {
142
+ const sp = searchParamsOf(req.url || "/");
143
+ const category = sp.get("category");
144
+ const devModeReadableOnly = sp.get("devModeReadableOnly") === "true";
145
+ let entries = [...getBridgeToolCatalogue()];
146
+ if (category)
147
+ entries = entries.filter((e) => e.category === category);
148
+ if (devModeReadableOnly)
149
+ entries = entries.filter((e) => !e.requiresDesignMode);
150
+ sendJson(res, 200, {
151
+ count: entries.length,
152
+ categories: Array.from(new Set(entries.map((e) => e.category))),
153
+ tools: entries,
154
+ });
155
+ return;
156
+ }
157
+ // GET /api/log — recent audit entries (ring buffer)
158
+ if (req.method === "GET" && pathname === "/api/log") {
159
+ const sp = searchParamsOf(req.url || "/");
160
+ const rawLimit = parseInt(sp.get("limit") ?? "", 10);
161
+ const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? rawLimit : 50;
162
+ sendJson(res, 200, { entries: getAuditSnapshot(limit) });
163
+ return;
164
+ }
102
165
  // POST /api/command
103
166
  if (req.method === "POST" && pathname === "/api/command") {
104
167
  if (!session.connected) {
@@ -111,7 +174,37 @@ export async function startHttpApi(bridgePort, wsServer) {
111
174
  sendJson(res, parsed.status, { error: parsed.error });
112
175
  return;
113
176
  }
177
+ // Idempotency: header wins, body fallback.
178
+ const headerKey = req.headers["idempotency-key"] ??
179
+ req.headers["Idempotency-Key"] ??
180
+ null;
181
+ const bodyKeyRaw = JSON.parse(body || "{}")?.idempotencyKey;
182
+ const idempotencyKey = (typeof headerKey === "string" && headerKey.length > 0 ? headerKey : null) ??
183
+ (typeof bodyKeyRaw === "string" && bodyKeyRaw.length > 0 ? bodyKeyRaw : null);
184
+ if (idempotencyKey) {
185
+ const cached = getIdempotent(idempotencyKey);
186
+ if (cached) {
187
+ sendJson(res, 200, { ...cached, idempotent: "hit" });
188
+ return;
189
+ }
190
+ }
191
+ const startedAt = Date.now();
114
192
  const result = await queue.execute(parsed.commandType, parsed.payload);
193
+ recordAudit({
194
+ at: startedAt,
195
+ commandId: result.commandId,
196
+ commandType: parsed.commandType,
197
+ status: result.status,
198
+ durationMs: typeof result.durationMs === "number"
199
+ ? result.durationMs
200
+ : Date.now() - startedAt,
201
+ error: result.error ?? null,
202
+ payloadKeys: Object.keys(parsed.payload ?? {}),
203
+ idempotencyKey,
204
+ });
205
+ if (idempotencyKey) {
206
+ putIdempotent(idempotencyKey, result);
207
+ }
115
208
  sendJson(res, 200, result);
116
209
  return;
117
210
  }
@@ -139,6 +232,9 @@ export async function startHttpApi(bridgePort, wsServer) {
139
232
  });
140
233
  server.listen(bridgePort, "127.0.0.1", () => {
141
234
  console.error(`[Bridge] Listening on http://127.0.0.1:${bridgePort} (REST /api/*, MCP /mcp, plugin ws://127.0.0.1:${bridgePort})`);
235
+ if (isAuthEnabled()) {
236
+ console.error("[Bridge] Auth enabled — require Authorization: Bearer <BRIDGE_AUTH_TOKEN>");
237
+ }
142
238
  resolve();
143
239
  });
144
240
  });
@@ -1 +1 @@
1
- {"version":3,"file":"http-api.js","sourceRoot":"","sources":["../src/http-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http-api.js","sourceRoot":"","sources":["../src/http-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Idempotency cache for POST /api/command.
3
+ *
4
+ * Clients may pass an `Idempotency-Key` HTTP header (or top-level
5
+ * `idempotencyKey` in the JSON body). Repeating the same key within the TTL
6
+ * window returns the original response without re-dispatching the command to
7
+ * the plugin — avoiding duplicate side effects on network retries.
8
+ *
9
+ * Cache is in-memory, per-process, and intentionally small.
10
+ */
11
+ import type { CommandResult } from "./types.js";
12
+ export declare function getIdempotent(key: string): CommandResult | null;
13
+ export declare function putIdempotent(key: string, result: CommandResult): void;