@fabric-harness/channels 0.16.0 → 0.17.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.
Files changed (83) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +6 -1
  3. package/dist/compatibility.d.ts +143 -0
  4. package/dist/compatibility.d.ts.map +1 -0
  5. package/dist/compatibility.js +30 -0
  6. package/dist/compatibility.js.map +1 -0
  7. package/dist/discord.d.ts +53 -0
  8. package/dist/discord.d.ts.map +1 -0
  9. package/dist/discord.js +95 -0
  10. package/dist/discord.js.map +1 -0
  11. package/dist/github.d.ts +37 -1
  12. package/dist/github.d.ts.map +1 -1
  13. package/dist/github.js +5 -5
  14. package/dist/github.js.map +1 -1
  15. package/dist/google-chat.d.ts +59 -0
  16. package/dist/google-chat.d.ts.map +1 -0
  17. package/dist/google-chat.js +127 -0
  18. package/dist/google-chat.js.map +1 -0
  19. package/dist/index.d.ts +4 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +2 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/intercom.d.ts +47 -0
  24. package/dist/intercom.d.ts.map +1 -0
  25. package/dist/intercom.js +40 -0
  26. package/dist/intercom.js.map +1 -0
  27. package/dist/linear.d.ts +46 -0
  28. package/dist/linear.d.ts.map +1 -0
  29. package/dist/linear.js +27 -0
  30. package/dist/linear.js.map +1 -0
  31. package/dist/messenger.d.ts +59 -0
  32. package/dist/messenger.d.ts.map +1 -0
  33. package/dist/messenger.js +49 -0
  34. package/dist/messenger.js.map +1 -0
  35. package/dist/notion.d.ts +46 -0
  36. package/dist/notion.d.ts.map +1 -0
  37. package/dist/notion.js +32 -0
  38. package/dist/notion.js.map +1 -0
  39. package/dist/resend.d.ts +44 -0
  40. package/dist/resend.d.ts.map +1 -0
  41. package/dist/resend.js +49 -0
  42. package/dist/resend.js.map +1 -0
  43. package/dist/salesforce-marketing-cloud.d.ts +39 -0
  44. package/dist/salesforce-marketing-cloud.d.ts.map +1 -0
  45. package/dist/salesforce-marketing-cloud.js +21 -0
  46. package/dist/salesforce-marketing-cloud.js.map +1 -0
  47. package/dist/shopify.d.ts +38 -0
  48. package/dist/shopify.d.ts.map +1 -0
  49. package/dist/shopify.js +29 -0
  50. package/dist/shopify.js.map +1 -0
  51. package/dist/slack.d.ts +19 -1
  52. package/dist/slack.d.ts.map +1 -1
  53. package/dist/slack.js +19 -7
  54. package/dist/slack.js.map +1 -1
  55. package/dist/stripe.d.ts +40 -0
  56. package/dist/stripe.d.ts.map +1 -0
  57. package/dist/stripe.js +58 -0
  58. package/dist/stripe.js.map +1 -0
  59. package/dist/teams.d.ts +58 -0
  60. package/dist/teams.d.ts.map +1 -0
  61. package/dist/teams.js +154 -0
  62. package/dist/teams.js.map +1 -0
  63. package/dist/telegram.d.ts +53 -0
  64. package/dist/telegram.d.ts.map +1 -0
  65. package/dist/telegram.js +76 -0
  66. package/dist/telegram.js.map +1 -0
  67. package/dist/twilio.d.ts +39 -0
  68. package/dist/twilio.d.ts.map +1 -0
  69. package/dist/twilio.js +83 -0
  70. package/dist/twilio.js.map +1 -0
  71. package/dist/webhook-shared.d.ts +43 -0
  72. package/dist/webhook-shared.d.ts.map +1 -0
  73. package/dist/webhook-shared.js +100 -0
  74. package/dist/webhook-shared.js.map +1 -0
  75. package/dist/whatsapp.d.ts +53 -0
  76. package/dist/whatsapp.d.ts.map +1 -0
  77. package/dist/whatsapp.js +98 -0
  78. package/dist/whatsapp.js.map +1 -0
  79. package/dist/zendesk.d.ts +48 -0
  80. package/dist/zendesk.d.ts.map +1 -0
  81. package/dist/zendesk.js +36 -0
  82. package/dist/zendesk.js.map +1 -0
  83. package/package.json +74 -5
@@ -0,0 +1,53 @@
1
+ import type { Channel, ToolDef } from '@fabric-harness/sdk/channel';
2
+ export interface WhatsAppConversationRef {
3
+ businessAccountId: string;
4
+ phoneNumberId: string;
5
+ userPhone: string;
6
+ }
7
+ export interface WhatsAppWebhookPayload {
8
+ entry?: Array<{
9
+ id?: string;
10
+ changes?: Array<{
11
+ value?: {
12
+ metadata?: {
13
+ phone_number_id?: string;
14
+ };
15
+ messages?: Array<{
16
+ id?: string;
17
+ from?: string;
18
+ text?: {
19
+ body?: string;
20
+ };
21
+ }>;
22
+ statuses?: Array<{
23
+ id?: string;
24
+ recipient_id?: string;
25
+ status?: string;
26
+ timestamp?: string;
27
+ errors?: unknown[];
28
+ }>;
29
+ };
30
+ }>;
31
+ }>;
32
+ }
33
+ export interface WhatsAppChannelOptions {
34
+ appSecret: string;
35
+ verifyToken: string;
36
+ agent: string;
37
+ tenantId?: string;
38
+ }
39
+ export interface WhatsAppChannel extends Channel {
40
+ conversationKey(ref: WhatsAppConversationRef): string;
41
+ parseConversationKey(id: string): WhatsAppConversationRef;
42
+ }
43
+ export declare function whatsAppConversationKey(ref: WhatsAppConversationRef): string;
44
+ export declare function parseWhatsAppConversationKey(id: string): WhatsAppConversationRef;
45
+ export declare function createWhatsAppChannel(options: WhatsAppChannelOptions): WhatsAppChannel;
46
+ export declare function replyInWhatsApp(ref: WhatsAppConversationRef, options: {
47
+ accessToken: string;
48
+ apiVersion?: string;
49
+ fetchImpl?: typeof fetch;
50
+ }): ToolDef<{
51
+ text: string;
52
+ }, unknown>;
53
+ //# sourceMappingURL=whatsapp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp.d.ts","sourceRoot":"","sources":["../src/whatsapp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAkB,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAGpF,MAAM,WAAW,uBAAuB;IAAG,iBAAiB,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAChH,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,OAAO,CAAC,EAAE,KAAK,CAAC;YACd,KAAK,CAAC,EAAE;gBACN,QAAQ,CAAC,EAAE;oBAAE,eAAe,CAAC,EAAE,MAAM,CAAA;iBAAE,CAAC;gBACxC,QAAQ,CAAC,EAAE,KAAK,CAAC;oBAAE,EAAE,CAAC,EAAE,MAAM,CAAC;oBAAC,IAAI,CAAC,EAAE,MAAM,CAAC;oBAAC,IAAI,CAAC,EAAE;wBAAE,IAAI,CAAC,EAAE,MAAM,CAAA;qBAAE,CAAA;iBAAE,CAAC,CAAC;gBAC3E,QAAQ,CAAC,EAAE,KAAK,CAAC;oBAAE,EAAE,CAAC,EAAE,MAAM,CAAC;oBAAC,YAAY,CAAC,EAAE,MAAM,CAAC;oBAAC,MAAM,CAAC,EAAE,MAAM,CAAC;oBAAC,SAAS,CAAC,EAAE,MAAM,CAAC;oBAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAA;iBAAE,CAAC,CAAC;aACnH,CAAC;SACH,CAAC,CAAC;KACJ,CAAC,CAAC;CACJ;AACD,MAAM,WAAW,sBAAsB;IAAG,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;AACpH,MAAM,WAAW,eAAgB,SAAQ,OAAO;IAC9C,eAAe,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,CAAC;IACtD,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,uBAAuB,CAAC;CAC3D;AACD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,CAE5E;AACD,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,uBAAuB,CAKhF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CA0DtF;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,uBAAuB,EAAE,OAAO,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,OAAO,CAAC,CAcjL"}
@@ -0,0 +1,98 @@
1
+ import { conversationKey, defineChannel, defineTool, hexToBytes, parseConversationKey, readJsonBody, verifyHmacSha256 } from '@fabric-harness/sdk/channel';
2
+ import { timingSafeString } from './webhook-shared.js';
3
+ export function whatsAppConversationKey(ref) {
4
+ return conversationKey('whatsapp', 'v1', ref.businessAccountId, ref.phoneNumberId, ref.userPhone);
5
+ }
6
+ export function parseWhatsAppConversationKey(id) {
7
+ const parsed = parseConversationKey(id);
8
+ if (parsed.provider !== 'whatsapp' || parsed.version !== 'v1' || parsed.segments.length !== 3)
9
+ throw new Error(`Invalid WhatsApp conversation key: "${id}".`);
10
+ const [businessAccountId, phoneNumberId, userPhone] = parsed.segments;
11
+ return { businessAccountId, phoneNumberId, userPhone };
12
+ }
13
+ export function createWhatsAppChannel(options) {
14
+ async function verifyRequest(request) {
15
+ const url = new URL(request.url);
16
+ const verifyToken = url.searchParams.get('hub.verify_token');
17
+ if (url.searchParams.get('hub.mode') !== 'subscribe' || !verifyToken || !timingSafeString(verifyToken, options.verifyToken))
18
+ return new Response(null, { status: 403 });
19
+ return new Response(url.searchParams.get('hub.challenge') ?? '', { status: 200 });
20
+ }
21
+ async function webhook(request, ctx) {
22
+ const body = await readJsonBody(request);
23
+ if (!body)
24
+ return new Response(null, { status: 413 });
25
+ const signature = request.headers.get('x-hub-signature-256');
26
+ if (!signature?.startsWith('sha256='))
27
+ return new Response(null, { status: 401 });
28
+ let bytes;
29
+ try {
30
+ bytes = hexToBytes(signature.slice(7));
31
+ }
32
+ catch {
33
+ return new Response(null, { status: 401 });
34
+ }
35
+ if (!(await verifyHmacSha256(options.appSecret, body.raw, bytes)))
36
+ return new Response(null, { status: 401 });
37
+ const payload = body.json;
38
+ const entries = Array.isArray(payload?.entry) ? payload.entry : [];
39
+ for (const entry of entries) {
40
+ const changes = Array.isArray(entry.changes) ? entry.changes : [];
41
+ for (const change of changes) {
42
+ const value = change.value;
43
+ const metadata = value?.metadata;
44
+ const messages = Array.isArray(value?.messages) ? value.messages : [];
45
+ for (const message of messages) {
46
+ const text = message.text?.body;
47
+ const from = message.from;
48
+ if (typeof text !== 'string' || !from || !metadata?.phone_number_id)
49
+ continue;
50
+ const ref = { businessAccountId: String(entry.id ?? ''), phoneNumberId: String(metadata.phone_number_id), userPhone: String(from) };
51
+ await ctx.dispatch(options.agent, {
52
+ instanceId: whatsAppConversationKey(ref), input: { type: 'whatsapp.message', text, messageId: message.id, from },
53
+ ...(message.id ? { dedupeKey: String(message.id) } : {}),
54
+ tenantId: options.tenantId ?? ref.businessAccountId,
55
+ actor: { onBehalfOf: String(from) },
56
+ });
57
+ }
58
+ const statuses = Array.isArray(value?.statuses) ? value.statuses : [];
59
+ for (const status of statuses) {
60
+ if (!status.recipient_id || !metadata?.phone_number_id)
61
+ continue;
62
+ const ref = {
63
+ businessAccountId: String(entry.id ?? ''),
64
+ phoneNumberId: metadata.phone_number_id,
65
+ userPhone: status.recipient_id,
66
+ };
67
+ await ctx.dispatch(options.agent, {
68
+ instanceId: whatsAppConversationKey(ref),
69
+ input: { type: 'whatsapp.status', messageId: status.id, status: status.status, timestamp: status.timestamp, errors: status.errors },
70
+ ...(status.id && status.status ? { dedupeKey: `${status.id}:status:${status.status}` } : {}),
71
+ tenantId: options.tenantId ?? ref.businessAccountId,
72
+ });
73
+ }
74
+ }
75
+ }
76
+ return new Response(null, { status: 200 });
77
+ }
78
+ return defineChannel({
79
+ name: 'whatsapp', routes: [{ method: 'GET', path: '/webhook', handler: verifyRequest }, { method: 'POST', path: '/webhook', handler: webhook }],
80
+ conversationKey: (ref) => whatsAppConversationKey(ref), parseConversationKey: (id) => parseWhatsAppConversationKey(id),
81
+ });
82
+ }
83
+ export function replyInWhatsApp(ref, options) {
84
+ const fetchImpl = options.fetchImpl ?? fetch;
85
+ return defineTool({
86
+ name: 'reply_in_whatsapp', description: 'Reply in the WhatsApp conversation this agent is handling.',
87
+ inputSchema: { type: 'object', additionalProperties: false, properties: { text: { type: 'string', minLength: 1 } }, required: ['text'] },
88
+ metadata: { effect: 'write', provider: 'whatsapp', channel: 'whatsapp' },
89
+ execute: async ({ text }) => {
90
+ const response = await fetchImpl(`https://graph.facebook.com/${options.apiVersion ?? 'v23.0'}/${encodeURIComponent(ref.phoneNumberId)}/messages`, {
91
+ method: 'POST', headers: { authorization: `Bearer ${options.accessToken}`, 'content-type': 'application/json' },
92
+ body: JSON.stringify({ messaging_product: 'whatsapp', to: ref.userPhone, type: 'text', text: { body: text } }),
93
+ });
94
+ return response.json();
95
+ },
96
+ });
97
+ }
98
+ //# sourceMappingURL=whatsapp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp.js","sourceRoot":"","sources":["../src/whatsapp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { Channel, ToolDef } from '@fabric-harness/sdk/channel';
2
+ import { type SimpleConversationRef } from './webhook-shared.js';
3
+ export interface ZendeskConversationRef extends SimpleConversationRef {
4
+ }
5
+ export interface ZendeskWebhookPayload {
6
+ id?: string;
7
+ type?: string;
8
+ account_id?: string;
9
+ ticket?: {
10
+ id?: string | number;
11
+ subject?: string;
12
+ description?: string;
13
+ requester?: {
14
+ id?: string | number;
15
+ };
16
+ submitter?: {
17
+ id?: string | number;
18
+ };
19
+ };
20
+ current_user?: {
21
+ id?: string | number;
22
+ };
23
+ detail?: Record<string, unknown>;
24
+ }
25
+ export interface ZendeskChannelOptions {
26
+ signingSecret: string;
27
+ agent: string;
28
+ subdomain: string;
29
+ tenantId?: string | ((payload: ZendeskWebhookPayload) => string | undefined);
30
+ }
31
+ export interface ZendeskChannel extends Channel {
32
+ conversationKey(ref: ZendeskConversationRef): string;
33
+ parseConversationKey(id: string): ZendeskConversationRef;
34
+ }
35
+ export declare const zendeskConversationKey: (ref: ZendeskConversationRef) => string;
36
+ export declare const parseZendeskConversationKey: (id: string) => SimpleConversationRef;
37
+ export declare function createZendeskChannel(options: ZendeskChannelOptions): ZendeskChannel;
38
+ export declare function commentOnZendeskTicket(ref: ZendeskConversationRef, options: {
39
+ subdomain: string;
40
+ token: string;
41
+ email: string;
42
+ ticketId: string | number;
43
+ fetchImpl?: typeof fetch;
44
+ }): ToolDef<{
45
+ text: string;
46
+ public?: boolean;
47
+ }, unknown>;
48
+ //# sourceMappingURL=zendesk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zendesk.d.ts","sourceRoot":"","sources":["../src/zendesk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAgH,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE/K,MAAM,WAAW,sBAAuB,SAAQ,qBAAqB;CAAG;AACxE,MAAM,WAAW,qBAAqB;IAAG,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE;YAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QAAC,SAAS,CAAC,EAAE;YAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAAC,YAAY,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE;AAC5T,MAAM,WAAW,qBAAqB;IAAG,aAAa,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,qBAAqB,KAAK,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE;AAChL,MAAM,WAAW,cAAe,SAAQ,OAAO;IAAG,eAAe,CAAC,GAAG,EAAE,sBAAsB,GAAG,MAAM,CAAC;IAAC,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,sBAAsB,CAAA;CAAE;AAElK,eAAO,MAAM,sBAAsB,GAAI,KAAK,sBAAsB,WAA0C,CAAC;AAC7G,eAAO,MAAM,2BAA2B,GAAI,IAAI,MAAM,0BAA8C,CAAC;AAErG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,cAAc,CAkBnF;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,sBAAsB,EAAE,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,OAAO,CAAC,CAQ3O"}
@@ -0,0 +1,36 @@
1
+ import { createJsonWebhookChannel, jsonWriteTool, parseSimpleConversationKey, simpleConversationKey, verifyBase64Hmac } from './webhook-shared.js';
2
+ export const zendeskConversationKey = (ref) => simpleConversationKey('zendesk', ref);
3
+ export const parseZendeskConversationKey = (id) => parseSimpleConversationKey('zendesk', id);
4
+ export function createZendeskChannel(options) {
5
+ return createJsonWebhookChannel({
6
+ name: 'zendesk', agent: options.agent,
7
+ authenticate: (request, raw) => {
8
+ const timestamp = request.headers.get('x-zendesk-webhook-signature-timestamp');
9
+ if (!timestamp)
10
+ return false;
11
+ const timestampBytes = new TextEncoder().encode(timestamp);
12
+ const signed = new Uint8Array(timestampBytes.length + raw.length);
13
+ signed.set(timestampBytes);
14
+ signed.set(raw, timestampBytes.length);
15
+ return verifyBase64Hmac(options.signingSecret, signed, request.headers.get('x-zendesk-webhook-signature'));
16
+ },
17
+ normalize: (payload) => {
18
+ const ticketId = payload.ticket?.id;
19
+ const actor = payload.current_user?.id ?? payload.ticket?.submitter?.id ?? payload.ticket?.requester?.id;
20
+ const tenantId = (typeof options.tenantId === 'function' ? options.tenantId(payload) : options.tenantId) ?? payload.account_id ?? options.subdomain;
21
+ if (ticketId === undefined || actor === undefined || !tenantId)
22
+ return undefined;
23
+ return { ref: { tenantId, conversationId: String(ticketId) }, dedupeKey: payload.id ?? `${payload.type}:${ticketId}`, actorId: String(actor), input: { type: `zendesk.${payload.type ?? 'ticket'}`, ticket: payload.ticket, detail: payload.detail } };
24
+ },
25
+ });
26
+ }
27
+ export function commentOnZendeskTicket(ref, options) {
28
+ return jsonWriteTool({
29
+ name: 'comment_on_zendesk_ticket', description: 'Add a governed comment to the Zendesk ticket this agent is handling.', provider: 'zendesk', fetchImpl: options.fetchImpl,
30
+ method: 'PUT', url: `https://${options.subdomain}.zendesk.com/api/v2/tickets/${options.ticketId}.json`,
31
+ headers: { authorization: `Basic ${btoa(`${options.email}/token:${options.token}`)}` },
32
+ inputSchema: { properties: { text: { type: 'string', minLength: 1 }, public: { type: 'boolean' } }, required: ['text'] },
33
+ body: ({ text, public: isPublic }) => ({ ticket: { comment: { body: text, public: isPublic ?? true } } }),
34
+ });
35
+ }
36
+ //# sourceMappingURL=zendesk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zendesk.js","sourceRoot":"","sources":["../src/zendesk.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabric-harness/channels",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Event-ingress channels (Slack, GitHub, …) for Fabric Harness agents.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Fabric",
@@ -11,7 +11,8 @@
11
11
  },
12
12
  "publishConfig": {
13
13
  "registry": "https://registry.npmjs.org",
14
- "access": "public"
14
+ "access": "public",
15
+ "provenance": false
15
16
  },
16
17
  "main": "dist/index.js",
17
18
  "types": "dist/index.d.ts",
@@ -20,6 +21,10 @@
20
21
  "types": "./dist/index.d.ts",
21
22
  "import": "./dist/index.js"
22
23
  },
24
+ "./compatibility": {
25
+ "types": "./dist/compatibility.d.ts",
26
+ "import": "./dist/compatibility.js"
27
+ },
23
28
  "./slack": {
24
29
  "types": "./dist/slack.d.ts",
25
30
  "import": "./dist/slack.js"
@@ -27,23 +32,87 @@
27
32
  "./github": {
28
33
  "types": "./dist/github.d.ts",
29
34
  "import": "./dist/github.js"
35
+ },
36
+ "./discord": {
37
+ "types": "./dist/discord.d.ts",
38
+ "import": "./dist/discord.js"
39
+ },
40
+ "./teams": {
41
+ "types": "./dist/teams.d.ts",
42
+ "import": "./dist/teams.js"
43
+ },
44
+ "./telegram": {
45
+ "types": "./dist/telegram.d.ts",
46
+ "import": "./dist/telegram.js"
47
+ },
48
+ "./twilio": {
49
+ "types": "./dist/twilio.d.ts",
50
+ "import": "./dist/twilio.js"
51
+ },
52
+ "./whatsapp": {
53
+ "types": "./dist/whatsapp.d.ts",
54
+ "import": "./dist/whatsapp.js"
55
+ },
56
+ "./google-chat": {
57
+ "types": "./dist/google-chat.d.ts",
58
+ "import": "./dist/google-chat.js"
59
+ },
60
+ "./linear": {
61
+ "types": "./dist/linear.d.ts",
62
+ "import": "./dist/linear.js"
63
+ },
64
+ "./notion": {
65
+ "types": "./dist/notion.d.ts",
66
+ "import": "./dist/notion.js"
67
+ },
68
+ "./stripe": {
69
+ "types": "./dist/stripe.d.ts",
70
+ "import": "./dist/stripe.js"
71
+ },
72
+ "./zendesk": {
73
+ "types": "./dist/zendesk.d.ts",
74
+ "import": "./dist/zendesk.js"
75
+ },
76
+ "./intercom": {
77
+ "types": "./dist/intercom.d.ts",
78
+ "import": "./dist/intercom.js"
79
+ },
80
+ "./shopify": {
81
+ "types": "./dist/shopify.d.ts",
82
+ "import": "./dist/shopify.js"
83
+ },
84
+ "./messenger": {
85
+ "types": "./dist/messenger.d.ts",
86
+ "import": "./dist/messenger.js"
87
+ },
88
+ "./resend": {
89
+ "types": "./dist/resend.d.ts",
90
+ "import": "./dist/resend.js"
91
+ },
92
+ "./salesforce-marketing-cloud": {
93
+ "types": "./dist/salesforce-marketing-cloud.d.ts",
94
+ "import": "./dist/salesforce-marketing-cloud.js"
30
95
  }
31
96
  },
32
97
  "files": [
33
98
  "dist",
34
99
  "README.md",
35
- "LICENSE"
100
+ "LICENSE",
101
+ "NOTICE"
36
102
  ],
37
103
  "dependencies": {
38
- "@fabric-harness/sdk": "^1.12.1"
104
+ "@fabric-harness/sdk": "^2.2.0"
39
105
  },
40
106
  "devDependencies": {
107
+ "esbuild": "^0.28.1",
108
+ "miniflare": "^4.20260625.0",
41
109
  "typescript": "^5.8.3",
42
110
  "vitest": "^4.1.5"
43
111
  },
44
112
  "scripts": {
45
113
  "build": "tsc -p tsconfig.json",
46
114
  "check": "tsc -b tsconfig.json",
47
- "test": "vitest run"
115
+ "test": "vitest run",
116
+ "test:live": "vitest run test/live.test.ts"
48
117
  }
49
118
  }