@better-webhook/cli 3.9.0 → 3.10.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/_binary_entry.js +29 -0
- package/dist/commands/capture.d.ts +2 -0
- package/dist/commands/capture.js +33 -0
- package/dist/commands/captures.d.ts +2 -0
- package/dist/commands/captures.js +316 -0
- package/dist/commands/dashboard.d.ts +2 -0
- package/dist/commands/dashboard.js +70 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.js +6 -0
- package/dist/commands/replay.d.ts +2 -0
- package/dist/commands/replay.js +140 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +182 -0
- package/dist/commands/templates.d.ts +2 -0
- package/dist/commands/templates.js +285 -0
- package/dist/core/capture-server.d.ts +37 -0
- package/dist/core/capture-server.js +400 -0
- package/dist/core/capture-server.test.d.ts +1 -0
- package/dist/core/capture-server.test.js +86 -0
- package/dist/core/cli-version.d.ts +1 -0
- package/dist/core/cli-version.js +30 -0
- package/dist/core/cli-version.test.d.ts +1 -0
- package/dist/core/cli-version.test.js +42 -0
- package/dist/core/dashboard-api.d.ts +8 -0
- package/dist/core/dashboard-api.js +333 -0
- package/dist/core/dashboard-server.d.ts +24 -0
- package/dist/core/dashboard-server.js +224 -0
- package/dist/core/debug-output.d.ts +3 -0
- package/dist/core/debug-output.js +69 -0
- package/dist/core/debug-verify.d.ts +25 -0
- package/dist/core/debug-verify.js +253 -0
- package/dist/core/executor.d.ts +11 -0
- package/dist/core/executor.js +152 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +5 -0
- package/dist/core/replay-engine.d.ts +20 -0
- package/dist/core/replay-engine.js +293 -0
- package/dist/core/replay-engine.test.d.ts +1 -0
- package/dist/core/replay-engine.test.js +482 -0
- package/dist/core/runtime-paths.d.ts +2 -0
- package/dist/core/runtime-paths.js +65 -0
- package/dist/core/runtime-paths.test.d.ts +1 -0
- package/dist/core/runtime-paths.test.js +50 -0
- package/dist/core/signature.d.ts +25 -0
- package/dist/core/signature.js +224 -0
- package/dist/core/signature.test.d.ts +1 -0
- package/dist/core/signature.test.js +38 -0
- package/dist/core/template-manager.d.ts +33 -0
- package/dist/core/template-manager.js +313 -0
- package/dist/core/template-manager.test.d.ts +1 -0
- package/dist/core/template-manager.test.js +236 -0
- package/dist/index.cjs +135 -20
- package/dist/index.js +123 -8
- package/dist/types/index.d.ts +312 -0
- package/dist/types/index.js +87 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1762,7 +1762,9 @@ function resolveRuntimePackageVersion(runtimeDir) {
|
|
|
1762
1762
|
continue;
|
|
1763
1763
|
}
|
|
1764
1764
|
visitedRoots.add(cliPackageRoot);
|
|
1765
|
-
const version = readPackageVersion(
|
|
1765
|
+
const version = readPackageVersion(
|
|
1766
|
+
path2.join(cliPackageRoot, "package.json")
|
|
1767
|
+
);
|
|
1766
1768
|
if (version) {
|
|
1767
1769
|
return version;
|
|
1768
1770
|
}
|
|
@@ -3162,6 +3164,7 @@ var WebhookProviderSchema = z.enum([
|
|
|
3162
3164
|
"shopify",
|
|
3163
3165
|
"twilio",
|
|
3164
3166
|
"ragie",
|
|
3167
|
+
"recall",
|
|
3165
3168
|
"sendgrid",
|
|
3166
3169
|
"slack",
|
|
3167
3170
|
"discord",
|
|
@@ -3855,6 +3858,7 @@ import prompts2 from "prompts";
|
|
|
3855
3858
|
import { request as request2 } from "undici";
|
|
3856
3859
|
|
|
3857
3860
|
// src/core/signature.ts
|
|
3861
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
3858
3862
|
import { createHmac } from "crypto";
|
|
3859
3863
|
function generateStripeSignature(payload, secret, timestamp) {
|
|
3860
3864
|
const ts = timestamp || Math.floor(Date.now() / 1e3);
|
|
@@ -3929,6 +3933,25 @@ function generateRagieSignature(payload, secret) {
|
|
|
3929
3933
|
value: signature
|
|
3930
3934
|
};
|
|
3931
3935
|
}
|
|
3936
|
+
function generateRecallSignature(payload, secret, timestamp, webhookId) {
|
|
3937
|
+
if (!secret.startsWith("whsec_")) {
|
|
3938
|
+
throw new Error(
|
|
3939
|
+
"Recall signature generation requires a secret with the whsec_ prefix"
|
|
3940
|
+
);
|
|
3941
|
+
}
|
|
3942
|
+
const ts = timestamp ?? Math.floor(Date.now() / 1e3);
|
|
3943
|
+
const msgId = webhookId ?? `msg_${Date.now()}`;
|
|
3944
|
+
const key = Buffer2.from(secret.slice("whsec_".length), "base64");
|
|
3945
|
+
if (key.length === 0) {
|
|
3946
|
+
throw new Error("Recall signing secret is invalid");
|
|
3947
|
+
}
|
|
3948
|
+
const signedPayload = `${msgId}.${ts}.${payload}`;
|
|
3949
|
+
const signature = createHmac("sha256", key).update(signedPayload).digest("base64");
|
|
3950
|
+
return {
|
|
3951
|
+
header: "Webhook-Signature",
|
|
3952
|
+
value: `v1,${signature}`
|
|
3953
|
+
};
|
|
3954
|
+
}
|
|
3932
3955
|
function generateSignature(provider, payload, secret, options) {
|
|
3933
3956
|
const timestamp = options?.timestamp;
|
|
3934
3957
|
switch (provider) {
|
|
@@ -3958,6 +3981,13 @@ function generateSignature(provider, payload, secret, options) {
|
|
|
3958
3981
|
return generateSendGridSignature(payload, secret, timestamp);
|
|
3959
3982
|
case "ragie":
|
|
3960
3983
|
return generateRagieSignature(payload, secret);
|
|
3984
|
+
case "recall":
|
|
3985
|
+
return generateRecallSignature(
|
|
3986
|
+
payload,
|
|
3987
|
+
secret,
|
|
3988
|
+
timestamp,
|
|
3989
|
+
options?.webhookId
|
|
3990
|
+
);
|
|
3961
3991
|
case "discord":
|
|
3962
3992
|
case "custom":
|
|
3963
3993
|
default:
|
|
@@ -4046,6 +4076,13 @@ function getProviderHeaders(provider, options) {
|
|
|
4046
4076
|
// Event type + nonce are included in the JSON body envelope.
|
|
4047
4077
|
);
|
|
4048
4078
|
break;
|
|
4079
|
+
case "recall":
|
|
4080
|
+
headers.push(
|
|
4081
|
+
{ key: "Content-Type", value: "application/json" },
|
|
4082
|
+
{ key: "Webhook-Id", value: options?.webhookId || `msg_${Date.now()}` },
|
|
4083
|
+
{ key: "Webhook-Timestamp", value: String(timestamp) }
|
|
4084
|
+
);
|
|
4085
|
+
break;
|
|
4049
4086
|
default:
|
|
4050
4087
|
headers.push({ key: "Content-Type", value: "application/json" });
|
|
4051
4088
|
}
|
|
@@ -4084,8 +4121,14 @@ async function executeWebhook(options) {
|
|
|
4084
4121
|
}
|
|
4085
4122
|
}
|
|
4086
4123
|
if (options.secret && options.provider && bodyStr) {
|
|
4124
|
+
const timestampHeader = headers["Webhook-Timestamp"] || headers["webhook-timestamp"] || headers["Svix-Timestamp"] || headers["svix-timestamp"] || headers["X-Slack-Request-Timestamp"] || headers["x-slack-request-timestamp"] || headers["X-Twilio-Email-Event-Webhook-Timestamp"] || headers["x-twilio-email-event-webhook-timestamp"];
|
|
4125
|
+
const parsedTimestamp = timestampHeader ? Number.parseInt(timestampHeader, 10) : void 0;
|
|
4126
|
+
const timestamp = Number.isFinite(parsedTimestamp) ? parsedTimestamp : void 0;
|
|
4127
|
+
const webhookId = headers["Webhook-Id"] || headers["webhook-id"] || headers["Svix-Id"] || headers["svix-id"] || headers["X-GitHub-Delivery"] || headers["x-github-delivery"];
|
|
4087
4128
|
const sig = generateSignature(options.provider, bodyStr, options.secret, {
|
|
4088
|
-
url: options.url
|
|
4129
|
+
url: options.url,
|
|
4130
|
+
timestamp,
|
|
4131
|
+
webhookId
|
|
4089
4132
|
});
|
|
4090
4133
|
if (sig) {
|
|
4091
4134
|
headers[sig.header] = sig.value;
|
|
@@ -4200,6 +4243,7 @@ function getSecretEnvVarName(provider) {
|
|
|
4200
4243
|
shopify: "SHOPIFY_WEBHOOK_SECRET",
|
|
4201
4244
|
twilio: "TWILIO_WEBHOOK_SECRET",
|
|
4202
4245
|
ragie: "RAGIE_WEBHOOK_SECRET",
|
|
4246
|
+
recall: "RECALL_WEBHOOK_SECRET",
|
|
4203
4247
|
slack: "SLACK_WEBHOOK_SECRET",
|
|
4204
4248
|
linear: "LINEAR_WEBHOOK_SECRET",
|
|
4205
4249
|
clerk: "CLERK_WEBHOOK_SECRET",
|
|
@@ -4646,6 +4690,12 @@ var CaptureServer = class {
|
|
|
4646
4690
|
return "ragie";
|
|
4647
4691
|
}
|
|
4648
4692
|
}
|
|
4693
|
+
if (this.hasStandardWebhookHeaders(headers)) {
|
|
4694
|
+
const recallUserAgent = this.headerIncludes(headers["user-agent"], "recall");
|
|
4695
|
+
if (recallUserAgent || this.hasRecallStandardWebhookShape(body)) {
|
|
4696
|
+
return "recall";
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4649
4699
|
if (headers["x-shopify-hmac-sha256"] || headers["x-shopify-topic"]) {
|
|
4650
4700
|
return "shopify";
|
|
4651
4701
|
}
|
|
@@ -4665,6 +4715,9 @@ var CaptureServer = class {
|
|
|
4665
4715
|
return "linear";
|
|
4666
4716
|
}
|
|
4667
4717
|
if (headers["svix-signature"]) {
|
|
4718
|
+
if (body && typeof body === "object" && "event" in body && typeof body.event === "string" && body.event.startsWith("bot.")) {
|
|
4719
|
+
return "recall";
|
|
4720
|
+
}
|
|
4668
4721
|
return "clerk";
|
|
4669
4722
|
}
|
|
4670
4723
|
return void 0;
|
|
@@ -4680,6 +4733,57 @@ var CaptureServer = class {
|
|
|
4680
4733
|
}
|
|
4681
4734
|
}
|
|
4682
4735
|
}
|
|
4736
|
+
hasStandardWebhookHeaders(headers) {
|
|
4737
|
+
return Boolean(
|
|
4738
|
+
headers["webhook-signature"] || headers["webhook-id"] && headers["webhook-timestamp"]
|
|
4739
|
+
);
|
|
4740
|
+
}
|
|
4741
|
+
hasRecallStandardWebhookShape(body) {
|
|
4742
|
+
if (!body || typeof body !== "object") {
|
|
4743
|
+
return false;
|
|
4744
|
+
}
|
|
4745
|
+
const payload = body;
|
|
4746
|
+
if (this.hasRecallEventPrefix(payload.event)) {
|
|
4747
|
+
return true;
|
|
4748
|
+
}
|
|
4749
|
+
if (this.hasRecallResourceCombination(payload)) {
|
|
4750
|
+
return true;
|
|
4751
|
+
}
|
|
4752
|
+
const nestedData = payload.data;
|
|
4753
|
+
if (nestedData && typeof nestedData === "object") {
|
|
4754
|
+
return this.hasRecallResourceCombination(
|
|
4755
|
+
nestedData
|
|
4756
|
+
);
|
|
4757
|
+
}
|
|
4758
|
+
return false;
|
|
4759
|
+
}
|
|
4760
|
+
hasRecallEventPrefix(event) {
|
|
4761
|
+
if (typeof event !== "string") {
|
|
4762
|
+
return false;
|
|
4763
|
+
}
|
|
4764
|
+
return ["bot.", "transcript.", "participant_events."].some(
|
|
4765
|
+
(prefix) => event.startsWith(prefix)
|
|
4766
|
+
);
|
|
4767
|
+
}
|
|
4768
|
+
hasRecallResourceCombination(payload) {
|
|
4769
|
+
const hasRealtimeEndpoint = "realtime_endpoint" in payload;
|
|
4770
|
+
const hasRecording = "recording" in payload;
|
|
4771
|
+
const hasParticipantEvents = "participant_events" in payload;
|
|
4772
|
+
const hasTranscript = "transcript" in payload;
|
|
4773
|
+
return hasRealtimeEndpoint && hasRecording && (hasParticipantEvents || hasTranscript);
|
|
4774
|
+
}
|
|
4775
|
+
headerIncludes(headerValue, searchText) {
|
|
4776
|
+
const normalizedSearchText = searchText.toLowerCase();
|
|
4777
|
+
if (typeof headerValue === "string") {
|
|
4778
|
+
return headerValue.toLowerCase().includes(normalizedSearchText);
|
|
4779
|
+
}
|
|
4780
|
+
if (Array.isArray(headerValue)) {
|
|
4781
|
+
return headerValue.some(
|
|
4782
|
+
(value) => value.toLowerCase().includes(normalizedSearchText)
|
|
4783
|
+
);
|
|
4784
|
+
}
|
|
4785
|
+
return false;
|
|
4786
|
+
}
|
|
4683
4787
|
/**
|
|
4684
4788
|
* Send message to a specific client
|
|
4685
4789
|
*/
|
|
@@ -4881,6 +4985,7 @@ var ReplayEngine = class {
|
|
|
4881
4985
|
"x-twilio-signature",
|
|
4882
4986
|
"x-slack-signature",
|
|
4883
4987
|
"svix-signature",
|
|
4988
|
+
"webhook-signature",
|
|
4884
4989
|
"linear-signature"
|
|
4885
4990
|
];
|
|
4886
4991
|
const headers = [];
|
|
@@ -4952,10 +5057,19 @@ var ReplayEngine = class {
|
|
|
4952
5057
|
}
|
|
4953
5058
|
if (capture2.provider === "ragie" && capture2.body) {
|
|
4954
5059
|
const body = capture2.body;
|
|
5060
|
+
if (typeof body.type === "string") {
|
|
5061
|
+
return body.type;
|
|
5062
|
+
}
|
|
4955
5063
|
if (typeof body.event_type === "string") {
|
|
4956
5064
|
return body.event_type;
|
|
4957
5065
|
}
|
|
4958
5066
|
}
|
|
5067
|
+
if (capture2.provider === "recall" && capture2.body) {
|
|
5068
|
+
const body = capture2.body;
|
|
5069
|
+
if (typeof body.event === "string") {
|
|
5070
|
+
return body.event;
|
|
5071
|
+
}
|
|
5072
|
+
}
|
|
4959
5073
|
const shopifyTopic = headers["x-shopify-topic"];
|
|
4960
5074
|
if (shopifyTopic) {
|
|
4961
5075
|
return Array.isArray(shopifyTopic) ? shopifyTopic[0] : shopifyTopic;
|
|
@@ -5542,6 +5656,7 @@ function getSecretEnvVarName2(provider) {
|
|
|
5542
5656
|
shopify: "SHOPIFY_WEBHOOK_SECRET",
|
|
5543
5657
|
twilio: "TWILIO_WEBHOOK_SECRET",
|
|
5544
5658
|
ragie: "RAGIE_WEBHOOK_SECRET",
|
|
5659
|
+
recall: "RECALL_WEBHOOK_SECRET",
|
|
5545
5660
|
slack: "SLACK_WEBHOOK_SECRET",
|
|
5546
5661
|
linear: "LINEAR_WEBHOOK_SECRET",
|
|
5547
5662
|
clerk: "CLERK_WEBHOOK_SECRET",
|
|
@@ -6119,13 +6234,13 @@ var dashboard = new Command6().name("dashboard").description("Start the local da
|
|
|
6119
6234
|
process.exitCode = 1;
|
|
6120
6235
|
return;
|
|
6121
6236
|
}
|
|
6237
|
+
const capturePort = Number.parseInt(String(options.capturePort), 10);
|
|
6238
|
+
if (!Number.isFinite(capturePort) || capturePort < 0 || capturePort > 65535) {
|
|
6239
|
+
console.error(source_default.red("Invalid capture port number"));
|
|
6240
|
+
process.exitCode = 1;
|
|
6241
|
+
return;
|
|
6242
|
+
}
|
|
6122
6243
|
try {
|
|
6123
|
-
const capturePort = Number.parseInt(String(options.capturePort), 10);
|
|
6124
|
-
if (!Number.isFinite(capturePort) || capturePort < 0 || capturePort > 65535) {
|
|
6125
|
-
console.error(source_default.red("Invalid capture port number"));
|
|
6126
|
-
process.exitCode = 1;
|
|
6127
|
-
return;
|
|
6128
|
-
}
|
|
6129
6244
|
const verbose = Boolean(options.verbose || options.debug);
|
|
6130
6245
|
const { url, server, capture: capture2 } = await startDashboardServer({
|
|
6131
6246
|
host: options.host,
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const HttpMethodSchema: z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]>;
|
|
3
|
+
export type HttpMethod = z.infer<typeof HttpMethodSchema>;
|
|
4
|
+
export declare const HeaderEntrySchema: z.ZodObject<{
|
|
5
|
+
key: z.ZodString;
|
|
6
|
+
value: z.ZodString;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
value: string;
|
|
9
|
+
key: string;
|
|
10
|
+
}, {
|
|
11
|
+
value: string;
|
|
12
|
+
key: string;
|
|
13
|
+
}>;
|
|
14
|
+
export type HeaderEntry = z.infer<typeof HeaderEntrySchema>;
|
|
15
|
+
export declare const WebhookProviderSchema: z.ZodEnum<["stripe", "github", "shopify", "twilio", "ragie", "recall", "sendgrid", "slack", "discord", "linear", "clerk", "custom"]>;
|
|
16
|
+
export type WebhookProvider = z.infer<typeof WebhookProviderSchema>;
|
|
17
|
+
export declare const TemplateMetadataSchema: z.ZodObject<{
|
|
18
|
+
id: z.ZodString;
|
|
19
|
+
name: z.ZodString;
|
|
20
|
+
description: z.ZodOptional<z.ZodString>;
|
|
21
|
+
provider: z.ZodEnum<["stripe", "github", "shopify", "twilio", "ragie", "recall", "sendgrid", "slack", "discord", "linear", "clerk", "custom"]>;
|
|
22
|
+
event: z.ZodString;
|
|
23
|
+
file: z.ZodString;
|
|
24
|
+
version: z.ZodOptional<z.ZodString>;
|
|
25
|
+
docsUrl: z.ZodOptional<z.ZodString>;
|
|
26
|
+
}, "strip", z.ZodTypeAny, {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
provider: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom";
|
|
30
|
+
event: string;
|
|
31
|
+
file: string;
|
|
32
|
+
description?: string | undefined;
|
|
33
|
+
version?: string | undefined;
|
|
34
|
+
docsUrl?: string | undefined;
|
|
35
|
+
}, {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
provider: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom";
|
|
39
|
+
event: string;
|
|
40
|
+
file: string;
|
|
41
|
+
description?: string | undefined;
|
|
42
|
+
version?: string | undefined;
|
|
43
|
+
docsUrl?: string | undefined;
|
|
44
|
+
}>;
|
|
45
|
+
export type TemplateMetadata = z.infer<typeof TemplateMetadataSchema>;
|
|
46
|
+
export declare const TemplatesIndexSchema: z.ZodObject<{
|
|
47
|
+
version: z.ZodString;
|
|
48
|
+
templates: z.ZodArray<z.ZodObject<{
|
|
49
|
+
id: z.ZodString;
|
|
50
|
+
name: z.ZodString;
|
|
51
|
+
description: z.ZodOptional<z.ZodString>;
|
|
52
|
+
provider: z.ZodEnum<["stripe", "github", "shopify", "twilio", "ragie", "recall", "sendgrid", "slack", "discord", "linear", "clerk", "custom"]>;
|
|
53
|
+
event: z.ZodString;
|
|
54
|
+
file: z.ZodString;
|
|
55
|
+
version: z.ZodOptional<z.ZodString>;
|
|
56
|
+
docsUrl: z.ZodOptional<z.ZodString>;
|
|
57
|
+
}, "strip", z.ZodTypeAny, {
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
provider: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom";
|
|
61
|
+
event: string;
|
|
62
|
+
file: string;
|
|
63
|
+
description?: string | undefined;
|
|
64
|
+
version?: string | undefined;
|
|
65
|
+
docsUrl?: string | undefined;
|
|
66
|
+
}, {
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
provider: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom";
|
|
70
|
+
event: string;
|
|
71
|
+
file: string;
|
|
72
|
+
description?: string | undefined;
|
|
73
|
+
version?: string | undefined;
|
|
74
|
+
docsUrl?: string | undefined;
|
|
75
|
+
}>, "many">;
|
|
76
|
+
}, "strip", z.ZodTypeAny, {
|
|
77
|
+
version: string;
|
|
78
|
+
templates: {
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
provider: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom";
|
|
82
|
+
event: string;
|
|
83
|
+
file: string;
|
|
84
|
+
description?: string | undefined;
|
|
85
|
+
version?: string | undefined;
|
|
86
|
+
docsUrl?: string | undefined;
|
|
87
|
+
}[];
|
|
88
|
+
}, {
|
|
89
|
+
version: string;
|
|
90
|
+
templates: {
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
provider: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom";
|
|
94
|
+
event: string;
|
|
95
|
+
file: string;
|
|
96
|
+
description?: string | undefined;
|
|
97
|
+
version?: string | undefined;
|
|
98
|
+
docsUrl?: string | undefined;
|
|
99
|
+
}[];
|
|
100
|
+
}>;
|
|
101
|
+
export type TemplatesIndex = z.infer<typeof TemplatesIndexSchema>;
|
|
102
|
+
export declare const WebhookTemplateSchema: z.ZodObject<{
|
|
103
|
+
url: z.ZodOptional<z.ZodString>;
|
|
104
|
+
method: z.ZodDefault<z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]>>;
|
|
105
|
+
headers: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
106
|
+
key: z.ZodString;
|
|
107
|
+
value: z.ZodString;
|
|
108
|
+
}, "strip", z.ZodTypeAny, {
|
|
109
|
+
value: string;
|
|
110
|
+
key: string;
|
|
111
|
+
}, {
|
|
112
|
+
value: string;
|
|
113
|
+
key: string;
|
|
114
|
+
}>, "many">>;
|
|
115
|
+
body: z.ZodOptional<z.ZodAny>;
|
|
116
|
+
provider: z.ZodOptional<z.ZodEnum<["stripe", "github", "shopify", "twilio", "ragie", "recall", "sendgrid", "slack", "discord", "linear", "clerk", "custom"]>>;
|
|
117
|
+
event: z.ZodOptional<z.ZodString>;
|
|
118
|
+
description: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, "strip", z.ZodTypeAny, {
|
|
120
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
121
|
+
headers: {
|
|
122
|
+
value: string;
|
|
123
|
+
key: string;
|
|
124
|
+
}[];
|
|
125
|
+
description?: string | undefined;
|
|
126
|
+
provider?: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom" | undefined;
|
|
127
|
+
event?: string | undefined;
|
|
128
|
+
url?: string | undefined;
|
|
129
|
+
body?: any;
|
|
130
|
+
}, {
|
|
131
|
+
description?: string | undefined;
|
|
132
|
+
provider?: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom" | undefined;
|
|
133
|
+
event?: string | undefined;
|
|
134
|
+
url?: string | undefined;
|
|
135
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | undefined;
|
|
136
|
+
headers?: {
|
|
137
|
+
value: string;
|
|
138
|
+
key: string;
|
|
139
|
+
}[] | undefined;
|
|
140
|
+
body?: any;
|
|
141
|
+
}>;
|
|
142
|
+
export type WebhookTemplate = z.infer<typeof WebhookTemplateSchema>;
|
|
143
|
+
export interface LocalTemplate {
|
|
144
|
+
id: string;
|
|
145
|
+
metadata: TemplateMetadata;
|
|
146
|
+
template: WebhookTemplate;
|
|
147
|
+
downloadedAt: string;
|
|
148
|
+
filePath: string;
|
|
149
|
+
}
|
|
150
|
+
export interface RemoteTemplate {
|
|
151
|
+
metadata: TemplateMetadata;
|
|
152
|
+
isDownloaded: boolean;
|
|
153
|
+
}
|
|
154
|
+
export declare const CapturedWebhookSchema: z.ZodObject<{
|
|
155
|
+
id: z.ZodString;
|
|
156
|
+
timestamp: z.ZodString;
|
|
157
|
+
method: z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]>;
|
|
158
|
+
url: z.ZodString;
|
|
159
|
+
path: z.ZodString;
|
|
160
|
+
headers: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
|
|
161
|
+
body: z.ZodOptional<z.ZodAny>;
|
|
162
|
+
rawBody: z.ZodString;
|
|
163
|
+
query: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
|
|
164
|
+
provider: z.ZodOptional<z.ZodEnum<["stripe", "github", "shopify", "twilio", "ragie", "recall", "sendgrid", "slack", "discord", "linear", "clerk", "custom"]>>;
|
|
165
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
166
|
+
contentLength: z.ZodOptional<z.ZodNumber>;
|
|
167
|
+
}, "strip", z.ZodTypeAny, {
|
|
168
|
+
path: string;
|
|
169
|
+
id: string;
|
|
170
|
+
url: string;
|
|
171
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
172
|
+
headers: Record<string, string | string[]>;
|
|
173
|
+
timestamp: string;
|
|
174
|
+
rawBody: string;
|
|
175
|
+
query: Record<string, string | string[]>;
|
|
176
|
+
provider?: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom" | undefined;
|
|
177
|
+
body?: any;
|
|
178
|
+
contentType?: string | undefined;
|
|
179
|
+
contentLength?: number | undefined;
|
|
180
|
+
}, {
|
|
181
|
+
path: string;
|
|
182
|
+
id: string;
|
|
183
|
+
url: string;
|
|
184
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
185
|
+
headers: Record<string, string | string[]>;
|
|
186
|
+
timestamp: string;
|
|
187
|
+
rawBody: string;
|
|
188
|
+
query: Record<string, string | string[]>;
|
|
189
|
+
provider?: "stripe" | "github" | "shopify" | "twilio" | "ragie" | "recall" | "sendgrid" | "slack" | "discord" | "linear" | "clerk" | "custom" | undefined;
|
|
190
|
+
body?: any;
|
|
191
|
+
contentType?: string | undefined;
|
|
192
|
+
contentLength?: number | undefined;
|
|
193
|
+
}>;
|
|
194
|
+
export type CapturedWebhook = z.infer<typeof CapturedWebhookSchema>;
|
|
195
|
+
export interface CaptureFile {
|
|
196
|
+
file: string;
|
|
197
|
+
capture: CapturedWebhook;
|
|
198
|
+
}
|
|
199
|
+
export interface WebhookExecutionOptions {
|
|
200
|
+
url: string;
|
|
201
|
+
method?: HttpMethod;
|
|
202
|
+
headers?: HeaderEntry[];
|
|
203
|
+
body?: unknown;
|
|
204
|
+
secret?: string;
|
|
205
|
+
provider?: WebhookProvider;
|
|
206
|
+
timeout?: number;
|
|
207
|
+
}
|
|
208
|
+
export interface WebhookExecutionResult {
|
|
209
|
+
status: number;
|
|
210
|
+
statusText: string;
|
|
211
|
+
headers: Record<string, string | string[]>;
|
|
212
|
+
body: unknown;
|
|
213
|
+
bodyText: string;
|
|
214
|
+
json?: unknown;
|
|
215
|
+
duration: number;
|
|
216
|
+
}
|
|
217
|
+
export interface ReplayOptions {
|
|
218
|
+
targetUrl: string;
|
|
219
|
+
method?: HttpMethod;
|
|
220
|
+
headers?: HeaderEntry[];
|
|
221
|
+
}
|
|
222
|
+
export declare const ConfigSchema: z.ZodObject<{
|
|
223
|
+
version: z.ZodDefault<z.ZodString>;
|
|
224
|
+
templatesDir: z.ZodOptional<z.ZodString>;
|
|
225
|
+
capturesDir: z.ZodOptional<z.ZodString>;
|
|
226
|
+
defaultTargetUrl: z.ZodOptional<z.ZodString>;
|
|
227
|
+
secrets: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
228
|
+
dashboard: z.ZodOptional<z.ZodObject<{
|
|
229
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
230
|
+
host: z.ZodDefault<z.ZodString>;
|
|
231
|
+
}, "strip", z.ZodTypeAny, {
|
|
232
|
+
port: number;
|
|
233
|
+
host: string;
|
|
234
|
+
}, {
|
|
235
|
+
port?: number | undefined;
|
|
236
|
+
host?: string | undefined;
|
|
237
|
+
}>>;
|
|
238
|
+
capture: z.ZodOptional<z.ZodObject<{
|
|
239
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
240
|
+
host: z.ZodDefault<z.ZodString>;
|
|
241
|
+
}, "strip", z.ZodTypeAny, {
|
|
242
|
+
port: number;
|
|
243
|
+
host: string;
|
|
244
|
+
}, {
|
|
245
|
+
port?: number | undefined;
|
|
246
|
+
host?: string | undefined;
|
|
247
|
+
}>>;
|
|
248
|
+
}, "strip", z.ZodTypeAny, {
|
|
249
|
+
version: string;
|
|
250
|
+
templatesDir?: string | undefined;
|
|
251
|
+
capturesDir?: string | undefined;
|
|
252
|
+
defaultTargetUrl?: string | undefined;
|
|
253
|
+
secrets?: Record<string, string> | undefined;
|
|
254
|
+
dashboard?: {
|
|
255
|
+
port: number;
|
|
256
|
+
host: string;
|
|
257
|
+
} | undefined;
|
|
258
|
+
capture?: {
|
|
259
|
+
port: number;
|
|
260
|
+
host: string;
|
|
261
|
+
} | undefined;
|
|
262
|
+
}, {
|
|
263
|
+
version?: string | undefined;
|
|
264
|
+
templatesDir?: string | undefined;
|
|
265
|
+
capturesDir?: string | undefined;
|
|
266
|
+
defaultTargetUrl?: string | undefined;
|
|
267
|
+
secrets?: Record<string, string> | undefined;
|
|
268
|
+
dashboard?: {
|
|
269
|
+
port?: number | undefined;
|
|
270
|
+
host?: string | undefined;
|
|
271
|
+
} | undefined;
|
|
272
|
+
capture?: {
|
|
273
|
+
port?: number | undefined;
|
|
274
|
+
host?: string | undefined;
|
|
275
|
+
} | undefined;
|
|
276
|
+
}>;
|
|
277
|
+
export type Config = z.infer<typeof ConfigSchema>;
|
|
278
|
+
export interface DashboardState {
|
|
279
|
+
templates: {
|
|
280
|
+
remote: RemoteTemplate[];
|
|
281
|
+
local: LocalTemplate[];
|
|
282
|
+
};
|
|
283
|
+
captures: CaptureFile[];
|
|
284
|
+
config: Config;
|
|
285
|
+
}
|
|
286
|
+
export interface WebSocketMessage {
|
|
287
|
+
type: "capture" | "templates_updated" | "captures_updated" | "replay_result" | "error";
|
|
288
|
+
payload: unknown;
|
|
289
|
+
}
|
|
290
|
+
export interface SignatureOptions {
|
|
291
|
+
provider: WebhookProvider;
|
|
292
|
+
payload: string;
|
|
293
|
+
secret: string;
|
|
294
|
+
timestamp?: number;
|
|
295
|
+
}
|
|
296
|
+
export interface GeneratedSignature {
|
|
297
|
+
header: string;
|
|
298
|
+
value: string;
|
|
299
|
+
}
|
|
300
|
+
export interface SaveAsTemplateOptions {
|
|
301
|
+
id?: string;
|
|
302
|
+
name?: string;
|
|
303
|
+
event?: string;
|
|
304
|
+
description?: string;
|
|
305
|
+
url?: string;
|
|
306
|
+
overwrite?: boolean;
|
|
307
|
+
}
|
|
308
|
+
export interface SaveAsTemplateResult {
|
|
309
|
+
id: string;
|
|
310
|
+
filePath: string;
|
|
311
|
+
template: WebhookTemplate;
|
|
312
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const HttpMethodSchema = z.enum([
|
|
3
|
+
"GET",
|
|
4
|
+
"POST",
|
|
5
|
+
"PUT",
|
|
6
|
+
"PATCH",
|
|
7
|
+
"DELETE",
|
|
8
|
+
"HEAD",
|
|
9
|
+
"OPTIONS",
|
|
10
|
+
]);
|
|
11
|
+
export const HeaderEntrySchema = z.object({
|
|
12
|
+
key: z.string().min(1),
|
|
13
|
+
value: z.string(),
|
|
14
|
+
});
|
|
15
|
+
export const WebhookProviderSchema = z.enum([
|
|
16
|
+
"stripe",
|
|
17
|
+
"github",
|
|
18
|
+
"shopify",
|
|
19
|
+
"twilio",
|
|
20
|
+
"ragie",
|
|
21
|
+
"recall",
|
|
22
|
+
"sendgrid",
|
|
23
|
+
"slack",
|
|
24
|
+
"discord",
|
|
25
|
+
"linear",
|
|
26
|
+
"clerk",
|
|
27
|
+
"custom",
|
|
28
|
+
]);
|
|
29
|
+
export const TemplateMetadataSchema = z.object({
|
|
30
|
+
id: z.string(),
|
|
31
|
+
name: z.string(),
|
|
32
|
+
description: z.string().optional(),
|
|
33
|
+
provider: WebhookProviderSchema,
|
|
34
|
+
event: z.string(),
|
|
35
|
+
file: z.string(),
|
|
36
|
+
version: z.string().optional(),
|
|
37
|
+
docsUrl: z.string().url().optional(),
|
|
38
|
+
});
|
|
39
|
+
export const TemplatesIndexSchema = z.object({
|
|
40
|
+
version: z.string(),
|
|
41
|
+
templates: z.array(TemplateMetadataSchema),
|
|
42
|
+
});
|
|
43
|
+
export const WebhookTemplateSchema = z.object({
|
|
44
|
+
url: z.string().url().optional(),
|
|
45
|
+
method: HttpMethodSchema.default("POST"),
|
|
46
|
+
headers: z.array(HeaderEntrySchema).default([]),
|
|
47
|
+
body: z.any().optional(),
|
|
48
|
+
provider: WebhookProviderSchema.optional(),
|
|
49
|
+
event: z.string().optional(),
|
|
50
|
+
description: z.string().optional(),
|
|
51
|
+
});
|
|
52
|
+
export const CapturedWebhookSchema = z.object({
|
|
53
|
+
id: z.string(),
|
|
54
|
+
timestamp: z.string(),
|
|
55
|
+
method: HttpMethodSchema,
|
|
56
|
+
url: z.string(),
|
|
57
|
+
path: z.string(),
|
|
58
|
+
headers: z.record(z.union([z.string(), z.array(z.string())])),
|
|
59
|
+
body: z.any().optional(),
|
|
60
|
+
rawBody: z.string(),
|
|
61
|
+
query: z.record(z.union([z.string(), z.array(z.string())])),
|
|
62
|
+
provider: WebhookProviderSchema.optional(),
|
|
63
|
+
contentType: z.string().optional(),
|
|
64
|
+
contentLength: z.number().optional(),
|
|
65
|
+
});
|
|
66
|
+
export const ConfigSchema = z.object({
|
|
67
|
+
version: z.string().default("2.0.0"),
|
|
68
|
+
templatesDir: z.string().optional(),
|
|
69
|
+
capturesDir: z.string().optional(),
|
|
70
|
+
defaultTargetUrl: z.string().url().optional(),
|
|
71
|
+
secrets: z
|
|
72
|
+
.record(z.string())
|
|
73
|
+
.optional()
|
|
74
|
+
.describe("Provider secrets for signature generation"),
|
|
75
|
+
dashboard: z
|
|
76
|
+
.object({
|
|
77
|
+
port: z.number().default(4000),
|
|
78
|
+
host: z.string().default("localhost"),
|
|
79
|
+
})
|
|
80
|
+
.optional(),
|
|
81
|
+
capture: z
|
|
82
|
+
.object({
|
|
83
|
+
port: z.number().default(3001),
|
|
84
|
+
host: z.string().default("0.0.0.0"),
|
|
85
|
+
})
|
|
86
|
+
.optional(),
|
|
87
|
+
});
|