@hostwebhook/node-types 1.36.0 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,7 +18,7 @@ exports.isNodeType = isNodeType;
18
18
  const PROCESSING_OUTPUTS = [
19
19
  'endpoint', 'router', 'filter', 'transform', 'cache', 'code', 'rateLimiter',
20
20
  'aggregator', 'conditional', 'delay', 'schemaValidator', 'split', 'markdown', 'fileTransform',
21
- 'emailAction', 'httpAction', 'mongoAction', 'postgresAction', 'notificationAction', 'sheetsAction', 'calendarAction', 'docsAction', 'driveAction', 'firecrawlAction', 'telegramAction', 'whatsappAction', 'discordAction', 'googleContactsAction', 'vectorStore', 'loop',
21
+ 'emailAction', 'httpAction', 'mongoAction', 'postgresAction', 'notificationAction', 'sheetsAction', 'calendarAction', 'docsAction', 'driveAction', 'firecrawlAction', 'telegramAction', 'whatsappAction', 'discordAction', 'slackAction', 'googleContactsAction', 'vectorStore', 'loop',
22
22
  ];
23
23
  /** Standard processing input sources */
24
24
  const STANDARD_INPUTS = [
@@ -26,7 +26,7 @@ const STANDARD_INPUTS = [
26
26
  'cache', 'code', 'rateLimiter', 'aggregator', 'conditional', 'delay', 'schemaValidator', 'split', 'loop', 'markdown', 'fileTransform',
27
27
  ];
28
28
  /** Action nodes that can chain (non-terminal) */
29
- const CHAINABLE_ACTIONS = ['httpAction', 'mongoAction', 'postgresAction', 'sheetsAction', 'calendarAction', 'docsAction', 'driveAction', 'firecrawlAction', 'telegramAction', 'whatsappAction', 'discordAction', 'googleContactsAction', 'vectorStore'];
29
+ const CHAINABLE_ACTIONS = ['httpAction', 'mongoAction', 'postgresAction', 'sheetsAction', 'calendarAction', 'docsAction', 'driveAction', 'firecrawlAction', 'telegramAction', 'whatsappAction', 'discordAction', 'slackAction', 'googleContactsAction', 'vectorStore'];
30
30
  /** Full input list for action nodes (standard + chainable actions) */
31
31
  const ACTION_INPUTS = [...STANDARD_INPUTS, ...CHAINABLE_ACTIONS];
32
32
  exports.NODE_CONNECTIONS = {
@@ -57,7 +57,7 @@ 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: ['endpoint', 'filter', 'transform'], canOutputTo: ['endpoint', 'filter', 'transform', 'emailAction', 'httpAction', 'mongoAction', 'postgresAction', 'notificationAction', 'sheetsAction', 'calendarAction', 'docsAction', 'driveAction', 'firecrawlAction', 'telegramAction', 'whatsappAction', 'discordAction', 'googleContactsAction', 'vectorStore'], special: { hasRejectionOutputNodes: true } },
60
+ approval: { acceptsInputFrom: ['endpoint', 'filter', 'transform'], canOutputTo: ['endpoint', '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
63
  router: { acceptsInputFrom: ['endpoint', 'scheduledWebhook', 'filter', 'transform'], canOutputTo: PROCESSING_OUTPUTS.filter(t => t !== 'endpoint') },
@@ -75,6 +75,7 @@ exports.NODE_CONNECTIONS = {
75
75
  telegramAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
76
76
  whatsappAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
77
77
  discordAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
78
+ slackAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
78
79
  googleContactsAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
79
80
  vectorStore: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
80
81
  // ── Processing (transform-like) ──
@@ -14,6 +14,7 @@ exports.CREDENTIAL_TYPES = [
14
14
  { type: 'mongodb', ssrfValidated: true, tunnelable: true },
15
15
  { type: 'postgres', ssrfValidated: true, tunnelable: true },
16
16
  { type: 'slack_webhook' },
17
+ { type: 'slack_oauth' },
17
18
  { type: 'discord_webhook' },
18
19
  { type: 'llm_anthropic' },
19
20
  { type: 'llm_openai' },
package/dist/dispatch.js CHANGED
@@ -50,6 +50,7 @@ exports.NODE_DISPATCH = {
50
50
  telegramAction: { service: 'telegramActionsService', collection: 'telegramactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
51
51
  whatsappAction: { service: 'whatsappActionsService', collection: 'whatsappactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
52
52
  discordAction: { service: 'discordActionsService', collection: 'discordactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
53
+ slackAction: { service: 'slackActionsService', collection: 'slackactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
53
54
  googleContactsAction: { service: 'googleContactsActionsService', collection: 'googlecontactsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
54
55
  // ── Sources — start the flow themselves, not dispatched ──
55
56
  endpoint: { service: 'endpointsService', collection: 'endpoints', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
package/dist/index.d.ts CHANGED
@@ -17,6 +17,8 @@ export { WHATSAPP_OPERATIONS, isWhatsAppOperation, } from './whatsapp-operations
17
17
  export type { WhatsAppOperation } from './whatsapp-operations';
18
18
  export { DISCORD_OPERATIONS, isDiscordOperation, } from './discord-operations';
19
19
  export type { DiscordOperation } from './discord-operations';
20
+ export { SLACK_OPERATIONS, SLACK_OPERATION_SPECS, isSlackOperation, } from './slack-operations';
21
+ export type { SlackOperation, SlackParamSpec, SlackOperationSpec, } from './slack-operations';
20
22
  export { GOOGLE_CONTACTS_OPERATIONS, GOOGLE_CONTACTS_OPERATIONS_V1, GOOGLE_CONTACTS_OPERATIONS_V2, isGoogleContactsOperation, } from './google-contacts-operations';
21
23
  export type { GoogleContactsOperation } from './google-contacts-operations';
22
24
  export type { CredentialTypeRegistration, CredentialType } from './credentials';
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.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_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; } });
@@ -50,6 +50,10 @@ Object.defineProperty(exports, "isWhatsAppOperation", { enumerable: true, get: f
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
52
  Object.defineProperty(exports, "isDiscordOperation", { enumerable: true, get: function () { return discord_operations_1.isDiscordOperation; } });
53
+ var slack_operations_1 = require("./slack-operations");
54
+ Object.defineProperty(exports, "SLACK_OPERATIONS", { enumerable: true, get: function () { return slack_operations_1.SLACK_OPERATIONS; } });
55
+ Object.defineProperty(exports, "SLACK_OPERATION_SPECS", { enumerable: true, get: function () { return slack_operations_1.SLACK_OPERATION_SPECS; } });
56
+ Object.defineProperty(exports, "isSlackOperation", { enumerable: true, get: function () { return slack_operations_1.isSlackOperation; } });
53
57
  var google_contacts_operations_1 = require("./google-contacts-operations");
54
58
  Object.defineProperty(exports, "GOOGLE_CONTACTS_OPERATIONS", { enumerable: true, get: function () { return google_contacts_operations_1.GOOGLE_CONTACTS_OPERATIONS; } });
55
59
  Object.defineProperty(exports, "GOOGLE_CONTACTS_OPERATIONS_V1", { enumerable: true, get: function () { return google_contacts_operations_1.GOOGLE_CONTACTS_OPERATIONS_V1; } });
package/dist/registry.js CHANGED
@@ -252,6 +252,20 @@ exports.NODE_REGISTRY = {
252
252
  // multi-op tool surface — the LLM picks the operation per call.
253
253
  isToolOnly: (e) => e.aiEnabled === true,
254
254
  },
255
+ slackAction: {
256
+ type: 'slackAction', prefix: 'sl', label: 'Slack Action',
257
+ group: 'Actions', detailPath: '/dashboard/slack-actions', apiPath: '/slack-actions',
258
+ stateKey: 'slackActions', allStateKey: 'allSlackActions',
259
+ // Slack brand purple ("aubergine"-derived family). Matches the
260
+ // accent color used by SlackConfigSection / ServiceTriggerNode for
261
+ // visual continuity across Slack-related nodes.
262
+ color: '#7c3aed', testable: true,
263
+ // Same AI-tool gating as Telegram/Discord/WhatsApp/Email/Calendar/
264
+ // Contacts. When aiEnabled the node fans out into 16 MCP tools
265
+ // (one per SLACK_OPERATIONS entry); hide canvas handles to prevent
266
+ // accidental wiring with empty fields the LLM is supposed to fill.
267
+ isToolOnly: (e) => e.aiEnabled === true,
268
+ },
255
269
  googleContactsAction: {
256
270
  type: 'googleContactsAction', prefix: 'gc', label: 'Google Contacts',
257
271
  group: 'Actions', detailPath: '/dashboard/google-contacts-actions', apiPath: '/google-contacts-actions',
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Slack Web API operation enum — single source of truth across the
3
+ * api, dashboard, and downstream consumers (Message Broker, MCP server).
4
+ * Used by:
5
+ * - slackAction entity / DTO (api): operation field + validation
6
+ * - dashboard SlackAction operation picker + form generation
7
+ * - MCP toolkit-specs expansion (one aiEnabled slackAction → N tools)
8
+ *
9
+ * v1 covers 16 ops — messaging, channel CRUD, members, reactions, files.
10
+ * Future additions (pin / unpin, files.list, conversations.archive, app
11
+ * publish, scheduled.list, etc.) extend this list — bump the package and
12
+ * re-install in consumers, same pattern as Gmail / Calendar / Discord.
13
+ */
14
+ export declare const SLACK_OPERATIONS: readonly ["sendMessage", "updateMessage", "deleteMessage", "sendEphemeral", "scheduleMessage", "getMessage", "listChannels", "getChannelHistory", "getThreadReplies", "createChannel", "inviteToChannel", "addReaction", "removeReaction", "listUsers", "getUserInfo", "uploadFile"];
15
+ export type SlackOperation = (typeof SLACK_OPERATIONS)[number];
16
+ /** Type guard — useful when validating untrusted input (DTOs, AI tool calls). */
17
+ export declare function isSlackOperation(value: unknown): value is SlackOperation;
18
+ /**
19
+ * Per-operation parameter schema. Drives:
20
+ * 1. Form auto-generation in the SlackAction detail page (dashboard).
21
+ * 2. AI tool argument schema when `aiEnabled === true`.
22
+ * 3. MCP tools/list expansion (one slackAction → N MCP tools).
23
+ *
24
+ * Field types kept narrow on purpose so the dashboard form picker can
25
+ * render the right control (channel-picker vs free text vs number).
26
+ * The api side `SlackOperationsService` accepts the same shapes.
27
+ */
28
+ export interface SlackParamSpec {
29
+ /** Field key — also the property name on operationConfig / payload. */
30
+ name: string;
31
+ /** UI label. */
32
+ label: string;
33
+ /** Param type for form rendering + AI tool schema. */
34
+ type: 'channel' | 'user' | 'string' | 'text' | 'number' | 'boolean' | 'emoji' | 'blocks' | 'json' | 'fileUrl';
35
+ /** Required at submit time. */
36
+ required?: boolean;
37
+ /** Human description — also used as the AI tool param description. */
38
+ description: string;
39
+ /** Hint shown under the input. */
40
+ placeholder?: string;
41
+ }
42
+ export interface SlackOperationSpec {
43
+ /** UI label for the operation picker. */
44
+ label: string;
45
+ /** Description shown in the picker + reused by the AI tool description
46
+ * when the user hasn't set a custom one on the entity. */
47
+ description: string;
48
+ /** Verb the operation maps to in Slack's docs (slack.com/methods/...). */
49
+ apiMethod: string;
50
+ /** Parameter schema. Order matters for form rendering. */
51
+ params: SlackParamSpec[];
52
+ }
53
+ export declare const SLACK_OPERATION_SPECS: Record<SlackOperation, SlackOperationSpec>;
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SLACK_OPERATION_SPECS = exports.SLACK_OPERATIONS = void 0;
4
+ exports.isSlackOperation = isSlackOperation;
5
+ /**
6
+ * Slack Web API operation enum — single source of truth across the
7
+ * api, dashboard, and downstream consumers (Message Broker, MCP server).
8
+ * Used by:
9
+ * - slackAction entity / DTO (api): operation field + validation
10
+ * - dashboard SlackAction operation picker + form generation
11
+ * - MCP toolkit-specs expansion (one aiEnabled slackAction → N tools)
12
+ *
13
+ * v1 covers 16 ops — messaging, channel CRUD, members, reactions, files.
14
+ * Future additions (pin / unpin, files.list, conversations.archive, app
15
+ * publish, scheduled.list, etc.) extend this list — bump the package and
16
+ * re-install in consumers, same pattern as Gmail / Calendar / Discord.
17
+ */
18
+ exports.SLACK_OPERATIONS = [
19
+ // Messages
20
+ 'sendMessage',
21
+ 'updateMessage',
22
+ 'deleteMessage',
23
+ 'sendEphemeral',
24
+ 'scheduleMessage',
25
+ 'getMessage',
26
+ // Channels
27
+ 'listChannels',
28
+ 'getChannelHistory',
29
+ 'getThreadReplies',
30
+ 'createChannel',
31
+ 'inviteToChannel',
32
+ // Reactions
33
+ 'addReaction',
34
+ 'removeReaction',
35
+ // Users
36
+ 'listUsers',
37
+ 'getUserInfo',
38
+ // Files
39
+ 'uploadFile',
40
+ ];
41
+ /** Type guard — useful when validating untrusted input (DTOs, AI tool calls). */
42
+ function isSlackOperation(value) {
43
+ return (typeof value === 'string' &&
44
+ exports.SLACK_OPERATIONS.includes(value));
45
+ }
46
+ exports.SLACK_OPERATION_SPECS = {
47
+ sendMessage: {
48
+ label: 'Send message',
49
+ description: 'Post a message to a channel, group, or DM.',
50
+ apiMethod: 'chat.postMessage',
51
+ params: [
52
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel id (C…) or DM id (D…) where the message will be posted.' },
53
+ { name: 'text', label: 'Text', type: 'text', description: 'Message text. Supports Slack mrkdwn. Required when blocks is empty.' },
54
+ { name: 'blocks', label: 'Blocks (optional)', type: 'blocks', description: 'Slack Block Kit JSON for rich layouts. Overrides text rendering when set.' },
55
+ { name: 'threadTs', label: 'Thread ts (optional)', type: 'string', description: 'When set, the message replies inside an existing thread. Use the parent message timestamp.' },
56
+ ],
57
+ },
58
+ updateMessage: {
59
+ label: 'Update message',
60
+ description: 'Edit a message the bot posted earlier.',
61
+ apiMethod: 'chat.update',
62
+ params: [
63
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel where the original message lives.' },
64
+ { name: 'ts', label: 'Message ts', type: 'string', required: true, description: 'Timestamp of the message to edit (returned by sendMessage).' },
65
+ { name: 'text', label: 'New text', type: 'text', description: 'Replacement text. Required when blocks is empty.' },
66
+ { name: 'blocks', label: 'New blocks (optional)', type: 'blocks', description: 'Replacement Block Kit layout.' },
67
+ ],
68
+ },
69
+ deleteMessage: {
70
+ label: 'Delete message',
71
+ description: 'Delete a message the bot posted earlier.',
72
+ apiMethod: 'chat.delete',
73
+ params: [
74
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel where the message lives.' },
75
+ { name: 'ts', label: 'Message ts', type: 'string', required: true, description: 'Timestamp of the message to delete.' },
76
+ ],
77
+ },
78
+ sendEphemeral: {
79
+ label: 'Send ephemeral',
80
+ description: 'Post a message visible only to a single user (the rest of the channel does not see it).',
81
+ apiMethod: 'chat.postEphemeral',
82
+ params: [
83
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel where the ephemeral message will appear.' },
84
+ { name: 'user', label: 'User', type: 'user', required: true, description: 'User id (U…) — only this user sees the message.' },
85
+ { name: 'text', label: 'Text', type: 'text', description: 'Message text. Required when blocks is empty.' },
86
+ { name: 'blocks', label: 'Blocks (optional)', type: 'blocks', description: 'Block Kit layout.' },
87
+ ],
88
+ },
89
+ scheduleMessage: {
90
+ label: 'Schedule message',
91
+ description: 'Schedule a message to be posted at a future time.',
92
+ apiMethod: 'chat.scheduleMessage',
93
+ params: [
94
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel where the scheduled message will be posted.' },
95
+ { name: 'postAt', label: 'Post at (unix sec)', type: 'number', required: true, description: 'When Slack should post the message — unix timestamp in seconds.' },
96
+ { name: 'text', label: 'Text', type: 'text', description: 'Message text. Required when blocks is empty.' },
97
+ { name: 'blocks', label: 'Blocks (optional)', type: 'blocks', description: 'Block Kit layout.' },
98
+ ],
99
+ },
100
+ getMessage: {
101
+ label: 'Get message',
102
+ description: 'Fetch a single message by its timestamp.',
103
+ apiMethod: 'conversations.history',
104
+ params: [
105
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel where the message lives.' },
106
+ { name: 'ts', label: 'Message ts', type: 'string', required: true, description: 'Timestamp of the message to fetch.' },
107
+ ],
108
+ },
109
+ listChannels: {
110
+ label: 'List channels',
111
+ description: 'List public + private channels the bot can see in the workspace.',
112
+ apiMethod: 'conversations.list',
113
+ params: [
114
+ { name: 'limit', label: 'Limit', type: 'number', description: 'Max channels to return (1-1000). Default 200.' },
115
+ { name: 'excludeArchived', label: 'Exclude archived', type: 'boolean', description: 'Hide archived channels. Default true.' },
116
+ ],
117
+ },
118
+ getChannelHistory: {
119
+ label: 'Get channel history',
120
+ description: 'Read recent messages from a channel.',
121
+ apiMethod: 'conversations.history',
122
+ params: [
123
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel to read from.' },
124
+ { name: 'limit', label: 'Limit', type: 'number', description: 'Max messages to return (1-200). Default 50.' },
125
+ { name: 'oldest', label: 'Oldest ts', type: 'string', description: 'Only messages after this timestamp.' },
126
+ { name: 'latest', label: 'Latest ts', type: 'string', description: 'Only messages before this timestamp.' },
127
+ ],
128
+ },
129
+ getThreadReplies: {
130
+ label: 'Get thread replies',
131
+ description: 'Fetch replies to a thread.',
132
+ apiMethod: 'conversations.replies',
133
+ params: [
134
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel where the thread lives.' },
135
+ { name: 'ts', label: 'Parent ts', type: 'string', required: true, description: 'Timestamp of the thread parent message.' },
136
+ { name: 'limit', label: 'Limit', type: 'number', description: 'Max replies to return (1-1000). Default 100.' },
137
+ ],
138
+ },
139
+ createChannel: {
140
+ label: 'Create channel',
141
+ description: 'Create a new public or private channel.',
142
+ apiMethod: 'conversations.create',
143
+ params: [
144
+ { name: 'name', label: 'Name', type: 'string', required: true, description: 'Channel name (lowercase, no spaces, < 80 chars).' },
145
+ { name: 'isPrivate', label: 'Private', type: 'boolean', description: 'Create a private channel instead of public. Default false.' },
146
+ ],
147
+ },
148
+ inviteToChannel: {
149
+ label: 'Invite to channel',
150
+ description: 'Invite one or more users to a channel.',
151
+ apiMethod: 'conversations.invite',
152
+ params: [
153
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel id to invite users to.' },
154
+ { name: 'users', label: 'Users', type: 'string', required: true, description: 'Comma-separated user ids (U…) to invite.' },
155
+ ],
156
+ },
157
+ addReaction: {
158
+ label: 'Add reaction',
159
+ description: 'Add an emoji reaction to a message.',
160
+ apiMethod: 'reactions.add',
161
+ params: [
162
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel where the message lives.' },
163
+ { name: 'ts', label: 'Message ts', type: 'string', required: true, description: 'Timestamp of the message to react to.' },
164
+ { name: 'name', label: 'Emoji name', type: 'emoji', required: true, description: 'Emoji name without colons (e.g. thumbsup, white_check_mark).' },
165
+ ],
166
+ },
167
+ removeReaction: {
168
+ label: 'Remove reaction',
169
+ description: 'Remove an emoji reaction from a message.',
170
+ apiMethod: 'reactions.remove',
171
+ params: [
172
+ { name: 'channel', label: 'Channel', type: 'channel', required: true, description: 'Channel where the message lives.' },
173
+ { name: 'ts', label: 'Message ts', type: 'string', required: true, description: 'Timestamp of the message.' },
174
+ { name: 'name', label: 'Emoji name', type: 'emoji', required: true, description: 'Emoji name without colons.' },
175
+ ],
176
+ },
177
+ listUsers: {
178
+ label: 'List users',
179
+ description: 'List human members of the workspace (excludes deleted users + bots by default).',
180
+ apiMethod: 'users.list',
181
+ params: [
182
+ { name: 'limit', label: 'Limit', type: 'number', description: 'Max users to return (1-1000). Default 200.' },
183
+ { name: 'includeDeleted', label: 'Include deleted', type: 'boolean', description: 'Include deactivated users. Default false.' },
184
+ { name: 'includeBots', label: 'Include bots', type: 'boolean', description: 'Include bot users + app users. Default false.' },
185
+ ],
186
+ },
187
+ getUserInfo: {
188
+ label: 'Get user info',
189
+ description: 'Fetch a user profile (name, email, timezone, status).',
190
+ apiMethod: 'users.info',
191
+ params: [
192
+ { name: 'user', label: 'User', type: 'user', required: true, description: 'User id (U…) to look up.' },
193
+ ],
194
+ },
195
+ uploadFile: {
196
+ label: 'Upload file',
197
+ description: 'Upload a file (PDF, image, anything) and optionally share it in a channel.',
198
+ apiMethod: 'files.uploadV2',
199
+ params: [
200
+ { name: 'url', label: 'File URL', type: 'fileUrl', description: 'Public URL or HW file _file.downloadUrl that HW will fetch and re-upload.' },
201
+ { name: 'contentBase64', label: 'File content (base64)', type: 'text', description: 'Inline file content as base64 — alternative to url for small payloads.' },
202
+ { name: 'filename', label: 'Filename', type: 'string', description: 'Display name in Slack. Auto-derived from URL when omitted.' },
203
+ { name: 'channel', label: 'Channel (optional)', type: 'channel', description: 'Channel to share the uploaded file in.' },
204
+ { name: 'title', label: 'Title (optional)', type: 'string', description: 'Title shown above the file in Slack.' },
205
+ { name: 'initialComment', label: 'Initial comment (optional)', type: 'text', description: 'Message Slack posts together with the file.' },
206
+ { name: 'threadTs', label: 'Thread ts (optional)', type: 'string', description: 'Attach the file to an existing thread.' },
207
+ ],
208
+ },
209
+ };
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** All valid node type identifiers */
2
- export type NodeType = 'endpoint' | 'scheduledWebhook' | 'chatTrigger' | 'serviceTrigger' | 'voiceAgent' | 'filter' | 'transform' | 'schemaValidator' | 'conditional' | 'delay' | 'rateLimiter' | 'aggregator' | 'cache' | 'code' | 'ai' | 'merge' | 'approval' | 'split' | 'loop' | 'markdown' | 'fileTransform' | 'router' | 'emailAction' | 'httpAction' | 'mongoAction' | 'postgresAction' | 'notificationAction' | 'sheetsAction' | 'calendarAction' | 'docsAction' | 'driveAction' | 'firecrawlAction' | 'telegramAction' | 'whatsappAction' | 'discordAction' | 'googleContactsAction' | 'vectorStore' | 'stickyNote';
2
+ export type NodeType = 'endpoint' | 'scheduledWebhook' | 'chatTrigger' | 'serviceTrigger' | 'voiceAgent' | 'filter' | 'transform' | 'schemaValidator' | 'conditional' | 'delay' | 'rateLimiter' | 'aggregator' | 'cache' | 'code' | 'ai' | 'merge' | 'approval' | 'split' | 'loop' | 'markdown' | 'fileTransform' | 'router' | 'emailAction' | 'httpAction' | 'mongoAction' | 'postgresAction' | 'notificationAction' | 'sheetsAction' | 'calendarAction' | 'docsAction' | 'driveAction' | 'firecrawlAction' | 'telegramAction' | 'whatsappAction' | 'discordAction' | 'slackAction' | 'googleContactsAction' | 'vectorStore' | '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 */
package/dist/ui.js CHANGED
@@ -52,6 +52,7 @@ exports.NODE_UI = {
52
52
  telegramAction: { fromNodes: true, toNodes: true, inputHandles: ['left'], dotHandles: { input: ['left-in'], output: ['right-out'] }, special: { loopBackAllowed: true, routerTargetLabel: 'telegram' } },
53
53
  whatsappAction: { fromNodes: true, toNodes: true, inputHandles: ['left'], dotHandles: { input: ['left-in'], output: ['right-out'] }, special: { loopBackAllowed: true, routerTargetLabel: 'whatsapp' } },
54
54
  discordAction: { fromNodes: true, toNodes: true, inputHandles: ['left'], dotHandles: { input: ['left-in'], output: ['right-out'] }, special: { loopBackAllowed: true, routerTargetLabel: 'discord' } },
55
+ slackAction: { fromNodes: true, toNodes: true, inputHandles: ['left'], dotHandles: { input: ['left-in'], output: ['right-out'] }, special: { loopBackAllowed: true, routerTargetLabel: 'slack' } },
55
56
  googleContactsAction: { fromNodes: true, toNodes: true, inputHandles: ['left'], dotHandles: { input: ['left-in'], output: ['right-out'] }, special: { loopBackAllowed: true } },
56
57
  vectorStore: { fromNodes: true, toNodes: true, inputHandles: ['left'], dotHandles: { input: ['left-in'], output: ['right-out'] }, special: { loopBackAllowed: true } },
57
58
  // ── Annotations ──
@@ -68,6 +69,7 @@ exports.PREFIX_TO_TYPE = [
68
69
  { prefix: 'tg-', type: 'telegramAction', canvasType: 'telegramAction' },
69
70
  { prefix: 'wa-', type: 'whatsappAction', canvasType: 'whatsappAction' },
70
71
  { prefix: 'dc-', type: 'discordAction', canvasType: 'discordAction' },
72
+ { prefix: 'sl-', type: 'slackAction', canvasType: 'slackAction' },
71
73
  { prefix: 'gc-', type: 'googleContactsAction', canvasType: 'googleContactsAction' },
72
74
  { prefix: 'ha-', type: 'httpAction', canvasType: 'httpAction' },
73
75
  { prefix: 'ma-', type: 'mongoAction', canvasType: 'mongoAction' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostwebhook/node-types",
3
- "version": "1.36.0",
3
+ "version": "1.38.0",
4
4
  "description": "Shared node type definitions, connection rules, and dispatch config for HostWebhook",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",