@melaya/runner 1.1.61 → 1.1.62

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.
@@ -9,6 +9,7 @@
9
9
  * - Per-run nonce required in the URL path to prevent injection from
10
10
  * other processes on the same machine
11
11
  */
12
+ import http from "http";
12
13
  import type { Socket } from "socket.io-client";
13
14
  export interface LocalRelay {
14
15
  port: number;
@@ -16,4 +17,10 @@ export interface LocalRelay {
16
17
  close: () => void;
17
18
  }
18
19
  export declare function setActiveProject(project: string): void;
19
- export declare function startLocalRelay(socket: Socket, verbose: boolean, serverUrl?: string): Promise<LocalRelay>;
20
+ export interface LocalRelayRoutes {
21
+ /** POST /vaults/op (Obsidian vault tools, protocol §2). Authenticated by the
22
+ * vault capability in `Authorization: Vault <cap>`, not by the nonce: the
23
+ * handler verifies it (local device vaults) or forwards it to the server. */
24
+ vaultOp?: (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void> | void;
25
+ }
26
+ export declare function startLocalRelay(socket: Socket, verbose: boolean, serverUrl?: string, routes?: LocalRelayRoutes): Promise<LocalRelay>;
@@ -55,7 +55,7 @@ function _flushThrottle(socket, verbose) {
55
55
  _throttleQueue = [];
56
56
  _throttleTimer = null;
57
57
  }
58
- export function startLocalRelay(socket, verbose, serverUrl) {
58
+ export function startLocalRelay(socket, verbose, serverUrl, routes = {}) {
59
59
  const nonce = crypto.randomUUID().replace(/-/g, "");
60
60
  return new Promise((resolve, reject) => {
61
61
  const expectedPath = `/events/relay/${nonce}`;
@@ -147,6 +147,26 @@ export function startLocalRelay(socket, verbose, serverUrl) {
147
147
  });
148
148
  return;
149
149
  }
150
+ // ── Obsidian vault ops (docs/plans/obsidian-vault-protocol.md §2) ──
151
+ if (req.method === "POST" && req.url && /^\/vaults\/op\/?(\?.*)?$/.test(req.url)) {
152
+ if (!routes.vaultOp) {
153
+ res.writeHead(404);
154
+ res.end("Not found");
155
+ return;
156
+ }
157
+ Promise.resolve(routes.vaultOp(req, res)).catch(() => {
158
+ if (res.headersSent) {
159
+ try {
160
+ res.end();
161
+ }
162
+ catch { /* closed */ }
163
+ return;
164
+ }
165
+ res.writeHead(500, { "Content-Type": "application/json" });
166
+ res.end('{"ok":false,"error":"relay_failed"}');
167
+ });
168
+ return;
169
+ }
150
170
  if (req.method !== "POST" || req.url !== expectedPath) {
151
171
  res.writeHead(404);
152
172
  res.end("Not found");