@cueloop/daemon 0.1.0-alpha.76 → 0.1.0-alpha.77

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.76",
3
+ "version": "0.1.0-alpha.77",
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": {
@@ -35,7 +35,7 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@cueloop/schema": "0.1.0-alpha.76",
38
+ "@cueloop/schema": "0.1.0-alpha.77",
39
39
  "@pierre/diffs": "^1.3.6",
40
40
  "effect": "^4.0.0-rc.115",
41
41
  "valibot": "^1.4.2"
package/src/api.ts CHANGED
@@ -432,6 +432,17 @@ export class DaemonCore {
432
432
  return session;
433
433
  }
434
434
 
435
+ /** Set the private-share allowlist of GitHub logins; presence marks the share private. */
436
+ sessionSetAccess(id: string, githubLogins: string[]): Thread {
437
+ const session = this.mutable(id);
438
+
439
+ session.access = { githubLogins };
440
+ this.store.upsert(session);
441
+ this.emit("session.updated", id);
442
+
443
+ return session;
444
+ }
445
+
435
446
  /** Remove a session for good (inbox delete); resolved or pending, both go. */
436
447
  sessionDelete(id: string): void {
437
448
  const session = this.store.get(id);
@@ -35,6 +35,7 @@ const PRIMITIVE_ROLES = {
35
35
  "session.cutBlock": "owner",
36
36
  "session.restoreBlock": "owner",
37
37
  "session.curate": "owner",
38
+ "session.setAccess": "owner",
38
39
  "session.setViewed": "owner",
39
40
  "session.setTitle": "owner",
40
41
  // reading the local working tree is the owner's alone; a share carries no repo to read
package/src/client.ts CHANGED
@@ -88,6 +88,8 @@ export interface SessionClient {
88
88
  sessionRestoreBlock(id: string, baseBlockIndex: number, line?: number): Promise<Thread>;
89
89
  /** Replace a diff review's reject decisions; the working copy follows. */
90
90
  sessionCurate(id: string, rejections: HunkRejection[]): Promise<Thread>;
91
+ /** Replace the private-share allowlist of GitHub logins; presence marks the share private. */
92
+ sessionSetAccess(id: string, githubLogins: string[]): Promise<Thread>;
91
93
  sessionSetViewed(id: string, viewedPaths: string[]): Promise<Thread>;
92
94
  /** Rename a session's display title; an empty title restores the derived default. */
93
95
  sessionSetTitle(id: string, title: string): Promise<Thread>;
@@ -450,6 +452,9 @@ export class DaemonClient implements SessionClient {
450
452
  sessionCurate(id: string, rejections: HunkRejection[]): Promise<Thread> {
451
453
  return this.request("session.curate", { id, rejections }, ThreadRecordSchema);
452
454
  }
455
+ sessionSetAccess(id: string, githubLogins: string[]): Promise<Thread> {
456
+ return this.request("session.setAccess", { id, githubLogins }, ThreadRecordSchema);
457
+ }
453
458
  sessionSetViewed(id: string, viewedPaths: string[]): Promise<Thread> {
454
459
  return this.request("session.setViewed", { id, viewedPaths }, ThreadRecordSchema);
455
460
  }
package/src/server.ts CHANGED
@@ -385,6 +385,11 @@ export class DaemonServer {
385
385
 
386
386
  return this.core.sessionCurate(params.id, params.rejections);
387
387
  },
388
+ "session.setAccess": (_connection, request) => {
389
+ const params = parseParams("session.setAccess", request.params);
390
+
391
+ return this.core.sessionSetAccess(params.id, params.githubLogins);
392
+ },
388
393
  "session.setViewed": (_connection, request) => {
389
394
  const params = parseParams("session.setViewed", request.params);
390
395
 
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import * as v from "valibot";
2
3
  import { mkdtempSync, rmSync } from "node:fs";
3
4
  import { tmpdir } from "node:os";
4
5
  import { join } from "node:path";
@@ -280,6 +281,7 @@ describe("wire pins", () => {
280
281
  createdAt: "now",
281
282
  shareId: "p_abc123xy",
282
283
  owner: "SHA256:owner",
284
+ access: { githubLogins: ["octocat"] },
283
285
  participants: [fullIdentity],
284
286
  };
285
287
 
@@ -346,3 +348,21 @@ describe("wire pins", () => {
346
348
  }
347
349
  });
348
350
  });
351
+
352
+ describe("IdentitySchema provider", () => {
353
+ test("accepts a verified github identity", () => {
354
+ const parsed = v.safeParse(IdentitySchema, {
355
+ id: "SHA256:abc",
356
+ provider: "github",
357
+ name: "markus",
358
+ });
359
+
360
+ expect(parsed.success).toBe(true);
361
+ });
362
+
363
+ test("rejects an unknown provider", () => {
364
+ const parsed = v.safeParse(IdentitySchema, { id: "SHA256:abc", provider: "email" });
365
+
366
+ expect(parsed.success).toBe(false);
367
+ });
368
+ });
package/src/validate.ts CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  type HunkRejection,
25
25
  type Revision,
26
26
  type SessionHistory,
27
+ type ShareAccess,
27
28
  validateHistory,
28
29
  type Verdict,
29
30
  type WorkspaceKey,
@@ -125,7 +126,7 @@ export const FullAnnotationSchema = v.object({
125
126
 
126
127
  export const IdentitySchema = v.object({
127
128
  id: NonEmpty,
128
- provider: v.literal("ssh"),
129
+ provider: v.picklist(["ssh", "github"]),
129
130
  name: v.optional(v.string()),
130
131
  handle: v.optional(v.string()),
131
132
  } satisfies EntriesOf<Identity>);
@@ -204,6 +205,7 @@ export const Params = {
204
205
  "session.fork": v.object({ id: SessionId }),
205
206
  "session.refreshDiff": v.object({ id: SessionId }),
206
207
  "session.setShareId": v.object({ id: SessionId, shareId: NonEmpty }),
208
+ "session.setAccess": v.object({ id: SessionId, githubLogins: v.array(NonEmpty) }),
207
209
  "session.delete": v.object({ id: SessionId }),
208
210
  "session.mergeShared": v.object({
209
211
  id: SessionId,
@@ -349,6 +351,9 @@ export const ThreadRecordSchema = v.object({
349
351
  shareId: v.optional(v.string()),
350
352
  shareBranch: v.optional(v.string()),
351
353
  owner: v.optional(v.string()),
354
+ access: v.optional(
355
+ v.object({ githubLogins: v.array(NonEmpty) } satisfies EntriesOf<ShareAccess>),
356
+ ),
352
357
  participants: v.optional(v.array(IdentitySchema)),
353
358
  } satisfies EntriesOf<Thread>);
354
359