@minipim/sdk 0.2.0 → 0.3.1
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 +3 -1
- package/dist/attributes.cjs +80 -0
- package/dist/attributes.d.cts +48 -0
- package/dist/attributes.d.ts +12 -11
- package/dist/attributes.js +46 -71
- package/dist/index.cjs +163 -0
- package/dist/index.d.cts +132 -0
- package/dist/index.d.ts +128 -13
- package/dist/index.js +117 -16
- package/dist/openapi.cjs +18 -0
- package/dist/openapi.d.cts +7204 -0
- package/dist/openapi.d.ts +345 -9
- 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 +6 -4
- package/dist/webhook-edge.js +40 -31
- package/dist/{webhook-shared.d.ts → webhook-shared-CjMkFYVb.d.cts} +3 -6
- 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 +5 -4
- package/dist/webhook.js +27 -39
- package/package.json +45 -13
- package/dist/attributes.d.ts.map +0 -1
- package/dist/attributes.js.map +0 -1
- 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/errors.d.ts +0 -27
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -30
- package/dist/errors.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/paginate.d.ts +0 -34
- package/dist/paginate.d.ts.map +0 -1
- package/dist/paginate.js +0 -43
- package/dist/paginate.js.map +0 -1
- package/dist/webhook-edge.d.ts.map +0 -1
- package/dist/webhook-edge.js.map +0 -1
- package/dist/webhook-shared.d.ts.map +0 -1
- package/dist/webhook-shared.js +0 -30
- package/dist/webhook-shared.js.map +0 -1
- package/dist/webhook.d.ts.map +0 -1
- package/dist/webhook.js.map +0 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Typed TypeScript client for the [MiniPim](https://github.com/Epic-Design-Labs/mi
|
|
|
8
8
|
pnpm add @minipim/sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Requires Node 18+ (for native `fetch`) or a fetch polyfill. **ESM
|
|
11
|
+
Requires Node 18+ (for native `fetch`) or a fetch polyfill. Ships **both ESM and CommonJS** builds (v0.3.0+) — `import` and `require` both work, including in CJS test tooling. The root entry imports no `node:` modules, so `createMinipimClient` and the attribute/pagination helpers are safe in Edge runtimes.
|
|
12
12
|
|
|
13
13
|
`baseUrl` is the **origin** (`https://api.minipim.com`); every endpoint path already includes `/v1/...`, so you pass `pim.GET('/v1/products')`, not a pre-joined URL.
|
|
14
14
|
|
|
@@ -128,6 +128,8 @@ const all = await collectAll<Product>(pim, '/v1/products');
|
|
|
128
128
|
|
|
129
129
|
`paginate` manages `limit`/`offset`, honors the server's `hasMore`, and defaults to the 200-row max page size (override with `pageSize`). Pass `withTotal: true` in `query` if you need `total` — it adds one `COUNT(*)`, so leave it off on hot reads.
|
|
130
130
|
|
|
131
|
+
Endpoints that return a **plain array** instead of the envelope (`/v1/categories` without `?limit=`, `/v1/attributes`, `/v1/products/{id}/variants`) are handled too (v0.3.0+): the array is treated as the one-and-only page, so `collectAll` works uniformly across every list endpoint.
|
|
132
|
+
|
|
131
133
|
## Attribute helpers
|
|
132
134
|
|
|
133
135
|
Attribute values are `unknown` and keyed by `(locale, channel)`. List responses return the raw `{ code: [{ locale, channel, value }] }` shape (only product *detail* with `?locale=&channel=` returns a flat `resolvedAttributes`). The SDK ships the flatten + coercion helpers so you don't reimplement them:
|
|
@@ -0,0 +1,80 @@
|
|
|
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/attributes.ts
|
|
21
|
+
var attributes_exports = {};
|
|
22
|
+
__export(attributes_exports, {
|
|
23
|
+
asMeasurement: () => asMeasurement,
|
|
24
|
+
asMoney: () => asMoney,
|
|
25
|
+
flattenAttributes: () => flattenAttributes,
|
|
26
|
+
formatMoney: () => formatMoney,
|
|
27
|
+
getAttribute: () => getAttribute
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(attributes_exports);
|
|
30
|
+
function getAttribute(attributes, code, opts = {}) {
|
|
31
|
+
const records = attributes[code];
|
|
32
|
+
if (!records || records.length === 0) return void 0;
|
|
33
|
+
const locale = opts.locale ?? null;
|
|
34
|
+
const channel = opts.channel ?? null;
|
|
35
|
+
const layers = [
|
|
36
|
+
[locale, channel],
|
|
37
|
+
[locale, null],
|
|
38
|
+
[null, channel],
|
|
39
|
+
[null, null]
|
|
40
|
+
];
|
|
41
|
+
for (const [l, c] of layers) {
|
|
42
|
+
const hit = records.find((r) => r.locale === l && r.channel === c);
|
|
43
|
+
if (hit) return hit.value;
|
|
44
|
+
}
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
function flattenAttributes(attributes, opts = {}) {
|
|
48
|
+
const out = {};
|
|
49
|
+
for (const code of Object.keys(attributes)) {
|
|
50
|
+
const v = getAttribute(attributes, code, opts);
|
|
51
|
+
if (v !== void 0) out[code] = v;
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
function asMoney(value) {
|
|
56
|
+
if (value && typeof value === "object" && typeof value.amount_cents === "number" && typeof value.currency === "string") {
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function asMeasurement(value) {
|
|
62
|
+
if (value && typeof value === "object" && typeof value.amount === "number" && typeof value.unit === "string") {
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
function formatMoney(money, locale = "en-US") {
|
|
68
|
+
return new Intl.NumberFormat(locale, {
|
|
69
|
+
style: "currency",
|
|
70
|
+
currency: money.currency
|
|
71
|
+
}).format(money.amount_cents / 100);
|
|
72
|
+
}
|
|
73
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
74
|
+
0 && (module.exports = {
|
|
75
|
+
asMeasurement,
|
|
76
|
+
asMoney,
|
|
77
|
+
flattenAttributes,
|
|
78
|
+
formatMoney,
|
|
79
|
+
getAttribute
|
|
80
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribute helpers. MiniPim stores attribute values keyed by
|
|
3
|
+
* `(locale, channel)` — list responses always return the raw
|
|
4
|
+
* `{ code: [{ locale, channel, value }] }` shape (only product *detail*
|
|
5
|
+
* with `?locale=&channel=` returns a flat `resolvedAttributes`). So every
|
|
6
|
+
* consumer ends up writing the same flatten + money/measurement coercions.
|
|
7
|
+
* These are those helpers, typed.
|
|
8
|
+
*/
|
|
9
|
+
interface AttributeValueRecord {
|
|
10
|
+
locale: string | null;
|
|
11
|
+
channel: string | null;
|
|
12
|
+
value: unknown;
|
|
13
|
+
}
|
|
14
|
+
type AttributesPayload = Record<string, AttributeValueRecord[]>;
|
|
15
|
+
interface Money {
|
|
16
|
+
amount_cents: number;
|
|
17
|
+
currency: string;
|
|
18
|
+
}
|
|
19
|
+
interface Measurement {
|
|
20
|
+
amount: number;
|
|
21
|
+
unit: string;
|
|
22
|
+
}
|
|
23
|
+
interface ResolveOptions {
|
|
24
|
+
locale?: string | null;
|
|
25
|
+
channel?: string | null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve a single attribute code to its value for a (locale, channel).
|
|
29
|
+
* Fallback order mirrors the server: exact `(locale, channel)` →
|
|
30
|
+
* `(locale, null)` → `(null, channel)` → `(null, null)`. Returns
|
|
31
|
+
* `undefined` when nothing matches.
|
|
32
|
+
*/
|
|
33
|
+
declare function getAttribute(attributes: AttributesPayload, code: string, opts?: ResolveOptions): unknown;
|
|
34
|
+
/**
|
|
35
|
+
* Flatten an entire attribute payload to a `{ code: value }` map for a
|
|
36
|
+
* (locale, channel) — the client-side equivalent of the server's
|
|
37
|
+
* `resolvedAttributes`, for use on list responses where the server doesn't
|
|
38
|
+
* flatten. Codes with no matching value are omitted.
|
|
39
|
+
*/
|
|
40
|
+
declare function flattenAttributes(attributes: AttributesPayload, opts?: ResolveOptions): Record<string, unknown>;
|
|
41
|
+
/** Narrow an attribute value to Money, or null if it isn't money-shaped. */
|
|
42
|
+
declare function asMoney(value: unknown): Money | null;
|
|
43
|
+
/** Narrow an attribute value to Measurement, or null if it isn't measurement-shaped. */
|
|
44
|
+
declare function asMeasurement(value: unknown): Measurement | null;
|
|
45
|
+
/** Format integer-cents Money as a localized currency string. */
|
|
46
|
+
declare function formatMoney(money: Money, locale?: string): string;
|
|
47
|
+
|
|
48
|
+
export { type AttributeValueRecord, type AttributesPayload, type Measurement, type Money, type ResolveOptions, asMeasurement, asMoney, flattenAttributes, formatMoney, getAttribute };
|
package/dist/attributes.d.ts
CHANGED
|
@@ -6,21 +6,21 @@
|
|
|
6
6
|
* consumer ends up writing the same flatten + money/measurement coercions.
|
|
7
7
|
* These are those helpers, typed.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
interface AttributeValueRecord {
|
|
10
10
|
locale: string | null;
|
|
11
11
|
channel: string | null;
|
|
12
12
|
value: unknown;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
type AttributesPayload = Record<string, AttributeValueRecord[]>;
|
|
15
|
+
interface Money {
|
|
16
16
|
amount_cents: number;
|
|
17
17
|
currency: string;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
interface Measurement {
|
|
20
20
|
amount: number;
|
|
21
21
|
unit: string;
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
interface ResolveOptions {
|
|
24
24
|
locale?: string | null;
|
|
25
25
|
channel?: string | null;
|
|
26
26
|
}
|
|
@@ -30,18 +30,19 @@ export interface ResolveOptions {
|
|
|
30
30
|
* `(locale, null)` → `(null, channel)` → `(null, null)`. Returns
|
|
31
31
|
* `undefined` when nothing matches.
|
|
32
32
|
*/
|
|
33
|
-
|
|
33
|
+
declare function getAttribute(attributes: AttributesPayload, code: string, opts?: ResolveOptions): unknown;
|
|
34
34
|
/**
|
|
35
35
|
* Flatten an entire attribute payload to a `{ code: value }` map for a
|
|
36
36
|
* (locale, channel) — the client-side equivalent of the server's
|
|
37
37
|
* `resolvedAttributes`, for use on list responses where the server doesn't
|
|
38
38
|
* flatten. Codes with no matching value are omitted.
|
|
39
39
|
*/
|
|
40
|
-
|
|
40
|
+
declare function flattenAttributes(attributes: AttributesPayload, opts?: ResolveOptions): Record<string, unknown>;
|
|
41
41
|
/** Narrow an attribute value to Money, or null if it isn't money-shaped. */
|
|
42
|
-
|
|
42
|
+
declare function asMoney(value: unknown): Money | null;
|
|
43
43
|
/** Narrow an attribute value to Measurement, or null if it isn't measurement-shaped. */
|
|
44
|
-
|
|
44
|
+
declare function asMeasurement(value: unknown): Measurement | null;
|
|
45
45
|
/** Format integer-cents Money as a localized currency string. */
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
declare function formatMoney(money: Money, locale?: string): string;
|
|
47
|
+
|
|
48
|
+
export { type AttributeValueRecord, type AttributesPayload, type Measurement, type Money, type ResolveOptions, asMeasurement, asMoney, flattenAttributes, formatMoney, getAttribute };
|
package/dist/attributes.js
CHANGED
|
@@ -1,76 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return undefined;
|
|
19
|
-
const locale = opts.locale ?? null;
|
|
20
|
-
const channel = opts.channel ?? null;
|
|
21
|
-
const layers = [
|
|
22
|
-
[locale, channel],
|
|
23
|
-
[locale, null],
|
|
24
|
-
[null, channel],
|
|
25
|
-
[null, null],
|
|
26
|
-
];
|
|
27
|
-
for (const [l, c] of layers) {
|
|
28
|
-
const hit = records.find((r) => r.locale === l && r.channel === c);
|
|
29
|
-
if (hit)
|
|
30
|
-
return hit.value;
|
|
31
|
-
}
|
|
32
|
-
return undefined;
|
|
1
|
+
// src/attributes.ts
|
|
2
|
+
function getAttribute(attributes, code, opts = {}) {
|
|
3
|
+
const records = attributes[code];
|
|
4
|
+
if (!records || records.length === 0) return void 0;
|
|
5
|
+
const locale = opts.locale ?? null;
|
|
6
|
+
const channel = opts.channel ?? null;
|
|
7
|
+
const layers = [
|
|
8
|
+
[locale, channel],
|
|
9
|
+
[locale, null],
|
|
10
|
+
[null, channel],
|
|
11
|
+
[null, null]
|
|
12
|
+
];
|
|
13
|
+
for (const [l, c] of layers) {
|
|
14
|
+
const hit = records.find((r) => r.locale === l && r.channel === c);
|
|
15
|
+
if (hit) return hit.value;
|
|
16
|
+
}
|
|
17
|
+
return void 0;
|
|
33
18
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const out = {};
|
|
42
|
-
for (const code of Object.keys(attributes)) {
|
|
43
|
-
const v = getAttribute(attributes, code, opts);
|
|
44
|
-
if (v !== undefined)
|
|
45
|
-
out[code] = v;
|
|
46
|
-
}
|
|
47
|
-
return out;
|
|
19
|
+
function flattenAttributes(attributes, opts = {}) {
|
|
20
|
+
const out = {};
|
|
21
|
+
for (const code of Object.keys(attributes)) {
|
|
22
|
+
const v = getAttribute(attributes, code, opts);
|
|
23
|
+
if (v !== void 0) out[code] = v;
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
48
26
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
typeof value.currency === 'string') {
|
|
55
|
-
return value;
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
27
|
+
function asMoney(value) {
|
|
28
|
+
if (value && typeof value === "object" && typeof value.amount_cents === "number" && typeof value.currency === "string") {
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
58
32
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
typeof value.unit === 'string') {
|
|
65
|
-
return value;
|
|
66
|
-
}
|
|
67
|
-
return null;
|
|
33
|
+
function asMeasurement(value) {
|
|
34
|
+
if (value && typeof value === "object" && typeof value.amount === "number" && typeof value.unit === "string") {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
68
38
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}).format(money.amount_cents / 100);
|
|
39
|
+
function formatMoney(money, locale = "en-US") {
|
|
40
|
+
return new Intl.NumberFormat(locale, {
|
|
41
|
+
style: "currency",
|
|
42
|
+
currency: money.currency
|
|
43
|
+
}).format(money.amount_cents / 100);
|
|
75
44
|
}
|
|
76
|
-
|
|
45
|
+
export {
|
|
46
|
+
asMeasurement,
|
|
47
|
+
asMoney,
|
|
48
|
+
flattenAttributes,
|
|
49
|
+
formatMoney,
|
|
50
|
+
getAttribute
|
|
51
|
+
};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
asMeasurement: () => asMeasurement,
|
|
34
|
+
asMoney: () => asMoney,
|
|
35
|
+
collectAll: () => collectAll,
|
|
36
|
+
createMinipimClient: () => createMinipimClient,
|
|
37
|
+
flattenAttributes: () => flattenAttributes,
|
|
38
|
+
formatMoney: () => formatMoney,
|
|
39
|
+
getAttribute: () => getAttribute,
|
|
40
|
+
getErrorMessage: () => getErrorMessage,
|
|
41
|
+
isMinipimError: () => isMinipimError,
|
|
42
|
+
paginate: () => paginate
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(src_exports);
|
|
45
|
+
|
|
46
|
+
// src/client.ts
|
|
47
|
+
var import_openapi_fetch = __toESM(require("openapi-fetch"), 1);
|
|
48
|
+
function createMinipimClient(opts) {
|
|
49
|
+
const headers = {
|
|
50
|
+
"x-organization-id": opts.organizationId,
|
|
51
|
+
...opts.headers ?? {}
|
|
52
|
+
};
|
|
53
|
+
if (opts.apiKey) headers["Authorization"] = `Bearer ${opts.apiKey}`;
|
|
54
|
+
if (opts.userId) headers["x-pim-user-id"] = opts.userId;
|
|
55
|
+
return (0, import_openapi_fetch.default)({
|
|
56
|
+
baseUrl: opts.baseUrl.replace(/\/$/, ""),
|
|
57
|
+
fetch: opts.fetch,
|
|
58
|
+
headers
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/paginate.ts
|
|
63
|
+
async function* paginate(client, path, opts = {}) {
|
|
64
|
+
const pageSize = opts.pageSize ?? 200;
|
|
65
|
+
let offset = 0;
|
|
66
|
+
for (; ; ) {
|
|
67
|
+
const get = client.GET;
|
|
68
|
+
const { data, error, response } = await get(path, {
|
|
69
|
+
params: { query: { ...opts.query ?? {}, limit: pageSize, offset } }
|
|
70
|
+
});
|
|
71
|
+
if (error || !data) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`paginate ${path} failed at offset ${offset} (HTTP ${response?.status})`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
if (Array.isArray(data)) {
|
|
77
|
+
for (const item of data) yield item;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!Array.isArray(data.data)) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`paginate ${path}: response is neither a list envelope nor an array \u2014 this endpoint may not be paginatable`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
for (const item of data.data) yield item;
|
|
86
|
+
const more = data.hasMore ?? data.data.length === pageSize;
|
|
87
|
+
if (!more || data.data.length === 0) return;
|
|
88
|
+
offset += pageSize;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function collectAll(client, path, opts = {}) {
|
|
92
|
+
const out = [];
|
|
93
|
+
for await (const item of paginate(client, path, opts)) out.push(item);
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/errors.ts
|
|
98
|
+
function isMinipimError(value) {
|
|
99
|
+
if (!value || typeof value !== "object") return false;
|
|
100
|
+
const e = value.error;
|
|
101
|
+
return !!e && typeof e === "object" && typeof e.code === "string" && typeof e.message === "string";
|
|
102
|
+
}
|
|
103
|
+
function getErrorMessage(error, fallback = "request failed") {
|
|
104
|
+
return isMinipimError(error) ? error.error.message : fallback;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/attributes.ts
|
|
108
|
+
function getAttribute(attributes, code, opts = {}) {
|
|
109
|
+
const records = attributes[code];
|
|
110
|
+
if (!records || records.length === 0) return void 0;
|
|
111
|
+
const locale = opts.locale ?? null;
|
|
112
|
+
const channel = opts.channel ?? null;
|
|
113
|
+
const layers = [
|
|
114
|
+
[locale, channel],
|
|
115
|
+
[locale, null],
|
|
116
|
+
[null, channel],
|
|
117
|
+
[null, null]
|
|
118
|
+
];
|
|
119
|
+
for (const [l, c] of layers) {
|
|
120
|
+
const hit = records.find((r) => r.locale === l && r.channel === c);
|
|
121
|
+
if (hit) return hit.value;
|
|
122
|
+
}
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
function flattenAttributes(attributes, opts = {}) {
|
|
126
|
+
const out = {};
|
|
127
|
+
for (const code of Object.keys(attributes)) {
|
|
128
|
+
const v = getAttribute(attributes, code, opts);
|
|
129
|
+
if (v !== void 0) out[code] = v;
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
function asMoney(value) {
|
|
134
|
+
if (value && typeof value === "object" && typeof value.amount_cents === "number" && typeof value.currency === "string") {
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
function asMeasurement(value) {
|
|
140
|
+
if (value && typeof value === "object" && typeof value.amount === "number" && typeof value.unit === "string") {
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
function formatMoney(money, locale = "en-US") {
|
|
146
|
+
return new Intl.NumberFormat(locale, {
|
|
147
|
+
style: "currency",
|
|
148
|
+
currency: money.currency
|
|
149
|
+
}).format(money.amount_cents / 100);
|
|
150
|
+
}
|
|
151
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
152
|
+
0 && (module.exports = {
|
|
153
|
+
asMeasurement,
|
|
154
|
+
asMoney,
|
|
155
|
+
collectAll,
|
|
156
|
+
createMinipimClient,
|
|
157
|
+
flattenAttributes,
|
|
158
|
+
formatMoney,
|
|
159
|
+
getAttribute,
|
|
160
|
+
getErrorMessage,
|
|
161
|
+
isMinipimError,
|
|
162
|
+
paginate
|
|
163
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Client } from 'openapi-fetch';
|
|
2
|
+
import { paths } from './openapi.cjs';
|
|
3
|
+
export { components, operations } from './openapi.cjs';
|
|
4
|
+
export { AttributeValueRecord, AttributesPayload, Measurement, Money, ResolveOptions, asMeasurement, asMoney, flattenAttributes, formatMoney, getAttribute } from './attributes.cjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Thin wrapper around `openapi-fetch` that pre-binds the tenancy header and
|
|
8
|
+
* (optionally) an API key. Returns the standard openapi-fetch client, so all
|
|
9
|
+
* its features (request interceptors, raw response access, etc.) work as
|
|
10
|
+
* documented at https://openapi-ts.dev/openapi-fetch/.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
interface CreateMinipimClientOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Base URL of the MiniPim API, e.g. `https://api.minipim.com`. Required.
|
|
16
|
+
* Trailing slashes are normalized.
|
|
17
|
+
*/
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
/**
|
|
20
|
+
* Tenant the client speaks for. Required — every authenticated endpoint
|
|
21
|
+
* needs `x-organization-id`. API keys identify the principal, not the
|
|
22
|
+
* tenant.
|
|
23
|
+
*/
|
|
24
|
+
organizationId: string;
|
|
25
|
+
/**
|
|
26
|
+
* Bearer API key (e.g. `pim_abc123…`). Issue one in the admin under
|
|
27
|
+
* /api-keys. If you're running in dev with `PIM_AUTH=header`, omit this
|
|
28
|
+
* and set `userId` instead.
|
|
29
|
+
*/
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Dev-only header (`x-pim-user-id`). Only set when the deployment is in
|
|
33
|
+
* `header` auth mode. Ignored in `jwt` / `clerk` deployments.
|
|
34
|
+
*/
|
|
35
|
+
userId?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Extra headers merged onto every request — useful for tracing IDs,
|
|
38
|
+
* feature flags, etc. Don't put auth here; use `apiKey`/`userId` so the
|
|
39
|
+
* names stay consistent.
|
|
40
|
+
*/
|
|
41
|
+
headers?: Record<string, string>;
|
|
42
|
+
/**
|
|
43
|
+
* Override `fetch` — pass a polyfill in Node <18 or a wrapped fetch that
|
|
44
|
+
* adds timeouts, retries, telemetry. Defaults to the global `fetch`.
|
|
45
|
+
*/
|
|
46
|
+
fetch?: typeof fetch;
|
|
47
|
+
}
|
|
48
|
+
type MinipimClient = Client<paths>;
|
|
49
|
+
/**
|
|
50
|
+
* Create a typed MiniPim client.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { createMinipimClient } from '@minipim/sdk';
|
|
55
|
+
*
|
|
56
|
+
* const pim = createMinipimClient({
|
|
57
|
+
* baseUrl: 'https://api.minipim.com',
|
|
58
|
+
* organizationId: '00000000-0000-0000-0000-000000000001',
|
|
59
|
+
* apiKey: process.env.MINIPIM_API_KEY!,
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* const { data, error } = await pim.GET('/v1/products', {
|
|
63
|
+
* params: { query: { limit: 50, categoryId: '…' } },
|
|
64
|
+
* });
|
|
65
|
+
* if (error) throw new Error(error.error.message);
|
|
66
|
+
* console.log(data.hasMore, data.data.length);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function createMinipimClient(opts: CreateMinipimClientOptions): MinipimClient;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Generic pagination helper. Every MiniPim list endpoint returns
|
|
73
|
+
* `{ data, limit, offset, hasMore }`; this walks the pages so consumers
|
|
74
|
+
* don't hand-roll the `hasMore` loop. Yields one item at a time.
|
|
75
|
+
*
|
|
76
|
+
* Typed loosely on purpose — openapi-fetch's per-path generics don't
|
|
77
|
+
* compose into a single reusable signature without a lot of conditional-
|
|
78
|
+
* type machinery, and the envelope shape is uniform across list endpoints.
|
|
79
|
+
* The item type is yours to specify via the generic.
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
interface PaginateOptions {
|
|
83
|
+
/** Query params (filters, sort, withTotal, etc). `limit`/`offset` are managed for you. */
|
|
84
|
+
query?: Record<string, unknown>;
|
|
85
|
+
/** Page size. Default 200 (the API max). */
|
|
86
|
+
pageSize?: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Async-iterate every item across all pages of a MiniPim list endpoint.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* import { paginate } from '@minipim/sdk';
|
|
94
|
+
* for await (const product of paginate<Product>(pim, '/v1/products', {
|
|
95
|
+
* query: { status: 'active' },
|
|
96
|
+
* })) {
|
|
97
|
+
* await ingest(product);
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
declare function paginate<T = unknown>(client: MinipimClient, path: string, opts?: PaginateOptions): AsyncGenerator<T, void, unknown>;
|
|
102
|
+
/** Collect every page into an array. Convenience around {@link paginate}. */
|
|
103
|
+
declare function collectAll<T = unknown>(client: MinipimClient, path: string, opts?: PaginateOptions): Promise<T[]>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Error envelope + type guard. Every MiniPim 4xx/5xx returns
|
|
107
|
+
* `{ error: { code, message, details? } }`. openapi-fetch types `res.error`
|
|
108
|
+
* as a union across a path's declared error responses, which is awkward to
|
|
109
|
+
* narrow to `.error.message`. This guard collapses that to a single shape.
|
|
110
|
+
*/
|
|
111
|
+
interface MinipimError {
|
|
112
|
+
error: {
|
|
113
|
+
code: string;
|
|
114
|
+
message: string;
|
|
115
|
+
details?: unknown;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** True when `value` is a MiniPim `{ error: { code, message } }` envelope. */
|
|
119
|
+
declare function isMinipimError(value: unknown): value is MinipimError;
|
|
120
|
+
/**
|
|
121
|
+
* Pull a human-readable message out of an openapi-fetch `error` value,
|
|
122
|
+
* whatever its declared union shape. Falls back to `fallback`.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* const { data, error } = await pim.GET('/v1/products');
|
|
127
|
+
* if (error) throw new Error(getErrorMessage(error, 'request failed'));
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
declare function getErrorMessage(error: unknown, fallback?: string): string;
|
|
131
|
+
|
|
132
|
+
export { type CreateMinipimClientOptions, type MinipimClient, type MinipimError, type PaginateOptions, collectAll, createMinipimClient, getErrorMessage, isMinipimError, paginate, paths };
|