Skip to content

Commit 9ed8713

Browse files
authored
feat: add support to @slack/web-api for work objects (#2231)
1 parent 16bd88e commit 9ed8713

File tree

9 files changed

+181
-11
lines changed

9 files changed

+181
-11
lines changed

packages/web-api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
},
5050
"dependencies": {
5151
"@slack/logger": "^4.0.0",
52-
"@slack/types": "^2.17.0",
52+
"@slack/types": "^2.18.0",
5353
"@types/node": ">=18.0.0",
5454
"@types/retry": "0.12.0",
5555
"axios": "^1.11.0",

packages/web-api/src/methods.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ import type {
177177
DndSetSnoozeArguments,
178178
DndTeamInfoArguments,
179179
EmojiListArguments,
180+
EntityPresentDetailsArguments,
180181
FilesCommentsDeleteArguments,
181182
FilesCompleteUploadExternalArguments,
182183
FilesDeleteArguments,
@@ -437,6 +438,7 @@ import type {
437438
DndSetSnoozeResponse,
438439
DndTeamInfoResponse,
439440
EmojiListResponse,
441+
EntityPresentDetailsResponse,
440442
FilesCommentsDeleteResponse,
441443
FilesCompleteUploadExternalResponse,
442444
FilesDeleteResponse,
@@ -1879,6 +1881,17 @@ export abstract class Methods extends EventEmitter<WebClientEvent> {
18791881
list: bindApiCallWithOptionalArgument<EmojiListArguments, EmojiListResponse>(this, 'emoji.list'),
18801882
};
18811883

1884+
public readonly entity = {
1885+
/**
1886+
* @description Provide information about the entity to be displayed in the flexpane.
1887+
* @see {@link https://docs.slack.dev/reference/methods/entity.presentDetails}
1888+
*/
1889+
presentDetails: bindApiCall<EntityPresentDetailsArguments, EntityPresentDetailsResponse>(
1890+
this,
1891+
'entity.presentDetails',
1892+
),
1893+
};
1894+
18821895
public readonly files = {
18831896
/**
18841897
* @description Finishes an upload started with {@link https://docs.slack.dev/reference/methods/files.getUploadURLExternal `files.getUploadURLExternal`}.

packages/web-api/src/types/request/chat.ts

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type {
22
Block, // TODO: these will be combined into one in a new types release
3+
EntityMetadata,
34
KnownBlock,
45
LinkUnfurls,
56
MessageAttachment,
@@ -104,6 +105,19 @@ export interface BroadcastedThreadReply extends ThreadTS {
104105
// or not broadcasted. Broadcasted replies are necessarily threaded, so `thread_ts` becomes required.
105106
type ReplyInThread = WithinThreadReply | BroadcastedThreadReply;
106107

108+
export interface ChatPostMessageMetadata {
109+
/**
110+
* @description Object representing message metadata, entity and/or event data to attach to a Slack message.
111+
* Provide 'entities' to set work object entity metadata.
112+
* Provide 'event_type' and 'event_payload' to set event metadata.
113+
*/
114+
metadata?: Partial<MessageMetadata> & {
115+
/**
116+
* @description An array of work object entities.
117+
*/
118+
entities?: EntityMetadata[];
119+
};
120+
}
107121
export interface Metadata {
108122
/** @description Object representing message metadata, which will be made accessible to any user or app. */
109123
metadata?: MessageMetadata;
@@ -191,7 +205,7 @@ export type ChatPostMessageArguments = TokenOverridable &
191205
Authorship &
192206
Parse &
193207
LinkNames &
194-
Metadata &
208+
ChatPostMessageMetadata &
195209
Unfurls & {
196210
/** @description Disable Slack markup parsing by setting to `false`. Enabled by default. */
197211
mrkdwn?: boolean;
@@ -256,13 +270,8 @@ export interface SourceAndUnfurlID {
256270
type UnfurlTarget = ChannelAndTS | SourceAndUnfurlID;
257271

258272
// https://docs.slack.dev/reference/methods/chat.unfurl
259-
export type ChatUnfurlArguments = {
260-
/**
261-
* @description URL-encoded JSON map with keys set to URLs featured in the the message, pointing to their unfurl
262-
* blocks or message attachments.
263-
*/
264-
unfurls: LinkUnfurls;
265-
} & UnfurlTarget &
273+
export type ChatUnfurlArguments = (ChatUnfurlUnfurls | ChatUnfurlMetadata) &
274+
UnfurlTarget &
266275
TokenOverridable & {
267276
/**
268277
* @description Provide a simply-formatted string to send as an ephemeral message to the user as invitation to
@@ -286,6 +295,29 @@ export type ChatUnfurlArguments = {
286295
user_auth_blocks?: (KnownBlock | Block)[];
287296
};
288297

298+
/**
299+
* @description The `unfurls` param of the `chat.unfurl` API.
300+
*/
301+
interface ChatUnfurlUnfurls {
302+
/**
303+
* @description Object with keys set to URLs featured in the message, pointing to their unfurl
304+
* blocks or message attachments.
305+
*/
306+
unfurls: LinkUnfurls;
307+
}
308+
309+
/**
310+
* @description The `metadata` param of the `chat.unfurl` API.
311+
*/
312+
interface ChatUnfurlMetadata {
313+
/**
314+
* @description Unfurl metadata featuring an array of entities to attach to the message based on URLs featured in the message.
315+
*/
316+
metadata: Partial<MessageMetadata> & {
317+
entities: EntityMetadata[];
318+
};
319+
}
320+
289321
// https://docs.slack.dev/reference/methods/chat.update
290322
export type ChatUpdateArguments = MessageContents & {
291323
/** @description Timestamp of the message to be updated. */
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { EntityActionButton, EntityMetadata } from '@slack/types';
2+
import type { TokenOverridable } from './common';
3+
4+
// https://docs.slack.dev/reference/methods/entity.presentDetails
5+
export type EntityPresentDetailsArguments = TokenOverridable & {
6+
/**
7+
* @description Entity metadata to be presented in the flexpane.
8+
* */
9+
metadata?: EntityMetadata;
10+
/**
11+
* @description A reference to the original user action that initated the request.
12+
* */
13+
trigger_id: string;
14+
/**
15+
* @description Set user_auth_required to true to indicate that the user must authenticate to view the full
16+
* flexpane data. Defaults to false.
17+
* */
18+
user_auth_required?: boolean;
19+
/**
20+
* @description A custom URL to which users are directed for authentication if required.
21+
* Example: "https://example.com/onboarding?user_id=xxx"
22+
* */
23+
user_auth_url?: string;
24+
/** @description Error response preventing flexpane data from being returned. */
25+
error?: {
26+
/**
27+
* @description Error status indicating why the entity could not be presented.
28+
* */
29+
status: string;
30+
/**
31+
* @description If status is 'custom', you can use this field to provide a message to the client.
32+
* */
33+
custom_message?: string;
34+
/**
35+
* @description String format, eg. 'markdown'.
36+
* */
37+
message_format?: string;
38+
/**
39+
* @description If status is 'custom', you can use this field to provide a title to the client.
40+
* */
41+
custom_title?: string;
42+
/**
43+
* @description Set of action buttons to be shown in case of a specific error.
44+
* */
45+
actions?: EntityActionButton[];
46+
};
47+
};

packages/web-api/src/types/request/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ export type {
215215
DndTeamInfoArguments,
216216
} from './dnd';
217217
export type { EmojiListArguments } from './emoji';
218+
export type { EntityPresentDetailsArguments } from './entity';
218219
export type {
219220
FilesCommentsDeleteArguments,
220221
FilesCompleteUploadExternalArguments,

packages/web-api/src/types/request/manifest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ type ManifestEvent =
467467
| 'dnd_updated_user'
468468
| 'email_domain_changed'
469469
| 'emoji_changed'
470+
| 'entity_details_requested'
470471
| 'file_change'
471472
| 'file_comment_added'
472473
| 'file_comment_deleted'
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/////////////////////////////////////////////////////////////////////////////////////////
2+
// //
3+
// !!! DO NOT EDIT THIS FILE !!! //
4+
// //
5+
// This file is auto-generated by scripts/generate-web-api-types.sh in the repository. //
6+
// Please refer to the script code to learn how to update the source data. //
7+
// //
8+
/////////////////////////////////////////////////////////////////////////////////////////
9+
10+
import type { WebAPICallResult } from '../../WebClient';
11+
export type EntityPresentDetailsResponse = WebAPICallResult & {
12+
error?: string;
13+
needed?: string;
14+
ok?: boolean;
15+
provided?: string;
16+
warning?: string;
17+
};

packages/web-api/src/types/response/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ export { DndInfoResponse } from './DndInfoResponse';
202202
export { DndSetSnoozeResponse } from './DndSetSnoozeResponse';
203203
export { DndTeamInfoResponse } from './DndTeamInfoResponse';
204204
export { EmojiListResponse } from './EmojiListResponse';
205+
export { EntityPresentDetailsResponse } from './EntityPresentDetailsResponse';
205206
export { FilesCommentsAddResponse } from './FilesCommentsAddResponse';
206207
export { FilesCommentsDeleteResponse } from './FilesCommentsDeleteResponse';
207208
export { FilesCommentsEditResponse } from './FilesCommentsEditResponse';

packages/web-api/test/types/methods/chat.test-d.ts

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { CustomFieldType, type EntityMetadata } from '@slack/types';
12
import { expectAssignable, expectError } from 'tsd';
2-
33
import { WebClient } from '../../../src/WebClient';
44

55
const web = new WebClient('TOKEN');
@@ -441,6 +441,25 @@ expectAssignable<Parameters<typeof web.chat.postMessage>>([
441441
reply_broadcast: false, // can send a threaded message and explicitly not broadcast it
442442
},
443443
]);
444+
expectAssignable<Parameters<typeof web.chat.postMessage>>([
445+
{
446+
channel: 'C1234',
447+
text: 'hello',
448+
thread_ts: '1234.56',
449+
metadata: {
450+
entities: [
451+
{
452+
entity_type: 'slack#/entities/file',
453+
entity_payload: {
454+
attributes: { title: { text: 'My File' } },
455+
},
456+
external_ref: { id: '' },
457+
url: '',
458+
},
459+
],
460+
},
461+
},
462+
]);
444463
// adding a test for when `reply_broadcast` specific boolean value is not known ahead of time
445464
// https://github.com/slackapi/node-slack-sdk/issues/1859
446465
function wideBooleanTest(b: boolean) {
@@ -663,7 +682,7 @@ expectError(
663682
);
664683
expectError(
665684
web.chat.unfurl({
666-
channel: 'C1234', // missing unfurls
685+
channel: 'C1234', // missing both unfurls and metadata
667686
ts: '1234.56',
668687
}),
669688
);
@@ -717,6 +736,45 @@ expectAssignable<Parameters<typeof web.chat.unfurl>>([
717736
ts: '1234.56',
718737
},
719738
]);
739+
const entityMetadata: EntityMetadata = {
740+
entity_type: 'slack#/entities/task',
741+
entity_payload: {
742+
attributes: {
743+
title: {
744+
text: 'Important task',
745+
},
746+
},
747+
fields: {
748+
status: {
749+
value: 'All clear',
750+
},
751+
description: {
752+
value: 'Details of the task.',
753+
},
754+
},
755+
custom_fields: [
756+
{
757+
label: 'My Field',
758+
key: 'my-field',
759+
type: CustomFieldType.Array,
760+
item_type: 'slack#/types/channel_id',
761+
value: [{ value: 'C0123ABC' }],
762+
},
763+
],
764+
},
765+
external_ref: { id: '1234' },
766+
url: 'https://myappdomain.com/id/1234',
767+
app_unfurl_url: 'https://myappdomain.com/id/1234?myquery=param',
768+
};
769+
expectAssignable<Parameters<typeof web.chat.unfurl>>([
770+
{
771+
channel: 'C1234',
772+
ts: '1234.56',
773+
metadata: {
774+
entities: [entityMetadata],
775+
},
776+
},
777+
]);
720778

721779
// chat.update
722780
// -- sad path

0 commit comments

Comments
 (0)