@shivaedev/webhooks 0.1.0 → 0.1.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../../src/internal/receive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE1E,eAAO,MAAM,OAAO,GAAgC,CAAC,4fA6BnD,CAAC"}
1
+ {"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../../src/internal/receive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE1E,eAAO,MAAM,OAAO,GAAgC,CAAC,4fA+BnD,CAAC"}
@@ -1,12 +1,13 @@
1
1
  import { Effect, Option } from "effect";
2
2
  import { HttpServerResponse } from "effect/http";
3
+ import * as HttpStatus from "effect/http/HttpStatus";
3
4
  import { SqlClient } from "effect/sql";
4
5
  import { enqueueWebhookJobs } from "#registration.ts";
5
6
  export const receive = Effect.fnUntraced(function* (name, source, key, body, headers, jobs) {
6
7
  yield* source.strategy.verify(body, headers, key);
7
8
  const { id, event } = source.strategy.delivery(headers);
8
9
  if (!(id && event)) {
9
- return HttpServerResponse.text("Invalid delivery", { status: 400 });
10
+ return HttpServerResponse.text("Invalid delivery", { status: HttpStatus.fromLiteral("BadRequest") });
10
11
  }
11
12
  const definition = Object.hasOwn(source.events, event) ? source.events[event] : undefined;
12
13
  const sql = yield* SqlClient.SqlClient;
@@ -15,12 +16,14 @@ export const receive = Effect.fnUntraced(function* (name, source, key, body, hea
15
16
  values (${name}, ${id}, ${event}, 'ignored', '[]'::jsonb)
16
17
  on conflict (source, delivery_id) do nothing returning delivery_id`;
17
18
  if (inserted.length === 0) {
18
- return HttpServerResponse.text("already queued", { status: 200 });
19
+ return HttpServerResponse.text("already queued", { status: HttpStatus.fromLiteral("OK") });
19
20
  }
20
21
  const requests = definition === undefined ? [] : yield* definition.decode(body);
21
22
  const ids = (yield* enqueueWebhookJobs(requests, jobs)).flatMap(Option.toArray);
22
23
  yield* sql `update webhook_receipts set job_ids = ${JSON.stringify(ids)}::jsonb, outcome = ${requests.length === 0 ? "ignored" : "queued"} where source = ${name} and delivery_id = ${id}`;
23
- return HttpServerResponse.text(requests.length === 0 ? "ignored" : "queued", { status: requests.length === 0 ? 200 : 202 });
24
+ return HttpServerResponse.text(requests.length === 0 ? "ignored" : "queued", {
25
+ status: requests.length === 0 ? HttpStatus.fromLiteral("OK") : HttpStatus.fromLiteral("Accepted"),
26
+ });
24
27
  }));
25
28
  });
26
29
  //# sourceMappingURL=receive.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"receive.js","sourceRoot":"","sources":["../../src/internal/receive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAiB,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAsB,MAAM,kBAAkB,CAAC;AAE1E,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EACjD,IAAY,EACZ,MAAwB,EACxB,GAA8B,EAC9B,IAAgB,EAChB,OAAyC,EACzC,IAAmB;IAEnB,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACxD,IAAI,CAAC,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,kBAAkB,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1F,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,OAAO,KAAK,CAAC,CAAC,GAAG,CAAC,eAAe,CAChC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA;cAChB,IAAI,KAAK,EAAE,KAAK,KAAK;uEACoC,CAAC;QACrE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,kBAAkB,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChF,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChF,KAAK,CAAC,CAAC,GAAG,CAAA,yCAAyC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,sBAAsB,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,mBAAmB,IAAI,sBAAsB,EAAE,EAAE,CAAC;QAC1L,OAAO,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7H,CAAC,CAAC,CACF,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"receive.js","sourceRoot":"","sources":["../../src/internal/receive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAiB,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAsB,MAAM,kBAAkB,CAAC;AAE1E,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EACjD,IAAY,EACZ,MAAwB,EACxB,GAA8B,EAC9B,IAAgB,EAChB,OAAyC,EACzC,IAAmB;IAEnB,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACxD,IAAI,CAAC,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,kBAAkB,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACtG,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1F,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,OAAO,KAAK,CAAC,CAAC,GAAG,CAAC,eAAe,CAChC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA;cAChB,IAAI,KAAK,EAAE,KAAK,KAAK;uEACoC,CAAC;QACrE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,kBAAkB,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5F,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChF,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChF,KAAK,CAAC,CAAC,GAAG,CAAA,yCAAyC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,sBAAsB,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,mBAAmB,IAAI,sBAAsB,EAAE,EAAE,CAAC;QAC1L,OAAO,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE;YAC5E,MAAM,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC;SACjG,CAAC,CAAC;IACJ,CAAC,CAAC,CACF,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAU,KAAK,EAAiB,MAAM,QAAQ,CAAC;AACpE,OAAO,EAAE,UAAU,EAAsB,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,mBAAmB,CAAC,KAAK,EAAE,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,IAAI,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,CAAC,KAAK,EAAE,CAAC,CAAC,oKA6B5E"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAU,KAAK,EAAiB,MAAM,QAAQ,CAAC;AACpE,OAAO,EAAE,UAAU,EAAsB,MAAM,aAAa,CAAC;AAE7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,mBAAmB,CAAC,KAAK,EAAE,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,IAAI,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,CAAC,KAAK,EAAE,CAAC,CAAC,oKA+B5E"}
package/dist/route.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Effect, Layer } from "effect";
2
2
  import { HttpRouter, HttpServerResponse } from "effect/http";
3
+ import * as HttpStatus from "effect/http/HttpStatus";
3
4
  import { readBoundedBody } from "@shivaedev/http/server/boundedBody.ts";
4
5
  import { receive } from "#internal/receive.ts";
5
6
  export function webhookRoute(options) {
@@ -16,11 +17,11 @@ export function webhookRoute(options) {
16
17
  const source = Object.hasOwn(options.sources, name) ? options.sources[name] : undefined;
17
18
  const key = keys.get(name);
18
19
  if (source === undefined || key === undefined) {
19
- return HttpServerResponse.empty({ status: 404 });
20
+ return HttpServerResponse.empty({ status: HttpStatus.fromLiteral("NotFound") });
20
21
  }
21
22
  const body = new Uint8Array(yield* readBoundedBody(request));
22
23
  return yield* receive(name, source, key, body, request.headers, jobs).pipe(Effect.provideContext(context));
23
- }).pipe(Effect.catchTag("RequestBodyTooLarge", () => Effect.succeed(HttpServerResponse.empty({ status: 413 }))), Effect.catchTag("WebhookUnauthorized", () => Effect.succeed(HttpServerResponse.empty({ status: 401 }))), Effect.catchTag("SchemaError", () => Effect.succeed(HttpServerResponse.empty({ status: 400 }))), Effect.catch(() => Effect.succeed(HttpServerResponse.empty({ status: 503 })))));
24
+ }).pipe(Effect.catchTag("RequestBodyTooLarge", () => Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("PayloadTooLarge") }))), Effect.catchTag("WebhookUnauthorized", () => Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("Unauthorized") }))), Effect.catchTag("SchemaError", () => Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("BadRequest") }))), Effect.catch(() => Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("ServiceUnavailable") })))));
24
25
  }).pipe(Effect.orDie));
25
26
  }
26
27
  //# sourceMappingURL=route.js.map
package/dist/route.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/webhooks",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Verified webhook receipts and transactional job delivery over Effect HTTP",
5
5
  "keywords": [
6
6
  "effect"
@@ -47,15 +47,15 @@
47
47
  "dependencies": {
48
48
  "@shivaedev/github": "0.7.0",
49
49
  "@shivaedev/http": "0.1.0",
50
- "@shivaedev/jobs": "0.21.0",
51
- "@shivaedev/sql": "0.23.0"
50
+ "@shivaedev/jobs": "0.22.0",
51
+ "@shivaedev/sql": "0.24.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@effect/platform-node": "4.0.5",
55
- "@shivaedev/quality": "0.42.0",
56
- "@shivaedev/server": "0.2.0",
57
- "@shivaedev/test-sql": "0.10.1",
58
- "@shivaedev/test-story": "0.21.1",
55
+ "@shivaedev/quality": "0.43.0",
56
+ "@shivaedev/server": "0.3.0",
57
+ "@shivaedev/test-sql": "0.10.2",
58
+ "@shivaedev/test-story": "0.22.0",
59
59
  "@types/node": "24.19.2",
60
60
  "effect": "4.0.5",
61
61
  "pg-boss": "12.38.0",
@@ -1,5 +1,6 @@
1
1
  import { Effect, Option, type Redacted } from "effect";
2
2
  import { HttpServerResponse } from "effect/http";
3
+ import * as HttpStatus from "effect/http/HttpStatus";
3
4
  import { SqlClient } from "effect/sql";
4
5
  import type { PgBossService } from "@shivaedev/jobs/server/service.ts";
5
6
  import { enqueueWebhookJobs, type WebhookSource } from "#registration.ts";
@@ -15,7 +16,7 @@ export const receive = Effect.fnUntraced(function* <R>(
15
16
  yield* source.strategy.verify(body, headers, key);
16
17
  const { id, event } = source.strategy.delivery(headers);
17
18
  if (!(id && event)) {
18
- return HttpServerResponse.text("Invalid delivery", { status: 400 });
19
+ return HttpServerResponse.text("Invalid delivery", { status: HttpStatus.fromLiteral("BadRequest") });
19
20
  }
20
21
  const definition = Object.hasOwn(source.events, event) ? source.events[event] : undefined;
21
22
  const sql = yield* SqlClient.SqlClient;
@@ -25,12 +26,14 @@ export const receive = Effect.fnUntraced(function* <R>(
25
26
  values (${name}, ${id}, ${event}, 'ignored', '[]'::jsonb)
26
27
  on conflict (source, delivery_id) do nothing returning delivery_id`;
27
28
  if (inserted.length === 0) {
28
- return HttpServerResponse.text("already queued", { status: 200 });
29
+ return HttpServerResponse.text("already queued", { status: HttpStatus.fromLiteral("OK") });
29
30
  }
30
31
  const requests = definition === undefined ? [] : yield* definition.decode(body);
31
32
  const ids = (yield* enqueueWebhookJobs(requests, jobs)).flatMap(Option.toArray);
32
33
  yield* sql`update webhook_receipts set job_ids = ${JSON.stringify(ids)}::jsonb, outcome = ${requests.length === 0 ? "ignored" : "queued"} where source = ${name} and delivery_id = ${id}`;
33
- return HttpServerResponse.text(requests.length === 0 ? "ignored" : "queued", { status: requests.length === 0 ? 200 : 202 });
34
+ return HttpServerResponse.text(requests.length === 0 ? "ignored" : "queued", {
35
+ status: requests.length === 0 ? HttpStatus.fromLiteral("OK") : HttpStatus.fromLiteral("Accepted"),
36
+ });
34
37
  }),
35
38
  );
36
39
  });
package/src/route.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type Context, Effect, Layer, type Redacted } from "effect";
2
2
  import { HttpRouter, HttpServerResponse } from "effect/http";
3
+ import * as HttpStatus from "effect/http/HttpStatus";
3
4
  import type { SqlClient } from "effect/sql";
4
5
  import { readBoundedBody } from "@shivaedev/http/server/boundedBody.ts";
5
6
  import type { PgBossService } from "@shivaedev/jobs/server/service.ts";
@@ -28,15 +29,17 @@ export function webhookRoute<TJobs, R>(options: WebhookRouteOptions<TJobs, R>) {
28
29
  const source = Object.hasOwn(options.sources, name) ? options.sources[name] : undefined;
29
30
  const key = keys.get(name);
30
31
  if (source === undefined || key === undefined) {
31
- return HttpServerResponse.empty({ status: 404 });
32
+ return HttpServerResponse.empty({ status: HttpStatus.fromLiteral("NotFound") });
32
33
  }
33
34
  const body = new Uint8Array(yield* readBoundedBody(request));
34
35
  return yield* receive(name, source, key, body, request.headers, jobs).pipe(Effect.provideContext(context));
35
36
  }).pipe(
36
- Effect.catchTag("RequestBodyTooLarge", () => Effect.succeed(HttpServerResponse.empty({ status: 413 }))),
37
- Effect.catchTag("WebhookUnauthorized", () => Effect.succeed(HttpServerResponse.empty({ status: 401 }))),
38
- Effect.catchTag("SchemaError", () => Effect.succeed(HttpServerResponse.empty({ status: 400 }))),
39
- Effect.catch(() => Effect.succeed(HttpServerResponse.empty({ status: 503 }))),
37
+ Effect.catchTag("RequestBodyTooLarge", () =>
38
+ Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("PayloadTooLarge") })),
39
+ ),
40
+ Effect.catchTag("WebhookUnauthorized", () => Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("Unauthorized") }))),
41
+ Effect.catchTag("SchemaError", () => Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("BadRequest") }))),
42
+ Effect.catch(() => Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("ServiceUnavailable") }))),
40
43
  ),
41
44
  );
42
45
  }).pipe(Effect.orDie),