@cueloop/daemon 0.1.0-alpha.58 → 0.1.0-alpha.59

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cueloop/daemon",
3
- "version": "0.1.0-alpha.58",
3
+ "version": "0.1.0-alpha.59",
4
4
  "description": "The cueloop session daemon and its client: socket protocol, atomic store, resumable waits",
5
5
  "homepage": "https://github.com/mmurakaru/cueloop#readme",
6
6
  "bugs": {
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@cueloop/schema": "0.1.0-alpha.58",
36
+ "@cueloop/schema": "0.1.0-alpha.59",
37
37
  "valibot": "^1.4.2"
38
38
  },
39
39
  "engines": {
@@ -102,6 +102,17 @@ describe("socket round-trip", () => {
102
102
  } catch (error) {
103
103
  expect((error as DaemonClientError).code).toBe("unknown_method");
104
104
  }
105
+ const prototypeMethods = await Promise.allSettled([
106
+ client.request("__proto__", {}),
107
+ client.request("toString", {}),
108
+ client.request("constructor", {}),
109
+ ]);
110
+ for (const result of prototypeMethods) {
111
+ expect(result.status).toBe("rejected");
112
+ expect(((result as PromiseRejectedResult).reason as DaemonClientError).code).toBe(
113
+ "unknown_method",
114
+ );
115
+ }
105
116
  // the daemon is still fully alive afterwards
106
117
  const session = await client.sessionCreate(WS, PLAN);
107
118
  expect((await client.sessionGet(session.id)).id).toBe(session.id);
package/src/server.ts CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  import { DaemonCore, type DaemonEvent } from "./api";
18
18
  import { DaemonError } from "./errors";
19
19
  import { roleAllowsMethod, type DaemonRole } from "./capabilities";
20
- import { isKnownMethod, parseParams } from "./validate";
20
+ import { isKnownMethod, parseParams, type MethodName } from "./validate";
21
21
  import { BackpressureWriter, LineBuffer, type Request } from "./protocol";
22
22
  import { cueloopHome, lockPath, pidPath, socketPath } from "./paths";
23
23
 
@@ -28,6 +28,8 @@ interface Connection {
28
28
  role: DaemonRole;
29
29
  }
30
30
 
31
+ type MethodHandler = (connection: Connection, request: Request) => unknown;
32
+
31
33
  export interface DaemonOptions {
32
34
  home?: string;
33
35
  /** Idle-exit delay; 0 disables (tests, foreground runs). */
@@ -222,6 +224,91 @@ export class DaemonServer {
222
224
  }
223
225
  }
224
226
 
227
+ private readonly handlers: Record<MethodName, MethodHandler> = {
228
+ "daemon.ping": () => ({ pid: process.pid }),
229
+ "daemon.hello": (connection, request) => {
230
+ connection.role = parseParams("daemon.hello", request.params).role;
231
+ return {};
232
+ },
233
+ "daemon.shutdown": () => {
234
+ setTimeout(() => {
235
+ this.stop();
236
+ this.onIdleExit();
237
+ }, 10);
238
+ return {};
239
+ },
240
+ "events.subscribe": (connection) => {
241
+ connection.subscribed = true;
242
+ return {};
243
+ },
244
+ "session.create": (_connection, request) => {
245
+ const params = parseParams("session.create", request.params);
246
+ return this.core.sessionCreate({ workspace: params.workspace, artifact: params.artifact });
247
+ },
248
+ "session.get": (_connection, request) =>
249
+ this.core.sessionGet(parseParams("session.get", request.params).id),
250
+ "session.list": (_connection, request) =>
251
+ this.core.sessionList(parseParams("session.list", request.params).filter),
252
+ "session.wait": (_connection, request) => {
253
+ const params = parseParams("session.wait", request.params);
254
+ return this.core.sessionWait(params.id, params.timeoutMs);
255
+ },
256
+ "session.annotate": (_connection, request) => {
257
+ const params = parseParams("session.annotate", request.params);
258
+ return this.core.sessionAnnotate(params.id, params.annotation, params.authorName);
259
+ },
260
+ "session.removeAnnotation": (_connection, request) => {
261
+ const params = parseParams("session.removeAnnotation", request.params);
262
+ return this.core.sessionRemoveAnnotation(params.id, params.annotationId);
263
+ },
264
+ "session.setWorkingCopy": (_connection, request) => {
265
+ const params = parseParams("session.setWorkingCopy", request.params);
266
+ return this.core.sessionSetWorkingCopy(params.id, params.workingCopy);
267
+ },
268
+ "session.setViewed": (_connection, request) => {
269
+ const params = parseParams("session.setViewed", request.params);
270
+ return this.core.sessionSetViewed(params.id, params.viewedPaths);
271
+ },
272
+ "session.refreshDiff": (_connection, request) => {
273
+ const params = parseParams("session.refreshDiff", request.params);
274
+ return this.core.sessionRefreshDiff(params.id);
275
+ },
276
+ "session.setShareId": (_connection, request) => {
277
+ const params = parseParams("session.setShareId", request.params);
278
+ return this.core.sessionSetShareId(params.id, params.shareId);
279
+ },
280
+ "session.delete": (_connection, request) => {
281
+ this.core.sessionDelete(parseParams("session.delete", request.params).id);
282
+ return {};
283
+ },
284
+ "session.mergeShared": (_connection, request) => {
285
+ const params = parseParams("session.mergeShared", request.params);
286
+ return this.core.sessionMergeShared(params.id, {
287
+ annotations: params.annotations,
288
+ participants: params.participants,
289
+ });
290
+ },
291
+ "session.resolve": (_connection, request) => {
292
+ const params = parseParams("session.resolve", request.params);
293
+ return this.core.sessionResolve(params.id, params.verdictKind, params.summary);
294
+ },
295
+ "session.submitRevision": (_connection, request) => {
296
+ const params = parseParams("session.submitRevision", request.params);
297
+ return this.core.sessionSubmitRevision(
298
+ params.id,
299
+ params.content,
300
+ params.addressedAnnotationIds,
301
+ );
302
+ },
303
+ "herdr.getTab": (_connection, request) =>
304
+ this.core.herdrGetTab(parseParams("herdr.getTab", request.params).id),
305
+ "herdr.setTab": (_connection, request) => {
306
+ const params = parseParams("herdr.setTab", request.params);
307
+ this.core.herdrSetTab(params.id, { tabId: params.tabId, paneId: params.paneId });
308
+ return {};
309
+ },
310
+ };
311
+
225
312
  private async dispatch(connection: Connection, request: Request): Promise<unknown> {
226
313
  // The wire is untrusted JSON: validate before DaemonCore sees anything.
227
314
  if (typeof request.method !== "string" || !isKnownMethod(request.method)) {
@@ -232,86 +319,9 @@ export class DaemonServer {
232
319
  if (!roleAllowsMethod(connection.role, request.method)) {
233
320
  throw new DaemonError("forbidden", `role ${connection.role} cannot call ${request.method}`);
234
321
  }
235
- const core = this.core;
236
- switch (request.method) {
237
- case "daemon.ping":
238
- return { pid: process.pid };
239
- case "daemon.hello":
240
- connection.role = parseParams("daemon.hello", request.params).role;
241
- return {};
242
- case "daemon.shutdown":
243
- setTimeout(() => {
244
- this.stop();
245
- this.onIdleExit();
246
- }, 10);
247
- return {};
248
- case "events.subscribe":
249
- connection.subscribed = true;
250
- return {};
251
- case "session.create": {
252
- const params = parseParams("session.create", request.params);
253
- return core.sessionCreate({ workspace: params.workspace, artifact: params.artifact });
254
- }
255
- case "session.get":
256
- return core.sessionGet(parseParams("session.get", request.params).id);
257
- case "session.list":
258
- return core.sessionList(parseParams("session.list", request.params).filter);
259
- case "session.wait": {
260
- const params = parseParams("session.wait", request.params);
261
- return core.sessionWait(params.id, params.timeoutMs);
262
- }
263
- case "session.annotate": {
264
- const params = parseParams("session.annotate", request.params);
265
- return core.sessionAnnotate(params.id, params.annotation, params.authorName);
266
- }
267
- case "session.removeAnnotation": {
268
- const params = parseParams("session.removeAnnotation", request.params);
269
- return core.sessionRemoveAnnotation(params.id, params.annotationId);
270
- }
271
- case "session.setWorkingCopy": {
272
- const params = parseParams("session.setWorkingCopy", request.params);
273
- return core.sessionSetWorkingCopy(params.id, params.workingCopy);
274
- }
275
- case "session.setViewed": {
276
- const params = parseParams("session.setViewed", request.params);
277
- return core.sessionSetViewed(params.id, params.viewedPaths);
278
- }
279
- case "session.refreshDiff": {
280
- const params = parseParams("session.refreshDiff", request.params);
281
- return core.sessionRefreshDiff(params.id);
282
- }
283
- case "session.setShareId": {
284
- const params = parseParams("session.setShareId", request.params);
285
- return core.sessionSetShareId(params.id, params.shareId);
286
- }
287
- case "session.delete": {
288
- core.sessionDelete(parseParams("session.delete", request.params).id);
289
- return {};
290
- }
291
- case "session.mergeShared": {
292
- const params = parseParams("session.mergeShared", request.params);
293
- return core.sessionMergeShared(params.id, {
294
- annotations: params.annotations,
295
- participants: params.participants,
296
- });
297
- }
298
- case "session.resolve": {
299
- const params = parseParams("session.resolve", request.params);
300
- return core.sessionResolve(params.id, params.verdictKind, params.summary);
301
- }
302
- case "session.submitRevision": {
303
- const params = parseParams("session.submitRevision", request.params);
304
- return core.sessionSubmitRevision(params.id, params.content, params.addressedAnnotationIds);
305
- }
306
- case "herdr.getTab":
307
- return core.herdrGetTab(parseParams("herdr.getTab", request.params).id);
308
- case "herdr.setTab": {
309
- const params = parseParams("herdr.setTab", request.params);
310
- core.herdrSetTab(params.id, { tabId: params.tabId, paneId: params.paneId });
311
- return {};
312
- }
313
- default:
314
- throw new DaemonError("unknown_method", `unknown method ${request.method}`);
322
+ if (!Object.hasOwn(this.handlers, request.method)) {
323
+ throw new DaemonError("unknown_method", `unknown method ${request.method}`);
315
324
  }
325
+ return this.handlers[request.method](connection, request);
316
326
  }
317
327
  }