@webhooks-cc/sdk 0.6.0 → 1.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.
@@ -0,0 +1,236 @@
1
+ // src/errors.ts
2
+ var WebhooksCCError = class extends Error {
3
+ constructor(statusCode, message) {
4
+ super(message);
5
+ this.statusCode = statusCode;
6
+ this.name = "WebhooksCCError";
7
+ Object.setPrototypeOf(this, new.target.prototype);
8
+ }
9
+ };
10
+ var UnauthorizedError = class extends WebhooksCCError {
11
+ constructor(message = "Invalid or missing API key") {
12
+ super(401, message);
13
+ this.name = "UnauthorizedError";
14
+ }
15
+ };
16
+ var NotFoundError = class extends WebhooksCCError {
17
+ constructor(message = "Resource not found") {
18
+ super(404, message);
19
+ this.name = "NotFoundError";
20
+ }
21
+ };
22
+ var TimeoutError = class extends WebhooksCCError {
23
+ constructor(timeoutMs) {
24
+ super(0, `Request timed out after ${timeoutMs}ms`);
25
+ this.name = "TimeoutError";
26
+ }
27
+ };
28
+ var RateLimitError = class extends WebhooksCCError {
29
+ constructor(retryAfter) {
30
+ const message = retryAfter ? `Rate limited, retry after ${retryAfter}s` : "Rate limited";
31
+ super(429, message);
32
+ this.name = "RateLimitError";
33
+ this.retryAfter = retryAfter;
34
+ }
35
+ };
36
+
37
+ // src/utils.ts
38
+ var DURATION_REGEX = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/;
39
+ function parseDuration(input) {
40
+ if (typeof input === "number") {
41
+ if (!Number.isFinite(input) || input < 0) {
42
+ throw new Error(`Invalid duration: must be a finite non-negative number, got ${input}`);
43
+ }
44
+ return input;
45
+ }
46
+ const trimmed = input.trim();
47
+ const asNumber = Number(trimmed);
48
+ if (!isNaN(asNumber) && trimmed.length > 0) {
49
+ if (!Number.isFinite(asNumber) || asNumber < 0) {
50
+ throw new Error(`Invalid duration: must be a finite non-negative number, got "${input}"`);
51
+ }
52
+ return asNumber;
53
+ }
54
+ const match = DURATION_REGEX.exec(trimmed);
55
+ if (!match) {
56
+ throw new Error(`Invalid duration: "${input}"`);
57
+ }
58
+ const value = parseFloat(match[1]);
59
+ switch (match[2]) {
60
+ case "ms":
61
+ return value;
62
+ case "s":
63
+ return value * 1e3;
64
+ case "m":
65
+ return value * 6e4;
66
+ case "h":
67
+ return value * 36e5;
68
+ case "d":
69
+ return value * 864e5;
70
+ default:
71
+ throw new Error(`Invalid duration: "${input}"`);
72
+ }
73
+ }
74
+
75
+ // src/diff.ts
76
+ function isPlainObject(value) {
77
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
78
+ }
79
+ function isJsonBody(body) {
80
+ if (body.length === 0) {
81
+ return { valid: false };
82
+ }
83
+ try {
84
+ return { valid: true, value: JSON.parse(body) };
85
+ } catch {
86
+ return { valid: false };
87
+ }
88
+ }
89
+ function areEqual(left, right) {
90
+ if (left === right) {
91
+ return true;
92
+ }
93
+ if (Array.isArray(left) && Array.isArray(right)) {
94
+ return left.length === right.length && left.every((value, index) => areEqual(value, right[index]));
95
+ }
96
+ if (isPlainObject(left) && isPlainObject(right)) {
97
+ const leftKeys = Object.keys(left);
98
+ const rightKeys = Object.keys(right);
99
+ return leftKeys.length === rightKeys.length && leftKeys.every((key) => areEqual(left[key], right[key]));
100
+ }
101
+ return Number.isNaN(left) && Number.isNaN(right);
102
+ }
103
+ function compareJsonValues(left, right, path, changes) {
104
+ if (areEqual(left, right)) {
105
+ return;
106
+ }
107
+ if (Array.isArray(left) && Array.isArray(right)) {
108
+ const maxLength = Math.max(left.length, right.length);
109
+ for (let index = 0; index < maxLength; index++) {
110
+ const nextPath = path ? `${path}.${index}` : String(index);
111
+ compareJsonValues(left[index], right[index], nextPath, changes);
112
+ }
113
+ return;
114
+ }
115
+ if (isPlainObject(left) && isPlainObject(right)) {
116
+ const keys = [.../* @__PURE__ */ new Set([...Object.keys(left), ...Object.keys(right)])].sort();
117
+ for (const key of keys) {
118
+ const nextPath = path ? `${path}.${key}` : key;
119
+ compareJsonValues(left[key], right[key], nextPath, changes);
120
+ }
121
+ return;
122
+ }
123
+ changes[path || "$"] = { left, right };
124
+ }
125
+ function formatJsonDiff(changes) {
126
+ return Object.entries(changes).map(
127
+ ([path, difference]) => `${path}: ${JSON.stringify(difference.left)} -> ${JSON.stringify(difference.right)}`
128
+ ).join("\n");
129
+ }
130
+ function formatTextDiff(left, right) {
131
+ const leftLines = left.split("\n");
132
+ const rightLines = right.split("\n");
133
+ const maxLength = Math.max(leftLines.length, rightLines.length);
134
+ const lines = [];
135
+ for (let index = 0; index < maxLength; index++) {
136
+ const leftLine = leftLines[index];
137
+ const rightLine = rightLines[index];
138
+ if (leftLine === rightLine) {
139
+ continue;
140
+ }
141
+ if (leftLine !== void 0) {
142
+ lines.push(`- ${leftLine}`);
143
+ }
144
+ if (rightLine !== void 0) {
145
+ lines.push(`+ ${rightLine}`);
146
+ }
147
+ }
148
+ return lines.join("\n");
149
+ }
150
+ function normalizeHeaders(headers, ignoredHeaders) {
151
+ const normalized = {};
152
+ for (const [key, value] of Object.entries(headers)) {
153
+ const lowerKey = key.toLowerCase();
154
+ if (!ignoredHeaders.has(lowerKey)) {
155
+ normalized[lowerKey] = value;
156
+ }
157
+ }
158
+ return normalized;
159
+ }
160
+ function diffHeaders(leftHeaders, rightHeaders, options) {
161
+ const ignoredHeaders = new Set(
162
+ (options.ignoreHeaders ?? []).map((header) => header.toLowerCase())
163
+ );
164
+ const left = normalizeHeaders(leftHeaders, ignoredHeaders);
165
+ const right = normalizeHeaders(rightHeaders, ignoredHeaders);
166
+ const leftKeys = new Set(Object.keys(left));
167
+ const rightKeys = new Set(Object.keys(right));
168
+ const added = [...rightKeys].filter((key) => !leftKeys.has(key)).sort();
169
+ const removed = [...leftKeys].filter((key) => !rightKeys.has(key)).sort();
170
+ const changed = {};
171
+ for (const key of [...leftKeys].filter((header) => rightKeys.has(header)).sort()) {
172
+ if (left[key] !== right[key]) {
173
+ changed[key] = { left: left[key], right: right[key] };
174
+ }
175
+ }
176
+ if (added.length === 0 && removed.length === 0 && Object.keys(changed).length === 0) {
177
+ return void 0;
178
+ }
179
+ return { added, removed, changed };
180
+ }
181
+ function diffBodies(leftBody, rightBody) {
182
+ const left = leftBody ?? "";
183
+ const right = rightBody ?? "";
184
+ if (left === right) {
185
+ return void 0;
186
+ }
187
+ const leftJson = isJsonBody(left);
188
+ const rightJson = isJsonBody(right);
189
+ if (leftJson.valid && rightJson.valid) {
190
+ const changed = {};
191
+ compareJsonValues(leftJson.value, rightJson.value, "", changed);
192
+ if (Object.keys(changed).length === 0) {
193
+ return void 0;
194
+ }
195
+ return {
196
+ type: "json",
197
+ changed,
198
+ diff: formatJsonDiff(changed)
199
+ };
200
+ }
201
+ return {
202
+ type: "text",
203
+ diff: formatTextDiff(left, right)
204
+ };
205
+ }
206
+ function diffRequests(left, right, options = {}) {
207
+ const differences = {};
208
+ if (left.method !== right.method) {
209
+ differences.method = { left: left.method, right: right.method };
210
+ }
211
+ if (left.path !== right.path) {
212
+ differences.path = { left: left.path, right: right.path };
213
+ }
214
+ const headerDiff = diffHeaders(left.headers, right.headers, options);
215
+ if (headerDiff) {
216
+ differences.headers = headerDiff;
217
+ }
218
+ const bodyDiff = diffBodies(left.body, right.body);
219
+ if (bodyDiff) {
220
+ differences.body = bodyDiff;
221
+ }
222
+ return {
223
+ matches: Object.keys(differences).length === 0,
224
+ differences
225
+ };
226
+ }
227
+
228
+ export {
229
+ WebhooksCCError,
230
+ UnauthorizedError,
231
+ NotFoundError,
232
+ TimeoutError,
233
+ RateLimitError,
234
+ parseDuration,
235
+ diffRequests
236
+ };