corsair 0.1.21 → 0.1.22
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,4 +1,5 @@
|
|
|
1
1
|
import type { CorsairPlugin } from '../plugins';
|
|
2
|
+
type DbFieldType = 'string' | 'number' | 'boolean' | 'date';
|
|
2
3
|
export type EndpointSchemaResult = {
|
|
3
4
|
/** Human-readable description of what this endpoint does. */
|
|
4
5
|
description?: string;
|
|
@@ -34,6 +35,35 @@ export type WebhookSchemaResult = {
|
|
|
34
35
|
*/
|
|
35
36
|
availableWebhooks?: Record<string, string[]>;
|
|
36
37
|
};
|
|
38
|
+
export type DbSearchSchemaResult = {
|
|
39
|
+
/**
|
|
40
|
+
* What this entity type represents and how to search it.
|
|
41
|
+
* Pass `limit` and `offset` as numbers for pagination.
|
|
42
|
+
*/
|
|
43
|
+
description: string;
|
|
44
|
+
/**
|
|
45
|
+
* Filterable fields for the search() call.
|
|
46
|
+
* All active filters are AND-combined. Omit a field to skip filtering on it.
|
|
47
|
+
*
|
|
48
|
+
* Each operator shorthand: passing a raw value (string/number/boolean/Date) is
|
|
49
|
+
* equivalent to `{ equals: value }`.
|
|
50
|
+
*/
|
|
51
|
+
filters: {
|
|
52
|
+
/** Filter by the entity's external platform ID (e.g. a Slack channel ID). */
|
|
53
|
+
entity_id: {
|
|
54
|
+
type: 'string';
|
|
55
|
+
operators: string[];
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Filter by fields inside the entity's data payload.
|
|
59
|
+
* Only flat primitive fields are listed — nested objects are not filterable.
|
|
60
|
+
*/
|
|
61
|
+
data: Record<string, {
|
|
62
|
+
type: DbFieldType;
|
|
63
|
+
operators: string[];
|
|
64
|
+
}>;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
37
67
|
export type ListOperationsOptions = {
|
|
38
68
|
/**
|
|
39
69
|
* Filter to a specific plugin by its ID (e.g. 'slack', 'github').
|
|
@@ -42,24 +72,29 @@ export type ListOperationsOptions = {
|
|
|
42
72
|
*/
|
|
43
73
|
plugin?: string;
|
|
44
74
|
/**
|
|
45
|
-
* Whether to list API endpoints or
|
|
46
|
-
*
|
|
75
|
+
* Whether to list API endpoints, webhooks, or database entities.
|
|
76
|
+
* - 'api' (default) — lists callable API endpoint paths
|
|
77
|
+
* - 'webhooks' — lists receivable webhook event paths
|
|
78
|
+
* - 'db' — lists searchable database entity paths (one .search per entity type)
|
|
47
79
|
*/
|
|
48
|
-
type?: 'api' | 'webhooks';
|
|
80
|
+
type?: 'api' | 'webhooks' | 'db';
|
|
49
81
|
};
|
|
50
82
|
export type CorsairInspectMethods = {
|
|
51
83
|
/**
|
|
52
|
-
* Lists available operations (API endpoints or
|
|
84
|
+
* Lists available operations (API endpoints, webhooks, or database entities) for the configured plugins.
|
|
53
85
|
*
|
|
54
86
|
* - No options → all API endpoint paths across every plugin, keyed by plugin ID
|
|
55
87
|
* - `{ type: 'webhooks' }` → all webhook paths across every plugin, keyed by plugin ID
|
|
88
|
+
* - `{ type: 'db' }` → all searchable DB entity paths across every plugin, keyed by plugin ID
|
|
56
89
|
* - `{ plugin: 'slack' }` → Slack API endpoint paths as a flat array
|
|
57
90
|
* - `{ plugin: 'slack', type: 'webhooks' }` → Slack webhook paths as a flat array
|
|
91
|
+
* - `{ plugin: 'slack', type: 'db' }` → Slack DB entity search paths as a flat array
|
|
58
92
|
* - If the plugin is known but not configured, returns a plain string message.
|
|
59
93
|
* - If the plugin string is completely unrecognised, returns all API endpoints (same as no options).
|
|
60
94
|
*
|
|
61
95
|
* API paths use the format `plugin.api.group.method` (e.g. `slack.api.messages.post`).
|
|
62
96
|
* Webhook paths use the format `plugin.webhooks.group.event` (e.g. `slack.webhooks.messages.message`).
|
|
97
|
+
* DB paths use the format `plugin.db.entityType.search` (e.g. `slack.db.messages.search`).
|
|
63
98
|
* All paths can be passed directly to `get_schema()`.
|
|
64
99
|
*
|
|
65
100
|
* @example
|
|
@@ -72,15 +107,19 @@ export type CorsairInspectMethods = {
|
|
|
72
107
|
* corsair.list_operations({ plugin: 'slack', type: 'webhooks' })
|
|
73
108
|
* // ['slack.webhooks.messages.message', 'slack.webhooks.channels.created', ...]
|
|
74
109
|
*
|
|
110
|
+
* corsair.list_operations({ plugin: 'slack', type: 'db' })
|
|
111
|
+
* // ['slack.db.messages.search', 'slack.db.channels.search', 'slack.db.users.search', ...]
|
|
112
|
+
*
|
|
75
113
|
* corsair.list_operations({ plugin: 'unknown' })
|
|
76
114
|
* // "unknown isn't configured in the Corsair instance."
|
|
77
115
|
*/
|
|
78
116
|
list_operations(options?: ListOperationsOptions): Record<string, string[]> | string[] | string;
|
|
79
117
|
/**
|
|
80
|
-
* Returns schema and metadata for a specific API endpoint or
|
|
118
|
+
* Returns schema and metadata for a specific API endpoint, webhook, or database entity search.
|
|
81
119
|
* The path format determines which kind of schema is returned:
|
|
82
120
|
* - API path (`plugin.api.group.method`) → `EndpointSchemaResult`
|
|
83
121
|
* - Webhook path (`plugin.webhooks.group.event`) → `WebhookSchemaResult`
|
|
122
|
+
* - DB path (`plugin.db.entityType.search`) → `DbSearchSchemaResult`
|
|
84
123
|
*
|
|
85
124
|
* Casing is ignored — the path is lowercased before lookup.
|
|
86
125
|
* If the path is not found, returns an object with available paths for self-correction.
|
|
@@ -92,14 +131,18 @@ export type CorsairInspectMethods = {
|
|
|
92
131
|
* corsair.get_schema('slack.webhooks.messages.message')
|
|
93
132
|
* // { description: '...', usage: '...', payload: { ... }, response: { ... } }
|
|
94
133
|
*
|
|
134
|
+
* corsair.get_schema('slack.db.messages.search')
|
|
135
|
+
* // { description: '...', filters: { entity_id: { ... }, data: { text: { type: 'string', operators: [...] }, ... } } }
|
|
136
|
+
*
|
|
95
137
|
* corsair.get_schema('slack.api.invalid')
|
|
96
138
|
* // { availableMethods: { slack: ['slack.api.channels.list', ...], ... } }
|
|
97
139
|
*/
|
|
98
|
-
get_schema(path: string): EndpointSchemaResult | WebhookSchemaResult;
|
|
140
|
+
get_schema(path: string): EndpointSchemaResult | WebhookSchemaResult | DbSearchSchemaResult;
|
|
99
141
|
};
|
|
100
142
|
/**
|
|
101
143
|
* Creates the list_operations / get_schema functions bound to a specific plugin list.
|
|
102
144
|
* Used by both single-tenant and multi-tenant client builders.
|
|
103
145
|
*/
|
|
104
146
|
export declare function buildInspectMethods(plugins: readonly CorsairPlugin[]): CorsairInspectMethods;
|
|
147
|
+
export {};
|
|
105
148
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../core/inspect/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../core/inspect/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,YAAY,CAAC;AA2FnE,KAAK,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAyF5D,MAAM,MAAM,oBAAoB,GAAG;IAClC,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,aAAa,CAAC;IAC7C,4CAA4C;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yDAAyD;IACzD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAClC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,EAAE;QACR,6EAA6E;QAC7E,SAAS,EAAE;YAAE,IAAI,EAAE,QAAQ,CAAC;YAAC,SAAS,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;QACnD;;;WAGG;QACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,IAAI,EAAE,WAAW,CAAC;YAAC,SAAS,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAC;KACjE,CAAC;CACF,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IACnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,KAAK,GAAG,UAAU,GAAG,IAAI,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IACnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,eAAe,CACd,OAAO,CAAC,EAAE,qBAAqB,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC;IAChD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,UAAU,CACT,IAAI,EAAE,MAAM,GACV,oBAAoB,GAAG,mBAAmB,GAAG,oBAAoB,CAAC;CACrE,CAAC;AAmYF;;;GAGG;AACH,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,SAAS,aAAa,EAAE,GAC/B,qBAAqB,CASvB"}
|
|
@@ -75,6 +75,89 @@ function zodToJsonSchema(schema) {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
78
|
+
// DB Entity Helpers
|
|
79
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
80
|
+
const STRING_OPERATORS = ['equals', 'contains', 'startsWith', 'endsWith', 'in'];
|
|
81
|
+
const NUMBER_OPERATORS = ['equals', 'gt', 'gte', 'lt', 'lte', 'in'];
|
|
82
|
+
const BOOLEAN_OPERATORS = ['equals'];
|
|
83
|
+
const DATE_OPERATORS = ['equals', 'before', 'after', 'between'];
|
|
84
|
+
/**
|
|
85
|
+
* Unwraps Optional/Nullable/Default/Effects wrappers to find the primitive leaf type.
|
|
86
|
+
* Returns null for complex types (objects, arrays, unions) that are not directly filterable.
|
|
87
|
+
*/
|
|
88
|
+
function getSchemaLeafType(schema) {
|
|
89
|
+
const def = schema._def;
|
|
90
|
+
const typeName = def.typeName;
|
|
91
|
+
switch (typeName) {
|
|
92
|
+
case 'ZodOptional':
|
|
93
|
+
case 'ZodNullable':
|
|
94
|
+
case 'ZodDefault':
|
|
95
|
+
return getSchemaLeafType(def.innerType);
|
|
96
|
+
case 'ZodEffects':
|
|
97
|
+
// Covers z.coerce.date() and other transforms
|
|
98
|
+
return getSchemaLeafType(def.schema);
|
|
99
|
+
case 'ZodString':
|
|
100
|
+
return 'string';
|
|
101
|
+
case 'ZodNumber':
|
|
102
|
+
return 'number';
|
|
103
|
+
case 'ZodBoolean':
|
|
104
|
+
return 'boolean';
|
|
105
|
+
case 'ZodDate':
|
|
106
|
+
return 'date';
|
|
107
|
+
default:
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Derives the filterable fields from a Zod object schema.
|
|
113
|
+
* Only flat primitive fields (string, number, boolean, date) are included.
|
|
114
|
+
* Nested objects and arrays are skipped — the ORM does not support filtering into them.
|
|
115
|
+
*/
|
|
116
|
+
function buildFilterableFields(schema) {
|
|
117
|
+
const def = schema._def;
|
|
118
|
+
const typeName = def.typeName;
|
|
119
|
+
if (typeName === 'ZodOptional' ||
|
|
120
|
+
typeName === 'ZodNullable' ||
|
|
121
|
+
typeName === 'ZodDefault') {
|
|
122
|
+
return buildFilterableFields(def.innerType);
|
|
123
|
+
}
|
|
124
|
+
if (typeName === 'ZodEffects') {
|
|
125
|
+
return buildFilterableFields(def.schema);
|
|
126
|
+
}
|
|
127
|
+
if (typeName !== 'ZodObject')
|
|
128
|
+
return {};
|
|
129
|
+
const shape = def.shape();
|
|
130
|
+
const result = {};
|
|
131
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
132
|
+
const leafType = getSchemaLeafType(fieldSchema);
|
|
133
|
+
if (leafType === 'string') {
|
|
134
|
+
result[key] = { type: 'string', operators: STRING_OPERATORS };
|
|
135
|
+
}
|
|
136
|
+
else if (leafType === 'number') {
|
|
137
|
+
result[key] = { type: 'number', operators: NUMBER_OPERATORS };
|
|
138
|
+
}
|
|
139
|
+
else if (leafType === 'boolean') {
|
|
140
|
+
result[key] = { type: 'boolean', operators: BOOLEAN_OPERATORS };
|
|
141
|
+
}
|
|
142
|
+
else if (leafType === 'date') {
|
|
143
|
+
result[key] = { type: 'date', operators: DATE_OPERATORS };
|
|
144
|
+
}
|
|
145
|
+
// Nested objects, arrays, unions — not filterable via ORM, omit them
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Case-insensitive lookup for an entity name in a schema's entities map.
|
|
151
|
+
* Entity names are camelCase (e.g. 'userGroups') but agent paths are lowercased.
|
|
152
|
+
*/
|
|
153
|
+
function findEntityCaseInsensitive(entities, lowercasedName) {
|
|
154
|
+
for (const [key, schema] of Object.entries(entities)) {
|
|
155
|
+
if (key.toLowerCase() === lowercasedName)
|
|
156
|
+
return [key, schema];
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
78
161
|
// Endpoint Tree Walker
|
|
79
162
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
80
163
|
function walkEndpointTree(tree, pathParts, result) {
|
|
@@ -222,13 +305,17 @@ function listOperations(plugins, options) {
|
|
|
222
305
|
walkWebhookTree(found.webhooks, [], paths);
|
|
223
306
|
return paths.map((path) => `${found.id}.webhooks.${path}`);
|
|
224
307
|
}
|
|
225
|
-
|
|
226
|
-
|
|
308
|
+
if (type === 'db') {
|
|
309
|
+
const entities = found.schema?.entities;
|
|
310
|
+
if (!entities)
|
|
227
311
|
return [];
|
|
228
|
-
|
|
229
|
-
walkEndpointTree(found.endpoints, [], paths);
|
|
230
|
-
return paths.map((path) => `${found.id}.api.${path.toLowerCase()}`);
|
|
312
|
+
return Object.keys(entities).map((entityName) => `${found.id}.db.${entityName}.search`);
|
|
231
313
|
}
|
|
314
|
+
if (!found.endpoints)
|
|
315
|
+
return [];
|
|
316
|
+
const paths = [];
|
|
317
|
+
walkEndpointTree(found.endpoints, [], paths);
|
|
318
|
+
return paths.map((path) => `${found.id}.api.${path.toLowerCase()}`);
|
|
232
319
|
}
|
|
233
320
|
const result = {};
|
|
234
321
|
if (type === 'webhooks') {
|
|
@@ -240,6 +327,14 @@ function listOperations(plugins, options) {
|
|
|
240
327
|
result[p.id] = paths.map((path) => `${p.id}.webhooks.${path}`);
|
|
241
328
|
}
|
|
242
329
|
}
|
|
330
|
+
else if (type === 'db') {
|
|
331
|
+
for (const p of plugins) {
|
|
332
|
+
const entities = p.schema?.entities;
|
|
333
|
+
if (!entities)
|
|
334
|
+
continue;
|
|
335
|
+
result[p.id] = Object.keys(entities).map((entityName) => `${p.id}.db.${entityName}.search`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
243
338
|
else {
|
|
244
339
|
for (const p of plugins) {
|
|
245
340
|
if (!p.endpoints)
|
|
@@ -274,6 +369,38 @@ function getSchema(plugins, path) {
|
|
|
274
369
|
const remainder = normalised.slice(dotIndex + 1);
|
|
275
370
|
const plugin = plugins.find((p) => p.id === pluginId);
|
|
276
371
|
if (plugin) {
|
|
372
|
+
// ── DB search path: plugin.db.entityType.search ────────────────────────
|
|
373
|
+
if (remainder.startsWith('db.')) {
|
|
374
|
+
const dbPath = remainder.slice(3); // strip 'db.'
|
|
375
|
+
const lastDot = dbPath.lastIndexOf('.');
|
|
376
|
+
if (lastDot !== -1) {
|
|
377
|
+
const entityNameLower = dbPath.slice(0, lastDot);
|
|
378
|
+
const method = dbPath.slice(lastDot + 1);
|
|
379
|
+
const entities = plugin.schema?.entities;
|
|
380
|
+
if (method === 'search' && entities) {
|
|
381
|
+
const entry = findEntityCaseInsensitive(entities, entityNameLower);
|
|
382
|
+
if (entry) {
|
|
383
|
+
const [entityName, entitySchema] = entry;
|
|
384
|
+
return {
|
|
385
|
+
description: `Search ${pluginId} ${entityName} stored in the local database. Returns an array of matching records. Pass limit and offset (numbers) for pagination.`,
|
|
386
|
+
filters: {
|
|
387
|
+
entity_id: {
|
|
388
|
+
type: 'string',
|
|
389
|
+
operators: STRING_OPERATORS,
|
|
390
|
+
},
|
|
391
|
+
data: buildFilterableFields(entitySchema),
|
|
392
|
+
},
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// Invalid db path — return available db operations for self-correction
|
|
398
|
+
return {
|
|
399
|
+
availableMethods: listOperations(plugins, {
|
|
400
|
+
type: 'db',
|
|
401
|
+
}),
|
|
402
|
+
};
|
|
403
|
+
}
|
|
277
404
|
// ── Webhook path: plugin.webhooks.group.event ──────────────────────────
|
|
278
405
|
if (remainder.startsWith('webhooks.')) {
|
|
279
406
|
const webhookPathNormalised = remainder.slice(9); // strip 'webhooks.'
|