@cstar.help/js 0.1.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.
- package/README.md +202 -0
- package/dist/chat/index.cjs +238 -0
- package/dist/chat/index.d.cts +172 -0
- package/dist/chat/index.d.ts +172 -0
- package/dist/chat/index.js +213 -0
- package/dist/index.cjs +364 -0
- package/dist/index.d.cts +519 -0
- package/dist/index.d.ts +519 -0
- package/dist/index.js +331 -0
- package/dist/library/index.cjs +97 -0
- package/dist/library/index.d.cts +82 -0
- package/dist/library/index.d.ts +82 -0
- package/dist/library/index.js +72 -0
- package/dist/webhook/index.cjs +84 -0
- package/dist/webhook/index.d.cts +163 -0
- package/dist/webhook/index.d.ts +163 -0
- package/dist/webhook/index.js +62 -0
- package/package.json +85 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/webhook/index.ts
|
|
21
|
+
var webhook_exports = {};
|
|
22
|
+
__export(webhook_exports, {
|
|
23
|
+
WebhookSignatureVerificationError: () => WebhookSignatureVerificationError,
|
|
24
|
+
constructEvent: () => constructEvent,
|
|
25
|
+
constructEventAsync: () => constructEventAsync,
|
|
26
|
+
verifySignature: () => verifySignature,
|
|
27
|
+
verifySignatureAsync: () => verifySignatureAsync
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(webhook_exports);
|
|
30
|
+
var WebhookSignatureVerificationError = class extends Error {
|
|
31
|
+
constructor(message) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "WebhookSignatureVerificationError";
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
function constructEvent(rawBody, signature, secret) {
|
|
37
|
+
if (!verifySignature(rawBody, signature, secret)) {
|
|
38
|
+
throw new WebhookSignatureVerificationError(
|
|
39
|
+
"Webhook signature verification failed. Ensure you are using the raw request body and the correct endpoint secret."
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return JSON.parse(rawBody);
|
|
43
|
+
}
|
|
44
|
+
async function constructEventAsync(rawBody, signature, secret) {
|
|
45
|
+
const valid = await verifySignatureAsync(rawBody, signature, secret);
|
|
46
|
+
if (!valid) {
|
|
47
|
+
throw new WebhookSignatureVerificationError(
|
|
48
|
+
"Webhook signature verification failed. Ensure you are using the raw request body and the correct endpoint secret."
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return JSON.parse(rawBody);
|
|
52
|
+
}
|
|
53
|
+
function verifySignature(rawBody, signature, secret) {
|
|
54
|
+
const crypto2 = require("crypto");
|
|
55
|
+
const expected = "sha256=" + crypto2.createHmac("sha256", secret).update(rawBody).digest("hex");
|
|
56
|
+
if (signature.length !== expected.length) return false;
|
|
57
|
+
return crypto2.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
|
58
|
+
}
|
|
59
|
+
async function verifySignatureAsync(rawBody, signature, secret) {
|
|
60
|
+
const encoder = new TextEncoder();
|
|
61
|
+
const key = await crypto.subtle.importKey(
|
|
62
|
+
"raw",
|
|
63
|
+
encoder.encode(secret),
|
|
64
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
65
|
+
false,
|
|
66
|
+
["sign"]
|
|
67
|
+
);
|
|
68
|
+
const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(rawBody));
|
|
69
|
+
const expected = "sha256=" + Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
70
|
+
if (signature.length !== expected.length) return false;
|
|
71
|
+
let result = 0;
|
|
72
|
+
for (let i = 0; i < signature.length; i++) {
|
|
73
|
+
result |= signature.charCodeAt(i) ^ expected.charCodeAt(i);
|
|
74
|
+
}
|
|
75
|
+
return result === 0;
|
|
76
|
+
}
|
|
77
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
78
|
+
0 && (module.exports = {
|
|
79
|
+
WebhookSignatureVerificationError,
|
|
80
|
+
constructEvent,
|
|
81
|
+
constructEventAsync,
|
|
82
|
+
verifySignature,
|
|
83
|
+
verifySignatureAsync
|
|
84
|
+
});
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/** Metadata: string key-value pairs. Max 50 keys, 40-char keys, 500-char values. */
|
|
2
|
+
type Metadata = Record<string, string>;
|
|
3
|
+
|
|
4
|
+
/** A message on a ticket. */
|
|
5
|
+
interface Message {
|
|
6
|
+
id: string;
|
|
7
|
+
object: 'message';
|
|
8
|
+
sender: 'customer' | 'agent' | 'system';
|
|
9
|
+
content: string;
|
|
10
|
+
senderId: string | null;
|
|
11
|
+
senderName: string | null;
|
|
12
|
+
senderAvatarUrl: string | null;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
mergedFromShortId: string | null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** A cStar support ticket. */
|
|
18
|
+
interface Ticket {
|
|
19
|
+
id: string;
|
|
20
|
+
object: 'ticket';
|
|
21
|
+
title: string;
|
|
22
|
+
priority: 'low' | 'normal' | 'high' | 'urgent';
|
|
23
|
+
status: string;
|
|
24
|
+
customerId: string | null;
|
|
25
|
+
customerName: string | null;
|
|
26
|
+
assignedTo: string | null;
|
|
27
|
+
tags: string[];
|
|
28
|
+
notes: string | null;
|
|
29
|
+
messageCount: number;
|
|
30
|
+
responseDeadline: string | null;
|
|
31
|
+
resolutionDeadline: string | null;
|
|
32
|
+
firstResponseAt: string | null;
|
|
33
|
+
responseTier: string | null;
|
|
34
|
+
resolutionTier: string | null;
|
|
35
|
+
slaPaused: boolean;
|
|
36
|
+
metadata: Metadata;
|
|
37
|
+
createdAt: string;
|
|
38
|
+
closedAt: string | null;
|
|
39
|
+
updatedAt: string;
|
|
40
|
+
/** Present when expand includes 'messages' or on single-ticket GET. */
|
|
41
|
+
messages?: Message[];
|
|
42
|
+
/** Present when expand includes 'customer'. */
|
|
43
|
+
customer?: TicketCustomerSummary | null;
|
|
44
|
+
}
|
|
45
|
+
/** Inline customer summary when expanding on a ticket. */
|
|
46
|
+
interface TicketCustomerSummary {
|
|
47
|
+
id: string;
|
|
48
|
+
object: 'customer';
|
|
49
|
+
name: string;
|
|
50
|
+
email: string;
|
|
51
|
+
sentiment: string;
|
|
52
|
+
status: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A cStar customer. */
|
|
56
|
+
interface Customer {
|
|
57
|
+
id: string;
|
|
58
|
+
object: 'customer';
|
|
59
|
+
name: string;
|
|
60
|
+
email: string;
|
|
61
|
+
sentiment: string;
|
|
62
|
+
status: string;
|
|
63
|
+
tags: string[];
|
|
64
|
+
notes: string | null;
|
|
65
|
+
customFields: Record<string, unknown>;
|
|
66
|
+
ticketCount: number;
|
|
67
|
+
metadata: Metadata;
|
|
68
|
+
createdAt: string;
|
|
69
|
+
updatedAt: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** A cStar knowledge base article. */
|
|
73
|
+
interface Article {
|
|
74
|
+
id: string;
|
|
75
|
+
object: 'article';
|
|
76
|
+
title: string;
|
|
77
|
+
slug: string | null;
|
|
78
|
+
excerpt: string | null;
|
|
79
|
+
content: string | null;
|
|
80
|
+
category: string;
|
|
81
|
+
status: 'draft' | 'published';
|
|
82
|
+
tags: string[];
|
|
83
|
+
notes: string | null;
|
|
84
|
+
viewCount: number;
|
|
85
|
+
useCount: number;
|
|
86
|
+
readTime: string;
|
|
87
|
+
isPublic: boolean;
|
|
88
|
+
publishedAt: string | null;
|
|
89
|
+
metaDescription: string | null;
|
|
90
|
+
metadata: Metadata;
|
|
91
|
+
createdAt: string;
|
|
92
|
+
updatedAt: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** All webhook event types supported by cStar. */
|
|
96
|
+
type WebhookEventType = 'ticket.created' | 'ticket.updated' | 'ticket.closed' | 'ticket.message_added' | 'customer.created' | 'customer.updated' | 'article.created' | 'article.published' | 'article.updated' | 'boss.spawned' | 'boss.defeated' | 'player.level_up' | 'achievement.unlocked' | 'survey.submitted';
|
|
97
|
+
/** A webhook event delivered to your endpoint. */
|
|
98
|
+
interface WebhookEvent<T extends WebhookEventType = WebhookEventType> {
|
|
99
|
+
/** Unique event ID (idempotency key). */
|
|
100
|
+
id: string;
|
|
101
|
+
/** Event type. */
|
|
102
|
+
type: T;
|
|
103
|
+
/** When the event was created (ISO 8601). */
|
|
104
|
+
created_at: string;
|
|
105
|
+
/** Team that owns this event. */
|
|
106
|
+
team_id: string;
|
|
107
|
+
/** Event-specific payload. */
|
|
108
|
+
data: WebhookEventData<T>;
|
|
109
|
+
}
|
|
110
|
+
/** Discriminated union mapping event types to their data payloads. */
|
|
111
|
+
type WebhookEventData<T extends WebhookEventType> = T extends 'ticket.created' | 'ticket.updated' | 'ticket.closed' ? {
|
|
112
|
+
ticket: Ticket;
|
|
113
|
+
} : T extends 'ticket.message_added' ? {
|
|
114
|
+
ticket: Ticket;
|
|
115
|
+
message: Message;
|
|
116
|
+
} : T extends 'customer.created' | 'customer.updated' ? {
|
|
117
|
+
customer: Customer;
|
|
118
|
+
} : T extends 'article.created' | 'article.published' | 'article.updated' ? {
|
|
119
|
+
article: Article;
|
|
120
|
+
} : Record<string, unknown>;
|
|
121
|
+
|
|
122
|
+
/** Thrown when webhook signature verification fails. */
|
|
123
|
+
declare class WebhookSignatureVerificationError extends Error {
|
|
124
|
+
constructor(message: string);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Verify a webhook signature and parse the event (synchronous, Node.js only).
|
|
128
|
+
*
|
|
129
|
+
* Uses Node.js `crypto` module for timing-safe HMAC comparison.
|
|
130
|
+
* For browser/edge environments, use `constructEventAsync()`.
|
|
131
|
+
*
|
|
132
|
+
* @param rawBody - Raw request body as a string (NOT parsed JSON)
|
|
133
|
+
* @param signature - Value of the `X-Signature` header
|
|
134
|
+
* @param secret - Your webhook endpoint's secret (`whsec_*`)
|
|
135
|
+
* @returns Parsed and verified webhook event
|
|
136
|
+
* @throws {WebhookSignatureVerificationError} If verification fails
|
|
137
|
+
*/
|
|
138
|
+
declare function constructEvent(rawBody: string, signature: string, secret: string): WebhookEvent;
|
|
139
|
+
/**
|
|
140
|
+
* Verify a webhook signature and parse the event (async, works everywhere).
|
|
141
|
+
*
|
|
142
|
+
* Uses the Web Crypto API — compatible with browsers, Deno, Cloudflare Workers,
|
|
143
|
+
* and Node.js 18+.
|
|
144
|
+
*
|
|
145
|
+
* @param rawBody - Raw request body as a string (NOT parsed JSON)
|
|
146
|
+
* @param signature - Value of the `X-Signature` header
|
|
147
|
+
* @param secret - Your webhook endpoint's secret (`whsec_*`)
|
|
148
|
+
* @returns Parsed and verified webhook event
|
|
149
|
+
* @throws {WebhookSignatureVerificationError} If verification fails
|
|
150
|
+
*/
|
|
151
|
+
declare function constructEventAsync(rawBody: string, signature: string, secret: string): Promise<WebhookEvent>;
|
|
152
|
+
/**
|
|
153
|
+
* Verify an HMAC-SHA256 signature (synchronous, Node.js only).
|
|
154
|
+
* Uses timing-safe comparison to prevent timing attacks.
|
|
155
|
+
*/
|
|
156
|
+
declare function verifySignature(rawBody: string, signature: string, secret: string): boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Verify an HMAC-SHA256 signature (async, works everywhere).
|
|
159
|
+
* Uses the Web Crypto API with constant-time comparison.
|
|
160
|
+
*/
|
|
161
|
+
declare function verifySignatureAsync(rawBody: string, signature: string, secret: string): Promise<boolean>;
|
|
162
|
+
|
|
163
|
+
export { type WebhookEvent, WebhookSignatureVerificationError, constructEvent, constructEventAsync, verifySignature, verifySignatureAsync };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/** Metadata: string key-value pairs. Max 50 keys, 40-char keys, 500-char values. */
|
|
2
|
+
type Metadata = Record<string, string>;
|
|
3
|
+
|
|
4
|
+
/** A message on a ticket. */
|
|
5
|
+
interface Message {
|
|
6
|
+
id: string;
|
|
7
|
+
object: 'message';
|
|
8
|
+
sender: 'customer' | 'agent' | 'system';
|
|
9
|
+
content: string;
|
|
10
|
+
senderId: string | null;
|
|
11
|
+
senderName: string | null;
|
|
12
|
+
senderAvatarUrl: string | null;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
mergedFromShortId: string | null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** A cStar support ticket. */
|
|
18
|
+
interface Ticket {
|
|
19
|
+
id: string;
|
|
20
|
+
object: 'ticket';
|
|
21
|
+
title: string;
|
|
22
|
+
priority: 'low' | 'normal' | 'high' | 'urgent';
|
|
23
|
+
status: string;
|
|
24
|
+
customerId: string | null;
|
|
25
|
+
customerName: string | null;
|
|
26
|
+
assignedTo: string | null;
|
|
27
|
+
tags: string[];
|
|
28
|
+
notes: string | null;
|
|
29
|
+
messageCount: number;
|
|
30
|
+
responseDeadline: string | null;
|
|
31
|
+
resolutionDeadline: string | null;
|
|
32
|
+
firstResponseAt: string | null;
|
|
33
|
+
responseTier: string | null;
|
|
34
|
+
resolutionTier: string | null;
|
|
35
|
+
slaPaused: boolean;
|
|
36
|
+
metadata: Metadata;
|
|
37
|
+
createdAt: string;
|
|
38
|
+
closedAt: string | null;
|
|
39
|
+
updatedAt: string;
|
|
40
|
+
/** Present when expand includes 'messages' or on single-ticket GET. */
|
|
41
|
+
messages?: Message[];
|
|
42
|
+
/** Present when expand includes 'customer'. */
|
|
43
|
+
customer?: TicketCustomerSummary | null;
|
|
44
|
+
}
|
|
45
|
+
/** Inline customer summary when expanding on a ticket. */
|
|
46
|
+
interface TicketCustomerSummary {
|
|
47
|
+
id: string;
|
|
48
|
+
object: 'customer';
|
|
49
|
+
name: string;
|
|
50
|
+
email: string;
|
|
51
|
+
sentiment: string;
|
|
52
|
+
status: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A cStar customer. */
|
|
56
|
+
interface Customer {
|
|
57
|
+
id: string;
|
|
58
|
+
object: 'customer';
|
|
59
|
+
name: string;
|
|
60
|
+
email: string;
|
|
61
|
+
sentiment: string;
|
|
62
|
+
status: string;
|
|
63
|
+
tags: string[];
|
|
64
|
+
notes: string | null;
|
|
65
|
+
customFields: Record<string, unknown>;
|
|
66
|
+
ticketCount: number;
|
|
67
|
+
metadata: Metadata;
|
|
68
|
+
createdAt: string;
|
|
69
|
+
updatedAt: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** A cStar knowledge base article. */
|
|
73
|
+
interface Article {
|
|
74
|
+
id: string;
|
|
75
|
+
object: 'article';
|
|
76
|
+
title: string;
|
|
77
|
+
slug: string | null;
|
|
78
|
+
excerpt: string | null;
|
|
79
|
+
content: string | null;
|
|
80
|
+
category: string;
|
|
81
|
+
status: 'draft' | 'published';
|
|
82
|
+
tags: string[];
|
|
83
|
+
notes: string | null;
|
|
84
|
+
viewCount: number;
|
|
85
|
+
useCount: number;
|
|
86
|
+
readTime: string;
|
|
87
|
+
isPublic: boolean;
|
|
88
|
+
publishedAt: string | null;
|
|
89
|
+
metaDescription: string | null;
|
|
90
|
+
metadata: Metadata;
|
|
91
|
+
createdAt: string;
|
|
92
|
+
updatedAt: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** All webhook event types supported by cStar. */
|
|
96
|
+
type WebhookEventType = 'ticket.created' | 'ticket.updated' | 'ticket.closed' | 'ticket.message_added' | 'customer.created' | 'customer.updated' | 'article.created' | 'article.published' | 'article.updated' | 'boss.spawned' | 'boss.defeated' | 'player.level_up' | 'achievement.unlocked' | 'survey.submitted';
|
|
97
|
+
/** A webhook event delivered to your endpoint. */
|
|
98
|
+
interface WebhookEvent<T extends WebhookEventType = WebhookEventType> {
|
|
99
|
+
/** Unique event ID (idempotency key). */
|
|
100
|
+
id: string;
|
|
101
|
+
/** Event type. */
|
|
102
|
+
type: T;
|
|
103
|
+
/** When the event was created (ISO 8601). */
|
|
104
|
+
created_at: string;
|
|
105
|
+
/** Team that owns this event. */
|
|
106
|
+
team_id: string;
|
|
107
|
+
/** Event-specific payload. */
|
|
108
|
+
data: WebhookEventData<T>;
|
|
109
|
+
}
|
|
110
|
+
/** Discriminated union mapping event types to their data payloads. */
|
|
111
|
+
type WebhookEventData<T extends WebhookEventType> = T extends 'ticket.created' | 'ticket.updated' | 'ticket.closed' ? {
|
|
112
|
+
ticket: Ticket;
|
|
113
|
+
} : T extends 'ticket.message_added' ? {
|
|
114
|
+
ticket: Ticket;
|
|
115
|
+
message: Message;
|
|
116
|
+
} : T extends 'customer.created' | 'customer.updated' ? {
|
|
117
|
+
customer: Customer;
|
|
118
|
+
} : T extends 'article.created' | 'article.published' | 'article.updated' ? {
|
|
119
|
+
article: Article;
|
|
120
|
+
} : Record<string, unknown>;
|
|
121
|
+
|
|
122
|
+
/** Thrown when webhook signature verification fails. */
|
|
123
|
+
declare class WebhookSignatureVerificationError extends Error {
|
|
124
|
+
constructor(message: string);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Verify a webhook signature and parse the event (synchronous, Node.js only).
|
|
128
|
+
*
|
|
129
|
+
* Uses Node.js `crypto` module for timing-safe HMAC comparison.
|
|
130
|
+
* For browser/edge environments, use `constructEventAsync()`.
|
|
131
|
+
*
|
|
132
|
+
* @param rawBody - Raw request body as a string (NOT parsed JSON)
|
|
133
|
+
* @param signature - Value of the `X-Signature` header
|
|
134
|
+
* @param secret - Your webhook endpoint's secret (`whsec_*`)
|
|
135
|
+
* @returns Parsed and verified webhook event
|
|
136
|
+
* @throws {WebhookSignatureVerificationError} If verification fails
|
|
137
|
+
*/
|
|
138
|
+
declare function constructEvent(rawBody: string, signature: string, secret: string): WebhookEvent;
|
|
139
|
+
/**
|
|
140
|
+
* Verify a webhook signature and parse the event (async, works everywhere).
|
|
141
|
+
*
|
|
142
|
+
* Uses the Web Crypto API — compatible with browsers, Deno, Cloudflare Workers,
|
|
143
|
+
* and Node.js 18+.
|
|
144
|
+
*
|
|
145
|
+
* @param rawBody - Raw request body as a string (NOT parsed JSON)
|
|
146
|
+
* @param signature - Value of the `X-Signature` header
|
|
147
|
+
* @param secret - Your webhook endpoint's secret (`whsec_*`)
|
|
148
|
+
* @returns Parsed and verified webhook event
|
|
149
|
+
* @throws {WebhookSignatureVerificationError} If verification fails
|
|
150
|
+
*/
|
|
151
|
+
declare function constructEventAsync(rawBody: string, signature: string, secret: string): Promise<WebhookEvent>;
|
|
152
|
+
/**
|
|
153
|
+
* Verify an HMAC-SHA256 signature (synchronous, Node.js only).
|
|
154
|
+
* Uses timing-safe comparison to prevent timing attacks.
|
|
155
|
+
*/
|
|
156
|
+
declare function verifySignature(rawBody: string, signature: string, secret: string): boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Verify an HMAC-SHA256 signature (async, works everywhere).
|
|
159
|
+
* Uses the Web Crypto API with constant-time comparison.
|
|
160
|
+
*/
|
|
161
|
+
declare function verifySignatureAsync(rawBody: string, signature: string, secret: string): Promise<boolean>;
|
|
162
|
+
|
|
163
|
+
export { type WebhookEvent, WebhookSignatureVerificationError, constructEvent, constructEventAsync, verifySignature, verifySignatureAsync };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/webhook/index.ts
|
|
9
|
+
var WebhookSignatureVerificationError = class extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "WebhookSignatureVerificationError";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function constructEvent(rawBody, signature, secret) {
|
|
16
|
+
if (!verifySignature(rawBody, signature, secret)) {
|
|
17
|
+
throw new WebhookSignatureVerificationError(
|
|
18
|
+
"Webhook signature verification failed. Ensure you are using the raw request body and the correct endpoint secret."
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return JSON.parse(rawBody);
|
|
22
|
+
}
|
|
23
|
+
async function constructEventAsync(rawBody, signature, secret) {
|
|
24
|
+
const valid = await verifySignatureAsync(rawBody, signature, secret);
|
|
25
|
+
if (!valid) {
|
|
26
|
+
throw new WebhookSignatureVerificationError(
|
|
27
|
+
"Webhook signature verification failed. Ensure you are using the raw request body and the correct endpoint secret."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return JSON.parse(rawBody);
|
|
31
|
+
}
|
|
32
|
+
function verifySignature(rawBody, signature, secret) {
|
|
33
|
+
const crypto2 = __require("crypto");
|
|
34
|
+
const expected = "sha256=" + crypto2.createHmac("sha256", secret).update(rawBody).digest("hex");
|
|
35
|
+
if (signature.length !== expected.length) return false;
|
|
36
|
+
return crypto2.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
|
37
|
+
}
|
|
38
|
+
async function verifySignatureAsync(rawBody, signature, secret) {
|
|
39
|
+
const encoder = new TextEncoder();
|
|
40
|
+
const key = await crypto.subtle.importKey(
|
|
41
|
+
"raw",
|
|
42
|
+
encoder.encode(secret),
|
|
43
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
44
|
+
false,
|
|
45
|
+
["sign"]
|
|
46
|
+
);
|
|
47
|
+
const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(rawBody));
|
|
48
|
+
const expected = "sha256=" + Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
49
|
+
if (signature.length !== expected.length) return false;
|
|
50
|
+
let result = 0;
|
|
51
|
+
for (let i = 0; i < signature.length; i++) {
|
|
52
|
+
result |= signature.charCodeAt(i) ^ expected.charCodeAt(i);
|
|
53
|
+
}
|
|
54
|
+
return result === 0;
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
WebhookSignatureVerificationError,
|
|
58
|
+
constructEvent,
|
|
59
|
+
constructEventAsync,
|
|
60
|
+
verifySignature,
|
|
61
|
+
verifySignatureAsync
|
|
62
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cstar.help/js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official TypeScript SDK for the cStar customer support platform",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./chat": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/chat/index.d.ts",
|
|
23
|
+
"default": "./dist/chat/index.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/chat/index.d.cts",
|
|
27
|
+
"default": "./dist/chat/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"./library": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/library/index.d.ts",
|
|
33
|
+
"default": "./dist/library/index.js"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/library/index.d.cts",
|
|
37
|
+
"default": "./dist/library/index.cjs"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"./webhook": {
|
|
41
|
+
"import": {
|
|
42
|
+
"types": "./dist/webhook/index.d.ts",
|
|
43
|
+
"default": "./dist/webhook/index.js"
|
|
44
|
+
},
|
|
45
|
+
"require": {
|
|
46
|
+
"types": "./dist/webhook/index.d.cts",
|
|
47
|
+
"default": "./dist/webhook/index.cjs"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"dist"
|
|
53
|
+
],
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsup",
|
|
56
|
+
"dev": "tsup --watch",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"test:watch": "vitest",
|
|
59
|
+
"typecheck": "tsc --noEmit"
|
|
60
|
+
},
|
|
61
|
+
"keywords": [
|
|
62
|
+
"cstar",
|
|
63
|
+
"customer-support",
|
|
64
|
+
"sdk",
|
|
65
|
+
"api",
|
|
66
|
+
"typescript"
|
|
67
|
+
],
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=18.0.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"@supabase/supabase-js": ">=2.0.0"
|
|
74
|
+
},
|
|
75
|
+
"peerDependenciesMeta": {
|
|
76
|
+
"@supabase/supabase-js": {
|
|
77
|
+
"optional": true
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"tsup": "^8.0.0",
|
|
82
|
+
"typescript": "^5.7.0",
|
|
83
|
+
"vitest": "^3.0.0"
|
|
84
|
+
}
|
|
85
|
+
}
|