Commit aced743
feat(slack): primitives subpaths (4.30 — vercel/chat#538,547,548,555,559) (#139)
* feat(slack): webhook primitives subpath (vercel/chat#538)
Port of upstream b332a03 — adds chat_sdk.adapters.slack.webhook, a
lightweight runtime-free subpath for lower-level Slack webhook handling:
verifying Slack requests (HMAC v0 + custom verifiers), reading signed
webhook bodies, parsing Events API callbacks, slash commands, and
interactive payloads into typed dataclasses with provider-native
continuation data.
The adapter now verifies through the shared verify_slack_request /
verify_slack_signature primitives (single implementation — the inline
_verify_signature method is removed, matching upstream), reads bodies via
the shared read_slack_request_body helper, and sources
SlackWebhookVerifier from webhook/types.py. The slack package __init__ is
now lazy (PEP 562) so importing the webhook subpath does not pull in the
full adapter runtime — the Python analog of upstream's package subpath
export boundary.
Python-specific notes: verify_slack_signature is sync (no WebCrypto);
verify helpers accept a pre-read body= for non-re-readable framework
requests; now() returns epoch seconds.
https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64
* feat(slack): format primitives subpath (vercel/chat#547)
Port of upstream 4c46c26 — adds chat_sdk.adapters.slack.format, a
runtime-free subpath for Slack formatting helpers: plain_text/mrkdwn text
objects, mrkdwn escaping/unescaping, user/channel/user-group/special
mentions, links, localized date tokens, mrkdwn-to-Markdown normalization,
Markdown-bold conversion, and ID-based bare-mention linking — without the
full Slack adapter, slack_sdk, or the chat runtime.
Python-specific notes: option objects (SlackTextOptions, SlackDateOptions)
become keyword-only arguments; format_slack_date accepts datetime or an
integer unix timestamp (TS Date | number) and the TypeError message says
'datetime' instead of 'Date'.
https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64
* feat(slack): api primitives subpath (vercel/chat#548, #559)
Port of upstream aba6aa9 (api/client.ts) and 6ed4a43 (api/extra.ts) —
adds chat_sdk.adapters.slack.api, a runtime-free subpath exposed upstream
as @chat-adapter/slack/api. Provides fetch-based primitives for calling
Slack Web API methods (call_slack_api), posting/updating/deleting messages
(post_slack_message, post_slack_ephemeral, update_slack_message,
delete_slack_message), sending interaction response_url payloads
(send_slack_response_url), uploading files through Slack's external upload
flow (upload_slack_files), fetching private Slack file URLs with bearer
auth (fetch_slack_file), fetching thread replies with cursor pagination
(fetch_slack_thread_replies), and opening modal views (open_slack_view) —
without the full Slack adapter, slack_sdk, Socket Mode, or the chat
runtime.
Importing this subpath never imports an HTTP client: the default fetch
lazily imports httpx only when a request is actually made (matching the
high-level adapter's optional-httpx pattern), and any async HTTP stack can
be injected via the fetch= parameter. SlackBotToken is declared locally
rather than imported from the adapter's types module, so the subpath stays
self-contained and runtime-free — mirroring upstream's independent
declaration in api/client.ts.
Python-specific notes: option objects become keyword-only arguments;
camelCase request fields are emitted at the Slack serialization boundary
(markdown_text, reply_broadcast, thread_ts, ...) while the API is
snake_case. Python-specific hardening (divergences, see
docs/UPSTREAM_SYNC.md Known Non-Parity): send_slack_response_url requires
an https://*.slack.com URL and fetch_slack_file requires a Slack-owned
file host before forwarding the bearer token (SSRF / token-leak guards
mirroring the high-level adapter); upstream validates neither.
Tests port api/index.test.ts and api/boundary.test.ts with injected
AsyncMock fetches (no network), plus the two divergence guards.
https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64
* feat(slack): block kit primitives subpath (vercel/chat#555, #559)
Port of upstream dbd8dc5 (blocks/index.ts, types.ts, limits.ts,
errors.ts) and 6ed4a43 (blocks/input.ts) — adds
chat_sdk.adapters.slack.blocks, a runtime-free subpath exposed upstream as
@chat-adapter/slack/blocks. Converts Chat SDK-style card objects into
Slack Block Kit blocks (card_to_slack_blocks / card_to_block_kit), a
Markdown fallback (card_to_slack_fallback_text / card_to_fallback_text),
and emoji-placeholder codes (convert_slack_emoji_placeholders), enforcing
docs-backed Slack size limits (LIMITS) for headers, images, actions,
select options, fields, and tables. Also ports the generic input-request
helpers: input_request_to_slack_blocks (buttons / select / radio /
freeform), parse_slack_input_response, build_slack_freeform_view,
parse_slack_freeform_value, and answered_slack_input_blocks — without the
full Slack adapter, slack_sdk, or the chat runtime. The only cross-module
dependency is the sibling format subpath (markdown_bold_to_slack_mrkdwn),
which is itself runtime-free.
Python-specific notes: the card-input shapes (SlackCardElement and
children) are self-contained TypedDicts declared here rather than imported
from chat_sdk.cards, keeping the subpath runtime-free. Input field names
are snake_case (image_url, initial_option, request_id, allow_freeform,
selected_option_value, action_id, block_id), matching chat_sdk.cards and
the Python port convention — upstream uses camelCase. Emitted Block Kit
dicts keep Slack's API field names verbatim (alt_text, action_id,
block_id, static_select, column_settings, raw_text, private_metadata),
which is the Slack serialization boundary. Discriminated-union dispatch on
the literal type key uses per-branch casts / arg-type ignores, mirroring
the high-level adapter's cards.py.
Tests port blocks/index.test.ts and blocks/boundary.test.ts with full
output equality, plus extra coverage of the parse-None and
string-metadata paths.
https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64
* fix(slack): port dropped parse fields + fix select-action label (4.30 fidelity)
Port the SlackFile/SlackUser/SlackViewStateValue primitives and the
helpers (parseFiles/inferFileType/parseUser/findPromptBlock/
readPromptText/parseViewValues) that the webhook parse.py port dropped vs
upstream chat@4.30.0 packages/adapter-slack/src/webhook/parse.ts:
- files[]: populated on every message-like event via _parse_files
(mimetype-inferred type, raw retained).
- SlackAction.label: now prefers the selected option's text and falls
back to the element text (parse.ts:276); surface selected_option_label.
- SlackUser: attached as the user object on block_actions / view_submission
/ view_closed payloads and on each parsed action.
- block_actions: restore message_blocks / message_prompt_block /
message_prompt_text; view_submission: restore callback_id /
private_metadata / values (parseViewValues).
Extend webhook primitive tests to lock in every newly-ported field; add
Known-Non-Parity rows for the slack/api SSRF + token-leak guards.
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 4d7f7d8 commit aced743
22 files changed
Lines changed: 5103 additions & 188 deletions
File tree
- docs
- src/chat_sdk/adapters/slack
- api
- blocks
- webhook
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
646 | 646 | | |
647 | 647 | | |
648 | 648 | | |
| 649 | + | |
| 650 | + | |
649 | 651 | | |
650 | 652 | | |
651 | 653 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
4 | 17 | | |
5 | 18 | | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
16 | 15 | | |
17 | 16 | | |
18 | 17 | | |
| |||
58 | 57 | | |
59 | 58 | | |
60 | 59 | | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
61 | 64 | | |
62 | 65 | | |
63 | 66 | | |
| |||
1392 | 1395 | | |
1393 | 1396 | | |
1394 | 1397 | | |
1395 | | - | |
1396 | | - | |
1397 | | - | |
1398 | | - | |
1399 | | - | |
1400 | | - | |
1401 | | - | |
1402 | | - | |
1403 | | - | |
1404 | | - | |
1405 | | - | |
1406 | | - | |
1407 | | - | |
1408 | | - | |
1409 | | - | |
1410 | | - | |
1411 | | - | |
1412 | | - | |
1413 | | - | |
1414 | | - | |
1415 | | - | |
1416 | | - | |
1417 | | - | |
1418 | | - | |
1419 | | - | |
1420 | | - | |
1421 | | - | |
| 1398 | + | |
| 1399 | + | |
| 1400 | + | |
| 1401 | + | |
| 1402 | + | |
1422 | 1403 | | |
1423 | 1404 | | |
1424 | 1405 | | |
| |||
1455 | 1436 | | |
1456 | 1437 | | |
1457 | 1438 | | |
1458 | | - | |
| 1439 | + | |
1459 | 1440 | | |
1460 | 1441 | | |
1461 | 1442 | | |
| |||
1484 | 1465 | | |
1485 | 1466 | | |
1486 | 1467 | | |
1487 | | - | |
1488 | | - | |
1489 | | - | |
1490 | | - | |
1491 | | - | |
1492 | | - | |
1493 | | - | |
1494 | | - | |
1495 | | - | |
1496 | | - | |
1497 | | - | |
1498 | | - | |
1499 | | - | |
1500 | | - | |
1501 | | - | |
1502 | | - | |
1503 | | - | |
1504 | | - | |
1505 | | - | |
1506 | | - | |
1507 | | - | |
1508 | | - | |
1509 | | - | |
1510 | | - | |
1511 | | - | |
| 1468 | + | |
| 1469 | + | |
| 1470 | + | |
| 1471 | + | |
| 1472 | + | |
| 1473 | + | |
| 1474 | + | |
| 1475 | + | |
| 1476 | + | |
| 1477 | + | |
| 1478 | + | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
1512 | 1484 | | |
1513 | 1485 | | |
1514 | 1486 | | |
| |||
1658 | 1630 | | |
1659 | 1631 | | |
1660 | 1632 | | |
1661 | | - | |
1662 | | - | |
1663 | | - | |
1664 | | - | |
1665 | | - | |
1666 | | - | |
1667 | | - | |
1668 | | - | |
1669 | | - | |
1670 | | - | |
1671 | | - | |
1672 | | - | |
1673 | | - | |
1674 | | - | |
1675 | | - | |
1676 | | - | |
1677 | | - | |
1678 | | - | |
1679 | | - | |
1680 | | - | |
1681 | | - | |
1682 | | - | |
1683 | | - | |
1684 | | - | |
1685 | | - | |
1686 | | - | |
1687 | | - | |
1688 | | - | |
1689 | | - | |
1690 | | - | |
1691 | | - | |
1692 | | - | |
1693 | | - | |
1694 | | - | |
1695 | | - | |
1696 | | - | |
1697 | | - | |
1698 | | - | |
1699 | | - | |
1700 | | - | |
1701 | | - | |
1702 | | - | |
1703 | | - | |
1704 | | - | |
1705 | | - | |
1706 | | - | |
1707 | 1633 | | |
1708 | 1634 | | |
1709 | 1635 | | |
| |||
0 commit comments