two-stroke 7.5.0 → 7.6.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/.github/workflows/dependabot.yml +1 -1
- package/bin/api-types.mjs +3 -11
- package/bin/bulk.mjs +2 -5
- package/bin/lint.mjs +1 -1
- package/bin/test.mjs +2 -7
- package/package.json +4 -4
- package/src/fake.ts +1 -1
- package/src/index.ts +42 -77
- package/src/once.ts +111 -113
- package/src/open-api.ts +49 -59
- package/src/test.ts +18 -22
- package/src/types.ts +4 -18
- package/tsconfig.json +2 -6
- package/worker-configuration.d.ts +10953 -9819
- package/wrangler.jsonc +4 -7
package/src/open-api.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { z, ZodType } from "zod/v4";
|
|
2
|
-
import { type
|
|
2
|
+
import { type Route } from "./types";
|
|
3
3
|
|
|
4
4
|
export const openAPI =
|
|
5
|
-
<T
|
|
6
|
-
title: string,
|
|
7
|
-
release: string,
|
|
8
|
-
noAuth: () => A,
|
|
9
|
-
routes: Route<T, A>[],
|
|
10
|
-
) =>
|
|
5
|
+
<T, A>(title: string, release: string, noAuth: () => A, routes: Route<T, A>[]) =>
|
|
11
6
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
12
7
|
async () => ({
|
|
13
8
|
body: {
|
|
@@ -25,68 +20,63 @@ export const openAPI =
|
|
|
25
20
|
},
|
|
26
21
|
},
|
|
27
22
|
paths: Object.fromEntries(
|
|
28
|
-
Object.entries(Object.groupBy(routes, ({ path }) => path)).map(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
(r.params?.shape ?? {}) as Record<string, ZodType>,
|
|
38
|
-
).map(([k, v]) => ({
|
|
23
|
+
Object.entries(Object.groupBy(routes, ({ path }) => path)).map(([path, rs]) => [
|
|
24
|
+
path,
|
|
25
|
+
Object.fromEntries(
|
|
26
|
+
(rs ?? []).map((r) => [
|
|
27
|
+
r.method.toLocaleLowerCase(),
|
|
28
|
+
{
|
|
29
|
+
parameters: [
|
|
30
|
+
...Object.entries((r.params?.shape ?? {}) as Record<string, ZodType>).map(
|
|
31
|
+
([k, v]) => ({
|
|
39
32
|
name: k,
|
|
40
33
|
in: "query",
|
|
41
34
|
required: !v.safeParse(undefined).success,
|
|
42
35
|
schema: z.toJSONSchema(v, { io: "input" }),
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
36
|
+
}),
|
|
37
|
+
),
|
|
38
|
+
...Array.from(r.path.matchAll(/\/{(?<name>[^}]*)}/g), (match) => ({
|
|
39
|
+
name: match.groups!.name,
|
|
40
|
+
in: "path",
|
|
41
|
+
required: true,
|
|
42
|
+
schema: {
|
|
43
|
+
type: "string",
|
|
44
|
+
},
|
|
45
|
+
})),
|
|
46
|
+
],
|
|
47
|
+
...(r.auth === noAuth ? {} : { security: [{ auth: [] }] }),
|
|
48
|
+
...(r.method === "POST" || r.method === "PUT"
|
|
49
|
+
? {
|
|
50
|
+
requestBody: {
|
|
49
51
|
required: true,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
? {
|
|
59
|
-
requestBody: {
|
|
60
|
-
required: true,
|
|
61
|
-
content: {
|
|
62
|
-
"application/json": r.input
|
|
63
|
-
? {
|
|
64
|
-
schema: z.toJSONSchema(r.input, {
|
|
65
|
-
io: "input",
|
|
66
|
-
}),
|
|
67
|
-
}
|
|
68
|
-
: undefined,
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
}
|
|
72
|
-
: {}),
|
|
73
|
-
responses: {
|
|
74
|
-
"200": {
|
|
75
|
-
description: "OK",
|
|
76
|
-
content: {
|
|
77
|
-
"application/json": {
|
|
78
|
-
schema: z.toJSONSchema(r.output),
|
|
52
|
+
content: {
|
|
53
|
+
"application/json": r.input
|
|
54
|
+
? {
|
|
55
|
+
schema: z.toJSONSchema(r.input, {
|
|
56
|
+
io: "input",
|
|
57
|
+
}),
|
|
58
|
+
}
|
|
59
|
+
: undefined,
|
|
79
60
|
},
|
|
80
61
|
},
|
|
62
|
+
}
|
|
63
|
+
: {}),
|
|
64
|
+
responses: {
|
|
65
|
+
"200": {
|
|
66
|
+
description: "OK",
|
|
67
|
+
content: {
|
|
68
|
+
"application/json": {
|
|
69
|
+
schema: z.toJSONSchema(r.output),
|
|
70
|
+
},
|
|
81
71
|
},
|
|
82
|
-
"400": status400,
|
|
83
|
-
"500": status500,
|
|
84
72
|
},
|
|
73
|
+
"400": status400,
|
|
74
|
+
"500": status500,
|
|
85
75
|
},
|
|
86
|
-
|
|
87
|
-
),
|
|
88
|
-
|
|
89
|
-
),
|
|
76
|
+
},
|
|
77
|
+
]),
|
|
78
|
+
),
|
|
79
|
+
]),
|
|
90
80
|
),
|
|
91
81
|
},
|
|
92
82
|
});
|
package/src/test.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { env, exports } from "cloudflare:workers";
|
|
2
2
|
import { type JWTPayload, SignJWT, exportJWK, generateKeyPair } from "jose";
|
|
3
3
|
import createClient from "openapi-fetch";
|
|
4
|
-
import { http, HttpResponse } from
|
|
5
|
-
import { setupServer } from
|
|
4
|
+
import { http, HttpResponse } from "msw";
|
|
5
|
+
import { setupServer } from "msw/node";
|
|
6
6
|
|
|
7
7
|
const msw = setupServer();
|
|
8
8
|
msw.listen();
|
|
@@ -32,11 +32,7 @@ export const setupTests = async <Paths extends {}>() => {
|
|
|
32
32
|
await waitUntil(() => expect(log).contains("Queue batch finished"));
|
|
33
33
|
console.log = orig;
|
|
34
34
|
},
|
|
35
|
-
async fakeJWK(
|
|
36
|
-
issuer: keyof typeof env,
|
|
37
|
-
audience: keyof typeof env,
|
|
38
|
-
claims: JWTPayload,
|
|
39
|
-
) {
|
|
35
|
+
async fakeJWK(issuer: keyof typeof env, audience: keyof typeof env, claims: JWTPayload) {
|
|
40
36
|
const { publicKey, privateKey } = await generateKeyPair("RS256");
|
|
41
37
|
// Hack around Cloudflare not setting
|
|
42
38
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -49,16 +45,20 @@ export const setupTests = async <Paths extends {}>() => {
|
|
|
49
45
|
jwk.kid = "test";
|
|
50
46
|
jwk.alg = "RS256";
|
|
51
47
|
beforeAll(() => {
|
|
52
|
-
msw.use(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
msw.use(
|
|
49
|
+
...[
|
|
50
|
+
http.get(`${env[issuer]}/.well-known/openid-configuration`, () =>
|
|
51
|
+
HttpResponse.json({
|
|
52
|
+
jwks_uri: `${env[issuer]}/.well-known/jwks`,
|
|
53
|
+
}),
|
|
54
|
+
),
|
|
55
|
+
http.get(`${env[issuer]}/.well-known/jwks`, () =>
|
|
56
|
+
HttpResponse.json({
|
|
57
|
+
keys: [jwk],
|
|
58
|
+
}),
|
|
59
|
+
),
|
|
60
|
+
],
|
|
61
|
+
);
|
|
62
62
|
});
|
|
63
63
|
return await new SignJWT(claims)
|
|
64
64
|
.setProtectedHeader({ typ: "JWT", alg: "RS256", kid: jwk.kid })
|
|
@@ -107,11 +107,7 @@ export function recordFormRequest(
|
|
|
107
107
|
},
|
|
108
108
|
) {
|
|
109
109
|
return ({ body }: { body?: BodyInit }) => {
|
|
110
|
-
cb(
|
|
111
|
-
Object.fromEntries(
|
|
112
|
-
new URLSearchParams((body?.valueOf() as string) ?? "").entries(),
|
|
113
|
-
),
|
|
114
|
-
);
|
|
110
|
+
cb(Object.fromEntries(new URLSearchParams((body?.valueOf() as string) ?? "").entries()));
|
|
115
111
|
return { statusCode, data, responseOptions: responseOptions ?? {} };
|
|
116
112
|
};
|
|
117
113
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
import { Toucan } from "toucan-js";
|
|
2
2
|
import { ZodType, ZodObject, z } from "zod/v4";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
| string
|
|
6
|
-
| Queue
|
|
7
|
-
| KVNamespace
|
|
8
|
-
| R2Bucket
|
|
9
|
-
| D1Database
|
|
10
|
-
| Fetcher
|
|
11
|
-
| Hyperdrive
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
-
| DurableObjectNamespace<any>
|
|
14
|
-
| Vectorize
|
|
15
|
-
| ImagesBinding;
|
|
16
|
-
};
|
|
17
|
-
export type Route<T extends Env, A> =
|
|
3
|
+
|
|
4
|
+
export type Route<T, A> =
|
|
18
5
|
| {
|
|
19
6
|
auth: (c: { req: Request; env: T }) => Promise<A>;
|
|
20
7
|
method: "GET" | "DELETE";
|
|
@@ -41,12 +28,11 @@ export type Route<T extends Env, A> =
|
|
|
41
28
|
|
|
42
29
|
export type ExtractParameterNames<S extends string> =
|
|
43
30
|
S extends `${string}{${infer Name}}${infer Rest}`
|
|
44
|
-
?
|
|
45
|
-
Record<Name, string> & ExtractParameterNames<Rest>
|
|
31
|
+
? Record<Name, string> & ExtractParameterNames<Rest>
|
|
46
32
|
: Record<string, string>;
|
|
47
33
|
|
|
48
34
|
export type Handler<
|
|
49
|
-
T
|
|
35
|
+
T,
|
|
50
36
|
I extends ZodType | undefined,
|
|
51
37
|
O extends ZodType,
|
|
52
38
|
A,
|
package/tsconfig.json
CHANGED
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
"erasableSyntaxOnly": true,
|
|
4
4
|
"esModuleInterop": true,
|
|
5
5
|
"isolatedModules": true,
|
|
6
|
-
"lib": [
|
|
7
|
-
"ESNext"
|
|
8
|
-
],
|
|
6
|
+
"lib": ["ESNext"],
|
|
9
7
|
"module": "ESNext",
|
|
10
8
|
"moduleResolution": "bundler",
|
|
11
9
|
"noUncheckedIndexedAccess": true,
|
|
@@ -20,7 +18,5 @@
|
|
|
20
18
|
],
|
|
21
19
|
"verbatimModuleSyntax": true
|
|
22
20
|
},
|
|
23
|
-
"exclude": [
|
|
24
|
-
"../../dist"
|
|
25
|
-
]
|
|
21
|
+
"exclude": ["../../dist"]
|
|
26
22
|
}
|