@chat-adapter/shared 4.13.1 → 4.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -217,13 +217,13 @@ declare function bufferToDataUri(buffer: Buffer, mimeType?: string): string;
217
217
  */
218
218
  declare class AdapterError extends Error {
219
219
  readonly adapter: string;
220
- readonly code?: string | undefined;
220
+ readonly code?: string;
221
221
  /**
222
222
  * @param message - Human-readable error message
223
223
  * @param adapter - Name of the adapter (e.g., "slack", "teams", "gchat")
224
224
  * @param code - Optional error code for programmatic handling
225
225
  */
226
- constructor(message: string, adapter: string, code?: string | undefined);
226
+ constructor(message: string, adapter: string, code?: string);
227
227
  }
228
228
  /**
229
229
  * Rate limit error - thrown when platform API rate limits are hit.
@@ -235,8 +235,8 @@ declare class AdapterError extends Error {
235
235
  * ```
236
236
  */
237
237
  declare class AdapterRateLimitError extends AdapterError {
238
- readonly retryAfter?: number | undefined;
239
- constructor(adapter: string, retryAfter?: number | undefined);
238
+ readonly retryAfter?: number;
239
+ constructor(adapter: string, retryAfter?: number);
240
240
  }
241
241
  /**
242
242
  * Authentication error - thrown when credentials are invalid or expired.
@@ -260,8 +260,8 @@ declare class AuthenticationError extends AdapterError {
260
260
  */
261
261
  declare class ResourceNotFoundError extends AdapterError {
262
262
  readonly resourceType: string;
263
- readonly resourceId?: string | undefined;
264
- constructor(adapter: string, resourceType: string, resourceId?: string | undefined);
263
+ readonly resourceId?: string;
264
+ constructor(adapter: string, resourceType: string, resourceId?: string);
265
265
  }
266
266
  /**
267
267
  * Permission error - thrown when the bot lacks required permissions.
@@ -273,8 +273,8 @@ declare class ResourceNotFoundError extends AdapterError {
273
273
  */
274
274
  declare class PermissionError extends AdapterError {
275
275
  readonly action: string;
276
- readonly requiredScope?: string | undefined;
277
- constructor(adapter: string, action: string, requiredScope?: string | undefined);
276
+ readonly requiredScope?: string;
277
+ constructor(adapter: string, action: string, requiredScope?: string);
278
278
  }
279
279
  /**
280
280
  * Validation error - thrown when input data is invalid.
@@ -296,8 +296,8 @@ declare class ValidationError extends AdapterError {
296
296
  * ```
297
297
  */
298
298
  declare class NetworkError extends AdapterError {
299
- readonly originalError?: Error | undefined;
300
- constructor(adapter: string, message?: string, originalError?: Error | undefined);
299
+ readonly originalError?: Error;
300
+ constructor(adapter: string, message?: string, originalError?: Error);
301
301
  }
302
302
 
303
303
  export { AdapterError, AdapterRateLimitError, AuthenticationError, BUTTON_STYLE_MAPPINGS, type FallbackTextOptions, type FileDataInput, NetworkError, PermissionError, type PlatformName, ResourceNotFoundError, type ToBufferOptions, ValidationError, bufferToDataUri, cardToFallbackText, createEmojiConverter, extractCard, extractFiles, mapButtonStyle, toBuffer, toBufferSync };
package/dist/index.js CHANGED
@@ -18,6 +18,8 @@ function extractFiles(message) {
18
18
 
19
19
  // src/errors.ts
20
20
  var AdapterError = class extends Error {
21
+ adapter;
22
+ code;
21
23
  /**
22
24
  * @param message - Human-readable error message
23
25
  * @param adapter - Name of the adapter (e.g., "slack", "teams", "gchat")
@@ -25,20 +27,21 @@ var AdapterError = class extends Error {
25
27
  */
26
28
  constructor(message, adapter, code) {
27
29
  super(message);
30
+ this.name = "AdapterError";
28
31
  this.adapter = adapter;
29
32
  this.code = code;
30
- this.name = "AdapterError";
31
33
  }
32
34
  };
33
35
  var AdapterRateLimitError = class extends AdapterError {
36
+ retryAfter;
34
37
  constructor(adapter, retryAfter) {
35
38
  super(
36
39
  `Rate limited by ${adapter}${retryAfter ? `, retry after ${retryAfter}s` : ""}`,
37
40
  adapter,
38
41
  "RATE_LIMITED"
39
42
  );
40
- this.retryAfter = retryAfter;
41
43
  this.name = "AdapterRateLimitError";
44
+ this.retryAfter = retryAfter;
42
45
  }
43
46
  };
44
47
  var AuthenticationError = class extends AdapterError {
@@ -52,6 +55,8 @@ var AuthenticationError = class extends AdapterError {
52
55
  }
53
56
  };
54
57
  var ResourceNotFoundError = class extends AdapterError {
58
+ resourceType;
59
+ resourceId;
55
60
  constructor(adapter, resourceType, resourceId) {
56
61
  const idPart = resourceId ? ` '${resourceId}'` : "";
57
62
  super(
@@ -59,12 +64,14 @@ var ResourceNotFoundError = class extends AdapterError {
59
64
  adapter,
60
65
  "NOT_FOUND"
61
66
  );
67
+ this.name = "ResourceNotFoundError";
62
68
  this.resourceType = resourceType;
63
69
  this.resourceId = resourceId;
64
- this.name = "ResourceNotFoundError";
65
70
  }
66
71
  };
67
72
  var PermissionError = class extends AdapterError {
73
+ action;
74
+ requiredScope;
68
75
  constructor(adapter, action, requiredScope) {
69
76
  const scopePart = requiredScope ? ` (requires: ${requiredScope})` : "";
70
77
  super(
@@ -72,9 +79,9 @@ var PermissionError = class extends AdapterError {
72
79
  adapter,
73
80
  "PERMISSION_DENIED"
74
81
  );
82
+ this.name = "PermissionError";
75
83
  this.action = action;
76
84
  this.requiredScope = requiredScope;
77
- this.name = "PermissionError";
78
85
  }
79
86
  };
80
87
  var ValidationError = class extends AdapterError {
@@ -84,14 +91,15 @@ var ValidationError = class extends AdapterError {
84
91
  }
85
92
  };
86
93
  var NetworkError = class extends AdapterError {
94
+ originalError;
87
95
  constructor(adapter, message, originalError) {
88
96
  super(
89
97
  message || `Network error communicating with ${adapter}`,
90
98
  adapter,
91
99
  "NETWORK_ERROR"
92
100
  );
93
- this.originalError = originalError;
94
101
  this.name = "NetworkError";
102
+ this.originalError = originalError;
95
103
  }
96
104
  };
97
105
 
@@ -153,7 +161,9 @@ function createEmojiConverter(platform) {
153
161
  return (text) => convertEmojiPlaceholders(text, platform);
154
162
  }
155
163
  function mapButtonStyle(style, platform) {
156
- if (!style) return void 0;
164
+ if (!style) {
165
+ return void 0;
166
+ }
157
167
  return BUTTON_STYLE_MAPPINGS[platform][style];
158
168
  }
159
169
  function cardToFallbackText(card, options = {}) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapter-utils.ts","../src/errors.ts","../src/buffer-utils.ts","../src/card-utils.ts"],"sourcesContent":["/**\n * Shared utility functions for chat adapters.\n *\n * These utilities are used across all adapter implementations (Slack, Teams, GChat)\n * to reduce code duplication and ensure consistent behavior.\n */\n\nimport type { AdapterPostableMessage, CardElement, FileUpload } from \"chat\";\nimport { isCardElement } from \"chat\";\n\n/**\n * Extract CardElement from an AdapterPostableMessage if present.\n *\n * Handles two cases:\n * 1. The message IS a CardElement (type: \"card\")\n * 2. The message is a PostableCard with a `card` property\n *\n * @param message - The message to extract the card from\n * @returns The CardElement if found, null otherwise\n *\n * @example\n * ```typescript\n * // Case 1: Direct CardElement\n * const card = Card({ title: \"Test\" });\n * extractCard(card); // returns the card\n *\n * // Case 2: PostableCard wrapper\n * const message = { card, fallbackText: \"...\" };\n * extractCard(message); // returns the card\n *\n * // Case 3: Non-card message\n * extractCard(\"Hello\"); // returns null\n * extractCard({ markdown: \"**bold**\" }); // returns null\n * ```\n */\nexport function extractCard(\n message: AdapterPostableMessage,\n): CardElement | null {\n if (isCardElement(message)) {\n return message;\n }\n if (typeof message === \"object\" && message !== null && \"card\" in message) {\n return message.card;\n }\n return null;\n}\n\n/**\n * Extract FileUpload array from an AdapterPostableMessage if present.\n *\n * Files can be attached to PostableRaw, PostableMarkdown, PostableAst,\n * or PostableCard messages via the `files` property.\n *\n * @param message - The message to extract files from\n * @returns Array of FileUpload objects, or empty array if none\n *\n * @example\n * ```typescript\n * // With files\n * const message = {\n * markdown: \"**Text**\",\n * files: [{ data: Buffer.from(\"...\"), filename: \"doc.pdf\" }]\n * };\n * extractFiles(message); // returns the files array\n *\n * // Without files\n * extractFiles(\"Hello\"); // returns []\n * extractFiles({ raw: \"text\" }); // returns []\n * ```\n */\nexport function extractFiles(message: AdapterPostableMessage): FileUpload[] {\n if (typeof message === \"object\" && message !== null && \"files\" in message) {\n return (message as { files?: FileUpload[] }).files ?? [];\n }\n return [];\n}\n","/**\n * Standardized error types for chat adapters.\n *\n * These error classes provide consistent error handling across all\n * adapter implementations.\n */\n\n/**\n * Base error class for adapter operations.\n *\n * All adapter-specific errors should extend this class.\n */\nexport class AdapterError extends Error {\n /**\n * @param message - Human-readable error message\n * @param adapter - Name of the adapter (e.g., \"slack\", \"teams\", \"gchat\")\n * @param code - Optional error code for programmatic handling\n */\n constructor(\n message: string,\n public readonly adapter: string,\n public readonly code?: string,\n ) {\n super(message);\n this.name = \"AdapterError\";\n }\n}\n\n/**\n * Rate limit error - thrown when platform API rate limits are hit.\n *\n * @example\n * ```typescript\n * throw new AdapterRateLimitError(\"slack\", 30);\n * // message: \"Rate limited by slack, retry after 30s\"\n * ```\n */\nexport class AdapterRateLimitError extends AdapterError {\n constructor(\n adapter: string,\n public readonly retryAfter?: number,\n ) {\n super(\n `Rate limited by ${adapter}${retryAfter ? `, retry after ${retryAfter}s` : \"\"}`,\n adapter,\n \"RATE_LIMITED\",\n );\n this.name = \"AdapterRateLimitError\";\n }\n}\n\n/**\n * Authentication error - thrown when credentials are invalid or expired.\n *\n * @example\n * ```typescript\n * throw new AuthenticationError(\"teams\", \"Token expired\");\n * ```\n */\nexport class AuthenticationError extends AdapterError {\n constructor(adapter: string, message?: string) {\n super(\n message || `Authentication failed for ${adapter}`,\n adapter,\n \"AUTH_FAILED\",\n );\n this.name = \"AuthenticationError\";\n }\n}\n\n/**\n * Not found error - thrown when a requested resource doesn't exist.\n *\n * @example\n * ```typescript\n * throw new ResourceNotFoundError(\"slack\", \"channel\", \"C123456\");\n * // message: \"channel 'C123456' not found in slack\"\n * ```\n */\nexport class ResourceNotFoundError extends AdapterError {\n constructor(\n adapter: string,\n public readonly resourceType: string,\n public readonly resourceId?: string,\n ) {\n const idPart = resourceId ? ` '${resourceId}'` : \"\";\n super(\n `${resourceType}${idPart} not found in ${adapter}`,\n adapter,\n \"NOT_FOUND\",\n );\n this.name = \"ResourceNotFoundError\";\n }\n}\n\n/**\n * Permission error - thrown when the bot lacks required permissions.\n *\n * @example\n * ```typescript\n * throw new PermissionError(\"teams\", \"send messages\", \"channels:write\");\n * ```\n */\nexport class PermissionError extends AdapterError {\n constructor(\n adapter: string,\n public readonly action: string,\n public readonly requiredScope?: string,\n ) {\n const scopePart = requiredScope ? ` (requires: ${requiredScope})` : \"\";\n super(\n `Permission denied: cannot ${action} in ${adapter}${scopePart}`,\n adapter,\n \"PERMISSION_DENIED\",\n );\n this.name = \"PermissionError\";\n }\n}\n\n/**\n * Validation error - thrown when input data is invalid.\n *\n * @example\n * ```typescript\n * throw new ValidationError(\"slack\", \"Message text exceeds 40000 characters\");\n * ```\n */\nexport class ValidationError extends AdapterError {\n constructor(adapter: string, message: string) {\n super(message, adapter, \"VALIDATION_ERROR\");\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Network error - thrown when there's a network/connectivity issue.\n *\n * @example\n * ```typescript\n * throw new NetworkError(\"gchat\", \"Connection timeout after 30s\");\n * ```\n */\nexport class NetworkError extends AdapterError {\n constructor(\n adapter: string,\n message?: string,\n public readonly originalError?: Error,\n ) {\n super(\n message || `Network error communicating with ${adapter}`,\n adapter,\n \"NETWORK_ERROR\",\n );\n this.name = \"NetworkError\";\n }\n}\n","/**\n * Buffer conversion utilities for handling file uploads.\n *\n * These utilities handle the conversion of various data types\n * (Buffer, ArrayBuffer, Blob) to Node.js Buffer for file uploads.\n */\n\nimport type { PlatformName } from \"./card-utils\";\nimport { ValidationError } from \"./errors\";\n\n/**\n * The supported input types for file data.\n */\nexport type FileDataInput = Buffer | ArrayBuffer | Blob;\n\n/**\n * Options for buffer conversion.\n */\nexport interface ToBufferOptions {\n /**\n * The platform name for error messages.\n */\n platform: PlatformName;\n\n /**\n * If true, throws ValidationError for unsupported types.\n * If false, returns null for unsupported types.\n * Default: true\n */\n throwOnUnsupported?: boolean;\n}\n\n/**\n * Convert various data types to a Node.js Buffer.\n *\n * Handles:\n * - Buffer: returned as-is\n * - ArrayBuffer: converted using Buffer.from()\n * - Blob: converted via arrayBuffer() then Buffer.from()\n *\n * @param data - The file data to convert\n * @param options - Conversion options\n * @returns Buffer or null if conversion fails and throwOnUnsupported is false\n * @throws ValidationError if data type is unsupported and throwOnUnsupported is true\n *\n * @example\n * ```typescript\n * // Throw on unsupported (default behavior)\n * const buffer = await toBuffer(file.data, { platform: \"slack\" });\n *\n * // Return null on unsupported\n * const buffer = await toBuffer(file.data, { platform: \"teams\", throwOnUnsupported: false });\n * if (!buffer) continue; // Skip unsupported files\n * ```\n */\nexport async function toBuffer(\n data: FileDataInput | unknown,\n options: ToBufferOptions,\n): Promise<Buffer | null> {\n const { platform, throwOnUnsupported = true } = options;\n\n if (Buffer.isBuffer(data)) {\n return data;\n }\n\n if (data instanceof ArrayBuffer) {\n return Buffer.from(data);\n }\n\n if (data instanceof Blob) {\n const arrayBuffer = await data.arrayBuffer();\n return Buffer.from(arrayBuffer);\n }\n\n if (throwOnUnsupported) {\n throw new ValidationError(platform, \"Unsupported file data type\");\n }\n\n return null;\n}\n\n/**\n * Synchronous version of toBuffer for non-Blob data.\n *\n * Use this when you know the data is not a Blob (e.g., already validated).\n *\n * @param data - The file data to convert (Buffer or ArrayBuffer only)\n * @param options - Conversion options\n * @returns Buffer or null if conversion fails\n * @throws ValidationError if data is a Blob or unsupported type and throwOnUnsupported is true\n */\nexport function toBufferSync(\n data: Buffer | ArrayBuffer | unknown,\n options: ToBufferOptions,\n): Buffer | null {\n const { platform, throwOnUnsupported = true } = options;\n\n if (Buffer.isBuffer(data)) {\n return data;\n }\n\n if (data instanceof ArrayBuffer) {\n return Buffer.from(data);\n }\n\n if (data instanceof Blob) {\n if (throwOnUnsupported) {\n throw new ValidationError(\n platform,\n \"Cannot convert Blob synchronously. Use toBuffer() for async conversion.\",\n );\n }\n return null;\n }\n\n if (throwOnUnsupported) {\n throw new ValidationError(platform, \"Unsupported file data type\");\n }\n\n return null;\n}\n\n/**\n * Convert a Buffer to a data URI string.\n *\n * @param buffer - The buffer to convert\n * @param mimeType - The MIME type (default: application/octet-stream)\n * @returns Data URI string in format `data:{mimeType};base64,{base64Data}`\n *\n * @example\n * ```typescript\n * const dataUri = bufferToDataUri(buffer, \"image/png\");\n * // \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA...\"\n * ```\n */\nexport function bufferToDataUri(\n buffer: Buffer,\n mimeType = \"application/octet-stream\",\n): string {\n const base64 = buffer.toString(\"base64\");\n return `data:${mimeType};base64,${base64}`;\n}\n","/**\n * Shared card conversion utilities for adapters.\n *\n * These utilities reduce duplication across adapter implementations\n * for card-to-platform-format conversions.\n */\n\nimport type { ButtonElement, CardChild, CardElement } from \"chat\";\nimport { convertEmojiPlaceholders } from \"chat\";\n\n/**\n * Supported platform names for adapter utilities.\n */\nexport type PlatformName = \"slack\" | \"gchat\" | \"teams\" | \"discord\";\n\n/**\n * Button style mappings per platform.\n *\n * Maps our standard button styles (\"primary\", \"danger\") to\n * platform-specific values.\n */\nexport const BUTTON_STYLE_MAPPINGS: Record<\n PlatformName,\n Record<string, string>\n> = {\n slack: { primary: \"primary\", danger: \"danger\" },\n gchat: { primary: \"primary\", danger: \"danger\" }, // Colors handled via buttonColor\n teams: { primary: \"positive\", danger: \"destructive\" },\n discord: { primary: \"primary\", danger: \"danger\" },\n};\n\n/**\n * Create a platform-specific emoji converter function.\n *\n * Returns a function that converts emoji placeholders (e.g., `{{emoji:wave}}`)\n * to the platform's native format.\n *\n * @example\n * ```typescript\n * const convertEmoji = createEmojiConverter(\"slack\");\n * convertEmoji(\"{{emoji:wave}} Hello\"); // \":wave: Hello\"\n * ```\n */\nexport function createEmojiConverter(\n platform: PlatformName,\n): (text: string) => string {\n return (text: string) => convertEmojiPlaceholders(text, platform);\n}\n\n/**\n * Map a button style to the platform-specific value.\n *\n * @example\n * ```typescript\n * mapButtonStyle(\"primary\", \"teams\"); // \"positive\"\n * mapButtonStyle(\"danger\", \"slack\"); // \"danger\"\n * mapButtonStyle(undefined, \"teams\"); // undefined\n * ```\n */\nexport function mapButtonStyle(\n style: ButtonElement[\"style\"],\n platform: PlatformName,\n): string | undefined {\n if (!style) return undefined;\n return BUTTON_STYLE_MAPPINGS[platform][style];\n}\n\n/**\n * Options for fallback text generation.\n */\nexport interface FallbackTextOptions {\n /** Bold format string (default: \"*\" for mrkdwn, \"**\" for markdown) */\n boldFormat?: \"*\" | \"**\";\n /** Line break between sections (default: \"\\n\") */\n lineBreak?: \"\\n\" | \"\\n\\n\";\n /** Platform for emoji conversion (optional) */\n platform?: PlatformName;\n}\n\n/**\n * Generate fallback plain text from a card element.\n *\n * Used when the platform can't render rich cards or for notification previews.\n * Consolidates duplicate implementations from individual adapters.\n *\n * @example\n * ```typescript\n * // Slack-style (mrkdwn)\n * cardToFallbackText(card, { boldFormat: \"*\", platform: \"slack\" });\n *\n * // Teams-style (markdown with double line breaks)\n * cardToFallbackText(card, { boldFormat: \"**\", lineBreak: \"\\n\\n\", platform: \"teams\" });\n * ```\n */\nexport function cardToFallbackText(\n card: CardElement,\n options: FallbackTextOptions = {},\n): string {\n const { boldFormat = \"*\", lineBreak = \"\\n\", platform } = options;\n\n const convertText = platform\n ? createEmojiConverter(platform)\n : (t: string) => t;\n\n const parts: string[] = [];\n\n if (card.title) {\n parts.push(`${boldFormat}${convertText(card.title)}${boldFormat}`);\n }\n\n if (card.subtitle) {\n parts.push(convertText(card.subtitle));\n }\n\n for (const child of card.children) {\n const text = childToFallbackText(child, convertText);\n if (text) {\n parts.push(text);\n }\n }\n\n return parts.join(lineBreak);\n}\n\n/**\n * Convert a card child element to fallback text.\n * Internal helper for cardToFallbackText.\n */\nfunction childToFallbackText(\n child: CardChild,\n convertText: (t: string) => string,\n): string | null {\n switch (child.type) {\n case \"text\":\n return convertText(child.content);\n case \"fields\":\n return child.children\n .map((f) => `${convertText(f.label)}: ${convertText(f.value)}`)\n .join(\"\\n\");\n case \"actions\":\n // Actions are interactive-only — exclude from fallback text.\n // Fallback text is used for notifications and screen readers where buttons aren't actionable.\n // See: https://docs.slack.dev/reference/methods/chat.postMessage\n return null;\n case \"section\":\n return child.children\n .map((c) => childToFallbackText(c, convertText))\n .filter(Boolean)\n .join(\"\\n\");\n case \"divider\":\n return \"---\";\n default:\n return null;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/adapter-utils.ts","../src/errors.ts","../src/buffer-utils.ts","../src/card-utils.ts"],"sourcesContent":["/**\n * Shared utility functions for chat adapters.\n *\n * These utilities are used across all adapter implementations (Slack, Teams, GChat)\n * to reduce code duplication and ensure consistent behavior.\n */\n\nimport type { AdapterPostableMessage, CardElement, FileUpload } from \"chat\";\nimport { isCardElement } from \"chat\";\n\n/**\n * Extract CardElement from an AdapterPostableMessage if present.\n *\n * Handles two cases:\n * 1. The message IS a CardElement (type: \"card\")\n * 2. The message is a PostableCard with a `card` property\n *\n * @param message - The message to extract the card from\n * @returns The CardElement if found, null otherwise\n *\n * @example\n * ```typescript\n * // Case 1: Direct CardElement\n * const card = Card({ title: \"Test\" });\n * extractCard(card); // returns the card\n *\n * // Case 2: PostableCard wrapper\n * const message = { card, fallbackText: \"...\" };\n * extractCard(message); // returns the card\n *\n * // Case 3: Non-card message\n * extractCard(\"Hello\"); // returns null\n * extractCard({ markdown: \"**bold**\" }); // returns null\n * ```\n */\nexport function extractCard(\n message: AdapterPostableMessage\n): CardElement | null {\n if (isCardElement(message)) {\n return message;\n }\n if (typeof message === \"object\" && message !== null && \"card\" in message) {\n return message.card;\n }\n return null;\n}\n\n/**\n * Extract FileUpload array from an AdapterPostableMessage if present.\n *\n * Files can be attached to PostableRaw, PostableMarkdown, PostableAst,\n * or PostableCard messages via the `files` property.\n *\n * @param message - The message to extract files from\n * @returns Array of FileUpload objects, or empty array if none\n *\n * @example\n * ```typescript\n * // With files\n * const message = {\n * markdown: \"**Text**\",\n * files: [{ data: Buffer.from(\"...\"), filename: \"doc.pdf\" }]\n * };\n * extractFiles(message); // returns the files array\n *\n * // Without files\n * extractFiles(\"Hello\"); // returns []\n * extractFiles({ raw: \"text\" }); // returns []\n * ```\n */\nexport function extractFiles(message: AdapterPostableMessage): FileUpload[] {\n if (typeof message === \"object\" && message !== null && \"files\" in message) {\n return (message as { files?: FileUpload[] }).files ?? [];\n }\n return [];\n}\n","/**\n * Standardized error types for chat adapters.\n *\n * These error classes provide consistent error handling across all\n * adapter implementations.\n */\n\n/**\n * Base error class for adapter operations.\n *\n * All adapter-specific errors should extend this class.\n */\nexport class AdapterError extends Error {\n readonly adapter: string;\n readonly code?: string;\n\n /**\n * @param message - Human-readable error message\n * @param adapter - Name of the adapter (e.g., \"slack\", \"teams\", \"gchat\")\n * @param code - Optional error code for programmatic handling\n */\n constructor(message: string, adapter: string, code?: string) {\n super(message);\n this.name = \"AdapterError\";\n this.adapter = adapter;\n this.code = code;\n }\n}\n\n/**\n * Rate limit error - thrown when platform API rate limits are hit.\n *\n * @example\n * ```typescript\n * throw new AdapterRateLimitError(\"slack\", 30);\n * // message: \"Rate limited by slack, retry after 30s\"\n * ```\n */\nexport class AdapterRateLimitError extends AdapterError {\n readonly retryAfter?: number;\n\n constructor(adapter: string, retryAfter?: number) {\n super(\n `Rate limited by ${adapter}${retryAfter ? `, retry after ${retryAfter}s` : \"\"}`,\n adapter,\n \"RATE_LIMITED\"\n );\n this.name = \"AdapterRateLimitError\";\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Authentication error - thrown when credentials are invalid or expired.\n *\n * @example\n * ```typescript\n * throw new AuthenticationError(\"teams\", \"Token expired\");\n * ```\n */\nexport class AuthenticationError extends AdapterError {\n constructor(adapter: string, message?: string) {\n super(\n message || `Authentication failed for ${adapter}`,\n adapter,\n \"AUTH_FAILED\"\n );\n this.name = \"AuthenticationError\";\n }\n}\n\n/**\n * Not found error - thrown when a requested resource doesn't exist.\n *\n * @example\n * ```typescript\n * throw new ResourceNotFoundError(\"slack\", \"channel\", \"C123456\");\n * // message: \"channel 'C123456' not found in slack\"\n * ```\n */\nexport class ResourceNotFoundError extends AdapterError {\n readonly resourceType: string;\n readonly resourceId?: string;\n\n constructor(adapter: string, resourceType: string, resourceId?: string) {\n const idPart = resourceId ? ` '${resourceId}'` : \"\";\n super(\n `${resourceType}${idPart} not found in ${adapter}`,\n adapter,\n \"NOT_FOUND\"\n );\n this.name = \"ResourceNotFoundError\";\n this.resourceType = resourceType;\n this.resourceId = resourceId;\n }\n}\n\n/**\n * Permission error - thrown when the bot lacks required permissions.\n *\n * @example\n * ```typescript\n * throw new PermissionError(\"teams\", \"send messages\", \"channels:write\");\n * ```\n */\nexport class PermissionError extends AdapterError {\n readonly action: string;\n readonly requiredScope?: string;\n\n constructor(adapter: string, action: string, requiredScope?: string) {\n const scopePart = requiredScope ? ` (requires: ${requiredScope})` : \"\";\n super(\n `Permission denied: cannot ${action} in ${adapter}${scopePart}`,\n adapter,\n \"PERMISSION_DENIED\"\n );\n this.name = \"PermissionError\";\n this.action = action;\n this.requiredScope = requiredScope;\n }\n}\n\n/**\n * Validation error - thrown when input data is invalid.\n *\n * @example\n * ```typescript\n * throw new ValidationError(\"slack\", \"Message text exceeds 40000 characters\");\n * ```\n */\nexport class ValidationError extends AdapterError {\n constructor(adapter: string, message: string) {\n super(message, adapter, \"VALIDATION_ERROR\");\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Network error - thrown when there's a network/connectivity issue.\n *\n * @example\n * ```typescript\n * throw new NetworkError(\"gchat\", \"Connection timeout after 30s\");\n * ```\n */\nexport class NetworkError extends AdapterError {\n readonly originalError?: Error;\n\n constructor(adapter: string, message?: string, originalError?: Error) {\n super(\n message || `Network error communicating with ${adapter}`,\n adapter,\n \"NETWORK_ERROR\"\n );\n this.name = \"NetworkError\";\n this.originalError = originalError;\n }\n}\n","/**\n * Buffer conversion utilities for handling file uploads.\n *\n * These utilities handle the conversion of various data types\n * (Buffer, ArrayBuffer, Blob) to Node.js Buffer for file uploads.\n */\n\nimport type { PlatformName } from \"./card-utils\";\nimport { ValidationError } from \"./errors\";\n\n/**\n * The supported input types for file data.\n */\nexport type FileDataInput = Buffer | ArrayBuffer | Blob;\n\n/**\n * Options for buffer conversion.\n */\nexport interface ToBufferOptions {\n /**\n * The platform name for error messages.\n */\n platform: PlatformName;\n\n /**\n * If true, throws ValidationError for unsupported types.\n * If false, returns null for unsupported types.\n * Default: true\n */\n throwOnUnsupported?: boolean;\n}\n\n/**\n * Convert various data types to a Node.js Buffer.\n *\n * Handles:\n * - Buffer: returned as-is\n * - ArrayBuffer: converted using Buffer.from()\n * - Blob: converted via arrayBuffer() then Buffer.from()\n *\n * @param data - The file data to convert\n * @param options - Conversion options\n * @returns Buffer or null if conversion fails and throwOnUnsupported is false\n * @throws ValidationError if data type is unsupported and throwOnUnsupported is true\n *\n * @example\n * ```typescript\n * // Throw on unsupported (default behavior)\n * const buffer = await toBuffer(file.data, { platform: \"slack\" });\n *\n * // Return null on unsupported\n * const buffer = await toBuffer(file.data, { platform: \"teams\", throwOnUnsupported: false });\n * if (!buffer) continue; // Skip unsupported files\n * ```\n */\nexport async function toBuffer(\n data: FileDataInput | unknown,\n options: ToBufferOptions\n): Promise<Buffer | null> {\n const { platform, throwOnUnsupported = true } = options;\n\n if (Buffer.isBuffer(data)) {\n return data;\n }\n\n if (data instanceof ArrayBuffer) {\n return Buffer.from(data);\n }\n\n if (data instanceof Blob) {\n const arrayBuffer = await data.arrayBuffer();\n return Buffer.from(arrayBuffer);\n }\n\n if (throwOnUnsupported) {\n throw new ValidationError(platform, \"Unsupported file data type\");\n }\n\n return null;\n}\n\n/**\n * Synchronous version of toBuffer for non-Blob data.\n *\n * Use this when you know the data is not a Blob (e.g., already validated).\n *\n * @param data - The file data to convert (Buffer or ArrayBuffer only)\n * @param options - Conversion options\n * @returns Buffer or null if conversion fails\n * @throws ValidationError if data is a Blob or unsupported type and throwOnUnsupported is true\n */\nexport function toBufferSync(\n data: Buffer | ArrayBuffer | unknown,\n options: ToBufferOptions\n): Buffer | null {\n const { platform, throwOnUnsupported = true } = options;\n\n if (Buffer.isBuffer(data)) {\n return data;\n }\n\n if (data instanceof ArrayBuffer) {\n return Buffer.from(data);\n }\n\n if (data instanceof Blob) {\n if (throwOnUnsupported) {\n throw new ValidationError(\n platform,\n \"Cannot convert Blob synchronously. Use toBuffer() for async conversion.\"\n );\n }\n return null;\n }\n\n if (throwOnUnsupported) {\n throw new ValidationError(platform, \"Unsupported file data type\");\n }\n\n return null;\n}\n\n/**\n * Convert a Buffer to a data URI string.\n *\n * @param buffer - The buffer to convert\n * @param mimeType - The MIME type (default: application/octet-stream)\n * @returns Data URI string in format `data:{mimeType};base64,{base64Data}`\n *\n * @example\n * ```typescript\n * const dataUri = bufferToDataUri(buffer, \"image/png\");\n * // \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA...\"\n * ```\n */\nexport function bufferToDataUri(\n buffer: Buffer,\n mimeType = \"application/octet-stream\"\n): string {\n const base64 = buffer.toString(\"base64\");\n return `data:${mimeType};base64,${base64}`;\n}\n","/**\n * Shared card conversion utilities for adapters.\n *\n * These utilities reduce duplication across adapter implementations\n * for card-to-platform-format conversions.\n */\n\nimport type { ButtonElement, CardChild, CardElement } from \"chat\";\nimport { convertEmojiPlaceholders } from \"chat\";\n\n/**\n * Supported platform names for adapter utilities.\n */\nexport type PlatformName = \"slack\" | \"gchat\" | \"teams\" | \"discord\";\n\n/**\n * Button style mappings per platform.\n *\n * Maps our standard button styles (\"primary\", \"danger\") to\n * platform-specific values.\n */\nexport const BUTTON_STYLE_MAPPINGS: Record<\n PlatformName,\n Record<string, string>\n> = {\n slack: { primary: \"primary\", danger: \"danger\" },\n gchat: { primary: \"primary\", danger: \"danger\" }, // Colors handled via buttonColor\n teams: { primary: \"positive\", danger: \"destructive\" },\n discord: { primary: \"primary\", danger: \"danger\" },\n};\n\n/**\n * Create a platform-specific emoji converter function.\n *\n * Returns a function that converts emoji placeholders (e.g., `{{emoji:wave}}`)\n * to the platform's native format.\n *\n * @example\n * ```typescript\n * const convertEmoji = createEmojiConverter(\"slack\");\n * convertEmoji(\"{{emoji:wave}} Hello\"); // \":wave: Hello\"\n * ```\n */\nexport function createEmojiConverter(\n platform: PlatformName\n): (text: string) => string {\n return (text: string) => convertEmojiPlaceholders(text, platform);\n}\n\n/**\n * Map a button style to the platform-specific value.\n *\n * @example\n * ```typescript\n * mapButtonStyle(\"primary\", \"teams\"); // \"positive\"\n * mapButtonStyle(\"danger\", \"slack\"); // \"danger\"\n * mapButtonStyle(undefined, \"teams\"); // undefined\n * ```\n */\nexport function mapButtonStyle(\n style: ButtonElement[\"style\"],\n platform: PlatformName\n): string | undefined {\n if (!style) {\n return undefined;\n }\n return BUTTON_STYLE_MAPPINGS[platform][style];\n}\n\n/**\n * Options for fallback text generation.\n */\nexport interface FallbackTextOptions {\n /** Bold format string (default: \"*\" for mrkdwn, \"**\" for markdown) */\n boldFormat?: \"*\" | \"**\";\n /** Line break between sections (default: \"\\n\") */\n lineBreak?: \"\\n\" | \"\\n\\n\";\n /** Platform for emoji conversion (optional) */\n platform?: PlatformName;\n}\n\n/**\n * Generate fallback plain text from a card element.\n *\n * Used when the platform can't render rich cards or for notification previews.\n * Consolidates duplicate implementations from individual adapters.\n *\n * @example\n * ```typescript\n * // Slack-style (mrkdwn)\n * cardToFallbackText(card, { boldFormat: \"*\", platform: \"slack\" });\n *\n * // Teams-style (markdown with double line breaks)\n * cardToFallbackText(card, { boldFormat: \"**\", lineBreak: \"\\n\\n\", platform: \"teams\" });\n * ```\n */\nexport function cardToFallbackText(\n card: CardElement,\n options: FallbackTextOptions = {}\n): string {\n const { boldFormat = \"*\", lineBreak = \"\\n\", platform } = options;\n\n const convertText = platform\n ? createEmojiConverter(platform)\n : (t: string) => t;\n\n const parts: string[] = [];\n\n if (card.title) {\n parts.push(`${boldFormat}${convertText(card.title)}${boldFormat}`);\n }\n\n if (card.subtitle) {\n parts.push(convertText(card.subtitle));\n }\n\n for (const child of card.children) {\n const text = childToFallbackText(child, convertText);\n if (text) {\n parts.push(text);\n }\n }\n\n return parts.join(lineBreak);\n}\n\n/**\n * Convert a card child element to fallback text.\n * Internal helper for cardToFallbackText.\n */\nfunction childToFallbackText(\n child: CardChild,\n convertText: (t: string) => string\n): string | null {\n switch (child.type) {\n case \"text\":\n return convertText(child.content);\n case \"fields\":\n return child.children\n .map((f) => `${convertText(f.label)}: ${convertText(f.value)}`)\n .join(\"\\n\");\n case \"actions\":\n // Actions are interactive-only — exclude from fallback text.\n // Fallback text is used for notifications and screen readers where buttons aren't actionable.\n // See: https://docs.slack.dev/reference/methods/chat.postMessage\n return null;\n case \"section\":\n return child.children\n .map((c) => childToFallbackText(c, convertText))\n .filter(Boolean)\n .join(\"\\n\");\n case \"divider\":\n return \"---\";\n default:\n return null;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chat-adapter/shared",
3
- "version": "4.13.1",
3
+ "version": "4.13.3",
4
4
  "description": "Shared utilities for chat SDK adapters",
5
5
  "type": "module",
6
6
  "exports": {
@@ -15,18 +15,35 @@
15
15
  "dist"
16
16
  ],
17
17
  "dependencies": {
18
- "chat": "4.13.1"
18
+ "chat": "4.13.3"
19
19
  },
20
20
  "devDependencies": {
21
- "@biomejs/biome": "^2.3.10",
22
21
  "@types/node": "^22.10.2",
23
22
  "tsup": "^8.3.5",
24
23
  "typescript": "^5.7.2",
25
24
  "vitest": "^2.1.8"
26
25
  },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/vercel/chat.git",
29
+ "directory": "packages/adapter-shared"
30
+ },
31
+ "homepage": "https://github.com/vercel/chat#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/vercel/chat/issues"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "keywords": [
39
+ "chat",
40
+ "bot",
41
+ "adapter",
42
+ "shared"
43
+ ],
44
+ "license": "MIT",
27
45
  "scripts": {
28
46
  "build": "tsup",
29
- "test": "vitest run",
30
- "lint": "biome check src"
47
+ "test": "vitest run --coverage"
31
48
  }
32
49
  }