Skip to content

Commit cf723d8

Browse files
authored
Fix dataset schema payload types and release v3.0.4 (#81)
* fix(actor): accept object payloads in dataset schema * fix(actor): align dataset schema with json payload types
1 parent 42c6e37 commit cf723d8

7 files changed

Lines changed: 198 additions & 36 deletions

File tree

.actor/actor.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"name": "webhook-debugger-logger",
44
"title": "Webhook Debugger, Logger & API Mocking Suite",
55
"description": "Enterprise-grade tool to test, debug, and mock webhooks. Features real-time SSE streaming, request replay, HTTP forwarding, and JSON schema validation. Perfect for Stripe, GitHub, and Shopify integrations.",
6-
"version": "3.0.3",
6+
"version": "3.0.4",
77
"output": "./output_schema.json",
88
"input": "./input_schema.json",
99
"webServerSchema": "./web_server_schema.json",

.actor/dataset_schema.json

Lines changed: 129 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,31 @@
5858
}
5959
},
6060
"body": {
61-
"type": "string",
61+
"oneOf": [
62+
{
63+
"type": "string"
64+
},
65+
{
66+
"type": "object"
67+
},
68+
{
69+
"type": "array"
70+
},
71+
{
72+
"type": "number"
73+
},
74+
{
75+
"type": "boolean"
76+
},
77+
{
78+
"type": "null"
79+
}
80+
],
6281
"title": "Body",
63-
"description": "The raw or parsed request body",
64-
"example": "{\"status\": \"success\"}"
82+
"description": "The raw request body as text, or a parsed/offloaded JSON payload",
83+
"example": {
84+
"status": "success"
85+
}
6586
},
6687
"contentType": {
6788
"type": "string",
@@ -106,16 +127,39 @@
106127
"example": 200
107128
},
108129
"responseBody": {
109-
"type": "string",
130+
"oneOf": [
131+
{
132+
"type": "string"
133+
},
134+
{
135+
"type": "object"
136+
},
137+
{
138+
"type": "array"
139+
},
140+
{
141+
"type": "number"
142+
},
143+
{
144+
"type": "boolean"
145+
},
146+
{
147+
"type": "null"
148+
}
149+
],
110150
"title": "Response Body",
111-
"description": "Body returned to the webhook sender",
112-
"example": "{\"received\": true}"
151+
"description": "Response body returned to the webhook sender as text or JSON",
152+
"example": {
153+
"received": true
154+
}
113155
},
114156
"responseHeaders": {
115157
"type": "object",
116158
"title": "Response Headers",
117159
"description": "Headers returned to the webhook sender",
118-
"example": { "content-type": "application/json" }
160+
"example": {
161+
"content-type": "application/json"
162+
}
119163
},
120164
"signatureProvider": {
121165
"type": "string",
@@ -153,17 +197,41 @@
153197
"display": {
154198
"component": "table",
155199
"properties": {
156-
"timestamp": { "label": "Time", "format": "date" },
157-
"requestId": { "label": "Req ID" },
158-
"signatureValid": { "label": "Sig", "format": "boolean" },
159-
"webhookId": { "label": "Webhook ID" },
160-
"method": { "label": "Method" },
161-
"statusCode": { "label": "Status" },
162-
"contentType": { "label": "Content-Type" },
163-
"size": { "label": "Size (Bytes)" },
164-
"processingTime": { "label": "Latency (ms)" },
165-
"remoteIp": { "label": "Source IP" },
166-
"signatureProvider": { "label": "Provider" }
200+
"timestamp": {
201+
"label": "Time",
202+
"format": "date"
203+
},
204+
"requestId": {
205+
"label": "Req ID"
206+
},
207+
"signatureValid": {
208+
"label": "Sig",
209+
"format": "boolean"
210+
},
211+
"webhookId": {
212+
"label": "Webhook ID"
213+
},
214+
"method": {
215+
"label": "Method"
216+
},
217+
"statusCode": {
218+
"label": "Status"
219+
},
220+
"contentType": {
221+
"label": "Content-Type"
222+
},
223+
"size": {
224+
"label": "Size (Bytes)"
225+
},
226+
"processingTime": {
227+
"label": "Latency (ms)"
228+
},
229+
"remoteIp": {
230+
"label": "Source IP"
231+
},
232+
"signatureProvider": {
233+
"label": "Provider"
234+
}
167235
}
168236
}
169237
},
@@ -189,18 +257,49 @@
189257
"display": {
190258
"component": "table",
191259
"properties": {
192-
"timestamp": { "label": "Time", "format": "date" },
193-
"requestId": { "label": "Req ID" },
194-
"signatureValid": { "label": "Sig", "format": "boolean" },
195-
"method": { "label": "Method" },
196-
"statusCode": { "label": "Status" },
197-
"query": { "label": "Query", "format": "object" },
198-
"headers": { "label": "Headers", "format": "object" },
199-
"body": { "label": "Body", "format": "text" },
200-
"responseBody": { "label": "Res Body", "format": "text" },
201-
"responseHeaders": { "label": "Res Headers", "format": "object" },
202-
"signatureProvider": { "label": "Sig Provider" },
203-
"signatureError": { "label": "Sig Error" }
260+
"timestamp": {
261+
"label": "Time",
262+
"format": "date"
263+
},
264+
"requestId": {
265+
"label": "Req ID"
266+
},
267+
"signatureValid": {
268+
"label": "Sig",
269+
"format": "boolean"
270+
},
271+
"method": {
272+
"label": "Method"
273+
},
274+
"statusCode": {
275+
"label": "Status"
276+
},
277+
"query": {
278+
"label": "Query",
279+
"format": "object"
280+
},
281+
"headers": {
282+
"label": "Headers",
283+
"format": "object"
284+
},
285+
"body": {
286+
"label": "Body",
287+
"format": "text"
288+
},
289+
"responseBody": {
290+
"label": "Res Body",
291+
"format": "text"
292+
},
293+
"responseHeaders": {
294+
"label": "Res Headers",
295+
"format": "object"
296+
},
297+
"signatureProvider": {
298+
"label": "Sig Provider"
299+
},
300+
"signatureError": {
301+
"label": "Sig Error"
302+
}
204303
}
205304
}
206305
}

.actor/web_server_schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"info": {
44
"title": "Webhook Debugger & Logger API",
55
"description": "OpenAPI description for the Webhook Debugger & Logger Actor web server. Authentication is configuration-driven: when authKey is configured, management routes require either a bearer token or the key query parameter; when authKey is unset, those routes remain accessible without credentials.",
6-
"version": "3.0.3"
6+
"version": "3.0.4"
77
},
88
"servers": [
99
{
@@ -80,7 +80,7 @@
8080
"schema": {
8181
"type": "string"
8282
},
83-
"example": "Webhook Debugger & Logger (v3.0.3)\nActive Webhooks: 1\nSignature Verification: STRIPE"
83+
"example": "Webhook Debugger & Logger (v3.0.4)\nActive Webhooks: 1\nSignature Verification: STRIPE"
8484
}
8585
}
8686
},

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
55

6+
## [3.0.4] - 2026-04-18
7+
8+
### Fixed (3.0.4)
9+
10+
- **Apify**: Relax the dataset storage schema for `body` and `responseBody` so webhook events can be stored when request or response payloads are captured as any JSON-compatible values instead of only strings and objects.
11+
- **Tests**: Add a regression test that keeps the Actor dataset schema aligned with the webhook payload shapes persisted by the runtime.
12+
613
## [3.0.3] - 2026-04-18
714

815
### Fixed (3.0.3)

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "webhook-debugger-logger",
3-
"version": "3.0.3",
3+
"version": "3.0.4",
44
"type": "module",
55
"description": "Generate temporary webhook URLs and log all incoming requests with full details.",
66
"main": "src/main.js",

tests/unit/actor/input_schema.test.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import { getInputSchemaSecretFieldKeys } from "@apify/input_secrets";
88
import { createRequire } from "node:module";
99

1010
const require = createRequire(import.meta.url);
11+
const Ajv = require("ajv").default;
1112
const inputSchema = require("../../../.actor/input_schema.json");
13+
const datasetSchema = require("../../../.actor/dataset_schema.json");
1214

1315
/**
1416
* @param {unknown} value
@@ -130,3 +132,57 @@ describe("Apify input schema", () => {
130132
expect(missingDescriptions).toEqual([]);
131133
});
132134
});
135+
136+
describe("Apify dataset schema", () => {
137+
it("allows webhook body fields to be stored in the runtime-supported JSON shapes", () => {
138+
const ajv = new Ajv({ strict: false, validateFormats: false });
139+
const validate = ajv.compile(datasetSchema.fields);
140+
141+
expect(
142+
validate({
143+
body: { status: "success" },
144+
responseBody: { received: true },
145+
}),
146+
).toBe(true);
147+
expect(validate.errors).toBeNull();
148+
149+
expect(
150+
validate({
151+
body: '{"status":"success"}',
152+
responseBody: '{"received":true}',
153+
}),
154+
).toBe(true);
155+
expect(validate.errors).toBeNull();
156+
157+
expect(
158+
validate({
159+
body: ["first", "second"],
160+
responseBody: null,
161+
}),
162+
).toBe(true);
163+
expect(validate.errors).toBeNull();
164+
165+
expect(
166+
validate({
167+
body: 123,
168+
responseBody: true,
169+
}),
170+
).toBe(true);
171+
expect(validate.errors).toBeNull();
172+
173+
expect(
174+
validate({
175+
body: false,
176+
responseBody: ["one", "two", "three"],
177+
}),
178+
).toBe(true);
179+
expect(validate.errors).toBeNull();
180+
181+
expect(
182+
validate({
183+
body: () => "not-json",
184+
}),
185+
).toBe(false);
186+
expect(validate.errors).not.toBeNull();
187+
});
188+
});

0 commit comments

Comments
 (0)