
Security News
AGENTS.md Gains Traction as an Open Format for AI Coding Agents
AGENTS.md is a fast-growing open format giving AI coding agents a shared, predictable way to understand project setup, style, and workflows.
@slack-wrench/blocks
Advanced tools
Create messages with block kit more functionally and with less recall and repetition. Never need to remember json formats or accidentally type markdown
instead of mrkdwn
again!
This package helps abstract away some of the specifics, and deduplicate some of the repetitive code needed to create blocks being sent to Slack.
It also automatically handles various slack API limitations on content to ensure blocks built with dynamic content at least don't break when sent to Slack. Learn more about this in the Limits section.
# Yarn
yarn add @slack-wrench/blocks
# npm
npm install @slack-wrench/blocks
Example block kit builder search channel message
import { App } from '@slack/bolt';
import { Actions, Blocks, Button, Context, DateString, Divider, Markdown, MdSection, User } from '@slack-wrench/blocks';
const app = new App({ /* token, secret */ });
app.message(':wave:', async ({ message, say }) => {
say({
blocks: Blocks([
MdSection(`Hello, ${User(message.user)}! Let me help you find some channels.`, {
accessory: Button('Search', 'changeSearch'),
}),
Divider(),
MdSection('*Channels*'),
MdSection('*house-ravenclaw*\nDiscuss Ravenclaw business'),
Context([
Markdown(
`120 members\nLast post: ${DateString(1575643433, 'date_pretty', '1575643433')}`,
),
]),
Actions([
Button(':thumbsup:', 'thumbsUp', {
value: 'house-ravenclaw',
}),
Button(':thumbsdown:', 'thumbsDown', {
value: 'house-ravenclaw',
}),
]),
});
});
Before:
const { App } = require('@slack/bolt');
const app = new App({
/* token, secret */
});
app.message(':wave:', async ({ message, say }) => {
say({
blocks: [
{
accessory: {
type: 'button',
text: { type: 'plain_text', text: 'Search', emoji: true },
action_id: 'changeSearch',
},
text: {
type: 'mrkdwn',
text: `Hello, <@${message.user}>Let me help you find some channels.`,
},
type: 'section',
},
{ type: 'divider' },
{ text: { type: 'mrkdwn', text: '*Channels*' }, type: 'section' },
{
text: {
type: 'mrkdwn',
text: '*house-ravenclaw*\nDiscuss Ravenclaw business',
},
type: 'section',
},
{
type: 'context',
elements: [
{
type: 'mrkdwn',
text:
'120 members\nLast post: <!date^1575643433^{date_pretty}|1575643433>',
},
],
},
{
type: 'actions',
elements: [
{
type: 'button',
text: { type: 'plain_text', text: ':thumbsup:', emoji: true },
action_id: 'thumbsUp',
value: 'house-ravenclaw',
},
{
type: 'button',
text: { type: 'plain_text', text: ':thumbsdown:', emoji: true },
action_id: 'thumbsDown',
value: 'house-ravenclaw',
},
],
},
],
});
});
The Slack API fails completely if all of the various fields don't meet the length requirements outlined in their documentation. This is a lot to keep track of, so this package makes an attempt at sane defaults for cutting off content so that your requests to the Slack APIs won't error, even if you have very long dynamic content.
Depending on the type of the field being limited, different default limit behavior is applied.
There are three primary functions applied, depending on the field type: truncate
, ellipsis
, or disallow
.
truncate
cuts the field at the maximum. Examples:
ellipsis
happens for most text fields - titles, descriptions, placeholders, etc.
{ text: '<string>'}
) as well as string
fieldsdisallow
happens for any field that is typically programmatic and the value is required to stay the same for app functionality
For example, on an Option composition object, here are the functions applied by default and the limits for the fields.
const optionLimits: LimitOpts = {
text: [75, ellipsis],
value: [75, disallow],
description: [75, ellipsis],
url: [3000, truncate],
};
So, the text
field has a maximum length of 75
. If the provided text in building the block is greater than 75, then the text field is 'limited' via the ellipsis
function.
// { text: 'text', value: 'value' }
Option('text', 'value');
// { text: '<first 73 characters> …', value: 'value' }
Option('<80 character text>', 'value');
// Throws
Option('text', '<80 character id value>');
You can override the applied functions in most blocks by using the LimiterFuncs
argument. This involves passing an object mapping of fields (strings) to functions. Provided functions include truncate
, ellipsis
, disallow
, and identity
.
For example, if you didn't want it to throw on a value being too long, you could truncate that field instead of disallowing:
// map the `value` field to the truncate function instead of the default disallow
Option('title', dynamicText, undefined, { value: truncate });
In the same way that you can override, you can also provide your own custom functions (e.g. parsing URLs and removing query parameters, showing the last 10 instead of the first 10 in an array...).
The limiter function is passed two values - the limit (number) for the field in context and the string or array on which the check is done.
For example, to provide a function that just rendered an error string for text that is too long, you could do this:
Option(dynamicText, 'value', undefined, {
text: (limit, dynamicText) =>
`ERR: TOO LONG. LONGER than (${limit}): ${dynamicText.substring(0, 10)}...`,
});
Limiter function signature: <T>(limit: number, value: T) => T
. Be sure to return a value that is the same type as the value
passed - text element, string, option object array, etc. depending on the field.
Note that this function only gets called when the passed dynamicText is greater than the limit. Also, if you end up returning a value under the limit
, the block could break when the API call is made to Slack (since Slack will refuse the request).
For some blocks, rules are applied to nested blocks in specific fields. For example, the Section block fields
field requires that each text object in fields
has a maximum text length of 2000.
In cases such as this, you can override the default limiter function by providing a tuple instead of just a value limiter: [valLimiter, eachLimiters]
, where eachLimiters
is another mapping of Limiters
. For example, to truncate at 2000 characters instead of ellipsis for fields on a section, you could do:
Section(
{
text: PlainText(text),
fields: [{ text: dynamicText }],
},
{
fields: [truncate, { text: truncate }],
},
);
FAQs
Typescript Slack Blockkit components
The npm package @slack-wrench/blocks receives a total of 311 weekly downloads. As such, @slack-wrench/blocks popularity was classified as not popular.
We found that @slack-wrench/blocks demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
AGENTS.md is a fast-growing open format giving AI coding agents a shared, predictable way to understand project setup, style, and workflows.
Security News
/Research
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
Security News
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.