@stacksjs/chat 0.70.22 โ†’ 0.70.25

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/README.md CHANGED
@@ -39,9 +39,9 @@ Drivers are configured with the following environment variables:
39
39
  #### Slack
40
40
 
41
41
  ```bash
42
- SLACK_APPLICATION_ID=SAID123
43
- SLACK_CLIENT_ID=SCID123
44
- SLACK_SECRET_KEY=SSK123
42
+ SLACK*APPLICATION*ID=SAID123
43
+ SLACK*CLIENT*ID=SCID123
44
+ SLACK*SECRET*KEY=SSK123
45
45
  ```
46
46
 
47
47
  ## ๐Ÿงช Testing
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- var e={};var s={};var t={};export{t as teams,s as slack,e as discord};
2
+ var w=Object.defineProperty;var h=(q)=>q;function f(q,z){this[q]=h.bind(null,z)}var B=(q,z)=>{for(var F in z)w(q,F,{get:z[F],enumerable:!0,configurable:!0,set:f.bind(z,F)})};var j={};B(j,{sendWebhook:()=>P,sendEmbed:()=>S,send:()=>Z,driver:()=>u,default:()=>k,configure:()=>N,Driver:()=>O,DiscordDriver:()=>O});import{log as R}from"@stacksjs/logging";import{log as D}from"@stacksjs/logging";class K{config;constructor(q){this.config={maxRetries:q?.maxRetries||3,retryTimeout:q?.retryTimeout||1000,...q}}configure(q){this.config={...this.config,...q}}validateMessage(q){if(!q.to)throw Error("Message recipient is required");if(!q.content&&!q.template)throw Error("Either message content or template is required");return!0}async handleError(q,z){let F=q instanceof Error?q:Error(String(q));D.error(`[${this.name}] Message sending failed`,{error:F.message,stack:F.stack?.replace(/https?:\/\/[^\s)\]"']+/g,"[REDACTED-URL]"),to:z.to,subject:z.subject});let G={message:`Message sending failed: ${F.message}`,success:!1,provider:this.name};if(z.onError){let H=z.onError(F),J=H instanceof Promise?await H:H;G={...G,...J,success:!1,provider:this.name}}return G}async handleSuccess(q,z){let F={message:"Message sent successfully",success:!0,provider:this.name,messageId:z};try{if(q.handle){let G=q.handle(),H=G instanceof Promise?await G:G;F={...F,...H,success:!0,provider:this.name,messageId:z}}if(q.onSuccess){let G=q.onSuccess(),H=G instanceof Promise?await G:G;F={...F,...H,success:!0,provider:this.name,messageId:z}}}catch(G){return this.handleError(G,q)}return F}}var L={};function N(q){if(q.webhookUrl){let z;try{z=new URL(q.webhookUrl)}catch{throw Error(`[chat/discord] webhookUrl is not a valid URL: ${q.webhookUrl}`)}if(z.protocol!=="https:")throw Error("[chat/discord] webhookUrl must use https://");if(!/(^|\.)discord(?:app)?\.com$/i.test(z.hostname))throw Error(`[chat/discord] webhookUrl host "${z.hostname}" is not a Discord-owned domain.`)}L={...L,...q}}class O extends K{name="discord";constructor(q){super({maxRetries:q?.maxRetries??3,retryTimeout:q?.retryTimeout??1000});if(q)N(q)}async send(q,z){let F={provider:this.name,to:q.to,subject:q.subject||"No subject"};R.info("Sending message via Discord...",F);try{return this.validateMessage(q),await this.sendWithRetry(q,z)}catch(G){return this.handleError(G,q)}}async sendWithRetry(q,z,F=1){try{let G=await this.sendMessage(q,z);return this.handleSuccess(q,G.id)}catch(G){if(F<this.config.maxRetries)return R.warn(`[${this.name}] Message send failed, retrying (${F}/${this.config.maxRetries})`),await new Promise((H)=>setTimeout(H,this.config.retryTimeout)),this.sendWithRetry(q,z,F+1);throw G}}async sendMessage(q,z){if(L.webhookUrl)return this.sendViaWebhook(q);if(L.botToken)return this.sendViaBotToken(q);throw Error("Discord not configured: provide webhookUrl or botToken")}async sendViaWebhook(q){let z={content:q.content,username:q.from};if(q.subject||q.template)z.embeds=[this.buildEmbed(q)];let F=await fetch(L.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(z)});if(!F.ok){let H=await F.text();throw Error(`Discord webhook failed: ${F.status} - ${H}`)}if(F.status===204)return{};return{id:(await F.json()).id}}async sendViaBotToken(q){let z=q.to,F={content:q.content};if(q.subject||q.template)F.embeds=[this.buildEmbed(q)];let G=await fetch(`https://discord.com/api/v10/channels/${z}/messages`,{method:"POST",headers:{Authorization:`Bot ${L.botToken}`,"Content-Type":"application/json"},body:JSON.stringify(F)});if(!G.ok){let J=await G.json();throw Error(`Discord API failed: ${G.status} - ${J.message}`)}return{id:(await G.json()).id}}buildEmbed(q){let z={};if(q.subject)z.title=q.subject;if(q.content)z.description=q.content;return z.color=5793266,z.timestamp=new Date().toISOString(),z}}async function Z(q,z){return new O().send(q,z)}async function P(q,z,F){try{let G={content:z,...F},H=await fetch(q,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(G)});if(!H.ok){let J=await H.text();return{success:!1,provider:"discord",message:`Webhook failed: ${H.status} - ${J}`}}return{success:!0,provider:"discord",message:"Message sent successfully"}}catch(G){return{success:!1,provider:"discord",message:(G instanceof Error?G:Error(String(G))).message}}}async function S(q,z,F){return P(q,"",{...F,embeds:[z]})}var u=new O,k={send:Z,sendWebhook:P,sendEmbed:S,configure:N,DiscordDriver:O};var W={};B(W,{sendWebhook:()=>$,send:()=>_,driver:()=>b,default:()=>v,configure:()=>Q,SlackDriver:()=>V,Driver:()=>V});import{log as y}from"@stacksjs/logging";var M={};function Q(q){if(q.webhookUrl){let z;try{z=new URL(q.webhookUrl)}catch{throw Error(`[chat/slack] webhookUrl is not a valid URL: ${q.webhookUrl}`)}if(z.protocol!=="https:")throw Error("[chat/slack] webhookUrl must use https:// \u2014 Slack does not accept plain HTTP webhooks.");if(!/(^|\.)slack\.com$/i.test(z.hostname))throw Error(`[chat/slack] webhookUrl host "${z.hostname}" is not a Slack-owned domain.`)}M={...M,...q}}class V extends K{name="slack";constructor(q){super({maxRetries:q?.maxRetries??3,retryTimeout:q?.retryTimeout??1000});if(q)Q(q)}async send(q,z){let F={provider:this.name,to:q.to,subject:q.subject||"No subject"};y.info("Sending message via Slack...",F);try{return this.validateMessage(q),await this.sendWithRetry(q,z)}catch(G){return this.handleError(G,q)}}async sendWithRetry(q,z,F=1){try{let G=await this.sendMessage(q,z);return this.handleSuccess(q,G.ts)}catch(G){if(F<this.config.maxRetries)return y.warn(`[${this.name}] Message send failed, retrying (${F}/${this.config.maxRetries})`),await new Promise((H)=>setTimeout(H,this.config.retryTimeout)),this.sendWithRetry(q,z,F+1);throw G}}async sendMessage(q,z){if(M.webhookUrl)return this.sendViaWebhook(q);if(M.botToken)return this.sendViaBotToken(q);throw Error("Slack not configured: provide webhookUrl or botToken")}async sendViaWebhook(q){let F=q.content||q.subject||"",H={text:F.length>40000?`${F.slice(0,39986)}\u2026 [truncated]`:F,username:q.from,mrkdwn:!0};if(q.template)H.blocks=this.buildBlocks(q);let J=await fetch(M.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(H)});if(!J.ok){let x=await J.text();throw Error(`Slack webhook failed: ${J.status} - ${x}`)}return{}}async sendViaBotToken(q){let z={channel:q.to,text:q.content||q.subject,mrkdwn:!0};if(q.template)z.blocks=this.buildBlocks(q);let F=await fetch("https://slack.com/api/chat.postMessage",{method:"POST",headers:{Authorization:`Bearer ${M.botToken}`,"Content-Type":"application/json"},body:JSON.stringify(z)});if(!F.ok)throw Error(`Slack API failed: ${F.status}`);let G=await F.json();if(!G.ok)throw Error(`Slack API error: ${G.error}`);return{ts:G.ts}}buildBlocks(q){let z=[];if(q.subject)z.push({type:"header",text:{type:"plain_text",text:q.subject,emoji:!0}});if(q.content)z.push({type:"section",text:{type:"mrkdwn",text:q.content}});return z}}async function _(q,z){return new V().send(q,z)}async function $(q,z,F){try{let G={text:z,...F},H=await fetch(q,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(G)});if(!H.ok){let J=await H.text();return{success:!1,provider:"slack",message:`Webhook failed: ${H.status} - ${J}`}}return{success:!0,provider:"slack",message:"Message sent successfully"}}catch(G){return{success:!1,provider:"slack",message:(G instanceof Error?G:Error(String(G))).message}}}var b=new V,v={send:_,sendWebhook:$,configure:Q,SlackDriver:V};var C={};B(C,{sendWebhook:()=>E,sendCard:()=>T,send:()=>A,driver:()=>d,default:()=>c,configure:()=>X,TeamsDriver:()=>Y,Driver:()=>Y});import{log as U}from"@stacksjs/logging";var I={};function X(q){I={...I,...q}}class Y extends K{name="teams";constructor(q){super({maxRetries:q?.maxRetries??3,retryTimeout:q?.retryTimeout??1000});if(q)X(q)}async send(q,z){let F={provider:this.name,to:q.to,subject:q.subject||"No subject"};U.info("Sending message via Microsoft Teams...",F);try{return this.validateMessage(q),await this.sendWithRetry(q,z)}catch(G){return this.handleError(G,q)}}async sendWithRetry(q,z,F=1){try{return await this.sendMessage(q,z),this.handleSuccess(q)}catch(G){if(F<this.config.maxRetries)return U.warn(`[${this.name}] Message send failed, retrying (${F}/${this.config.maxRetries})`),await new Promise((H)=>setTimeout(H,this.config.retryTimeout)),this.sendWithRetry(q,z,F+1);throw G}}async sendMessage(q,z){let F=I.webhookUrl||q.to;if(!F||!F.includes("webhook.office.com"))throw Error("Teams webhook URL not configured or invalid");let G=this.buildPayload(q),H=await fetch(F,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(G)});if(!H.ok){let J=await H.text();throw Error(`Teams webhook failed: ${H.status} - ${J}`)}}buildPayload(q){if(!q.subject&&!q.template)return{type:"message",text:q.content||""};let z=this.buildAdaptiveCard(q);return{type:"message",summary:q.subject||q.content?.substring(0,50)||"Notification",attachments:[{contentType:"application/vnd.microsoft.card.adaptive",content:z}]}}buildAdaptiveCard(q){let z=[];if(q.subject)z.push({type:"TextBlock",text:q.subject,size:"Large",weight:"Bolder",wrap:!0});if(q.content)z.push({type:"TextBlock",text:q.content,wrap:!0});return z.push({type:"TextBlock",text:new Date().toLocaleString(),size:"Small",color:"Dark",wrap:!0}),{type:"AdaptiveCard",version:"1.4",$schema:"http://adaptivecards.io/schemas/adaptive-card.json",body:z}}}async function A(q,z){return new Y().send(q,z)}async function E(q,z){try{let G=await fetch(q,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({type:"message",text:z})});if(!G.ok){let H=await G.text();return{success:!1,provider:"teams",message:`Webhook failed: ${G.status} - ${H}`}}return{success:!0,provider:"teams",message:"Message sent successfully"}}catch(F){return{success:!1,provider:"teams",message:(F instanceof Error?F:Error(String(F))).message}}}async function T(q,z,F){try{let H=await fetch(q,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({type:"message",summary:F||"Notification",attachments:[{contentType:"application/vnd.microsoft.card.adaptive",content:z}]})});if(!H.ok){let J=await H.text();return{success:!1,provider:"teams",message:`Webhook failed: ${H.status} - ${J}`}}return{success:!0,provider:"teams",message:"Card sent successfully"}}catch(G){return{success:!1,provider:"teams",message:(G instanceof Error?G:Error(String(G))).message}}}var d=new Y,c={send:A,sendWebhook:E,sendCard:T,configure:X,TeamsDriver:Y};async function o(q,z={}){let F=z.driver??"slack";switch(F){case"slack":return _(q);case"discord":return Z(q);case"teams":return A(q);default:return{success:!1,provider:F,message:`Unknown chat driver: ${F}`}}}async function s(q,z,F){return $(q,z,F)}async function e(q,z,F){return P(q,z,F)}async function qq(q,z){return E(q,z)}function zq(q){Q(q)}function Fq(q){N(q)}function Gq(q){X(q)}export{C as teams,W as slack,qq as sendToTeams,s as sendToSlack,e as sendToDiscord,o as send,j as discord,Gq as configureTeams,zq as configureSlack,Fq as configureDiscord};
@@ -0,0 +1,75 @@
1
+ import { BaseChatDriver } from './base';
2
+ import type { ChatMessage, ChatResult, RenderOptions } from '@stacksjs/types';
3
+ /**
4
+ * Configure Discord with webhook URL or bot token.
5
+ *
6
+ * Validates that the webhook URL (when provided) is HTTPS pointing at
7
+ * Discord's host. Same reasoning as the Slack driver โ€” `http://` URLs
8
+ * leak the webhook token; off-domain URLs are typo'd configuration.
9
+ */
10
+ export declare function configure(options: DiscordConfig): void;
11
+ /**
12
+ * Send a message to Discord
13
+ */
14
+ export declare function send(message: ChatMessage, options?: RenderOptions): Promise<ChatResult>;
15
+ /**
16
+ * Send a simple message via Discord webhook
17
+ */
18
+ export declare function sendWebhook(webhookUrl: string, content: string, options?: Partial<DiscordMessage>): Promise<ChatResult>;
19
+ /**
20
+ * Send an embed message via Discord webhook
21
+ */
22
+ export declare function sendEmbed(webhookUrl: string, embed: DiscordEmbed, options?: Partial<DiscordMessage>): Promise<ChatResult>;
23
+ export declare const driver: DiscordDriver;
24
+ export declare interface DiscordConfig {
25
+ webhookUrl?: string
26
+ botToken?: string
27
+ maxRetries?: number
28
+ retryTimeout?: number
29
+ }
30
+ export declare interface DiscordEmbed {
31
+ title?: string
32
+ description?: string
33
+ url?: string
34
+ color?: number
35
+ timestamp?: string
36
+ footer?: {
37
+ text: string
38
+ icon_url?: string
39
+ }
40
+ image?: {
41
+ url: string
42
+ }
43
+ thumbnail?: {
44
+ url: string
45
+ }
46
+ author?: {
47
+ name: string
48
+ url?: string
49
+ icon_url?: string
50
+ }
51
+ fields?: Array<{
52
+ name: string
53
+ value: string
54
+ inline?: boolean
55
+ }>
56
+ }
57
+ export declare interface DiscordMessage {
58
+ content?: string
59
+ username?: string
60
+ avatarUrl?: string
61
+ tts?: boolean
62
+ embeds?: DiscordEmbed[]
63
+ allowedMentions?: {
64
+ parse?: Array<'roles' | 'users' | 'everyone'>
65
+ roles?: string[]
66
+ users?: string[]
67
+ }
68
+ }
69
+ export declare class DiscordDriver extends BaseChatDriver {
70
+ name: string;
71
+ constructor(options?: DiscordConfig);
72
+ send(message: ChatMessage, options?: RenderOptions): Promise<ChatResult>;
73
+ }
74
+ export { DiscordDriver as Driver };
75
+ export default { send, sendWebhook, sendEmbed, configure, DiscordDriver };
@@ -0,0 +1,76 @@
1
+ import { BaseChatDriver } from './base';
2
+ import type { ChatMessage, ChatResult, RenderOptions } from '@stacksjs/types';
3
+ /**
4
+ * Configure Slack with webhook URL or bot token.
5
+ *
6
+ * Validates that the webhook URL (when provided) is HTTPS pointing at
7
+ * Slack's webhook host. A misconfigured `http://` URL would leak the
8
+ * channel-specific token in plaintext to anyone watching network
9
+ * traffic; a typo'd domain would silently send messages to whatever
10
+ * server happens to accept them.
11
+ */
12
+ export declare function configure(options: SlackConfig): void;
13
+ /**
14
+ * Send a message to Slack
15
+ */
16
+ export declare function send(message: ChatMessage, options?: RenderOptions): Promise<ChatResult>;
17
+ /**
18
+ * Send a simple text message to a Slack channel via webhook
19
+ */
20
+ export declare function sendWebhook(webhookUrl: string, text: string, options?: Partial<SlackMessage>): Promise<ChatResult>;
21
+ export declare const driver: SlackDriver;
22
+ export declare interface SlackConfig {
23
+ webhookUrl?: string
24
+ botToken?: string
25
+ maxRetries?: number
26
+ retryTimeout?: number
27
+ }
28
+ export declare interface SlackMessage {
29
+ channel?: string
30
+ text?: string
31
+ blocks?: SlackBlock[]
32
+ attachments?: SlackAttachment[]
33
+ username?: string
34
+ iconEmoji?: string
35
+ iconUrl?: string
36
+ threadTs?: string
37
+ mrkdwn?: boolean
38
+ }
39
+ export declare interface SlackBlock {
40
+ type: 'section' | 'divider' | 'header' | 'context' | 'actions' | 'image'
41
+ text?: {
42
+ type: 'plain_text' | 'mrkdwn'
43
+ text: string
44
+ emoji?: boolean
45
+ }
46
+ accessory?: any
47
+ elements?: any[]
48
+ block_id?: string
49
+ }
50
+ export declare interface SlackAttachment {
51
+ color?: string
52
+ pretext?: string
53
+ author_name?: string
54
+ author_link?: string
55
+ author_icon?: string
56
+ title?: string
57
+ title_link?: string
58
+ text?: string
59
+ fields?: Array<{
60
+ title: string
61
+ value: string
62
+ short?: boolean
63
+ }>
64
+ image_url?: string
65
+ thumb_url?: string
66
+ footer?: string
67
+ footer_icon?: string
68
+ ts?: number
69
+ }
70
+ export declare class SlackDriver extends BaseChatDriver {
71
+ name: string;
72
+ constructor(options?: SlackConfig);
73
+ send(message: ChatMessage, options?: RenderOptions): Promise<ChatResult>;
74
+ }
75
+ export { SlackDriver as Driver };
76
+ export default { send, sendWebhook, configure, SlackDriver };
@@ -0,0 +1,69 @@
1
+ import { BaseChatDriver } from './base';
2
+ import type { ChatMessage, ChatResult, RenderOptions } from '@stacksjs/types';
3
+ /**
4
+ * Configure Teams with webhook URL
5
+ */
6
+ export declare function configure(options: TeamsConfig): void;
7
+ /**
8
+ * Send a message to Microsoft Teams
9
+ */
10
+ export declare function send(message: ChatMessage, options?: RenderOptions): Promise<ChatResult>;
11
+ /**
12
+ * Send a simple text message to Teams via webhook
13
+ */
14
+ export declare function sendWebhook(webhookUrl: string, text: string): Promise<ChatResult>;
15
+ /**
16
+ * Send an Adaptive Card to Teams via webhook
17
+ */
18
+ export declare function sendCard(webhookUrl: string, card: TeamsAdaptiveCard, summary?: string): Promise<ChatResult>;
19
+ export declare const driver: TeamsDriver;
20
+ export declare interface TeamsConfig {
21
+ webhookUrl?: string
22
+ maxRetries?: number
23
+ retryTimeout?: number
24
+ }
25
+ export declare interface TeamsAdaptiveCard {
26
+ type: 'AdaptiveCard'
27
+ version: string
28
+ body: TeamsCardElement[]
29
+ actions?: TeamsCardAction[]
30
+ $schema?: string
31
+ }
32
+ export declare interface TeamsCardElement {
33
+ type: 'TextBlock' | 'Image' | 'Container' | 'ColumnSet' | 'Column' | 'FactSet' | 'ImageSet'
34
+ text?: string
35
+ size?: 'Small' | 'Default' | 'Medium' | 'Large' | 'ExtraLarge'
36
+ weight?: 'Lighter' | 'Default' | 'Bolder'
37
+ color?: 'Default' | 'Dark' | 'Light' | 'Accent' | 'Good' | 'Warning' | 'Attention'
38
+ wrap?: boolean
39
+ url?: string
40
+ altText?: string
41
+ items?: TeamsCardElement[]
42
+ columns?: TeamsCardElement[]
43
+ width?: string
44
+ facts?: Array<{ title: string, value: string }>
45
+ images?: Array<{ type: 'Image', url: string, size?: string }>
46
+ }
47
+ export declare interface TeamsCardAction {
48
+ type: 'Action.OpenUrl' | 'Action.Submit' | 'Action.ShowCard'
49
+ title: string
50
+ url?: string
51
+ data?: Record<string, any>
52
+ card?: TeamsAdaptiveCard
53
+ }
54
+ export declare interface TeamsMessage {
55
+ type?: 'message'
56
+ summary?: string
57
+ text?: string
58
+ attachments?: Array<{
59
+ contentType: 'application/vnd.microsoft.card.adaptive'
60
+ content: TeamsAdaptiveCard
61
+ }>
62
+ }
63
+ export declare class TeamsDriver extends BaseChatDriver {
64
+ name: string;
65
+ constructor(options?: TeamsConfig);
66
+ send(message: ChatMessage, options?: RenderOptions): Promise<ChatResult>;
67
+ }
68
+ export { TeamsDriver as Driver };
69
+ export default { send, sendWebhook, sendCard, configure, TeamsDriver };
@@ -0,0 +1,43 @@
1
+ import * as discord from './drivers/discord';
2
+ import * as slack from './drivers/slack';
3
+ import * as teams from './drivers/teams';
4
+ import type { ChatMessage, ChatResult } from '@stacksjs/types';
5
+ // Re-export types
6
+ export type { SlackConfig, SlackMessage, SlackBlock, SlackAttachment } from './drivers/slack';
7
+ export type { DiscordConfig, DiscordMessage, DiscordEmbed } from './drivers/discord';
8
+ export type { TeamsConfig, TeamsMessage, TeamsAdaptiveCard, TeamsCardElement, TeamsCardAction } from './drivers/teams';
9
+ /**
10
+ * Send a chat message using the specified driver
11
+ */
12
+ export declare function send(message: ChatMessage, options?: SendOptions): Promise<ChatResult>;
13
+ /**
14
+ * Send a message to Slack via webhook
15
+ */
16
+ export declare function sendToSlack(webhookUrl: string, text: string, options?: Parameters<typeof slack.sendWebhook>[2]): Promise<ChatResult>;
17
+ /**
18
+ * Send a message to Discord via webhook
19
+ */
20
+ export declare function sendToDiscord(webhookUrl: string, content: string, options?: Parameters<typeof discord.sendWebhook>[2]): Promise<ChatResult>;
21
+ /**
22
+ * Send a message to Teams via webhook
23
+ */
24
+ export declare function sendToTeams(webhookUrl: string, text: string): Promise<ChatResult>;
25
+ /**
26
+ * Configure Slack driver
27
+ */
28
+ export declare function configureSlack(config: slack.SlackConfig): void;
29
+ /**
30
+ * Configure Discord driver
31
+ */
32
+ export declare function configureDiscord(config: discord.DiscordConfig): void;
33
+ /**
34
+ * Configure Teams driver
35
+ */
36
+ export declare function configureTeams(config: teams.TeamsConfig): void;
37
+ export declare interface SendOptions {
38
+ driver?: ChatDriver
39
+ }
40
+ export type ChatDriver = 'slack' | 'discord' | 'teams';
41
+ export * as discord from './drivers/discord';
42
+ export * as slack from './drivers/slack';
43
+ export * as teams from './drivers/teams';
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@stacksjs/chat",
3
3
  "type": "module",
4
- "version": "0.70.22",
4
+ "version": "0.70.25",
5
5
  "description": "Easily interact with chat APIs.",
6
6
  "author": "Chris Breuer",
7
- "contributors": ["Chris Breuer <chris@stacksjs.org>"],
7
+ "contributors": [
8
+ "Chris Breuer <chris@stacksjs.com>"
9
+ ],
8
10
  "license": "MIT",
9
11
  "funding": "https://github.com/sponsors/chrisbbreuer",
10
12
  "homepage": "https://github.com/stacksjs/stacks/tree/main/storage/framework/core/chat#readme",
@@ -16,28 +18,40 @@
16
18
  "bugs": {
17
19
  "url": "https://github.com/stacksjs/stacks/issues"
18
20
  },
19
- "keywords": ["chat", "stacks", "discord", "microsoft teams", "slack"],
21
+ "keywords": [
22
+ "chat",
23
+ "stacks",
24
+ "discord",
25
+ "microsoft teams",
26
+ "slack"
27
+ ],
20
28
  "exports": {
21
29
  ".": {
30
+ "bun": "./src/index.ts",
31
+ "types": "./dist/index.d.ts",
22
32
  "import": "./dist/index.js"
23
33
  },
24
34
  "./*": {
35
+ "bun": "./src/*",
25
36
  "import": "./dist/*"
26
37
  }
27
38
  },
28
39
  "module": "dist/index.js",
29
40
  "types": "dist/index.d.ts",
30
- "files": ["README.md", "dist"],
41
+ "files": [
42
+ "README.md",
43
+ "dist"
44
+ ],
31
45
  "scripts": {
32
46
  "build": "bun build.ts",
33
47
  "typecheck": "bun tsc --noEmit",
34
48
  "prepublishOnly": "bun run build"
35
49
  },
36
50
  "devDependencies": {
37
- "@stacksjs/cli": "0.70.18",
38
- "@stacksjs/config": "0.70.18",
39
- "@stacksjs/development": "0.70.18",
40
- "@stacksjs/error-handling": "0.70.18",
41
- "@stacksjs/types": "0.70.18"
51
+ "@stacksjs/cli": "0.70.23",
52
+ "@stacksjs/config": "0.70.23",
53
+ "better-dx": "^0.2.12",
54
+ "@stacksjs/error-handling": "0.70.23",
55
+ "@stacksjs/types": "0.70.23"
42
56
  }
43
57
  }
package/dist/base.d.ts DELETED
@@ -1,111 +0,0 @@
1
- import type { ChatDriver, ChatDriverConfig, ChatMessage, ChatResult, RenderOptions } from '@stacksjs/types';
2
-
3
- export declare abstract class BaseChatDriver implements ChatDriver {
4
- public abstract name: string
5
- protected config: Required<ChatDriverConfig>
6
-
7
- constructor(config?: ChatDriverConfig) {
8
- this.config = {
9
- maxRetries: config?.maxRetries || 3,
10
- retryTimeout: config?.retryTimeout || 1000,
11
- ...config,
12
- }
13
- }
14
-
15
- public configure(config: ChatDriverConfig): void {
16
- this.config = { ...this.config, ...config }
17
- }
18
-
19
- public abstract send(message: ChatMessage, options?: RenderOptions): Promise<ChatResult>
20
-
21
- protected validateMessage(message: ChatMessage): boolean {
22
- if (!message.to) {
23
- throw new Error('Message recipient is required')
24
- }
25
-
26
- if (!message.content && !message.template) {
27
- throw new Error('Either message content or template is required')
28
- }
29
-
30
- return true
31
- }
32
-
33
- protected async handleError(error: unknown, message: ChatMessage): Promise<ChatResult> {
34
- const err = error instanceof Error ? error : new Error(String(error))
35
-
36
- log.error(`[${this.name}] Message sending failed`, {
37
- error: err.message,
38
- stack: err.stack,
39
- to: message.to,
40
- subject: message.subject,
41
- })
42
-
43
- let result: ChatResult = {
44
- message: `Message sending failed: ${err.message}`,
45
- success: false,
46
- provider: this.name,
47
- }
48
-
49
- if (message.onError) {
50
- const customResult = message.onError(err)
51
- const handlerResult = customResult instanceof Promise
52
- ? await customResult
53
- : customResult
54
-
55
- result = {
56
- ...result,
57
- ...handlerResult,
58
- success: false,
59
- provider: this.name,
60
- }
61
- }
62
-
63
- return result
64
- }
65
-
66
- protected async handleSuccess(message: ChatMessage, messageId?: string): Promise<ChatResult> {
67
- let result: ChatResult = {
68
- message: 'Message sent successfully',
69
- success: true,
70
- provider: this.name,
71
- messageId,
72
- }
73
-
74
- try {
75
- if (message.handle) {
76
- const customResult = message.handle()
77
- const handlerResult = customResult instanceof Promise
78
- ? await customResult
79
- : customResult
80
-
81
- result = {
82
- ...result,
83
- ...handlerResult,
84
- success: true,
85
- provider: this.name,
86
- messageId,
87
- }
88
- }
89
-
90
- if (message.onSuccess) {
91
- const successResult = message.onSuccess()
92
- const handlerResult = successResult instanceof Promise
93
- ? await successResult
94
- : successResult
95
-
96
- result = {
97
- ...result,
98
- ...handlerResult,
99
- success: true,
100
- provider: this.name,
101
- messageId,
102
- }
103
- }
104
- }
105
- catch (error) {
106
- return this.handleError(error, message)
107
- }
108
-
109
- return result
110
- }
111
- }
package/dist/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export * as discord from './drivers/discord'
2
- export * as slack from './drivers/slack'
3
- export * as teams from './drivers/teams'
package/dist/teams.d.ts DELETED
@@ -1 +0,0 @@
1
- export type {}