@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/webhook.js
CHANGED
|
@@ -1,94 +1,28 @@
|
|
|
1
|
-
|
|
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
|
-
*/
|
|
1
|
+
// src/webhook.ts
|
|
2
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
3
|
+
|
|
4
|
+
// src/webhook-shared.ts
|
|
17
5
|
function decodeHex(s) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
return out;
|
|
6
|
+
if (s.length % 2 !== 0) return new Uint8Array(0);
|
|
7
|
+
const out = new Uint8Array(s.length / 2);
|
|
8
|
+
for (let i = 0; i < out.length; i++) {
|
|
9
|
+
const byte = parseInt(s.slice(i * 2, i * 2 + 2), 16);
|
|
10
|
+
if (Number.isNaN(byte)) return new Uint8Array(0);
|
|
11
|
+
out[i] = byte;
|
|
12
|
+
}
|
|
13
|
+
return out;
|
|
28
14
|
}
|
|
29
15
|
function stripPrefix(sig) {
|
|
30
|
-
|
|
16
|
+
return sig.startsWith("sha256=") ? sig.slice(7) : sig;
|
|
31
17
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
18
|
+
|
|
19
|
+
// src/webhook.ts
|
|
20
|
+
function verifyMinipimWebhook(opts) {
|
|
21
|
+
const expected = createHmac("sha256", opts.secret).update(opts.rawBody).digest();
|
|
22
|
+
const got = decodeHex(stripPrefix(opts.signature));
|
|
23
|
+
if (got.length !== expected.length) return false;
|
|
24
|
+
return timingSafeEqual(expected, got);
|
|
39
25
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
* @example
|
|
44
|
-
* ```ts
|
|
45
|
-
* // Next.js App Router route handler
|
|
46
|
-
* export async function POST(req: Request) {
|
|
47
|
-
* const raw = await req.text();
|
|
48
|
-
* const sig = req.headers.get('x-minipim-signature-256') ?? '';
|
|
49
|
-
* if (!verifyMinipimWebhook({ rawBody: raw, signature: sig, secret })) {
|
|
50
|
-
* return new Response('invalid signature', { status: 401 });
|
|
51
|
-
* }
|
|
52
|
-
* const event = JSON.parse(raw);
|
|
53
|
-
* // ... handle event
|
|
54
|
-
* return Response.json({ ok: true });
|
|
55
|
-
* }
|
|
56
|
-
* ```
|
|
57
|
-
*
|
|
58
|
-
* Returns `false` on any verification problem (wrong signature, malformed
|
|
59
|
-
* header, length mismatch). Constant-time comparison — safe against timing
|
|
60
|
-
* attacks. Throws only if `node:crypto` is unavailable; if you're on Edge,
|
|
61
|
-
* use `verifyMinipimWebhookEdge` instead.
|
|
62
|
-
*/
|
|
63
|
-
export async function verifyMinipimWebhook(opts) {
|
|
64
|
-
// Lazy-import so the runtime exception is only thrown when actually
|
|
65
|
-
// calling this on Edge. The async signature matches the Edge variant
|
|
66
|
-
// so consumers don't have to branch.
|
|
67
|
-
const { createHmac } = await import('node:crypto');
|
|
68
|
-
const expected = createHmac('sha256', opts.secret).update(opts.rawBody).digest();
|
|
69
|
-
const got = decodeHex(stripPrefix(opts.signature));
|
|
70
|
-
return timingSafeEqualBytes(new Uint8Array(expected), got);
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Edge / browser variant using WebCrypto. Same shape as
|
|
74
|
-
* {@link verifyMinipimWebhook}; use this in Cloudflare Workers, Vercel
|
|
75
|
-
* Edge Runtime, Deno, or browsers.
|
|
76
|
-
*/
|
|
77
|
-
export async function verifyMinipimWebhookEdge(opts) {
|
|
78
|
-
const enc = new TextEncoder();
|
|
79
|
-
// Normalize both inputs to fresh Uint8Arrays — `new Uint8Array(view)`
|
|
80
|
-
// creates a new ArrayBuffer-backed copy, which is what WebCrypto's
|
|
81
|
-
// `subtle.sign` requires under TS 5.7's tightened typings. Without the
|
|
82
|
-
// re-wrap, a Buffer passed in from Node code can be `Uint8Array<ArrayBufferLike>`
|
|
83
|
-
// and trips the type checker (runtime is fine either way).
|
|
84
|
-
const keyData = enc.encode(opts.secret);
|
|
85
|
-
const bodyData = typeof opts.rawBody === 'string'
|
|
86
|
-
? enc.encode(opts.rawBody)
|
|
87
|
-
: new Uint8Array(opts.rawBody);
|
|
88
|
-
const key = await crypto.subtle.importKey('raw', keyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
89
|
-
const sigBuf = await crypto.subtle.sign('HMAC', key, bodyData);
|
|
90
|
-
const expected = new Uint8Array(sigBuf);
|
|
91
|
-
const got = decodeHex(stripPrefix(opts.signature));
|
|
92
|
-
return timingSafeEqualBytes(expected, got);
|
|
93
|
-
}
|
|
94
|
-
//# sourceMappingURL=webhook.js.map
|
|
26
|
+
export {
|
|
27
|
+
verifyMinipimWebhook
|
|
28
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minipim/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Typed TypeScript client for the MiniPim API.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/Epic-Design-Labs/minipim",
|
|
@@ -11,20 +11,58 @@
|
|
|
11
11
|
},
|
|
12
12
|
"bugs": "https://github.com/Epic-Design-Labs/minipim/issues",
|
|
13
13
|
"type": "module",
|
|
14
|
-
"main": "./dist/index.
|
|
14
|
+
"main": "./dist/index.cjs",
|
|
15
15
|
"types": "./dist/index.d.ts",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
18
|
-
"import":
|
|
19
|
-
|
|
18
|
+
"import": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"require": {
|
|
23
|
+
"types": "./dist/index.d.cts",
|
|
24
|
+
"default": "./dist/index.cjs"
|
|
25
|
+
}
|
|
20
26
|
},
|
|
21
27
|
"./webhook": {
|
|
22
|
-
"import":
|
|
23
|
-
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/webhook.d.ts",
|
|
30
|
+
"default": "./dist/webhook.js"
|
|
31
|
+
},
|
|
32
|
+
"require": {
|
|
33
|
+
"types": "./dist/webhook.d.cts",
|
|
34
|
+
"default": "./dist/webhook.cjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"./webhook-edge": {
|
|
38
|
+
"import": {
|
|
39
|
+
"types": "./dist/webhook-edge.d.ts",
|
|
40
|
+
"default": "./dist/webhook-edge.js"
|
|
41
|
+
},
|
|
42
|
+
"require": {
|
|
43
|
+
"types": "./dist/webhook-edge.d.cts",
|
|
44
|
+
"default": "./dist/webhook-edge.cjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"./attributes": {
|
|
48
|
+
"import": {
|
|
49
|
+
"types": "./dist/attributes.d.ts",
|
|
50
|
+
"default": "./dist/attributes.js"
|
|
51
|
+
},
|
|
52
|
+
"require": {
|
|
53
|
+
"types": "./dist/attributes.d.cts",
|
|
54
|
+
"default": "./dist/attributes.cjs"
|
|
55
|
+
}
|
|
24
56
|
},
|
|
25
57
|
"./openapi": {
|
|
26
|
-
"import":
|
|
27
|
-
|
|
58
|
+
"import": {
|
|
59
|
+
"types": "./dist/openapi.d.ts",
|
|
60
|
+
"default": "./dist/openapi.js"
|
|
61
|
+
},
|
|
62
|
+
"require": {
|
|
63
|
+
"types": "./dist/openapi.d.cts",
|
|
64
|
+
"default": "./dist/openapi.cjs"
|
|
65
|
+
}
|
|
28
66
|
}
|
|
29
67
|
},
|
|
30
68
|
"files": [
|
|
@@ -40,19 +78,21 @@
|
|
|
40
78
|
"openapi",
|
|
41
79
|
"typescript"
|
|
42
80
|
],
|
|
43
|
-
"scripts": {
|
|
44
|
-
"build": "tsc -b",
|
|
45
|
-
"typecheck": "tsc --noEmit",
|
|
46
|
-
"gen": "openapi-typescript https://api.minipim.com/docs/json -o src/openapi.ts"
|
|
47
|
-
},
|
|
48
81
|
"dependencies": {
|
|
49
82
|
"openapi-fetch": "^0.13.0"
|
|
50
83
|
},
|
|
51
84
|
"devDependencies": {
|
|
52
85
|
"openapi-typescript": "^7.5.0",
|
|
86
|
+
"tsup": "^8.5.1",
|
|
53
87
|
"typescript": "^5.7.0"
|
|
54
88
|
},
|
|
55
89
|
"publishConfig": {
|
|
56
90
|
"access": "public"
|
|
91
|
+
},
|
|
92
|
+
"module": "./dist/index.js",
|
|
93
|
+
"scripts": {
|
|
94
|
+
"build": "tsup",
|
|
95
|
+
"typecheck": "tsc --noEmit",
|
|
96
|
+
"gen": "openapi-typescript https://api.minipim.com/docs/json -o src/openapi.ts"
|
|
57
97
|
}
|
|
58
|
-
}
|
|
98
|
+
}
|
package/dist/client.d.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin wrapper around `openapi-fetch` that pre-binds the tenancy header and
|
|
3
|
-
* (optionally) an API key. Returns the standard openapi-fetch client, so all
|
|
4
|
-
* its features (request interceptors, raw response access, etc.) work as
|
|
5
|
-
* documented at https://openapi-ts.dev/openapi-fetch/.
|
|
6
|
-
*/
|
|
7
|
-
import { type Client } from 'openapi-fetch';
|
|
8
|
-
import type { paths } from './openapi.js';
|
|
9
|
-
export interface CreateMinipimClientOptions {
|
|
10
|
-
/**
|
|
11
|
-
* Base URL of the MiniPim API, e.g. `https://api.minipim.com`. Required.
|
|
12
|
-
* Trailing slashes are normalized.
|
|
13
|
-
*/
|
|
14
|
-
baseUrl: string;
|
|
15
|
-
/**
|
|
16
|
-
* Tenant the client speaks for. Required — every authenticated endpoint
|
|
17
|
-
* needs `x-organization-id`. API keys identify the principal, not the
|
|
18
|
-
* tenant.
|
|
19
|
-
*/
|
|
20
|
-
organizationId: string;
|
|
21
|
-
/**
|
|
22
|
-
* Bearer API key (e.g. `pim_abc123…`). Issue one in the admin under
|
|
23
|
-
* /api-keys. If you're running in dev with `PIM_AUTH=header`, omit this
|
|
24
|
-
* and set `userId` instead.
|
|
25
|
-
*/
|
|
26
|
-
apiKey?: string;
|
|
27
|
-
/**
|
|
28
|
-
* Dev-only header (`x-pim-user-id`). Only set when the deployment is in
|
|
29
|
-
* `header` auth mode. Ignored in `jwt` / `clerk` deployments.
|
|
30
|
-
*/
|
|
31
|
-
userId?: string;
|
|
32
|
-
/**
|
|
33
|
-
* Extra headers merged onto every request — useful for tracing IDs,
|
|
34
|
-
* feature flags, etc. Don't put auth here; use `apiKey`/`userId` so the
|
|
35
|
-
* names stay consistent.
|
|
36
|
-
*/
|
|
37
|
-
headers?: Record<string, string>;
|
|
38
|
-
/**
|
|
39
|
-
* Override `fetch` — pass a polyfill in Node <18 or a wrapped fetch that
|
|
40
|
-
* adds timeouts, retries, telemetry. Defaults to the global `fetch`.
|
|
41
|
-
*/
|
|
42
|
-
fetch?: typeof fetch;
|
|
43
|
-
}
|
|
44
|
-
export type MinipimClient = Client<paths>;
|
|
45
|
-
/**
|
|
46
|
-
* Create a typed MiniPim client.
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* ```ts
|
|
50
|
-
* import { createMinipimClient } from '@minipim/sdk';
|
|
51
|
-
*
|
|
52
|
-
* const pim = createMinipimClient({
|
|
53
|
-
* baseUrl: 'https://api.minipim.com',
|
|
54
|
-
* organizationId: '00000000-0000-0000-0000-000000000001',
|
|
55
|
-
* apiKey: process.env.MINIPIM_API_KEY!,
|
|
56
|
-
* });
|
|
57
|
-
*
|
|
58
|
-
* const { data, error } = await pim.GET('/v1/products', {
|
|
59
|
-
* params: { query: { limit: 50, categoryId: '…' } },
|
|
60
|
-
* });
|
|
61
|
-
* if (error) throw new Error(error.error.message);
|
|
62
|
-
* console.log(data.hasMore, data.data.length);
|
|
63
|
-
* ```
|
|
64
|
-
*/
|
|
65
|
-
export declare function createMinipimClient(opts: CreateMinipimClientOptions): MinipimClient;
|
|
66
|
-
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAqB,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,0BAA0B,GAC/B,aAAa,CAaf"}
|
package/dist/client.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin wrapper around `openapi-fetch` that pre-binds the tenancy header and
|
|
3
|
-
* (optionally) an API key. Returns the standard openapi-fetch client, so all
|
|
4
|
-
* its features (request interceptors, raw response access, etc.) work as
|
|
5
|
-
* documented at https://openapi-ts.dev/openapi-fetch/.
|
|
6
|
-
*/
|
|
7
|
-
import createClient from 'openapi-fetch';
|
|
8
|
-
/**
|
|
9
|
-
* Create a typed MiniPim client.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```ts
|
|
13
|
-
* import { createMinipimClient } from '@minipim/sdk';
|
|
14
|
-
*
|
|
15
|
-
* const pim = createMinipimClient({
|
|
16
|
-
* baseUrl: 'https://api.minipim.com',
|
|
17
|
-
* organizationId: '00000000-0000-0000-0000-000000000001',
|
|
18
|
-
* apiKey: process.env.MINIPIM_API_KEY!,
|
|
19
|
-
* });
|
|
20
|
-
*
|
|
21
|
-
* const { data, error } = await pim.GET('/v1/products', {
|
|
22
|
-
* params: { query: { limit: 50, categoryId: '…' } },
|
|
23
|
-
* });
|
|
24
|
-
* if (error) throw new Error(error.error.message);
|
|
25
|
-
* console.log(data.hasMore, data.data.length);
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
export function createMinipimClient(opts) {
|
|
29
|
-
const headers = {
|
|
30
|
-
'x-organization-id': opts.organizationId,
|
|
31
|
-
...(opts.headers ?? {}),
|
|
32
|
-
};
|
|
33
|
-
if (opts.apiKey)
|
|
34
|
-
headers['Authorization'] = `Bearer ${opts.apiKey}`;
|
|
35
|
-
if (opts.userId)
|
|
36
|
-
headers['x-pim-user-id'] = opts.userId;
|
|
37
|
-
return createClient({
|
|
38
|
-
baseUrl: opts.baseUrl.replace(/\/$/, ''),
|
|
39
|
-
fetch: opts.fetch,
|
|
40
|
-
headers,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,YAA6B,MAAM,eAAe,CAAC;AAyC1D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAgC;IAEhC,MAAM,OAAO,GAA2B;QACtC,mBAAmB,EAAE,IAAI,CAAC,cAAc;QACxC,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;KACxB,CAAC;IACF,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,IAAI,CAAC,MAAM,EAAE,CAAC;IACpE,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IAExD,OAAO,YAAY,CAAQ;QACzB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QACxC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO;KACR,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,KAAK,oBAAoB,GAC1B,MAAM,cAAc,CAAC;AAItB,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,mBAAmB,GAGpB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,oBAAoB,EACpB,wBAAwB,GAEzB,MAAM,cAAc,CAAC"}
|