@contractspec/integration.runtime 2.10.0 → 3.0.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 (62) hide show
  1. package/dist/channel/dispatcher.d.ts +37 -0
  2. package/dist/channel/dispatcher.js +130 -0
  3. package/dist/channel/dispatcher.test.d.ts +1 -0
  4. package/dist/channel/github.d.ts +47 -0
  5. package/dist/channel/github.js +58 -0
  6. package/dist/channel/github.test.d.ts +1 -0
  7. package/dist/channel/index.d.ts +14 -0
  8. package/dist/channel/index.js +1420 -0
  9. package/dist/channel/memory-store.d.ts +28 -0
  10. package/dist/channel/memory-store.js +223 -0
  11. package/dist/channel/policy.d.ts +19 -0
  12. package/dist/channel/policy.js +110 -0
  13. package/dist/channel/policy.test.d.ts +1 -0
  14. package/dist/channel/postgres-queries.d.ts +11 -0
  15. package/dist/channel/postgres-queries.js +222 -0
  16. package/dist/channel/postgres-schema.d.ts +1 -0
  17. package/dist/channel/postgres-schema.js +94 -0
  18. package/dist/channel/postgres-store.d.ts +21 -0
  19. package/dist/channel/postgres-store.js +498 -0
  20. package/dist/channel/postgres-store.test.d.ts +1 -0
  21. package/dist/channel/replay-fixtures.d.ts +8 -0
  22. package/dist/channel/replay-fixtures.js +31 -0
  23. package/dist/channel/replay.test.d.ts +1 -0
  24. package/dist/channel/service.d.ts +26 -0
  25. package/dist/channel/service.js +287 -0
  26. package/dist/channel/service.test.d.ts +1 -0
  27. package/dist/channel/slack.d.ts +42 -0
  28. package/dist/channel/slack.js +82 -0
  29. package/dist/channel/slack.test.d.ts +1 -0
  30. package/dist/channel/store.d.ts +83 -0
  31. package/dist/channel/store.js +1 -0
  32. package/dist/channel/telemetry.d.ts +17 -0
  33. package/dist/channel/telemetry.js +1 -0
  34. package/dist/channel/types.d.ts +111 -0
  35. package/dist/channel/types.js +1 -0
  36. package/dist/channel/whatsapp-meta.d.ts +55 -0
  37. package/dist/channel/whatsapp-meta.js +66 -0
  38. package/dist/channel/whatsapp-meta.test.d.ts +1 -0
  39. package/dist/channel/whatsapp-twilio.d.ts +20 -0
  40. package/dist/channel/whatsapp-twilio.js +61 -0
  41. package/dist/channel/whatsapp-twilio.test.d.ts +1 -0
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.js +1418 -1
  44. package/dist/node/channel/dispatcher.js +129 -0
  45. package/dist/node/channel/github.js +57 -0
  46. package/dist/node/channel/index.js +1419 -0
  47. package/dist/node/channel/memory-store.js +222 -0
  48. package/dist/node/channel/policy.js +109 -0
  49. package/dist/node/channel/postgres-queries.js +221 -0
  50. package/dist/node/channel/postgres-schema.js +93 -0
  51. package/dist/node/channel/postgres-store.js +497 -0
  52. package/dist/node/channel/replay-fixtures.js +30 -0
  53. package/dist/node/channel/service.js +286 -0
  54. package/dist/node/channel/slack.js +81 -0
  55. package/dist/node/channel/store.js +0 -0
  56. package/dist/node/channel/telemetry.js +0 -0
  57. package/dist/node/channel/types.js +0 -0
  58. package/dist/node/channel/whatsapp-meta.js +65 -0
  59. package/dist/node/channel/whatsapp-twilio.js +60 -0
  60. package/dist/node/index.js +1418 -1
  61. package/dist/runtime.health.test.d.ts +1 -0
  62. package/package.json +213 -6
@@ -0,0 +1,66 @@
1
+ // @bun
2
+ // src/channel/whatsapp-meta.ts
3
+ import { createHmac, timingSafeEqual } from "crypto";
4
+ function verifyMetaSignature(input) {
5
+ if (!input.signatureHeader) {
6
+ return { valid: false, reason: "missing_signature" };
7
+ }
8
+ const expected = `sha256=${createHmac("sha256", input.appSecret).update(input.rawBody).digest("hex")}`;
9
+ const expectedBuffer = Buffer.from(expected, "utf8");
10
+ const providedBuffer = Buffer.from(input.signatureHeader, "utf8");
11
+ if (expectedBuffer.length !== providedBuffer.length) {
12
+ return { valid: false, reason: "signature_length_mismatch" };
13
+ }
14
+ return timingSafeEqual(expectedBuffer, providedBuffer) ? { valid: true } : { valid: false, reason: "signature_mismatch" };
15
+ }
16
+ function parseMetaWebhookPayload(rawBody) {
17
+ return JSON.parse(rawBody);
18
+ }
19
+ function normalizeMetaWhatsappInboundEvents(input) {
20
+ const events = [];
21
+ for (const entry of input.payload.entry ?? []) {
22
+ for (const change of entry.changes ?? []) {
23
+ const value = change.value;
24
+ if (!value)
25
+ continue;
26
+ const phoneNumberId = value.metadata?.phone_number_id;
27
+ for (const message of value.messages ?? []) {
28
+ const from = message.from;
29
+ const messageId = message.id;
30
+ const text = message.text?.body;
31
+ if (!from || !messageId || !text)
32
+ continue;
33
+ const occurredAt = message.timestamp ? new Date(Number(message.timestamp) * 1000) : new Date;
34
+ events.push({
35
+ workspaceId: input.workspaceId,
36
+ providerKey: "messaging.whatsapp.meta",
37
+ externalEventId: messageId,
38
+ eventType: "whatsapp.meta.message",
39
+ occurredAt,
40
+ signatureValid: input.signatureValid,
41
+ traceId: input.traceId,
42
+ rawPayload: input.rawBody,
43
+ thread: {
44
+ externalThreadId: from,
45
+ externalChannelId: phoneNumberId,
46
+ externalUserId: from
47
+ },
48
+ message: {
49
+ text,
50
+ externalMessageId: messageId
51
+ },
52
+ metadata: {
53
+ messageType: message.type ?? "text",
54
+ phoneNumberId: phoneNumberId ?? ""
55
+ }
56
+ });
57
+ }
58
+ }
59
+ }
60
+ return events;
61
+ }
62
+ export {
63
+ verifyMetaSignature,
64
+ parseMetaWebhookPayload,
65
+ normalizeMetaWhatsappInboundEvents
66
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { ChannelInboundEvent } from './types';
2
+ export interface TwilioWebhookVerificationInput {
3
+ authToken: string;
4
+ signatureHeader: string | null;
5
+ requestUrl: string;
6
+ formBody: URLSearchParams;
7
+ }
8
+ export interface TwilioSignatureVerificationResult {
9
+ valid: boolean;
10
+ reason?: string;
11
+ }
12
+ export declare function verifyTwilioSignature(input: TwilioWebhookVerificationInput): TwilioSignatureVerificationResult;
13
+ export declare function parseTwilioFormPayload(rawBody: string): URLSearchParams;
14
+ export declare function normalizeTwilioWhatsappInboundEvent(input: {
15
+ workspaceId: string;
16
+ formBody: URLSearchParams;
17
+ signatureValid: boolean;
18
+ traceId?: string;
19
+ rawBody?: string;
20
+ }): ChannelInboundEvent | null;
@@ -0,0 +1,61 @@
1
+ // @bun
2
+ // src/channel/whatsapp-twilio.ts
3
+ import { createHmac, timingSafeEqual } from "crypto";
4
+ function verifyTwilioSignature(input) {
5
+ if (!input.signatureHeader) {
6
+ return { valid: false, reason: "missing_signature" };
7
+ }
8
+ const sortedKeys = Array.from(input.formBody.keys()).sort();
9
+ let payload = input.requestUrl;
10
+ for (const key of sortedKeys) {
11
+ const value = input.formBody.get(key) ?? "";
12
+ payload += `${key}${value}`;
13
+ }
14
+ const expected = createHmac("sha1", input.authToken).update(payload).digest("base64");
15
+ const expectedBuffer = Buffer.from(expected, "utf8");
16
+ const providedBuffer = Buffer.from(input.signatureHeader, "utf8");
17
+ if (expectedBuffer.length !== providedBuffer.length) {
18
+ return { valid: false, reason: "signature_length_mismatch" };
19
+ }
20
+ return timingSafeEqual(expectedBuffer, providedBuffer) ? { valid: true } : { valid: false, reason: "signature_mismatch" };
21
+ }
22
+ function parseTwilioFormPayload(rawBody) {
23
+ return new URLSearchParams(rawBody);
24
+ }
25
+ function normalizeTwilioWhatsappInboundEvent(input) {
26
+ const messageSid = input.formBody.get("MessageSid");
27
+ const from = input.formBody.get("From");
28
+ const to = input.formBody.get("To");
29
+ const body = input.formBody.get("Body");
30
+ if (!messageSid || !from || !body) {
31
+ return null;
32
+ }
33
+ return {
34
+ workspaceId: input.workspaceId,
35
+ providerKey: "messaging.whatsapp.twilio",
36
+ externalEventId: messageSid,
37
+ eventType: "whatsapp.twilio.message",
38
+ occurredAt: new Date,
39
+ signatureValid: input.signatureValid,
40
+ traceId: input.traceId,
41
+ rawPayload: input.rawBody,
42
+ thread: {
43
+ externalThreadId: from,
44
+ externalChannelId: to ?? undefined,
45
+ externalUserId: from
46
+ },
47
+ message: {
48
+ text: body,
49
+ externalMessageId: messageSid
50
+ },
51
+ metadata: {
52
+ accountSid: input.formBody.get("AccountSid") ?? "",
53
+ profileName: input.formBody.get("ProfileName") ?? ""
54
+ }
55
+ };
56
+ }
57
+ export {
58
+ verifyTwilioSignature,
59
+ parseTwilioFormPayload,
60
+ normalizeTwilioWhatsappInboundEvent
61
+ };
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './runtime';
2
2
  export * from './health';
3
+ export * from './channel';
3
4
  export * from './secrets';