@slates/provider 1.0.0-rc.2 → 1.0.0-rc.21
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/index.cjs +2885 -2
- package/dist/index.d.cts +1019 -0
- package/dist/index.d.ts +1019 -9
- package/dist/index.module.js +2775 -2
- package/package.json +9 -6
- package/src/action/action.ts +92 -4
- package/src/action/attachment.ts +87 -0
- package/src/action/builder.test.ts +136 -0
- package/src/action/builder.ts +113 -15
- package/src/action/directUpload.test.ts +70 -0
- package/src/action/directUpload.ts +105 -0
- package/src/action/getFileUrlTool.ts +41 -0
- package/src/action/index.ts +4 -2
- package/src/action/publicTool.ts +36 -0
- package/src/action/scopes.test.ts +76 -0
- package/src/action/scopes.ts +103 -0
- package/src/action/tool.ts +22 -6
- package/src/action/trigger.ts +19 -11
- package/src/adapter/adapter.ts +38 -0
- package/src/adapter/index.test.ts +322 -0
- package/src/adapter/index.ts +2 -0
- package/src/adapter/spec.ts +154 -0
- package/src/auth/auth.ts +3 -3
- package/src/auth/index.ts +2 -0
- package/src/auth/oauth.test.ts +83 -0
- package/src/auth/oauth.ts +150 -0
- package/src/auth/redact.test.ts +103 -0
- package/src/auth/redact.ts +111 -0
- package/src/auth/types.ts +72 -13
- package/src/axios/http.test.ts +83 -0
- package/src/axios/index.ts +116 -10
- package/src/axios/trace.test.ts +377 -0
- package/src/axios/trace.ts +803 -0
- package/src/config/config.ts +14 -3
- package/src/context/context.ts +264 -17
- package/src/context/hook.test.ts +46 -0
- package/src/context/hook.ts +15 -6
- package/src/context/index.ts +1 -0
- package/src/context/pQueue.ts +4 -0
- package/src/crypto/hmac.test.ts +40 -0
- package/src/crypto/hmac.ts +32 -0
- package/src/crypto/index.ts +1 -0
- package/src/docs.ts +22 -0
- package/src/error/api.test.ts +114 -0
- package/src/error/api.ts +236 -0
- package/src/error/axios.ts +220 -0
- package/src/error/base.test.ts +178 -0
- package/src/error/base.ts +108 -2
- package/src/error/declaration.ts +7 -2
- package/src/error/defaults.ts +50 -0
- package/src/error/index.ts +4 -0
- package/src/error/service.ts +170 -0
- package/src/error/types.ts +75 -0
- package/src/error/utils.ts +157 -0
- package/src/file/index.test.ts +36 -0
- package/src/file/index.ts +27 -0
- package/src/index.ts +8 -0
- package/src/logger/logger.test.ts +57 -0
- package/src/logger/logger.ts +72 -11
- package/src/module/resolveDefaultExport.test.ts +32 -0
- package/src/module/resolveDefaultExport.ts +14 -0
- package/src/object/index.test.ts +38 -0
- package/src/object/index.ts +12 -0
- package/src/specification/slate.ts +40 -4
- package/src/specification/specification.ts +10 -6
- package/src/webhook/graph.test.ts +37 -0
- package/src/webhook/graph.ts +22 -0
- package/src/webhook/index.ts +2 -0
- package/src/webhook/meta.test.ts +52 -0
- package/src/webhook/meta.ts +43 -0
- package/dist/action/action.d.ts +0 -98
- package/dist/action/action.d.ts.map +0 -1
- package/dist/action/builder.d.ts +0 -27
- package/dist/action/builder.d.ts.map +0 -1
- package/dist/action/index.d.ts +0 -5
- package/dist/action/index.d.ts.map +0 -1
- package/dist/action/tool.d.ts +0 -14
- package/dist/action/tool.d.ts.map +0 -1
- package/dist/action/trigger.d.ts +0 -32
- package/dist/action/trigger.d.ts.map +0 -1
- package/dist/auth/auth.d.ts +0 -30
- package/dist/auth/auth.d.ts.map +0 -1
- package/dist/auth/index.d.ts +0 -3
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/types.d.ts +0 -148
- package/dist/auth/types.d.ts.map +0 -1
- package/dist/axios/index.d.ts +0 -4
- package/dist/axios/index.d.ts.map +0 -1
- package/dist/config/config.d.ts +0 -26
- package/dist/config/config.d.ts.map +0 -1
- package/dist/config/index.d.ts +0 -2
- package/dist/config/index.d.ts.map +0 -1
- package/dist/context/context.d.ts +0 -20
- package/dist/context/context.d.ts.map +0 -1
- package/dist/context/hook.d.ts +0 -4
- package/dist/context/hook.d.ts.map +0 -1
- package/dist/context/index.d.ts +0 -2
- package/dist/context/index.d.ts.map +0 -1
- package/dist/error/base.d.ts +0 -5
- package/dist/error/base.d.ts.map +0 -1
- package/dist/error/declaration.d.ts +0 -6
- package/dist/error/declaration.d.ts.map +0 -1
- package/dist/error/index.d.ts +0 -3
- package/dist/error/index.d.ts.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.modern.js +0 -2
- package/dist/index.modern.js.map +0 -1
- package/dist/index.module.js.map +0 -1
- package/dist/index.umd.js +0 -2
- package/dist/index.umd.js.map +0 -1
- package/dist/logger/index.d.ts +0 -2
- package/dist/logger/index.d.ts.map +0 -1
- package/dist/logger/logger.d.ts +0 -20
- package/dist/logger/logger.d.ts.map +0 -1
- package/dist/specification/index.d.ts +0 -3
- package/dist/specification/index.d.ts.map +0 -1
- package/dist/specification/slate.d.ts +0 -15
- package/dist/specification/slate.d.ts.map +0 -1
- package/dist/specification/specification.d.ts +0 -30
- package/dist/specification/specification.d.ts.map +0 -1
- package/dist/specification/zero.d.ts +0 -13
- package/dist/specification/zero.d.ts.map +0 -1
- package/dist/tokens.d.ts +0 -34
- package/dist/tokens.d.ts.map +0 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { type SlateLogEntry, SlateLogger } from './logger';
|
|
3
|
+
|
|
4
|
+
let flushLogs = async () => {
|
|
5
|
+
await new Promise(resolve => setTimeout(resolve, 20));
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
describe('SlateLogger', () => {
|
|
9
|
+
it('keeps a readable message and structured data for object logs', async () => {
|
|
10
|
+
let entries: SlateLogEntry[] = [];
|
|
11
|
+
let logger = new SlateLogger([
|
|
12
|
+
batch => {
|
|
13
|
+
entries.push(...batch);
|
|
14
|
+
}
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
logger.info({
|
|
18
|
+
message: 'Invoking tool action',
|
|
19
|
+
providerId: 'demo-slate',
|
|
20
|
+
actionId: 'echo',
|
|
21
|
+
phase: 'start'
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
await flushLogs();
|
|
25
|
+
|
|
26
|
+
expect(entries[0]).toMatchObject({
|
|
27
|
+
type: 'info',
|
|
28
|
+
message: 'Invoking tool action',
|
|
29
|
+
data: {
|
|
30
|
+
providerId: 'demo-slate',
|
|
31
|
+
actionId: 'echo',
|
|
32
|
+
phase: 'start'
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('captures error details as structured metadata', async () => {
|
|
38
|
+
let entries: SlateLogEntry[] = [];
|
|
39
|
+
let logger = new SlateLogger([
|
|
40
|
+
batch => {
|
|
41
|
+
entries.push(...batch);
|
|
42
|
+
}
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
logger.error(new Error('boom'));
|
|
46
|
+
|
|
47
|
+
await flushLogs();
|
|
48
|
+
|
|
49
|
+
expect(entries[0]?.message).toBe('Error: boom');
|
|
50
|
+
expect(entries[0]?.data).toMatchObject({
|
|
51
|
+
error: {
|
|
52
|
+
name: 'Error',
|
|
53
|
+
message: 'boom'
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
package/src/logger/logger.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { encode } from '@toon-format/toon';
|
|
2
2
|
|
|
3
3
|
export type SlateLogType = 'info' | 'warn' | 'error' | 'progress';
|
|
4
|
+
export type SlateLogFields = Record<string, unknown>;
|
|
4
5
|
|
|
5
6
|
export type SlateLogMessageInput =
|
|
6
7
|
| string
|
|
@@ -12,22 +13,79 @@ export type SlateLogMessageInput =
|
|
|
12
13
|
| object
|
|
13
14
|
| SlateLogMessageInput[];
|
|
14
15
|
|
|
15
|
-
let
|
|
16
|
+
let isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
17
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
18
|
+
|
|
19
|
+
let normalizeMessage = (
|
|
20
|
+
message: SlateLogMessageInput
|
|
21
|
+
): {
|
|
22
|
+
message: string;
|
|
23
|
+
data?: SlateLogFields;
|
|
24
|
+
} => {
|
|
25
|
+
if (Array.isArray(message)) {
|
|
26
|
+
let parts = message.map(part => normalizeMessage(part));
|
|
27
|
+
let combinedMessage = parts
|
|
28
|
+
.map(part => part.message)
|
|
29
|
+
.filter(Boolean)
|
|
30
|
+
.join(' ')
|
|
31
|
+
.trim();
|
|
32
|
+
|
|
33
|
+
let dataParts = parts
|
|
34
|
+
.map(part => {
|
|
35
|
+
if (part.data) {
|
|
36
|
+
return {
|
|
37
|
+
message: part.message,
|
|
38
|
+
...part.data
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return part.message;
|
|
43
|
+
})
|
|
44
|
+
.filter(Boolean);
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
message: combinedMessage || 'Log entry',
|
|
48
|
+
data: dataParts.length > 0 ? { parts: dataParts } : undefined
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
16
52
|
if (typeof message === 'object') {
|
|
17
|
-
if (message === null) return 'null';
|
|
53
|
+
if (message === null) return { message: 'null' };
|
|
18
54
|
if (message instanceof Error) {
|
|
19
|
-
return
|
|
55
|
+
return {
|
|
56
|
+
message: `${message.name}: ${message.message}`,
|
|
57
|
+
data: {
|
|
58
|
+
error: {
|
|
59
|
+
name: message.name,
|
|
60
|
+
message: message.message,
|
|
61
|
+
stack: message.stack
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
20
65
|
}
|
|
21
|
-
|
|
66
|
+
|
|
67
|
+
if (isRecord(message) && typeof message.message === 'string') {
|
|
68
|
+
let { message: text, ...data } = message;
|
|
69
|
+
return {
|
|
70
|
+
message: text || 'Log entry',
|
|
71
|
+
data: Object.keys(data).length > 0 ? data : undefined
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
message: encode(message),
|
|
77
|
+
data: isRecord(message) ? message : undefined
|
|
78
|
+
};
|
|
22
79
|
}
|
|
23
80
|
|
|
24
|
-
return String(message);
|
|
81
|
+
return { message: String(message) };
|
|
25
82
|
};
|
|
26
83
|
|
|
27
84
|
export interface SlateLogEntry {
|
|
28
85
|
type: SlateLogType;
|
|
29
86
|
message: string;
|
|
30
87
|
timestamp: Date;
|
|
88
|
+
data?: SlateLogFields;
|
|
31
89
|
}
|
|
32
90
|
|
|
33
91
|
export type SlateLogListener = (entries: SlateLogEntry[]) => void;
|
|
@@ -44,9 +102,10 @@ export class SlateLogger {
|
|
|
44
102
|
private flush() {
|
|
45
103
|
if (this.#timer) clearTimeout(this.#timer);
|
|
46
104
|
if (this.#logs.length === 0) return;
|
|
105
|
+
let logs = this.#logs.splice(0);
|
|
47
106
|
|
|
48
107
|
for (let listener of this.#listeners) {
|
|
49
|
-
listener(
|
|
108
|
+
listener(logs);
|
|
50
109
|
}
|
|
51
110
|
}
|
|
52
111
|
|
|
@@ -59,27 +118,29 @@ export class SlateLogger {
|
|
|
59
118
|
}
|
|
60
119
|
|
|
61
120
|
log(type: SlateLogType, message: SlateLogMessageInput) {
|
|
121
|
+
let normalized = normalizeMessage(message);
|
|
62
122
|
this.#logs.push({
|
|
63
123
|
type,
|
|
64
124
|
timestamp: new Date(),
|
|
65
|
-
message:
|
|
125
|
+
message: normalized.message,
|
|
126
|
+
data: normalized.data
|
|
66
127
|
});
|
|
67
128
|
this.scheduleFlush();
|
|
68
129
|
}
|
|
69
130
|
|
|
70
131
|
info(...message: SlateLogMessageInput[]) {
|
|
71
|
-
this.log('info', message.flat());
|
|
132
|
+
this.log('info', message.length === 1 ? message[0]! : message.flat());
|
|
72
133
|
}
|
|
73
134
|
|
|
74
135
|
warn(...message: SlateLogMessageInput[]) {
|
|
75
|
-
this.log('warn', message.flat());
|
|
136
|
+
this.log('warn', message.length === 1 ? message[0]! : message.flat());
|
|
76
137
|
}
|
|
77
138
|
|
|
78
139
|
error(...message: SlateLogMessageInput[]) {
|
|
79
|
-
this.log('error', message.flat());
|
|
140
|
+
this.log('error', message.length === 1 ? message[0]! : message.flat());
|
|
80
141
|
}
|
|
81
142
|
|
|
82
143
|
progress(...message: SlateLogMessageInput[]) {
|
|
83
|
-
this.log('progress', message.flat());
|
|
144
|
+
this.log('progress', message.length === 1 ? message[0]! : message.flat());
|
|
84
145
|
}
|
|
85
146
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { resolveDefaultExport } from './resolveDefaultExport';
|
|
3
|
+
|
|
4
|
+
class Example {
|
|
5
|
+
value: number;
|
|
6
|
+
constructor(value: number) {
|
|
7
|
+
this.value = value;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('resolveDefaultExport', () => {
|
|
12
|
+
it('returns a constructor export as-is', () => {
|
|
13
|
+
expect(resolveDefaultExport<typeof Example>(Example)).toBe(Example);
|
|
14
|
+
expect(new (resolveDefaultExport<typeof Example>(Example))(1).value).toBe(1);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('unwraps CJS default-export objects produced by bundlers', () => {
|
|
18
|
+
expect(resolveDefaultExport<typeof Example>({ default: Example })).toBe(Example);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('unwraps nested default exports from double-bundling', () => {
|
|
22
|
+
expect(
|
|
23
|
+
resolveDefaultExport<typeof Example>({ default: { default: Example } })
|
|
24
|
+
).toBe(Example);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('throws when the export is not a constructor', () => {
|
|
28
|
+
expect(() => resolveDefaultExport({})).toThrow(TypeError);
|
|
29
|
+
expect(() => resolveDefaultExport({ default: { foo: 1 } })).toThrow(TypeError);
|
|
30
|
+
expect(() => resolveDefaultExport(undefined)).toThrow(TypeError);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export let resolveDefaultExport = <T>(value: unknown): T => {
|
|
2
|
+
let current = value;
|
|
3
|
+
|
|
4
|
+
for (let i = 0; i < 4; i++) {
|
|
5
|
+
if (typeof current === 'function') return current as T;
|
|
6
|
+
if (current && typeof current === 'object' && 'default' in current) {
|
|
7
|
+
current = (current as { default: unknown }).default;
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
throw new TypeError('Module export is not a constructor');
|
|
14
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { pickDefined, setIfDefined } from './index';
|
|
3
|
+
|
|
4
|
+
describe('object helpers', () => {
|
|
5
|
+
it('omits only undefined values', () => {
|
|
6
|
+
expect(
|
|
7
|
+
pickDefined({
|
|
8
|
+
keepNull: null,
|
|
9
|
+
keepFalse: false,
|
|
10
|
+
keepZero: 0,
|
|
11
|
+
keepEmpty: '',
|
|
12
|
+
dropUndefined: undefined
|
|
13
|
+
})
|
|
14
|
+
).toEqual({
|
|
15
|
+
keepNull: null,
|
|
16
|
+
keepFalse: false,
|
|
17
|
+
keepZero: 0,
|
|
18
|
+
keepEmpty: ''
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('sets only defined values on an existing target', () => {
|
|
23
|
+
let target: Record<string, unknown> = {};
|
|
24
|
+
|
|
25
|
+
setIfDefined(target, 'nullValue', null);
|
|
26
|
+
setIfDefined(target, 'falseValue', false);
|
|
27
|
+
setIfDefined(target, 'zeroValue', 0);
|
|
28
|
+
setIfDefined(target, 'emptyValue', '');
|
|
29
|
+
setIfDefined(target, 'undefinedValue', undefined);
|
|
30
|
+
|
|
31
|
+
expect(target).toEqual({
|
|
32
|
+
nullValue: null,
|
|
33
|
+
falseValue: false,
|
|
34
|
+
zeroValue: 0,
|
|
35
|
+
emptyValue: ''
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export let pickDefined = <T extends object>(value: T) =>
|
|
2
|
+
Object.fromEntries(
|
|
3
|
+
Object.entries(value).filter(([, child]) => child !== undefined)
|
|
4
|
+
) as Partial<T> & Record<string, unknown>;
|
|
5
|
+
|
|
6
|
+
export let setIfDefined = (target: Record<string, unknown>, key: string, value: unknown) => {
|
|
7
|
+
if (value !== undefined) {
|
|
8
|
+
target[key] = value;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return target;
|
|
12
|
+
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { SlateTool, SlateTrigger } from '../action';
|
|
2
|
-
import {
|
|
1
|
+
import type { SlateTool, SlateTrigger } from '../action';
|
|
2
|
+
import type { SlateAdapter } from '../adapter';
|
|
3
|
+
import { SlateDeclarationError } from '../error';
|
|
4
|
+
import type { SlateSpecification } from './specification';
|
|
3
5
|
|
|
4
6
|
export class Slate<ConfigType extends {}, AuthType extends {}> {
|
|
5
7
|
private constructor(
|
|
@@ -7,15 +9,45 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
|
|
|
7
9
|
private readonly _actions: (
|
|
8
10
|
| SlateTrigger<ConfigType, AuthType, any, any>
|
|
9
11
|
| SlateTool<ConfigType, AuthType, any, any>
|
|
10
|
-
)[]
|
|
12
|
+
)[],
|
|
13
|
+
private readonly _adapters: SlateAdapter<ConfigType, AuthType>[]
|
|
11
14
|
) {}
|
|
12
15
|
|
|
13
16
|
static create<ConfigType extends {}, AuthType extends {}>(params: {
|
|
14
17
|
spec: SlateSpecification<ConfigType, AuthType>;
|
|
15
18
|
triggers: SlateTrigger<ConfigType, AuthType, any, any>[];
|
|
16
19
|
tools: SlateTool<ConfigType, AuthType, any, any>[];
|
|
20
|
+
adapters?: SlateAdapter<ConfigType, AuthType>[];
|
|
17
21
|
}) {
|
|
18
|
-
|
|
22
|
+
let adapters = params.adapters ?? [];
|
|
23
|
+
let actions = [...params.triggers, ...params.tools];
|
|
24
|
+
let seenAdapterIds = new Set<string>();
|
|
25
|
+
let seenActionKeys = new Map(actions.map(action => [action.key, action]));
|
|
26
|
+
|
|
27
|
+
for (let adapter of adapters) {
|
|
28
|
+
if (seenAdapterIds.has(adapter.id)) {
|
|
29
|
+
throw new SlateDeclarationError(
|
|
30
|
+
`Adapter "${adapter.id}" is registered more than once`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
seenAdapterIds.add(adapter.id);
|
|
34
|
+
|
|
35
|
+
for (let action of adapter.actions) {
|
|
36
|
+
let existing = seenActionKeys.get(action.key);
|
|
37
|
+
if (existing && existing !== action) {
|
|
38
|
+
throw new SlateDeclarationError(
|
|
39
|
+
`Adapter "${adapter.id}" action "${action.key}" conflicts with another action`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!existing) {
|
|
44
|
+
actions.push(action);
|
|
45
|
+
seenActionKeys.set(action.key, action);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return new Slate(params.spec, actions, adapters);
|
|
19
51
|
}
|
|
20
52
|
|
|
21
53
|
get spec() {
|
|
@@ -25,4 +57,8 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
|
|
|
25
57
|
get actions() {
|
|
26
58
|
return this._actions;
|
|
27
59
|
}
|
|
60
|
+
|
|
61
|
+
get adapters() {
|
|
62
|
+
return this._adapters;
|
|
63
|
+
}
|
|
28
64
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
|
-
import { SlateAuth } from '../auth';
|
|
3
|
-
import { SlateConfig } from '../config';
|
|
2
|
+
import type { SlateAuth } from '../auth';
|
|
3
|
+
import type { SlateConfig } from '../config';
|
|
4
|
+
import type { SlateProviderDocsReference } from '../docs';
|
|
4
5
|
|
|
5
6
|
export interface SlateSpecificationParameters {
|
|
6
7
|
key: string;
|
|
7
8
|
name: string;
|
|
8
9
|
description?: string;
|
|
10
|
+
docs?: SlateProviderDocsReference[];
|
|
9
11
|
metadata?: Record<string, any>;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
export interface SlateSpecificationCreateParameters<
|
|
13
|
-
|
|
14
|
-
AuthType extends {}
|
|
15
|
-
> extends SlateSpecificationParameters {
|
|
14
|
+
export interface SlateSpecificationCreateParameters<ConfigType extends {}, AuthType extends {}>
|
|
15
|
+
extends SlateSpecificationParameters {
|
|
16
16
|
config: SlateConfig<ConfigType>;
|
|
17
17
|
auth: SlateAuth<AuthType>;
|
|
18
18
|
}
|
|
@@ -63,6 +63,10 @@ export class SlateSpecification<ConfigType extends {}, AuthType extends {}> {
|
|
|
63
63
|
get description() {
|
|
64
64
|
return this._params.description;
|
|
65
65
|
}
|
|
66
|
+
|
|
67
|
+
get docs() {
|
|
68
|
+
return this._params.docs;
|
|
69
|
+
}
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
export let spec = <ConfigType extends {}, AuthType extends {}>(
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { getGraphWebhookValidationResponse, graphWebhookHttp } from './graph';
|
|
3
|
+
|
|
4
|
+
describe('Microsoft Graph webhook validation', () => {
|
|
5
|
+
it('makes only validation requests synchronous', () => {
|
|
6
|
+
expect(graphWebhookHttp).toEqual({
|
|
7
|
+
methods: ['POST'],
|
|
8
|
+
sync: {
|
|
9
|
+
mode: 'match',
|
|
10
|
+
match: [{ hasQueryParam: 'validationToken' }]
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('echoes the URL-decoded validation token as plain text', () => {
|
|
16
|
+
let response = getGraphWebhookValidationResponse(
|
|
17
|
+
new Request(
|
|
18
|
+
'https://example.com/webhook?validationToken=Validation%3a+Testing+client+application+reachability',
|
|
19
|
+
{ method: 'POST' }
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
expect(response).toEqual({
|
|
24
|
+
status: 200,
|
|
25
|
+
headers: { 'content-type': 'text/plain' },
|
|
26
|
+
body: 'Validation: Testing client application reachability'
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('ignores ordinary change notifications', () => {
|
|
31
|
+
expect(
|
|
32
|
+
getGraphWebhookValidationResponse(
|
|
33
|
+
new Request('https://example.com/webhook', { method: 'POST' })
|
|
34
|
+
)
|
|
35
|
+
).toBeNull();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SlateWebhookHttpOptions, SlateWebhookHttpResponseInit } from '../action';
|
|
2
|
+
|
|
3
|
+
export const graphWebhookHttp = {
|
|
4
|
+
methods: ['POST'],
|
|
5
|
+
sync: {
|
|
6
|
+
mode: 'match',
|
|
7
|
+
match: [{ hasQueryParam: 'validationToken' }]
|
|
8
|
+
}
|
|
9
|
+
} satisfies SlateWebhookHttpOptions;
|
|
10
|
+
|
|
11
|
+
export let getGraphWebhookValidationResponse = (
|
|
12
|
+
request: Request
|
|
13
|
+
): SlateWebhookHttpResponseInit | null => {
|
|
14
|
+
let validationToken = new URL(request.url).searchParams.get('validationToken');
|
|
15
|
+
if (validationToken === null) return null;
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
status: 200,
|
|
19
|
+
headers: { 'content-type': 'text/plain' },
|
|
20
|
+
body: validationToken
|
|
21
|
+
};
|
|
22
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { getMetaWebhookVerificationResponse, metaWebhookHttp } from './meta';
|
|
3
|
+
|
|
4
|
+
let verificationRequest = (verifyToken = 'verify-token', challenge = 'challenge-value') =>
|
|
5
|
+
new Request(
|
|
6
|
+
`https://example.com/webhook?hub.mode=subscribe&hub.verify_token=${verifyToken}&hub.challenge=${challenge}`
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
describe('Meta webhook verification', () => {
|
|
10
|
+
it('makes only verification GET requests synchronous', () => {
|
|
11
|
+
expect(metaWebhookHttp).toEqual({
|
|
12
|
+
methods: ['GET', 'POST'],
|
|
13
|
+
sync: {
|
|
14
|
+
mode: 'match',
|
|
15
|
+
match: [{ method: 'GET', hasQueryParam: 'hub.mode' }]
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('returns the challenge for a matching configured token', () => {
|
|
21
|
+
expect(getMetaWebhookVerificationResponse(verificationRequest(), 'verify-token')).toEqual({
|
|
22
|
+
status: 200,
|
|
23
|
+
headers: { 'content-type': 'text/plain' },
|
|
24
|
+
body: 'challenge-value'
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('rejects a mismatched configured token', () => {
|
|
29
|
+
expect(
|
|
30
|
+
getMetaWebhookVerificationResponse(verificationRequest('wrong-token'), 'verify-token')
|
|
31
|
+
).toMatchObject({ status: 403 });
|
|
32
|
+
expect(
|
|
33
|
+
getMetaWebhookVerificationResponse(verificationRequest('wrong-token'), '')
|
|
34
|
+
).toMatchObject({ status: 403 });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('preserves legacy verification when no token is configured', () => {
|
|
38
|
+
expect(
|
|
39
|
+
getMetaWebhookVerificationResponse(verificationRequest('legacy-token'), undefined)
|
|
40
|
+
).toMatchObject({ status: 200, body: 'challenge-value' });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('rejects malformed verification and ignores POST events', () => {
|
|
44
|
+
let malformed = new Request('https://example.com/webhook?hub.mode=subscribe');
|
|
45
|
+
let post = new Request('https://example.com/webhook', { method: 'POST' });
|
|
46
|
+
|
|
47
|
+
expect(getMetaWebhookVerificationResponse(malformed, undefined)).toMatchObject({
|
|
48
|
+
status: 400
|
|
49
|
+
});
|
|
50
|
+
expect(getMetaWebhookVerificationResponse(post, undefined)).toBeNull();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { SlateWebhookHttpOptions, SlateWebhookHttpResponseInit } from '../action';
|
|
2
|
+
|
|
3
|
+
export const metaWebhookHttp = {
|
|
4
|
+
methods: ['GET', 'POST'],
|
|
5
|
+
sync: {
|
|
6
|
+
mode: 'match',
|
|
7
|
+
match: [{ method: 'GET', hasQueryParam: 'hub.mode' }]
|
|
8
|
+
}
|
|
9
|
+
} satisfies SlateWebhookHttpOptions;
|
|
10
|
+
|
|
11
|
+
export let getMetaWebhookVerificationResponse = (
|
|
12
|
+
request: Request,
|
|
13
|
+
expectedVerifyToken: string | undefined
|
|
14
|
+
): SlateWebhookHttpResponseInit | null => {
|
|
15
|
+
if (request.method !== 'GET') return null;
|
|
16
|
+
|
|
17
|
+
let url = new URL(request.url);
|
|
18
|
+
let mode = url.searchParams.get('hub.mode');
|
|
19
|
+
let verifyToken = url.searchParams.get('hub.verify_token');
|
|
20
|
+
let challenge = url.searchParams.get('hub.challenge');
|
|
21
|
+
|
|
22
|
+
if (mode !== 'subscribe' || challenge === null) {
|
|
23
|
+
return {
|
|
24
|
+
status: 400,
|
|
25
|
+
headers: { 'content-type': 'text/plain' },
|
|
26
|
+
body: 'invalid webhook verification request'
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (expectedVerifyToken !== undefined && verifyToken !== expectedVerifyToken) {
|
|
31
|
+
return {
|
|
32
|
+
status: 403,
|
|
33
|
+
headers: { 'content-type': 'text/plain' },
|
|
34
|
+
body: 'invalid verify token'
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
status: 200,
|
|
40
|
+
headers: { 'content-type': 'text/plain' },
|
|
41
|
+
body: challenge
|
|
42
|
+
};
|
|
43
|
+
};
|
package/dist/action/action.d.ts
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { SlateContext } from '../context';
|
|
3
|
-
import { SlateSpecification } from '../specification/specification';
|
|
4
|
-
export type SlateActionType = 'tool' | 'trigger';
|
|
5
|
-
export interface SlateActionParameters {
|
|
6
|
-
key: string;
|
|
7
|
-
name: string;
|
|
8
|
-
description?: string;
|
|
9
|
-
instructions?: string[];
|
|
10
|
-
constraints?: string[];
|
|
11
|
-
tags?: {
|
|
12
|
-
destructive?: boolean;
|
|
13
|
-
readOnly?: boolean;
|
|
14
|
-
[key: string]: boolean | undefined;
|
|
15
|
-
};
|
|
16
|
-
metadata?: Record<string, any>;
|
|
17
|
-
}
|
|
18
|
-
export type SlateToolInvocationHandler<ConfigType extends {}, AuthType extends {}, InputType extends {}, OutputType extends {}> = (context: SlateContext<ConfigType, AuthType, InputType>) => Promise<{
|
|
19
|
-
output: OutputType;
|
|
20
|
-
message: string;
|
|
21
|
-
}>;
|
|
22
|
-
export type SlateTriggerMappingHandler<ConfigType extends {}, AuthType extends {}, InputType extends {}, OutputType extends {}> = (context: SlateContext<ConfigType, AuthType, InputType>) => Promise<{
|
|
23
|
-
type: string;
|
|
24
|
-
id: string;
|
|
25
|
-
output: OutputType;
|
|
26
|
-
}>;
|
|
27
|
-
export type SlateTriggerPollingHandler<ConfigType extends {}, AuthType extends {}, InputType extends {}> = (context: SlateContext<ConfigType, AuthType, {
|
|
28
|
-
state: any | null;
|
|
29
|
-
}>) => Promise<{
|
|
30
|
-
inputs: InputType[];
|
|
31
|
-
updatedState?: any;
|
|
32
|
-
}>;
|
|
33
|
-
export type SlateTriggerWebhookRequestHandler<ConfigType extends {}, AuthType extends {}, InputType extends {}> = (context: SlateContext<ConfigType, AuthType, {
|
|
34
|
-
request: Request;
|
|
35
|
-
state: any | null;
|
|
36
|
-
}>) => Promise<{
|
|
37
|
-
inputs: InputType[];
|
|
38
|
-
updatedState?: any;
|
|
39
|
-
}>;
|
|
40
|
-
export type SlateTriggerWebhookAutoRegistrationHandler<ConfigType extends {}, AuthType extends {}> = (context: SlateContext<ConfigType, AuthType, {
|
|
41
|
-
webhookBaseUrl: string;
|
|
42
|
-
}>) => Promise<{
|
|
43
|
-
registrationDetails: any;
|
|
44
|
-
state?: any;
|
|
45
|
-
}>;
|
|
46
|
-
export type SlateTriggerWebhookAutoUnregistrationHandler<ConfigType extends {}, AuthType extends {}> = (context: SlateContext<ConfigType, AuthType, {
|
|
47
|
-
webhookBaseUrl: string;
|
|
48
|
-
registrationDetails: any;
|
|
49
|
-
state: any | null;
|
|
50
|
-
}>) => Promise<unknown>;
|
|
51
|
-
export interface SlateActionParametersTool<ConfigType extends {}, AuthType extends {}, InputType extends {}, OutputType extends {}> {
|
|
52
|
-
type: 'tool';
|
|
53
|
-
handleInvocation: SlateToolInvocationHandler<ConfigType, AuthType, InputType, OutputType>;
|
|
54
|
-
}
|
|
55
|
-
export interface SlatePollingOptions {
|
|
56
|
-
intervalInSeconds?: number;
|
|
57
|
-
}
|
|
58
|
-
export interface SlateActionParametersTrigger<ConfigType extends {}, AuthType extends {}, InputType extends {}, OutputType extends {}> {
|
|
59
|
-
type: 'trigger';
|
|
60
|
-
source: 'polling' | 'webhook';
|
|
61
|
-
polling?: SlatePollingOptions;
|
|
62
|
-
handleEvent: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
|
|
63
|
-
handleRequest?: SlateTriggerWebhookRequestHandler<ConfigType, AuthType, InputType>;
|
|
64
|
-
pollEvents?: SlateTriggerPollingHandler<ConfigType, AuthType, InputType>;
|
|
65
|
-
autoRegisterWebhook?: SlateTriggerWebhookAutoRegistrationHandler<ConfigType, AuthType>;
|
|
66
|
-
autoUnregisterWebhook?: SlateTriggerWebhookAutoUnregistrationHandler<ConfigType, AuthType>;
|
|
67
|
-
}
|
|
68
|
-
export type SlateActionParametersAny<ConfigType extends {}, AuthType extends {}, InputType extends {}, OutputType extends {}> = SlateActionParametersTool<ConfigType, AuthType, InputType, OutputType> | SlateActionParametersTrigger<ConfigType, AuthType, InputType, OutputType>;
|
|
69
|
-
export type SlateActionCreateParameters<ConfigType extends {}, AuthType extends {}, InputType extends {}, OutputType extends {}> = SlateActionParametersAny<ConfigType, AuthType, InputType, OutputType> & SlateActionParameters & {
|
|
70
|
-
configSchema: z.ZodType<ConfigType>;
|
|
71
|
-
authSchema: z.ZodType<AuthType>;
|
|
72
|
-
inputSchema: z.ZodType<InputType>;
|
|
73
|
-
outputSchema: z.ZodType<OutputType>;
|
|
74
|
-
};
|
|
75
|
-
export declare abstract class SlateAction<Type extends SlateActionType, ConfigType extends {}, AuthType extends {}, InputType extends {}, OutputType extends {}> {
|
|
76
|
-
readonly type: Type;
|
|
77
|
-
protected readonly _spec: SlateSpecification<ConfigType, AuthType>;
|
|
78
|
-
protected readonly _inputSchema: z.ZodType<InputType>;
|
|
79
|
-
protected readonly _outputSchema: z.ZodType<OutputType>;
|
|
80
|
-
protected readonly _params: SlateActionParameters;
|
|
81
|
-
constructor(type: Type, _spec: SlateSpecification<ConfigType, AuthType>, _inputSchema: z.ZodType<InputType>, _outputSchema: z.ZodType<OutputType>, _params: SlateActionParameters);
|
|
82
|
-
get configSchema(): z.ZodType<ConfigType, unknown, z.core.$ZodTypeInternals<ConfigType, unknown>>;
|
|
83
|
-
get inputSchema(): z.ZodType<InputType, unknown, z.core.$ZodTypeInternals<InputType, unknown>>;
|
|
84
|
-
get outputSchema(): z.ZodType<OutputType, unknown, z.core.$ZodTypeInternals<OutputType, unknown>>;
|
|
85
|
-
get parameters(): SlateActionParameters;
|
|
86
|
-
get key(): string;
|
|
87
|
-
get name(): string;
|
|
88
|
-
get description(): string | undefined;
|
|
89
|
-
get tags(): {
|
|
90
|
-
[key: string]: boolean | undefined;
|
|
91
|
-
destructive?: boolean;
|
|
92
|
-
readOnly?: boolean;
|
|
93
|
-
} | undefined;
|
|
94
|
-
get instructions(): string[] | undefined;
|
|
95
|
-
get constraints(): string[] | undefined;
|
|
96
|
-
get metadata(): Record<string, any> | undefined;
|
|
97
|
-
}
|
|
98
|
-
//# sourceMappingURL=action.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/action/action.ts"],"names":[],"mappings":"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"}
|