Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/lib/sanitize-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ const IMAGE_KEYS = new Set(['image_url']);
*/
const RETRIEVAL_ONLY_KEYS = new Map<string, Set<string>>([
// Covers both the image block and the image element — both `type: 'image'`.
['image', new Set(['image_width', 'image_height', 'image_bytes', 'fallback', 'is_animated'])]
['image', new Set(['image_width', 'image_height', 'image_bytes', 'fallback', 'is_animated'])],
// Slack renders the chart server-side and attaches the rendered previews on
// retrieval; sending them back is rejected as `unknown property 'preview_images'`.
['data_visualization', new Set(['preview_images'])]
]);

/**
Expand Down
24 changes: 24 additions & 0 deletions test/sanitize-blocks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,30 @@ describe('retrieval-only image metadata', () => {
expect(Object.hasOwn(out.elements[0], 'image_bytes')).toBe(false);
});

it('drops preview_images Slack adds to retrieved data_visualization blocks', () => {
const block = {
type: 'data_visualization',
title: 'Weekly active users',
chart: { type: 'line', series: [] },
preview_images: [{ url: 'https://slack.example/chart.png' }]
} as unknown as SupportedBlock;
const out = sanitizeBlock(block) as Record<string, unknown>;
expect(Object.hasOwn(out, 'preview_images')).toBe(false);
expect(out.title).toBe('Weekly active users');
expect(out.chart).toBeDefined();
});

it('leaves preview_images untouched on non-data_visualization objects', () => {
const block = {
type: 'section',
text: { type: 'mrkdwn', text: 'hi' },
preview_images: ['keep me']
} as unknown as SupportedBlock;
const out = sanitizeBlock(block) as Record<string, unknown>;
expect(out.preview_images).toEqual(['keep me']);
expect(out).toBe(block);
});

it('leaves the same field names untouched on non-image objects', () => {
const block = {
type: 'section',
Expand Down
Loading