@moonbase.sh/storefront-api 0.1.78
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/dist/index.cjs +685 -0
- package/dist/index.d.cts +11684 -0
- package/dist/index.d.ts +11684 -0
- package/dist/index.js +640 -0
- package/package.json +30 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
// src/identity/endpoints.ts
|
|
2
|
+
import fetch from "cross-fetch";
|
|
3
|
+
|
|
4
|
+
// src/utils/problemHandler.ts
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
// src/utils/errors.ts
|
|
8
|
+
var NotAuthorizedError = class extends Error {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
this.name = "NotAuthorizedError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var NotAuthenticatedError = class extends Error {
|
|
15
|
+
constructor() {
|
|
16
|
+
super();
|
|
17
|
+
this.name = "NotAuthenticatedError";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var NotFoundError = class extends Error {
|
|
21
|
+
constructor() {
|
|
22
|
+
super();
|
|
23
|
+
this.name = "NotFoundError";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// src/utils/problemHandler.ts
|
|
28
|
+
var problemDetailsSchema = z.object({
|
|
29
|
+
type: z.string(),
|
|
30
|
+
title: z.string(),
|
|
31
|
+
detail: z.string().optional(),
|
|
32
|
+
status: z.number()
|
|
33
|
+
});
|
|
34
|
+
async function handleResponseProblem(response) {
|
|
35
|
+
if (response.status === 404)
|
|
36
|
+
throw new NotFoundError();
|
|
37
|
+
if (response.status === 401)
|
|
38
|
+
throw new NotAuthenticatedError();
|
|
39
|
+
if (response.status === 403)
|
|
40
|
+
throw new NotAuthorizedError();
|
|
41
|
+
let problemDetails;
|
|
42
|
+
try {
|
|
43
|
+
const json = await response.json();
|
|
44
|
+
problemDetails = problemDetailsSchema.parse(json);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
throw new Error("An unknown problem occurred");
|
|
47
|
+
}
|
|
48
|
+
if (problemDetails.detail)
|
|
49
|
+
throw new Error(problemDetails.detail);
|
|
50
|
+
if (problemDetails.title)
|
|
51
|
+
throw new Error(problemDetails.title);
|
|
52
|
+
throw new Error("An unknown problem occurred");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/identity/schemas.ts
|
|
56
|
+
import { z as z2 } from "zod";
|
|
57
|
+
var addressSchema = z2.object({
|
|
58
|
+
countryCode: z2.string(),
|
|
59
|
+
streetAddress1: z2.string(),
|
|
60
|
+
streetAddress2: z2.string().nullable(),
|
|
61
|
+
locality: z2.string().nullable(),
|
|
62
|
+
region: z2.string().nullable(),
|
|
63
|
+
postCode: z2.string()
|
|
64
|
+
});
|
|
65
|
+
var communicationPreferencesSchema = z2.object({
|
|
66
|
+
newsletterOptIn: z2.boolean()
|
|
67
|
+
// productUpdatesOptIn: z.boolean(), // TODO: Enable when relevant
|
|
68
|
+
});
|
|
69
|
+
var userSchema = z2.object({
|
|
70
|
+
id: z2.string(),
|
|
71
|
+
email: z2.string(),
|
|
72
|
+
name: z2.string(),
|
|
73
|
+
tenantId: z2.string(),
|
|
74
|
+
address: addressSchema.optional(),
|
|
75
|
+
communicationPreferences: communicationPreferencesSchema
|
|
76
|
+
});
|
|
77
|
+
var identityUserSchema = userSchema.and(z2.object({
|
|
78
|
+
accessToken: z2.string(),
|
|
79
|
+
refreshToken: z2.string()
|
|
80
|
+
}));
|
|
81
|
+
|
|
82
|
+
// src/identity/endpoints.ts
|
|
83
|
+
var IdentityEndpoints = class {
|
|
84
|
+
constructor(api, tokenStore) {
|
|
85
|
+
this.api = api;
|
|
86
|
+
this.tokenStore = tokenStore;
|
|
87
|
+
}
|
|
88
|
+
async get() {
|
|
89
|
+
const response = await this.api.authenticatedFetch("/api/customer/meta/user");
|
|
90
|
+
return userSchema.parse(response);
|
|
91
|
+
}
|
|
92
|
+
async signIn(email, password) {
|
|
93
|
+
const response = await fetch(`${this.api.baseUrl}/api/customer/identity/sign-in?email=${email}&scheme=JWT`, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: {
|
|
96
|
+
"Accept": "application/json",
|
|
97
|
+
"Content-Type": "text/plain",
|
|
98
|
+
"x-mb-cors": "1"
|
|
99
|
+
},
|
|
100
|
+
body: password
|
|
101
|
+
});
|
|
102
|
+
if (response.status >= 400)
|
|
103
|
+
await handleResponseProblem(response);
|
|
104
|
+
const data = await response.json();
|
|
105
|
+
const user = identityUserSchema.parse(data);
|
|
106
|
+
this.tokenStore.setUser(user);
|
|
107
|
+
return user;
|
|
108
|
+
}
|
|
109
|
+
async signUp(name, email, password, address, acceptedPrivacyPolicy, acceptedTermsAndConditions, communicationOptIn) {
|
|
110
|
+
const response = await this.api.fetch(`/api/customer/identity/sign-up?scheme=JWT&communicationOptIn=${communicationOptIn ? "true" : "false"}`, "POST", {
|
|
111
|
+
name,
|
|
112
|
+
email,
|
|
113
|
+
password,
|
|
114
|
+
address,
|
|
115
|
+
acceptedPrivacyPolicy,
|
|
116
|
+
acceptedTermsAndConditions
|
|
117
|
+
});
|
|
118
|
+
const user = identityUserSchema.parse(response);
|
|
119
|
+
this.tokenStore.setUser(user);
|
|
120
|
+
return user;
|
|
121
|
+
}
|
|
122
|
+
async update(name, email, emailConfirmationToken, communicationPreferences) {
|
|
123
|
+
const response = await this.api.authenticatedFetch("/api/customer/identity", "PATCH", {
|
|
124
|
+
name,
|
|
125
|
+
email,
|
|
126
|
+
emailConfirmationToken,
|
|
127
|
+
communicationPreferences
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
needsEmailConfirmationToken: response.status === 201
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async setPassword(currentPassword, newPassword) {
|
|
134
|
+
await this.api.authenticatedFetch(`/api/customer/identity/set-password`, "POST", {
|
|
135
|
+
currentPassword,
|
|
136
|
+
newPassword
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
async forgotPassword(email) {
|
|
140
|
+
await this.api.fetch(`/api/customer/identity/forgot-password?email=${encodeURIComponent(email)}`, "POST");
|
|
141
|
+
}
|
|
142
|
+
async resetPassword(email, newPassword, code) {
|
|
143
|
+
const response = await fetch(`${this.api.baseUrl}/api/customer/identity/reset-password?email=${encodeURIComponent(email)}&code=${code}`, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: {
|
|
146
|
+
"Accept": "application/json",
|
|
147
|
+
"Content-Type": "text/plain",
|
|
148
|
+
"x-mb-cors": "1"
|
|
149
|
+
},
|
|
150
|
+
body: newPassword
|
|
151
|
+
});
|
|
152
|
+
if (response.status >= 400)
|
|
153
|
+
await handleResponseProblem(response);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/globalSchemas.ts
|
|
158
|
+
import { z as z3 } from "zod";
|
|
159
|
+
var priceCollectionSchema = z3.record(z3.number());
|
|
160
|
+
var percentageOffDiscountSchema = z3.object({
|
|
161
|
+
type: z3.literal("PercentageOffDiscount"),
|
|
162
|
+
name: z3.string(),
|
|
163
|
+
description: z3.string().optional(),
|
|
164
|
+
percentage: z3.number(),
|
|
165
|
+
total: priceCollectionSchema
|
|
166
|
+
});
|
|
167
|
+
var flatAmountOffDiscountSchema = z3.object({
|
|
168
|
+
type: z3.literal("FlatAmountOffDiscount"),
|
|
169
|
+
name: z3.string(),
|
|
170
|
+
description: z3.string().optional(),
|
|
171
|
+
total: priceCollectionSchema
|
|
172
|
+
});
|
|
173
|
+
var discountSchema = z3.discriminatedUnion("type", [
|
|
174
|
+
percentageOffDiscountSchema,
|
|
175
|
+
flatAmountOffDiscountSchema
|
|
176
|
+
]);
|
|
177
|
+
var pricingVariationSchema = z3.object({
|
|
178
|
+
id: z3.string(),
|
|
179
|
+
name: z3.string(),
|
|
180
|
+
originalPrice: priceCollectionSchema,
|
|
181
|
+
price: priceCollectionSchema,
|
|
182
|
+
hasDiscount: z3.boolean(),
|
|
183
|
+
discount: discountSchema.optional()
|
|
184
|
+
});
|
|
185
|
+
function paged(itemSchema) {
|
|
186
|
+
return z3.object({
|
|
187
|
+
items: z3.array(itemSchema),
|
|
188
|
+
hasMore: z3.boolean(),
|
|
189
|
+
next: z3.string().nullable()
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
function quantifiable(itemSchema) {
|
|
193
|
+
return z3.object({
|
|
194
|
+
value: itemSchema,
|
|
195
|
+
quantity: z3.number()
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/licenses/schemas.ts
|
|
200
|
+
import { z as z5 } from "zod";
|
|
201
|
+
|
|
202
|
+
// src/products/schemas.ts
|
|
203
|
+
import { z as z4 } from "zod";
|
|
204
|
+
|
|
205
|
+
// src/products/models.ts
|
|
206
|
+
var Platform = /* @__PURE__ */ ((Platform2) => {
|
|
207
|
+
Platform2["Universal"] = "Universal";
|
|
208
|
+
Platform2["Windows"] = "Windows";
|
|
209
|
+
Platform2["Linux"] = "Linux";
|
|
210
|
+
Platform2["Mac"] = "Mac";
|
|
211
|
+
return Platform2;
|
|
212
|
+
})(Platform || {});
|
|
213
|
+
|
|
214
|
+
// src/products/schemas.ts
|
|
215
|
+
var downloadSchema = z4.object({
|
|
216
|
+
name: z4.string(),
|
|
217
|
+
key: z4.string(),
|
|
218
|
+
platform: z4.nativeEnum(Platform),
|
|
219
|
+
size: z4.number(),
|
|
220
|
+
path: z4.string().nullable()
|
|
221
|
+
});
|
|
222
|
+
var productSummarySchema = z4.object({
|
|
223
|
+
id: z4.string(),
|
|
224
|
+
name: z4.string(),
|
|
225
|
+
tagline: z4.string(),
|
|
226
|
+
website: z4.string().optional(),
|
|
227
|
+
iconUrl: z4.string().optional(),
|
|
228
|
+
numberOfLicenses: z4.number().optional(),
|
|
229
|
+
numberOfTrials: z4.number().optional(),
|
|
230
|
+
currentActivations: z4.number().optional(),
|
|
231
|
+
maxActivations: z4.number().optional(),
|
|
232
|
+
currentVersion: z4.string().nullable(),
|
|
233
|
+
downloadsNeedsUser: z4.boolean(),
|
|
234
|
+
downloadsNeedsOwnership: z4.boolean(),
|
|
235
|
+
downloads: z4.array(downloadSchema).optional()
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// src/licenses/models.ts
|
|
239
|
+
var LicenseStatus = /* @__PURE__ */ ((LicenseStatus2) => {
|
|
240
|
+
LicenseStatus2["Active"] = "Active";
|
|
241
|
+
LicenseStatus2["Revoked"] = "Revoked";
|
|
242
|
+
return LicenseStatus2;
|
|
243
|
+
})(LicenseStatus || {});
|
|
244
|
+
var ActivationStatus = /* @__PURE__ */ ((ActivationStatus2) => {
|
|
245
|
+
ActivationStatus2["Active"] = "Active";
|
|
246
|
+
ActivationStatus2["Revoked"] = "Revoked";
|
|
247
|
+
return ActivationStatus2;
|
|
248
|
+
})(ActivationStatus || {});
|
|
249
|
+
var ActivationMethod = /* @__PURE__ */ ((ActivationMethod2) => {
|
|
250
|
+
ActivationMethod2["Online"] = "Online";
|
|
251
|
+
ActivationMethod2["Offline"] = "Offline";
|
|
252
|
+
return ActivationMethod2;
|
|
253
|
+
})(ActivationMethod || {});
|
|
254
|
+
|
|
255
|
+
// src/licenses/schemas.ts
|
|
256
|
+
var licenseSchema = z5.object({
|
|
257
|
+
id: z5.string(),
|
|
258
|
+
status: z5.nativeEnum(LicenseStatus),
|
|
259
|
+
product: productSummarySchema.optional(),
|
|
260
|
+
activeNumberOfActivations: z5.number(),
|
|
261
|
+
maxNumberOfActivations: z5.number(),
|
|
262
|
+
createdAt: z5.coerce.date()
|
|
263
|
+
});
|
|
264
|
+
var activationSchema = z5.object({
|
|
265
|
+
id: z5.string(),
|
|
266
|
+
licenseId: z5.string(),
|
|
267
|
+
name: z5.string(),
|
|
268
|
+
status: z5.nativeEnum(ActivationStatus),
|
|
269
|
+
activationMethod: z5.nativeEnum(ActivationMethod),
|
|
270
|
+
lastValidatedAt: z5.coerce.date().nullable()
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// src/licenses/endpoints.ts
|
|
274
|
+
var LicenseEndpoints = class {
|
|
275
|
+
constructor(api) {
|
|
276
|
+
this.api = api;
|
|
277
|
+
}
|
|
278
|
+
async get(nextUrl) {
|
|
279
|
+
const response = await this.api.authenticatedFetch(nextUrl || "/api/customer/licenses");
|
|
280
|
+
return paged(licenseSchema).parse(response);
|
|
281
|
+
}
|
|
282
|
+
async getActivations(licenseId, nextUrl) {
|
|
283
|
+
const response = await this.api.authenticatedFetch(
|
|
284
|
+
nextUrl || `/api/customer/licenses/${licenseId}/activations`
|
|
285
|
+
);
|
|
286
|
+
return paged(activationSchema).parse(response);
|
|
287
|
+
}
|
|
288
|
+
async revokeActivation(licenseId, activationId) {
|
|
289
|
+
await this.api.authenticatedFetch(`/api/customer/licenses/${licenseId}/activations/${activationId}/revoke`);
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// src/orders/schemas.ts
|
|
294
|
+
import { z as z7 } from "zod";
|
|
295
|
+
|
|
296
|
+
// src/storefront/schemas.ts
|
|
297
|
+
import { z as z6 } from "zod";
|
|
298
|
+
var storefrontProductSchema = z6.object({
|
|
299
|
+
id: z6.string(),
|
|
300
|
+
name: z6.string(),
|
|
301
|
+
tagline: z6.string(),
|
|
302
|
+
iconUrl: z6.string().nullable(),
|
|
303
|
+
owned: z6.boolean(),
|
|
304
|
+
defaultVariation: pricingVariationSchema.optional(),
|
|
305
|
+
variations: pricingVariationSchema.array().optional(),
|
|
306
|
+
type: z6.void().transform(() => "product").pipe(z6.literal("product"))
|
|
307
|
+
});
|
|
308
|
+
var storefrontBundleSchema = z6.object({
|
|
309
|
+
id: z6.string(),
|
|
310
|
+
name: z6.string(),
|
|
311
|
+
tagline: z6.string(),
|
|
312
|
+
iconUrl: z6.string().nullable(),
|
|
313
|
+
owned: z6.boolean(),
|
|
314
|
+
partial: z6.boolean(),
|
|
315
|
+
products: storefrontProductSchema.and(z6.object({
|
|
316
|
+
included: z6.boolean()
|
|
317
|
+
})).array(),
|
|
318
|
+
defaultVariation: pricingVariationSchema.optional(),
|
|
319
|
+
variations: pricingVariationSchema.array().optional(),
|
|
320
|
+
type: z6.void().transform(() => "bundle").pipe(z6.literal("bundle"))
|
|
321
|
+
});
|
|
322
|
+
var storefrontSchema = z6.object({
|
|
323
|
+
suggestedCurrency: z6.string(),
|
|
324
|
+
products: storefrontProductSchema.array(),
|
|
325
|
+
bundles: storefrontBundleSchema.array()
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// src/orders/models.ts
|
|
329
|
+
var OrderStatus = /* @__PURE__ */ ((OrderStatus2) => {
|
|
330
|
+
OrderStatus2["Open"] = "Open";
|
|
331
|
+
OrderStatus2["PaymentRequested"] = "PaymentRequested";
|
|
332
|
+
OrderStatus2["Completed"] = "Completed";
|
|
333
|
+
OrderStatus2["Fulfilled"] = "Fulfilled";
|
|
334
|
+
OrderStatus2["Returned"] = "Returned";
|
|
335
|
+
OrderStatus2["Failed"] = "Failed";
|
|
336
|
+
return OrderStatus2;
|
|
337
|
+
})(OrderStatus || {});
|
|
338
|
+
|
|
339
|
+
// src/orders/schemas.ts
|
|
340
|
+
var couponSchema = z7.object({
|
|
341
|
+
code: z7.string(),
|
|
342
|
+
name: z7.string(),
|
|
343
|
+
description: z7.string()
|
|
344
|
+
});
|
|
345
|
+
var percentageOffDiscountSchema2 = z7.object({
|
|
346
|
+
type: z7.literal("PercentageOffDiscount"),
|
|
347
|
+
name: z7.string(),
|
|
348
|
+
description: z7.string().optional(),
|
|
349
|
+
percentage: z7.number(),
|
|
350
|
+
total: priceCollectionSchema.optional(),
|
|
351
|
+
isExclusive: z7.boolean()
|
|
352
|
+
});
|
|
353
|
+
var flatAmountOffDiscountSchema2 = z7.object({
|
|
354
|
+
type: z7.literal("FlatAmountOffDiscount"),
|
|
355
|
+
name: z7.string(),
|
|
356
|
+
description: z7.string().optional(),
|
|
357
|
+
total: priceCollectionSchema.optional(),
|
|
358
|
+
isExclusive: z7.boolean()
|
|
359
|
+
});
|
|
360
|
+
var discountSchema2 = z7.discriminatedUnion("type", [
|
|
361
|
+
percentageOffDiscountSchema2,
|
|
362
|
+
flatAmountOffDiscountSchema2
|
|
363
|
+
]);
|
|
364
|
+
var openProductLineItem = z7.object({
|
|
365
|
+
id: z7.string(),
|
|
366
|
+
type: z7.literal("Product"),
|
|
367
|
+
productId: z7.string(),
|
|
368
|
+
quantity: z7.number(),
|
|
369
|
+
variationId: z7.string(),
|
|
370
|
+
price: priceCollectionSchema.optional(),
|
|
371
|
+
variation: pricingVariationSchema.optional(),
|
|
372
|
+
product: storefrontProductSchema.optional(),
|
|
373
|
+
appliedDiscount: discountSchema2.optional()
|
|
374
|
+
});
|
|
375
|
+
var openBundleLineItem = z7.object({
|
|
376
|
+
id: z7.string(),
|
|
377
|
+
type: z7.literal("Bundle"),
|
|
378
|
+
bundleId: z7.string(),
|
|
379
|
+
quantity: z7.number(),
|
|
380
|
+
variationId: z7.string(),
|
|
381
|
+
price: priceCollectionSchema.optional(),
|
|
382
|
+
variation: pricingVariationSchema.optional(),
|
|
383
|
+
bundle: storefrontBundleSchema.optional(),
|
|
384
|
+
appliedDiscount: discountSchema2.optional()
|
|
385
|
+
});
|
|
386
|
+
var openOrderLineItem = z7.discriminatedUnion("type", [
|
|
387
|
+
openProductLineItem,
|
|
388
|
+
openBundleLineItem
|
|
389
|
+
]);
|
|
390
|
+
var openOrderSchema = z7.object({
|
|
391
|
+
id: z7.string(),
|
|
392
|
+
status: z7.literal("Open" /* Open */),
|
|
393
|
+
currency: z7.string(),
|
|
394
|
+
items: openOrderLineItem.array(),
|
|
395
|
+
couponsApplied: couponSchema.array(),
|
|
396
|
+
checkoutUrl: z7.string().optional()
|
|
397
|
+
});
|
|
398
|
+
var orderSchema = z7.discriminatedUnion("status", [
|
|
399
|
+
openOrderSchema
|
|
400
|
+
]);
|
|
401
|
+
|
|
402
|
+
// src/orders/endpoints.ts
|
|
403
|
+
var OrderEndpoints = class {
|
|
404
|
+
constructor(api) {
|
|
405
|
+
this.api = api;
|
|
406
|
+
}
|
|
407
|
+
async get(orderId) {
|
|
408
|
+
const response = await this.api.fetch(`/api/customer/orders/${orderId}`);
|
|
409
|
+
return orderSchema.parse(response);
|
|
410
|
+
}
|
|
411
|
+
async pushContent(order, checkout) {
|
|
412
|
+
const response = await this.api.fetch(
|
|
413
|
+
`/api/customer/orders/${order.id}${checkout ? `?checkout=true&returnUrl=${encodeURIComponent(checkout.returnUrl)}` : ""}`,
|
|
414
|
+
"PATCH",
|
|
415
|
+
{
|
|
416
|
+
currency: order.currency,
|
|
417
|
+
items: order.items
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
return openOrderSchema.parse(response);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
// src/products/endpoints.ts
|
|
425
|
+
var ProductEndpoints = class {
|
|
426
|
+
constructor(api) {
|
|
427
|
+
this.api = api;
|
|
428
|
+
}
|
|
429
|
+
async getOwned(nextUrl) {
|
|
430
|
+
const response = await this.api.authenticatedFetch(nextUrl || "/api/customer/products");
|
|
431
|
+
return paged(productSummarySchema).parse(response);
|
|
432
|
+
}
|
|
433
|
+
async getLicenses(productId, nextUrl) {
|
|
434
|
+
const response = await this.api.authenticatedFetch(nextUrl || `/api/customer/products/${productId}/licenses`);
|
|
435
|
+
return paged(licenseSchema).parse(response);
|
|
436
|
+
}
|
|
437
|
+
async getActivations(productId, nextUrl) {
|
|
438
|
+
const response = await this.api.authenticatedFetch(nextUrl || `/api/customer/products/${productId}/licenses/activations`);
|
|
439
|
+
return paged(activationSchema).parse(response);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
// src/storefront/endpoints.ts
|
|
444
|
+
var StorefrontEndpoints = class {
|
|
445
|
+
constructor(api) {
|
|
446
|
+
this.api = api;
|
|
447
|
+
}
|
|
448
|
+
async get() {
|
|
449
|
+
const response = await this.api.fetch("/api/customer/storefront");
|
|
450
|
+
return storefrontSchema.parse(response);
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// src/utils/api.ts
|
|
455
|
+
import fetch2 from "cross-fetch";
|
|
456
|
+
var MoonbaseApi = class {
|
|
457
|
+
constructor(baseUrl, tokenStore) {
|
|
458
|
+
this.baseUrl = baseUrl;
|
|
459
|
+
this.tokenStore = tokenStore;
|
|
460
|
+
}
|
|
461
|
+
async authenticatedFetch(path, method, body) {
|
|
462
|
+
if (!this.tokenStore.hasAccessToken)
|
|
463
|
+
throw new NotAuthenticatedError();
|
|
464
|
+
return await this.fetch(path, method, body);
|
|
465
|
+
}
|
|
466
|
+
async fetch(path, method, body) {
|
|
467
|
+
const accessToken = await this.tokenStore.getAccessToken();
|
|
468
|
+
const response = await fetch2(this.baseUrl + path, {
|
|
469
|
+
method: method || "GET",
|
|
470
|
+
mode: "cors",
|
|
471
|
+
headers: {
|
|
472
|
+
"Accept": "application/json",
|
|
473
|
+
"Content-Type": "application/json",
|
|
474
|
+
// While this fetch can be anonymous, we add the token if we have it
|
|
475
|
+
...accessToken ? { Authorization: `Bearer ${accessToken}` } : {},
|
|
476
|
+
// Force CORS on all calls
|
|
477
|
+
"x-mb-cors": "1"
|
|
478
|
+
},
|
|
479
|
+
body: body ? JSON.stringify(body) : void 0
|
|
480
|
+
});
|
|
481
|
+
if (response.status >= 400)
|
|
482
|
+
await handleResponseProblem(response);
|
|
483
|
+
return await response.json();
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// src/utils/tokenStore.ts
|
|
488
|
+
import fetch3 from "cross-fetch";
|
|
489
|
+
var _TokenStore = class _TokenStore {
|
|
490
|
+
constructor(configuration) {
|
|
491
|
+
this.configuration = configuration;
|
|
492
|
+
this.tokens = null;
|
|
493
|
+
this.refreshTimeoutId = null;
|
|
494
|
+
this.refreshPromise = null;
|
|
495
|
+
if (typeof window !== "undefined") {
|
|
496
|
+
window.addEventListener("storage", (event) => this.handleStorageUpdate(event));
|
|
497
|
+
const storedTokens = localStorage.getItem(_TokenStore.storageKey);
|
|
498
|
+
if (storedTokens) {
|
|
499
|
+
this.tokens = JSON.parse(storedTokens);
|
|
500
|
+
this.tokens.expiresAt = new Date(this.tokens.expiresAt);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
get user() {
|
|
505
|
+
if (this.tokens)
|
|
506
|
+
return this.tokens;
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
get hasAccessToken() {
|
|
510
|
+
return !!this.tokens;
|
|
511
|
+
}
|
|
512
|
+
async getAccessToken() {
|
|
513
|
+
var _a, _b, _c;
|
|
514
|
+
if (this.isExpired) {
|
|
515
|
+
if (this.refreshPromise) {
|
|
516
|
+
const tokens2 = await this.refreshPromise;
|
|
517
|
+
return (_a = tokens2 == null ? void 0 : tokens2.accessToken) != null ? _a : null;
|
|
518
|
+
}
|
|
519
|
+
this.refreshPromise = this.refreshTokens();
|
|
520
|
+
const tokens = await this.refreshPromise;
|
|
521
|
+
return (_b = tokens == null ? void 0 : tokens.accessToken) != null ? _b : null;
|
|
522
|
+
}
|
|
523
|
+
return ((_c = this.tokens) == null ? void 0 : _c.accessToken) || null;
|
|
524
|
+
}
|
|
525
|
+
setUser(user) {
|
|
526
|
+
if (user === null) {
|
|
527
|
+
this.tokens = null;
|
|
528
|
+
if (typeof window !== "undefined" && localStorage)
|
|
529
|
+
localStorage.removeItem(_TokenStore.storageKey);
|
|
530
|
+
if (this.refreshTimeoutId != null)
|
|
531
|
+
window.clearTimeout(this.refreshTimeoutId);
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
this.tokens = {
|
|
535
|
+
...user,
|
|
536
|
+
// Hardcoded 15 minutes now, might want to check the JWT tho
|
|
537
|
+
expiresAt: new Date((/* @__PURE__ */ new Date()).getTime() + 15 * 60 * 1e3)
|
|
538
|
+
};
|
|
539
|
+
if (typeof window !== "undefined" && localStorage)
|
|
540
|
+
localStorage.setItem(_TokenStore.storageKey, JSON.stringify(this.tokens));
|
|
541
|
+
if (this.refreshTimeoutId != null)
|
|
542
|
+
window.clearTimeout(this.refreshTimeoutId);
|
|
543
|
+
this.refreshTimeoutId = window.setTimeout(() => {
|
|
544
|
+
this.refreshPromise = this.refreshTokens();
|
|
545
|
+
}, 10 * 60 * 1e3);
|
|
546
|
+
return this.tokens;
|
|
547
|
+
}
|
|
548
|
+
get isExpired() {
|
|
549
|
+
return this.tokens != null && this.tokens.expiresAt < /* @__PURE__ */ new Date();
|
|
550
|
+
}
|
|
551
|
+
async refreshTokens() {
|
|
552
|
+
if (!this.tokens)
|
|
553
|
+
throw new Error("No tokens found to refresh");
|
|
554
|
+
const response = await fetch3(`${this.configuration.endpoint}/api/customer/identity/refresh?token=${this.tokens.refreshToken}`, {
|
|
555
|
+
method: "POST",
|
|
556
|
+
headers: {
|
|
557
|
+
"Accept": "application/json",
|
|
558
|
+
"Content-Type": "text/plain",
|
|
559
|
+
"x-mb-cors": "1"
|
|
560
|
+
},
|
|
561
|
+
body: this.tokens.accessToken
|
|
562
|
+
});
|
|
563
|
+
if (response.status !== 200) {
|
|
564
|
+
if (response.status === 403) {
|
|
565
|
+
this.setUser(null);
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
throw new Error(`Could not refresh access token, status code ${response.status}`);
|
|
569
|
+
}
|
|
570
|
+
const result = identityUserSchema.parse(await response.json());
|
|
571
|
+
return this.setUser(result);
|
|
572
|
+
}
|
|
573
|
+
handleStorageUpdate(event) {
|
|
574
|
+
switch (event.key) {
|
|
575
|
+
case _TokenStore.storageKey:
|
|
576
|
+
this.tokens = JSON.parse(event.newValue);
|
|
577
|
+
this.tokens.expiresAt = new Date(this.tokens.expiresAt);
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
_TokenStore.storageKey = "moonbase_auth";
|
|
583
|
+
var TokenStore = _TokenStore;
|
|
584
|
+
|
|
585
|
+
// src/vouchers/schemas.ts
|
|
586
|
+
import { z as z8 } from "zod";
|
|
587
|
+
var voucherSchema = z8.object({
|
|
588
|
+
id: z8.string(),
|
|
589
|
+
name: z8.string(),
|
|
590
|
+
description: z8.string(),
|
|
591
|
+
code: z8.string(),
|
|
592
|
+
redeemed: z8.boolean(),
|
|
593
|
+
redeemsProducts: quantifiable(storefrontProductSchema).array(),
|
|
594
|
+
redeemsBundles: quantifiable(storefrontBundleSchema).array()
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// src/vouchers/endpoints.ts
|
|
598
|
+
var VoucherEndpoints = class {
|
|
599
|
+
constructor(api) {
|
|
600
|
+
this.api = api;
|
|
601
|
+
}
|
|
602
|
+
async peek(code) {
|
|
603
|
+
const response = await this.api.fetch(`/api/customer/vouchers?code=${encodeURIComponent(code)}`);
|
|
604
|
+
return voucherSchema.parse(response);
|
|
605
|
+
}
|
|
606
|
+
async redeem(code) {
|
|
607
|
+
const response = await this.api.authenticatedFetch(
|
|
608
|
+
`/api/customer/vouchers/redeem?code=${encodeURIComponent(code)}`,
|
|
609
|
+
"POST"
|
|
610
|
+
);
|
|
611
|
+
return voucherSchema.parse(response);
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
// src/index.ts
|
|
616
|
+
var MoonbaseClient = class {
|
|
617
|
+
constructor(configuration) {
|
|
618
|
+
this.configuration = configuration;
|
|
619
|
+
this.configuration.endpoint = this.configuration.endpoint.replace(/\/$/, "");
|
|
620
|
+
this.tokenStore = new TokenStore(configuration);
|
|
621
|
+
const api = new MoonbaseApi(this.configuration.endpoint, this.tokenStore);
|
|
622
|
+
this.storefront = new StorefrontEndpoints(api);
|
|
623
|
+
this.identity = new IdentityEndpoints(api, this.tokenStore);
|
|
624
|
+
this.vouchers = new VoucherEndpoints(api);
|
|
625
|
+
this.orders = new OrderEndpoints(api);
|
|
626
|
+
this.licenses = new LicenseEndpoints(api);
|
|
627
|
+
this.products = new ProductEndpoints(api);
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
export {
|
|
631
|
+
ActivationMethod,
|
|
632
|
+
ActivationStatus,
|
|
633
|
+
LicenseStatus,
|
|
634
|
+
MoonbaseClient,
|
|
635
|
+
NotAuthenticatedError,
|
|
636
|
+
NotAuthorizedError,
|
|
637
|
+
NotFoundError,
|
|
638
|
+
OrderStatus,
|
|
639
|
+
Platform
|
|
640
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@moonbase.sh/storefront-api",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.78",
|
|
5
|
+
"description": "Package to let you build storefronts with Moonbase.sh as payment and delivery provider",
|
|
6
|
+
"author": "Tobias Lønnerød Madsen <m@dsen.tv>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/**"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"cross-fetch": "^3.1.5",
|
|
17
|
+
"zod": "^3.21.4"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^18.14.2",
|
|
21
|
+
"rimraf": "^5.0.0",
|
|
22
|
+
"tsup": "^7.1.0",
|
|
23
|
+
"typescript": "~5.1.6"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
27
|
+
"dev": "tsup src/index.ts --format esm,cjs --watch --dts",
|
|
28
|
+
"version": "npm version"
|
|
29
|
+
}
|
|
30
|
+
}
|