@webhooks-cc/sdk 0.5.0 → 0.6.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/dist/index.d.mts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +78 -3
- package/dist/index.mjs +78 -3
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -199,6 +199,7 @@ interface SDKDescription {
|
|
|
199
199
|
version: string;
|
|
200
200
|
endpoints: Record<string, OperationDescription>;
|
|
201
201
|
sendTo: OperationDescription;
|
|
202
|
+
buildRequest: OperationDescription;
|
|
202
203
|
requests: Record<string, OperationDescription>;
|
|
203
204
|
}
|
|
204
205
|
|
|
@@ -275,6 +276,21 @@ declare class WebhooksCC {
|
|
|
275
276
|
send: (slug: string, options?: SendOptions) => Promise<Response>;
|
|
276
277
|
sendTemplate: (slug: string, options: SendTemplateOptions) => Promise<Response>;
|
|
277
278
|
};
|
|
279
|
+
/**
|
|
280
|
+
* Build a request without sending it. Returns the computed method, URL,
|
|
281
|
+
* headers, and body — including any provider signatures. Useful for
|
|
282
|
+
* debugging what sendTo would actually send.
|
|
283
|
+
*
|
|
284
|
+
* @param url - Target URL (http or https)
|
|
285
|
+
* @param options - Same options as sendTo
|
|
286
|
+
* @returns The computed request details
|
|
287
|
+
*/
|
|
288
|
+
buildRequest: (url: string, options?: SendToOptions) => Promise<{
|
|
289
|
+
url: string;
|
|
290
|
+
method: string;
|
|
291
|
+
headers: Record<string, string>;
|
|
292
|
+
body?: string;
|
|
293
|
+
}>;
|
|
278
294
|
/**
|
|
279
295
|
* Send a webhook directly to any URL with optional provider signing.
|
|
280
296
|
* Use this for local integration testing — send properly signed webhooks
|
package/dist/index.d.ts
CHANGED
|
@@ -199,6 +199,7 @@ interface SDKDescription {
|
|
|
199
199
|
version: string;
|
|
200
200
|
endpoints: Record<string, OperationDescription>;
|
|
201
201
|
sendTo: OperationDescription;
|
|
202
|
+
buildRequest: OperationDescription;
|
|
202
203
|
requests: Record<string, OperationDescription>;
|
|
203
204
|
}
|
|
204
205
|
|
|
@@ -275,6 +276,21 @@ declare class WebhooksCC {
|
|
|
275
276
|
send: (slug: string, options?: SendOptions) => Promise<Response>;
|
|
276
277
|
sendTemplate: (slug: string, options: SendTemplateOptions) => Promise<Response>;
|
|
277
278
|
};
|
|
279
|
+
/**
|
|
280
|
+
* Build a request without sending it. Returns the computed method, URL,
|
|
281
|
+
* headers, and body — including any provider signatures. Useful for
|
|
282
|
+
* debugging what sendTo would actually send.
|
|
283
|
+
*
|
|
284
|
+
* @param url - Target URL (http or https)
|
|
285
|
+
* @param options - Same options as sendTo
|
|
286
|
+
* @returns The computed request details
|
|
287
|
+
*/
|
|
288
|
+
buildRequest: (url: string, options?: SendToOptions) => Promise<{
|
|
289
|
+
url: string;
|
|
290
|
+
method: string;
|
|
291
|
+
headers: Record<string, string>;
|
|
292
|
+
body?: string;
|
|
293
|
+
}>;
|
|
278
294
|
/**
|
|
279
295
|
* Send a webhook directly to any URL with optional provider signing.
|
|
280
296
|
* Use this for local integration testing — send properly signed webhooks
|
package/dist/index.js
CHANGED
|
@@ -768,10 +768,17 @@ async function buildTemplateSendOptions(endpointUrl, options) {
|
|
|
768
768
|
const timestamp = options.timestamp ?? Math.floor(Date.now() / 1e3);
|
|
769
769
|
const signingInput = `${msgId}.${timestamp}.${body}`;
|
|
770
770
|
let rawSecret = options.secret;
|
|
771
|
-
|
|
771
|
+
const hadPrefix = rawSecret.startsWith("whsec_");
|
|
772
|
+
if (hadPrefix) {
|
|
772
773
|
rawSecret = rawSecret.slice(6);
|
|
773
774
|
}
|
|
774
|
-
|
|
775
|
+
let secretBytes;
|
|
776
|
+
try {
|
|
777
|
+
secretBytes = fromBase64(rawSecret);
|
|
778
|
+
} catch {
|
|
779
|
+
const raw = hadPrefix ? options.secret : rawSecret;
|
|
780
|
+
secretBytes = new TextEncoder().encode(raw);
|
|
781
|
+
}
|
|
775
782
|
const signature = await hmacSignRaw("SHA-256", secretBytes, signingInput);
|
|
776
783
|
return {
|
|
777
784
|
method: method2,
|
|
@@ -833,7 +840,7 @@ async function buildTemplateSendOptions(endpointUrl, options) {
|
|
|
833
840
|
var DEFAULT_BASE_URL = "https://webhooks.cc";
|
|
834
841
|
var DEFAULT_WEBHOOK_URL = "https://go.webhooks.cc";
|
|
835
842
|
var DEFAULT_TIMEOUT = 3e4;
|
|
836
|
-
var SDK_VERSION = "0.
|
|
843
|
+
var SDK_VERSION = "0.6.0";
|
|
837
844
|
var MIN_POLL_INTERVAL = 10;
|
|
838
845
|
var MAX_POLL_INTERVAL = 6e4;
|
|
839
846
|
var ALLOWED_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]);
|
|
@@ -956,6 +963,64 @@ var WebhooksCC = class {
|
|
|
956
963
|
return this.endpoints.send(slug, sendOptions);
|
|
957
964
|
}
|
|
958
965
|
};
|
|
966
|
+
/**
|
|
967
|
+
* Build a request without sending it. Returns the computed method, URL,
|
|
968
|
+
* headers, and body — including any provider signatures. Useful for
|
|
969
|
+
* debugging what sendTo would actually send.
|
|
970
|
+
*
|
|
971
|
+
* @param url - Target URL (http or https)
|
|
972
|
+
* @param options - Same options as sendTo
|
|
973
|
+
* @returns The computed request details
|
|
974
|
+
*/
|
|
975
|
+
this.buildRequest = async (url, options = {}) => {
|
|
976
|
+
let parsed;
|
|
977
|
+
try {
|
|
978
|
+
parsed = new URL(url);
|
|
979
|
+
} catch {
|
|
980
|
+
throw new Error(`Invalid URL: "${url}" is not a valid URL`);
|
|
981
|
+
}
|
|
982
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
983
|
+
throw new Error("Invalid URL: only http and https protocols are supported");
|
|
984
|
+
}
|
|
985
|
+
if (options.provider) {
|
|
986
|
+
if (!options.secret || typeof options.secret !== "string") {
|
|
987
|
+
throw new Error("buildRequest with a provider requires a non-empty secret");
|
|
988
|
+
}
|
|
989
|
+
const sendOptions = await buildTemplateSendOptions(url, {
|
|
990
|
+
provider: options.provider,
|
|
991
|
+
template: options.template,
|
|
992
|
+
secret: options.secret,
|
|
993
|
+
event: options.event,
|
|
994
|
+
body: options.body,
|
|
995
|
+
method: options.method,
|
|
996
|
+
headers: options.headers,
|
|
997
|
+
timestamp: options.timestamp
|
|
998
|
+
});
|
|
999
|
+
return {
|
|
1000
|
+
url,
|
|
1001
|
+
method: (sendOptions.method ?? "POST").toUpperCase(),
|
|
1002
|
+
headers: sendOptions.headers ?? {},
|
|
1003
|
+
body: sendOptions.body !== void 0 ? typeof sendOptions.body === "string" ? sendOptions.body : JSON.stringify(sendOptions.body) : void 0
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
const method = (options.method ?? "POST").toUpperCase();
|
|
1007
|
+
if (!ALLOWED_METHODS.has(method)) {
|
|
1008
|
+
throw new Error(
|
|
1009
|
+
`Invalid HTTP method: "${options.method}". Must be one of: ${[...ALLOWED_METHODS].join(", ")}`
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
const headers = { ...options.headers ?? {} };
|
|
1013
|
+
const hasContentType = Object.keys(headers).some((k) => k.toLowerCase() === "content-type");
|
|
1014
|
+
if (options.body !== void 0 && !hasContentType) {
|
|
1015
|
+
headers["Content-Type"] = "application/json";
|
|
1016
|
+
}
|
|
1017
|
+
return {
|
|
1018
|
+
url,
|
|
1019
|
+
method,
|
|
1020
|
+
headers,
|
|
1021
|
+
body: options.body !== void 0 ? typeof options.body === "string" ? options.body : JSON.stringify(options.body) : void 0
|
|
1022
|
+
};
|
|
1023
|
+
};
|
|
959
1024
|
/**
|
|
960
1025
|
* Send a webhook directly to any URL with optional provider signing.
|
|
961
1026
|
* Use this for local integration testing — send properly signed webhooks
|
|
@@ -1380,6 +1445,16 @@ var WebhooksCC = class {
|
|
|
1380
1445
|
headers: "Record<string, string>?"
|
|
1381
1446
|
}
|
|
1382
1447
|
},
|
|
1448
|
+
buildRequest: {
|
|
1449
|
+
description: "Build a request without sending it \u2014 returns computed method, URL, headers, and body including provider signatures",
|
|
1450
|
+
params: {
|
|
1451
|
+
url: "string",
|
|
1452
|
+
provider: '"stripe"|"github"|"shopify"|"twilio"|"standard-webhooks"?',
|
|
1453
|
+
secret: "string?",
|
|
1454
|
+
body: "unknown?",
|
|
1455
|
+
headers: "Record<string, string>?"
|
|
1456
|
+
}
|
|
1457
|
+
},
|
|
1383
1458
|
requests: {
|
|
1384
1459
|
list: {
|
|
1385
1460
|
description: "List captured requests",
|
package/dist/index.mjs
CHANGED
|
@@ -719,10 +719,17 @@ async function buildTemplateSendOptions(endpointUrl, options) {
|
|
|
719
719
|
const timestamp = options.timestamp ?? Math.floor(Date.now() / 1e3);
|
|
720
720
|
const signingInput = `${msgId}.${timestamp}.${body}`;
|
|
721
721
|
let rawSecret = options.secret;
|
|
722
|
-
|
|
722
|
+
const hadPrefix = rawSecret.startsWith("whsec_");
|
|
723
|
+
if (hadPrefix) {
|
|
723
724
|
rawSecret = rawSecret.slice(6);
|
|
724
725
|
}
|
|
725
|
-
|
|
726
|
+
let secretBytes;
|
|
727
|
+
try {
|
|
728
|
+
secretBytes = fromBase64(rawSecret);
|
|
729
|
+
} catch {
|
|
730
|
+
const raw = hadPrefix ? options.secret : rawSecret;
|
|
731
|
+
secretBytes = new TextEncoder().encode(raw);
|
|
732
|
+
}
|
|
726
733
|
const signature = await hmacSignRaw("SHA-256", secretBytes, signingInput);
|
|
727
734
|
return {
|
|
728
735
|
method: method2,
|
|
@@ -784,7 +791,7 @@ async function buildTemplateSendOptions(endpointUrl, options) {
|
|
|
784
791
|
var DEFAULT_BASE_URL = "https://webhooks.cc";
|
|
785
792
|
var DEFAULT_WEBHOOK_URL = "https://go.webhooks.cc";
|
|
786
793
|
var DEFAULT_TIMEOUT = 3e4;
|
|
787
|
-
var SDK_VERSION = "0.
|
|
794
|
+
var SDK_VERSION = "0.6.0";
|
|
788
795
|
var MIN_POLL_INTERVAL = 10;
|
|
789
796
|
var MAX_POLL_INTERVAL = 6e4;
|
|
790
797
|
var ALLOWED_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]);
|
|
@@ -907,6 +914,64 @@ var WebhooksCC = class {
|
|
|
907
914
|
return this.endpoints.send(slug, sendOptions);
|
|
908
915
|
}
|
|
909
916
|
};
|
|
917
|
+
/**
|
|
918
|
+
* Build a request without sending it. Returns the computed method, URL,
|
|
919
|
+
* headers, and body — including any provider signatures. Useful for
|
|
920
|
+
* debugging what sendTo would actually send.
|
|
921
|
+
*
|
|
922
|
+
* @param url - Target URL (http or https)
|
|
923
|
+
* @param options - Same options as sendTo
|
|
924
|
+
* @returns The computed request details
|
|
925
|
+
*/
|
|
926
|
+
this.buildRequest = async (url, options = {}) => {
|
|
927
|
+
let parsed;
|
|
928
|
+
try {
|
|
929
|
+
parsed = new URL(url);
|
|
930
|
+
} catch {
|
|
931
|
+
throw new Error(`Invalid URL: "${url}" is not a valid URL`);
|
|
932
|
+
}
|
|
933
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
934
|
+
throw new Error("Invalid URL: only http and https protocols are supported");
|
|
935
|
+
}
|
|
936
|
+
if (options.provider) {
|
|
937
|
+
if (!options.secret || typeof options.secret !== "string") {
|
|
938
|
+
throw new Error("buildRequest with a provider requires a non-empty secret");
|
|
939
|
+
}
|
|
940
|
+
const sendOptions = await buildTemplateSendOptions(url, {
|
|
941
|
+
provider: options.provider,
|
|
942
|
+
template: options.template,
|
|
943
|
+
secret: options.secret,
|
|
944
|
+
event: options.event,
|
|
945
|
+
body: options.body,
|
|
946
|
+
method: options.method,
|
|
947
|
+
headers: options.headers,
|
|
948
|
+
timestamp: options.timestamp
|
|
949
|
+
});
|
|
950
|
+
return {
|
|
951
|
+
url,
|
|
952
|
+
method: (sendOptions.method ?? "POST").toUpperCase(),
|
|
953
|
+
headers: sendOptions.headers ?? {},
|
|
954
|
+
body: sendOptions.body !== void 0 ? typeof sendOptions.body === "string" ? sendOptions.body : JSON.stringify(sendOptions.body) : void 0
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
const method = (options.method ?? "POST").toUpperCase();
|
|
958
|
+
if (!ALLOWED_METHODS.has(method)) {
|
|
959
|
+
throw new Error(
|
|
960
|
+
`Invalid HTTP method: "${options.method}". Must be one of: ${[...ALLOWED_METHODS].join(", ")}`
|
|
961
|
+
);
|
|
962
|
+
}
|
|
963
|
+
const headers = { ...options.headers ?? {} };
|
|
964
|
+
const hasContentType = Object.keys(headers).some((k) => k.toLowerCase() === "content-type");
|
|
965
|
+
if (options.body !== void 0 && !hasContentType) {
|
|
966
|
+
headers["Content-Type"] = "application/json";
|
|
967
|
+
}
|
|
968
|
+
return {
|
|
969
|
+
url,
|
|
970
|
+
method,
|
|
971
|
+
headers,
|
|
972
|
+
body: options.body !== void 0 ? typeof options.body === "string" ? options.body : JSON.stringify(options.body) : void 0
|
|
973
|
+
};
|
|
974
|
+
};
|
|
910
975
|
/**
|
|
911
976
|
* Send a webhook directly to any URL with optional provider signing.
|
|
912
977
|
* Use this for local integration testing — send properly signed webhooks
|
|
@@ -1331,6 +1396,16 @@ var WebhooksCC = class {
|
|
|
1331
1396
|
headers: "Record<string, string>?"
|
|
1332
1397
|
}
|
|
1333
1398
|
},
|
|
1399
|
+
buildRequest: {
|
|
1400
|
+
description: "Build a request without sending it \u2014 returns computed method, URL, headers, and body including provider signatures",
|
|
1401
|
+
params: {
|
|
1402
|
+
url: "string",
|
|
1403
|
+
provider: '"stripe"|"github"|"shopify"|"twilio"|"standard-webhooks"?',
|
|
1404
|
+
secret: "string?",
|
|
1405
|
+
body: "unknown?",
|
|
1406
|
+
headers: "Record<string, string>?"
|
|
1407
|
+
}
|
|
1408
|
+
},
|
|
1334
1409
|
requests: {
|
|
1335
1410
|
list: {
|
|
1336
1411
|
description: "List captured requests",
|