@zhin.js/adapter-satori 1.1.26 → 1.1.28
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/CHANGELOG.md +154 -0
- package/LICENSE +21 -0
- package/README.md +6 -6
- package/adapters/satori/index.js +5 -0
- package/adapters/satori/index.ts +5 -0
- package/lib/endpoint.d.ts +2 -1
- package/lib/endpoint.js +194 -66
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/protocol.d.ts +121 -9
- package/lib/protocol.js +561 -6
- package/lib/webhook.d.ts +8 -5
- package/lib/webhook.js +10 -24
- package/package.json +17 -23
- package/schema.json +0 -56
- package/src/endpoint.ts +221 -63
- package/src/index.ts +16 -0
- package/src/protocol.ts +671 -8
- package/src/webhook.ts +13 -29
package/src/webhook.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Satori webhook HTTP: token → opcode → parse → admit.
|
|
3
3
|
*/
|
|
4
4
|
import { timingSafeEqual } from 'node:crypto';
|
|
5
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
6
5
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
7
6
|
import { getLogger } from '@zhin.js/logger';
|
|
8
7
|
import {
|
|
@@ -15,7 +14,7 @@ const logger = getLogger('satori');
|
|
|
15
14
|
export interface SatoriWebhookHandler {
|
|
16
15
|
readonly config: ResolvedSatoriWebhookConfig;
|
|
17
16
|
readonly isOpen: boolean;
|
|
18
|
-
acceptHttp(request:
|
|
17
|
+
acceptHttp(request: Request): Promise<Response>;
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
export function registerSatoriWebhookRoutes(
|
|
@@ -24,55 +23,40 @@ export function registerSatoriWebhookRoutes(
|
|
|
24
23
|
): HttpRouteRegistration[] {
|
|
25
24
|
const path = handler.config.path;
|
|
26
25
|
return [
|
|
27
|
-
http.route('POST', path,
|
|
28
|
-
await handleSatoriWebhookRequest(request, response, handler);
|
|
29
|
-
}, { summary: 'Satori webhook callback', tags: ['satori'] }),
|
|
26
|
+
http.route('POST', path, (request) => handleSatoriWebhookRequest(request, handler), { summary: 'Satori webhook callback', tags: ['satori'] }),
|
|
30
27
|
];
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
export async function handleSatoriWebhookRequest(
|
|
34
|
-
request:
|
|
35
|
-
response: ServerResponse,
|
|
31
|
+
request: Request,
|
|
36
32
|
handler: SatoriWebhookHandler,
|
|
37
|
-
): Promise<
|
|
33
|
+
): Promise<Response> {
|
|
38
34
|
try {
|
|
39
35
|
if (!verifySatoriToken(handler.config.token, request)) {
|
|
40
|
-
|
|
41
|
-
response.end(JSON.stringify({ message: 'Unauthorized' }));
|
|
42
|
-
return;
|
|
36
|
+
return new Response(JSON.stringify({ message: 'Unauthorized' }), { status: 403, headers: { 'Content-Type': 'application/json' } });
|
|
43
37
|
}
|
|
44
38
|
const opcode = resolveSatoriOpcode(request);
|
|
45
39
|
if (opcode !== SatoriOpcode.EVENT && opcode !== SatoriOpcode.META) {
|
|
46
|
-
|
|
47
|
-
response.end(JSON.stringify({ message: 'OK' }));
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
if (handler.isOpen) {
|
|
51
|
-
await handler.acceptHttp(request, response);
|
|
52
|
-
} else {
|
|
53
|
-
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
54
|
-
response.end(JSON.stringify({ status: 'ok' }));
|
|
40
|
+
return new Response(JSON.stringify({ message: 'OK' }), { status: 200, headers: { 'Content-Type': 'application/json' } });
|
|
55
41
|
}
|
|
42
|
+
if (handler.isOpen) return await handler.acceptHttp(request);
|
|
43
|
+
return new Response(JSON.stringify({ status: 'ok' }), { status: 200, headers: { 'Content-Type': 'application/json' } });
|
|
56
44
|
} catch (error) {
|
|
57
45
|
logger.error('Satori webhook error:', error);
|
|
58
|
-
|
|
59
|
-
response.writeHead(500, { 'Content-Type': 'application/json' });
|
|
60
|
-
response.end(JSON.stringify({ message: 'Internal Server Error' }));
|
|
61
|
-
}
|
|
46
|
+
return new Response(JSON.stringify({ message: 'Internal Server Error' }), { status: 500, headers: { 'Content-Type': 'application/json' } });
|
|
62
47
|
}
|
|
63
48
|
}
|
|
64
49
|
|
|
65
|
-
export function resolveSatoriOpcode(request:
|
|
66
|
-
const
|
|
67
|
-
const value = Array.isArray(raw) ? raw[0] : raw;
|
|
50
|
+
export function resolveSatoriOpcode(request: { readonly headers: Headers }): number | undefined {
|
|
51
|
+
const value = request.headers.get('satori-opcode');
|
|
68
52
|
if (value == null || value === '') return undefined;
|
|
69
53
|
const parsed = Number.parseInt(String(value), 10);
|
|
70
54
|
return Number.isNaN(parsed) ? undefined : parsed;
|
|
71
55
|
}
|
|
72
56
|
|
|
73
|
-
export function verifySatoriToken(token: string | undefined, request:
|
|
57
|
+
export function verifySatoriToken(token: string | undefined, request: { readonly headers: Headers }): boolean {
|
|
74
58
|
if (!token) return true;
|
|
75
|
-
const auth = request.headers.authorization ?? '';
|
|
59
|
+
const auth = request.headers.get('authorization') ?? '';
|
|
76
60
|
const expected = Buffer.from(`Bearer ${token}`, 'utf8');
|
|
77
61
|
const actual = Buffer.from(auth, 'utf8');
|
|
78
62
|
return actual.length === expected.length && timingSafeEqual(actual, expected);
|