@shivaedev/webhooks 0.1.3 → 0.2.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/README.md +12 -13
- package/dist/server/WebhookUnauthorized.d.ts.map +1 -0
- package/dist/server/WebhookUnauthorized.js.map +1 -0
- package/dist/{github.d.ts → server/github.d.ts} +1 -1
- package/dist/server/github.d.ts.map +1 -0
- package/dist/{github.js → server/github.js} +1 -1
- package/dist/server/github.js.map +1 -0
- package/dist/server/internal/Receipt.d.ts +14 -0
- package/dist/server/internal/Receipt.d.ts.map +1 -0
- package/dist/server/internal/Receipt.js +10 -0
- package/dist/server/internal/Receipt.js.map +1 -0
- package/dist/server/internal/receiptMigrations.d.ts +7 -0
- package/dist/server/internal/receiptMigrations.d.ts.map +1 -0
- package/dist/server/internal/receiptMigrations.js +12 -0
- package/dist/server/internal/receiptMigrations.js.map +1 -0
- package/dist/{internal → server/internal}/receive.d.ts +1 -1
- package/dist/server/internal/receive.d.ts.map +1 -0
- package/dist/{internal → server/internal}/receive.js +4 -4
- package/dist/server/internal/receive.js.map +1 -0
- package/dist/server/migrations/0001_create_receipts.d.ts +5 -0
- package/dist/server/migrations/0001_create_receipts.d.ts.map +1 -0
- package/dist/server/migrations/0001_create_receipts.js +15 -0
- package/dist/server/migrations/0001_create_receipts.js.map +1 -0
- package/dist/server/migrations/0002_receipt_job_ids.d.ts +5 -0
- package/dist/server/migrations/0002_receipt_job_ids.d.ts.map +1 -0
- package/dist/server/migrations/0002_receipt_job_ids.js +11 -0
- package/dist/server/migrations/0002_receipt_job_ids.js.map +1 -0
- package/dist/{registration.d.ts → server/registration.d.ts} +1 -1
- package/dist/server/registration.d.ts.map +1 -0
- package/dist/server/registration.js.map +1 -0
- package/dist/{route.d.ts → server/route.d.ts} +2 -2
- package/dist/server/route.d.ts.map +1 -0
- package/dist/{route.js → server/route.js} +11 -5
- package/dist/server/route.js.map +1 -0
- package/dist/server/webhookReceipts.d.ts.map +1 -0
- package/dist/server/webhookReceipts.js +19 -0
- package/dist/server/webhookReceipts.js.map +1 -0
- package/package.json +11 -11
- package/src/{github.ts → server/github.ts} +2 -2
- package/src/server/internal/Receipt.ts +10 -0
- package/src/server/internal/receiptMigrations.ts +12 -0
- package/src/{internal → server/internal}/receive.ts +4 -4
- package/src/server/migrations/0001_create_receipts.ts +15 -0
- package/src/server/migrations/0002_receipt_job_ids.ts +11 -0
- package/src/{registration.ts → server/registration.ts} +1 -1
- package/src/{route.ts → server/route.ts} +15 -6
- package/src/server/webhookReceipts.ts +20 -0
- package/dist/WebhookUnauthorized.d.ts.map +0 -1
- package/dist/WebhookUnauthorized.js.map +0 -1
- package/dist/github.d.ts.map +0 -1
- package/dist/github.js.map +0 -1
- package/dist/internal/receive.d.ts.map +0 -1
- package/dist/internal/receive.js.map +0 -1
- package/dist/registration.d.ts.map +0 -1
- package/dist/registration.js.map +0 -1
- package/dist/route.d.ts.map +0 -1
- package/dist/route.js.map +0 -1
- package/dist/webhookReceipts.d.ts.map +0 -1
- package/dist/webhookReceipts.js +0 -23
- package/dist/webhookReceipts.js.map +0 -1
- package/src/webhookReceipts.ts +0 -24
- /package/dist/{WebhookUnauthorized.d.ts → server/WebhookUnauthorized.d.ts} +0 -0
- /package/dist/{WebhookUnauthorized.js → server/WebhookUnauthorized.js} +0 -0
- /package/dist/{registration.js → server/registration.js} +0 -0
- /package/dist/{webhookReceipts.d.ts → server/webhookReceipts.d.ts} +0 -0
- /package/src/{WebhookUnauthorized.ts → server/WebhookUnauthorized.ts} +0 -0
package/README.md
CHANGED
|
@@ -23,19 +23,21 @@ A source has a name, a verification strategy, a signing key loaded through Effec
|
|
|
23
23
|
|
|
24
24
|
### Register receipts and queues
|
|
25
25
|
|
|
26
|
-
Register `webhookReceipts` in the host's `migrations.components` alongside `pgBossSchema()`. The normal migration mode applies it; `check` reports
|
|
26
|
+
Register `webhookReceipts` in the host's `migrations.components` alongside `pgBossSchema()`. The normal migration mode applies it; `check` reports missing or pending receipt migrations, and `wait` waits for them. The receipt table is `webhook_receipts`, keyed by `(source, delivery_id)`, with the event, a UTC `timestamptz` received time, `queued` or `ignored` outcome, and a `text[]` column of queued job IDs. The component applies numbered migrations recorded in `webhook_receipts_migrations`, preserving existing receipts when their schema changes.
|
|
27
|
+
|
|
28
|
+
When upgrading a database whose `job_ids` column is JSON, stop the older receivers, apply `webhookReceipts`, then start the new receivers. Direct SQL readers use PostgreSQL array operations for `job_ids`.
|
|
27
29
|
|
|
28
30
|
```ts
|
|
29
31
|
import { Config, Effect, Layer, Redacted, Schema } from "effect";
|
|
30
32
|
import { SqlClient } from "effect/sql";
|
|
31
33
|
import { defineQueue } from "@shivaedev/jobs/server/definition.ts";
|
|
32
34
|
import { pgBossSchema } from "@shivaedev/jobs/server/schema.ts";
|
|
33
|
-
import { makePgBoss } from "@shivaedev/jobs/server/service.ts";
|
|
35
|
+
import { makePgBoss, pgBossLayer } from "@shivaedev/jobs/server/service.ts";
|
|
34
36
|
import { appHost } from "@shivaedev/server/appHost.ts";
|
|
35
|
-
import { githubSource } from "@shivaedev/webhooks/github.ts";
|
|
36
|
-
import { webhookEvent, webhookJob } from "@shivaedev/webhooks/registration.ts";
|
|
37
|
-
import { webhookRoute } from "@shivaedev/webhooks/route.ts";
|
|
38
|
-
import { webhookReceipts } from "@shivaedev/webhooks/webhookReceipts.ts";
|
|
37
|
+
import { githubSource } from "@shivaedev/webhooks/server/github.ts";
|
|
38
|
+
import { webhookEvent, webhookJob } from "@shivaedev/webhooks/server/registration.ts";
|
|
39
|
+
import { webhookRoute } from "@shivaedev/webhooks/server/route.ts";
|
|
40
|
+
import { webhookReceipts } from "@shivaedev/webhooks/server/webhookReceipts.ts";
|
|
39
41
|
|
|
40
42
|
const Jobs = makePgBoss("app/Jobs");
|
|
41
43
|
const IndexIssue = defineQueue({
|
|
@@ -62,11 +64,7 @@ const Host = appHost({
|
|
|
62
64
|
},
|
|
63
65
|
application: Effect.gen(function* () {
|
|
64
66
|
const sql = yield* SqlClient.SqlClient;
|
|
65
|
-
const jobs = Jobs.layer({
|
|
66
|
-
connectionString: Redacted.value(databaseUrl),
|
|
67
|
-
jobs: [IndexIssue],
|
|
68
|
-
migrate: false,
|
|
69
|
-
});
|
|
67
|
+
const jobs = Jobs.layer({ jobs: [IndexIssue] }).pipe(Layer.provide(pgBossLayer({ connectionString: databaseUrl, migrate: false })));
|
|
70
68
|
return {
|
|
71
69
|
group: Api,
|
|
72
70
|
handlers,
|
|
@@ -75,14 +73,13 @@ const Host = appHost({
|
|
|
75
73
|
routes: webhookRoute({ basePath: "/webhooks", jobs: Jobs, sources }).pipe(
|
|
76
74
|
Layer.provide(jobs),
|
|
77
75
|
Layer.provide(Layer.succeed(SqlClient.SqlClient, sql)),
|
|
78
|
-
Layer.orDie,
|
|
79
76
|
),
|
|
80
77
|
};
|
|
81
78
|
}),
|
|
82
79
|
});
|
|
83
80
|
```
|
|
84
81
|
|
|
85
|
-
`databaseUrl`, `loader`, `Api`, `handlers` and `sessions` are the application's existing host inputs. The route above receives GitHub deliveries at `POST /webhooks/github`. It uses the existing `appHost.routes` option and the host's `maxBodySize`; the jobs client and SQL client must point at the same PostgreSQL database. Register workers separately with the job definitions' `handle` method, in the processes your application chooses.
|
|
82
|
+
`databaseUrl`, `loader`, `Api`, `handlers` and `sessions` are the application's existing host inputs. The route above receives GitHub deliveries at `POST /webhooks/github`. It uses the existing `appHost.routes` option and the host's `maxBodySize`; the jobs client and SQL client must point at the same PostgreSQL database. Register workers separately with the job definitions' `handle` method, in the processes your application chooses. A missing signing key fails the route Layer with `ConfigError`; composing it into `Host` preserves that typed error for the application's startup to handle.
|
|
86
83
|
|
|
87
84
|
### Answers and retries
|
|
88
85
|
|
|
@@ -100,6 +97,8 @@ const Host = appHost({
|
|
|
100
97
|
|
|
101
98
|
Refused requests create no receipt and no jobs. Signatures are checked before decoding; unlisted events are verified and recorded without decoding. The signing key, signature and raw body stay out of responses, logs and spans.
|
|
102
99
|
|
|
100
|
+
Database and enqueue failures log their redacted cause and `errorTag` at error level before the empty 503 response. The HTTP request span records the redacted failure with its original tag. Receiving a delivery runs under the `Webhooks.receive` span.
|
|
101
|
+
|
|
103
102
|
The receipt insert and every enqueue use one SQL transaction. Concurrent copies wait on the receipt's unique key: a committed first copy makes the second a duplicate; a rolled-back first copy lets the second receive the delivery itself. If any enqueue fails, earlier enqueues and the receipt roll back, and the sender's retry can succeed. Receipts for ignored events are deduplicated too.
|
|
104
103
|
|
|
105
104
|
### Other senders
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebhookUnauthorized.d.ts","sourceRoot":"","sources":["../../src/server/WebhookUnauthorized.ts"],"names":[],"mappings":";;;AAEA,qBAAa,mBAAoB,SAAQ,wBAAuC;CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebhookUnauthorized.js","sourceRoot":"","sources":["../../src/server/WebhookUnauthorized.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,MAAM,OAAO,mBAAoB,SAAQ,IAAI,CAAC,WAAW,CAAC,qBAAqB,CAAC;CAAG"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WebhookSource, WebhookStrategy } from "#registration.ts";
|
|
1
|
+
import type { WebhookSource, WebhookStrategy } from "#server/registration.ts";
|
|
2
2
|
export declare const githubStrategy: WebhookStrategy;
|
|
3
3
|
export declare function githubSource<R>(options: Omit<WebhookSource<R>, "strategy">): WebhookSource<R>;
|
|
4
4
|
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/server/github.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG9E,eAAO,MAAM,cAAc,EAAE,eAG5B,CAAC;AAEF,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAE7F"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { verifyWebhook } from "@shivaedev/github/verifyWebhook.ts";
|
|
3
|
-
import { WebhookUnauthorized } from "#WebhookUnauthorized.ts";
|
|
3
|
+
import { WebhookUnauthorized } from "#server/WebhookUnauthorized.ts";
|
|
4
4
|
export const githubStrategy = {
|
|
5
5
|
delivery: (headers) => ({ event: headers["x-github-event"], id: headers["x-github-delivery"] }),
|
|
6
6
|
verify: (body, headers, key) => verifyWebhook(body, headers["x-hub-signature-256"], key).pipe(Effect.mapError(() => new WebhookUnauthorized())),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/server/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAErE,MAAM,CAAC,MAAM,cAAc,GAAoB;IAC9C,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,mBAAmB,CAAC,EAAE,CAAC;IAC/F,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,qBAAqB,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE,CAAC,CAAC;CAC/I,CAAC;AAEF,MAAM,UAAU,YAAY,CAAI,OAA2C;IAC1E,OAAO,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export declare const Receipt: Schema.encodeKeys<Schema.Struct<{
|
|
3
|
+
readonly deliveryId: Schema.String;
|
|
4
|
+
readonly event: Schema.String;
|
|
5
|
+
readonly jobIds: Schema.$Array<Schema.String>;
|
|
6
|
+
readonly outcome: Schema.Literals<readonly ["queued", "ignored"]>;
|
|
7
|
+
readonly receivedAt: Schema.Date;
|
|
8
|
+
readonly source: Schema.String;
|
|
9
|
+
}>, {
|
|
10
|
+
readonly deliveryId: "delivery_id";
|
|
11
|
+
readonly jobIds: "job_ids";
|
|
12
|
+
readonly receivedAt: "received_at";
|
|
13
|
+
}>;
|
|
14
|
+
//# sourceMappingURL=Receipt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Receipt.d.ts","sourceRoot":"","sources":["../../../src/server/internal/Receipt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,eAAO,MAAM,OAAO;;;;;;;;;;;EAOmF,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export const Receipt = Schema.Struct({
|
|
3
|
+
deliveryId: Schema.String,
|
|
4
|
+
event: Schema.String,
|
|
5
|
+
jobIds: Schema.Array(Schema.String),
|
|
6
|
+
outcome: Schema.Literals(["queued", "ignored"]),
|
|
7
|
+
receivedAt: Schema.Date,
|
|
8
|
+
source: Schema.String,
|
|
9
|
+
}).pipe(Schema.encodeKeys({ deliveryId: "delivery_id", jobIds: "job_ids", receivedAt: "received_at" }));
|
|
10
|
+
//# sourceMappingURL=Receipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Receipt.js","sourceRoot":"","sources":["../../../src/server/internal/Receipt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM;IACzB,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC,IAAI;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM;CACrB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receiptMigrations.d.ts","sourceRoot":"","sources":["../../../src/server/internal/receiptMigrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,eAAO,MAAM,iBAAiB;aAC7B,MAAM;aAIN,WAAW,EAAE,WAAW;aACxB,KAAK,EAAE,6BAA6B;CAC3B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Migrator } from "effect/sql";
|
|
2
|
+
import createReceipts from "#server/migrations/0001_create_receipts.ts";
|
|
3
|
+
import receiptJobIds from "#server/migrations/0002_receipt_job_ids.ts";
|
|
4
|
+
export const receiptMigrations = {
|
|
5
|
+
loader: Migrator.fromRecord({
|
|
6
|
+
"0001_create_receipts": createReceipts,
|
|
7
|
+
"0002_receipt_job_ids": receiptJobIds,
|
|
8
|
+
}),
|
|
9
|
+
lockTimeout: "5 seconds",
|
|
10
|
+
table: "webhook_receipts_migrations",
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=receiptMigrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receiptMigrations.js","sourceRoot":"","sources":["../../../src/server/internal/receiptMigrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,cAAc,MAAM,4CAA4C,CAAC;AACxE,OAAO,aAAa,MAAM,4CAA4C,CAAC;AAEvE,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAChC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC;QAC3B,sBAAsB,EAAE,cAAc;QACtC,sBAAsB,EAAE,aAAa;KACrC,CAAC;IACF,WAAW,EAAE,WAAW;IACxB,KAAK,EAAE,6BAA6B;CAC3B,CAAC"}
|
|
@@ -2,6 +2,6 @@ import { Effect, type Redacted } from "effect";
|
|
|
2
2
|
import { HttpServerResponse } from "effect/http";
|
|
3
3
|
import { SqlClient } from "effect/sql";
|
|
4
4
|
import type { PgBossService } from "@shivaedev/jobs/server/service.ts";
|
|
5
|
-
import { type WebhookSource } from "#registration.ts";
|
|
5
|
+
import { type WebhookSource } from "#server/registration.ts";
|
|
6
6
|
export declare const receive: <R>(name: string, source: WebhookSource<R>, key: Redacted.Redacted<string>, body: Uint8Array<ArrayBufferLike>, headers: Readonly<Record<string, string>>, jobs: PgBossService) => Effect.Effect<HttpServerResponse.HttpServerResponse, import("@shivaedev/jobs/server/error.ts").PgBossError | import("@shivaedev/jobs/server/error.ts").PgBossPayloadError | import("effect/Schema").SchemaError | import("effect/sql/SqlError").SqlError | import("../WebhookUnauthorized.ts").WebhookUnauthorized, R | SqlClient.SqlClient>;
|
|
7
7
|
//# sourceMappingURL=receive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receive.d.ts","sourceRoot":"","sources":["../../../src/server/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,yBAAyB,CAAC;AAEjF,eAAO,MAAM,OAAO,GAA4C,CAAC,4fA+B/D,CAAC"}
|
|
@@ -2,8 +2,8 @@ import { Effect, Option } from "effect";
|
|
|
2
2
|
import { HttpServerResponse } from "effect/http";
|
|
3
3
|
import * as HttpStatus from "effect/http/HttpStatus";
|
|
4
4
|
import { SqlClient } from "effect/sql";
|
|
5
|
-
import { enqueueWebhookJobs } from "#registration.ts";
|
|
6
|
-
export const receive = Effect.
|
|
5
|
+
import { enqueueWebhookJobs } from "#server/registration.ts";
|
|
6
|
+
export const receive = Effect.fn("Webhooks.receive")(function* (name, source, key, body, headers, jobs) {
|
|
7
7
|
yield* source.strategy.verify(body, headers, key);
|
|
8
8
|
const { id, event } = source.strategy.delivery(headers);
|
|
9
9
|
if (!(id && event)) {
|
|
@@ -13,14 +13,14 @@ export const receive = Effect.fnUntraced(function* (name, source, key, body, hea
|
|
|
13
13
|
const sql = yield* SqlClient.SqlClient;
|
|
14
14
|
return yield* sql.withTransaction(Effect.gen(function* () {
|
|
15
15
|
const inserted = yield* sql `insert into webhook_receipts (source, delivery_id, event, outcome, job_ids)
|
|
16
|
-
values (${name}, ${id}, ${event}, 'ignored',
|
|
16
|
+
values (${name}, ${id}, ${event}, 'ignored', array[]::text[])
|
|
17
17
|
on conflict (source, delivery_id) do nothing returning delivery_id`;
|
|
18
18
|
if (inserted.length === 0) {
|
|
19
19
|
return HttpServerResponse.text("already queued", { status: HttpStatus.fromLiteral("OK") });
|
|
20
20
|
}
|
|
21
21
|
const requests = definition === undefined ? [] : yield* definition.decode(body);
|
|
22
22
|
const ids = (yield* enqueueWebhookJobs(requests, jobs)).flatMap(Option.toArray);
|
|
23
|
-
yield* sql `update webhook_receipts set job_ids = ${
|
|
23
|
+
yield* sql `update webhook_receipts set job_ids = array[${sql.csv(ids.map((jobId) => sql `${jobId}`))}]::text[], outcome = ${requests.length === 0 ? "ignored" : "queued"} where source = ${name} and delivery_id = ${id}`;
|
|
24
24
|
return HttpServerResponse.text(requests.length === 0 ? "ignored" : "queued", {
|
|
25
25
|
status: requests.length === 0 ? HttpStatus.fromLiteral("OK") : HttpStatus.fromLiteral("Accepted"),
|
|
26
26
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receive.js","sourceRoot":"","sources":["../../../src/server/internal/receive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"0001_create_receipts.d.ts","sourceRoot":"","sources":["../../../src/server/migrations/0001_create_receipts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
export default Effect.gen(function* () {
|
|
4
|
+
const sql = yield* SqlClient.SqlClient;
|
|
5
|
+
yield* sql `create table if not exists webhook_receipts (
|
|
6
|
+
source text not null,
|
|
7
|
+
delivery_id text not null,
|
|
8
|
+
event text not null,
|
|
9
|
+
received_at timestamptz not null default now(),
|
|
10
|
+
outcome text not null check (outcome in ('queued', 'ignored')),
|
|
11
|
+
job_ids jsonb not null,
|
|
12
|
+
primary key (source, delivery_id)
|
|
13
|
+
)`;
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=0001_create_receipts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"0001_create_receipts.js","sourceRoot":"","sources":["../../../src/server/migrations/0001_create_receipts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,eAAe,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,KAAK,CAAC,CAAC,GAAG,CAAA;;;;;;;;GAQR,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"0002_receipt_job_ids.d.ts","sourceRoot":"","sources":["../../../src/server/migrations/0002_receipt_job_ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
export default Effect.gen(function* () {
|
|
4
|
+
const sql = yield* SqlClient.SqlClient;
|
|
5
|
+
yield* sql `alter table webhook_receipts add column job_ids_text text[]`;
|
|
6
|
+
yield* sql `update webhook_receipts set job_ids_text = array(select jsonb_array_elements_text(job_ids))`;
|
|
7
|
+
yield* sql `alter table webhook_receipts alter column job_ids_text set not null`;
|
|
8
|
+
yield* sql `alter table webhook_receipts drop column job_ids`;
|
|
9
|
+
yield* sql `alter table webhook_receipts rename column job_ids_text to job_ids`;
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=0002_receipt_job_ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"0002_receipt_job_ids.js","sourceRoot":"","sources":["../../../src/server/migrations/0002_receipt_job_ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,eAAe,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;IACvC,KAAK,CAAC,CAAC,GAAG,CAAA,6DAA6D,CAAC;IACxE,KAAK,CAAC,CAAC,GAAG,CAAA,6FAA6F,CAAC;IACxG,KAAK,CAAC,CAAC,GAAG,CAAA,qEAAqE,CAAC;IAChF,KAAK,CAAC,CAAC,GAAG,CAAA,kDAAkD,CAAC;IAC7D,KAAK,CAAC,CAAC,GAAG,CAAA,oEAAoE,CAAC;AAChF,CAAC,CAAC,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { type Config, Effect, type Option, type Redacted, Schema } from "effect"
|
|
|
2
2
|
import type { JobPayloadSchema, QueueDefinition } from "@shivaedev/jobs/server/definition.ts";
|
|
3
3
|
import type { PgBossError, PgBossPayloadError } from "@shivaedev/jobs/server/error.ts";
|
|
4
4
|
import type { PgBossService } from "@shivaedev/jobs/server/service.ts";
|
|
5
|
-
import type { WebhookUnauthorized } from "#WebhookUnauthorized.ts";
|
|
5
|
+
import type { WebhookUnauthorized } from "#server/WebhookUnauthorized.ts";
|
|
6
6
|
declare const enqueue: unique symbol;
|
|
7
7
|
export interface WebhookJob<R = never> {
|
|
8
8
|
readonly [enqueue]: (jobs: PgBossService) => Effect.Effect<Option.Option<string>, PgBossError | PgBossPayloadError, R>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/server/registration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAC9F,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAE1E,QAAA,MAAM,OAAO,eAA+B,CAAC;AAE7C,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,KAAK;IACpC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,kBAAkB,EAAE,CAAC,CAAC,CAAC;CACvH;AAED,wBAAgB,UAAU,CAAC,KAAK,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,gBAAgB,EACvF,KAAK,EAAE,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,EACvC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAC5C,UAAU,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAE1C;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,KAAK;IACtC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;CACtG;AAED,wBAAgB,YAAY,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,EAAE,CAAC,GAAG,KAAK,EACxE,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,GAC1D,YAAY,CAAC,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAI/C;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,KAAK;IACvC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAK;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC1I,QAAQ,CAAC,MAAM,EAAE,CAChB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACzC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,KAC1B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;CAC9C;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,+EAE5F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration.js","sourceRoot":"","sources":["../../src/server/registration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,MAAM,EAA8B,MAAM,EAAE,MAAM,QAAQ,CAAC;AAMjF,MAAM,OAAO,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAM7C,MAAM,UAAU,UAAU,CACzB,KAAuC,EACvC,OAA8C;IAE9C,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;AAC9D,CAAC;AAMD,MAAM,UAAU,YAAY,CAC3B,MAAe,EACf,IAA4D;IAE5D,OAAO;QACN,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;KAClI,CAAC;AACH,CAAC;AAiBD,MAAM,UAAU,kBAAkB,CAAI,QAAkC,EAAE,IAAmB;IAC5F,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -2,11 +2,11 @@ import { type Context, Layer } from "effect";
|
|
|
2
2
|
import { HttpRouter } from "effect/http";
|
|
3
3
|
import type { SqlClient } from "effect/sql";
|
|
4
4
|
import type { PgBossService } from "@shivaedev/jobs/server/service.ts";
|
|
5
|
-
import type { WebhookSource } from "#registration.ts";
|
|
5
|
+
import type { WebhookSource } from "#server/registration.ts";
|
|
6
6
|
export interface WebhookRouteOptions<TJobs, R> {
|
|
7
7
|
readonly basePath: `/${string}`;
|
|
8
8
|
readonly jobs: Context.Key<TJobs, PgBossService>;
|
|
9
9
|
readonly sources: Readonly<Record<string, WebhookSource<R>>>;
|
|
10
10
|
}
|
|
11
|
-
export declare function webhookRoute<TJobs, R>(options: WebhookRouteOptions<TJobs, R>): Layer.Layer<never,
|
|
11
|
+
export declare function webhookRoute<TJobs, R>(options: WebhookRouteOptions<TJobs, R>): Layer.Layer<never, import("effect/Config").ConfigError, HttpRouter.HttpRouter | HttpRouter.Request<"Error", unknown> | SqlClient.SqlClient | Exclude<R, import("effect/Scope").Scope> | Exclude<TJobs, import("effect/Scope").Scope>>;
|
|
12
12
|
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/server/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,OAAO,EAAU,KAAK,EAAiB,MAAM,QAAQ,CAAC;AAC3E,OAAO,EAAE,UAAU,EAA6C,MAAM,aAAa,CAAC;AAEpF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,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,yOAuC5E"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Effect, Layer } from "effect";
|
|
2
|
-
import { HttpRouter, HttpServerResponse } from "effect/http";
|
|
1
|
+
import { Cause, Effect, Layer } from "effect";
|
|
2
|
+
import { HttpRouter, HttpServerRespondable, HttpServerResponse } from "effect/http";
|
|
3
3
|
import * as HttpStatus from "effect/http/HttpStatus";
|
|
4
|
+
import { redactDiagnosticCause } from "@shivaedev/errors/redactCause.ts";
|
|
4
5
|
import { readBoundedBody } from "@shivaedev/http/server/boundedBody.ts";
|
|
5
|
-
import { receive } from "#internal/receive.ts";
|
|
6
|
+
import { receive } from "#server/internal/receive.ts";
|
|
6
7
|
export function webhookRoute(options) {
|
|
7
8
|
return Layer.unwrap(Effect.gen(function* () {
|
|
8
9
|
const context = yield* Effect.context();
|
|
@@ -21,7 +22,12 @@ export function webhookRoute(options) {
|
|
|
21
22
|
}
|
|
22
23
|
const body = new Uint8Array(yield* readBoundedBody(request));
|
|
23
24
|
return yield* receive(name, source, key, body, request.headers, jobs).pipe(Effect.provideContext(context));
|
|
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(() =>
|
|
25
|
-
|
|
25
|
+
}).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((error) => {
|
|
26
|
+
const response = HttpServerResponse.empty({ status: HttpStatus.fromLiteral("ServiceUnavailable") });
|
|
27
|
+
// Preserve the failure for HTTP tracing without attaching the request's credentials to a synthetic 503 error.
|
|
28
|
+
const cause = redactDiagnosticCause(Cause.fail(Object.assign(error, { [HttpServerRespondable.symbol]: () => Effect.succeed(response) })));
|
|
29
|
+
return Effect.logError("Webhook receipt failed", cause).pipe(Effect.annotateLogs({ errorTag: error._tag }), Effect.andThen(Effect.failCause(cause)));
|
|
30
|
+
})));
|
|
31
|
+
}));
|
|
26
32
|
}
|
|
27
33
|
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/server/route.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhookReceipts.d.ts","sourceRoot":"","sources":["../../src/server/webhookReceipts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAGzE,eAAO,MAAM,eAAe,EAAE,eAY7B,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
import { migratePostgres } from "@shivaedev/sql/migrations.ts";
|
|
4
|
+
import { pendingPostgresMigrations } from "@shivaedev/sql/pendingPostgresMigrations.ts";
|
|
5
|
+
import { receiptMigrations } from "#server/internal/receiptMigrations.ts";
|
|
6
|
+
export const webhookReceipts = {
|
|
7
|
+
apply: migratePostgres(receiptMigrations),
|
|
8
|
+
name: "webhook-receipts",
|
|
9
|
+
pending: Effect.gen(function* () {
|
|
10
|
+
const sql = yield* SqlClient.SqlClient;
|
|
11
|
+
const [row] = yield* sql `select to_regclass('webhook_receipts')::text as name`;
|
|
12
|
+
if (row === undefined || row.name === null) {
|
|
13
|
+
return "webhook_receipts is missing";
|
|
14
|
+
}
|
|
15
|
+
const { migrations } = yield* pendingPostgresMigrations(receiptMigrations);
|
|
16
|
+
return migrations.length === 0 ? undefined : `pending receipt migrations: ${migrations.map(({ name }) => name).join(", ")}`;
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=webhookReceipts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhookReceipts.js","sourceRoot":"","sources":["../../src/server/webhookReceipts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAExF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE1E,MAAM,CAAC,MAAM,eAAe,GAAoB;IAC/C,KAAK,EAAE,eAAe,CAAC,iBAAiB,CAAC;IACzC,IAAI,EAAE,kBAAkB;IACxB,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC5B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAyB,sDAAsD,CAAC;QACxG,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAC5C,OAAO,6BAA6B,CAAC;QACtC,CAAC;QACD,MAAM,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC,CAAC,yBAAyB,CAAC,iBAAiB,CAAC,CAAC;QAC3E,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,+BAA+B,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC7H,CAAC,CAAC;CACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/webhooks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Verified webhook receipts and transactional job delivery over Effect HTTP",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect"
|
|
@@ -31,8 +31,7 @@
|
|
|
31
31
|
"types": "./dist/*.d.ts",
|
|
32
32
|
"default": "./dist/*.js"
|
|
33
33
|
},
|
|
34
|
-
"./package.json": "./package.json"
|
|
35
|
-
"./internal/*": null
|
|
34
|
+
"./package.json": "./package.json"
|
|
36
35
|
},
|
|
37
36
|
"files": [
|
|
38
37
|
"dist",
|
|
@@ -45,17 +44,18 @@
|
|
|
45
44
|
"README.md"
|
|
46
45
|
],
|
|
47
46
|
"dependencies": {
|
|
48
|
-
"@shivaedev/
|
|
49
|
-
"@shivaedev/
|
|
50
|
-
"@shivaedev/
|
|
51
|
-
"@shivaedev/
|
|
47
|
+
"@shivaedev/errors": "0.1.2",
|
|
48
|
+
"@shivaedev/github": "0.8.0",
|
|
49
|
+
"@shivaedev/http": "0.3.0",
|
|
50
|
+
"@shivaedev/jobs": "0.23.0",
|
|
51
|
+
"@shivaedev/sql": "0.26.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@effect/platform-node": "4.0.6",
|
|
55
|
-
"@shivaedev/quality": "0.
|
|
56
|
-
"@shivaedev/server": "0.
|
|
57
|
-
"@shivaedev/test-sql": "0.
|
|
58
|
-
"@shivaedev/test-story": "0.
|
|
55
|
+
"@shivaedev/quality": "0.46.0",
|
|
56
|
+
"@shivaedev/server": "0.6.0",
|
|
57
|
+
"@shivaedev/test-sql": "0.12.0",
|
|
58
|
+
"@shivaedev/test-story": "0.25.0",
|
|
59
59
|
"@types/node": "24.19.2",
|
|
60
60
|
"effect": "4.0.6",
|
|
61
61
|
"pg-boss": "12.38.0",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { verifyWebhook } from "@shivaedev/github/verifyWebhook.ts";
|
|
3
|
-
import type { WebhookSource, WebhookStrategy } from "#registration.ts";
|
|
4
|
-
import { WebhookUnauthorized } from "#WebhookUnauthorized.ts";
|
|
3
|
+
import type { WebhookSource, WebhookStrategy } from "#server/registration.ts";
|
|
4
|
+
import { WebhookUnauthorized } from "#server/WebhookUnauthorized.ts";
|
|
5
5
|
|
|
6
6
|
export const githubStrategy: WebhookStrategy = {
|
|
7
7
|
delivery: (headers) => ({ event: headers["x-github-event"], id: headers["x-github-delivery"] }),
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
export const Receipt = Schema.Struct({
|
|
4
|
+
deliveryId: Schema.String,
|
|
5
|
+
event: Schema.String,
|
|
6
|
+
jobIds: Schema.Array(Schema.String),
|
|
7
|
+
outcome: Schema.Literals(["queued", "ignored"]),
|
|
8
|
+
receivedAt: Schema.Date,
|
|
9
|
+
source: Schema.String,
|
|
10
|
+
}).pipe(Schema.encodeKeys({ deliveryId: "delivery_id", jobIds: "job_ids", receivedAt: "received_at" }));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Migrator } from "effect/sql";
|
|
2
|
+
import createReceipts from "#server/migrations/0001_create_receipts.ts";
|
|
3
|
+
import receiptJobIds from "#server/migrations/0002_receipt_job_ids.ts";
|
|
4
|
+
|
|
5
|
+
export const receiptMigrations = {
|
|
6
|
+
loader: Migrator.fromRecord({
|
|
7
|
+
"0001_create_receipts": createReceipts,
|
|
8
|
+
"0002_receipt_job_ids": receiptJobIds,
|
|
9
|
+
}),
|
|
10
|
+
lockTimeout: "5 seconds",
|
|
11
|
+
table: "webhook_receipts_migrations",
|
|
12
|
+
} as const;
|
|
@@ -3,9 +3,9 @@ import { HttpServerResponse } from "effect/http";
|
|
|
3
3
|
import * as HttpStatus from "effect/http/HttpStatus";
|
|
4
4
|
import { SqlClient } from "effect/sql";
|
|
5
5
|
import type { PgBossService } from "@shivaedev/jobs/server/service.ts";
|
|
6
|
-
import { enqueueWebhookJobs, type WebhookSource } from "#registration.ts";
|
|
6
|
+
import { enqueueWebhookJobs, type WebhookSource } from "#server/registration.ts";
|
|
7
7
|
|
|
8
|
-
export const receive = Effect.
|
|
8
|
+
export const receive = Effect.fn("Webhooks.receive")(function* <R>(
|
|
9
9
|
name: string,
|
|
10
10
|
source: WebhookSource<R>,
|
|
11
11
|
key: Redacted.Redacted<string>,
|
|
@@ -23,14 +23,14 @@ export const receive = Effect.fnUntraced(function* <R>(
|
|
|
23
23
|
return yield* sql.withTransaction(
|
|
24
24
|
Effect.gen(function* () {
|
|
25
25
|
const inserted = yield* sql`insert into webhook_receipts (source, delivery_id, event, outcome, job_ids)
|
|
26
|
-
values (${name}, ${id}, ${event}, 'ignored',
|
|
26
|
+
values (${name}, ${id}, ${event}, 'ignored', array[]::text[])
|
|
27
27
|
on conflict (source, delivery_id) do nothing returning delivery_id`;
|
|
28
28
|
if (inserted.length === 0) {
|
|
29
29
|
return HttpServerResponse.text("already queued", { status: HttpStatus.fromLiteral("OK") });
|
|
30
30
|
}
|
|
31
31
|
const requests = definition === undefined ? [] : yield* definition.decode(body);
|
|
32
32
|
const ids = (yield* enqueueWebhookJobs(requests, jobs)).flatMap(Option.toArray);
|
|
33
|
-
yield* sql`update webhook_receipts set job_ids = ${
|
|
33
|
+
yield* sql`update webhook_receipts set job_ids = array[${sql.csv(ids.map((jobId) => sql`${jobId}`))}]::text[], outcome = ${requests.length === 0 ? "ignored" : "queued"} where source = ${name} and delivery_id = ${id}`;
|
|
34
34
|
return HttpServerResponse.text(requests.length === 0 ? "ignored" : "queued", {
|
|
35
35
|
status: requests.length === 0 ? HttpStatus.fromLiteral("OK") : HttpStatus.fromLiteral("Accepted"),
|
|
36
36
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
|
|
4
|
+
export default Effect.gen(function* () {
|
|
5
|
+
const sql = yield* SqlClient.SqlClient;
|
|
6
|
+
yield* sql`create table if not exists webhook_receipts (
|
|
7
|
+
source text not null,
|
|
8
|
+
delivery_id text not null,
|
|
9
|
+
event text not null,
|
|
10
|
+
received_at timestamptz not null default now(),
|
|
11
|
+
outcome text not null check (outcome in ('queued', 'ignored')),
|
|
12
|
+
job_ids jsonb not null,
|
|
13
|
+
primary key (source, delivery_id)
|
|
14
|
+
)`;
|
|
15
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
|
|
4
|
+
export default Effect.gen(function* () {
|
|
5
|
+
const sql = yield* SqlClient.SqlClient;
|
|
6
|
+
yield* sql`alter table webhook_receipts add column job_ids_text text[]`;
|
|
7
|
+
yield* sql`update webhook_receipts set job_ids_text = array(select jsonb_array_elements_text(job_ids))`;
|
|
8
|
+
yield* sql`alter table webhook_receipts alter column job_ids_text set not null`;
|
|
9
|
+
yield* sql`alter table webhook_receipts drop column job_ids`;
|
|
10
|
+
yield* sql`alter table webhook_receipts rename column job_ids_text to job_ids`;
|
|
11
|
+
});
|
|
@@ -2,7 +2,7 @@ import { type Config, Effect, type Option, type Redacted, Schema } from "effect"
|
|
|
2
2
|
import type { JobPayloadSchema, QueueDefinition } from "@shivaedev/jobs/server/definition.ts";
|
|
3
3
|
import type { PgBossError, PgBossPayloadError } from "@shivaedev/jobs/server/error.ts";
|
|
4
4
|
import type { PgBossService } from "@shivaedev/jobs/server/service.ts";
|
|
5
|
-
import type { WebhookUnauthorized } from "#WebhookUnauthorized.ts";
|
|
5
|
+
import type { WebhookUnauthorized } from "#server/WebhookUnauthorized.ts";
|
|
6
6
|
|
|
7
7
|
const enqueue = Symbol("WebhookJob.enqueue");
|
|
8
8
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { type Context, Effect, Layer, type Redacted } from "effect";
|
|
2
|
-
import { HttpRouter, HttpServerResponse } from "effect/http";
|
|
1
|
+
import { Cause, type Context, Effect, Layer, type Redacted } from "effect";
|
|
2
|
+
import { HttpRouter, HttpServerRespondable, HttpServerResponse } from "effect/http";
|
|
3
3
|
import * as HttpStatus from "effect/http/HttpStatus";
|
|
4
4
|
import type { SqlClient } from "effect/sql";
|
|
5
|
+
import { redactDiagnosticCause } from "@shivaedev/errors/redactCause.ts";
|
|
5
6
|
import { readBoundedBody } from "@shivaedev/http/server/boundedBody.ts";
|
|
6
7
|
import type { PgBossService } from "@shivaedev/jobs/server/service.ts";
|
|
7
|
-
import { receive } from "#internal/receive.ts";
|
|
8
|
-
import type { WebhookSource } from "#registration.ts";
|
|
8
|
+
import { receive } from "#server/internal/receive.ts";
|
|
9
|
+
import type { WebhookSource } from "#server/registration.ts";
|
|
9
10
|
|
|
10
11
|
export interface WebhookRouteOptions<TJobs, R> {
|
|
11
12
|
readonly basePath: `/${string}`;
|
|
@@ -39,9 +40,17 @@ export function webhookRoute<TJobs, R>(options: WebhookRouteOptions<TJobs, R>) {
|
|
|
39
40
|
),
|
|
40
41
|
Effect.catchTag("WebhookUnauthorized", () => Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("Unauthorized") }))),
|
|
41
42
|
Effect.catchTag("SchemaError", () => Effect.succeed(HttpServerResponse.empty({ status: HttpStatus.fromLiteral("BadRequest") }))),
|
|
42
|
-
Effect.catch(() =>
|
|
43
|
+
Effect.catch((error) => {
|
|
44
|
+
const response = HttpServerResponse.empty({ status: HttpStatus.fromLiteral("ServiceUnavailable") });
|
|
45
|
+
// Preserve the failure for HTTP tracing without attaching the request's credentials to a synthetic 503 error.
|
|
46
|
+
const cause = redactDiagnosticCause(Cause.fail(Object.assign(error, { [HttpServerRespondable.symbol]: () => Effect.succeed(response) })));
|
|
47
|
+
return Effect.logError("Webhook receipt failed", cause).pipe(
|
|
48
|
+
Effect.annotateLogs({ errorTag: error._tag }),
|
|
49
|
+
Effect.andThen(Effect.failCause(cause)),
|
|
50
|
+
);
|
|
51
|
+
}),
|
|
43
52
|
),
|
|
44
53
|
);
|
|
45
|
-
})
|
|
54
|
+
}),
|
|
46
55
|
);
|
|
47
56
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
import { migratePostgres } from "@shivaedev/sql/migrations.ts";
|
|
4
|
+
import { pendingPostgresMigrations } from "@shivaedev/sql/pendingPostgresMigrations.ts";
|
|
5
|
+
import type { SchemaComponent } from "@shivaedev/sql/SchemaComponent.ts";
|
|
6
|
+
import { receiptMigrations } from "#server/internal/receiptMigrations.ts";
|
|
7
|
+
|
|
8
|
+
export const webhookReceipts: SchemaComponent = {
|
|
9
|
+
apply: migratePostgres(receiptMigrations),
|
|
10
|
+
name: "webhook-receipts",
|
|
11
|
+
pending: Effect.gen(function* () {
|
|
12
|
+
const sql = yield* SqlClient.SqlClient;
|
|
13
|
+
const [row] = yield* sql<{ name: string | null }>`select to_regclass('webhook_receipts')::text as name`;
|
|
14
|
+
if (row === undefined || row.name === null) {
|
|
15
|
+
return "webhook_receipts is missing";
|
|
16
|
+
}
|
|
17
|
+
const { migrations } = yield* pendingPostgresMigrations(receiptMigrations);
|
|
18
|
+
return migrations.length === 0 ? undefined : `pending receipt migrations: ${migrations.map(({ name }) => name).join(", ")}`;
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WebhookUnauthorized.d.ts","sourceRoot":"","sources":["../src/WebhookUnauthorized.ts"],"names":[],"mappings":";;;AAEA,qBAAa,mBAAoB,SAAQ,wBAAuC;CAAG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WebhookUnauthorized.js","sourceRoot":"","sources":["../src/WebhookUnauthorized.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,MAAM,OAAO,mBAAoB,SAAQ,IAAI,CAAC,WAAW,CAAC,qBAAqB,CAAC;CAAG"}
|
package/dist/github.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGvE,eAAO,MAAM,cAAc,EAAE,eAG5B,CAAC;AAEF,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAE7F"}
|
package/dist/github.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,CAAC,MAAM,cAAc,GAAoB;IAC9C,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,mBAAmB,CAAC,EAAE,CAAC;IAC/F,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,qBAAqB,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE,CAAC,CAAC;CAC/I,CAAC;AAEF,MAAM,UAAU,YAAY,CAAI,OAA2C;IAC1E,OAAO,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AACjD,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../src/registration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAC9F,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,QAAA,MAAM,OAAO,eAA+B,CAAC;AAE7C,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,KAAK;IACpC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,kBAAkB,EAAE,CAAC,CAAC,CAAC;CACvH;AAED,wBAAgB,UAAU,CAAC,KAAK,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,gBAAgB,EACvF,KAAK,EAAE,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,EACvC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAC5C,UAAU,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAE1C;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,KAAK;IACtC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;CACtG;AAED,wBAAgB,YAAY,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,EAAE,CAAC,GAAG,KAAK,EACxE,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,GAC1D,YAAY,CAAC,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAI/C;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,KAAK;IACvC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAK;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC1I,QAAQ,CAAC,MAAM,EAAE,CAChB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACzC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,KAC1B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;CAC9C;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,+EAE5F"}
|
package/dist/registration.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registration.js","sourceRoot":"","sources":["../src/registration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,MAAM,EAA8B,MAAM,EAAE,MAAM,QAAQ,CAAC;AAMjF,MAAM,OAAO,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAM7C,MAAM,UAAU,UAAU,CACzB,KAAuC,EACvC,OAA8C;IAE9C,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;AAC9D,CAAC;AAMD,MAAM,UAAU,YAAY,CAC3B,MAAe,EACf,IAA4D;IAE5D,OAAO;QACN,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;KAClI,CAAC;AACH,CAAC;AAiBD,MAAM,UAAU,kBAAkB,CAAI,QAAkC,EAAE,IAAmB;IAC5F,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACtE,CAAC"}
|
package/dist/route.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhookReceipts.d.ts","sourceRoot":"","sources":["../src/webhookReceipts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAEzE,eAAO,MAAM,eAAe,EAAE,eAmB7B,CAAC"}
|
package/dist/webhookReceipts.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
2
|
-
import { SqlClient } from "effect/sql";
|
|
3
|
-
export const webhookReceipts = {
|
|
4
|
-
apply: Effect.gen(function* () {
|
|
5
|
-
const sql = yield* SqlClient.SqlClient;
|
|
6
|
-
yield* sql `create table if not exists webhook_receipts (
|
|
7
|
-
source text not null,
|
|
8
|
-
delivery_id text not null,
|
|
9
|
-
event text not null,
|
|
10
|
-
received_at timestamptz not null default now(),
|
|
11
|
-
outcome text not null check (outcome in ('queued', 'ignored')),
|
|
12
|
-
job_ids jsonb not null,
|
|
13
|
-
primary key (source, delivery_id)
|
|
14
|
-
)`;
|
|
15
|
-
}),
|
|
16
|
-
name: "webhook-receipts",
|
|
17
|
-
pending: Effect.gen(function* () {
|
|
18
|
-
const sql = yield* SqlClient.SqlClient;
|
|
19
|
-
const [row] = yield* sql `select to_regclass('webhook_receipts')::text as name`;
|
|
20
|
-
return row === undefined || row.name === null ? "webhook_receipts is missing" : undefined;
|
|
21
|
-
}),
|
|
22
|
-
};
|
|
23
|
-
//# sourceMappingURL=webhookReceipts.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhookReceipts.js","sourceRoot":"","sources":["../src/webhookReceipts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,MAAM,CAAC,MAAM,eAAe,GAAoB;IAC/C,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;QACvC,KAAK,CAAC,CAAC,GAAG,CAAA;;;;;;;;IAQR,CAAC;IACJ,CAAC,CAAC;IACF,IAAI,EAAE,kBAAkB;IACxB,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC5B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAyB,sDAAsD,CAAC;QACxG,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3F,CAAC,CAAC;CACF,CAAC"}
|
package/src/webhookReceipts.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
2
|
-
import { SqlClient } from "effect/sql";
|
|
3
|
-
import type { SchemaComponent } from "@shivaedev/sql/SchemaComponent.ts";
|
|
4
|
-
|
|
5
|
-
export const webhookReceipts: SchemaComponent = {
|
|
6
|
-
apply: Effect.gen(function* () {
|
|
7
|
-
const sql = yield* SqlClient.SqlClient;
|
|
8
|
-
yield* sql`create table if not exists webhook_receipts (
|
|
9
|
-
source text not null,
|
|
10
|
-
delivery_id text not null,
|
|
11
|
-
event text not null,
|
|
12
|
-
received_at timestamptz not null default now(),
|
|
13
|
-
outcome text not null check (outcome in ('queued', 'ignored')),
|
|
14
|
-
job_ids jsonb not null,
|
|
15
|
-
primary key (source, delivery_id)
|
|
16
|
-
)`;
|
|
17
|
-
}),
|
|
18
|
-
name: "webhook-receipts",
|
|
19
|
-
pending: Effect.gen(function* () {
|
|
20
|
-
const sql = yield* SqlClient.SqlClient;
|
|
21
|
-
const [row] = yield* sql<{ name: string | null }>`select to_regclass('webhook_receipts')::text as name`;
|
|
22
|
-
return row === undefined || row.name === null ? "webhook_receipts is missing" : undefined;
|
|
23
|
-
}),
|
|
24
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|