# `client/classify` — HTTP status + Slack-error classifier ## Purpose `classify.ts` exports two pure mapping functions that fold transport-level failure signals into the stable `SLACK_CODES` registry. `classifyHttpStatus` partitions every observed HTTP status code into one of `AUTH_ERROR`, `CHANNEL_NOT_FOUND`, `TIMEOUT`, `RATE_LIMITED`, or the catch-all `API_ERROR`. `classifySlackError` does the same for Slack's JSON-level error strings (`invalid_auth`, `channel_not_found`, `team_not_found`, etc.). Centralising the classification keeps the API client and the webhook client in lock-step and gives downstream retry wrappers a single source of truth for what the package considers a retryable failure. ## Features - Total HTTP-status partition — every numeric status maps to exactly one code. - Total Slack-error partition — every JSON `error` string maps to exactly one code, with regex matchers grouping family members (`is_archived`/`not_in_channel` count as `CHANNEL_NOT_FOUND`). - Pure functions — no side effects, no module-scope state, safe to tree-shake. - Literal-typed return — `SlackErrorCode` discriminated union is preserved. ## Usage: Basic ```ts import { classifyHttpStatus, classifySlackError, } from "@suaveplan/slack-client/client/classify"; const fromStatus = classifyHttpStatus(429); // "SLACK.RATE_LIMITED" const fromBody = classifySlackError("invalid_auth"); // "SLACK.AUTH_ERROR" ``` ## Usage: Advanced ```ts import { classifyHttpStatus, classifySlackError, } from "@suaveplan/slack-client/client/classify"; import { SLACK_CODES } from "@suaveplan/slack-client/error-codes"; function isRetryable(code: ReturnType): boolean { return ( code === SLACK_CODES.RATE_LIMITED || code === SLACK_CODES.TIMEOUT || code === SLACK_CODES.API_ERROR ); } const retry = isRetryable(classifyHttpStatus(503)); // true ``` ## API Reference - `classifyHttpStatus(status: number): SlackErrorCode` - `classifySlackError(slackError: string): SlackErrorCode` ## Implementation Notes The Slack-error matchers use case-insensitive regular expressions because Slack's documentation is inconsistent on casing and the API has historically returned both `invalid_auth` and `Invalid_Auth` in different surfaces. The order of the checks is important — `invalid_auth` must match before any `not_*` matcher because `not_authed` is an auth error, not a channel error. The HTTP-status partition deliberately uses `===` comparisons rather than range checks so that adding a new status (e.g. 451) requires an explicit decision rather than silently joining the catch-all bucket.