mashroo3 0.1.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 +21 -0
- package/README.md +113 -0
- package/index.d.ts +70 -0
- package/index.js +246 -0
- package/package.json +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mashroo3
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# mashroo3
|
|
2
|
+
|
|
3
|
+
Simple JavaScript client for the Mashroo3 API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install mashroo3
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
const { Mashroo3 } = require("mashroo3");
|
|
15
|
+
|
|
16
|
+
const mashroo3 = new Mashroo3("YOUR_API_KEY");
|
|
17
|
+
|
|
18
|
+
const catalog = await mashroo3.catalog.list();
|
|
19
|
+
console.log(catalog);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Also supported:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
const { mashroo3 } = require("mashroo3");
|
|
26
|
+
const client = new mashroo3("YOUR_API_KEY");
|
|
27
|
+
const orders = await client.orders.list();
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
ESM:
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
import Mashroo3 from "mashroo3";
|
|
34
|
+
|
|
35
|
+
const mashroo3 = new Mashroo3("YOUR_API_KEY");
|
|
36
|
+
const orders = await mashroo3.orders.list();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Constructor
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
new Mashroo3(apiKey, options?)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Options:
|
|
46
|
+
|
|
47
|
+
- `baseUrl` (default: `https://mashroo3.net`)
|
|
48
|
+
- `timeoutMs` (default: `30000`)
|
|
49
|
+
- `fetch` custom fetch implementation (optional)
|
|
50
|
+
|
|
51
|
+
## API
|
|
52
|
+
|
|
53
|
+
### Catalog
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
await mashroo3.catalog.list();
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Customers
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
await mashroo3.customers.list();
|
|
63
|
+
|
|
64
|
+
await mashroo3.customers.create({
|
|
65
|
+
name: "John Doe",
|
|
66
|
+
phone: "+15550000000",
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Orders
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
// Returns latest orders from /api/orders (currently last 10 on server side)
|
|
74
|
+
await mashroo3.orders.list();
|
|
75
|
+
|
|
76
|
+
await mashroo3.orders.get(44);
|
|
77
|
+
|
|
78
|
+
await mashroo3.orders.create({
|
|
79
|
+
customer_id: 12,
|
|
80
|
+
items: [
|
|
81
|
+
{ product_id: 1, qty: 2 },
|
|
82
|
+
{ product_id: 5, qty: 1 }
|
|
83
|
+
],
|
|
84
|
+
paid: 20
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await mashroo3.orders.refund(44, {
|
|
88
|
+
items: [
|
|
89
|
+
{ order_item_id: 101, qty: 1 }
|
|
90
|
+
],
|
|
91
|
+
reason: "Damaged item"
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Low-level request
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
await mashroo3.request("GET", "/api/catalog");
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Error Handling
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
try {
|
|
105
|
+
await mashroo3.orders.get(999999);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (error.name === "Mashroo3Error") {
|
|
108
|
+
console.error(error.message);
|
|
109
|
+
console.error(error.status);
|
|
110
|
+
console.error(error.data);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export type QueryValue =
|
|
2
|
+
| string
|
|
3
|
+
| number
|
|
4
|
+
| boolean
|
|
5
|
+
| null
|
|
6
|
+
| undefined
|
|
7
|
+
| Array<string | number | boolean | null | undefined>;
|
|
8
|
+
|
|
9
|
+
export type QueryParams = Record<string, QueryValue>;
|
|
10
|
+
|
|
11
|
+
export interface Mashroo3Options {
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
fetch?: typeof fetch;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface RequestOptions {
|
|
18
|
+
query?: QueryParams;
|
|
19
|
+
body?: unknown;
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export declare class Mashroo3Error extends Error {
|
|
24
|
+
status: number | null;
|
|
25
|
+
data: unknown;
|
|
26
|
+
code: string | null;
|
|
27
|
+
constructor(
|
|
28
|
+
message: string,
|
|
29
|
+
options?: {
|
|
30
|
+
status?: number | null;
|
|
31
|
+
data?: unknown;
|
|
32
|
+
code?: string | null;
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export declare class Mashroo3 {
|
|
38
|
+
apiKey: string;
|
|
39
|
+
baseUrl: string;
|
|
40
|
+
timeoutMs: number;
|
|
41
|
+
catalog: {
|
|
42
|
+
list: (query?: QueryParams) => Promise<any[]>;
|
|
43
|
+
};
|
|
44
|
+
customers: {
|
|
45
|
+
list: (query?: QueryParams) => Promise<any[]>;
|
|
46
|
+
create: (payload: unknown) => Promise<any>;
|
|
47
|
+
};
|
|
48
|
+
orders: {
|
|
49
|
+
list: (query?: QueryParams) => Promise<any[]>;
|
|
50
|
+
get: (orderId: number) => Promise<any>;
|
|
51
|
+
create: (payload: unknown) => Promise<any>;
|
|
52
|
+
refund: (orderId: number, payload: unknown) => Promise<any>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
constructor(apiKey: string, options?: Mashroo3Options);
|
|
56
|
+
request(method: string, path: string, options?: RequestOptions): Promise<any>;
|
|
57
|
+
|
|
58
|
+
listCatalog(query?: QueryParams): Promise<any[]>;
|
|
59
|
+
listCustomers(query?: QueryParams): Promise<any[]>;
|
|
60
|
+
createCustomer(payload: unknown): Promise<any>;
|
|
61
|
+
listOrders(query?: QueryParams): Promise<any[]>;
|
|
62
|
+
getOrder(orderId: number): Promise<any>;
|
|
63
|
+
createOrder(payload: unknown): Promise<any>;
|
|
64
|
+
refundOrder(orderId: number, payload: unknown): Promise<any>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export declare function mashroo3(apiKey: string, options?: Mashroo3Options): Mashroo3;
|
|
68
|
+
|
|
69
|
+
declare const _default: typeof Mashroo3;
|
|
70
|
+
export default _default;
|
package/index.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
class Mashroo3Error extends Error {
|
|
4
|
+
constructor(message, options = {}) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "Mashroo3Error";
|
|
7
|
+
this.status = options.status ?? null;
|
|
8
|
+
this.data = options.data ?? null;
|
|
9
|
+
this.code = options.code ?? null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class Mashroo3 {
|
|
14
|
+
constructor(apiKey, options = {}) {
|
|
15
|
+
if (typeof apiKey !== "string" || apiKey.trim() === "") {
|
|
16
|
+
throw new TypeError("Mashroo3 API key is required.");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const providedFetch = options.fetch || globalThis.fetch;
|
|
20
|
+
if (typeof providedFetch !== "function") {
|
|
21
|
+
throw new TypeError(
|
|
22
|
+
"A fetch implementation is required. Use Node.js >= 18 or pass { fetch } in options."
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.apiKey = apiKey.trim();
|
|
27
|
+
this.baseUrl = String(options.baseUrl || "https://mashroo3.net").replace(
|
|
28
|
+
/\/+$/,
|
|
29
|
+
""
|
|
30
|
+
);
|
|
31
|
+
this.timeoutMs =
|
|
32
|
+
Number.isFinite(options.timeoutMs) && options.timeoutMs > 0
|
|
33
|
+
? Number(options.timeoutMs)
|
|
34
|
+
: 30000;
|
|
35
|
+
this._fetch = providedFetch;
|
|
36
|
+
|
|
37
|
+
this.catalog = {
|
|
38
|
+
list: (query) => this.listCatalog(query),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
this.customers = {
|
|
42
|
+
list: (query) => this.listCustomers(query),
|
|
43
|
+
create: (payload) => this.createCustomer(payload),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
this.orders = {
|
|
47
|
+
list: (query) => this.listOrders(query),
|
|
48
|
+
get: (orderId) => this.getOrder(orderId),
|
|
49
|
+
create: (payload) => this.createOrder(payload),
|
|
50
|
+
refund: (orderId, payload) => this.refundOrder(orderId, payload),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async request(method, path, options = {}) {
|
|
55
|
+
return this._request(method, path, options);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async listCatalog(query = {}) {
|
|
59
|
+
const payload = await this._request("GET", "/api/catalog", { query });
|
|
60
|
+
return this._extractList(payload, ["products", "catalog", "items"]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async listCustomers(query = {}) {
|
|
64
|
+
const payload = await this._request("GET", "/api/customers", { query });
|
|
65
|
+
return this._extractList(payload, ["customers", "items"]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async createCustomer(payload) {
|
|
69
|
+
const response = await this._request("POST", "/api/customers", { body: payload });
|
|
70
|
+
const data = this._extractData(response);
|
|
71
|
+
if (data && typeof data === "object" && data.customer) {
|
|
72
|
+
return data.customer;
|
|
73
|
+
}
|
|
74
|
+
return data;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async listOrders(query = {}) {
|
|
78
|
+
const payload = await this._request("GET", "/api/orders", { query });
|
|
79
|
+
return this._extractList(payload, ["orders", "items"]);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async getOrder(orderId) {
|
|
83
|
+
const normalizedOrderId = this._validateOrderId(orderId);
|
|
84
|
+
const payload = await this._request("GET", `/api/orders/${normalizedOrderId}`);
|
|
85
|
+
return this._extractData(payload);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async createOrder(payload) {
|
|
89
|
+
const response = await this._request("POST", "/api/orders", { body: payload });
|
|
90
|
+
const data = this._extractData(response);
|
|
91
|
+
if (data && typeof data === "object" && data.order) {
|
|
92
|
+
return data.order;
|
|
93
|
+
}
|
|
94
|
+
return data;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async refundOrder(orderId, payload) {
|
|
98
|
+
const normalizedOrderId = this._validateOrderId(orderId);
|
|
99
|
+
const response = await this._request(
|
|
100
|
+
"POST",
|
|
101
|
+
`/api/orders/${normalizedOrderId}/refund`,
|
|
102
|
+
{ body: payload }
|
|
103
|
+
);
|
|
104
|
+
return this._extractData(response);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_validateOrderId(orderId) {
|
|
108
|
+
const parsed = Number(orderId);
|
|
109
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
110
|
+
throw new TypeError("orderId must be a positive integer.");
|
|
111
|
+
}
|
|
112
|
+
return parsed;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_buildUrl(path, query) {
|
|
116
|
+
const normalizedPath = String(path || "").startsWith("/") ? path : `/${path}`;
|
|
117
|
+
const url = new URL(`${this.baseUrl}${normalizedPath}`);
|
|
118
|
+
|
|
119
|
+
if (query && typeof query === "object") {
|
|
120
|
+
for (const [key, value] of Object.entries(query)) {
|
|
121
|
+
if (value === undefined || value === null) continue;
|
|
122
|
+
if (Array.isArray(value)) {
|
|
123
|
+
for (const item of value) {
|
|
124
|
+
if (item === undefined || item === null) continue;
|
|
125
|
+
url.searchParams.append(key, String(item));
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
url.searchParams.set(key, String(value));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return url.toString();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
_extractData(payload) {
|
|
137
|
+
if (payload && typeof payload === "object" && "data" in payload) {
|
|
138
|
+
return payload.data;
|
|
139
|
+
}
|
|
140
|
+
return payload;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
_extractList(payload, listKeys) {
|
|
144
|
+
const data = this._extractData(payload);
|
|
145
|
+
if (Array.isArray(data)) return data;
|
|
146
|
+
|
|
147
|
+
if (data && typeof data === "object") {
|
|
148
|
+
for (const key of listKeys) {
|
|
149
|
+
if (Array.isArray(data[key])) return data[key];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
_extractErrorMessage(payload) {
|
|
157
|
+
if (!payload || typeof payload !== "object") return null;
|
|
158
|
+
const message = payload.message ?? payload.error ?? payload.errors;
|
|
159
|
+
|
|
160
|
+
if (typeof message === "string" && message.trim() !== "") return message;
|
|
161
|
+
if (Array.isArray(message) && message.length > 0) return String(message[0]);
|
|
162
|
+
if (message && typeof message === "object") {
|
|
163
|
+
const values = Object.values(message);
|
|
164
|
+
if (values.length > 0) return String(values[0]);
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async _request(method, path, options = {}) {
|
|
170
|
+
const upperMethod = String(method || "GET").toUpperCase();
|
|
171
|
+
const url = this._buildUrl(path, options.query);
|
|
172
|
+
|
|
173
|
+
const controller = new AbortController();
|
|
174
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
175
|
+
|
|
176
|
+
let response;
|
|
177
|
+
try {
|
|
178
|
+
response = await this._fetch(url, {
|
|
179
|
+
method: upperMethod,
|
|
180
|
+
headers: {
|
|
181
|
+
Accept: "application/json",
|
|
182
|
+
"Content-Type": "application/json",
|
|
183
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
184
|
+
"X-API-Key": this.apiKey,
|
|
185
|
+
"x-api-key": this.apiKey,
|
|
186
|
+
...(options.headers || {}),
|
|
187
|
+
},
|
|
188
|
+
body:
|
|
189
|
+
options.body === undefined || upperMethod === "GET"
|
|
190
|
+
? undefined
|
|
191
|
+
: JSON.stringify(options.body),
|
|
192
|
+
signal: controller.signal,
|
|
193
|
+
});
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if (error && error.name === "AbortError") {
|
|
196
|
+
throw new Mashroo3Error(
|
|
197
|
+
`Request timeout after ${this.timeoutMs}ms for ${upperMethod} ${path}`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
throw new Mashroo3Error(
|
|
201
|
+
`Network error while calling ${upperMethod} ${path}: ${
|
|
202
|
+
error && error.message ? error.message : String(error)
|
|
203
|
+
}`
|
|
204
|
+
);
|
|
205
|
+
} finally {
|
|
206
|
+
clearTimeout(timeout);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const rawBody = await response.text();
|
|
210
|
+
let parsedBody = null;
|
|
211
|
+
if (rawBody) {
|
|
212
|
+
try {
|
|
213
|
+
parsedBody = JSON.parse(rawBody);
|
|
214
|
+
} catch (_) {
|
|
215
|
+
parsedBody = null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (!response.ok) {
|
|
220
|
+
throw new Mashroo3Error(
|
|
221
|
+
this._extractErrorMessage(parsedBody) ||
|
|
222
|
+
`Request failed with status ${response.status}`,
|
|
223
|
+
{ status: response.status, data: parsedBody ?? rawBody }
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (parsedBody && typeof parsedBody === "object" && parsedBody.ok === false) {
|
|
228
|
+
throw new Mashroo3Error(
|
|
229
|
+
this._extractErrorMessage(parsedBody) || "Mashroo3 API returned ok=false",
|
|
230
|
+
{ status: response.status, data: parsedBody }
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return parsedBody;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function mashroo3(apiKey, options) {
|
|
239
|
+
return new Mashroo3(apiKey, options);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
module.exports = Mashroo3;
|
|
243
|
+
module.exports.default = Mashroo3;
|
|
244
|
+
module.exports.Mashroo3 = Mashroo3;
|
|
245
|
+
module.exports.mashroo3 = mashroo3;
|
|
246
|
+
module.exports.Mashroo3Error = Mashroo3Error;
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mashroo3",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Simple JavaScript client for the Mashroo3 API.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"import": "./index.js",
|
|
11
|
+
"require": "./index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"index.js",
|
|
19
|
+
"index.d.ts",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"keywords": [
|
|
24
|
+
"mashroo3",
|
|
25
|
+
"api",
|
|
26
|
+
"sdk",
|
|
27
|
+
"orders",
|
|
28
|
+
"catalog",
|
|
29
|
+
"inventory"
|
|
30
|
+
],
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
}
|