skedyul 0.2.69 → 0.2.71

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/.build-stamp CHANGED
@@ -1 +1 @@
1
- 1769572224136
1
+ 1769638280655
package/dist/config.d.ts CHANGED
@@ -602,9 +602,12 @@ export interface PageDefinition {
602
602
  export type WebhookHttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
603
603
  export interface WebhookRequest {
604
604
  method: string;
605
- headers: Record<string, string>;
606
- body: unknown;
605
+ url: string;
606
+ path: string;
607
+ headers: Record<string, string | string[] | undefined>;
607
608
  query: Record<string, string>;
609
+ body: unknown;
610
+ rawBody?: Buffer;
608
611
  }
609
612
  export interface WebhookHandlerContext {
610
613
  appInstallationId: string | null;
package/dist/server.js CHANGED
@@ -679,38 +679,69 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
679
679
  else {
680
680
  parsedBody = rawBody;
681
681
  }
682
- // Build WebhookRequest
683
- const webhookRequest = {
684
- method: req.method ?? 'POST',
685
- url: url.toString(),
686
- path: pathname,
687
- headers: req.headers,
688
- query: Object.fromEntries(url.searchParams.entries()),
689
- body: parsedBody,
690
- rawBody: rawBody ? Buffer.from(rawBody, 'utf-8') : undefined,
691
- };
692
- // Build WebhookContext - check for platform-injected headers
693
- const appInstallationId = req.headers['x-skedyul-app-installation-id'];
694
- const workplaceId = req.headers['x-skedyul-workplace-id'];
695
- const registrationContextHeader = req.headers['x-skedyul-registration-context'];
696
- // Parse registration context from base64-encoded header
697
- let registrationContext = {};
698
- if (registrationContextHeader) {
699
- try {
700
- const decoded = Buffer.from(registrationContextHeader, 'base64').toString('utf-8');
701
- registrationContext = JSON.parse(decoded);
702
- }
703
- catch {
704
- console.warn('Failed to parse X-Skedyul-Registration-Context header');
682
+ // Check if this is an envelope format from the platform
683
+ // Envelope format: { env: {...}, request: {...}, context: {...} }
684
+ const isEnvelope = (typeof parsedBody === 'object' &&
685
+ parsedBody !== null &&
686
+ 'env' in parsedBody &&
687
+ 'request' in parsedBody &&
688
+ 'context' in parsedBody);
689
+ let webhookRequest;
690
+ let webhookContext;
691
+ let requestEnv = {};
692
+ if (isEnvelope) {
693
+ // Platform envelope format - extract env, request, and context
694
+ const envelope = parsedBody;
695
+ requestEnv = envelope.env ?? {};
696
+ // Parse the original request body
697
+ let originalParsedBody = envelope.request.body;
698
+ const originalContentType = envelope.request.headers['content-type'] ?? '';
699
+ if (originalContentType.includes('application/json')) {
700
+ try {
701
+ originalParsedBody = envelope.request.body ? JSON.parse(envelope.request.body) : {};
702
+ }
703
+ catch {
704
+ // Keep as string if JSON parsing fails
705
+ }
705
706
  }
707
+ webhookRequest = {
708
+ method: envelope.request.method,
709
+ url: envelope.request.url,
710
+ path: envelope.request.path,
711
+ headers: envelope.request.headers,
712
+ query: envelope.request.query,
713
+ body: originalParsedBody,
714
+ rawBody: envelope.request.body ? Buffer.from(envelope.request.body, 'utf-8') : undefined,
715
+ };
716
+ webhookContext = {
717
+ env: { ...process.env, ...requestEnv },
718
+ appInstallationId: envelope.context.appInstallationId,
719
+ workplace: envelope.context.workplace,
720
+ registration: envelope.context.registration ?? {},
721
+ };
706
722
  }
707
- const webhookContext = {
708
- env: process.env,
709
- // Platform-injected context for registration-based webhooks
710
- appInstallationId: appInstallationId ?? null,
711
- workplace: workplaceId ? { id: workplaceId, subdomain: null } : null,
712
- registration: registrationContext,
713
- };
723
+ else {
724
+ // Direct request format (legacy or direct calls)
725
+ webhookRequest = {
726
+ method: req.method ?? 'POST',
727
+ url: url.toString(),
728
+ path: pathname,
729
+ headers: req.headers,
730
+ query: Object.fromEntries(url.searchParams.entries()),
731
+ body: parsedBody,
732
+ rawBody: rawBody ? Buffer.from(rawBody, 'utf-8') : undefined,
733
+ };
734
+ webhookContext = {
735
+ env: process.env,
736
+ appInstallationId: null,
737
+ workplace: null,
738
+ registration: {},
739
+ };
740
+ }
741
+ // Temporarily inject env into process.env for skedyul client to use
742
+ // (same pattern as tool handler)
743
+ const originalEnv = { ...process.env };
744
+ Object.assign(process.env, requestEnv);
714
745
  // Invoke the handler
715
746
  let webhookResponse;
716
747
  try {
@@ -721,6 +752,10 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
721
752
  sendJSON(res, 500, { error: 'Webhook handler error' });
722
753
  return;
723
754
  }
755
+ finally {
756
+ // Restore original env
757
+ process.env = originalEnv;
758
+ }
724
759
  // Send response
725
760
  const status = webhookResponse.status ?? 200;
726
761
  const responseHeaders = {
@@ -826,8 +861,8 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
826
861
  key,
827
862
  typeof value === 'string' ? value : value?.[0] ?? '',
828
863
  ]));
829
- const webhookRequest = {
830
- method: req.method,
864
+ const coreWebhookRequest = {
865
+ method: req.method ?? 'POST',
831
866
  headers: normalizedHeaders,
832
867
  body: webhookBody,
833
868
  query: Object.fromEntries(url.searchParams.entries()),
@@ -837,7 +872,7 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
837
872
  ? Buffer.from(rawWebhookBody, 'utf-8')
838
873
  : undefined,
839
874
  };
840
- const webhookResponse = await service_1.coreApiService.dispatchWebhook(webhookRequest);
875
+ const webhookResponse = await service_1.coreApiService.dispatchWebhook(coreWebhookRequest);
841
876
  res.writeHead(webhookResponse.status, {
842
877
  'Content-Type': 'application/json',
843
878
  });
@@ -965,50 +1000,77 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
965
1000
  else {
966
1001
  parsedBody = rawBody;
967
1002
  }
968
- // Build URL
969
- const forwardedProto = event.headers?.['x-forwarded-proto'] ??
970
- event.headers?.['X-Forwarded-Proto'];
971
- const protocol = forwardedProto ?? 'https';
972
- const host = event.headers?.host ?? event.headers?.Host ?? 'localhost';
973
- const queryString = event.queryStringParameters
974
- ? '?' + new URLSearchParams(event.queryStringParameters).toString()
975
- : '';
976
- const webhookUrl = `${protocol}://${host}${path}${queryString}`;
977
- // Build WebhookRequest
978
- const webhookRequest = {
979
- method,
980
- url: webhookUrl,
981
- path,
982
- headers: event.headers,
983
- query: event.queryStringParameters ?? {},
984
- body: parsedBody,
985
- rawBody: rawBody ? Buffer.from(rawBody, 'utf-8') : undefined,
986
- };
987
- // Build WebhookContext - check for platform-injected headers
988
- const appInstallationId = event.headers?.['x-skedyul-app-installation-id'] ??
989
- event.headers?.['X-Skedyul-App-Installation-Id'];
990
- const workplaceId = event.headers?.['x-skedyul-workplace-id'] ??
991
- event.headers?.['X-Skedyul-Workplace-Id'];
992
- const registrationContextHeader = event.headers?.['x-skedyul-registration-context'] ??
993
- event.headers?.['X-Skedyul-Registration-Context'];
994
- // Parse registration context from base64-encoded header
995
- let registrationContext = {};
996
- if (registrationContextHeader) {
997
- try {
998
- const decoded = Buffer.from(registrationContextHeader, 'base64').toString('utf-8');
999
- registrationContext = JSON.parse(decoded);
1000
- }
1001
- catch {
1002
- console.warn('Failed to parse X-Skedyul-Registration-Context header');
1003
+ // Check if this is an envelope format from the platform
1004
+ // Envelope format: { env: {...}, request: {...}, context: {...} }
1005
+ const isEnvelope = (typeof parsedBody === 'object' &&
1006
+ parsedBody !== null &&
1007
+ 'env' in parsedBody &&
1008
+ 'request' in parsedBody &&
1009
+ 'context' in parsedBody);
1010
+ let webhookRequest;
1011
+ let webhookContext;
1012
+ let requestEnv = {};
1013
+ if (isEnvelope) {
1014
+ // Platform envelope format - extract env, request, and context
1015
+ const envelope = parsedBody;
1016
+ requestEnv = envelope.env ?? {};
1017
+ // Parse the original request body
1018
+ let originalParsedBody = envelope.request.body;
1019
+ const originalContentType = envelope.request.headers['content-type'] ?? '';
1020
+ if (originalContentType.includes('application/json')) {
1021
+ try {
1022
+ originalParsedBody = envelope.request.body ? JSON.parse(envelope.request.body) : {};
1023
+ }
1024
+ catch {
1025
+ // Keep as string if JSON parsing fails
1026
+ }
1003
1027
  }
1028
+ webhookRequest = {
1029
+ method: envelope.request.method,
1030
+ url: envelope.request.url,
1031
+ path: envelope.request.path,
1032
+ headers: envelope.request.headers,
1033
+ query: envelope.request.query,
1034
+ body: originalParsedBody,
1035
+ rawBody: envelope.request.body ? Buffer.from(envelope.request.body, 'utf-8') : undefined,
1036
+ };
1037
+ webhookContext = {
1038
+ env: { ...process.env, ...requestEnv },
1039
+ appInstallationId: envelope.context.appInstallationId,
1040
+ workplace: envelope.context.workplace,
1041
+ registration: envelope.context.registration ?? {},
1042
+ };
1004
1043
  }
1005
- const webhookContext = {
1006
- env: process.env,
1007
- // Platform-injected context for registration-based webhooks
1008
- appInstallationId: appInstallationId ?? null,
1009
- workplace: workplaceId ? { id: workplaceId, subdomain: null } : null,
1010
- registration: registrationContext,
1011
- };
1044
+ else {
1045
+ // Direct request format (legacy or direct calls)
1046
+ const forwardedProto = event.headers?.['x-forwarded-proto'] ??
1047
+ event.headers?.['X-Forwarded-Proto'];
1048
+ const protocol = forwardedProto ?? 'https';
1049
+ const host = event.headers?.host ?? event.headers?.Host ?? 'localhost';
1050
+ const queryString = event.queryStringParameters
1051
+ ? '?' + new URLSearchParams(event.queryStringParameters).toString()
1052
+ : '';
1053
+ const webhookUrl = `${protocol}://${host}${path}${queryString}`;
1054
+ webhookRequest = {
1055
+ method,
1056
+ url: webhookUrl,
1057
+ path,
1058
+ headers: event.headers,
1059
+ query: event.queryStringParameters ?? {},
1060
+ body: parsedBody,
1061
+ rawBody: rawBody ? Buffer.from(rawBody, 'utf-8') : undefined,
1062
+ };
1063
+ webhookContext = {
1064
+ env: process.env,
1065
+ appInstallationId: null,
1066
+ workplace: null,
1067
+ registration: {},
1068
+ };
1069
+ }
1070
+ // Temporarily inject env into process.env for skedyul client to use
1071
+ // (same pattern as tool handler)
1072
+ const originalEnv = { ...process.env };
1073
+ Object.assign(process.env, requestEnv);
1012
1074
  // Invoke the handler
1013
1075
  let webhookResponse;
1014
1076
  try {
@@ -1018,6 +1080,10 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
1018
1080
  console.error(`Webhook handler '${handle}' error:`, err);
1019
1081
  return createResponse(500, { error: 'Webhook handler error' }, headers);
1020
1082
  }
1083
+ finally {
1084
+ // Restore original env
1085
+ process.env = originalEnv;
1086
+ }
1021
1087
  // Build response headers
1022
1088
  const responseHeaders = {
1023
1089
  ...headers,
@@ -1072,9 +1138,9 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
1072
1138
  const protocol = forwardedProto ?? 'https';
1073
1139
  const host = event.headers?.host ?? event.headers?.Host ?? 'localhost';
1074
1140
  const webhookUrl = `${protocol}://${host}${event.path}`;
1075
- const webhookRequest = {
1141
+ const coreWebhookRequest = {
1076
1142
  method,
1077
- headers: event.headers ?? {},
1143
+ headers: (event.headers ?? {}),
1078
1144
  body: webhookBody,
1079
1145
  query: event.queryStringParameters ?? {},
1080
1146
  url: webhookUrl,
@@ -1083,7 +1149,7 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
1083
1149
  ? Buffer.from(rawWebhookBody, 'utf-8')
1084
1150
  : undefined,
1085
1151
  };
1086
- const webhookResponse = await service_1.coreApiService.dispatchWebhook(webhookRequest);
1152
+ const webhookResponse = await service_1.coreApiService.dispatchWebhook(coreWebhookRequest);
1087
1153
  return createResponse(webhookResponse.status, webhookResponse.body ?? {}, headers);
1088
1154
  }
1089
1155
  if (path === '/estimate' && method === 'POST') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skedyul",
3
- "version": "0.2.69",
3
+ "version": "0.2.71",
4
4
  "description": "The Skedyul SDK for Node.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",