Skip to content
19 changes: 19 additions & 0 deletions .changeset/deep-knives-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
"@slack/web-api": minor
---

feat: add `highlight_type` to [`files.completeUploadExternal`](https://docs.slack.dev/reference/methods/files.completeUploadExternal) and [`filesUploadV2`](https://docs.slack.dev/tools/node-slack-sdk/web-api#upload-a-file) for optimistic rendering

```js
import { WebClient } from "@slack/web-api";

const client = new WebClient(process.env.SLACK_BOT_TOKEN);

await client.filesUploadV2({
channel_id: "C0123456789",
file: "./image.png",
filename: "image.png",
title: "Image Upload",
highlight_type: "png",
});
```
22 changes: 22 additions & 0 deletions packages/web-api/src/file-upload.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,28 @@ describe('file-upload', () => {
});
});
describe('getAllFileUploadsToComplete', () => {
it('should pass all expected properties through to the completion job', () => {
const fileUploadJob1 = {
file: Buffer.from('test'),
filename: 'image.png',
file_id: 'id1',
title: 'test1',
channel_id: 'C123',
thread_ts: '1.0',
initial_comment: 'Here is an image',
highlight_type: 'png',
blocks: [{ type: 'section', text: { type: 'plain_text', text: 'hello' } }],
};
const toComplete = getAllFileUploadsToComplete([fileUploadJob1]);
const job = Object.values(toComplete)[0];
assert.strictEqual(job.files[0].id, 'id1');
assert.strictEqual(job.files[0].title, 'test1');
assert.strictEqual(job.channel_id, 'C123');
assert.strictEqual(job.thread_ts, '1.0');
assert.strictEqual(job.initial_comment, 'Here is an image');
assert.strictEqual(job.files[0].highlight_type, 'png');
assert.deepStrictEqual(job.blocks, fileUploadJob1.blocks);
});
describe('when channel_id is the same', () => {
it('should group uploads with matching thread_ts and initial_comment together', () => {
const fileUploadJob1 = {
Expand Down
6 changes: 4 additions & 2 deletions packages/web-api/src/file-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export async function getFileUploadJob(
blocks: options.blocks,
channel_id: options.channels ?? options.channel_id,
filename: options.filename ?? fileName,
highlight_type: options.highlight_type,
initial_comment: options.initial_comment,
snippet_type: options.snippet_type,
title: options.title ?? options.filename ?? fileName, // default title to filename unless otherwise specified
Expand Down Expand Up @@ -234,13 +235,13 @@ export function getAllFileUploadsToComplete(
): Record<string, FilesCompleteUploadExternalArguments> {
const toComplete: Record<string, FilesCompleteUploadExternalArguments> = {};
for (const upload of fileUploads) {
const { blocks, channel_id, thread_ts, initial_comment, file_id, title } = upload;
const { blocks, channel_id, thread_ts, highlight_type, initial_comment, file_id, title } = upload;
if (file_id) {
const compareString = `:::${channel_id}:::${thread_ts}:::${initial_comment}:::${JSON.stringify(blocks)}`;
// biome-ignore lint/suspicious/noPrototypeBuiltins: TODO use hasOwn instead of hasOwnProperty
if (!Object.prototype.hasOwnProperty.call(toComplete, compareString)) {
toComplete[compareString] = {
files: [{ id: file_id, title }],
files: [{ id: file_id, title, highlight_type }],
channel_id,
blocks,
initial_comment,
Expand All @@ -262,6 +263,7 @@ export function getAllFileUploadsToComplete(
toComplete[compareString].files.push({
id: file_id,
title,
highlight_type,
});
}
} else {
Expand Down
10 changes: 10 additions & 0 deletions packages/web-api/src/types/request/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ export interface FileType {
export interface FileUploadComplete {
/** @description Encoded file ID. */
id: string;
/**
* @description Optional highlight type hint for the file. The upload processing job may overwrite this value.
* @see {@link https://docs.slack.dev/reference/methods/files.completeUploadExternal}
*/
highlight_type?: string;
/** @description File title. */
title?: string;
}
Expand Down Expand Up @@ -168,6 +173,11 @@ export type FileUploadV2 = FileUpload & {
channel_id?: string;
/** @deprecated use channel_id instead */
channels?: string;
/**
* @description Optional highlight type hint for the file. The upload processing job may overwrite this value.
* @see {@link https://docs.slack.dev/reference/methods/files.completeUploadExternal}
*/
highlight_type?: string;
/** @description Syntax type of the snippet being uploaded. E.g. `python`. */
snippet_type?: string;
};
Expand Down