@abdssamie/convex-checkpoints 0.1.1 → 0.1.2
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 +28 -10
- package/dist/client/index.d.ts +5 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +23 -2
- package/dist/client/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/index.ts +32 -2
package/README.md
CHANGED
|
@@ -54,6 +54,10 @@ checkpoints.on("user.signup", async (ctx, payload) => {
|
|
|
54
54
|
Actions are not database transactions, so design retries and idempotency
|
|
55
55
|
explicitly when external systems are involved.
|
|
56
56
|
|
|
57
|
+
The registry gives you typed checkpoint names and payloads while writing
|
|
58
|
+
handlers and submit calls. Your exported Convex functions are still the runtime
|
|
59
|
+
boundary where you validate input and enforce permissions.
|
|
60
|
+
|
|
57
61
|
```ts
|
|
58
62
|
// convex/checkpoints.ts
|
|
59
63
|
import { components, internal } from "./_generated/api.js";
|
|
@@ -144,34 +148,48 @@ checkpoint ID and skip handler re-execution.
|
|
|
144
148
|
|
|
145
149
|
## HTTP
|
|
146
150
|
|
|
147
|
-
|
|
151
|
+
Prefer mutation wrappers for app-driven checkpoints. They run inside your app's
|
|
152
|
+
Convex functions, so you can authenticate the user, validate the input, write
|
|
153
|
+
app data, and submit the checkpoint in one place.
|
|
154
|
+
|
|
155
|
+
HTTP ingestion is for server-to-server entry points such as webhooks or trusted
|
|
156
|
+
backend jobs. Treat it as a public endpoint: anyone who can reach the URL can
|
|
157
|
+
try to submit a checkpoint unless you verify the request.
|
|
148
158
|
|
|
149
159
|
```ts
|
|
150
160
|
// convex/http.ts
|
|
151
161
|
import { checkpoints } from "./checkpoints.js";
|
|
152
162
|
|
|
153
|
-
export default checkpoints.http("/checkpoints"
|
|
163
|
+
export default checkpoints.http("/checkpoints", {
|
|
164
|
+
token: process.env.CHECKPOINTS_SECRET,
|
|
165
|
+
});
|
|
154
166
|
```
|
|
155
167
|
|
|
168
|
+
Requests must include `Authorization: Bearer <token>`. Keep
|
|
169
|
+
`CHECKPOINTS_SECRET` in server-side environment variables only. If the token
|
|
170
|
+
option is configured but the environment variable is missing or empty, HTTP
|
|
171
|
+
checkpoint submissions are rejected.
|
|
172
|
+
|
|
156
173
|
This registers both `POST /checkpoints` and checkpoint-specific routes such as
|
|
157
174
|
`POST /checkpoints/post.created`.
|
|
158
175
|
|
|
159
|
-
For checkpoint-specific routes, the
|
|
160
|
-
payload:
|
|
176
|
+
For checkpoint-specific routes, the route selects the checkpoint name and the
|
|
177
|
+
request body becomes the payload:
|
|
161
178
|
|
|
162
179
|
```sh
|
|
163
180
|
curl -X POST "$CONVEX_SITE_URL/checkpoints/post.created" \
|
|
164
181
|
-H "Content-Type: application/json" \
|
|
182
|
+
-H "Authorization: Bearer $CHECKPOINTS_SECRET" \
|
|
165
183
|
-d '{"userId":"user1","postId":"post1"}'
|
|
166
184
|
```
|
|
167
185
|
|
|
168
|
-
|
|
169
|
-
|
|
186
|
+
For webhook providers, verify the provider's signature in `authorize`. The
|
|
187
|
+
request is cloned before authorization runs, so signature checks can read the
|
|
188
|
+
body without preventing checkpoint parsing afterward.
|
|
170
189
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
validators because TypeScript types are not available at runtime.
|
|
190
|
+
Do not put a checkpoint HTTP secret in browser code. If a user action in your
|
|
191
|
+
app should submit a checkpoint, expose a Convex mutation instead and call
|
|
192
|
+
`checkpoints.submit(ctx, ...)` from that mutation.
|
|
175
193
|
|
|
176
194
|
## Tests
|
|
177
195
|
|
package/dist/client/index.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ type SubmitArgs<TCheckpointRegistry extends CheckpointRegistry, TCheckpoint exte
|
|
|
11
11
|
name: TCheckpoint;
|
|
12
12
|
payload: TCheckpointRegistry[TCheckpoint];
|
|
13
13
|
};
|
|
14
|
+
type HttpOptions = {
|
|
15
|
+
token?: string;
|
|
16
|
+
authorize?: (request: Request) => boolean | Promise<boolean>;
|
|
17
|
+
};
|
|
14
18
|
export declare class ConvexCheckpoints<TCheckpointRegistry extends CheckpointRegistry> extends CheckpointDispatcher<TCheckpointRegistry> {
|
|
15
19
|
private component;
|
|
16
20
|
constructor(component: ComponentApi);
|
|
@@ -55,7 +59,7 @@ export declare class ConvexCheckpoints<TCheckpointRegistry extends CheckpointReg
|
|
|
55
59
|
userId?: string;
|
|
56
60
|
}[]>>;
|
|
57
61
|
};
|
|
58
|
-
http(path?: string): import("convex/server").HttpRouter;
|
|
62
|
+
http(path?: string, options?: HttpOptions): import("convex/server").HttpRouter;
|
|
59
63
|
private submitFromArgs;
|
|
60
64
|
}
|
|
61
65
|
export type { CheckpointHandler };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,EACL,iBAAiB,IAAI,oBAAoB,EACzC,KAAK,iBAAiB,EACvB,MAAM,sCAAsC,CAAC;AAE9C,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAClD,KAAK,cAAc,CAAC,mBAAmB,SAAS,kBAAkB,IAAI,OAAO,CAC3E,MAAM,mBAAmB,EACzB,MAAM,CACP,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAOF,KAAK,UAAU,CACb,mBAAmB,SAAS,kBAAkB,EAC9C,WAAW,SAAS,cAAc,CAAC,mBAAmB,CAAC,IACrD,cAAc,GAAG;IACnB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;CAC3C,CAAC;AAEF,qBAAa,iBAAiB,CAC5B,mBAAmB,SAAS,kBAAkB,CAC9C,SAAQ,oBAAoB,CAAC,mBAAmB,CAAC;IACrC,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,YAAY;IAI9B,MAAM,CAAC,WAAW,SAAS,cAAc,CAAC,mBAAmB,CAAC,EACzE,GAAG,EAAE,UAAU,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACrE,IAAI,EAAE,UAAU,CAAC,mBAAmB,EAAE,WAAW,CAAC;IAS7C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuBH,IAAI,CAAC,IAAI,SAAiB;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,EACL,iBAAiB,IAAI,oBAAoB,EACzC,KAAK,iBAAiB,EACvB,MAAM,sCAAsC,CAAC;AAE9C,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAClD,KAAK,cAAc,CAAC,mBAAmB,SAAS,kBAAkB,IAAI,OAAO,CAC3E,MAAM,mBAAmB,EACzB,MAAM,CACP,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAOF,KAAK,UAAU,CACb,mBAAmB,SAAS,kBAAkB,EAC9C,WAAW,SAAS,cAAc,CAAC,mBAAmB,CAAC,IACrD,cAAc,GAAG;IACnB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;CAC3C,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D,CAAC;AAEF,qBAAa,iBAAiB,CAC5B,mBAAmB,SAAS,kBAAkB,CAC9C,SAAQ,oBAAoB,CAAC,mBAAmB,CAAC;IACrC,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,YAAY;IAI9B,MAAM,CAAC,WAAW,SAAS,cAAc,CAAC,mBAAmB,CAAC,EACzE,GAAG,EAAE,UAAU,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACrE,IAAI,EAAE,UAAU,CAAC,mBAAmB,EAAE,WAAW,CAAC;IAS7C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuBH,IAAI,CAAC,IAAI,SAAiB,EAAE,OAAO,GAAE,WAAgB;YAgE9C,cAAc;CAc7B;AAED,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
|
package/dist/client/index.js
CHANGED
|
@@ -36,12 +36,15 @@ export class ConvexCheckpoints extends CheckpointDispatcher {
|
|
|
36
36
|
}),
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
-
http(path = "/checkpoints") {
|
|
39
|
+
http(path = "/checkpoints", options = {}) {
|
|
40
40
|
const http = httpRouter();
|
|
41
41
|
http.route({
|
|
42
42
|
path,
|
|
43
43
|
method: "POST",
|
|
44
44
|
handler: httpActionGeneric(async (ctx, request) => {
|
|
45
|
+
if (!(await isAuthorized(request, options))) {
|
|
46
|
+
return json({ error: "unauthorized" }, 401);
|
|
47
|
+
}
|
|
45
48
|
const args = await readSubmitArgsFromBody(request);
|
|
46
49
|
if (args === null) {
|
|
47
50
|
return json({ error: "invalid_checkpoint" }, 400);
|
|
@@ -60,6 +63,9 @@ export class ConvexCheckpoints extends CheckpointDispatcher {
|
|
|
60
63
|
pathPrefix,
|
|
61
64
|
method: "POST",
|
|
62
65
|
handler: httpActionGeneric(async (ctx, request) => {
|
|
66
|
+
if (!(await isAuthorized(request, options))) {
|
|
67
|
+
return json({ error: "unauthorized" }, 401);
|
|
68
|
+
}
|
|
63
69
|
const checkpointName = readCheckpointNameFromPath(request, pathPrefix);
|
|
64
70
|
if (checkpointName === null) {
|
|
65
71
|
return json({ error: "invalid_checkpoint_path" }, 400);
|
|
@@ -87,6 +93,21 @@ export class ConvexCheckpoints extends CheckpointDispatcher {
|
|
|
87
93
|
return result;
|
|
88
94
|
}
|
|
89
95
|
}
|
|
96
|
+
async function isAuthorized(request, options) {
|
|
97
|
+
if ("token" in options) {
|
|
98
|
+
if (typeof options.token !== "string" || options.token.length === 0) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const authorization = request.headers.get("authorization");
|
|
102
|
+
if (authorization !== `Bearer ${options.token}`) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (options.authorize === undefined) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
return await options.authorize(request.clone());
|
|
110
|
+
}
|
|
90
111
|
async function readSubmitArgsFromBody(request) {
|
|
91
112
|
const checkpoint = await readJsonObject(request);
|
|
92
113
|
if (checkpoint === null || typeof checkpoint.name !== "string") {
|
|
@@ -171,7 +192,7 @@ function corsHeaders() {
|
|
|
171
192
|
return {
|
|
172
193
|
"Access-Control-Allow-Origin": "*",
|
|
173
194
|
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
174
|
-
"Access-Control-Allow-Headers": "Content-Type",
|
|
195
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
175
196
|
};
|
|
176
197
|
}
|
|
177
198
|
//# sourceMappingURL=index.js.map
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAElC,OAAO,EACL,iBAAiB,IAAI,oBAAoB,GAE1C,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/client/index.ts
CHANGED
|
@@ -31,6 +31,11 @@ type SubmitArgs<
|
|
|
31
31
|
payload: TCheckpointRegistry[TCheckpoint];
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
+
type HttpOptions = {
|
|
35
|
+
token?: string;
|
|
36
|
+
authorize?: (request: Request) => boolean | Promise<boolean>;
|
|
37
|
+
};
|
|
38
|
+
|
|
34
39
|
export class ConvexCheckpoints<
|
|
35
40
|
TCheckpointRegistry extends CheckpointRegistry,
|
|
36
41
|
> extends CheckpointDispatcher<TCheckpointRegistry> {
|
|
@@ -72,12 +77,16 @@ export class ConvexCheckpoints<
|
|
|
72
77
|
};
|
|
73
78
|
}
|
|
74
79
|
|
|
75
|
-
public http(path = "/checkpoints") {
|
|
80
|
+
public http(path = "/checkpoints", options: HttpOptions = {}) {
|
|
76
81
|
const http = httpRouter();
|
|
77
82
|
http.route({
|
|
78
83
|
path,
|
|
79
84
|
method: "POST",
|
|
80
85
|
handler: httpActionGeneric(async (ctx, request) => {
|
|
86
|
+
if (!(await isAuthorized(request, options))) {
|
|
87
|
+
return json({ error: "unauthorized" }, 401);
|
|
88
|
+
}
|
|
89
|
+
|
|
81
90
|
const args = await readSubmitArgsFromBody(request);
|
|
82
91
|
if (args === null) {
|
|
83
92
|
return json({ error: "invalid_checkpoint" }, 400);
|
|
@@ -102,6 +111,10 @@ export class ConvexCheckpoints<
|
|
|
102
111
|
pathPrefix,
|
|
103
112
|
method: "POST",
|
|
104
113
|
handler: httpActionGeneric(async (ctx, request) => {
|
|
114
|
+
if (!(await isAuthorized(request, options))) {
|
|
115
|
+
return json({ error: "unauthorized" }, 401);
|
|
116
|
+
}
|
|
117
|
+
|
|
105
118
|
const checkpointName = readCheckpointNameFromPath(request, pathPrefix);
|
|
106
119
|
if (checkpointName === null) {
|
|
107
120
|
return json({ error: "invalid_checkpoint_path" }, 400);
|
|
@@ -146,6 +159,23 @@ export class ConvexCheckpoints<
|
|
|
146
159
|
|
|
147
160
|
export type { CheckpointHandler };
|
|
148
161
|
|
|
162
|
+
async function isAuthorized(request: Request, options: HttpOptions) {
|
|
163
|
+
if ("token" in options) {
|
|
164
|
+
if (typeof options.token !== "string" || options.token.length === 0) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
const authorization = request.headers.get("authorization");
|
|
168
|
+
if (authorization !== `Bearer ${options.token}`) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (options.authorize === undefined) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
return await options.authorize(request.clone());
|
|
177
|
+
}
|
|
178
|
+
|
|
149
179
|
async function readSubmitArgsFromBody(
|
|
150
180
|
request: Request,
|
|
151
181
|
): Promise<UntypedSubmitArgs | null> {
|
|
@@ -259,6 +289,6 @@ function corsHeaders() {
|
|
|
259
289
|
return {
|
|
260
290
|
"Access-Control-Allow-Origin": "*",
|
|
261
291
|
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
262
|
-
"Access-Control-Allow-Headers": "Content-Type",
|
|
292
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
263
293
|
};
|
|
264
294
|
}
|