@sentry/junior-memory 0.124.0 → 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
- import type { MemoryRuntimeContext } from "./types";
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;
@@ -10,29 +14,74 @@ declare const personalMemoryPageInputSchema: z.ZodObject<{
10
14
  createdAtMs: z.ZodNumber;
11
15
  id: z.ZodString;
12
16
  }, z.core.$strict>>;
17
+ kind: z.ZodOptional<z.ZodEnum<{
18
+ preference: "preference";
19
+ procedure: "procedure";
20
+ knowledge: "knowledge";
21
+ }>>;
13
22
  limit: z.ZodNumber;
23
+ origin: z.ZodOptional<z.ZodEnum<{
24
+ automatic: "automatic";
25
+ explicit: "explicit";
26
+ }>>;
14
27
  query: z.ZodOptional<z.ZodString>;
28
+ visibility: z.ZodOptional<z.ZodEnum<{
29
+ public: "public";
30
+ private: "private";
31
+ }>>;
15
32
  }, z.core.$strict>;
16
33
  export type PersonalMemoryCursor = z.output<typeof personalMemoryCursorSchema>;
17
34
  export type PersonalMemoryPageInput = z.output<typeof personalMemoryPageInputSchema>;
35
+ export type MemoryVisibility = z.output<typeof memoryVisibilitySchema>;
18
36
  export interface PersonalMemoryPage {
19
- memories: MemoryRecord[];
37
+ memories: PersonalMemoryRecord[];
20
38
  nextCursor?: PersonalMemoryCursor;
21
39
  }
40
+ /** Safe provenance attached to one viewer-visible memory. */
41
+ export type PersonalMemoryRecord = MemoryRecord & {
42
+ origin: "automatic" | "explicit" | "other";
43
+ sourcePlatform: "local" | "slack";
44
+ visibility: MemoryVisibility;
45
+ };
46
+ /** Viewer-scoped active memory totals used by the dashboard. */
47
+ export interface PersonalMemoryStats {
48
+ active: number;
49
+ automatic: number;
50
+ createdThirtyDays: number;
51
+ embedded: number;
52
+ explicit: number;
53
+ knowledge: number;
54
+ personal: number;
55
+ preference: number;
56
+ procedure: number;
57
+ public: number;
58
+ }
59
+ /** Viewer-scoped memory creation totals for one UTC calendar day. */
60
+ export interface PersonalMemoryDay {
61
+ date: string;
62
+ personal: number;
63
+ public: number;
64
+ }
22
65
  /** Expected failure when a viewer does not own the requested memory. */
23
66
  export declare class PersonalMemoryNotFoundError extends Error {
24
67
  constructor();
25
68
  }
26
- /** Viewer-scoped personal memory operations shared by dashboard and REST. */
69
+ /** Viewer-scoped memory operations shared by dashboard and REST. */
27
70
  export interface PersonalMemoryCollection {
28
71
  /** Archive one exact personal memory owned by a linked actor. */
29
72
  archive(id: string): Promise<MemoryRecord>;
30
- /** Read one exact personal memory owned by a linked actor. */
31
- get(id: string): Promise<MemoryRecord>;
32
- /** 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. */
33
76
  list(input: PersonalMemoryPageInput): Promise<PersonalMemoryPage>;
77
+ /** Summarize active memories across every authorized viewer scope. */
78
+ stats(): Promise<PersonalMemoryStats>;
79
+ /** Read memory creation history across every authorized viewer scope. */
80
+ timeline(input: {
81
+ days: number;
82
+ }): Promise<PersonalMemoryDay[]>;
34
83
  }
35
- /** Build storage operations for every personal scope linked to one viewer. */
84
+ /** Build storage operations for every memory scope linked to one viewer. */
36
85
  export declare function createPersonalMemoryCollection(db: MemoryDb, runtimeContexts: MemoryRuntimeContext[], options?: {
37
86
  now?: () => number;
38
87
  }): PersonalMemoryCollection;
@@ -1,21 +1,31 @@
1
1
  import type { PluginUserPageActor } from "@sentry/junior-plugin-api";
2
+ import { type MemoryVisibility, type PersonalMemoryRecord } from "./personal-store";
2
3
  import type { MemoryDb, MemoryRecord } from "./store";
4
+ import type { MemoryKind } from "./types";
3
5
  export interface ViewerMemoryPage {
4
- memories: MemoryRecord[];
6
+ memories: PersonalMemoryRecord[];
5
7
  nextCursor?: string;
6
8
  }
7
9
  export interface ViewerMemoryPageInput {
8
10
  cursor?: string;
11
+ kind?: MemoryKind;
9
12
  limit: number;
13
+ origin?: "automatic" | "explicit";
10
14
  query?: string;
15
+ visibility?: MemoryVisibility;
11
16
  }
12
17
  export declare class InvalidMemoryCursorError extends Error {
13
18
  constructor();
14
19
  }
15
20
  export { PersonalMemoryNotFoundError } from "./personal-store";
16
- /** 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. */
17
23
  export declare function createViewerMemories(db: MemoryDb, actors: PluginUserPageActor[]): {
18
24
  archive(id: string): Promise<MemoryRecord>;
19
- get(id: string): Promise<MemoryRecord>;
25
+ get(id: string): Promise<PersonalMemoryRecord>;
20
26
  list(input: ViewerMemoryPageInput): Promise<ViewerMemoryPage>;
27
+ stats(): Promise<import("./personal-store").PersonalMemoryStats>;
28
+ timeline(input: {
29
+ days: number;
30
+ }): Promise<import("./personal-store").PersonalMemoryDay[]>;
21
31
  };
@@ -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.0",
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.0"
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
 
@@ -36,7 +39,39 @@ export const memoryListResponseSchema = z
36
39
  })
37
40
  .strict();
38
41
 
42
+ const memoryDashboardDaySchema = z
43
+ .object({
44
+ date: z.iso.date(),
45
+ personal: z.number().int().min(0),
46
+ public: z.number().int().min(0),
47
+ })
48
+ .strict();
49
+
50
+ export const memoryDashboardResponseSchema = z
51
+ .object({
52
+ days: z.array(memoryDashboardDaySchema).length(90),
53
+ generatedAt: z.iso.datetime(),
54
+ stats: z
55
+ .object({
56
+ active: z.number().int().min(0),
57
+ automatic: z.number().int().min(0),
58
+ createdThirtyDays: z.number().int().min(0),
59
+ embedded: z.number().int().min(0),
60
+ explicit: z.number().int().min(0),
61
+ knowledge: z.number().int().min(0),
62
+ personal: z.number().int().min(0),
63
+ preference: z.number().int().min(0),
64
+ procedure: z.number().int().min(0),
65
+ public: z.number().int().min(0),
66
+ })
67
+ .strict(),
68
+ })
69
+ .strict();
70
+
39
71
  export type MemoryApi = z.output<typeof memoryApiSchema>;
72
+ export type MemoryDashboardResponse = z.output<
73
+ typeof memoryDashboardResponseSchema
74
+ >;
40
75
  export type MemoryListResponse = z.output<typeof memoryListResponseSchema>;
41
76
 
42
77
  const memoryListQuerySchema = z
@@ -59,7 +94,7 @@ function json(body: unknown, status = 200): Response {
59
94
  });
60
95
  }
61
96
 
62
- function apiMemory(memory: MemoryRecord): z.output<typeof memoryApiSchema> {
97
+ function apiMemory(memory: PersonalMemoryRecord): z.output<typeof memoryApiSchema> {
63
98
  return {
64
99
  content: memory.content,
65
100
  createdAt: new Date(memory.createdAtMs).toISOString(),
@@ -69,6 +104,7 @@ function apiMemory(memory: MemoryRecord): z.output<typeof memoryApiSchema> {
69
104
  id: memory.id,
70
105
  kind: memory.kind,
71
106
  observedAt: new Date(memory.observedAtMs).toISOString(),
107
+ visibility: memory.visibility,
72
108
  };
73
109
  }
74
110
 
@@ -82,7 +118,7 @@ function viewerEmail(
82
118
  return parsed.data.auth.user.email?.trim().toLowerCase() || undefined;
83
119
  }
84
120
 
85
- /** Create the authenticated personal-memory REST app. */
121
+ /** Create the authenticated viewer-memory REST app. */
86
122
  export function createMemoryApi(options: MemoryApiOptions): PluginRouteApp {
87
123
  return {
88
124
  async fetch(request, context) {
@@ -94,13 +130,35 @@ export function createMemoryApi(options: MemoryApiOptions): PluginRouteApp {
94
130
  const url = new URL(request.url);
95
131
  const memoryPath = /^\/memories\/([^/]+)$/.exec(url.pathname);
96
132
  const isCollection = url.pathname === "/memories";
97
- if (!isCollection && !memoryPath) {
133
+ const isDashboard = url.pathname === "/dashboard";
134
+ if (!isCollection && !isDashboard && !memoryPath) {
98
135
  return json({ error: "Not found." }, 404);
99
136
  }
100
137
 
101
138
  const actors = await options.actors(email);
102
139
  const memories = createViewerMemories(options.db, actors);
103
140
  try {
141
+ if (
142
+ isDashboard &&
143
+ (request.method === "GET" || request.method === "HEAD")
144
+ ) {
145
+ const [stats, days] = await Promise.all([
146
+ memories.stats(),
147
+ memories.timeline({ days: 90 }),
148
+ ]);
149
+ const body = memoryDashboardResponseSchema.parse({
150
+ days,
151
+ generatedAt: new Date().toISOString(),
152
+ stats,
153
+ });
154
+ return request.method === "HEAD"
155
+ ? new Response(null, {
156
+ headers: { "cache-control": "no-store" },
157
+ status: 200,
158
+ })
159
+ : json(body);
160
+ }
161
+
104
162
  if (
105
163
  isCollection &&
106
164
  (request.method === "GET" || request.method === "HEAD")
package/src/index.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  export { memoryPlugin } from "./plugin";
2
2
  export {
3
3
  memoryApiSchema,
4
+ memoryDashboardResponseSchema,
4
5
  memoryListResponseSchema,
5
6
  type MemoryApi,
7
+ type MemoryDashboardResponse,
6
8
  type MemoryListResponse,
7
9
  } from "./api";
8
10
  export type { MemoryPluginOptions } from "./plugin";