skedyul 0.1.20 → 0.1.22

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.
@@ -33,6 +33,20 @@ export declare const workplace: {
33
33
  list(args?: ListArgs): Promise<Workplace[]>;
34
34
  get(id: string): Promise<Workplace>;
35
35
  };
36
+ export interface ReceiveMessageInput {
37
+ /** Communication channel ID */
38
+ communicationChannelId: string;
39
+ /** Sender's identifier (e.g., phone number, email) */
40
+ from: string;
41
+ /** Message content */
42
+ message: string;
43
+ /** Optional remote/external message ID (e.g., Twilio MessageSid) */
44
+ remoteId?: string;
45
+ }
46
+ export interface ReceiveMessageResponse {
47
+ success: boolean;
48
+ messageId?: string;
49
+ }
36
50
  export declare const communicationChannel: {
37
51
  /**
38
52
  * List communication channels with optional filters.
@@ -48,5 +62,23 @@ export declare const communicationChannel: {
48
62
  */
49
63
  list(args?: ListArgs): Promise<CommunicationChannel[]>;
50
64
  get(id: string): Promise<CommunicationChannel | null>;
65
+ /**
66
+ * Receive an inbound message on a communication channel.
67
+ *
68
+ * This is typically called from webhook handlers to process incoming messages
69
+ * (e.g., SMS from Twilio, emails, WhatsApp messages).
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * // In a webhook handler
74
+ * const result = await communicationChannel.receiveMessage({
75
+ * communicationChannelId: channel.id,
76
+ * from: '+1234567890',
77
+ * message: 'Hello!',
78
+ * remoteId: 'twilio-message-sid-123',
79
+ * });
80
+ * ```
81
+ */
82
+ receiveMessage(input: ReceiveMessageInput): Promise<ReceiveMessageResponse>;
51
83
  };
52
84
  export {};
@@ -97,4 +97,30 @@ exports.communicationChannel = {
97
97
  const payload = (await callCore('communicationChannel.get', { id }));
98
98
  return payload.channel;
99
99
  },
100
+ /**
101
+ * Receive an inbound message on a communication channel.
102
+ *
103
+ * This is typically called from webhook handlers to process incoming messages
104
+ * (e.g., SMS from Twilio, emails, WhatsApp messages).
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * // In a webhook handler
109
+ * const result = await communicationChannel.receiveMessage({
110
+ * communicationChannelId: channel.id,
111
+ * from: '+1234567890',
112
+ * message: 'Hello!',
113
+ * remoteId: 'twilio-message-sid-123',
114
+ * });
115
+ * ```
116
+ */
117
+ async receiveMessage(input) {
118
+ const payload = (await callCore('communicationChannel.receiveMessage', {
119
+ communicationChannelId: input.communicationChannelId,
120
+ from: input.from,
121
+ message: input.message,
122
+ ...(input.remoteId ? { remoteId: input.remoteId } : {}),
123
+ }));
124
+ return payload;
125
+ },
100
126
  };
@@ -20,9 +20,12 @@ export interface Message {
20
20
  }
21
21
  export interface WebhookRequest {
22
22
  method: string;
23
+ url?: string;
24
+ path?: string;
23
25
  headers: Record<string, string>;
24
- body?: unknown;
25
26
  query?: Record<string, string | undefined>;
27
+ body?: unknown;
28
+ rawBody?: Buffer;
26
29
  }
27
30
  export interface WebhookResponse {
28
31
  status: number;
package/dist/server.js CHANGED
@@ -354,23 +354,27 @@ function createCallToolHandler(registry, state, onMaxRequests) {
354
354
  }
355
355
  };
356
356
  }
357
- function parseJSONBody(req) {
357
+ function readRawRequestBody(req) {
358
358
  return new Promise((resolve, reject) => {
359
359
  let body = '';
360
360
  req.on('data', (chunk) => {
361
361
  body += chunk.toString();
362
362
  });
363
363
  req.on('end', () => {
364
- try {
365
- resolve(body ? JSON.parse(body) : {});
366
- }
367
- catch (err) {
368
- reject(err);
369
- }
364
+ resolve(body);
370
365
  });
371
366
  req.on('error', reject);
372
367
  });
373
368
  }
369
+ async function parseJSONBody(req) {
370
+ const rawBody = await readRawRequestBody(req);
371
+ try {
372
+ return rawBody ? JSON.parse(rawBody) : {};
373
+ }
374
+ catch (err) {
375
+ throw err;
376
+ }
377
+ }
374
378
  function sendJSON(res, statusCode, data) {
375
379
  res.writeHead(statusCode, { 'Content-Type': 'application/json' });
376
380
  res.end(JSON.stringify(data));
@@ -551,22 +555,36 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
551
555
  return;
552
556
  }
553
557
  if (pathname === '/core/webhook' && req.method === 'POST') {
554
- let webhookBody = undefined;
558
+ let rawWebhookBody;
559
+ try {
560
+ rawWebhookBody = await readRawRequestBody(req);
561
+ }
562
+ catch {
563
+ sendJSON(res, 400, { status: 'parse-error' });
564
+ return;
565
+ }
566
+ let webhookBody;
555
567
  try {
556
- webhookBody = (await parseJSONBody(req));
568
+ webhookBody = rawWebhookBody ? JSON.parse(rawWebhookBody) : {};
557
569
  }
558
570
  catch {
559
571
  sendJSON(res, 400, { status: 'parse-error' });
560
572
  return;
561
573
  }
574
+ const normalizedHeaders = Object.fromEntries(Object.entries(req.headers).map(([key, value]) => [
575
+ key,
576
+ typeof value === 'string' ? value : value?.[0] ?? '',
577
+ ]));
562
578
  const webhookRequest = {
563
579
  method: req.method,
564
- headers: Object.fromEntries(Object.entries(req.headers).map(([key, value]) => [
565
- key,
566
- typeof value === 'string' ? value : value?.[0] ?? '',
567
- ])),
580
+ headers: normalizedHeaders,
568
581
  body: webhookBody,
569
582
  query: Object.fromEntries(url.searchParams.entries()),
583
+ url: url.toString(),
584
+ path: url.pathname,
585
+ rawBody: rawWebhookBody
586
+ ? Buffer.from(rawWebhookBody, 'utf-8')
587
+ : undefined,
570
588
  };
571
589
  const webhookResponse = await service_1.coreApiService.dispatchWebhook(webhookRequest);
572
590
  res.writeHead(webhookResponse.status, {
@@ -675,18 +693,29 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
675
693
  return createResponse(result.status, result.payload, headers);
676
694
  }
677
695
  if (path === '/core/webhook' && method === 'POST') {
678
- let webhookBody = undefined;
696
+ const rawWebhookBody = event.body ?? '';
697
+ let webhookBody;
679
698
  try {
680
- webhookBody = event.body ? JSON.parse(event.body) : {};
699
+ webhookBody = rawWebhookBody ? JSON.parse(rawWebhookBody) : {};
681
700
  }
682
701
  catch {
683
702
  return createResponse(400, { status: 'parse-error' }, headers);
684
703
  }
704
+ const forwardedProto = event.headers?.['x-forwarded-proto'] ??
705
+ event.headers?.['X-Forwarded-Proto'];
706
+ const protocol = forwardedProto ?? 'https';
707
+ const host = event.headers?.host ?? event.headers?.Host ?? 'localhost';
708
+ const webhookUrl = `${protocol}://${host}${event.path}`;
685
709
  const webhookRequest = {
686
710
  method,
687
711
  headers: event.headers ?? {},
688
712
  body: webhookBody,
689
713
  query: event.queryStringParameters ?? {},
714
+ url: webhookUrl,
715
+ path: event.path,
716
+ rawBody: rawWebhookBody
717
+ ? Buffer.from(rawWebhookBody, 'utf-8')
718
+ : undefined,
690
719
  };
691
720
  const webhookResponse = await service_1.coreApiService.dispatchWebhook(webhookRequest);
692
721
  return createResponse(webhookResponse.status, webhookResponse.body ?? {}, headers);
package/dist/types.d.ts CHANGED
@@ -127,7 +127,11 @@ export interface WebhookResponse {
127
127
  headers?: Record<string, string>;
128
128
  body?: unknown;
129
129
  }
130
- export type WebhookHandler = (request: WebhookRequest) => Promise<WebhookResponse> | WebhookResponse;
130
+ export interface WebhookContext {
131
+ /** Environment variables available during webhook handling */
132
+ env: Record<string, string | undefined>;
133
+ }
134
+ export type WebhookHandler = (request: WebhookRequest, context: WebhookContext) => Promise<WebhookResponse> | WebhookResponse;
131
135
  export interface WebhookDefinition {
132
136
  name: string;
133
137
  description: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skedyul",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "The Skedyul SDK for Node.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",