@minipim/sdk 0.1.0 → 0.3.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/LICENSE +15 -0
- package/README.md +60 -17
- package/dist/attributes.cjs +80 -0
- package/dist/attributes.d.cts +48 -0
- package/dist/attributes.d.ts +48 -0
- package/dist/attributes.js +51 -0
- package/dist/index.cjs +163 -0
- package/dist/index.d.cts +132 -0
- package/dist/index.d.ts +129 -8
- package/dist/index.js +117 -10
- package/dist/openapi.cjs +18 -0
- package/dist/openapi.d.cts +7042 -0
- package/dist/openapi.d.ts +190 -10
- package/dist/openapi.js +0 -6
- package/dist/webhook-edge.cjs +68 -0
- package/dist/webhook-edge.d.cts +26 -0
- package/dist/webhook-edge.d.ts +26 -0
- package/dist/webhook-edge.js +41 -0
- package/dist/webhook-shared-CjMkFYVb.d.cts +25 -0
- package/dist/webhook-shared-CjMkFYVb.d.ts +25 -0
- package/dist/webhook.cjs +53 -0
- package/dist/webhook.d.cts +26 -0
- package/dist/webhook.d.ts +11 -51
- package/dist/webhook.js +23 -89
- package/package.json +54 -14
- package/dist/client.d.ts +0 -66
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -43
- package/dist/client.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/openapi.d.ts.map +0 -1
- package/dist/openapi.js.map +0 -1
- package/dist/webhook.d.ts.map +0 -1
- package/dist/webhook.js.map +0 -1
package/dist/openapi.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* This file was auto-generated by openapi-typescript.
|
|
3
3
|
* Do not make direct changes to the file.
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
interface paths {
|
|
6
6
|
"/healthz": {
|
|
7
7
|
parameters: {
|
|
8
8
|
query?: never;
|
|
@@ -1176,7 +1176,7 @@ export interface paths {
|
|
|
1176
1176
|
brand?: string;
|
|
1177
1177
|
connectorId?: string;
|
|
1178
1178
|
updatedSince?: string;
|
|
1179
|
-
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt";
|
|
1179
|
+
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance";
|
|
1180
1180
|
sortDir?: "asc" | "desc";
|
|
1181
1181
|
limit?: number;
|
|
1182
1182
|
offset?: number;
|
|
@@ -1342,7 +1342,7 @@ export interface paths {
|
|
|
1342
1342
|
brand?: string;
|
|
1343
1343
|
connectorId?: string;
|
|
1344
1344
|
updatedSince?: string;
|
|
1345
|
-
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt";
|
|
1345
|
+
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance";
|
|
1346
1346
|
sortDir?: "asc" | "desc";
|
|
1347
1347
|
locale?: string;
|
|
1348
1348
|
channel?: string;
|
|
@@ -1725,6 +1725,9 @@ export interface paths {
|
|
|
1725
1725
|
missing: {
|
|
1726
1726
|
code: string;
|
|
1727
1727
|
locale: string | null;
|
|
1728
|
+
label?: string;
|
|
1729
|
+
variantsMissing?: number;
|
|
1730
|
+
variantsTotal?: number;
|
|
1728
1731
|
}[];
|
|
1729
1732
|
}[];
|
|
1730
1733
|
};
|
|
@@ -2139,6 +2142,36 @@ export interface paths {
|
|
|
2139
2142
|
}[];
|
|
2140
2143
|
};
|
|
2141
2144
|
};
|
|
2145
|
+
/** @description Default Response */
|
|
2146
|
+
404: {
|
|
2147
|
+
headers: {
|
|
2148
|
+
[name: string]: unknown;
|
|
2149
|
+
};
|
|
2150
|
+
content: {
|
|
2151
|
+
"application/json": {
|
|
2152
|
+
error: {
|
|
2153
|
+
code: string;
|
|
2154
|
+
message: string;
|
|
2155
|
+
details?: unknown;
|
|
2156
|
+
};
|
|
2157
|
+
};
|
|
2158
|
+
};
|
|
2159
|
+
};
|
|
2160
|
+
/** @description Default Response */
|
|
2161
|
+
422: {
|
|
2162
|
+
headers: {
|
|
2163
|
+
[name: string]: unknown;
|
|
2164
|
+
};
|
|
2165
|
+
content: {
|
|
2166
|
+
"application/json": {
|
|
2167
|
+
error: {
|
|
2168
|
+
code: string;
|
|
2169
|
+
message: string;
|
|
2170
|
+
details?: unknown;
|
|
2171
|
+
};
|
|
2172
|
+
};
|
|
2173
|
+
};
|
|
2174
|
+
};
|
|
2142
2175
|
};
|
|
2143
2176
|
};
|
|
2144
2177
|
put?: never;
|
|
@@ -3223,10 +3256,16 @@ export interface paths {
|
|
|
3223
3256
|
* To get a single category's full ancestor path, walk `parentId` upwards
|
|
3224
3257
|
* client-side, or hit `GET /v1/categories/{id}` which returns the same row
|
|
3225
3258
|
* shape with the resolved path included in `path`.
|
|
3259
|
+
*
|
|
3260
|
+
* Returns the full tree by default. `?limit=` / `?offset=` are supported
|
|
3261
|
+
* for large taxonomies (ordered by `position`); omit them to get everything.
|
|
3226
3262
|
*/
|
|
3227
3263
|
get: {
|
|
3228
3264
|
parameters: {
|
|
3229
|
-
query?:
|
|
3265
|
+
query?: {
|
|
3266
|
+
limit?: number;
|
|
3267
|
+
offset?: number;
|
|
3268
|
+
};
|
|
3230
3269
|
header?: never;
|
|
3231
3270
|
path?: never;
|
|
3232
3271
|
cookie?: never;
|
|
@@ -5848,7 +5887,7 @@ export interface paths {
|
|
|
5848
5887
|
put?: never;
|
|
5849
5888
|
/**
|
|
5850
5889
|
* Trigger a sync (pull / push / both)
|
|
5851
|
-
* @description
|
|
5890
|
+
* @description Asynchronous: returns the sync record immediately with status `running`; the work continues in the background. Poll `GET /v1/connectors/{id}/syncs` for the terminal status (`completed`/`partial`/`failed`) and stats. Pulls download media binaries and routinely take minutes — running in-request exceeded proxy timeouts, which severed responses mid-sync and invited retry double-pulls. Caveat: a server restart mid-sync leaves the row `running` forever; a BullMQ worker will make this durable later.
|
|
5852
5891
|
*/
|
|
5853
5892
|
post: {
|
|
5854
5893
|
parameters: {
|
|
@@ -6359,6 +6398,146 @@ export interface paths {
|
|
|
6359
6398
|
patch?: never;
|
|
6360
6399
|
trace?: never;
|
|
6361
6400
|
};
|
|
6401
|
+
"/v1/connectors/{id}/deliveries": {
|
|
6402
|
+
parameters: {
|
|
6403
|
+
query?: never;
|
|
6404
|
+
header?: never;
|
|
6405
|
+
path?: never;
|
|
6406
|
+
cookie?: never;
|
|
6407
|
+
};
|
|
6408
|
+
/**
|
|
6409
|
+
* Recent outbound webhook deliveries for a connector
|
|
6410
|
+
* @description Last 50 delivery attempts (event name, HTTP status, ok, error) for push connectors that POST events to a destination (e.g. headless). Answers "did any events actually arrive?" without grepping receiver logs.
|
|
6411
|
+
*/
|
|
6412
|
+
get: {
|
|
6413
|
+
parameters: {
|
|
6414
|
+
query?: never;
|
|
6415
|
+
header?: never;
|
|
6416
|
+
path: {
|
|
6417
|
+
id: string;
|
|
6418
|
+
};
|
|
6419
|
+
cookie?: never;
|
|
6420
|
+
};
|
|
6421
|
+
requestBody?: never;
|
|
6422
|
+
responses: {
|
|
6423
|
+
/** @description Default Response */
|
|
6424
|
+
200: {
|
|
6425
|
+
headers: {
|
|
6426
|
+
[name: string]: unknown;
|
|
6427
|
+
};
|
|
6428
|
+
content: {
|
|
6429
|
+
"application/json": {
|
|
6430
|
+
/** Format: uuid */
|
|
6431
|
+
id: string;
|
|
6432
|
+
eventName: string;
|
|
6433
|
+
status: number | null;
|
|
6434
|
+
ok: boolean;
|
|
6435
|
+
error: string | null;
|
|
6436
|
+
/** Format: date-time */
|
|
6437
|
+
createdAt: string;
|
|
6438
|
+
}[];
|
|
6439
|
+
};
|
|
6440
|
+
};
|
|
6441
|
+
/** @description Default Response */
|
|
6442
|
+
404: {
|
|
6443
|
+
headers: {
|
|
6444
|
+
[name: string]: unknown;
|
|
6445
|
+
};
|
|
6446
|
+
content: {
|
|
6447
|
+
"application/json": {
|
|
6448
|
+
error: {
|
|
6449
|
+
code: string;
|
|
6450
|
+
message: string;
|
|
6451
|
+
details?: unknown;
|
|
6452
|
+
};
|
|
6453
|
+
};
|
|
6454
|
+
};
|
|
6455
|
+
};
|
|
6456
|
+
};
|
|
6457
|
+
};
|
|
6458
|
+
put?: never;
|
|
6459
|
+
post?: never;
|
|
6460
|
+
delete?: never;
|
|
6461
|
+
options?: never;
|
|
6462
|
+
head?: never;
|
|
6463
|
+
patch?: never;
|
|
6464
|
+
trace?: never;
|
|
6465
|
+
};
|
|
6466
|
+
"/v1/connectors/{id}/webhooks/test": {
|
|
6467
|
+
parameters: {
|
|
6468
|
+
query?: never;
|
|
6469
|
+
header?: never;
|
|
6470
|
+
path?: never;
|
|
6471
|
+
cookie?: never;
|
|
6472
|
+
};
|
|
6473
|
+
get?: never;
|
|
6474
|
+
put?: never;
|
|
6475
|
+
/**
|
|
6476
|
+
* Send a signed test event to the connector destination
|
|
6477
|
+
* @description Delivers a synthetic `webhook.test` event (HMAC-signed like any real delivery) so integrators can verify endpoint wiring without mutating catalog data. Returns the delivery outcome and logs it like any other.
|
|
6478
|
+
*/
|
|
6479
|
+
post: {
|
|
6480
|
+
parameters: {
|
|
6481
|
+
query?: never;
|
|
6482
|
+
header?: never;
|
|
6483
|
+
path: {
|
|
6484
|
+
id: string;
|
|
6485
|
+
};
|
|
6486
|
+
cookie?: never;
|
|
6487
|
+
};
|
|
6488
|
+
requestBody?: never;
|
|
6489
|
+
responses: {
|
|
6490
|
+
/** @description Default Response */
|
|
6491
|
+
200: {
|
|
6492
|
+
headers: {
|
|
6493
|
+
[name: string]: unknown;
|
|
6494
|
+
};
|
|
6495
|
+
content: {
|
|
6496
|
+
"application/json": {
|
|
6497
|
+
ok: boolean;
|
|
6498
|
+
status: number | null;
|
|
6499
|
+
error?: string;
|
|
6500
|
+
};
|
|
6501
|
+
};
|
|
6502
|
+
};
|
|
6503
|
+
/** @description Default Response */
|
|
6504
|
+
404: {
|
|
6505
|
+
headers: {
|
|
6506
|
+
[name: string]: unknown;
|
|
6507
|
+
};
|
|
6508
|
+
content: {
|
|
6509
|
+
"application/json": {
|
|
6510
|
+
error: {
|
|
6511
|
+
code: string;
|
|
6512
|
+
message: string;
|
|
6513
|
+
details?: unknown;
|
|
6514
|
+
};
|
|
6515
|
+
};
|
|
6516
|
+
};
|
|
6517
|
+
};
|
|
6518
|
+
/** @description Default Response */
|
|
6519
|
+
422: {
|
|
6520
|
+
headers: {
|
|
6521
|
+
[name: string]: unknown;
|
|
6522
|
+
};
|
|
6523
|
+
content: {
|
|
6524
|
+
"application/json": {
|
|
6525
|
+
error: {
|
|
6526
|
+
code: string;
|
|
6527
|
+
message: string;
|
|
6528
|
+
details?: unknown;
|
|
6529
|
+
};
|
|
6530
|
+
};
|
|
6531
|
+
};
|
|
6532
|
+
};
|
|
6533
|
+
};
|
|
6534
|
+
};
|
|
6535
|
+
delete?: never;
|
|
6536
|
+
options?: never;
|
|
6537
|
+
head?: never;
|
|
6538
|
+
patch?: never;
|
|
6539
|
+
trace?: never;
|
|
6540
|
+
};
|
|
6362
6541
|
"/v1/connectors/{id}/webhooks/enable": {
|
|
6363
6542
|
parameters: {
|
|
6364
6543
|
query?: never;
|
|
@@ -6848,8 +7027,8 @@ export interface paths {
|
|
|
6848
7027
|
trace?: never;
|
|
6849
7028
|
};
|
|
6850
7029
|
}
|
|
6851
|
-
|
|
6852
|
-
|
|
7030
|
+
type webhooks = Record<string, never>;
|
|
7031
|
+
interface components {
|
|
6853
7032
|
schemas: never;
|
|
6854
7033
|
responses: never;
|
|
6855
7034
|
parameters: never;
|
|
@@ -6857,6 +7036,7 @@ export interface components {
|
|
|
6857
7036
|
headers: never;
|
|
6858
7037
|
pathItems: never;
|
|
6859
7038
|
}
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
7039
|
+
type $defs = Record<string, never>;
|
|
7040
|
+
type operations = Record<string, never>;
|
|
7041
|
+
|
|
7042
|
+
export type { $defs, components, operations, paths, webhooks };
|
package/dist/openapi.js
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/webhook-edge.ts
|
|
21
|
+
var webhook_edge_exports = {};
|
|
22
|
+
__export(webhook_edge_exports, {
|
|
23
|
+
verifyMinipimWebhookEdge: () => verifyMinipimWebhookEdge
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(webhook_edge_exports);
|
|
26
|
+
|
|
27
|
+
// src/webhook-shared.ts
|
|
28
|
+
function decodeHex(s) {
|
|
29
|
+
if (s.length % 2 !== 0) return new Uint8Array(0);
|
|
30
|
+
const out = new Uint8Array(s.length / 2);
|
|
31
|
+
for (let i = 0; i < out.length; i++) {
|
|
32
|
+
const byte = parseInt(s.slice(i * 2, i * 2 + 2), 16);
|
|
33
|
+
if (Number.isNaN(byte)) return new Uint8Array(0);
|
|
34
|
+
out[i] = byte;
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
function stripPrefix(sig) {
|
|
39
|
+
return sig.startsWith("sha256=") ? sig.slice(7) : sig;
|
|
40
|
+
}
|
|
41
|
+
function timingSafeEqualBytes(a, b) {
|
|
42
|
+
if (a.length !== b.length) return false;
|
|
43
|
+
let diff = 0;
|
|
44
|
+
for (let i = 0; i < a.length; i++) diff |= (a[i] ?? 0) ^ (b[i] ?? 0);
|
|
45
|
+
return diff === 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/webhook-edge.ts
|
|
49
|
+
async function verifyMinipimWebhookEdge(opts) {
|
|
50
|
+
const enc = new TextEncoder();
|
|
51
|
+
const keyData = enc.encode(opts.secret);
|
|
52
|
+
const bodyData = typeof opts.rawBody === "string" ? enc.encode(opts.rawBody) : new Uint8Array(opts.rawBody);
|
|
53
|
+
const key = await crypto.subtle.importKey(
|
|
54
|
+
"raw",
|
|
55
|
+
keyData,
|
|
56
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
57
|
+
false,
|
|
58
|
+
["sign"]
|
|
59
|
+
);
|
|
60
|
+
const sigBuf = await crypto.subtle.sign("HMAC", key, bodyData);
|
|
61
|
+
const expected = new Uint8Array(sigBuf);
|
|
62
|
+
const got = decodeHex(stripPrefix(opts.signature));
|
|
63
|
+
return timingSafeEqualBytes(expected, got);
|
|
64
|
+
}
|
|
65
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
66
|
+
0 && (module.exports = {
|
|
67
|
+
verifyMinipimWebhookEdge
|
|
68
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { V as VerifyWebhookOptions } from './webhook-shared-CjMkFYVb.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edge / browser webhook signature verification, via WebCrypto. Use in
|
|
5
|
+
* Cloudflare Workers, Vercel Edge Runtime, Deno, or browsers. Async because
|
|
6
|
+
* `crypto.subtle` is async. For Node use `@minipim/sdk/webhook` (synchronous).
|
|
7
|
+
*
|
|
8
|
+
* This entry point imports no `node:` modules, so it's safe in any Edge
|
|
9
|
+
* bundle.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Verify a MiniPim webhook signature in an Edge/WebCrypto runtime. Same
|
|
14
|
+
* contract as the Node `verifyMinipimWebhook` but async.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { verifyMinipimWebhookEdge } from '@minipim/sdk/webhook-edge';
|
|
19
|
+
*
|
|
20
|
+
* const ok = await verifyMinipimWebhookEdge({ rawBody, signature, secret });
|
|
21
|
+
* if (!ok) return new Response('invalid signature', { status: 401 });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare function verifyMinipimWebhookEdge(opts: VerifyWebhookOptions): Promise<boolean>;
|
|
25
|
+
|
|
26
|
+
export { VerifyWebhookOptions, verifyMinipimWebhookEdge };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { V as VerifyWebhookOptions } from './webhook-shared-CjMkFYVb.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edge / browser webhook signature verification, via WebCrypto. Use in
|
|
5
|
+
* Cloudflare Workers, Vercel Edge Runtime, Deno, or browsers. Async because
|
|
6
|
+
* `crypto.subtle` is async. For Node use `@minipim/sdk/webhook` (synchronous).
|
|
7
|
+
*
|
|
8
|
+
* This entry point imports no `node:` modules, so it's safe in any Edge
|
|
9
|
+
* bundle.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Verify a MiniPim webhook signature in an Edge/WebCrypto runtime. Same
|
|
14
|
+
* contract as the Node `verifyMinipimWebhook` but async.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { verifyMinipimWebhookEdge } from '@minipim/sdk/webhook-edge';
|
|
19
|
+
*
|
|
20
|
+
* const ok = await verifyMinipimWebhookEdge({ rawBody, signature, secret });
|
|
21
|
+
* if (!ok) return new Response('invalid signature', { status: 401 });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare function verifyMinipimWebhookEdge(opts: VerifyWebhookOptions): Promise<boolean>;
|
|
25
|
+
|
|
26
|
+
export { VerifyWebhookOptions, verifyMinipimWebhookEdge };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/webhook-shared.ts
|
|
2
|
+
function decodeHex(s) {
|
|
3
|
+
if (s.length % 2 !== 0) return new Uint8Array(0);
|
|
4
|
+
const out = new Uint8Array(s.length / 2);
|
|
5
|
+
for (let i = 0; i < out.length; i++) {
|
|
6
|
+
const byte = parseInt(s.slice(i * 2, i * 2 + 2), 16);
|
|
7
|
+
if (Number.isNaN(byte)) return new Uint8Array(0);
|
|
8
|
+
out[i] = byte;
|
|
9
|
+
}
|
|
10
|
+
return out;
|
|
11
|
+
}
|
|
12
|
+
function stripPrefix(sig) {
|
|
13
|
+
return sig.startsWith("sha256=") ? sig.slice(7) : sig;
|
|
14
|
+
}
|
|
15
|
+
function timingSafeEqualBytes(a, b) {
|
|
16
|
+
if (a.length !== b.length) return false;
|
|
17
|
+
let diff = 0;
|
|
18
|
+
for (let i = 0; i < a.length; i++) diff |= (a[i] ?? 0) ^ (b[i] ?? 0);
|
|
19
|
+
return diff === 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/webhook-edge.ts
|
|
23
|
+
async function verifyMinipimWebhookEdge(opts) {
|
|
24
|
+
const enc = new TextEncoder();
|
|
25
|
+
const keyData = enc.encode(opts.secret);
|
|
26
|
+
const bodyData = typeof opts.rawBody === "string" ? enc.encode(opts.rawBody) : new Uint8Array(opts.rawBody);
|
|
27
|
+
const key = await crypto.subtle.importKey(
|
|
28
|
+
"raw",
|
|
29
|
+
keyData,
|
|
30
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
31
|
+
false,
|
|
32
|
+
["sign"]
|
|
33
|
+
);
|
|
34
|
+
const sigBuf = await crypto.subtle.sign("HMAC", key, bodyData);
|
|
35
|
+
const expected = new Uint8Array(sigBuf);
|
|
36
|
+
const got = decodeHex(stripPrefix(opts.signature));
|
|
37
|
+
return timingSafeEqualBytes(expected, got);
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
verifyMinipimWebhookEdge
|
|
41
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers shared by the Node and Edge webhook verifiers. Deliberately
|
|
3
|
+
* free of `node:crypto` and WebCrypto so importing this file drags neither
|
|
4
|
+
* runtime's crypto into a bundle.
|
|
5
|
+
*/
|
|
6
|
+
interface VerifyWebhookOptions {
|
|
7
|
+
/**
|
|
8
|
+
* The **raw** request body — bytes or a string. **Not** the parsed JSON.
|
|
9
|
+
* Re-stringifying the parsed body reorders keys / changes whitespace and
|
|
10
|
+
* the HMAC will not match.
|
|
11
|
+
*
|
|
12
|
+
* Next.js route handler: `const raw = await req.text()`.
|
|
13
|
+
* Express: `express.raw({ type: 'application/json' })`, then `req.body`.
|
|
14
|
+
*/
|
|
15
|
+
rawBody: string | Uint8Array;
|
|
16
|
+
/**
|
|
17
|
+
* Value of the `X-MiniPim-Signature-256` header — `sha256=<hex>`. Pass it
|
|
18
|
+
* verbatim; the verifier strips the prefix.
|
|
19
|
+
*/
|
|
20
|
+
signature: string;
|
|
21
|
+
/** The secret configured on the headless connector. */
|
|
22
|
+
secret: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type { VerifyWebhookOptions as V };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers shared by the Node and Edge webhook verifiers. Deliberately
|
|
3
|
+
* free of `node:crypto` and WebCrypto so importing this file drags neither
|
|
4
|
+
* runtime's crypto into a bundle.
|
|
5
|
+
*/
|
|
6
|
+
interface VerifyWebhookOptions {
|
|
7
|
+
/**
|
|
8
|
+
* The **raw** request body — bytes or a string. **Not** the parsed JSON.
|
|
9
|
+
* Re-stringifying the parsed body reorders keys / changes whitespace and
|
|
10
|
+
* the HMAC will not match.
|
|
11
|
+
*
|
|
12
|
+
* Next.js route handler: `const raw = await req.text()`.
|
|
13
|
+
* Express: `express.raw({ type: 'application/json' })`, then `req.body`.
|
|
14
|
+
*/
|
|
15
|
+
rawBody: string | Uint8Array;
|
|
16
|
+
/**
|
|
17
|
+
* Value of the `X-MiniPim-Signature-256` header — `sha256=<hex>`. Pass it
|
|
18
|
+
* verbatim; the verifier strips the prefix.
|
|
19
|
+
*/
|
|
20
|
+
signature: string;
|
|
21
|
+
/** The secret configured on the headless connector. */
|
|
22
|
+
secret: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type { VerifyWebhookOptions as V };
|
package/dist/webhook.cjs
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/webhook.ts
|
|
21
|
+
var webhook_exports = {};
|
|
22
|
+
__export(webhook_exports, {
|
|
23
|
+
verifyMinipimWebhook: () => verifyMinipimWebhook
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(webhook_exports);
|
|
26
|
+
var import_node_crypto = require("crypto");
|
|
27
|
+
|
|
28
|
+
// src/webhook-shared.ts
|
|
29
|
+
function decodeHex(s) {
|
|
30
|
+
if (s.length % 2 !== 0) return new Uint8Array(0);
|
|
31
|
+
const out = new Uint8Array(s.length / 2);
|
|
32
|
+
for (let i = 0; i < out.length; i++) {
|
|
33
|
+
const byte = parseInt(s.slice(i * 2, i * 2 + 2), 16);
|
|
34
|
+
if (Number.isNaN(byte)) return new Uint8Array(0);
|
|
35
|
+
out[i] = byte;
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
function stripPrefix(sig) {
|
|
40
|
+
return sig.startsWith("sha256=") ? sig.slice(7) : sig;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/webhook.ts
|
|
44
|
+
function verifyMinipimWebhook(opts) {
|
|
45
|
+
const expected = (0, import_node_crypto.createHmac)("sha256", opts.secret).update(opts.rawBody).digest();
|
|
46
|
+
const got = decodeHex(stripPrefix(opts.signature));
|
|
47
|
+
if (got.length !== expected.length) return false;
|
|
48
|
+
return (0, import_node_crypto.timingSafeEqual)(expected, got);
|
|
49
|
+
}
|
|
50
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
51
|
+
0 && (module.exports = {
|
|
52
|
+
verifyMinipimWebhook
|
|
53
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { V as VerifyWebhookOptions } from './webhook-shared-CjMkFYVb.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Verify a MiniPim webhook signature in Node. Returns `true` only when the
|
|
5
|
+
* signature is valid; returns `false` on any problem (wrong signature,
|
|
6
|
+
* malformed header, length mismatch). Constant-time comparison.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { verifyMinipimWebhook } from '@minipim/sdk/webhook';
|
|
11
|
+
*
|
|
12
|
+
* export async function POST(req: Request) {
|
|
13
|
+
* const raw = await req.text();
|
|
14
|
+
* const sig = req.headers.get('x-minipim-signature-256') ?? '';
|
|
15
|
+
* if (!verifyMinipimWebhook({ rawBody: raw, signature: sig, secret })) {
|
|
16
|
+
* return new Response('invalid signature', { status: 401 });
|
|
17
|
+
* }
|
|
18
|
+
* const event = JSON.parse(raw);
|
|
19
|
+
* // ...handle event, respond 2xx
|
|
20
|
+
* return Response.json({ ok: true });
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare function verifyMinipimWebhook(opts: VerifyWebhookOptions): boolean;
|
|
25
|
+
|
|
26
|
+
export { VerifyWebhookOptions, verifyMinipimWebhook };
|
package/dist/webhook.d.ts
CHANGED
|
@@ -1,44 +1,14 @@
|
|
|
1
|
+
import { V as VerifyWebhookOptions } from './webhook-shared-CjMkFYVb.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* `X-MiniPim-Signature-256` header containing `sha256=<hex>` — the HMAC of
|
|
6
|
-
* the raw request body keyed by the connector's secret. Verifying it
|
|
7
|
-
* correctly is the #1 thing webhook consumers get wrong, so the SDK ships a
|
|
8
|
-
* reference implementation.
|
|
9
|
-
*
|
|
10
|
-
* Two variants exported:
|
|
11
|
-
* - `verifyMinipimWebhook` — sync, Node `crypto`. Use in any Node
|
|
12
|
-
* server (Express, Fastify, Next App Router
|
|
13
|
-
* route handlers).
|
|
14
|
-
* - `verifyMinipimWebhookEdge` — async, WebCrypto subtle. For Cloudflare
|
|
15
|
-
* Workers, Vercel Edge, Deno, browsers.
|
|
16
|
-
*/
|
|
17
|
-
export interface VerifyWebhookOptions {
|
|
18
|
-
/**
|
|
19
|
-
* The **raw** request body — bytes or a string. **Not** the parsed JSON.
|
|
20
|
-
* If you re-stringify the parsed body, whitespace and key ordering will
|
|
21
|
-
* differ from the original, and the HMAC will not match.
|
|
22
|
-
*
|
|
23
|
-
* In Next.js route handlers: `const rawBody = await req.text()`.
|
|
24
|
-
* In Express: register `express.raw({ type: 'application/json' })` and
|
|
25
|
-
* read `req.body` (it'll be a Buffer).
|
|
26
|
-
*/
|
|
27
|
-
rawBody: string | Uint8Array;
|
|
28
|
-
/**
|
|
29
|
-
* Value of the `X-MiniPim-Signature-256` header. Format:
|
|
30
|
-
* `sha256=<hex>` — pass it verbatim. The function strips the prefix.
|
|
31
|
-
*/
|
|
32
|
-
signature: string;
|
|
33
|
-
/** The secret you configured on the headless connector. */
|
|
34
|
-
secret: string;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Verify a MiniPim webhook signature in a Node environment.
|
|
4
|
+
* Verify a MiniPim webhook signature in Node. Returns `true` only when the
|
|
5
|
+
* signature is valid; returns `false` on any problem (wrong signature,
|
|
6
|
+
* malformed header, length mismatch). Constant-time comparison.
|
|
38
7
|
*
|
|
39
8
|
* @example
|
|
40
9
|
* ```ts
|
|
41
|
-
*
|
|
10
|
+
* import { verifyMinipimWebhook } from '@minipim/sdk/webhook';
|
|
11
|
+
*
|
|
42
12
|
* export async function POST(req: Request) {
|
|
43
13
|
* const raw = await req.text();
|
|
44
14
|
* const sig = req.headers.get('x-minipim-signature-256') ?? '';
|
|
@@ -46,21 +16,11 @@ export interface VerifyWebhookOptions {
|
|
|
46
16
|
* return new Response('invalid signature', { status: 401 });
|
|
47
17
|
* }
|
|
48
18
|
* const event = JSON.parse(raw);
|
|
49
|
-
* // ...
|
|
19
|
+
* // ...handle event, respond 2xx
|
|
50
20
|
* return Response.json({ ok: true });
|
|
51
21
|
* }
|
|
52
22
|
* ```
|
|
53
|
-
*
|
|
54
|
-
* Returns `false` on any verification problem (wrong signature, malformed
|
|
55
|
-
* header, length mismatch). Constant-time comparison — safe against timing
|
|
56
|
-
* attacks. Throws only if `node:crypto` is unavailable; if you're on Edge,
|
|
57
|
-
* use `verifyMinipimWebhookEdge` instead.
|
|
58
|
-
*/
|
|
59
|
-
export declare function verifyMinipimWebhook(opts: VerifyWebhookOptions): Promise<boolean>;
|
|
60
|
-
/**
|
|
61
|
-
* Edge / browser variant using WebCrypto. Same shape as
|
|
62
|
-
* {@link verifyMinipimWebhook}; use this in Cloudflare Workers, Vercel
|
|
63
|
-
* Edge Runtime, Deno, or browsers.
|
|
64
23
|
*/
|
|
65
|
-
|
|
66
|
-
|
|
24
|
+
declare function verifyMinipimWebhook(opts: VerifyWebhookOptions): boolean;
|
|
25
|
+
|
|
26
|
+
export { VerifyWebhookOptions, verifyMinipimWebhook };
|