Skip to content

Commit 7befdf1

Browse files
committed
feat(paykit): add webhook listen workflow
1 parent 14edca7 commit 7befdf1

26 files changed

Lines changed: 2320 additions & 19 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,6 @@ yarn-error.log*
3939
.DS_Store
4040
*.pem
4141
.env*.local
42+
.dev.vars
43+
.wrangler/
4244
.gstack/

apps/demo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"push:sandbox": "bun scripts/push-sandbox.ts",
1717
"start": "next start",
1818
"tunnel": "set -a; [ -f .env ] && . ./.env; set +a; if [ -n \"$CF_TUNNEL_ID\" ]; then cloudflared tunnel --url http://localhost:3000 run \"$CF_TUNNEL_ID\"; fi",
19-
"paykitjs": "tsx --conditions=paykit-source ../../packages/paykit/src/cli/index.ts",
19+
"paykitjs": "bun ../../packages/paykit/src/cli/index.ts",
2020
"typecheck": "tsc --noEmit",
2121
"push": "bun push:auth && bun push:paykit:polar && bun push:paykit:stripe && bun push:autumn",
2222
"push:auth": "bunx auth migrate --config src/lib/auth.ts --yes",

apps/wh/drizzle.config.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import fs from "node:fs";
2+
import path from "node:path";
3+
4+
import { defineConfig } from "drizzle-kit";
5+
6+
const d1StateDir = path.resolve(process.cwd(), ".wrangler/state/v3/d1/miniflare-D1DatabaseObject");
7+
8+
function resolveLocalSqliteFile(): string {
9+
const files = fs
10+
.readdirSync(d1StateDir)
11+
.filter((file) => file.endsWith(".sqlite") && file !== "metadata.sqlite")
12+
.toSorted();
13+
14+
const file = files[0];
15+
if (!file) {
16+
throw new Error(
17+
"No local D1 SQLite database found. Run `bun --filter wh db:migrate:local` first.",
18+
);
19+
}
20+
21+
return path.join(d1StateDir, file);
22+
}
23+
24+
export default defineConfig({
25+
dialect: "sqlite",
26+
out: "./migrations",
27+
schema: "./src/db/schema.ts",
28+
dbCredentials: {
29+
url: resolveLocalSqliteFile(),
30+
},
31+
});

apps/wh/migrations/0000_init.sql

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
CREATE TABLE `tunnel` (
2+
`id` text PRIMARY KEY NOT NULL,
3+
`device_token_hash` text NOT NULL,
4+
`provider_id` text NOT NULL,
5+
`environment` text NOT NULL,
6+
`provider_account_id` text NOT NULL,
7+
`provider_webhook_endpoint_id` text,
8+
`status` text NOT NULL DEFAULT 'active',
9+
`created_at` integer NOT NULL,
10+
`updated_at` integer NOT NULL,
11+
`last_seen_at` integer NOT NULL,
12+
`disabled_at` integer
13+
);
14+
15+
CREATE UNIQUE INDEX `tunnel_device_provider_unique`
16+
ON `tunnel` (`device_token_hash`, `provider_id`, `environment`, `provider_account_id`);
17+
18+
CREATE INDEX `tunnel_device_idx` ON `tunnel` (`device_token_hash`);
19+
20+
CREATE TABLE `delivery` (
21+
`id` text PRIMARY KEY NOT NULL,
22+
`tunnel_id` text NOT NULL,
23+
`method` text NOT NULL,
24+
`headers` text NOT NULL,
25+
`body` text NOT NULL,
26+
`status` text NOT NULL DEFAULT 'pending',
27+
`received_at` integer NOT NULL,
28+
`delivered_at` integer,
29+
FOREIGN KEY (`tunnel_id`) REFERENCES `tunnel`(`id`) ON DELETE cascade
30+
);
31+
32+
CREATE INDEX `delivery_tunnel_status_received_idx`
33+
ON `delivery` (`tunnel_id`, `status`, `received_at`);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
DROP INDEX `delivery_tunnel_status_received_idx`;--> statement-breakpoint
2+
ALTER TABLE `delivery` ADD `failed_at` integer;--> statement-breakpoint
3+
ALTER TABLE `delivery` ADD `error` text;--> statement-breakpoint
4+
CREATE INDEX `delivery_tunnel_delivery_idx` ON `delivery` (`tunnel_id`,`delivered_at`,`failed_at`,`received_at`);--> statement-breakpoint
5+
ALTER TABLE `delivery` DROP COLUMN `status`;
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
{
2+
"version": "6",
3+
"dialect": "sqlite",
4+
"id": "09df25c0-d0eb-49e5-8c78-c5cac3323bd4",
5+
"prevId": "00000000-0000-0000-0000-000000000000",
6+
"tables": {
7+
"delivery": {
8+
"name": "delivery",
9+
"columns": {
10+
"id": {
11+
"name": "id",
12+
"type": "text",
13+
"primaryKey": true,
14+
"notNull": true,
15+
"autoincrement": false
16+
},
17+
"tunnel_id": {
18+
"name": "tunnel_id",
19+
"type": "text",
20+
"primaryKey": false,
21+
"notNull": true,
22+
"autoincrement": false
23+
},
24+
"method": {
25+
"name": "method",
26+
"type": "text",
27+
"primaryKey": false,
28+
"notNull": true,
29+
"autoincrement": false
30+
},
31+
"headers": {
32+
"name": "headers",
33+
"type": "text",
34+
"primaryKey": false,
35+
"notNull": true,
36+
"autoincrement": false
37+
},
38+
"body": {
39+
"name": "body",
40+
"type": "text",
41+
"primaryKey": false,
42+
"notNull": true,
43+
"autoincrement": false
44+
},
45+
"status": {
46+
"name": "status",
47+
"type": "text",
48+
"primaryKey": false,
49+
"notNull": true,
50+
"autoincrement": false,
51+
"default": "'pending'"
52+
},
53+
"received_at": {
54+
"name": "received_at",
55+
"type": "integer",
56+
"primaryKey": false,
57+
"notNull": true,
58+
"autoincrement": false
59+
},
60+
"delivered_at": {
61+
"name": "delivered_at",
62+
"type": "integer",
63+
"primaryKey": false,
64+
"notNull": false,
65+
"autoincrement": false
66+
}
67+
},
68+
"indexes": {
69+
"delivery_tunnel_status_received_idx": {
70+
"name": "delivery_tunnel_status_received_idx",
71+
"columns": [
72+
"tunnel_id",
73+
"status",
74+
"received_at"
75+
],
76+
"isUnique": false
77+
}
78+
},
79+
"foreignKeys": {
80+
"delivery_tunnel_id_tunnel_id_fk": {
81+
"name": "delivery_tunnel_id_tunnel_id_fk",
82+
"tableFrom": "delivery",
83+
"tableTo": "tunnel",
84+
"columnsFrom": [
85+
"tunnel_id"
86+
],
87+
"columnsTo": [
88+
"id"
89+
],
90+
"onDelete": "cascade",
91+
"onUpdate": "no action"
92+
}
93+
},
94+
"compositePrimaryKeys": {},
95+
"uniqueConstraints": {},
96+
"checkConstraints": {}
97+
},
98+
"tunnel": {
99+
"name": "tunnel",
100+
"columns": {
101+
"id": {
102+
"name": "id",
103+
"type": "text",
104+
"primaryKey": true,
105+
"notNull": true,
106+
"autoincrement": false
107+
},
108+
"device_token_hash": {
109+
"name": "device_token_hash",
110+
"type": "text",
111+
"primaryKey": false,
112+
"notNull": true,
113+
"autoincrement": false
114+
},
115+
"provider_id": {
116+
"name": "provider_id",
117+
"type": "text",
118+
"primaryKey": false,
119+
"notNull": true,
120+
"autoincrement": false
121+
},
122+
"environment": {
123+
"name": "environment",
124+
"type": "text",
125+
"primaryKey": false,
126+
"notNull": true,
127+
"autoincrement": false
128+
},
129+
"provider_account_id": {
130+
"name": "provider_account_id",
131+
"type": "text",
132+
"primaryKey": false,
133+
"notNull": true,
134+
"autoincrement": false
135+
},
136+
"provider_webhook_endpoint_id": {
137+
"name": "provider_webhook_endpoint_id",
138+
"type": "text",
139+
"primaryKey": false,
140+
"notNull": false,
141+
"autoincrement": false
142+
},
143+
"status": {
144+
"name": "status",
145+
"type": "text",
146+
"primaryKey": false,
147+
"notNull": true,
148+
"autoincrement": false,
149+
"default": "'active'"
150+
},
151+
"created_at": {
152+
"name": "created_at",
153+
"type": "integer",
154+
"primaryKey": false,
155+
"notNull": true,
156+
"autoincrement": false
157+
},
158+
"updated_at": {
159+
"name": "updated_at",
160+
"type": "integer",
161+
"primaryKey": false,
162+
"notNull": true,
163+
"autoincrement": false
164+
},
165+
"last_seen_at": {
166+
"name": "last_seen_at",
167+
"type": "integer",
168+
"primaryKey": false,
169+
"notNull": true,
170+
"autoincrement": false
171+
},
172+
"disabled_at": {
173+
"name": "disabled_at",
174+
"type": "integer",
175+
"primaryKey": false,
176+
"notNull": false,
177+
"autoincrement": false
178+
}
179+
},
180+
"indexes": {
181+
"tunnel_device_provider_unique": {
182+
"name": "tunnel_device_provider_unique",
183+
"columns": [
184+
"device_token_hash",
185+
"provider_id",
186+
"environment",
187+
"provider_account_id"
188+
],
189+
"isUnique": true
190+
},
191+
"tunnel_device_idx": {
192+
"name": "tunnel_device_idx",
193+
"columns": [
194+
"device_token_hash"
195+
],
196+
"isUnique": false
197+
}
198+
},
199+
"foreignKeys": {},
200+
"compositePrimaryKeys": {},
201+
"uniqueConstraints": {},
202+
"checkConstraints": {}
203+
}
204+
},
205+
"views": {},
206+
"enums": {},
207+
"_meta": {
208+
"schemas": {},
209+
"tables": {},
210+
"columns": {}
211+
},
212+
"internal": {
213+
"indexes": {}
214+
}
215+
}

0 commit comments

Comments
 (0)