@sentry/junior-memory 0.124.1 → 0.124.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.
@@ -1,6 +1,10 @@
1
1
  import { z } from "zod";
2
2
  import { type MemoryDb, type MemoryRecord } from "./store";
3
3
  import { type MemoryRuntimeContext } from "./types";
4
+ declare const memoryVisibilitySchema: z.ZodEnum<{
5
+ public: "public";
6
+ private: "private";
7
+ }>;
4
8
  declare const personalMemoryCursorSchema: z.ZodObject<{
5
9
  createdAtMs: z.ZodNumber;
6
10
  id: z.ZodString;
@@ -21,17 +25,23 @@ declare const personalMemoryPageInputSchema: z.ZodObject<{
21
25
  explicit: "explicit";
22
26
  }>>;
23
27
  query: z.ZodOptional<z.ZodString>;
28
+ visibility: z.ZodOptional<z.ZodEnum<{
29
+ public: "public";
30
+ private: "private";
31
+ }>>;
24
32
  }, z.core.$strict>;
25
33
  export type PersonalMemoryCursor = z.output<typeof personalMemoryCursorSchema>;
26
34
  export type PersonalMemoryPageInput = z.output<typeof personalMemoryPageInputSchema>;
35
+ export type MemoryVisibility = z.output<typeof memoryVisibilitySchema>;
27
36
  export interface PersonalMemoryPage {
28
37
  memories: PersonalMemoryRecord[];
29
38
  nextCursor?: PersonalMemoryCursor;
30
39
  }
31
- /** Safe provenance attached to one viewer-owned personal memory. */
40
+ /** Safe provenance attached to one viewer-visible memory. */
32
41
  export type PersonalMemoryRecord = MemoryRecord & {
33
42
  origin: "automatic" | "explicit" | "other";
34
43
  sourcePlatform: "local" | "slack";
44
+ visibility: MemoryVisibility;
35
45
  };
36
46
  /** Viewer-scoped active memory totals used by the dashboard. */
37
47
  export interface PersonalMemoryStats {
@@ -41,36 +51,37 @@ export interface PersonalMemoryStats {
41
51
  embedded: number;
42
52
  explicit: number;
43
53
  knowledge: number;
54
+ personal: number;
44
55
  preference: number;
45
56
  procedure: number;
57
+ public: number;
46
58
  }
47
59
  /** Viewer-scoped memory creation totals for one UTC calendar day. */
48
60
  export interface PersonalMemoryDay {
49
61
  date: string;
50
- knowledge: number;
51
- preference: number;
52
- procedure: number;
62
+ personal: number;
63
+ public: number;
53
64
  }
54
65
  /** Expected failure when a viewer does not own the requested memory. */
55
66
  export declare class PersonalMemoryNotFoundError extends Error {
56
67
  constructor();
57
68
  }
58
- /** Viewer-scoped personal memory operations shared by dashboard and REST. */
69
+ /** Viewer-scoped memory operations shared by dashboard and REST. */
59
70
  export interface PersonalMemoryCollection {
60
71
  /** Archive one exact personal memory owned by a linked actor. */
61
72
  archive(id: string): Promise<MemoryRecord>;
62
- /** Read one exact personal memory owned by a linked actor. */
63
- get(id: string): Promise<MemoryRecord>;
64
- /** List one stable page across every linked personal scope. */
73
+ /** Read one exact memory visible to a linked actor. */
74
+ get(id: string): Promise<PersonalMemoryRecord>;
75
+ /** List one stable page across every authorized viewer scope. */
65
76
  list(input: PersonalMemoryPageInput): Promise<PersonalMemoryPage>;
66
- /** Summarize active memories across every linked personal scope. */
77
+ /** Summarize active memories across every authorized viewer scope. */
67
78
  stats(): Promise<PersonalMemoryStats>;
68
- /** Read memory creation history across every linked personal scope. */
79
+ /** Read memory creation history across every authorized viewer scope. */
69
80
  timeline(input: {
70
81
  days: number;
71
82
  }): Promise<PersonalMemoryDay[]>;
72
83
  }
73
- /** Build storage operations for every personal scope linked to one viewer. */
84
+ /** Build storage operations for every memory scope linked to one viewer. */
74
85
  export declare function createPersonalMemoryCollection(db: MemoryDb, runtimeContexts: MemoryRuntimeContext[], options?: {
75
86
  now?: () => number;
76
87
  }): PersonalMemoryCollection;
@@ -1,5 +1,5 @@
1
1
  import type { PluginUserPageActor } from "@sentry/junior-plugin-api";
2
- import { type PersonalMemoryRecord } from "./personal-store";
2
+ import { type MemoryVisibility, type PersonalMemoryRecord } from "./personal-store";
3
3
  import type { MemoryDb, MemoryRecord } from "./store";
4
4
  import type { MemoryKind } from "./types";
5
5
  export interface ViewerMemoryPage {
@@ -12,15 +12,17 @@ export interface ViewerMemoryPageInput {
12
12
  limit: number;
13
13
  origin?: "automatic" | "explicit";
14
14
  query?: string;
15
+ visibility?: MemoryVisibility;
15
16
  }
16
17
  export declare class InvalidMemoryCursorError extends Error {
17
18
  constructor();
18
19
  }
19
20
  export { PersonalMemoryNotFoundError } from "./personal-store";
20
- /** Build personal-memory operations authorized by a viewer's linked actors. */
21
+ export type { MemoryVisibility, PersonalMemoryRecord } from "./personal-store";
22
+ /** Build viewer memory operations authorized by a viewer's linked actors. */
21
23
  export declare function createViewerMemories(db: MemoryDb, actors: PluginUserPageActor[]): {
22
24
  archive(id: string): Promise<MemoryRecord>;
23
- get(id: string): Promise<MemoryRecord>;
25
+ get(id: string): Promise<PersonalMemoryRecord>;
24
26
  list(input: ViewerMemoryPageInput): Promise<ViewerMemoryPage>;
25
27
  stats(): Promise<import("./personal-store").PersonalMemoryStats>;
26
28
  timeline(input: {
@@ -1,4 +1,4 @@
1
- /** Project viewer-owned memories into Junior's core-rendered user page. */
1
+ /** Project viewer-visible memories into Junior's core-rendered user page. */
2
2
  import type { PluginUserPageDefinition } from "@sentry/junior-plugin-api";
3
- /** Create the interactive personal Memories dashboard page. */
3
+ /** Create the interactive Memories dashboard page. */
4
4
  export declare function createMemoryUserPage(): PluginUserPageDefinition;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-memory",
3
- "version": "0.124.1",
3
+ "version": "0.124.2",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -27,7 +27,7 @@
27
27
  "commander": "^14.0.3",
28
28
  "drizzle-orm": "^0.45.2",
29
29
  "zod": "^4.4.3",
30
- "@sentry/junior-plugin-api": "0.124.1"
30
+ "@sentry/junior-plugin-api": "0.124.2"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^25.9.1",
package/src/api.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Authenticated REST resources for personal memories.
2
+ * Authenticated REST resources for viewer-visible memories.
3
3
  *
4
4
  * HTTP identity is one verified viewer. Linked platform actors are resolved
5
- * behind the route boundary and used only to authorize personal scopes.
5
+ * behind the route boundary and used only to authorize personal and public
6
+ * workspace scopes.
6
7
  */
7
8
  import { z } from "zod";
8
9
  import {
@@ -11,11 +12,12 @@ import {
11
12
  type PluginRouteApp,
12
13
  type PluginUserPageActor,
13
14
  } from "@sentry/junior-plugin-api";
14
- import type { MemoryDb, MemoryRecord } from "./store";
15
+ import type { MemoryDb } from "./store";
15
16
  import {
16
17
  createViewerMemories,
17
18
  InvalidMemoryCursorError,
18
19
  PersonalMemoryNotFoundError,
20
+ type PersonalMemoryRecord,
19
21
  } from "./personal";
20
22
 
21
23
  export const memoryApiSchema = z
@@ -26,6 +28,7 @@ export const memoryApiSchema = z
26
28
  id: z.string().min(1),
27
29
  kind: z.enum(["preference", "procedure", "knowledge"]),
28
30
  observedAt: z.iso.datetime(),
31
+ visibility: z.enum(["private", "public"]),
29
32
  })
30
33
  .strict();
31
34
 
@@ -39,9 +42,8 @@ export const memoryListResponseSchema = z
39
42
  const memoryDashboardDaySchema = z
40
43
  .object({
41
44
  date: z.iso.date(),
42
- knowledge: z.number().int().min(0),
43
- preference: z.number().int().min(0),
44
- procedure: z.number().int().min(0),
45
+ personal: z.number().int().min(0),
46
+ public: z.number().int().min(0),
45
47
  })
46
48
  .strict();
47
49
 
@@ -57,8 +59,10 @@ export const memoryDashboardResponseSchema = z
57
59
  embedded: z.number().int().min(0),
58
60
  explicit: z.number().int().min(0),
59
61
  knowledge: z.number().int().min(0),
62
+ personal: z.number().int().min(0),
60
63
  preference: z.number().int().min(0),
61
64
  procedure: z.number().int().min(0),
65
+ public: z.number().int().min(0),
62
66
  })
63
67
  .strict(),
64
68
  })
@@ -90,7 +94,7 @@ function json(body: unknown, status = 200): Response {
90
94
  });
91
95
  }
92
96
 
93
- function apiMemory(memory: MemoryRecord): z.output<typeof memoryApiSchema> {
97
+ function apiMemory(memory: PersonalMemoryRecord): z.output<typeof memoryApiSchema> {
94
98
  return {
95
99
  content: memory.content,
96
100
  createdAt: new Date(memory.createdAtMs).toISOString(),
@@ -100,6 +104,7 @@ function apiMemory(memory: MemoryRecord): z.output<typeof memoryApiSchema> {
100
104
  id: memory.id,
101
105
  kind: memory.kind,
102
106
  observedAt: new Date(memory.observedAtMs).toISOString(),
107
+ visibility: memory.visibility,
103
108
  };
104
109
  }
105
110
 
@@ -113,7 +118,7 @@ function viewerEmail(
113
118
  return parsed.data.auth.user.email?.trim().toLowerCase() || undefined;
114
119
  }
115
120
 
116
- /** Create the authenticated personal-memory REST app. */
121
+ /** Create the authenticated viewer-memory REST app. */
117
122
  export function createMemoryApi(options: MemoryApiOptions): PluginRouteApp {
118
123
  return {
119
124
  async fetch(request, context) {
@@ -1,8 +1,8 @@
1
1
  /**
2
- * SQL operations over personal memories owned by one authenticated viewer.
2
+ * SQL operations over memories visible to one authenticated viewer.
3
3
  *
4
4
  * A viewer may resolve to several runtime actors. This store combines their
5
- * personal scopes without treating one actor as the canonical identity.
5
+ * personal scopes with authorized public workspace conversation scopes.
6
6
  */
7
7
  import { and, asc, desc, eq, gt, ilike, like, lt, or, sql } from "drizzle-orm";
8
8
  import { z } from "zod";
@@ -18,6 +18,7 @@ import {
18
18
  import { MEMORY_KINDS, type MemoryRuntimeContext } from "./types";
19
19
 
20
20
  const nonEmptyStringSchema = z.string().min(1);
21
+ const memoryVisibilitySchema = z.enum(["private", "public"]);
21
22
  const personalMemoryCursorSchema = z
22
23
  .object({
23
24
  createdAtMs: z.number().finite(),
@@ -31,6 +32,7 @@ const personalMemoryPageInputSchema = z
31
32
  limit: z.number().int().min(1).max(50),
32
33
  origin: z.enum(["automatic", "explicit"]).optional(),
33
34
  query: z.string().max(200).optional(),
35
+ visibility: memoryVisibilitySchema.optional(),
34
36
  })
35
37
  .strict();
36
38
  const personalMemoryTimelineInputSchema = z
@@ -46,15 +48,18 @@ export type PersonalMemoryPageInput = z.output<
46
48
  typeof personalMemoryPageInputSchema
47
49
  >;
48
50
 
51
+ export type MemoryVisibility = z.output<typeof memoryVisibilitySchema>;
52
+
49
53
  export interface PersonalMemoryPage {
50
54
  memories: PersonalMemoryRecord[];
51
55
  nextCursor?: PersonalMemoryCursor;
52
56
  }
53
57
 
54
- /** Safe provenance attached to one viewer-owned personal memory. */
58
+ /** Safe provenance attached to one viewer-visible memory. */
55
59
  export type PersonalMemoryRecord = MemoryRecord & {
56
60
  origin: "automatic" | "explicit" | "other";
57
61
  sourcePlatform: "local" | "slack";
62
+ visibility: MemoryVisibility;
58
63
  };
59
64
 
60
65
  /** Viewer-scoped active memory totals used by the dashboard. */
@@ -65,16 +70,17 @@ export interface PersonalMemoryStats {
65
70
  embedded: number;
66
71
  explicit: number;
67
72
  knowledge: number;
73
+ personal: number;
68
74
  preference: number;
69
75
  procedure: number;
76
+ public: number;
70
77
  }
71
78
 
72
79
  /** Viewer-scoped memory creation totals for one UTC calendar day. */
73
80
  export interface PersonalMemoryDay {
74
81
  date: string;
75
- knowledge: number;
76
- preference: number;
77
- procedure: number;
82
+ personal: number;
83
+ public: number;
78
84
  }
79
85
 
80
86
  /** Expected failure when a viewer does not own the requested memory. */
@@ -85,17 +91,17 @@ export class PersonalMemoryNotFoundError extends Error {
85
91
  }
86
92
  }
87
93
 
88
- /** Viewer-scoped personal memory operations shared by dashboard and REST. */
94
+ /** Viewer-scoped memory operations shared by dashboard and REST. */
89
95
  export interface PersonalMemoryCollection {
90
96
  /** Archive one exact personal memory owned by a linked actor. */
91
97
  archive(id: string): Promise<MemoryRecord>;
92
- /** Read one exact personal memory owned by a linked actor. */
93
- get(id: string): Promise<MemoryRecord>;
94
- /** List one stable page across every linked personal scope. */
98
+ /** Read one exact memory visible to a linked actor. */
99
+ get(id: string): Promise<PersonalMemoryRecord>;
100
+ /** List one stable page across every authorized viewer scope. */
95
101
  list(input: PersonalMemoryPageInput): Promise<PersonalMemoryPage>;
96
- /** Summarize active memories across every linked personal scope. */
102
+ /** Summarize active memories across every authorized viewer scope. */
97
103
  stats(): Promise<PersonalMemoryStats>;
98
- /** Read memory creation history across every linked personal scope. */
104
+ /** Read memory creation history across every authorized viewer scope. */
99
105
  timeline(input: { days: number }): Promise<PersonalMemoryDay[]>;
100
106
  }
101
107
 
@@ -112,7 +118,30 @@ function personalScopes(
112
118
  ];
113
119
  }
114
120
 
115
- function personalScopePredicate(scopes: ResolvedMemoryScope[]) {
121
+ /** Public workspace conversation scopes authorized by the viewer's Slack teams. */
122
+ function publicWorkspaceScopes(
123
+ runtimeContexts: MemoryRuntimeContext[],
124
+ ): ResolvedMemoryScope[] {
125
+ return [
126
+ ...new Map(
127
+ runtimeContexts.flatMap((context) => {
128
+ if (context.source.platform !== "slack" || !context.actor) {
129
+ return [];
130
+ }
131
+ if (context.actor.platform !== "slack") {
132
+ return [];
133
+ }
134
+ const scope: ResolvedMemoryScope = {
135
+ scope: "conversation",
136
+ scopeKey: `slack:${context.actor.teamId}`,
137
+ };
138
+ return [[`${scope.scope}:${scope.scopeKey}`, scope] as const];
139
+ }),
140
+ ).values(),
141
+ ];
142
+ }
143
+
144
+ function scopePredicate(scopes: ResolvedMemoryScope[]) {
116
145
  if (scopes.length === 0) return undefined;
117
146
  return or(
118
147
  ...scopes.map((scope) =>
@@ -148,30 +177,67 @@ function memoryOrigin(
148
177
  return "other";
149
178
  }
150
179
 
180
+ function memoryVisibility(
181
+ scope: MemoryRecord["scope"],
182
+ ): PersonalMemoryRecord["visibility"] {
183
+ return scope === "personal" ? "private" : "public";
184
+ }
185
+
151
186
  function personalMemoryRecord(
152
187
  row: typeof juniorMemoryMemories.$inferSelect,
153
188
  ): PersonalMemoryRecord {
189
+ const memory = parseMemoryRow(row);
154
190
  return {
155
- ...parseMemoryRow(row),
191
+ ...memory,
156
192
  origin: memoryOrigin(row.idempotencyKey),
157
193
  sourcePlatform: row.sourcePlatform,
194
+ visibility: memoryVisibility(memory.scope),
195
+ };
196
+ }
197
+
198
+ function emptyStats(): PersonalMemoryStats {
199
+ return {
200
+ active: 0,
201
+ automatic: 0,
202
+ createdThirtyDays: 0,
203
+ embedded: 0,
204
+ explicit: 0,
205
+ knowledge: 0,
206
+ personal: 0,
207
+ preference: 0,
208
+ procedure: 0,
209
+ public: 0,
158
210
  };
159
211
  }
160
212
 
161
- /** Build storage operations for every personal scope linked to one viewer. */
213
+ /** Build storage operations for every memory scope linked to one viewer. */
162
214
  export function createPersonalMemoryCollection(
163
215
  db: MemoryDb,
164
216
  runtimeContexts: MemoryRuntimeContext[],
165
217
  options: { now?: () => number } = {},
166
218
  ): PersonalMemoryCollection {
167
- const scopes = personalScopes(runtimeContexts);
219
+ const privateScopes = personalScopes(runtimeContexts);
220
+ const publicScopes = publicWorkspaceScopes(runtimeContexts);
221
+ const allScopes = [...privateScopes, ...publicScopes];
168
222
  const getNowMs = () => options.now?.() ?? Date.now();
169
223
 
224
+ function scopesForVisibility(
225
+ visibility: MemoryVisibility | undefined,
226
+ ): ResolvedMemoryScope[] {
227
+ if (visibility === "private") return privateScopes;
228
+ if (visibility === "public") return publicScopes;
229
+ return allScopes;
230
+ }
231
+
170
232
  return {
171
233
  async archive(id) {
172
234
  const memoryId = nonEmptyStringSchema.parse(id);
173
235
  const nowMs = getNowMs();
174
- const predicate = activeVisiblePredicate({ nowMs, scopes });
236
+ // Forget is personal-only; public workspace memories stay shared.
237
+ const predicate = activeVisiblePredicate({
238
+ nowMs,
239
+ scopes: privateScopes,
240
+ });
175
241
  if (!predicate) {
176
242
  throw new PersonalMemoryNotFoundError();
177
243
  }
@@ -195,7 +261,7 @@ export function createPersonalMemoryCollection(
195
261
  async get(id) {
196
262
  const memoryId = nonEmptyStringSchema.parse(id);
197
263
  const nowMs = getNowMs();
198
- const predicate = activeVisiblePredicate({ nowMs, scopes });
264
+ const predicate = activeVisiblePredicate({ nowMs, scopes: allScopes });
199
265
  if (!predicate) {
200
266
  throw new PersonalMemoryNotFoundError();
201
267
  }
@@ -207,12 +273,13 @@ export function createPersonalMemoryCollection(
207
273
  if (!rows[0]) {
208
274
  throw new PersonalMemoryNotFoundError();
209
275
  }
210
- return parseMemoryRow(rows[0]);
276
+ return personalMemoryRecord(rows[0]);
211
277
  },
212
278
 
213
279
  async list(input) {
214
280
  input = personalMemoryPageInputSchema.parse(input);
215
281
  const nowMs = getNowMs();
282
+ const scopes = scopesForVisibility(input.visibility);
216
283
  await archiveExpiredMemoryBatch({ db, nowMs, scopes });
217
284
  const active = activeVisiblePredicate({ nowMs, scopes });
218
285
  if (!active) {
@@ -275,19 +342,10 @@ export function createPersonalMemoryCollection(
275
342
 
276
343
  async stats() {
277
344
  const nowMs = getNowMs();
278
- await archiveExpiredMemoryBatch({ db, nowMs, scopes });
279
- const active = activeVisiblePredicate({ nowMs, scopes });
345
+ await archiveExpiredMemoryBatch({ db, nowMs, scopes: allScopes });
346
+ const active = activeVisiblePredicate({ nowMs, scopes: allScopes });
280
347
  if (!active) {
281
- return {
282
- active: 0,
283
- automatic: 0,
284
- createdThirtyDays: 0,
285
- embedded: 0,
286
- explicit: 0,
287
- knowledge: 0,
288
- preference: 0,
289
- procedure: 0,
290
- };
348
+ return emptyStats();
291
349
  }
292
350
  const [counts] = await db
293
351
  .select({
@@ -312,6 +370,10 @@ export function createPersonalMemoryCollection(
312
370
  sql<number>`count(*) filter (where ${juniorMemoryMemories.kind} = 'knowledge')`.mapWith(
313
371
  Number,
314
372
  ),
373
+ personal:
374
+ sql<number>`count(*) filter (where ${juniorMemoryMemories.scope} = 'personal')`.mapWith(
375
+ Number,
376
+ ),
315
377
  preference:
316
378
  sql<number>`count(*) filter (where ${juniorMemoryMemories.kind} = 'preference')`.mapWith(
317
379
  Number,
@@ -320,6 +382,10 @@ export function createPersonalMemoryCollection(
320
382
  sql<number>`count(*) filter (where ${juniorMemoryMemories.kind} = 'procedure')`.mapWith(
321
383
  Number,
322
384
  ),
385
+ public:
386
+ sql<number>`count(*) filter (where ${juniorMemoryMemories.scope} = 'conversation')`.mapWith(
387
+ Number,
388
+ ),
323
389
  })
324
390
  .from(juniorMemoryMemories)
325
391
  .leftJoin(
@@ -334,8 +400,10 @@ export function createPersonalMemoryCollection(
334
400
  embedded: counts?.embedded ?? 0,
335
401
  explicit: counts?.explicit ?? 0,
336
402
  knowledge: counts?.knowledge ?? 0,
403
+ personal: counts?.personal ?? 0,
337
404
  preference: counts?.preference ?? 0,
338
405
  procedure: counts?.procedure ?? 0,
406
+ public: counts?.public ?? 0,
339
407
  };
340
408
  },
341
409
 
@@ -343,13 +411,12 @@ export function createPersonalMemoryCollection(
343
411
  input = personalMemoryTimelineInputSchema.parse(input);
344
412
  const todayMs = Date.parse(`${utcDate(getNowMs())}T00:00:00.000Z`);
345
413
  const startMs = todayMs - (input.days - 1) * DAY_MS;
346
- const ownership = personalScopePredicate(scopes);
414
+ const ownership = scopePredicate(allScopes);
347
415
  if (!ownership) {
348
416
  return Array.from({ length: input.days }, (_, index) => ({
349
417
  date: utcDate(startMs + index * DAY_MS),
350
- knowledge: 0,
351
- preference: 0,
352
- procedure: 0,
418
+ personal: 0,
419
+ public: 0,
353
420
  }));
354
421
  }
355
422
  const rows = await db
@@ -357,16 +424,12 @@ export function createPersonalMemoryCollection(
357
424
  date: sql<string>`to_char(to_timestamp(${juniorMemoryMemories.createdAtMs} / 1000.0) AT TIME ZONE 'UTC', 'YYYY-MM-DD')`.as(
358
425
  "date",
359
426
  ),
360
- knowledge:
361
- sql<number>`count(*) filter (where ${juniorMemoryMemories.kind} = 'knowledge')`.mapWith(
427
+ personal:
428
+ sql<number>`count(*) filter (where ${juniorMemoryMemories.scope} = 'personal')`.mapWith(
362
429
  Number,
363
430
  ),
364
- preference:
365
- sql<number>`count(*) filter (where ${juniorMemoryMemories.kind} = 'preference')`.mapWith(
366
- Number,
367
- ),
368
- procedure:
369
- sql<number>`count(*) filter (where ${juniorMemoryMemories.kind} = 'procedure')`.mapWith(
431
+ public:
432
+ sql<number>`count(*) filter (where ${juniorMemoryMemories.scope} = 'conversation')`.mapWith(
370
433
  Number,
371
434
  ),
372
435
  })
@@ -383,9 +446,8 @@ export function createPersonalMemoryCollection(
383
446
  const row = byDate.get(date);
384
447
  return {
385
448
  date,
386
- knowledge: row?.knowledge ?? 0,
387
- preference: row?.preference ?? 0,
388
- procedure: row?.procedure ?? 0,
449
+ personal: row?.personal ?? 0,
450
+ public: row?.public ?? 0,
389
451
  };
390
452
  });
391
453
  },
package/src/personal.ts CHANGED
@@ -2,12 +2,14 @@
2
2
  * Authenticated-viewer memory access shared by REST and dashboard projections.
3
3
  *
4
4
  * Viewer identity may resolve to multiple platform actors. This module keeps
5
- * that federation behind one personal-memory collection.
5
+ * that federation behind one viewer-memory collection spanning personal and
6
+ * authorized public workspace scopes.
6
7
  */
7
8
  import { z } from "zod";
8
9
  import type { PluginUserPageActor } from "@sentry/junior-plugin-api";
9
10
  import {
10
11
  createPersonalMemoryCollection,
12
+ type MemoryVisibility,
11
13
  type PersonalMemoryRecord,
12
14
  } from "./personal-store";
13
15
  import type { MemoryDb, MemoryRecord } from "./store";
@@ -21,6 +23,7 @@ const cursorSchema = z
21
23
  origin: z.enum(["automatic", "explicit"]).optional(),
22
24
  query: z.string().max(200).optional(),
23
25
  version: z.literal(1),
26
+ visibility: z.enum(["private", "public"]).optional(),
24
27
  })
25
28
  .strict();
26
29
 
@@ -35,6 +38,7 @@ export interface ViewerMemoryPageInput {
35
38
  limit: number;
36
39
  origin?: "automatic" | "explicit";
37
40
  query?: string;
41
+ visibility?: MemoryVisibility;
38
42
  }
39
43
 
40
44
  export class InvalidMemoryCursorError extends Error {
@@ -45,6 +49,7 @@ export class InvalidMemoryCursorError extends Error {
45
49
  }
46
50
 
47
51
  export { PersonalMemoryNotFoundError } from "./personal-store";
52
+ export type { MemoryVisibility, PersonalMemoryRecord } from "./personal-store";
48
53
 
49
54
  function runtimeContext(actor: PluginUserPageActor): MemoryRuntimeContext {
50
55
  if (actor.platform === "slack") {
@@ -70,7 +75,7 @@ function runtimeContext(actor: PluginUserPageActor): MemoryRuntimeContext {
70
75
 
71
76
  function decodeCursor(
72
77
  value: string | undefined,
73
- input: Pick<ViewerMemoryPageInput, "kind" | "origin" | "query">,
78
+ input: Pick<ViewerMemoryPageInput, "kind" | "origin" | "query" | "visibility">,
74
79
  ) {
75
80
  if (!value) return undefined;
76
81
  try {
@@ -80,7 +85,8 @@ function decodeCursor(
80
85
  if (
81
86
  parsed.query !== input.query ||
82
87
  parsed.kind !== input.kind ||
83
- parsed.origin !== input.origin
88
+ parsed.origin !== input.origin ||
89
+ parsed.visibility !== input.visibility
84
90
  ) {
85
91
  throw new InvalidMemoryCursorError();
86
92
  }
@@ -92,7 +98,7 @@ function decodeCursor(
92
98
 
93
99
  function encodeCursor(
94
100
  cursor: { createdAtMs: number; id: string },
95
- input: Pick<ViewerMemoryPageInput, "kind" | "origin" | "query">,
101
+ input: Pick<ViewerMemoryPageInput, "kind" | "origin" | "query" | "visibility">,
96
102
  ): string {
97
103
  return Buffer.from(
98
104
  JSON.stringify({
@@ -100,13 +106,14 @@ function encodeCursor(
100
106
  ...(input.query ? { query: input.query } : {}),
101
107
  ...(input.kind ? { kind: input.kind } : {}),
102
108
  ...(input.origin ? { origin: input.origin } : {}),
109
+ ...(input.visibility ? { visibility: input.visibility } : {}),
103
110
  version: 1,
104
111
  }),
105
112
  "utf8",
106
113
  ).toString("base64url");
107
114
  }
108
115
 
109
- /** Build personal-memory operations authorized by a viewer's linked actors. */
116
+ /** Build viewer memory operations authorized by a viewer's linked actors. */
110
117
  export function createViewerMemories(
111
118
  db: MemoryDb,
112
119
  actors: PluginUserPageActor[],
@@ -119,7 +126,7 @@ export function createViewerMemories(
119
126
  async archive(id: string): Promise<MemoryRecord> {
120
127
  return await collection.archive(id);
121
128
  },
122
- async get(id: string): Promise<MemoryRecord> {
129
+ async get(id: string): Promise<PersonalMemoryRecord> {
123
130
  return await collection.get(id);
124
131
  },
125
132
  async list(input: ViewerMemoryPageInput): Promise<ViewerMemoryPage> {
@@ -128,6 +135,7 @@ export function createViewerMemories(
128
135
  ...(input.kind ? { kind: input.kind } : {}),
129
136
  ...(input.origin ? { origin: input.origin } : {}),
130
137
  ...(query ? { query } : {}),
138
+ ...(input.visibility ? { visibility: input.visibility } : {}),
131
139
  };
132
140
  const page = await collection.list({
133
141
  cursor: decodeCursor(input.cursor, filters),