corsair 0.1.76 → 0.1.78
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/dist/chunk-3X6WVI5I.js +1 -0
- package/dist/chunk-IGGCNGU2.js +1 -0
- package/dist/chunk-J6HIPZAR.js +26 -0
- package/dist/{chunk-UPIMTWVI.js → chunk-KLJBBN2T.js} +3 -3
- package/dist/core.d.ts +8 -18
- package/dist/core.js +1 -1
- package/dist/db.js +1 -1
- package/dist/hub.d.ts +140 -0
- package/dist/hub.js +1 -0
- package/dist/{index-DSVPkmM-.d.ts → index-BHyMcpwm.d.ts} +389 -492
- package/dist/index-aVkEGoHG.d.ts +53 -0
- package/dist/index-mZfhN-6e.d.ts +55 -0
- package/dist/index.d.ts +17 -6
- package/dist/index.js +3 -3
- package/dist/oauth.d.ts +6 -1
- package/dist/oauth.js +1 -1
- package/dist/orm.js +1 -1
- package/dist/setup.d.ts +5 -3
- package/dist/setup.js +1 -1
- package/dist/tenant-links-UNTSO7K7.d.ts +43 -0
- package/dist/{index-BnkJ_TYy.d.ts → tenant-match-utils-DXoUP9o9.d.ts} +42 -2
- package/dist/tunnel.d.ts +35 -0
- package/dist/tunnel.js +1 -0
- package/dist/types-B1We8TTP.d.ts +249 -0
- package/package.json +12 -2
- package/dist/chunk-3USHGH6P.js +0 -1
- package/dist/chunk-FL4GOHVN.js +0 -1
- package/dist/chunk-LIZVHWQK.js +0 -26
- package/dist/chunk-OZHME3EO.js +0 -1
- package/dist/chunk-UBM25HVI.js +0 -1
|
@@ -1,152 +1,7 @@
|
|
|
1
|
-
import { CorsairDatabase, CorsairPermission, CorsairDatabaseInput } from './db.js';
|
|
2
1
|
import { ZodTypeAny } from 'zod';
|
|
2
|
+
import { CorsairDatabase, CorsairPermission, CorsairDatabaseInput } from './db.js';
|
|
3
3
|
import { CorsairPluginSchema, PluginEntityClients } from './orm.js';
|
|
4
|
-
|
|
5
|
-
type AllErrors = 'RATE_LIMIT_ERROR' | 'AUTH_ERROR' | 'PERMISSION_ERROR' | 'NETWORK_ERROR' | 'TIMEOUT_ERROR' | 'SERVER_ERROR' | 'VALIDATION_ERROR' | 'NOT_FOUND_ERROR' | 'BAD_REQUEST_ERROR' | 'PARSING_ERROR' | 'DEFAULT' | (string & {});
|
|
6
|
-
declare const BaseProviders: readonly ["airtable", "amplitude", "asana", "bitwarden", "bluesky", "box", "cal", "calendly", "cloudflare", "cursor", "discord", "dodopayments", "dropbox", "exa", "figma", "firecrawl", "fireflies", "github", "gitlab", "gmail", "googlecalendar", "googledrive", "googlesheets", "grafana", "hackernews", "hubspot", "intercom", "jira", "linear", "monday", "notion", "onedrive", "openweathermap", "oura", "outlook", "pagerduty", "posthog", "razorpay", "reddit", "resend", "sentry", "sharepoint", "slack", "spotify", "strava", "stripe", "tally", "tavily", "teams", "telegram", "todoist", "trello", "twitter", "twitterapiio", "typeform", "vapi", "xquik", "youtube", "zendesk", "zohomail", "zoom"];
|
|
7
|
-
type AllProviders = 'airtable' | 'amplitude' | 'asana' | 'bitwarden' | 'bluesky' | 'box' | 'cal' | 'calendly' | 'cloudflare' | 'cursor' | 'discord' | 'dodopayments' | 'dropbox' | 'exa' | 'figma' | 'firecrawl' | 'fireflies' | 'github' | 'gitlab' | 'gmail' | 'googlecalendar' | 'googledrive' | 'googlesheets' | 'grafana' | 'hackernews' | 'hubspot' | 'intercom' | 'jira' | 'linear' | 'monday' | 'notion' | 'onedrive' | 'openweathermap' | 'oura' | 'outlook' | 'pagerduty' | 'posthog' | 'razorpay' | 'reddit' | 'resend' | 'sentry' | 'sharepoint' | 'slack' | 'spotify' | 'strava' | 'stripe' | 'tally' | 'tavily' | 'teams' | 'telegram' | 'todoist' | 'trello' | 'twitter' | 'twitterapiio' | 'typeform' | 'vapi' | 'xquik' | 'youtube' | 'zendesk' | 'zohomail' | 'zoom' | (string & {});
|
|
8
|
-
type AuthTypes = 'oauth_2' | 'api_key' | 'bot_token';
|
|
9
|
-
type PickAuth<T extends AuthTypes> = T;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Utility type that converts a union type to an intersection type.
|
|
13
|
-
* This is useful for combining multiple plugin interfaces into a single client interface.
|
|
14
|
-
* @template U - The union type to convert
|
|
15
|
-
*/
|
|
16
|
-
type UnionToIntersection$1<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
17
|
-
/**
|
|
18
|
-
* Bivariance hack for function types to ensure proper type inference.
|
|
19
|
-
* This helps TypeScript correctly infer function parameters and return types.
|
|
20
|
-
* @template Args - The function arguments array
|
|
21
|
-
* @template R - The function return type
|
|
22
|
-
*/
|
|
23
|
-
type Bivariant$2<Args extends unknown[], R> = {
|
|
24
|
-
bivarianceHack(...args: Args): R;
|
|
25
|
-
}['bivarianceHack'];
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Defines the default fields for each auth type at the integration and account levels.
|
|
29
|
-
* These are the base fields that every key manager of that auth type will have.
|
|
30
|
-
* Plugins can extend these with additional fields via `authConfig`.
|
|
31
|
-
*/
|
|
32
|
-
declare const BASE_AUTH_FIELDS: {
|
|
33
|
-
readonly oauth_2: {
|
|
34
|
-
readonly integration: readonly ["client_id", "client_secret", "redirect_url"];
|
|
35
|
-
readonly account: readonly ["access_token", "refresh_token", "expires_at", "scope", "webhook_signature"];
|
|
36
|
-
};
|
|
37
|
-
readonly api_key: {
|
|
38
|
-
readonly integration: readonly [];
|
|
39
|
-
readonly account: readonly ["api_key", "webhook_signature"];
|
|
40
|
-
};
|
|
41
|
-
readonly bot_token: {
|
|
42
|
-
readonly integration: readonly [];
|
|
43
|
-
readonly account: readonly ["bot_token", "webhook_signature"];
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* Type-level representation of the base auth field config.
|
|
48
|
-
*/
|
|
49
|
-
type BaseAuthFieldConfig = typeof BASE_AUTH_FIELDS;
|
|
50
|
-
/**
|
|
51
|
-
* Configuration that plugins can provide to extend the base auth fields.
|
|
52
|
-
* Each auth type can have additional integration-level and/or account-level fields.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```ts
|
|
56
|
-
* const gmailAuthConfig = {
|
|
57
|
-
* oauth_2: {
|
|
58
|
-
* integration: ["topic_id"] as const,
|
|
59
|
-
* account: ["history_id"] as const,
|
|
60
|
-
* },
|
|
61
|
-
* } as const satisfies PluginAuthConfig;
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
64
|
-
type PluginAuthConfig = {
|
|
65
|
-
[K in AuthTypes]?: {
|
|
66
|
-
integration?: readonly string[];
|
|
67
|
-
account?: readonly string[];
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
/**
|
|
71
|
-
* Extracts extra integration fields from a plugin auth config for a given auth type.
|
|
72
|
-
*/
|
|
73
|
-
type ExtraIntegrationFields<Config extends PluginAuthConfig | undefined, T extends AuthTypes> = Config extends PluginAuthConfig ? T extends keyof Config ? NonNullable<Config[T]> extends {
|
|
74
|
-
integration: infer F extends readonly string[];
|
|
75
|
-
} ? F[number] : never : never : never;
|
|
76
|
-
/**
|
|
77
|
-
* Extracts extra account fields from a plugin auth config for a given auth type.
|
|
78
|
-
*/
|
|
79
|
-
type ExtraAccountFields<Config extends PluginAuthConfig | undefined, T extends AuthTypes> = Config extends PluginAuthConfig ? T extends keyof Config ? NonNullable<Config[T]> extends {
|
|
80
|
-
account: infer F extends readonly string[];
|
|
81
|
-
} ? F[number] : never : never : never;
|
|
82
|
-
/**
|
|
83
|
-
* All integration field names for a given auth type (base + extension).
|
|
84
|
-
*/
|
|
85
|
-
type IntegrationFieldNames<T extends AuthTypes, Config extends PluginAuthConfig | undefined = undefined> = BaseAuthFieldConfig[T]['integration'][number] | ExtraIntegrationFields<Config, T>;
|
|
86
|
-
/**
|
|
87
|
-
* All account field names for a given auth type (base + extension).
|
|
88
|
-
*/
|
|
89
|
-
type AccountFieldNames<T extends AuthTypes, Config extends PluginAuthConfig | undefined = undefined> = BaseAuthFieldConfig[T]['account'][number] | ExtraAccountFields<Config, T>;
|
|
90
|
-
/**
|
|
91
|
-
* Generates getter and setter types for a single field.
|
|
92
|
-
* e.g., "client_id" → { get_client_id: () => Promise<string | null>, set_client_id: (value: string | null) => Promise<void> }
|
|
93
|
-
*/
|
|
94
|
-
type FieldAccessors<Field extends string> = {
|
|
95
|
-
[K in `get_${Field}`]: () => Promise<string | null>;
|
|
96
|
-
} & {
|
|
97
|
-
[K in `set_${Field}`]: (value: string | null) => Promise<void>;
|
|
98
|
-
};
|
|
99
|
-
/**
|
|
100
|
-
* Generates getters and setters for all fields in a union.
|
|
101
|
-
* Uses UnionToIntersection to merge individual field accessor types.
|
|
102
|
-
*/
|
|
103
|
-
type AllFieldAccessors<Fields extends string> = [Fields] extends [never] ? {} : UnionToIntersection$1<FieldAccessors<Fields>>;
|
|
104
|
-
/**
|
|
105
|
-
* Base key manager interface with DEK operations.
|
|
106
|
-
* All key managers (integration and account) include these.
|
|
107
|
-
*/
|
|
108
|
-
type BaseKeyManager = {
|
|
109
|
-
/**
|
|
110
|
-
* Get the current DEK (decrypted using KEK)
|
|
111
|
-
*/
|
|
112
|
-
get_dek: () => Promise<string>;
|
|
113
|
-
/**
|
|
114
|
-
* Issue a new DEK and re-encrypt all associated secrets
|
|
115
|
-
* @returns The new DEK (for reference, not typically needed)
|
|
116
|
-
*/
|
|
117
|
-
issue_new_dek: () => Promise<string>;
|
|
118
|
-
};
|
|
119
|
-
/**
|
|
120
|
-
* Integration credentials returned by get_integration_credentials (OAuth2 only).
|
|
121
|
-
*/
|
|
122
|
-
type OAuth2IntegrationCredentials = {
|
|
123
|
-
client_id: string | null;
|
|
124
|
-
client_secret: string | null;
|
|
125
|
-
redirect_url: string | null;
|
|
126
|
-
};
|
|
127
|
-
/**
|
|
128
|
-
* Integration-level key manager for a given auth type.
|
|
129
|
-
* Includes base DEK operations + auto-generated getters/setters for all fields.
|
|
130
|
-
*
|
|
131
|
-
* @template T - The auth type
|
|
132
|
-
* @template Config - Optional plugin auth config for extension fields
|
|
133
|
-
*/
|
|
134
|
-
type IntegrationKeyManagerFor<T extends AuthTypes, Config extends PluginAuthConfig | undefined = undefined> = BaseKeyManager & AllFieldAccessors<IntegrationFieldNames<T, Config>>;
|
|
135
|
-
/**
|
|
136
|
-
* Account-level key manager for a given auth type.
|
|
137
|
-
* Includes base DEK operations + auto-generated getters/setters for all fields.
|
|
138
|
-
* OAuth2 account managers also include `get_integration_credentials`.
|
|
139
|
-
*
|
|
140
|
-
* @template T - The auth type
|
|
141
|
-
* @template Config - Optional plugin auth config for extension fields
|
|
142
|
-
*/
|
|
143
|
-
type AccountKeyManagerFor<T extends AuthTypes, Config extends PluginAuthConfig | undefined = undefined> = BaseKeyManager & AllFieldAccessors<AccountFieldNames<T, Config>> & (T extends 'oauth_2' ? {
|
|
144
|
-
/**
|
|
145
|
-
* Get the integration-level OAuth2 credentials (client_id, client_secret, redirect_url).
|
|
146
|
-
* Useful for token refresh flows that need access to both account and integration secrets.
|
|
147
|
-
*/
|
|
148
|
-
get_integration_credentials: () => Promise<OAuth2IntegrationCredentials>;
|
|
149
|
-
} : {});
|
|
4
|
+
import { q as AllErrors, A as AuthTypes, a as AccountKeyManagerFor, P as PluginAuthConfig, I as IntegrationKeyManagerFor, f as AllProviders, H as HubConfig, n as HubConfigInput } from './types-B1We8TTP.js';
|
|
150
5
|
|
|
151
6
|
/**
|
|
152
7
|
* Bivariance hack for function types to ensure proper type inference.
|
|
@@ -307,6 +162,29 @@ type ManagementOk = {
|
|
|
307
162
|
ok: true;
|
|
308
163
|
};
|
|
309
164
|
type PermissionRecord = CorsairPermission;
|
|
165
|
+
type CreateConnectLinkInput = {
|
|
166
|
+
plugin: string;
|
|
167
|
+
tenantId?: string;
|
|
168
|
+
};
|
|
169
|
+
type ConnectLink = {
|
|
170
|
+
connectUrl: string;
|
|
171
|
+
state: string;
|
|
172
|
+
};
|
|
173
|
+
type ResolvedConnectLink = {
|
|
174
|
+
plugin: string;
|
|
175
|
+
tenantId: string;
|
|
176
|
+
providerName: string;
|
|
177
|
+
oauthUrl: string;
|
|
178
|
+
state: string;
|
|
179
|
+
};
|
|
180
|
+
type OAuthCallbackInput = {
|
|
181
|
+
code: string;
|
|
182
|
+
state: string;
|
|
183
|
+
};
|
|
184
|
+
type OAuthCallbackResult = {
|
|
185
|
+
plugin: string;
|
|
186
|
+
tenantId: string;
|
|
187
|
+
};
|
|
310
188
|
|
|
311
189
|
type CorsairManageNamespace = {
|
|
312
190
|
ok: () => ManagementOk;
|
|
@@ -328,168 +206,215 @@ type CorsairManageNamespace = {
|
|
|
328
206
|
get: (id: string) => Promise<PermissionRecord>;
|
|
329
207
|
getByToken: (token: string) => Promise<PermissionRecord>;
|
|
330
208
|
};
|
|
209
|
+
connect: {
|
|
210
|
+
createLink: (input: CreateConnectLinkInput) => Promise<ConnectLink>;
|
|
211
|
+
resolve: (state: string) => Promise<ResolvedConnectLink>;
|
|
212
|
+
oauthCallback: (input: OAuthCallbackInput) => Promise<OAuthCallbackResult>;
|
|
213
|
+
};
|
|
331
214
|
};
|
|
332
215
|
|
|
333
216
|
/**
|
|
334
|
-
*
|
|
335
|
-
*
|
|
217
|
+
* The `corsair.permissions` namespace available at the root of every corsair instance.
|
|
218
|
+
* Provides methods for querying and transitioning permission records.
|
|
219
|
+
*
|
|
220
|
+
* Status transitions exposed here are intentionally limited to safe, non-escalating states.
|
|
221
|
+
* Setting a record to 'approved' (which grants execution) is deliberately excluded —
|
|
222
|
+
* that must happen through the out-of-band review flow.
|
|
336
223
|
*/
|
|
337
|
-
type
|
|
338
|
-
/**
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
224
|
+
type CorsairPermissionsNamespace = {
|
|
225
|
+
/**
|
|
226
|
+
* Fetches a single permission record by its ID.
|
|
227
|
+
* Returns undefined if no record exists or if no database is configured.
|
|
228
|
+
*/
|
|
229
|
+
find_by_permission_id(id: string): Promise<CorsairPermission | undefined>;
|
|
230
|
+
/**
|
|
231
|
+
* Fetches a single permission record by its token.
|
|
232
|
+
* The token is the public-facing handle embedded in review URLs.
|
|
233
|
+
* Returns undefined if no record exists or if no database is configured.
|
|
234
|
+
*/
|
|
235
|
+
find_by_token(token: string): Promise<CorsairPermission | undefined>;
|
|
236
|
+
/**
|
|
237
|
+
* Marks the permission as 'executing'. Call this when executePermission picks up
|
|
238
|
+
* an approved record and is about to run the endpoint.
|
|
239
|
+
*/
|
|
240
|
+
set_executing(id: string): Promise<void>;
|
|
241
|
+
/**
|
|
242
|
+
* Marks the permission as 'completed'. Call this after the endpoint has finished
|
|
243
|
+
* executing successfully.
|
|
244
|
+
*/
|
|
245
|
+
set_completed(id: string): Promise<void>;
|
|
342
246
|
};
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
247
|
+
type EnforcePermissionOptions = {
|
|
248
|
+
pluginId: string;
|
|
249
|
+
endpointPath: string;
|
|
250
|
+
/** unknown: caller-supplied args vary per endpoint — not statically knowable here */
|
|
251
|
+
args: unknown;
|
|
252
|
+
mode: PermissionMode;
|
|
253
|
+
override?: PermissionPolicy;
|
|
254
|
+
riskLevel: EndpointRiskLevel;
|
|
255
|
+
meta?: EndpointMetaEntry;
|
|
256
|
+
/** Required to create an approval record. Without a DB, 'require_approval' falls back to deny. */
|
|
257
|
+
db?: CorsairDatabase;
|
|
258
|
+
timeoutMs?: number;
|
|
259
|
+
/** Tenant ID for multi-tenant instances. Stored on the record so executePermission can scope correctly. Defaults to 'default'. */
|
|
260
|
+
tenantId?: string;
|
|
261
|
+
/**
|
|
262
|
+
* Controls whether the call blocks until the user approves or denies.
|
|
263
|
+
* - `'synchronous'` → polls the DB every 500 ms; returns 'allow' on approval, 'blocked' on denial/timeout.
|
|
264
|
+
* - `'asynchronous'` → returns 'blocked' immediately after creating the pending record.
|
|
265
|
+
* - A no-arg function → called per-request, return value selects the mode dynamically.
|
|
266
|
+
* Defaults to `'asynchronous'`.
|
|
267
|
+
*/
|
|
268
|
+
approvalMode?: 'synchronous' | 'asynchronous' | (() => 'synchronous' | 'asynchronous');
|
|
269
|
+
};
|
|
270
|
+
type EnforcePermissionResult = {
|
|
271
|
+
result: 'allow' | 'blocked';
|
|
272
|
+
/** Why the call was blocked. Only present when result === 'blocked'. */
|
|
273
|
+
reason?: 'denied' | 'policy' | 'timeout' | 'pending';
|
|
274
|
+
/** Permission record ID. Present when a pending approval record exists. */
|
|
275
|
+
id?: string;
|
|
276
|
+
/** Permission token (the value embedded in review URLs). Present when a pending approval record exists. */
|
|
277
|
+
token?: string;
|
|
278
|
+
/** ISO8601 expiry for pending approval records. Present when token is present. */
|
|
279
|
+
expiresAt?: string;
|
|
280
|
+
/**
|
|
281
|
+
* Called by the endpoint binding layer after the endpoint executes successfully.
|
|
282
|
+
* Marks the permission record as 'completed' (single-use approval consumed).
|
|
283
|
+
* Only present when an 'approved' record was found and the call is allowed through.
|
|
284
|
+
*/
|
|
285
|
+
onComplete?: () => Promise<void>;
|
|
355
286
|
};
|
|
287
|
+
|
|
356
288
|
/**
|
|
357
|
-
*
|
|
358
|
-
*
|
|
289
|
+
* Extracts typed entity clients from a plugin schema.
|
|
290
|
+
* Each entity type becomes a `PluginEntityClient<DataSchema>`.
|
|
291
|
+
* Entities are nested under `db` to separate them from API endpoints.
|
|
359
292
|
*/
|
|
360
|
-
type
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
/** The entity relevant to the webhook (note that this is corsair_entities.id) */
|
|
364
|
-
corsairEntityId?: string;
|
|
365
|
-
/** Return this object to the sender. Defaults to empty. Usually only necessary for webhook confirmation / challenge. */
|
|
366
|
-
returnToSender?: Record<string, string>;
|
|
367
|
-
/** Optional data to return in the HTTP response */
|
|
368
|
-
data?: TData;
|
|
369
|
-
/** Optional error message if processing failed */
|
|
370
|
-
error?: string;
|
|
371
|
-
/** HTTP status code to return (defaults to 200 on success, 500 on error) */
|
|
372
|
-
statusCode?: number;
|
|
373
|
-
/** HTTP response headers to set on the outgoing response. Used for header-based handshakes (e.g. Asana X-Hook-Secret). */
|
|
374
|
-
responseHeaders?: Record<string, string>;
|
|
375
|
-
};
|
|
293
|
+
type InferPluginEntities<Schema extends CorsairPluginSchema<Record<string, ZodTypeAny>> | undefined> = Schema extends CorsairPluginSchema<infer Entities> ? {
|
|
294
|
+
db: PluginEntityClients<Entities>;
|
|
295
|
+
} : {};
|
|
376
296
|
/**
|
|
377
|
-
*
|
|
378
|
-
* request should be handled by this webhook.
|
|
379
|
-
* @param request - The raw webhook request data
|
|
380
|
-
* @returns True if this webhook should handle the request
|
|
297
|
+
* Utility type that converts a union to an intersection type.
|
|
381
298
|
*/
|
|
382
|
-
type
|
|
299
|
+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
383
300
|
/**
|
|
384
|
-
*
|
|
385
|
-
* @template
|
|
386
|
-
* @template
|
|
301
|
+
* Extracts the authType from plugin options.
|
|
302
|
+
* @template Options - The plugin options type
|
|
303
|
+
* @template DefaultAuthType - Optional default auth type to use when authType is optional or not present
|
|
304
|
+
*
|
|
305
|
+
* Priority:
|
|
306
|
+
* 1. If authType is a specific single AuthType (not a union), use that
|
|
307
|
+
* 2. If DefaultAuthType parameter is provided, use that as the fallback
|
|
308
|
+
* 3. Otherwise use the non-nullable union from authType
|
|
309
|
+
* 4. If authType is not in Options at all, fall back to DefaultAuthType
|
|
387
310
|
*/
|
|
388
|
-
type
|
|
389
|
-
bivarianceHack(...args: Args): R;
|
|
390
|
-
}['bivarianceHack'];
|
|
311
|
+
type ExtractAuthType<Options, DefaultAuthType extends AuthTypes | undefined = undefined> = 'authType' extends keyof Options ? Options['authType'] extends AuthTypes ? Options['authType'] : DefaultAuthType extends AuthTypes ? DefaultAuthType : NonNullable<Options['authType']> extends AuthTypes ? NonNullable<Options['authType']> : never : DefaultAuthType extends AuthTypes ? DefaultAuthType : never;
|
|
391
312
|
/**
|
|
392
|
-
*
|
|
393
|
-
* Takes context + webhook request, returns a webhook response.
|
|
394
|
-
* @template Ctx - The context type passed to the handler
|
|
395
|
-
* @template TPayload - The type of the webhook payload
|
|
396
|
-
* @template TResponseData - The type of data returned in the response
|
|
313
|
+
* Extracts Options type from plugin's options property.
|
|
397
314
|
*/
|
|
398
|
-
type
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
], Promise<WebhookResponse<TResponseData>>>;
|
|
315
|
+
type InferPluginOptions<P> = P extends {
|
|
316
|
+
options?: infer O;
|
|
317
|
+
} ? O : never;
|
|
402
318
|
/**
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
* @template Ctx - The context type passed to the handler
|
|
407
|
-
* @template TPayload - The type of the webhook payload
|
|
408
|
-
* @template TResponseData - The type of data returned in the response
|
|
319
|
+
* Extracts DefaultAuthType from plugin's __defaultAuthType property.
|
|
320
|
+
* Uses NonNullable<D> because the __defaultAuthType property is optional,
|
|
321
|
+
* which causes TypeScript to infer D as `AuthType | undefined`.
|
|
409
322
|
*/
|
|
410
|
-
type
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
/** Handles the webhook request after matching */
|
|
414
|
-
handler: CorsairWebhookHandler<Ctx, TPayload, TResponseData>;
|
|
415
|
-
};
|
|
323
|
+
type InferDefaultAuthType<P> = P extends {
|
|
324
|
+
__defaultAuthType?: infer D;
|
|
325
|
+
} ? NonNullable<D> extends AuthTypes ? NonNullable<D> : undefined : undefined;
|
|
416
326
|
/**
|
|
417
|
-
*
|
|
418
|
-
* Similar to EndpointTree but for webhook handlers.
|
|
419
|
-
*
|
|
420
|
-
* @example
|
|
421
|
-
* ```ts
|
|
422
|
-
* // Flat structure
|
|
423
|
-
* webhooks: {
|
|
424
|
-
* issueCreated: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
425
|
-
* issueClosed: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
426
|
-
* }
|
|
427
|
-
*
|
|
428
|
-
* // Nested structure
|
|
429
|
-
* webhooks: {
|
|
430
|
-
* issues: {
|
|
431
|
-
* created: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
432
|
-
* updated: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
433
|
-
* },
|
|
434
|
-
* pull_requests: {
|
|
435
|
-
* opened: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
436
|
-
* },
|
|
437
|
-
* }
|
|
438
|
-
* ```
|
|
327
|
+
* Extracts the AuthConfig from a plugin's authConfig property.
|
|
439
328
|
*/
|
|
440
|
-
type
|
|
441
|
-
|
|
442
|
-
};
|
|
329
|
+
type InferAuthConfig<P> = P extends {
|
|
330
|
+
authConfig?: infer C;
|
|
331
|
+
} ? C extends PluginAuthConfig ? C : undefined : undefined;
|
|
443
332
|
/**
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
* @template TPayload - The type of the webhook payload
|
|
447
|
-
* @template TResponseData - The type of data returned in the response
|
|
333
|
+
* Infers the complete namespace for a single plugin, including API endpoints,
|
|
334
|
+
* database entities, webhooks, and account-level keys.
|
|
448
335
|
*/
|
|
449
|
-
type
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
336
|
+
type InferPluginNamespace<P extends CorsairPlugin> = P extends CorsairPlugin<infer Id, infer Schema, infer Endpoints, infer Webhooks> ? {
|
|
337
|
+
[K in Id]: (Endpoints extends EndpointTree ? {
|
|
338
|
+
api: BindEndpoints<Endpoints>;
|
|
339
|
+
} : {}) & InferPluginEntities<Schema> & (Webhooks extends WebhookTree ? {
|
|
340
|
+
webhooks: BindWebhooks<Webhooks>;
|
|
341
|
+
/**
|
|
342
|
+
* Synchronously checks if an incoming webhook request is intended for this plugin.
|
|
343
|
+
* Only present if the plugin defines a `pluginWebhookMatcher`.
|
|
344
|
+
* Use this as a first-level filter before checking individual webhook matchers.
|
|
345
|
+
*/
|
|
346
|
+
pluginWebhookMatcher?: (request: RawWebhookRequest) => boolean;
|
|
347
|
+
/**
|
|
348
|
+
* Extracts the external tenant lookup key for this plugin's webhook.
|
|
349
|
+
* Only present if the plugin defines `pluginTenantWebhookMatcher`.
|
|
350
|
+
*/
|
|
351
|
+
pluginTenantWebhookMatcher?: CorsairWebhookTenantMatcher;
|
|
352
|
+
} : {}) & (ExtractAuthType<InferPluginOptions<P>, InferDefaultAuthType<P>> extends AuthTypes ? {
|
|
353
|
+
keys: AccountKeyManagerFor<ExtractAuthType<InferPluginOptions<P>, InferDefaultAuthType<P>>, InferAuthConfig<P>>;
|
|
354
|
+
} : {});
|
|
355
|
+
} : never;
|
|
455
356
|
/**
|
|
456
|
-
*
|
|
457
|
-
* This is what the end user interacts with after client initialization.
|
|
357
|
+
* Infers the integration-level key manager for a single plugin.
|
|
458
358
|
*/
|
|
459
|
-
type
|
|
460
|
-
[
|
|
461
|
-
};
|
|
359
|
+
type InferIntegrationKeys<P extends CorsairPlugin> = P extends CorsairPlugin<infer Id> ? ExtractAuthType<InferPluginOptions<P>, InferDefaultAuthType<P>> extends AuthTypes ? {
|
|
360
|
+
[K in Id]: IntegrationKeyManagerFor<ExtractAuthType<InferPluginOptions<P>, InferDefaultAuthType<P>>, InferAuthConfig<P>>;
|
|
361
|
+
} : never : never;
|
|
462
362
|
/**
|
|
463
|
-
*
|
|
464
|
-
* Handles both flat and nested webhook structures.
|
|
465
|
-
* @template T - The webhook tree to bind
|
|
363
|
+
* Combines all integration-level keys into a single interface.
|
|
466
364
|
*/
|
|
467
|
-
type
|
|
468
|
-
|
|
365
|
+
type InferAllIntegrationKeys<Plugins extends readonly CorsairPlugin[]> = UnionToIntersection<InferIntegrationKeys<Plugins[number]>>;
|
|
366
|
+
/**
|
|
367
|
+
* Combines all plugin namespaces into a single client interface.
|
|
368
|
+
*/
|
|
369
|
+
type InferPluginNamespaces<Plugins extends readonly CorsairPlugin[]> = UnionToIntersection<InferPluginNamespace<Plugins[number]>>;
|
|
370
|
+
/**
|
|
371
|
+
* The main Corsair client type that provides access to all plugin APIs, entities, webhooks, and keys.
|
|
372
|
+
*/
|
|
373
|
+
type CorsairClient<Plugins extends readonly CorsairPlugin[]> = InferPluginNamespaces<Plugins>;
|
|
374
|
+
/**
|
|
375
|
+
* Multi-tenant wrapper that provides a `withTenant` method to scope operations to a specific tenant.
|
|
376
|
+
* Also includes integration-level `keys` for managing shared secrets (OAuth2 client credentials, etc.)
|
|
377
|
+
*/
|
|
378
|
+
type CorsairTenantWrapper<Plugins extends readonly CorsairPlugin[]> = {
|
|
379
|
+
withTenant: (tenantId: string) => CorsairClient<Plugins>;
|
|
380
|
+
/**
|
|
381
|
+
* Integration-level key managers for each plugin.
|
|
382
|
+
* Used to manage secrets shared across all tenants (e.g., OAuth2 client_id, client_secret).
|
|
383
|
+
*/
|
|
384
|
+
keys: InferAllIntegrationKeys<Plugins>;
|
|
385
|
+
/**
|
|
386
|
+
* Permission management namespace. Use this to query and transition permission records.
|
|
387
|
+
* Available at the root regardless of multi-tenancy setting.
|
|
388
|
+
*/
|
|
389
|
+
permissions: CorsairPermissionsNamespace;
|
|
390
|
+
/**
|
|
391
|
+
* Management control plane namespace — in-process equivalent of the HTTP
|
|
392
|
+
* `managementHandler`. Lists tenants, plugins, connection status, and
|
|
393
|
+
* permission records without going through HTTP.
|
|
394
|
+
*/
|
|
395
|
+
manage: CorsairManageNamespace;
|
|
469
396
|
};
|
|
470
397
|
/**
|
|
471
|
-
*
|
|
472
|
-
* Used to provide compile-time validation for webhook schema registry keys.
|
|
473
|
-
* Passing an invalid path to any config that accepts WebhookPathsOf<T> is a type error.
|
|
474
|
-
*
|
|
475
|
-
* Design note: Same recursive constraint relaxation as EndpointPathsOf — see that type
|
|
476
|
-
* for a full explanation of why we use `extends object` rather than `extends WebhookTree`
|
|
477
|
-
* on the recursive call. We also check `{ match: any; handler: any }` before `object`
|
|
478
|
-
* because webhook leaves are objects themselves.
|
|
479
|
-
*
|
|
480
|
-
* @example
|
|
481
|
-
* Given: `{ messages: { message: { match: fn, handler: fn } }, channels: { created: { match: fn, handler: fn } } }`
|
|
482
|
-
* Result: `'messages.message' | 'channels.created'`
|
|
483
|
-
*
|
|
484
|
-
* @template T - The webhook tree to extract paths from (unconstrained to allow recursion through as-const types)
|
|
485
|
-
* @template Prefix - Internal accumulator for the current path prefix (do not supply manually)
|
|
398
|
+
* Single-tenant client that includes both plugin APIs and integration-level keys.
|
|
486
399
|
*/
|
|
487
|
-
type
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
400
|
+
type CorsairSingleTenantClient<Plugins extends readonly CorsairPlugin[]> = CorsairClient<Plugins> & {
|
|
401
|
+
/**
|
|
402
|
+
* Integration-level key managers for each plugin.
|
|
403
|
+
* Used to manage secrets shared across all tenants (e.g., OAuth2 client_id, client_secret).
|
|
404
|
+
*/
|
|
405
|
+
keys: InferAllIntegrationKeys<Plugins>;
|
|
406
|
+
/**
|
|
407
|
+
* Permission management namespace. Use this to query and transition permission records.
|
|
408
|
+
* Available at the root regardless of multi-tenancy setting.
|
|
409
|
+
*/
|
|
410
|
+
permissions: CorsairPermissionsNamespace;
|
|
411
|
+
/**
|
|
412
|
+
* Management control plane namespace — in-process equivalent of the HTTP
|
|
413
|
+
* `managementHandler`. Lists tenants, plugins, connection status, and
|
|
414
|
+
* permission records without going through HTTP.
|
|
415
|
+
*/
|
|
416
|
+
manage: CorsairManageNamespace;
|
|
417
|
+
};
|
|
493
418
|
|
|
494
419
|
/**
|
|
495
420
|
* Risk level classification for plugin endpoints.
|
|
@@ -725,6 +650,8 @@ type ExtractAllAuthTypes<Options> = 'authType' extends keyof Options ? NonNullab
|
|
|
725
650
|
* return await ctx.keys.get_access_token();
|
|
726
651
|
* } else if (ctx.authType === 'bot_token') {
|
|
727
652
|
* return await ctx.keys.get_bot_token();
|
|
653
|
+
* } else if (ctx.authType === 'managed') {
|
|
654
|
+
* return await ctx.keys.get_access_token();
|
|
728
655
|
* }
|
|
729
656
|
* return '';
|
|
730
657
|
* }
|
|
@@ -737,6 +664,10 @@ type KeyBuilderContext<Options extends Record<string, unknown>, AuthConfig exten
|
|
|
737
664
|
options: Options;
|
|
738
665
|
/** Account-level key manager - type narrows based on authType check */
|
|
739
666
|
keys: AccountKeyManagerFor<A, AuthConfig>;
|
|
667
|
+
/** Tenant ID for this request (always set; defaults to 'default' in single-tenant) */
|
|
668
|
+
tenantId: string;
|
|
669
|
+
/** Hub config when createCorsair({ hub: ... }) is configured */
|
|
670
|
+
hub?: HubConfig;
|
|
740
671
|
} : never : never;
|
|
741
672
|
/**
|
|
742
673
|
* Type for the keyBuilder callback function that retrieves the authentication key.
|
|
@@ -780,6 +711,17 @@ type CorsairPlugin<Id extends AllProviders = AllProviders, Schema extends Corsai
|
|
|
780
711
|
* should handle an incoming request. Acts as a first-level filter.
|
|
781
712
|
*/
|
|
782
713
|
pluginWebhookMatcher?: CorsairWebhookMatcher;
|
|
714
|
+
/**
|
|
715
|
+
* Extracts the external identifier used to resolve a tenant for this webhook
|
|
716
|
+
* (for example Slack `team_id`, GitHub `installation.id`). Return null when
|
|
717
|
+
* the request cannot be mapped to a tenant.
|
|
718
|
+
*/
|
|
719
|
+
pluginTenantWebhookMatcher?: CorsairWebhookTenantMatcher;
|
|
720
|
+
/**
|
|
721
|
+
* Resolves the external id to store on the account after OAuth so incoming
|
|
722
|
+
* webhooks can be routed to the correct tenant. Return null when unavailable.
|
|
723
|
+
*/
|
|
724
|
+
oauthWebhookTenantLinkResolver?: CorsairOAuthWebhookTenantLinkResolver;
|
|
783
725
|
/** Plugin-specific error handlers */
|
|
784
726
|
errorHandlers?: CorsairErrorHandler;
|
|
785
727
|
/**
|
|
@@ -1005,251 +947,206 @@ type CorsairIntegration<Plugins extends readonly CorsairPlugin[]> = {
|
|
|
1005
947
|
state: string;
|
|
1006
948
|
}) => string;
|
|
1007
949
|
};
|
|
950
|
+
/** Corsair Hub configuration for hosted OAuth connect flows. */
|
|
951
|
+
hub?: HubConfigInput;
|
|
1008
952
|
};
|
|
1009
953
|
|
|
954
|
+
type TokenResponse = {
|
|
955
|
+
access_token?: string;
|
|
956
|
+
refresh_token?: string;
|
|
957
|
+
expires_in?: number;
|
|
958
|
+
token_type?: string;
|
|
959
|
+
[key: string]: unknown;
|
|
960
|
+
};
|
|
1010
961
|
/**
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
1014
|
-
* Status transitions exposed here are intentionally limited to safe, non-escalating states.
|
|
1015
|
-
* Setting a record to 'approved' (which grants execution) is deliberately excluded —
|
|
1016
|
-
* that must happen through the out-of-band review flow.
|
|
962
|
+
* Exchanges an OAuth authorization code for access/refresh tokens.
|
|
963
|
+
* Supports both 'body' (default) and 'basic' token auth methods.
|
|
1017
964
|
*/
|
|
1018
|
-
|
|
1019
|
-
/**
|
|
1020
|
-
* Fetches a single permission record by its ID.
|
|
1021
|
-
* Returns undefined if no record exists or if no database is configured.
|
|
1022
|
-
*/
|
|
1023
|
-
find_by_permission_id(id: string): Promise<CorsairPermission | undefined>;
|
|
1024
|
-
/**
|
|
1025
|
-
* Fetches a single permission record by its token.
|
|
1026
|
-
* The token is the public-facing handle embedded in review URLs.
|
|
1027
|
-
* Returns undefined if no record exists or if no database is configured.
|
|
1028
|
-
*/
|
|
1029
|
-
find_by_token(token: string): Promise<CorsairPermission | undefined>;
|
|
1030
|
-
/**
|
|
1031
|
-
* Marks the permission as 'executing'. Call this when executePermission picks up
|
|
1032
|
-
* an approved record and is about to run the endpoint.
|
|
1033
|
-
*/
|
|
1034
|
-
set_executing(id: string): Promise<void>;
|
|
1035
|
-
/**
|
|
1036
|
-
* Marks the permission as 'completed'. Call this after the endpoint has finished
|
|
1037
|
-
* executing successfully.
|
|
1038
|
-
*/
|
|
1039
|
-
set_completed(id: string): Promise<void>;
|
|
1040
|
-
};
|
|
1041
|
-
type EnforcePermissionOptions = {
|
|
1042
|
-
pluginId: string;
|
|
1043
|
-
endpointPath: string;
|
|
1044
|
-
/** unknown: caller-supplied args vary per endpoint — not statically knowable here */
|
|
1045
|
-
args: unknown;
|
|
1046
|
-
mode: PermissionMode;
|
|
1047
|
-
override?: PermissionPolicy;
|
|
1048
|
-
riskLevel: EndpointRiskLevel;
|
|
1049
|
-
meta?: EndpointMetaEntry;
|
|
1050
|
-
/** Required to create an approval record. Without a DB, 'require_approval' falls back to deny. */
|
|
1051
|
-
db?: CorsairDatabase;
|
|
1052
|
-
timeoutMs?: number;
|
|
1053
|
-
/** Tenant ID for multi-tenant instances. Stored on the record so executePermission can scope correctly. Defaults to 'default'. */
|
|
1054
|
-
tenantId?: string;
|
|
1055
|
-
/**
|
|
1056
|
-
* Controls whether the call blocks until the user approves or denies.
|
|
1057
|
-
* - `'synchronous'` → polls the DB every 500 ms; returns 'allow' on approval, 'blocked' on denial/timeout.
|
|
1058
|
-
* - `'asynchronous'` → returns 'blocked' immediately after creating the pending record.
|
|
1059
|
-
* - A no-arg function → called per-request, return value selects the mode dynamically.
|
|
1060
|
-
* Defaults to `'asynchronous'`.
|
|
1061
|
-
*/
|
|
1062
|
-
approvalMode?: 'synchronous' | 'asynchronous' | (() => 'synchronous' | 'asynchronous');
|
|
1063
|
-
};
|
|
1064
|
-
type EnforcePermissionResult = {
|
|
1065
|
-
result: 'allow' | 'blocked';
|
|
1066
|
-
/** Why the call was blocked. Only present when result === 'blocked'. */
|
|
1067
|
-
reason?: 'denied' | 'policy' | 'timeout' | 'pending';
|
|
1068
|
-
/** Permission record ID. Present when a pending approval record exists. */
|
|
1069
|
-
id?: string;
|
|
1070
|
-
/** Permission token (the value embedded in review URLs). Present when a pending approval record exists. */
|
|
1071
|
-
token?: string;
|
|
1072
|
-
/**
|
|
1073
|
-
* Called by the endpoint binding layer after the endpoint executes successfully.
|
|
1074
|
-
* Marks the permission record as 'completed' (single-use approval consumed).
|
|
1075
|
-
* Only present when an 'approved' record was found and the call is allowed through.
|
|
1076
|
-
*/
|
|
1077
|
-
onComplete?: () => Promise<void>;
|
|
1078
|
-
};
|
|
965
|
+
declare function exchangeCodeForTokens(code: string, clientId: string, clientSecret: string, oauthConfig: OAuthConfig, redirectUri: string): Promise<TokenResponse>;
|
|
1079
966
|
|
|
1080
967
|
/**
|
|
1081
|
-
*
|
|
1082
|
-
*
|
|
1083
|
-
* Entities are nested under `db` to separate them from API endpoints.
|
|
968
|
+
* Raw incoming webhook data for matching (before full parsing).
|
|
969
|
+
* Used by matcher functions to determine if a webhook should be handled.
|
|
1084
970
|
*/
|
|
1085
|
-
type
|
|
1086
|
-
|
|
1087
|
-
|
|
971
|
+
type RawWebhookRequest = {
|
|
972
|
+
/** HTTP headers from the webhook request */
|
|
973
|
+
headers: Record<string, string | string[] | undefined>;
|
|
974
|
+
/** Raw request body (string or already parsed object) */
|
|
975
|
+
body: unknown;
|
|
976
|
+
/** Query string parameters when available (e.g. Microsoft Graph validationToken). */
|
|
977
|
+
query?: Record<string, string | string[] | undefined>;
|
|
978
|
+
};
|
|
1088
979
|
/**
|
|
1089
|
-
*
|
|
980
|
+
* Raw incoming webhook request data after initial processing.
|
|
981
|
+
* Contains the parsed payload, headers, and optional raw body string.
|
|
982
|
+
* @template TPayload - The type of the parsed webhook payload
|
|
1090
983
|
*/
|
|
1091
|
-
type
|
|
984
|
+
type WebhookRequest<TPayload = unknown> = {
|
|
985
|
+
/** Parsed payload from the webhook request body */
|
|
986
|
+
payload: TPayload;
|
|
987
|
+
/** HTTP headers from the webhook request */
|
|
988
|
+
headers: Record<string, string | string[] | undefined>;
|
|
989
|
+
/** Raw request body string (for signature verification) */
|
|
990
|
+
rawBody?: string;
|
|
991
|
+
/** Query string parameters when available. */
|
|
992
|
+
query?: Record<string, string | string[] | undefined>;
|
|
993
|
+
};
|
|
1092
994
|
/**
|
|
1093
|
-
*
|
|
1094
|
-
* @template
|
|
1095
|
-
* @template DefaultAuthType - Optional default auth type to use when authType is optional or not present
|
|
1096
|
-
*
|
|
1097
|
-
* Priority:
|
|
1098
|
-
* 1. If authType is a specific single AuthType (not a union), use that
|
|
1099
|
-
* 2. If DefaultAuthType parameter is provided, use that as the fallback
|
|
1100
|
-
* 3. Otherwise use the non-nullable union from authType
|
|
1101
|
-
* 4. If authType is not in Options at all, fall back to DefaultAuthType
|
|
995
|
+
* Response from a webhook handler that can include acknowledgment data.
|
|
996
|
+
* @template TData - The type of data to return in the response
|
|
1102
997
|
*/
|
|
1103
|
-
type
|
|
998
|
+
type WebhookResponse<TData = unknown> = {
|
|
999
|
+
/** Whether the webhook was processed successfully */
|
|
1000
|
+
success: boolean;
|
|
1001
|
+
/** The entity relevant to the webhook (note that this is corsair_entities.id) */
|
|
1002
|
+
corsairEntityId?: string;
|
|
1003
|
+
/** Return this object to the sender. Defaults to empty. Usually only necessary for webhook confirmation / challenge. */
|
|
1004
|
+
returnToSender?: Record<string, string>;
|
|
1005
|
+
/** Optional data to return in the HTTP response */
|
|
1006
|
+
data?: TData;
|
|
1007
|
+
/** Optional error message if processing failed */
|
|
1008
|
+
error?: string;
|
|
1009
|
+
/** HTTP status code to return (defaults to 200 on success, 500 on error) */
|
|
1010
|
+
statusCode?: number;
|
|
1011
|
+
/** HTTP response headers to set on the outgoing response. Used for header-based handshakes (e.g. Asana X-Hook-Secret). */
|
|
1012
|
+
responseHeaders?: Record<string, string>;
|
|
1013
|
+
};
|
|
1104
1014
|
/**
|
|
1105
|
-
*
|
|
1015
|
+
* A webhook matcher function that synchronously determines if a raw webhook
|
|
1016
|
+
* request should be handled by this webhook.
|
|
1017
|
+
* @param request - The raw webhook request data
|
|
1018
|
+
* @returns True if this webhook should handle the request
|
|
1106
1019
|
*/
|
|
1107
|
-
type
|
|
1108
|
-
options?: infer O;
|
|
1109
|
-
} ? O : never;
|
|
1020
|
+
type CorsairWebhookMatcher = (request: RawWebhookRequest) => boolean;
|
|
1110
1021
|
/**
|
|
1111
|
-
*
|
|
1112
|
-
*
|
|
1113
|
-
*
|
|
1022
|
+
* Identifies which external credential key should be used to resolve a tenant
|
|
1023
|
+
* for an incoming webhook. The `linkType` names the field stored on
|
|
1024
|
+
* `corsair_accounts` (for example `team_id`, `installation_id`).
|
|
1114
1025
|
*/
|
|
1115
|
-
type
|
|
1116
|
-
|
|
1117
|
-
|
|
1026
|
+
type WebhookTenantMatch = {
|
|
1027
|
+
linkType: string;
|
|
1028
|
+
externalId: string;
|
|
1029
|
+
};
|
|
1118
1030
|
/**
|
|
1119
|
-
* Extracts the
|
|
1031
|
+
* Extracts the tenant lookup key from a webhook after the plugin has been
|
|
1032
|
+
* identified. Return null when the payload does not contain a resolvable id
|
|
1033
|
+
* (for example URL verification challenges).
|
|
1120
1034
|
*/
|
|
1121
|
-
type
|
|
1122
|
-
authConfig?: infer C;
|
|
1123
|
-
} ? C extends PluginAuthConfig ? C : undefined : undefined;
|
|
1035
|
+
type CorsairWebhookTenantMatcher = (request: RawWebhookRequest) => WebhookTenantMatch | null;
|
|
1124
1036
|
/**
|
|
1125
|
-
*
|
|
1126
|
-
*
|
|
1037
|
+
* Resolves the webhook tenant link field after OAuth completes.
|
|
1038
|
+
* Return null when the provider does not expose a stable external id.
|
|
1127
1039
|
*/
|
|
1128
|
-
type
|
|
1129
|
-
[K in Id]: (Endpoints extends EndpointTree ? {
|
|
1130
|
-
api: BindEndpoints<Endpoints>;
|
|
1131
|
-
} : {}) & InferPluginEntities<Schema> & (Webhooks extends WebhookTree ? {
|
|
1132
|
-
webhooks: BindWebhooks<Webhooks>;
|
|
1133
|
-
/**
|
|
1134
|
-
* Synchronously checks if an incoming webhook request is intended for this plugin.
|
|
1135
|
-
* Only present if the plugin defines a `pluginWebhookMatcher`.
|
|
1136
|
-
* Use this as a first-level filter before checking individual webhook matchers.
|
|
1137
|
-
*/
|
|
1138
|
-
pluginWebhookMatcher?: (request: RawWebhookRequest) => boolean;
|
|
1139
|
-
} : {}) & (ExtractAuthType<InferPluginOptions<P>, InferDefaultAuthType<P>> extends AuthTypes ? {
|
|
1140
|
-
keys: AccountKeyManagerFor<ExtractAuthType<InferPluginOptions<P>, InferDefaultAuthType<P>>, InferAuthConfig<P>>;
|
|
1141
|
-
} : {});
|
|
1142
|
-
} : never;
|
|
1040
|
+
type CorsairOAuthWebhookTenantLinkResolver = (tokens: TokenResponse) => WebhookTenantMatch | null | Promise<WebhookTenantMatch | null>;
|
|
1143
1041
|
/**
|
|
1144
|
-
*
|
|
1042
|
+
* Bivariance hack for webhook function types to ensure proper type inference.
|
|
1043
|
+
* @template Args - The function arguments
|
|
1044
|
+
* @template R - The function return type
|
|
1145
1045
|
*/
|
|
1146
|
-
type
|
|
1147
|
-
|
|
1148
|
-
}
|
|
1046
|
+
type Bivariant<Args extends unknown[], R> = {
|
|
1047
|
+
bivarianceHack(...args: Args): R;
|
|
1048
|
+
}['bivarianceHack'];
|
|
1149
1049
|
/**
|
|
1150
|
-
*
|
|
1050
|
+
* A webhook handler function definition that processes incoming webhooks.
|
|
1051
|
+
* Takes context + webhook request, returns a webhook response.
|
|
1052
|
+
* @template Ctx - The context type passed to the handler
|
|
1053
|
+
* @template TPayload - The type of the webhook payload
|
|
1054
|
+
* @template TResponseData - The type of data returned in the response
|
|
1151
1055
|
*/
|
|
1152
|
-
type
|
|
1056
|
+
type CorsairWebhookHandler<Ctx extends CorsairContext = CorsairContext, TPayload = unknown, TResponseData = unknown> = Bivariant<[
|
|
1057
|
+
ctx: Ctx,
|
|
1058
|
+
request: WebhookRequest<TPayload>
|
|
1059
|
+
], Promise<WebhookResponse<TResponseData>>>;
|
|
1153
1060
|
/**
|
|
1154
|
-
*
|
|
1061
|
+
* A complete webhook definition with both matcher and handler.
|
|
1062
|
+
* The matcher synchronously determines if this webhook handles the incoming request.
|
|
1063
|
+
* The handler processes the webhook after matching.
|
|
1064
|
+
* @template Ctx - The context type passed to the handler
|
|
1065
|
+
* @template TPayload - The type of the webhook payload
|
|
1066
|
+
* @template TResponseData - The type of data returned in the response
|
|
1155
1067
|
*/
|
|
1156
|
-
type
|
|
1068
|
+
type CorsairWebhook<Ctx extends CorsairContext = CorsairContext, TPayload = unknown, TResponseData = unknown> = {
|
|
1069
|
+
/** Synchronously determines if this webhook handles the incoming request */
|
|
1070
|
+
match: CorsairWebhookMatcher;
|
|
1071
|
+
/** Handles the webhook request after matching */
|
|
1072
|
+
handler: CorsairWebhookHandler<Ctx, TPayload, TResponseData>;
|
|
1073
|
+
};
|
|
1157
1074
|
/**
|
|
1158
|
-
*
|
|
1075
|
+
* A tree of webhooks that can be nested arbitrarily deep.
|
|
1076
|
+
* Similar to EndpointTree but for webhook handlers.
|
|
1077
|
+
*
|
|
1078
|
+
* @example
|
|
1079
|
+
* ```ts
|
|
1080
|
+
* // Flat structure
|
|
1081
|
+
* webhooks: {
|
|
1082
|
+
* issueCreated: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
1083
|
+
* issueClosed: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
1084
|
+
* }
|
|
1085
|
+
*
|
|
1086
|
+
* // Nested structure
|
|
1087
|
+
* webhooks: {
|
|
1088
|
+
* issues: {
|
|
1089
|
+
* created: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
1090
|
+
* updated: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
1091
|
+
* },
|
|
1092
|
+
* pull_requests: {
|
|
1093
|
+
* opened: { match: (req) => ..., handler: async (ctx, req) => ... },
|
|
1094
|
+
* },
|
|
1095
|
+
* }
|
|
1096
|
+
* ```
|
|
1159
1097
|
*/
|
|
1160
|
-
type
|
|
1098
|
+
type WebhookTree = {
|
|
1099
|
+
[key: string]: CorsairWebhook | WebhookTree;
|
|
1100
|
+
};
|
|
1161
1101
|
/**
|
|
1162
|
-
*
|
|
1163
|
-
*
|
|
1102
|
+
* A bound webhook - the user-facing API after context is applied.
|
|
1103
|
+
* Contains both the matcher (unchanged) and the bound handler.
|
|
1104
|
+
* @template TPayload - The type of the webhook payload
|
|
1105
|
+
* @template TResponseData - The type of data returned in the response
|
|
1164
1106
|
*/
|
|
1165
|
-
type
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
*/
|
|
1171
|
-
keys: InferAllIntegrationKeys<Plugins>;
|
|
1172
|
-
/**
|
|
1173
|
-
* Permission management namespace. Use this to query and transition permission records.
|
|
1174
|
-
* Available at the root regardless of multi-tenancy setting.
|
|
1175
|
-
*/
|
|
1176
|
-
permissions: CorsairPermissionsNamespace;
|
|
1177
|
-
/**
|
|
1178
|
-
* Management control plane namespace — in-process equivalent of the HTTP
|
|
1179
|
-
* `managementHandler`. Lists tenants, plugins, connection status, and
|
|
1180
|
-
* permission records without going through HTTP.
|
|
1181
|
-
*/
|
|
1182
|
-
manage: CorsairManageNamespace;
|
|
1107
|
+
type BoundWebhook<TPayload = unknown, TResponseData = unknown> = {
|
|
1108
|
+
/** Synchronously determines if this webhook handles the incoming request */
|
|
1109
|
+
match: CorsairWebhookMatcher;
|
|
1110
|
+
/** Handles the webhook request (context already applied) */
|
|
1111
|
+
handler: (request: WebhookRequest<TPayload>) => Promise<WebhookResponse<TResponseData>>;
|
|
1183
1112
|
};
|
|
1184
1113
|
/**
|
|
1185
|
-
*
|
|
1114
|
+
* A tree of bound webhooks (context already applied).
|
|
1115
|
+
* This is what the end user interacts with after client initialization.
|
|
1186
1116
|
*/
|
|
1187
|
-
type
|
|
1188
|
-
|
|
1189
|
-
* Integration-level key managers for each plugin.
|
|
1190
|
-
* Used to manage secrets shared across all tenants (e.g., OAuth2 client_id, client_secret).
|
|
1191
|
-
*/
|
|
1192
|
-
keys: InferAllIntegrationKeys<Plugins>;
|
|
1193
|
-
/**
|
|
1194
|
-
* Permission management namespace. Use this to query and transition permission records.
|
|
1195
|
-
* Available at the root regardless of multi-tenancy setting.
|
|
1196
|
-
*/
|
|
1197
|
-
permissions: CorsairPermissionsNamespace;
|
|
1198
|
-
/**
|
|
1199
|
-
* Management control plane namespace — in-process equivalent of the HTTP
|
|
1200
|
-
* `managementHandler`. Lists tenants, plugins, connection status, and
|
|
1201
|
-
* permission records without going through HTTP.
|
|
1202
|
-
*/
|
|
1203
|
-
manage: CorsairManageNamespace;
|
|
1204
|
-
};
|
|
1205
|
-
|
|
1206
|
-
declare const CORSAIR_INTERNAL: unique symbol;
|
|
1207
|
-
type CorsairInternalConfig = {
|
|
1208
|
-
plugins: readonly CorsairPlugin[];
|
|
1209
|
-
database: CorsairDatabase | undefined;
|
|
1210
|
-
kek: string;
|
|
1211
|
-
multiTenancy: boolean;
|
|
1212
|
-
approval?: {
|
|
1213
|
-
timeout: string;
|
|
1214
|
-
onTimeout: 'deny' | 'approve';
|
|
1215
|
-
mode?: 'synchronous' | 'asynchronous' | (() => 'synchronous' | 'asynchronous');
|
|
1216
|
-
/** Called when a permission is blocked in async mode. Return the message surfaced to the LLM. */
|
|
1217
|
-
formatAsyncMessage?: (opts: {
|
|
1218
|
-
token: string;
|
|
1219
|
-
id: string;
|
|
1220
|
-
plugin: string;
|
|
1221
|
-
endpoint: string;
|
|
1222
|
-
args: unknown;
|
|
1223
|
-
}) => string;
|
|
1224
|
-
};
|
|
1225
|
-
connect?: {
|
|
1226
|
-
baseUrl: string;
|
|
1227
|
-
redirectUri: string;
|
|
1228
|
-
onAuthMissing?: (opts: {
|
|
1229
|
-
plugin: string;
|
|
1230
|
-
connectUrl: string;
|
|
1231
|
-
state: string;
|
|
1232
|
-
}) => string;
|
|
1233
|
-
};
|
|
1117
|
+
type BoundWebhookTree = {
|
|
1118
|
+
[key: string]: BoundWebhook<any, any> | BoundWebhookTree;
|
|
1234
1119
|
};
|
|
1235
1120
|
/**
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1239
|
-
* @param config - Configuration with plugins, database, and multiTenancy: true
|
|
1240
|
-
* @returns A tenant wrapper with `withTenant(tenantId)` method and integration-level `keys`
|
|
1121
|
+
* Recursively transforms webhook definitions to their bound (context-free) signatures.
|
|
1122
|
+
* Handles both flat and nested webhook structures.
|
|
1123
|
+
* @template T - The webhook tree to bind
|
|
1241
1124
|
*/
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
}
|
|
1125
|
+
type BindWebhooks<T extends WebhookTree> = {
|
|
1126
|
+
[K in keyof T]: T[K] extends CorsairWebhook<any, infer P, infer R> ? BoundWebhook<P, R> : T[K] extends WebhookTree ? BindWebhooks<T[K]> : never;
|
|
1127
|
+
};
|
|
1245
1128
|
/**
|
|
1246
|
-
*
|
|
1247
|
-
*
|
|
1248
|
-
*
|
|
1249
|
-
*
|
|
1129
|
+
* Derives all dot-notation webhook paths from a WebhookTree as a string literal union.
|
|
1130
|
+
* Used to provide compile-time validation for webhook schema registry keys.
|
|
1131
|
+
* Passing an invalid path to any config that accepts WebhookPathsOf<T> is a type error.
|
|
1132
|
+
*
|
|
1133
|
+
* Design note: Same recursive constraint relaxation as EndpointPathsOf — see that type
|
|
1134
|
+
* for a full explanation of why we use `extends object` rather than `extends WebhookTree`
|
|
1135
|
+
* on the recursive call. We also check `{ match: any; handler: any }` before `object`
|
|
1136
|
+
* because webhook leaves are objects themselves.
|
|
1137
|
+
*
|
|
1138
|
+
* @example
|
|
1139
|
+
* Given: `{ messages: { message: { match: fn, handler: fn } }, channels: { created: { match: fn, handler: fn } } }`
|
|
1140
|
+
* Result: `'messages.message' | 'channels.created'`
|
|
1141
|
+
*
|
|
1142
|
+
* @template T - The webhook tree to extract paths from (unconstrained to allow recursion through as-const types)
|
|
1143
|
+
* @template Prefix - Internal accumulator for the current path prefix (do not supply manually)
|
|
1250
1144
|
*/
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1145
|
+
type WebhookPathsOf<T, Prefix extends string = ''> = {
|
|
1146
|
+
[K in keyof T & string]: T[K] extends {
|
|
1147
|
+
match: any;
|
|
1148
|
+
handler: any;
|
|
1149
|
+
} ? Prefix extends '' ? K : `${Prefix}.${K}` : T[K] extends object ? WebhookPathsOf<T[K], Prefix extends '' ? K : `${Prefix}.${K}`> : never;
|
|
1150
|
+
}[keyof T & string];
|
|
1254
1151
|
|
|
1255
|
-
export { type
|
|
1152
|
+
export { type WebhookResponse as $, type PermissionPolicy as A, type BindEndpoints as B, type CorsairPlugin as C, type PluginEndpointMeta as D, type EndpointPathsOf as E, type PluginPermissionsConfig as F, type RequiredPluginEndpointMeta as G, type RequiredPluginEndpointSchemas as H, type RequiredPluginWebhookSchemas as I, type WebhookHooks as J, type KeyBuilderContext as K, type BindWebhooks as L, type BoundWebhook as M, type BoundWebhookTree as N, type OAuthConfig as O, type PermissionMode as P, type CorsairOAuthWebhookTenantLinkResolver as Q, type RetryStrategies as R, type CorsairWebhook as S, type TokenResponse as T, type CorsairWebhookHandler as U, type CorsairWebhookMatcher as V, type WebhookTenantMatch as W, type CorsairWebhookTenantMatcher as X, type RawWebhookRequest as Y, type WebhookPathsOf as Z, type WebhookRequest as _, type CorsairIntegration as a, type WebhookTree as a0, type ManagementOk as a1, type Tenant as a2, type CreateTenantInput as a3, type PluginInfo as a4, type ConnectionStatus as a5, type PermissionRecord as a6, type CreateConnectLinkInput as a7, type ConnectLink as a8, type ResolvedConnectLink as a9, type OAuthCallbackInput as aa, type OAuthCallbackResult as ab, type CorsairManageNamespace as ac, type PluginConnectionState as ad, type CorsairTenantWrapper as b, type CorsairSingleTenantClient as c, type CorsairClient as d, exchangeCodeForTokens as e, type BoundEndpointFn as f, type BoundEndpointTree as g, type CorsairContext as h, type CorsairEndpoint as i, type EndpointTree as j, type CorsairErrorHandler as k, type ErrorContext as l, type ErrorHandler as m, type ErrorHandlerAndMatchFunction as n, type ErrorMatcher as o, type RetryStrategy as p, type CorsairPermissionsNamespace as q, type EnforcePermissionOptions as r, type EnforcePermissionResult as s, type BeforeHookResult as t, type CorsairKeyBuilder as u, type CorsairKeyBuilderBase as v, type CorsairPluginContext as w, type EndpointHooks as x, type EndpointMetaEntry as y, type EndpointRiskLevel as z };
|