@sentry/junior-plugin-api 0.81.0 → 0.83.0

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.
@@ -101,6 +101,12 @@ export declare class EgressAuthRequired extends Error {
101
101
  cause?: unknown;
102
102
  });
103
103
  }
104
+ /** Deny provider egress before Junior issues credentials for a disallowed operation. */
105
+ export declare class EgressPolicyDenied extends Error {
106
+ constructor(message: string, options?: {
107
+ cause?: unknown;
108
+ });
109
+ }
104
110
  /** Provider account identity resolved by a plugin OAuth hook. */
105
111
  export type PluginProviderAccount = z.output<typeof pluginProviderAccountSchema>;
106
112
  /** Plugin-defined grant required before Junior can forward one outbound request. */
@@ -110,6 +116,8 @@ export interface PluginEgressRequest {
110
116
  /** Capped request body text when the host exposes it for provider-specific grant classification. */
111
117
  bodyText?: string;
112
118
  method: string;
119
+ /** Plugin-declared operation this request performs, used for grant classification and diagnostics. */
120
+ operation?: string;
113
121
  url: string;
114
122
  }
115
123
  export interface EgressHookContext extends PluginContext {
package/dist/hooks.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { EgressHookContext, EgressResponseHookContext, IssueCredentialHookContext, PluginCredentialResult, PluginGrant, PluginProviderAccount, ResolveOAuthAccountHookContext } from "./credentials";
2
- import type { HeartbeatHookContext, HeartbeatResult, OperationalReportHookContext, DashboardRouteRegistrationHookContext, PluginOperationalReportContent, PluginRoute, PluginRouteApp, RouteRegistrationHookContext, SlackConversationLink, SlackConversationLinkHookContext, StorageMigrationContext, StorageMigrationResult } from "./operations";
2
+ import type { HeartbeatHookContext, HeartbeatResult, OperationalReportHookContext, ApiRouteRegistrationHookContext, PluginOperationalReportContent, PluginRoute, PluginRouteApp, RouteRegistrationHookContext, SlackConversationLink, SlackConversationLinkHookContext, StorageMigrationContext, StorageMigrationResult } from "./operations";
3
3
  import type { BeforeToolExecuteHookContext, PluginToolDefinition, SandboxPrepareHookContext, ToolRegistrationHookContext } from "./tools";
4
4
  import type { PromptMessage, SystemPromptContext, UserPromptContext } from "./prompt";
5
5
  export interface PluginHooks {
@@ -11,7 +11,8 @@ export interface PluginHooks {
11
11
  issueCredential?(ctx: IssueCredentialHookContext): Promise<PluginCredentialResult> | PluginCredentialResult;
12
12
  onEgressResponse?(ctx: EgressResponseHookContext): Promise<void> | void;
13
13
  operationalReport?(ctx: OperationalReportHookContext): Promise<PluginOperationalReportContent | undefined> | PluginOperationalReportContent | undefined;
14
- dashboardRoutes?(ctx: DashboardRouteRegistrationHookContext): PluginRouteApp | undefined;
14
+ /** Return plugin-owned product API routes mounted under Junior's authenticated plugin namespace. */
15
+ apiRoutes?(ctx: ApiRouteRegistrationHookContext): PluginRouteApp | undefined;
15
16
  resolveOAuthAccount?(ctx: ResolveOAuthAccountHookContext): Promise<PluginProviderAccount | undefined> | PluginProviderAccount | undefined;
16
17
  routes?(ctx: RouteRegistrationHookContext): PluginRoute[];
17
18
  sandboxPrepare?(ctx: SandboxPrepareHookContext): Promise<void> | void;
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from "./context";
3
3
  export * from "./state";
4
4
  export { promptMessageSchema, type PromptMessage, type SystemPromptContext, type UserPromptContext, } from "./prompt";
5
5
  export * from "./dispatch";
6
+ export * from "./resource-events";
6
7
  export * from "./tasks";
7
8
  export * from "./tools";
8
9
  export * from "./operations";
package/dist/index.js CHANGED
@@ -164,29 +164,40 @@ var promptMessageSchema = z2.object({
164
164
  text: z2.string().trim().min(1).max(8e3)
165
165
  }).strict();
166
166
 
167
- // src/tasks.ts
167
+ // src/resource-events.ts
168
168
  import { z as z3 } from "zod";
169
- var pluginRunTranscriptEntrySchema = z3.discriminatedUnion("type", [
170
- z3.object({
171
- type: z3.literal("message"),
172
- role: z3.enum(["user", "assistant"]),
173
- text: z3.string().min(1)
169
+ var subscribableResourceSchema = z3.object({
170
+ label: z3.string().min(1),
171
+ provider: z3.string().min(1),
172
+ resourceRef: z3.string().min(1),
173
+ suggestedEvents: z3.array(z3.string().min(1)).optional(),
174
+ supportedEvents: z3.array(z3.string().min(1)),
175
+ type: z3.string().min(1)
176
+ }).strict();
177
+
178
+ // src/tasks.ts
179
+ import { z as z4 } from "zod";
180
+ var pluginRunTranscriptEntrySchema = z4.discriminatedUnion("type", [
181
+ z4.object({
182
+ type: z4.literal("message"),
183
+ role: z4.enum(["user", "assistant"]),
184
+ text: z4.string().min(1)
174
185
  }).strict(),
175
- z3.object({
176
- type: z3.literal("toolResult"),
177
- toolName: z3.string().min(1),
178
- isError: z3.boolean(),
179
- text: z3.string().min(1).optional()
186
+ z4.object({
187
+ type: z4.literal("toolResult"),
188
+ toolName: z4.string().min(1),
189
+ isError: z4.boolean(),
190
+ text: z4.string().min(1).optional()
180
191
  }).strict()
181
192
  ]);
182
- var pluginRunContextSchema = z3.object({
183
- completedAtMs: z3.number().finite(),
184
- conversationId: z3.string().min(1),
193
+ var pluginRunContextSchema = z4.object({
194
+ completedAtMs: z4.number().finite(),
195
+ conversationId: z4.string().min(1),
185
196
  destination: destinationSchema,
186
197
  requester: requesterSchema.optional(),
187
- runId: z3.string().min(1),
198
+ runId: z4.string().min(1),
188
199
  source: sourceSchema,
189
- transcript: z3.array(pluginRunTranscriptEntrySchema)
200
+ transcript: z4.array(pluginRunTranscriptEntrySchema)
190
201
  }).strict();
191
202
 
192
203
  // src/tools.ts
@@ -197,61 +208,75 @@ var PluginToolInputError = class extends Error {
197
208
  }
198
209
  };
199
210
 
211
+ // src/operations.ts
212
+ import { z as z5 } from "zod";
213
+ var pluginApiRouteRequestContextSchema = z5.object({
214
+ auth: z5.object({
215
+ user: z5.object({
216
+ email: z5.string().nullable().optional(),
217
+ emailVerified: z5.boolean().optional(),
218
+ hostedDomain: z5.string().nullable().optional(),
219
+ name: z5.string().nullable().optional()
220
+ }).strict()
221
+ }).strict(),
222
+ pluginName: nonBlankStringSchema
223
+ }).strict();
224
+
200
225
  // src/credentials.ts
201
- import { z as z4 } from "zod";
202
- var pluginProviderNameSchema = z4.string().regex(/^[a-z][a-z0-9-]*$/);
203
- var pluginGrantNameSchema = z4.string().regex(/^[a-z][a-z0-9.-]*$/);
204
- var pluginGrantAccessSchema = z4.union([
205
- z4.literal("read"),
206
- z4.literal("write")
226
+ import { z as z6 } from "zod";
227
+ var pluginProviderNameSchema = z6.string().regex(/^[a-z][a-z0-9-]*$/);
228
+ var pluginGrantNameSchema = z6.string().regex(/^[a-z][a-z0-9.-]*$/);
229
+ var pluginGrantAccessSchema = z6.union([
230
+ z6.literal("read"),
231
+ z6.literal("write")
207
232
  ]);
208
- var pluginAuthorizationSchema = z4.object({
233
+ var pluginAuthorizationSchema = z6.object({
209
234
  provider: pluginProviderNameSchema,
210
235
  scope: nonBlankStringSchema.optional(),
211
- type: z4.literal("oauth")
236
+ type: z6.literal("oauth")
212
237
  }).strict();
213
- var pluginProviderAccountSchema = z4.object({
238
+ var pluginProviderAccountSchema = z6.object({
214
239
  id: nonBlankStringSchema,
215
240
  label: nonBlankStringSchema.optional(),
216
241
  url: nonBlankStringSchema.optional()
217
242
  }).strict();
218
- var pluginStoredTokensSchema = z4.object({
243
+ var pluginStoredTokensSchema = z6.object({
219
244
  account: pluginProviderAccountSchema.optional(),
220
245
  accessToken: nonBlankStringSchema,
221
- expiresAt: z4.number().finite().optional(),
246
+ expiresAt: z6.number().finite().optional(),
222
247
  refreshToken: nonBlankStringSchema,
223
- refreshTokenExpiresAt: z4.number().finite().optional(),
248
+ refreshTokenExpiresAt: z6.number().finite().optional(),
224
249
  scope: nonBlankStringSchema.optional()
225
250
  }).strict();
226
- var pluginGrantSchema = z4.object({
251
+ var pluginGrantSchema = z6.object({
227
252
  access: pluginGrantAccessSchema,
228
253
  name: pluginGrantNameSchema,
229
254
  reason: nonBlankStringSchema.optional(),
230
- requirements: z4.array(nonBlankStringSchema).min(1).optional()
255
+ requirements: z6.array(nonBlankStringSchema).min(1).optional()
231
256
  }).strict();
232
- var pluginCredentialHeaderTransformSchema = z4.object({
233
- domain: z4.string().min(1),
234
- headers: z4.record(z4.string(), z4.string()).refine((headers) => Object.keys(headers).length > 0)
257
+ var pluginCredentialHeaderTransformSchema = z6.object({
258
+ domain: z6.string().min(1),
259
+ headers: z6.record(z6.string(), z6.string()).refine((headers) => Object.keys(headers).length > 0)
235
260
  }).strict();
236
- var pluginCredentialLeaseSchema = z4.object({
261
+ var pluginCredentialLeaseSchema = z6.object({
237
262
  account: pluginProviderAccountSchema.optional(),
238
263
  authorization: pluginAuthorizationSchema.optional(),
239
- expiresAt: z4.string().refine((value) => Number.isFinite(Date.parse(value))),
240
- headerTransforms: z4.array(pluginCredentialHeaderTransformSchema).min(1)
264
+ expiresAt: z6.string().refine((value) => Number.isFinite(Date.parse(value))),
265
+ headerTransforms: z6.array(pluginCredentialHeaderTransformSchema).min(1)
241
266
  }).strict();
242
- var pluginCredentialResultSchema = z4.discriminatedUnion("type", [
243
- z4.object({
267
+ var pluginCredentialResultSchema = z6.discriminatedUnion("type", [
268
+ z6.object({
244
269
  lease: pluginCredentialLeaseSchema,
245
- type: z4.literal("lease")
270
+ type: z6.literal("lease")
246
271
  }).strict(),
247
- z4.object({
272
+ z6.object({
248
273
  authorization: pluginAuthorizationSchema.optional(),
249
274
  message: nonBlankStringSchema,
250
- type: z4.literal("needed")
275
+ type: z6.literal("needed")
251
276
  }).strict(),
252
- z4.object({
277
+ z6.object({
253
278
  message: nonBlankStringSchema,
254
- type: z4.literal("unavailable")
279
+ type: z6.literal("unavailable")
255
280
  }).strict()
256
281
  ]);
257
282
  var EgressAuthRequired = class extends Error {
@@ -262,6 +287,12 @@ var EgressAuthRequired = class extends Error {
262
287
  this.authorization = options?.authorization;
263
288
  }
264
289
  };
290
+ var EgressPolicyDenied = class extends Error {
291
+ constructor(message, options) {
292
+ super(message, { cause: options?.cause });
293
+ this.name = "EgressPolicyDenied";
294
+ }
295
+ };
265
296
 
266
297
  // src/registration.ts
267
298
  var PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;
@@ -305,6 +336,7 @@ function defineJuniorPlugin(plugin) {
305
336
  }
306
337
  export {
307
338
  EgressAuthRequired,
339
+ EgressPolicyDenied,
308
340
  PluginToolInputError,
309
341
  createLocalSource,
310
342
  createSlackSource,
@@ -319,6 +351,7 @@ export {
319
351
  localSourceSchema,
320
352
  nonBlankStringSchema,
321
353
  platformSchema,
354
+ pluginApiRouteRequestContextSchema,
322
355
  pluginAuthorizationSchema,
323
356
  pluginCredentialHeaderTransformSchema,
324
357
  pluginCredentialLeaseSchema,
@@ -335,5 +368,6 @@ export {
335
368
  slackRequesterSchema,
336
369
  slackSourceSchema,
337
370
  sourceSchema,
338
- sourceTypeSchema
371
+ sourceTypeSchema,
372
+ subscribableResourceSchema
339
373
  };
@@ -1,3 +1,4 @@
1
+ import { z } from "zod";
1
2
  import type { PluginContext } from "./context";
2
3
  import type { Dispatch, DispatchOptions, DispatchResult } from "./dispatch";
3
4
  import type { PluginReadState, PluginState } from "./state";
@@ -8,7 +9,7 @@ export interface PluginConversationSummary {
8
9
  displayTitle: string;
9
10
  lastActivityAt: string;
10
11
  lastUpdatedAt: string;
11
- source?: "api" | "internal" | "local" | "plugin" | "scheduler" | "slack";
12
+ source?: "api" | "internal" | "local" | "plugin" | "resource_event" | "scheduler" | "slack";
12
13
  status: PluginConversationStatus;
13
14
  }
14
15
  export interface PluginConversations {
@@ -81,13 +82,27 @@ export interface PluginRoute {
81
82
  method?: PluginRouteMethod | PluginRouteMethod[];
82
83
  path: string;
83
84
  }
85
+ /** Fetch-compatible plugin HTTP app mounted by Junior. */
84
86
  export type PluginRouteApp = {
85
- fetch(request: Request): Promise<Response> | Response;
87
+ fetch(request: Request, context?: PluginApiRouteRequestContext): Promise<Response> | Response;
86
88
  };
87
89
  export interface RouteRegistrationHookContext extends PluginContext {
88
90
  }
89
- export interface DashboardRouteRegistrationHookContext extends PluginContext {
90
- }
91
+ export interface ApiRouteRegistrationHookContext extends PluginContext {
92
+ }
93
+ /** Per-request context Junior passes to authenticated plugin product API routes. */
94
+ export declare const pluginApiRouteRequestContextSchema: z.ZodObject<{
95
+ auth: z.ZodObject<{
96
+ user: z.ZodObject<{
97
+ email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
98
+ emailVerified: z.ZodOptional<z.ZodBoolean>;
99
+ hostedDomain: z.ZodOptional<z.ZodNullable<z.ZodString>>;
100
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
101
+ }, z.core.$strict>;
102
+ }, z.core.$strict>;
103
+ pluginName: z.ZodString;
104
+ }, z.core.$strict>;
105
+ export type PluginApiRouteRequestContext = z.output<typeof pluginApiRouteRequestContextSchema>;
91
106
  export interface SlackConversationLink {
92
107
  url: string;
93
108
  }
@@ -0,0 +1,10 @@
1
+ import { z } from "zod";
2
+ export declare const subscribableResourceSchema: z.ZodObject<{
3
+ label: z.ZodString;
4
+ provider: z.ZodString;
5
+ resourceRef: z.ZodString;
6
+ suggestedEvents: z.ZodOptional<z.ZodArray<z.ZodString>>;
7
+ supportedEvents: z.ZodArray<z.ZodString>;
8
+ type: z.ZodString;
9
+ }, z.core.$strict>;
10
+ export type SubscribableResource = z.output<typeof subscribableResourceSchema>;
package/dist/tools.d.ts CHANGED
@@ -36,6 +36,20 @@ export interface PluginSandbox {
36
36
  path: string;
37
37
  }): Promise<void>;
38
38
  }
39
+ export interface PluginEgress {
40
+ /**
41
+ * Fetch a provider URL with host-owned credentials.
42
+ *
43
+ * The runtime selects and injects credentials for `provider`; plugin code
44
+ * owns the request shape and response handling. `operation` names the
45
+ * provider action for grant selection and diagnostics.
46
+ */
47
+ fetch(input: {
48
+ operation: string;
49
+ provider: string;
50
+ request: Request;
51
+ }): Promise<Response>;
52
+ }
39
53
  export interface SandboxPrepareHookContext extends PluginContext {
40
54
  requester?: Requester;
41
55
  sandbox: PluginSandbox;
@@ -102,6 +116,7 @@ interface BaseToolRegistrationHookContext extends PluginContext {
102
116
  */
103
117
  conversationId?: string;
104
118
  embedder: PluginEmbedder;
119
+ egress: PluginEgress;
105
120
  model: PluginModel;
106
121
  state: PluginState;
107
122
  userText?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-plugin-api",
3
- "version": "0.81.0",
3
+ "version": "0.83.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -118,6 +118,14 @@ export class EgressAuthRequired extends Error {
118
118
  }
119
119
  }
120
120
 
121
+ /** Deny provider egress before Junior issues credentials for a disallowed operation. */
122
+ export class EgressPolicyDenied extends Error {
123
+ constructor(message: string, options?: { cause?: unknown }) {
124
+ super(message, { cause: options?.cause });
125
+ this.name = "EgressPolicyDenied";
126
+ }
127
+ }
128
+
121
129
  /** Provider account identity resolved by a plugin OAuth hook. */
122
130
  export type PluginProviderAccount = z.output<
123
131
  typeof pluginProviderAccountSchema
@@ -131,6 +139,8 @@ export interface PluginEgressRequest {
131
139
  /** Capped request body text when the host exposes it for provider-specific grant classification. */
132
140
  bodyText?: string;
133
141
  method: string;
142
+ /** Plugin-declared operation this request performs, used for grant classification and diagnostics. */
143
+ operation?: string;
134
144
  url: string;
135
145
  }
136
146
 
package/src/hooks.ts CHANGED
@@ -11,7 +11,7 @@ import type {
11
11
  HeartbeatHookContext,
12
12
  HeartbeatResult,
13
13
  OperationalReportHookContext,
14
- DashboardRouteRegistrationHookContext,
14
+ ApiRouteRegistrationHookContext,
15
15
  PluginOperationalReportContent,
16
16
  PluginRoute,
17
17
  PluginRouteApp,
@@ -57,9 +57,8 @@ export interface PluginHooks {
57
57
  | Promise<PluginOperationalReportContent | undefined>
58
58
  | PluginOperationalReportContent
59
59
  | undefined;
60
- dashboardRoutes?(
61
- ctx: DashboardRouteRegistrationHookContext,
62
- ): PluginRouteApp | undefined;
60
+ /** Return plugin-owned product API routes mounted under Junior's authenticated plugin namespace. */
61
+ apiRoutes?(ctx: ApiRouteRegistrationHookContext): PluginRouteApp | undefined;
63
62
  resolveOAuthAccount?(
64
63
  ctx: ResolveOAuthAccountHookContext,
65
64
  ):
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ export {
8
8
  type UserPromptContext,
9
9
  } from "./prompt";
10
10
  export * from "./dispatch";
11
+ export * from "./resource-events";
11
12
  export * from "./tasks";
12
13
  export * from "./tools";
13
14
  export * from "./operations";
package/src/operations.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import { z } from "zod";
1
2
  import type { PluginContext } from "./context";
2
3
  import type { Dispatch, DispatchOptions, DispatchResult } from "./dispatch";
4
+ import { nonBlankStringSchema } from "./schemas";
3
5
  import type { PluginReadState, PluginState } from "./state";
4
6
 
5
7
  export type PluginConversationStatus =
@@ -15,7 +17,14 @@ export interface PluginConversationSummary {
15
17
  displayTitle: string;
16
18
  lastActivityAt: string;
17
19
  lastUpdatedAt: string;
18
- source?: "api" | "internal" | "local" | "plugin" | "scheduler" | "slack";
20
+ source?:
21
+ | "api"
22
+ | "internal"
23
+ | "local"
24
+ | "plugin"
25
+ | "resource_event"
26
+ | "scheduler"
27
+ | "slack";
19
28
  status: PluginConversationStatus;
20
29
  }
21
30
 
@@ -113,13 +122,40 @@ export interface PluginRoute {
113
122
  path: string;
114
123
  }
115
124
 
125
+ /** Fetch-compatible plugin HTTP app mounted by Junior. */
116
126
  export type PluginRouteApp = {
117
- fetch(request: Request): Promise<Response> | Response;
127
+ fetch(
128
+ request: Request,
129
+ context?: PluginApiRouteRequestContext,
130
+ ): Promise<Response> | Response;
118
131
  };
119
132
 
120
133
  export interface RouteRegistrationHookContext extends PluginContext {}
121
134
 
122
- export interface DashboardRouteRegistrationHookContext extends PluginContext {}
135
+ export interface ApiRouteRegistrationHookContext extends PluginContext {}
136
+
137
+ /** Per-request context Junior passes to authenticated plugin product API routes. */
138
+ export const pluginApiRouteRequestContextSchema = z
139
+ .object({
140
+ auth: z
141
+ .object({
142
+ user: z
143
+ .object({
144
+ email: z.string().nullable().optional(),
145
+ emailVerified: z.boolean().optional(),
146
+ hostedDomain: z.string().nullable().optional(),
147
+ name: z.string().nullable().optional(),
148
+ })
149
+ .strict(),
150
+ })
151
+ .strict(),
152
+ pluginName: nonBlankStringSchema,
153
+ })
154
+ .strict();
155
+
156
+ export type PluginApiRouteRequestContext = z.output<
157
+ typeof pluginApiRouteRequestContextSchema
158
+ >;
123
159
 
124
160
  export interface SlackConversationLink {
125
161
  url: string;
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+
3
+ export const subscribableResourceSchema = z
4
+ .object({
5
+ label: z.string().min(1),
6
+ provider: z.string().min(1),
7
+ resourceRef: z.string().min(1),
8
+ suggestedEvents: z.array(z.string().min(1)).optional(),
9
+ supportedEvents: z.array(z.string().min(1)),
10
+ type: z.string().min(1),
11
+ })
12
+ .strict();
13
+
14
+ export type SubscribableResource = z.output<typeof subscribableResourceSchema>;
package/src/tools.ts CHANGED
@@ -49,6 +49,21 @@ export interface PluginSandbox {
49
49
  }): Promise<void>;
50
50
  }
51
51
 
52
+ export interface PluginEgress {
53
+ /**
54
+ * Fetch a provider URL with host-owned credentials.
55
+ *
56
+ * The runtime selects and injects credentials for `provider`; plugin code
57
+ * owns the request shape and response handling. `operation` names the
58
+ * provider action for grant selection and diagnostics.
59
+ */
60
+ fetch(input: {
61
+ operation: string;
62
+ provider: string;
63
+ request: Request;
64
+ }): Promise<Response>;
65
+ }
66
+
52
67
  export interface SandboxPrepareHookContext extends PluginContext {
53
68
  requester?: Requester;
54
69
  sandbox: PluginSandbox;
@@ -124,6 +139,7 @@ interface BaseToolRegistrationHookContext extends PluginContext {
124
139
  */
125
140
  conversationId?: string;
126
141
  embedder: PluginEmbedder;
142
+ egress: PluginEgress;
127
143
  model: PluginModel;
128
144
  state: PluginState;
129
145
  userText?: string;