@chat-adapter/shared 4.1.0

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/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vercel, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,227 @@
1
+ import { AdapterPostableMessage, CardElement, FileUpload, ButtonElement } from 'chat';
2
+
3
+ /**
4
+ * Shared utility functions for chat adapters.
5
+ *
6
+ * These utilities are used across all adapter implementations (Slack, Teams, GChat)
7
+ * to reduce code duplication and ensure consistent behavior.
8
+ */
9
+
10
+ /**
11
+ * Extract CardElement from an AdapterPostableMessage if present.
12
+ *
13
+ * Handles two cases:
14
+ * 1. The message IS a CardElement (type: "card")
15
+ * 2. The message is a PostableCard with a `card` property
16
+ *
17
+ * @param message - The message to extract the card from
18
+ * @returns The CardElement if found, null otherwise
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Case 1: Direct CardElement
23
+ * const card = Card({ title: "Test" });
24
+ * extractCard(card); // returns the card
25
+ *
26
+ * // Case 2: PostableCard wrapper
27
+ * const message = { card, fallbackText: "..." };
28
+ * extractCard(message); // returns the card
29
+ *
30
+ * // Case 3: Non-card message
31
+ * extractCard("Hello"); // returns null
32
+ * extractCard({ markdown: "**bold**" }); // returns null
33
+ * ```
34
+ */
35
+ declare function extractCard(message: AdapterPostableMessage): CardElement | null;
36
+ /**
37
+ * Extract FileUpload array from an AdapterPostableMessage if present.
38
+ *
39
+ * Files can be attached to PostableRaw, PostableMarkdown, PostableAst,
40
+ * or PostableCard messages via the `files` property.
41
+ *
42
+ * @param message - The message to extract files from
43
+ * @returns Array of FileUpload objects, or empty array if none
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * // With files
48
+ * const message = {
49
+ * markdown: "**Text**",
50
+ * files: [{ data: Buffer.from("..."), filename: "doc.pdf" }]
51
+ * };
52
+ * extractFiles(message); // returns the files array
53
+ *
54
+ * // Without files
55
+ * extractFiles("Hello"); // returns []
56
+ * extractFiles({ raw: "text" }); // returns []
57
+ * ```
58
+ */
59
+ declare function extractFiles(message: AdapterPostableMessage): FileUpload[];
60
+
61
+ /**
62
+ * Shared card conversion utilities for adapters.
63
+ *
64
+ * These utilities reduce duplication across adapter implementations
65
+ * for card-to-platform-format conversions.
66
+ */
67
+
68
+ /**
69
+ * Supported platform names for adapter utilities.
70
+ */
71
+ type PlatformName = "slack" | "gchat" | "teams";
72
+ /**
73
+ * Button style mappings per platform.
74
+ *
75
+ * Maps our standard button styles ("primary", "danger") to
76
+ * platform-specific values.
77
+ */
78
+ declare const BUTTON_STYLE_MAPPINGS: Record<PlatformName, Record<string, string>>;
79
+ /**
80
+ * Create a platform-specific emoji converter function.
81
+ *
82
+ * Returns a function that converts emoji placeholders (e.g., `{{emoji:wave}}`)
83
+ * to the platform's native format.
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const convertEmoji = createEmojiConverter("slack");
88
+ * convertEmoji("{{emoji:wave}} Hello"); // ":wave: Hello"
89
+ * ```
90
+ */
91
+ declare function createEmojiConverter(platform: PlatformName): (text: string) => string;
92
+ /**
93
+ * Map a button style to the platform-specific value.
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * mapButtonStyle("primary", "teams"); // "positive"
98
+ * mapButtonStyle("danger", "slack"); // "danger"
99
+ * mapButtonStyle(undefined, "teams"); // undefined
100
+ * ```
101
+ */
102
+ declare function mapButtonStyle(style: ButtonElement["style"], platform: PlatformName): string | undefined;
103
+ /**
104
+ * Options for fallback text generation.
105
+ */
106
+ interface FallbackTextOptions {
107
+ /** Bold format string (default: "*" for mrkdwn, "**" for markdown) */
108
+ boldFormat?: "*" | "**";
109
+ /** Line break between sections (default: "\n") */
110
+ lineBreak?: "\n" | "\n\n";
111
+ /** Platform for emoji conversion (optional) */
112
+ platform?: PlatformName;
113
+ }
114
+ /**
115
+ * Generate fallback plain text from a card element.
116
+ *
117
+ * Used when the platform can't render rich cards or for notification previews.
118
+ * Consolidates duplicate implementations from individual adapters.
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * // Slack-style (mrkdwn)
123
+ * cardToFallbackText(card, { boldFormat: "*", platform: "slack" });
124
+ *
125
+ * // Teams-style (markdown with double line breaks)
126
+ * cardToFallbackText(card, { boldFormat: "**", lineBreak: "\n\n", platform: "teams" });
127
+ * ```
128
+ */
129
+ declare function cardToFallbackText(card: CardElement, options?: FallbackTextOptions): string;
130
+
131
+ /**
132
+ * Standardized error types for chat adapters.
133
+ *
134
+ * These error classes provide consistent error handling across all
135
+ * adapter implementations.
136
+ */
137
+ /**
138
+ * Base error class for adapter operations.
139
+ *
140
+ * All adapter-specific errors should extend this class.
141
+ */
142
+ declare class AdapterError extends Error {
143
+ readonly adapter: string;
144
+ readonly code?: string | undefined;
145
+ /**
146
+ * @param message - Human-readable error message
147
+ * @param adapter - Name of the adapter (e.g., "slack", "teams", "gchat")
148
+ * @param code - Optional error code for programmatic handling
149
+ */
150
+ constructor(message: string, adapter: string, code?: string | undefined);
151
+ }
152
+ /**
153
+ * Rate limit error - thrown when platform API rate limits are hit.
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * throw new AdapterRateLimitError("slack", 30);
158
+ * // message: "Rate limited by slack, retry after 30s"
159
+ * ```
160
+ */
161
+ declare class AdapterRateLimitError extends AdapterError {
162
+ readonly retryAfter?: number | undefined;
163
+ constructor(adapter: string, retryAfter?: number | undefined);
164
+ }
165
+ /**
166
+ * Authentication error - thrown when credentials are invalid or expired.
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * throw new AuthenticationError("teams", "Token expired");
171
+ * ```
172
+ */
173
+ declare class AuthenticationError extends AdapterError {
174
+ constructor(adapter: string, message?: string);
175
+ }
176
+ /**
177
+ * Not found error - thrown when a requested resource doesn't exist.
178
+ *
179
+ * @example
180
+ * ```typescript
181
+ * throw new ResourceNotFoundError("slack", "channel", "C123456");
182
+ * // message: "channel 'C123456' not found in slack"
183
+ * ```
184
+ */
185
+ declare class ResourceNotFoundError extends AdapterError {
186
+ readonly resourceType: string;
187
+ readonly resourceId?: string | undefined;
188
+ constructor(adapter: string, resourceType: string, resourceId?: string | undefined);
189
+ }
190
+ /**
191
+ * Permission error - thrown when the bot lacks required permissions.
192
+ *
193
+ * @example
194
+ * ```typescript
195
+ * throw new PermissionError("teams", "send messages", "channels:write");
196
+ * ```
197
+ */
198
+ declare class PermissionError extends AdapterError {
199
+ readonly action: string;
200
+ readonly requiredScope?: string | undefined;
201
+ constructor(adapter: string, action: string, requiredScope?: string | undefined);
202
+ }
203
+ /**
204
+ * Validation error - thrown when input data is invalid.
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * throw new ValidationError("slack", "Message text exceeds 40000 characters");
209
+ * ```
210
+ */
211
+ declare class ValidationError extends AdapterError {
212
+ constructor(adapter: string, message: string);
213
+ }
214
+ /**
215
+ * Network error - thrown when there's a network/connectivity issue.
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * throw new NetworkError("gchat", "Connection timeout after 30s");
220
+ * ```
221
+ */
222
+ declare class NetworkError extends AdapterError {
223
+ readonly originalError?: Error | undefined;
224
+ constructor(adapter: string, message?: string, originalError?: Error | undefined);
225
+ }
226
+
227
+ export { AdapterError, AdapterRateLimitError, AuthenticationError, BUTTON_STYLE_MAPPINGS, type FallbackTextOptions, NetworkError, PermissionError, type PlatformName, ResourceNotFoundError, ValidationError, cardToFallbackText, createEmojiConverter, extractCard, extractFiles, mapButtonStyle };
package/dist/index.js ADDED
@@ -0,0 +1,162 @@
1
+ // src/adapter-utils.ts
2
+ import { isCardElement } from "chat";
3
+ function extractCard(message) {
4
+ if (isCardElement(message)) {
5
+ return message;
6
+ }
7
+ if (typeof message === "object" && message !== null && "card" in message) {
8
+ return message.card;
9
+ }
10
+ return null;
11
+ }
12
+ function extractFiles(message) {
13
+ if (typeof message === "object" && message !== null && "files" in message) {
14
+ return message.files ?? [];
15
+ }
16
+ return [];
17
+ }
18
+
19
+ // src/card-utils.ts
20
+ import { convertEmojiPlaceholders } from "chat";
21
+ var BUTTON_STYLE_MAPPINGS = {
22
+ slack: { primary: "primary", danger: "danger" },
23
+ gchat: { primary: "primary", danger: "danger" },
24
+ // Colors handled via buttonColor
25
+ teams: { primary: "positive", danger: "destructive" }
26
+ };
27
+ function createEmojiConverter(platform) {
28
+ return (text) => convertEmojiPlaceholders(text, platform);
29
+ }
30
+ function mapButtonStyle(style, platform) {
31
+ if (!style) return void 0;
32
+ return BUTTON_STYLE_MAPPINGS[platform][style];
33
+ }
34
+ function cardToFallbackText(card, options = {}) {
35
+ const { boldFormat = "*", lineBreak = "\n", platform } = options;
36
+ const convertText = platform ? createEmojiConverter(platform) : (t) => t;
37
+ const parts = [];
38
+ if (card.title) {
39
+ parts.push(`${boldFormat}${convertText(card.title)}${boldFormat}`);
40
+ }
41
+ if (card.subtitle) {
42
+ parts.push(convertText(card.subtitle));
43
+ }
44
+ for (const child of card.children) {
45
+ const text = childToFallbackText(child, convertText);
46
+ if (text) {
47
+ parts.push(text);
48
+ }
49
+ }
50
+ return parts.join(lineBreak);
51
+ }
52
+ function childToFallbackText(child, convertText) {
53
+ switch (child.type) {
54
+ case "text":
55
+ return convertText(child.content);
56
+ case "fields":
57
+ return child.children.map((f) => `${convertText(f.label)}: ${convertText(f.value)}`).join("\n");
58
+ case "actions":
59
+ return `[${child.children.map((b) => convertText(b.label)).join("] [")}]`;
60
+ case "section":
61
+ return child.children.map((c) => childToFallbackText(c, convertText)).filter(Boolean).join("\n");
62
+ case "divider":
63
+ return "---";
64
+ default:
65
+ return null;
66
+ }
67
+ }
68
+
69
+ // src/errors.ts
70
+ var AdapterError = class extends Error {
71
+ /**
72
+ * @param message - Human-readable error message
73
+ * @param adapter - Name of the adapter (e.g., "slack", "teams", "gchat")
74
+ * @param code - Optional error code for programmatic handling
75
+ */
76
+ constructor(message, adapter, code) {
77
+ super(message);
78
+ this.adapter = adapter;
79
+ this.code = code;
80
+ this.name = "AdapterError";
81
+ }
82
+ };
83
+ var AdapterRateLimitError = class extends AdapterError {
84
+ constructor(adapter, retryAfter) {
85
+ super(
86
+ `Rate limited by ${adapter}${retryAfter ? `, retry after ${retryAfter}s` : ""}`,
87
+ adapter,
88
+ "RATE_LIMITED"
89
+ );
90
+ this.retryAfter = retryAfter;
91
+ this.name = "AdapterRateLimitError";
92
+ }
93
+ };
94
+ var AuthenticationError = class extends AdapterError {
95
+ constructor(adapter, message) {
96
+ super(
97
+ message || `Authentication failed for ${adapter}`,
98
+ adapter,
99
+ "AUTH_FAILED"
100
+ );
101
+ this.name = "AuthenticationError";
102
+ }
103
+ };
104
+ var ResourceNotFoundError = class extends AdapterError {
105
+ constructor(adapter, resourceType, resourceId) {
106
+ const idPart = resourceId ? ` '${resourceId}'` : "";
107
+ super(
108
+ `${resourceType}${idPart} not found in ${adapter}`,
109
+ adapter,
110
+ "NOT_FOUND"
111
+ );
112
+ this.resourceType = resourceType;
113
+ this.resourceId = resourceId;
114
+ this.name = "ResourceNotFoundError";
115
+ }
116
+ };
117
+ var PermissionError = class extends AdapterError {
118
+ constructor(adapter, action, requiredScope) {
119
+ const scopePart = requiredScope ? ` (requires: ${requiredScope})` : "";
120
+ super(
121
+ `Permission denied: cannot ${action} in ${adapter}${scopePart}`,
122
+ adapter,
123
+ "PERMISSION_DENIED"
124
+ );
125
+ this.action = action;
126
+ this.requiredScope = requiredScope;
127
+ this.name = "PermissionError";
128
+ }
129
+ };
130
+ var ValidationError = class extends AdapterError {
131
+ constructor(adapter, message) {
132
+ super(message, adapter, "VALIDATION_ERROR");
133
+ this.name = "ValidationError";
134
+ }
135
+ };
136
+ var NetworkError = class extends AdapterError {
137
+ constructor(adapter, message, originalError) {
138
+ super(
139
+ message || `Network error communicating with ${adapter}`,
140
+ adapter,
141
+ "NETWORK_ERROR"
142
+ );
143
+ this.originalError = originalError;
144
+ this.name = "NetworkError";
145
+ }
146
+ };
147
+ export {
148
+ AdapterError,
149
+ AdapterRateLimitError,
150
+ AuthenticationError,
151
+ BUTTON_STYLE_MAPPINGS,
152
+ NetworkError,
153
+ PermissionError,
154
+ ResourceNotFoundError,
155
+ ValidationError,
156
+ cardToFallbackText,
157
+ createEmojiConverter,
158
+ extractCard,
159
+ extractFiles,
160
+ mapButtonStyle
161
+ };
162
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapter-utils.ts","../src/card-utils.ts","../src/errors.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 { CardElement } from \"chat\";\nimport { isCardElement } from \"chat\";\nimport type { AdapterPostableMessage, FileUpload } 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 * 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\";\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};\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 return `[${child.children.map((b) => convertText(b.label)).join(\"] [\")}]`;\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","/**\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"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@chat-adapter/shared",
3
+ "version": "4.1.0",
4
+ "description": "Shared utilities for chat SDK adapters",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ }
11
+ },
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "dependencies": {
18
+ "chat": "4.2.0"
19
+ },
20
+ "devDependencies": {
21
+ "@biomejs/biome": "^1.7.3",
22
+ "@types/node": "^22.10.2",
23
+ "tsup": "^8.3.5",
24
+ "typescript": "^5.7.2",
25
+ "vitest": "^2.1.8"
26
+ },
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "test": "vitest run",
30
+ "lint": "biome check src"
31
+ }
32
+ }