@hostwebhook/node-types 1.52.3 → 1.52.5
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/connections.js +6 -6
- package/dist/discord-operations.d.ts +51 -1
- package/dist/discord-operations.js +310 -2
- package/dist/dispatch.js +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/registry.js +8 -8
- package/dist/types.d.ts +5 -5
- package/dist/ui.js +4 -4
- package/package.json +1 -1
package/dist/connections.js
CHANGED
|
@@ -16,13 +16,13 @@ exports.isTerminal = isTerminal;
|
|
|
16
16
|
exports.isNodeType = isNodeType;
|
|
17
17
|
/** All node types that can appear as pipeline outputs */
|
|
18
18
|
const PROCESSING_OUTPUTS = [
|
|
19
|
-
'
|
|
19
|
+
'webhook', 'router', 'filter', 'transform', 'cache', 'code', 'rateLimiter',
|
|
20
20
|
'aggregator', 'conditional', 'delay', 'schemaValidator', 'split', 'markdown', 'fileTransform', 'limit',
|
|
21
21
|
'emailAction', 'httpAction', 'mongoAction', 'postgresAction', 'notificationAction', 'sheetsAction', 'calendarAction', 'docsAction', 'driveAction', 'firecrawlAction', 'telegramAction', 'whatsappAction', 'discordAction', 'slackAction', 'googleContactsAction', 'vectorStore', 'rssAction', 'socialMediaAction', 'loop',
|
|
22
22
|
];
|
|
23
23
|
/** Standard processing input sources */
|
|
24
24
|
const STANDARD_INPUTS = [
|
|
25
|
-
'
|
|
25
|
+
'webhook', 'scheduledWorkflow', 'serviceTrigger', 'voiceAgent', 'router', 'filter', 'transform',
|
|
26
26
|
'cache', 'code', 'rateLimiter', 'aggregator', 'conditional', 'delay', 'schemaValidator', 'split', 'loop', 'markdown', 'fileTransform', 'limit',
|
|
27
27
|
];
|
|
28
28
|
/** Action nodes that can chain (non-terminal) */
|
|
@@ -31,8 +31,8 @@ const CHAINABLE_ACTIONS = ['httpAction', 'mongoAction', 'postgresAction', 'sheet
|
|
|
31
31
|
const ACTION_INPUTS = [...STANDARD_INPUTS, ...CHAINABLE_ACTIONS];
|
|
32
32
|
exports.NODE_CONNECTIONS = {
|
|
33
33
|
// ── Source nodes ──
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
webhook: { acceptsInputFrom: [], canOutputTo: PROCESSING_OUTPUTS },
|
|
35
|
+
scheduledWorkflow: { acceptsInputFrom: [], canOutputTo: PROCESSING_OUTPUTS },
|
|
36
36
|
chatTrigger: { acceptsInputFrom: [], canOutputTo: PROCESSING_OUTPUTS },
|
|
37
37
|
serviceTrigger: { acceptsInputFrom: [], canOutputTo: PROCESSING_OUTPUTS },
|
|
38
38
|
voiceAgent: { acceptsInputFrom: [], canOutputTo: PROCESSING_OUTPUTS },
|
|
@@ -57,10 +57,10 @@ exports.NODE_CONNECTIONS = {
|
|
|
57
57
|
// approval is the generic "human-in-the-loop gate" — it should be
|
|
58
58
|
// able to gate ANY action, not the hand-picked subset that existed
|
|
59
59
|
// when this entry was last touched. Same staleness pattern as merge.
|
|
60
|
-
approval: { acceptsInputFrom: ['
|
|
60
|
+
approval: { acceptsInputFrom: ['webhook', 'filter', 'transform'], canOutputTo: ['webhook', 'filter', 'transform', 'emailAction', 'httpAction', 'mongoAction', 'postgresAction', 'notificationAction', 'sheetsAction', 'calendarAction', 'docsAction', 'driveAction', 'firecrawlAction', 'telegramAction', 'whatsappAction', 'discordAction', 'slackAction', 'googleContactsAction', 'vectorStore'], special: { hasRejectionOutputNodes: true } },
|
|
61
61
|
loop: { acceptsInputFrom: STANDARD_INPUTS, canOutputTo: PROCESSING_OUTPUTS, special: { hasLoopBack: true } },
|
|
62
62
|
// ── Routing nodes ──
|
|
63
|
-
router: { acceptsInputFrom: ['
|
|
63
|
+
router: { acceptsInputFrom: ['webhook', 'scheduledWorkflow', 'filter', 'transform'], canOutputTo: PROCESSING_OUTPUTS.filter(t => t !== 'webhook') },
|
|
64
64
|
// ── Action nodes ──
|
|
65
65
|
emailAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
66
66
|
httpAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* API, Dashboard, and any future consumers (Message Broker, MCP server).
|
|
4
4
|
* Used by:
|
|
5
5
|
* - discordAction entity / DTO (api): operation field + validation
|
|
6
|
-
* - dashboard DiscordAction operation picker
|
|
6
|
+
* - dashboard DiscordAction operation picker + form generation
|
|
7
7
|
* - MCP toolkit-specs expansion (one aiEnabled discordAction → N tools)
|
|
8
8
|
*
|
|
9
9
|
* Targets Discord API v10 (the current stable as of 2026). Each op maps
|
|
@@ -21,3 +21,53 @@ export declare const DISCORD_OPERATIONS: readonly ["sendMessage", "editMessage",
|
|
|
21
21
|
export type DiscordOperation = (typeof DISCORD_OPERATIONS)[number];
|
|
22
22
|
/** Type guard — useful when validating untrusted input (DTOs, tool calls). */
|
|
23
23
|
export declare function isDiscordOperation(value: unknown): value is DiscordOperation;
|
|
24
|
+
export interface DiscordParamSpec {
|
|
25
|
+
/** Field key — also the property name on operationConfig / payload. */
|
|
26
|
+
name: string;
|
|
27
|
+
/** UI label. Carries the "(optional)" suffix when the form shows one. */
|
|
28
|
+
label: string;
|
|
29
|
+
/**
|
|
30
|
+
* Param type for form rendering + AI tool schema.
|
|
31
|
+
*
|
|
32
|
+
* `channel`, `string`, `text`, `number`, `boolean` and `emoji` mean the same
|
|
33
|
+
* as in SlackParamSpec. `guild`, `role`, `member` and `select` are Discord's
|
|
34
|
+
* own: the first three map to its resource pickers, and `select` is a fixed
|
|
35
|
+
* option list (channel kind, thread kind, archive window) that Slack has no
|
|
36
|
+
* equivalent for.
|
|
37
|
+
*/
|
|
38
|
+
type: 'channel' | 'guild' | 'role' | 'member' | 'string' | 'text' | 'number' | 'boolean' | 'emoji' | 'select';
|
|
39
|
+
/** Required at submit time. */
|
|
40
|
+
required?: boolean;
|
|
41
|
+
/** Human description — also used as the AI tool param description. */
|
|
42
|
+
description: string;
|
|
43
|
+
/** Hint shown inside the input. */
|
|
44
|
+
placeholder?: string;
|
|
45
|
+
/** Value to show when the stored one is undefined. */
|
|
46
|
+
default?: string | number | boolean;
|
|
47
|
+
/** `select` only — the fixed option list, in display order. */
|
|
48
|
+
options?: Array<{
|
|
49
|
+
value: string | number;
|
|
50
|
+
label: string;
|
|
51
|
+
}>;
|
|
52
|
+
/** `number` only. */
|
|
53
|
+
min?: number;
|
|
54
|
+
max?: number;
|
|
55
|
+
/** `text` only — height of the textarea. */
|
|
56
|
+
rows?: number;
|
|
57
|
+
/** `channel` only — let categories be picked, for parent-category fields. */
|
|
58
|
+
allowCategories?: boolean;
|
|
59
|
+
/** `boolean` only — the bold line beside the switch. */
|
|
60
|
+
switchLabel?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface DiscordOperationSpec {
|
|
63
|
+
/** UI label for the operation picker. */
|
|
64
|
+
label: string;
|
|
65
|
+
/** Description shown in the picker + reused by the AI tool description
|
|
66
|
+
* when the user hasn't set a custom one on the entity. */
|
|
67
|
+
description: string;
|
|
68
|
+
/** Route the operation maps to in Discord's docs (discord.com/developers). */
|
|
69
|
+
apiMethod: string;
|
|
70
|
+
/** Parameter schema. Order matters for form rendering. */
|
|
71
|
+
params: DiscordParamSpec[];
|
|
72
|
+
}
|
|
73
|
+
export declare const DISCORD_OPERATION_SPECS: Record<DiscordOperation, DiscordOperationSpec>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DISCORD_OPERATIONS = void 0;
|
|
3
|
+
exports.DISCORD_OPERATION_SPECS = exports.DISCORD_OPERATIONS = void 0;
|
|
4
4
|
exports.isDiscordOperation = isDiscordOperation;
|
|
5
5
|
/**
|
|
6
6
|
* Discord Bot API operation enum — single source of truth across the
|
|
7
7
|
* API, Dashboard, and any future consumers (Message Broker, MCP server).
|
|
8
8
|
* Used by:
|
|
9
9
|
* - discordAction entity / DTO (api): operation field + validation
|
|
10
|
-
* - dashboard DiscordAction operation picker
|
|
10
|
+
* - dashboard DiscordAction operation picker + form generation
|
|
11
11
|
* - MCP toolkit-specs expansion (one aiEnabled discordAction → N tools)
|
|
12
12
|
*
|
|
13
13
|
* Targets Discord API v10 (the current stable as of 2026). Each op maps
|
|
@@ -50,3 +50,311 @@ function isDiscordOperation(value) {
|
|
|
50
50
|
return (typeof value === 'string' &&
|
|
51
51
|
exports.DISCORD_OPERATIONS.includes(value));
|
|
52
52
|
}
|
|
53
|
+
/* Fields several operations share. Each takes overrides because the same key
|
|
54
|
+
can want different wording per operation: messageId is a required "Message
|
|
55
|
+
ID" in six ops and an optional anchor in createThread. */
|
|
56
|
+
const channelId = (over = {}) => ({
|
|
57
|
+
name: 'channelId',
|
|
58
|
+
label: 'Channel ID',
|
|
59
|
+
type: 'channel',
|
|
60
|
+
required: true,
|
|
61
|
+
placeholder: '{{payload.channelId}}',
|
|
62
|
+
description: 'Snowflake of the channel. The picker auto-discovers the channels the bot can see; a template such as {{payload.channelId}} works too.',
|
|
63
|
+
...over,
|
|
64
|
+
});
|
|
65
|
+
const guildId = (over = {}) => ({
|
|
66
|
+
name: 'guildId',
|
|
67
|
+
label: 'Guild ID',
|
|
68
|
+
type: 'guild',
|
|
69
|
+
required: true,
|
|
70
|
+
description: 'Snowflake of the server. The picker auto-discovers the servers the bot belongs to; a template such as {{payload.guildId}} works too.',
|
|
71
|
+
...over,
|
|
72
|
+
});
|
|
73
|
+
const messageId = (over = {}) => ({
|
|
74
|
+
name: 'messageId',
|
|
75
|
+
label: 'Message ID',
|
|
76
|
+
type: 'string',
|
|
77
|
+
required: true,
|
|
78
|
+
placeholder: '{{payload.messageId}}',
|
|
79
|
+
description: 'Snowflake of the message.',
|
|
80
|
+
...over,
|
|
81
|
+
});
|
|
82
|
+
const userId = (over = {}) => ({
|
|
83
|
+
name: 'userId',
|
|
84
|
+
label: 'User ID',
|
|
85
|
+
type: 'member',
|
|
86
|
+
required: true,
|
|
87
|
+
description: 'Snowflake of the user. Listing members needs the Server Members Intent enabled in Developer Portal.',
|
|
88
|
+
...over,
|
|
89
|
+
});
|
|
90
|
+
const roleId = (over = {}) => ({
|
|
91
|
+
name: 'roleId',
|
|
92
|
+
label: 'Role ID',
|
|
93
|
+
type: 'role',
|
|
94
|
+
required: true,
|
|
95
|
+
description: 'Snowflake of the role. The role of the bot itself must sit above the target role in the hierarchy for grant and remove to work.',
|
|
96
|
+
...over,
|
|
97
|
+
});
|
|
98
|
+
const emoji = () => ({
|
|
99
|
+
name: 'emoji',
|
|
100
|
+
label: 'Emoji',
|
|
101
|
+
type: 'emoji',
|
|
102
|
+
required: true,
|
|
103
|
+
placeholder: 'name:id',
|
|
104
|
+
description: 'Unicode emoji, or a custom server emoji written as name:id. URL-encoding is handled.',
|
|
105
|
+
});
|
|
106
|
+
const content = () => ({
|
|
107
|
+
name: 'content',
|
|
108
|
+
label: 'Message content',
|
|
109
|
+
type: 'text',
|
|
110
|
+
required: true,
|
|
111
|
+
rows: 4,
|
|
112
|
+
placeholder: 'Hello! Anything I can help with?',
|
|
113
|
+
description: 'Message text. Markdown is supported, up to the 2000 characters Discord allows.',
|
|
114
|
+
});
|
|
115
|
+
const topic = (label) => ({
|
|
116
|
+
name: 'topic',
|
|
117
|
+
label,
|
|
118
|
+
type: 'text',
|
|
119
|
+
rows: 2,
|
|
120
|
+
placeholder: label.startsWith('New') ? 'New description' : 'Channel description',
|
|
121
|
+
description: 'Channel description, shown under its name in Discord.',
|
|
122
|
+
});
|
|
123
|
+
const slowmode = (label) => ({
|
|
124
|
+
name: 'slowmode',
|
|
125
|
+
label,
|
|
126
|
+
type: 'number',
|
|
127
|
+
min: 0,
|
|
128
|
+
max: 21600,
|
|
129
|
+
default: 0,
|
|
130
|
+
description: 'Seconds a member has to wait between messages. 0 turns slowmode off, 21600 is the six-hour maximum.',
|
|
131
|
+
});
|
|
132
|
+
const parentId = (label) => ({
|
|
133
|
+
name: 'parentId',
|
|
134
|
+
label,
|
|
135
|
+
type: 'channel',
|
|
136
|
+
allowCategories: true,
|
|
137
|
+
placeholder: 'Snowflake of a category',
|
|
138
|
+
description: 'Category to nest the channel under. Categories show in the picker with a folder icon.',
|
|
139
|
+
});
|
|
140
|
+
exports.DISCORD_OPERATION_SPECS = {
|
|
141
|
+
// ── Messages ──────────────────────────────────────────────────────
|
|
142
|
+
sendMessage: {
|
|
143
|
+
label: 'Send message',
|
|
144
|
+
description: 'Post text/embed to a channel or thread. Optional reply-to + threadId.',
|
|
145
|
+
apiMethod: 'POST /channels/{channel.id}/messages',
|
|
146
|
+
params: [
|
|
147
|
+
channelId(),
|
|
148
|
+
content(),
|
|
149
|
+
{
|
|
150
|
+
name: 'replyToMessageId',
|
|
151
|
+
label: 'Reply to message ID (optional)',
|
|
152
|
+
type: 'string',
|
|
153
|
+
placeholder: '{{payload.messageId}}',
|
|
154
|
+
description: 'Snowflake of a message to quote-reply to.',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: 'threadId',
|
|
158
|
+
label: 'Thread ID (optional)',
|
|
159
|
+
type: 'string',
|
|
160
|
+
placeholder: '{{payload.threadId}}',
|
|
161
|
+
description: 'Thread snowflake. When set, the message is posted into that thread instead of the parent channel.',
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'interactionReply',
|
|
165
|
+
label: 'Reply inline to slash command',
|
|
166
|
+
type: 'boolean',
|
|
167
|
+
/* Absent means on: an action downstream of a slash command should
|
|
168
|
+
answer the command by default, so only an explicit false opts out.
|
|
169
|
+
Renderers must compare against false rather than coerce. */
|
|
170
|
+
default: true,
|
|
171
|
+
switchLabel: 'Auto-reply to slash commands (recommended)',
|
|
172
|
+
description: 'When the run came from a Discord slash command, replace the "Bot is thinking" spinner with this message instead of posting a separate one. Falls back to a normal channel post otherwise.',
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
editMessage: {
|
|
177
|
+
label: 'Edit message',
|
|
178
|
+
description: 'Edit content/embeds of a message the bot owns.',
|
|
179
|
+
apiMethod: 'PATCH /channels/{channel.id}/messages/{message.id}',
|
|
180
|
+
params: [channelId(), messageId(), content()],
|
|
181
|
+
},
|
|
182
|
+
deleteMessage: {
|
|
183
|
+
label: 'Delete message',
|
|
184
|
+
description: 'Delete by id. Messages from other users need Manage Messages.',
|
|
185
|
+
apiMethod: 'DELETE /channels/{channel.id}/messages/{message.id}',
|
|
186
|
+
params: [channelId(), messageId()],
|
|
187
|
+
},
|
|
188
|
+
getMessage: {
|
|
189
|
+
label: 'Get message',
|
|
190
|
+
description: 'Fetch a single message plus its reactions and attachments.',
|
|
191
|
+
apiMethod: 'GET /channels/{channel.id}/messages/{message.id}',
|
|
192
|
+
params: [channelId(), messageId()],
|
|
193
|
+
},
|
|
194
|
+
addReaction: {
|
|
195
|
+
label: 'Add reaction',
|
|
196
|
+
description: 'React as the bot. Custom emoji format: name:id.',
|
|
197
|
+
apiMethod: 'PUT /channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me',
|
|
198
|
+
params: [channelId(), messageId(), emoji()],
|
|
199
|
+
},
|
|
200
|
+
removeReaction: {
|
|
201
|
+
label: 'Remove reaction',
|
|
202
|
+
description: 'Remove the reaction the bot itself added.',
|
|
203
|
+
apiMethod: 'DELETE /channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me',
|
|
204
|
+
params: [channelId(), messageId(), emoji()],
|
|
205
|
+
},
|
|
206
|
+
pinMessage: {
|
|
207
|
+
label: 'Pin message',
|
|
208
|
+
description: 'Pin a message in its channel. Needs Manage Messages.',
|
|
209
|
+
apiMethod: 'PUT /channels/{channel.id}/pins/{message.id}',
|
|
210
|
+
params: [channelId(), messageId()],
|
|
211
|
+
},
|
|
212
|
+
// ── Channels ──────────────────────────────────────────────────────
|
|
213
|
+
createChannel: {
|
|
214
|
+
label: 'Create channel',
|
|
215
|
+
description: 'Create text/voice/forum/announcement/category in a guild.',
|
|
216
|
+
apiMethod: 'POST /guilds/{guild.id}/channels',
|
|
217
|
+
params: [
|
|
218
|
+
guildId(),
|
|
219
|
+
{
|
|
220
|
+
name: 'name',
|
|
221
|
+
label: 'Name',
|
|
222
|
+
type: 'string',
|
|
223
|
+
required: true,
|
|
224
|
+
placeholder: 'ticket-1234',
|
|
225
|
+
description: 'Name for the new channel.',
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: 'type',
|
|
229
|
+
label: 'Channel type',
|
|
230
|
+
type: 'select',
|
|
231
|
+
default: 'text',
|
|
232
|
+
description: 'Kind of channel to create.',
|
|
233
|
+
options: [
|
|
234
|
+
{ value: 'text', label: 'Text' },
|
|
235
|
+
{ value: 'voice', label: 'Voice' },
|
|
236
|
+
{ value: 'forum', label: 'Forum' },
|
|
237
|
+
{ value: 'announcement', label: 'Announcement' },
|
|
238
|
+
{ value: 'category', label: 'Category' },
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
parentId('Parent category (optional)'),
|
|
242
|
+
topic('Topic (optional)'),
|
|
243
|
+
slowmode('Slowmode seconds (optional)'),
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
editChannel: {
|
|
247
|
+
label: 'Edit channel',
|
|
248
|
+
description: 'Rename, change topic, slowmode, parent category.',
|
|
249
|
+
apiMethod: 'PATCH /channels/{channel.id}',
|
|
250
|
+
params: [
|
|
251
|
+
channelId(),
|
|
252
|
+
{
|
|
253
|
+
name: 'name',
|
|
254
|
+
label: 'New name (optional)',
|
|
255
|
+
type: 'string',
|
|
256
|
+
placeholder: 'renamed-channel',
|
|
257
|
+
description: 'Replacement channel name.',
|
|
258
|
+
},
|
|
259
|
+
topic('New topic (optional)'),
|
|
260
|
+
slowmode('New slowmode seconds (optional)'),
|
|
261
|
+
parentId('New parent category (optional)'),
|
|
262
|
+
],
|
|
263
|
+
},
|
|
264
|
+
deleteChannel: {
|
|
265
|
+
label: 'Delete channel',
|
|
266
|
+
description: 'Permanently deletes a channel — irreversible.',
|
|
267
|
+
apiMethod: 'DELETE /channels/{channel.id}',
|
|
268
|
+
params: [channelId()],
|
|
269
|
+
},
|
|
270
|
+
getChannel: {
|
|
271
|
+
label: 'Get channel',
|
|
272
|
+
description: 'Fetch the full config and permissions of a channel.',
|
|
273
|
+
apiMethod: 'GET /channels/{channel.id}',
|
|
274
|
+
params: [channelId()],
|
|
275
|
+
},
|
|
276
|
+
listChannels: {
|
|
277
|
+
label: 'List channels',
|
|
278
|
+
description: 'Iterate every channel in a guild — output is iterable.',
|
|
279
|
+
apiMethod: 'GET /guilds/{guild.id}/channels',
|
|
280
|
+
params: [guildId()],
|
|
281
|
+
},
|
|
282
|
+
// ── Threads ───────────────────────────────────────────────────────
|
|
283
|
+
createThread: {
|
|
284
|
+
label: 'Create thread',
|
|
285
|
+
description: 'Off a message OR standalone (public/private/announcement).',
|
|
286
|
+
apiMethod: 'POST /channels/{channel.id}/threads',
|
|
287
|
+
params: [
|
|
288
|
+
channelId(),
|
|
289
|
+
{
|
|
290
|
+
name: 'name',
|
|
291
|
+
label: 'Name',
|
|
292
|
+
type: 'string',
|
|
293
|
+
required: true,
|
|
294
|
+
placeholder: 'Conversation about issue',
|
|
295
|
+
description: 'Name for the new thread.',
|
|
296
|
+
},
|
|
297
|
+
messageId({
|
|
298
|
+
label: 'Anchor message ID (optional)',
|
|
299
|
+
required: false,
|
|
300
|
+
description: 'Snowflake of a message to spawn the thread from. Leave blank for a standalone thread.',
|
|
301
|
+
}),
|
|
302
|
+
{
|
|
303
|
+
name: 'type',
|
|
304
|
+
label: 'Thread type',
|
|
305
|
+
type: 'select',
|
|
306
|
+
default: 'public',
|
|
307
|
+
description: 'Thread visibility. Ignored when an anchor message is set, since the thread then inherits from its parent.',
|
|
308
|
+
options: [
|
|
309
|
+
{ value: 'public', label: 'Public' },
|
|
310
|
+
{ value: 'private', label: 'Private' },
|
|
311
|
+
{ value: 'announcement', label: 'Announcement' },
|
|
312
|
+
],
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
name: 'autoArchiveMinutes',
|
|
316
|
+
label: 'Auto-archive minutes',
|
|
317
|
+
type: 'select',
|
|
318
|
+
default: 1440,
|
|
319
|
+
description: 'Idle time before Discord archives the thread.',
|
|
320
|
+
options: [
|
|
321
|
+
{ value: 60, label: '1 hour' },
|
|
322
|
+
{ value: 1440, label: '24 hours (default)' },
|
|
323
|
+
{ value: 4320, label: '3 days' },
|
|
324
|
+
{ value: 10080, label: '1 week' },
|
|
325
|
+
],
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
// ── DMs ───────────────────────────────────────────────────────────
|
|
330
|
+
sendDM: {
|
|
331
|
+
label: 'Send DM',
|
|
332
|
+
description: 'Direct message a user by id. Silently dropped if DMs disabled.',
|
|
333
|
+
apiMethod: 'POST /users/@me/channels then POST /channels/{channel.id}/messages',
|
|
334
|
+
params: [
|
|
335
|
+
userId({
|
|
336
|
+
description: 'Snowflake of the user to DM. The bot needs a server in common with them.',
|
|
337
|
+
}),
|
|
338
|
+
content(),
|
|
339
|
+
],
|
|
340
|
+
},
|
|
341
|
+
// ── Members & roles ───────────────────────────────────────────────
|
|
342
|
+
addRole: {
|
|
343
|
+
label: 'Add role to member',
|
|
344
|
+
description: 'The role of the bot must be ABOVE the target role in the hierarchy.',
|
|
345
|
+
apiMethod: 'PUT /guilds/{guild.id}/members/{user.id}/roles/{role.id}',
|
|
346
|
+
params: [guildId(), userId(), roleId()],
|
|
347
|
+
},
|
|
348
|
+
removeRole: {
|
|
349
|
+
label: 'Remove role from member',
|
|
350
|
+
description: 'Same hierarchy rule applies.',
|
|
351
|
+
apiMethod: 'DELETE /guilds/{guild.id}/members/{user.id}/roles/{role.id}',
|
|
352
|
+
params: [guildId(), userId(), roleId()],
|
|
353
|
+
},
|
|
354
|
+
getMember: {
|
|
355
|
+
label: 'Get member',
|
|
356
|
+
description: 'Fetch the nick, roles, joined_at and user object of a member.',
|
|
357
|
+
apiMethod: 'GET /guilds/{guild.id}/members/{user.id}',
|
|
358
|
+
params: [guildId(), userId()],
|
|
359
|
+
},
|
|
360
|
+
};
|
package/dist/dispatch.js
CHANGED
|
@@ -14,7 +14,7 @@ exports.NODE_DISPATCH = void 0;
|
|
|
14
14
|
exports.getAllNodeCollections = getAllNodeCollections;
|
|
15
15
|
exports.getNodeDispatchConfig = getNodeDispatchConfig;
|
|
16
16
|
exports.NODE_DISPATCH = {
|
|
17
|
-
// ── Pipeline processing — generic dispatch off
|
|
17
|
+
// ── Pipeline processing — generic dispatch off webhook ──
|
|
18
18
|
filter: { service: 'filterNodesService', collection: 'filternodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic' },
|
|
19
19
|
transform: { service: 'transformNodesService', collection: 'transformnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic' },
|
|
20
20
|
code: { service: 'codeNodesService', collection: 'codenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
|
|
@@ -37,7 +37,7 @@ exports.NODE_DISPATCH = {
|
|
|
37
37
|
loop: { service: 'loopNodesService', collection: 'loopnodes', hasFilters: false, outputFields: ['loopOutputNodes', 'doneOutputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
|
|
38
38
|
// ── Routing — custom dispatch ──
|
|
39
39
|
router: { service: 'routersService', collection: 'routers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
|
|
40
|
-
// ── Action nodes — fired in onDeliveryResult, excluded from
|
|
40
|
+
// ── Action nodes — fired in onDeliveryResult, excluded from webhook dispatch ──
|
|
41
41
|
emailAction: { service: 'emailActionsService', collection: 'emailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
42
42
|
httpAction: { service: 'httpActionsService', collection: 'httpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
43
43
|
mongoAction: { service: 'mongoActionsService', collection: 'mongoactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
@@ -56,8 +56,8 @@ exports.NODE_DISPATCH = {
|
|
|
56
56
|
rssAction: { service: 'rssActionsService', collection: 'rssactions', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
57
57
|
socialMediaAction: { service: 'socialMediaActionsService', collection: 'socialmediaactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
58
58
|
// ── Sources — start the flow themselves, not dispatched ──
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
webhook: { service: 'webhooksService', collection: 'webhooks', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
60
|
+
scheduledWorkflow: { service: 'scheduledWorkflowsService', collection: 'scheduledworkflows', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
61
61
|
chatTrigger: { service: 'chatTriggersService', collection: 'chattriggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
62
62
|
serviceTrigger: { service: 'serviceTriggersService', collection: 'servicetriggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
63
63
|
voiceAgent: { service: 'voiceAgentsService', collection: 'voiceagents', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
package/dist/index.d.ts
CHANGED
|
@@ -15,8 +15,8 @@ export { TELEGRAM_OPERATIONS, isTelegramOperation, } from './telegram-operations
|
|
|
15
15
|
export type { TelegramOperation } from './telegram-operations';
|
|
16
16
|
export { WHATSAPP_OPERATIONS, isWhatsAppOperation, } from './whatsapp-operations';
|
|
17
17
|
export type { WhatsAppOperation } from './whatsapp-operations';
|
|
18
|
-
export { DISCORD_OPERATIONS, isDiscordOperation, } from './discord-operations';
|
|
19
|
-
export type { DiscordOperation } from './discord-operations';
|
|
18
|
+
export { DISCORD_OPERATIONS, DISCORD_OPERATION_SPECS, isDiscordOperation, } from './discord-operations';
|
|
19
|
+
export type { DiscordOperation, DiscordParamSpec, DiscordOperationSpec, } from './discord-operations';
|
|
20
20
|
export { SLACK_OPERATIONS, SLACK_OPERATION_SPECS, isSlackOperation, } from './slack-operations';
|
|
21
21
|
export type { SlackOperation, SlackParamSpec, SlackOperationSpec, } from './slack-operations';
|
|
22
22
|
export { GOOGLE_CONTACTS_OPERATIONS, GOOGLE_CONTACTS_OPERATIONS_V1, GOOGLE_CONTACTS_OPERATIONS_V2, isGoogleContactsOperation, } from './google-contacts-operations';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isCredentialType = exports.getCredentialType = exports.credentialTypeValues = exports.CREDENTIAL_TYPE_VALUES = exports.CREDENTIAL_TYPES = exports.isGoogleContactsOperation = exports.GOOGLE_CONTACTS_OPERATIONS_V2 = exports.GOOGLE_CONTACTS_OPERATIONS_V1 = exports.GOOGLE_CONTACTS_OPERATIONS = exports.isSlackOperation = exports.SLACK_OPERATION_SPECS = exports.SLACK_OPERATIONS = exports.isDiscordOperation = exports.DISCORD_OPERATIONS = exports.isWhatsAppOperation = exports.WHATSAPP_OPERATIONS = exports.isTelegramOperation = exports.TELEGRAM_OPERATIONS = exports.isDriveOperation = exports.DRIVE_OPERATIONS = exports.isGoogleCalendarOperation = exports.GOOGLE_CALENDAR_OPERATIONS = exports.isGmailOperation = exports.GMAIL_OPERATIONS = exports.NODE_TYPE_TO_PREFIX = exports.PREFIX_TO_NODE_TYPE = exports.NODE_STATE_KEYS = exports.NODE_COLORS = exports.NODE_DETAIL_PATHS = exports.getNodeRegistryEntry = exports.NODE_REGISTRY = exports.getNodeDispatchConfig = exports.getAllNodeCollections = exports.NODE_DISPATCH = exports.resolveNodeId = exports.PREFIX_TO_TYPE = exports.NODE_UI = exports.ALL_NODE_TYPES = exports.isNodeType = exports.isTerminal = exports.canSendToNodes = exports.canReceiveFromNodes = exports.canReceiveFrom = exports.NODE_CONNECTIONS = exports.iterableMeta = exports.singleMeta = void 0;
|
|
3
|
+
exports.isCredentialType = exports.getCredentialType = exports.credentialTypeValues = exports.CREDENTIAL_TYPE_VALUES = exports.CREDENTIAL_TYPES = exports.isGoogleContactsOperation = exports.GOOGLE_CONTACTS_OPERATIONS_V2 = exports.GOOGLE_CONTACTS_OPERATIONS_V1 = exports.GOOGLE_CONTACTS_OPERATIONS = exports.isSlackOperation = exports.SLACK_OPERATION_SPECS = exports.SLACK_OPERATIONS = exports.isDiscordOperation = exports.DISCORD_OPERATION_SPECS = exports.DISCORD_OPERATIONS = exports.isWhatsAppOperation = exports.WHATSAPP_OPERATIONS = exports.isTelegramOperation = exports.TELEGRAM_OPERATIONS = exports.isDriveOperation = exports.DRIVE_OPERATIONS = exports.isGoogleCalendarOperation = exports.GOOGLE_CALENDAR_OPERATIONS = exports.isGmailOperation = exports.GMAIL_OPERATIONS = exports.NODE_TYPE_TO_PREFIX = exports.PREFIX_TO_NODE_TYPE = exports.NODE_STATE_KEYS = exports.NODE_COLORS = exports.NODE_DETAIL_PATHS = exports.getNodeRegistryEntry = exports.NODE_REGISTRY = exports.getNodeDispatchConfig = exports.getAllNodeCollections = exports.NODE_DISPATCH = exports.resolveNodeId = exports.PREFIX_TO_TYPE = exports.NODE_UI = exports.ALL_NODE_TYPES = exports.isNodeType = exports.isTerminal = exports.canSendToNodes = exports.canReceiveFromNodes = exports.canReceiveFrom = exports.NODE_CONNECTIONS = exports.iterableMeta = exports.singleMeta = void 0;
|
|
4
4
|
var types_1 = require("./types");
|
|
5
5
|
Object.defineProperty(exports, "singleMeta", { enumerable: true, get: function () { return types_1.singleMeta; } });
|
|
6
6
|
Object.defineProperty(exports, "iterableMeta", { enumerable: true, get: function () { return types_1.iterableMeta; } });
|
|
@@ -49,6 +49,7 @@ Object.defineProperty(exports, "WHATSAPP_OPERATIONS", { enumerable: true, get: f
|
|
|
49
49
|
Object.defineProperty(exports, "isWhatsAppOperation", { enumerable: true, get: function () { return whatsapp_operations_1.isWhatsAppOperation; } });
|
|
50
50
|
var discord_operations_1 = require("./discord-operations");
|
|
51
51
|
Object.defineProperty(exports, "DISCORD_OPERATIONS", { enumerable: true, get: function () { return discord_operations_1.DISCORD_OPERATIONS; } });
|
|
52
|
+
Object.defineProperty(exports, "DISCORD_OPERATION_SPECS", { enumerable: true, get: function () { return discord_operations_1.DISCORD_OPERATION_SPECS; } });
|
|
52
53
|
Object.defineProperty(exports, "isDiscordOperation", { enumerable: true, get: function () { return discord_operations_1.isDiscordOperation; } });
|
|
53
54
|
var slack_operations_1 = require("./slack-operations");
|
|
54
55
|
Object.defineProperty(exports, "SLACK_OPERATIONS", { enumerable: true, get: function () { return slack_operations_1.SLACK_OPERATIONS; } });
|
package/dist/registry.js
CHANGED
|
@@ -11,16 +11,16 @@ exports.NODE_TYPE_TO_PREFIX = exports.PREFIX_TO_NODE_TYPE = exports.NODE_STATE_K
|
|
|
11
11
|
exports.getNodeRegistryEntry = getNodeRegistryEntry;
|
|
12
12
|
exports.NODE_REGISTRY = {
|
|
13
13
|
// ── Sources ──
|
|
14
|
-
|
|
15
|
-
type: '
|
|
16
|
-
group: 'Sources', detailPath: '/dashboard/
|
|
17
|
-
stateKey: '
|
|
14
|
+
webhook: {
|
|
15
|
+
type: 'webhook', prefix: 'wh', label: 'Webhook',
|
|
16
|
+
group: 'Sources', detailPath: '/dashboard/webhooks', apiPath: '/webhooks',
|
|
17
|
+
stateKey: 'webhooks', allStateKey: 'allWebhooks',
|
|
18
18
|
color: '#a78bfa', testable: false,
|
|
19
19
|
},
|
|
20
|
-
|
|
21
|
-
type: '
|
|
22
|
-
group: 'Sources', detailPath: '/dashboard/scheduled-
|
|
23
|
-
stateKey: '
|
|
20
|
+
scheduledWorkflow: {
|
|
21
|
+
type: 'scheduledWorkflow', prefix: 'swf', label: 'Scheduled Workflow',
|
|
22
|
+
group: 'Sources', detailPath: '/dashboard/scheduled-workflows', apiPath: '/scheduled-workflows',
|
|
23
|
+
stateKey: 'scheduledWorkflows', allStateKey: 'allScheduledWorkflows',
|
|
24
24
|
color: '#2dd4bf', testable: true,
|
|
25
25
|
},
|
|
26
26
|
chatTrigger: {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** All valid node type identifiers */
|
|
2
|
-
export type NodeType = '
|
|
2
|
+
export type NodeType = 'webhook' | 'scheduledWorkflow' | 'chatTrigger' | 'serviceTrigger' | 'voiceAgent' | 'filter' | 'transform' | 'schemaValidator' | 'conditional' | 'delay' | 'rateLimiter' | 'aggregator' | 'cache' | 'code' | 'ai' | 'merge' | 'approval' | 'split' | 'loop' | 'markdown' | 'fileTransform' | 'limit' | 'router' | 'emailAction' | 'httpAction' | 'mongoAction' | 'postgresAction' | 'notificationAction' | 'sheetsAction' | 'calendarAction' | 'docsAction' | 'driveAction' | 'firecrawlAction' | 'telegramAction' | 'whatsappAction' | 'discordAction' | 'slackAction' | 'googleContactsAction' | 'vectorStore' | 'rssAction' | 'socialMediaAction' | 'stickyNote';
|
|
3
3
|
/** Node role in the pipeline */
|
|
4
4
|
export type NodeRole = 'source' | 'processing' | 'flowControl' | 'routing' | 'action' | 'monitoring';
|
|
5
5
|
/** Handle positions on the canvas node */
|
|
@@ -94,12 +94,12 @@ export interface NodeUIConfig {
|
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* How the event pipeline routes a payload to this node when an
|
|
97
|
-
* upstream
|
|
97
|
+
* upstream webhook connects to it directly. Required so adding a
|
|
98
98
|
* new node type at compile time is impossible without picking one.
|
|
99
99
|
*
|
|
100
100
|
* - 'generic': dispatchConnectedNodes loops findActiveByInputEndpoint
|
|
101
101
|
* on the service and dispatches every active match. Use for
|
|
102
|
-
* pipeline-style nodes that ingest
|
|
102
|
+
* pipeline-style nodes that ingest webhook payloads (filter,
|
|
103
103
|
* transform, ai, code, markdown, fileTransform, vectorStore).
|
|
104
104
|
*
|
|
105
105
|
* - 'custom': has a dedicated `case` in the dispatchOutputNodes
|
|
@@ -109,10 +109,10 @@ export interface NodeUIConfig {
|
|
|
109
109
|
* loop, merge, approval, schemaValidator, router). The generic
|
|
110
110
|
* loop must NOT process these — would dispatch twice.
|
|
111
111
|
*
|
|
112
|
-
* - 'excluded': not dispatched in the
|
|
112
|
+
* - 'excluded': not dispatched in the webhook flow at all. Action
|
|
113
113
|
* nodes (email/http/mongo/notification/sheets/calendar/docs/
|
|
114
114
|
* firecrawl) are fired post-delivery in onDeliveryResult with
|
|
115
|
-
* their own loops; ingress nodes (
|
|
115
|
+
* their own loops; ingress nodes (webhook/scheduledWorkflow/
|
|
116
116
|
* chatTrigger/serviceTrigger) start the flow themselves;
|
|
117
117
|
* stickyNote is purely visual.
|
|
118
118
|
*/
|
package/dist/ui.js
CHANGED
|
@@ -8,8 +8,8 @@ exports.PREFIX_TO_TYPE = exports.NODE_UI = void 0;
|
|
|
8
8
|
exports.resolveNodeId = resolveNodeId;
|
|
9
9
|
exports.NODE_UI = {
|
|
10
10
|
// ── Source nodes ──
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
webhook: { fromNodes: true, toNodes: true, isSource: true },
|
|
12
|
+
scheduledWorkflow: { fromNodes: false, toNodes: true, isSource: true, outputHandles: ['right', 'bottom'], dotHandles: { output: ['right-out', 'bottom-out'] } },
|
|
13
13
|
chatTrigger: { fromNodes: false, toNodes: true, isSource: true, outputHandles: ['right'], dotHandles: { output: ['right-out'] } },
|
|
14
14
|
serviceTrigger: { fromNodes: false, toNodes: true, isSource: true, outputHandles: ['right', 'bottom'], dotHandles: { output: ['right-out', 'bottom-out'] } },
|
|
15
15
|
// Voice Agent: dynamicOutputs=true tells NodeShell to derive ONE
|
|
@@ -72,8 +72,8 @@ exports.NODE_UI = {
|
|
|
72
72
|
};
|
|
73
73
|
/** Canvas prefix → node type mapping (used by FlowCanvas to identify node type from XYFlow node ID) */
|
|
74
74
|
exports.PREFIX_TO_TYPE = [
|
|
75
|
-
{ prefix: '
|
|
76
|
-
{ prefix: '
|
|
75
|
+
{ prefix: 'wh-', type: 'webhook', canvasType: 'webhook' },
|
|
76
|
+
{ prefix: 'swf-', type: 'scheduledWorkflow', canvasType: 'scheduledWorkflow' },
|
|
77
77
|
{ prefix: 'chat-', type: 'chatTrigger', canvasType: 'chatTrigger' },
|
|
78
78
|
{ prefix: 'svc-', type: 'serviceTrigger', canvasType: 'serviceTrigger' },
|
|
79
79
|
{ prefix: 'va-', type: 'voiceAgent', canvasType: 'voiceAgent' },
|
package/package.json
CHANGED