@frontdesk-africa/store-js 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 +242 -0
- package/dist/index.d.mts +2421 -0
- package/dist/index.d.ts +2421 -0
- package/dist/index.js +177 -0
- package/dist/index.mjs +142 -0
- package/package.json +50 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
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 __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
StoreApiError: () => StoreApiError,
|
|
35
|
+
createStoreClient: () => createStoreClient,
|
|
36
|
+
verifyWebhook: () => verifyWebhook
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(index_exports);
|
|
39
|
+
var StoreApiError = class extends Error {
|
|
40
|
+
static {
|
|
41
|
+
__name(this, "StoreApiError");
|
|
42
|
+
}
|
|
43
|
+
code;
|
|
44
|
+
status;
|
|
45
|
+
retryable;
|
|
46
|
+
requestId;
|
|
47
|
+
details;
|
|
48
|
+
constructor(status, body) {
|
|
49
|
+
const e = body?.error ?? {};
|
|
50
|
+
super(typeof e.message === "string" ? e.message : `Request failed (${status})`);
|
|
51
|
+
this.name = "StoreApiError";
|
|
52
|
+
this.status = status;
|
|
53
|
+
this.code = typeof e.code === "string" ? e.code : "INTERNAL";
|
|
54
|
+
this.retryable = e.retryable === true;
|
|
55
|
+
this.requestId = typeof e.requestId === "string" ? e.requestId : null;
|
|
56
|
+
this.details = e.details;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
function createStoreClient(opts) {
|
|
60
|
+
const base = opts.baseUrl.replace(/\/+$/, "");
|
|
61
|
+
const doFetch = opts.fetch ?? globalThis.fetch;
|
|
62
|
+
async function request(path, init) {
|
|
63
|
+
const headers = {
|
|
64
|
+
Accept: "application/json",
|
|
65
|
+
Authorization: `Bearer ${opts.key}`,
|
|
66
|
+
...init?.headers ?? {}
|
|
67
|
+
};
|
|
68
|
+
if (init?.body) headers["Content-Type"] = "application/json";
|
|
69
|
+
if (init?.idempotencyKey) headers["Idempotency-Key"] = init.idempotencyKey;
|
|
70
|
+
const res = await doFetch(`${base}${path}`, {
|
|
71
|
+
...init,
|
|
72
|
+
headers
|
|
73
|
+
});
|
|
74
|
+
const text = await res.text();
|
|
75
|
+
const body = text ? JSON.parse(text) : null;
|
|
76
|
+
if (!res.ok) throw new StoreApiError(res.status, body);
|
|
77
|
+
return body;
|
|
78
|
+
}
|
|
79
|
+
__name(request, "request");
|
|
80
|
+
const enc = encodeURIComponent;
|
|
81
|
+
return {
|
|
82
|
+
/** Escape hatch for anything not yet wrapped. Same auth, same error handling. */
|
|
83
|
+
request,
|
|
84
|
+
// ------------------------------------------------------------- read (fd_pk_)
|
|
85
|
+
storefront: /* @__PURE__ */ __name(() => request("/store/storefront"), "storefront"),
|
|
86
|
+
products: /* @__PURE__ */ __name(() => request("/store/products"), "products"),
|
|
87
|
+
product: /* @__PURE__ */ __name((slug) => request(`/store/products/${enc(slug)}`), "product"),
|
|
88
|
+
productSlots: /* @__PURE__ */ __name((slug, opts2) => request(`/store/products/${enc(slug)}/slots?variantRef=${enc(opts2.variantRef)}&date=${enc(opts2.date)}`), "productSlots"),
|
|
89
|
+
collections: /* @__PURE__ */ __name(() => request("/store/collections"), "collections"),
|
|
90
|
+
collection: /* @__PURE__ */ __name((slug) => request(`/store/collections/${enc(slug)}`), "collection"),
|
|
91
|
+
events: /* @__PURE__ */ __name(() => request("/store/events"), "events"),
|
|
92
|
+
event: /* @__PURE__ */ __name((slug) => request(`/store/events/${enc(slug)}`), "event"),
|
|
93
|
+
form: /* @__PURE__ */ __name((slug) => request(`/store/forms/${enc(slug)}`), "form"),
|
|
94
|
+
table: /* @__PURE__ */ __name((slug) => request(`/store/tables/${enc(slug)}`), "table"),
|
|
95
|
+
catalog: /* @__PURE__ */ __name((slug) => request(`/store/catalogs/${enc(slug)}`), "catalog"),
|
|
96
|
+
files: /* @__PURE__ */ __name((slug) => request(`/store/files/${enc(slug)}`), "files"),
|
|
97
|
+
note: /* @__PURE__ */ __name((slug) => request(`/store/notes/${enc(slug)}`), "note"),
|
|
98
|
+
deliveryZones: /* @__PURE__ */ __name(() => request("/store/delivery-zones"), "deliveryZones"),
|
|
99
|
+
/**
|
|
100
|
+
* Live stock for the variants a cart already holds — a cart is localStorage, so its lines can be
|
|
101
|
+
* days old. A ref missing from the response map is no longer purchasable: drop that line. Refs in
|
|
102
|
+
* `preorderable` are still buyable at 0 stock; cap those on `preorderRemaining` instead.
|
|
103
|
+
*/
|
|
104
|
+
availability: /* @__PURE__ */ __name((variantRefs) => request(`/store/availability?variantRefs=${enc(variantRefs.join(","))}`), "availability"),
|
|
105
|
+
/** The payment rails this workspace can charge, for rendering your own picker (headless only). */
|
|
106
|
+
paymentMethods: /* @__PURE__ */ __name((currency) => request(`/store/payment-methods${currency ? `?currency=${enc(currency)}` : ""}`), "paymentMethods"),
|
|
107
|
+
// --------------------------------------------------- checkout (fd_sk_, server)
|
|
108
|
+
/**
|
|
109
|
+
* Open a hosted checkout. SERVER ONLY — needs a secret key.
|
|
110
|
+
*
|
|
111
|
+
* `idempotencyKey` is required by the API, not optional politeness: reuse the same value on a
|
|
112
|
+
* retry and you get the SAME checkout back instead of charging a buyer twice. Derive it from
|
|
113
|
+
* something stable in your own system (your cart id), never a random value per attempt.
|
|
114
|
+
*/
|
|
115
|
+
createCheckout: /* @__PURE__ */ __name((input, idempotencyKey) => request("/store/checkouts", {
|
|
116
|
+
method: "POST",
|
|
117
|
+
body: JSON.stringify(input),
|
|
118
|
+
idempotencyKey
|
|
119
|
+
}), "createCheckout"),
|
|
120
|
+
/**
|
|
121
|
+
* Open a hosted checkout for event tickets. SERVER ONLY — needs a secret key.
|
|
122
|
+
*
|
|
123
|
+
* `GET /store/events/:slug` tells you what to collect first: each tier carries formFields,
|
|
124
|
+
* requiresAttendeeDetails, groupSize and min/max per order; the event carries minAge and dobMode.
|
|
125
|
+
* Everything is re-validated server-side, so prices and availability are never yours to decide.
|
|
126
|
+
*/
|
|
127
|
+
createEventCheckout: /* @__PURE__ */ __name((slug, input, idempotencyKey) => request(`/store/events/${enc(slug)}/checkout`, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
body: JSON.stringify(input),
|
|
130
|
+
idempotencyKey
|
|
131
|
+
}), "createEventCheckout"),
|
|
132
|
+
/**
|
|
133
|
+
* Open a ticket checkout you render yourself, including the payment step. SERVER ONLY, and the
|
|
134
|
+
* workspace must have headless switched on. Name ONE provider from `paymentMethods()`; branch on
|
|
135
|
+
* the provider you asked for, never on which payment field came back filled in.
|
|
136
|
+
*/
|
|
137
|
+
createHeadlessCheckout: /* @__PURE__ */ __name((slug, input, idempotencyKey) => request(`/store/events/${enc(slug)}/checkout/headless`, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
body: JSON.stringify(input),
|
|
140
|
+
idempotencyKey
|
|
141
|
+
}), "createHeadlessCheckout"),
|
|
142
|
+
/**
|
|
143
|
+
* The state of a checkout. THIS is how you confirm a purchase — the return redirect is a browser
|
|
144
|
+
* navigation and can be lost, replayed or forged, so never fulfil on it alone. Safe to poll while
|
|
145
|
+
* a buyer is paying: an open session is verified against the provider before we answer.
|
|
146
|
+
*/
|
|
147
|
+
getCheckout: /* @__PURE__ */ __name((ref) => request(`/store/checkouts/${enc(ref)}`), "getCheckout"),
|
|
148
|
+
/**
|
|
149
|
+
* Cancel an open checkout and release the seats it was holding, instead of leaving them out of
|
|
150
|
+
* stock until the session lapses. Cancelling an already-paid checkout returns 409.
|
|
151
|
+
*/
|
|
152
|
+
cancelCheckout: /* @__PURE__ */ __name((ref) => request(`/store/checkouts/${enc(ref)}/cancel`, {
|
|
153
|
+
method: "POST"
|
|
154
|
+
}), "cancelCheckout")
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
__name(createStoreClient, "createStoreClient");
|
|
158
|
+
async function verifyWebhook(opts) {
|
|
159
|
+
const { createHmac, timingSafeEqual } = await import("crypto");
|
|
160
|
+
const ts = String(opts.timestampHeader ?? "");
|
|
161
|
+
const got = String(opts.signatureHeader ?? "").replace(/^sha256=/, "");
|
|
162
|
+
if (!ts || !got) return false;
|
|
163
|
+
const tolerance = opts.toleranceSec ?? 300;
|
|
164
|
+
const age = Math.abs(Math.floor(Date.now() / 1e3) - Number(ts));
|
|
165
|
+
if (!Number.isFinite(age) || age > tolerance) return false;
|
|
166
|
+
const want = createHmac("sha256", opts.secret).update(`${ts}.${opts.rawBody}`).digest("hex");
|
|
167
|
+
const a = Buffer.from(got, "utf8");
|
|
168
|
+
const b = Buffer.from(want, "utf8");
|
|
169
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
170
|
+
}
|
|
171
|
+
__name(verifyWebhook, "verifyWebhook");
|
|
172
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
173
|
+
0 && (module.exports = {
|
|
174
|
+
StoreApiError,
|
|
175
|
+
createStoreClient,
|
|
176
|
+
verifyWebhook
|
|
177
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
var StoreApiError = class extends Error {
|
|
6
|
+
static {
|
|
7
|
+
__name(this, "StoreApiError");
|
|
8
|
+
}
|
|
9
|
+
code;
|
|
10
|
+
status;
|
|
11
|
+
retryable;
|
|
12
|
+
requestId;
|
|
13
|
+
details;
|
|
14
|
+
constructor(status, body) {
|
|
15
|
+
const e = body?.error ?? {};
|
|
16
|
+
super(typeof e.message === "string" ? e.message : `Request failed (${status})`);
|
|
17
|
+
this.name = "StoreApiError";
|
|
18
|
+
this.status = status;
|
|
19
|
+
this.code = typeof e.code === "string" ? e.code : "INTERNAL";
|
|
20
|
+
this.retryable = e.retryable === true;
|
|
21
|
+
this.requestId = typeof e.requestId === "string" ? e.requestId : null;
|
|
22
|
+
this.details = e.details;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
function createStoreClient(opts) {
|
|
26
|
+
const base = opts.baseUrl.replace(/\/+$/, "");
|
|
27
|
+
const doFetch = opts.fetch ?? globalThis.fetch;
|
|
28
|
+
async function request(path, init) {
|
|
29
|
+
const headers = {
|
|
30
|
+
Accept: "application/json",
|
|
31
|
+
Authorization: `Bearer ${opts.key}`,
|
|
32
|
+
...init?.headers ?? {}
|
|
33
|
+
};
|
|
34
|
+
if (init?.body) headers["Content-Type"] = "application/json";
|
|
35
|
+
if (init?.idempotencyKey) headers["Idempotency-Key"] = init.idempotencyKey;
|
|
36
|
+
const res = await doFetch(`${base}${path}`, {
|
|
37
|
+
...init,
|
|
38
|
+
headers
|
|
39
|
+
});
|
|
40
|
+
const text = await res.text();
|
|
41
|
+
const body = text ? JSON.parse(text) : null;
|
|
42
|
+
if (!res.ok) throw new StoreApiError(res.status, body);
|
|
43
|
+
return body;
|
|
44
|
+
}
|
|
45
|
+
__name(request, "request");
|
|
46
|
+
const enc = encodeURIComponent;
|
|
47
|
+
return {
|
|
48
|
+
/** Escape hatch for anything not yet wrapped. Same auth, same error handling. */
|
|
49
|
+
request,
|
|
50
|
+
// ------------------------------------------------------------- read (fd_pk_)
|
|
51
|
+
storefront: /* @__PURE__ */ __name(() => request("/store/storefront"), "storefront"),
|
|
52
|
+
products: /* @__PURE__ */ __name(() => request("/store/products"), "products"),
|
|
53
|
+
product: /* @__PURE__ */ __name((slug) => request(`/store/products/${enc(slug)}`), "product"),
|
|
54
|
+
productSlots: /* @__PURE__ */ __name((slug, opts2) => request(`/store/products/${enc(slug)}/slots?variantRef=${enc(opts2.variantRef)}&date=${enc(opts2.date)}`), "productSlots"),
|
|
55
|
+
collections: /* @__PURE__ */ __name(() => request("/store/collections"), "collections"),
|
|
56
|
+
collection: /* @__PURE__ */ __name((slug) => request(`/store/collections/${enc(slug)}`), "collection"),
|
|
57
|
+
events: /* @__PURE__ */ __name(() => request("/store/events"), "events"),
|
|
58
|
+
event: /* @__PURE__ */ __name((slug) => request(`/store/events/${enc(slug)}`), "event"),
|
|
59
|
+
form: /* @__PURE__ */ __name((slug) => request(`/store/forms/${enc(slug)}`), "form"),
|
|
60
|
+
table: /* @__PURE__ */ __name((slug) => request(`/store/tables/${enc(slug)}`), "table"),
|
|
61
|
+
catalog: /* @__PURE__ */ __name((slug) => request(`/store/catalogs/${enc(slug)}`), "catalog"),
|
|
62
|
+
files: /* @__PURE__ */ __name((slug) => request(`/store/files/${enc(slug)}`), "files"),
|
|
63
|
+
note: /* @__PURE__ */ __name((slug) => request(`/store/notes/${enc(slug)}`), "note"),
|
|
64
|
+
deliveryZones: /* @__PURE__ */ __name(() => request("/store/delivery-zones"), "deliveryZones"),
|
|
65
|
+
/**
|
|
66
|
+
* Live stock for the variants a cart already holds — a cart is localStorage, so its lines can be
|
|
67
|
+
* days old. A ref missing from the response map is no longer purchasable: drop that line. Refs in
|
|
68
|
+
* `preorderable` are still buyable at 0 stock; cap those on `preorderRemaining` instead.
|
|
69
|
+
*/
|
|
70
|
+
availability: /* @__PURE__ */ __name((variantRefs) => request(`/store/availability?variantRefs=${enc(variantRefs.join(","))}`), "availability"),
|
|
71
|
+
/** The payment rails this workspace can charge, for rendering your own picker (headless only). */
|
|
72
|
+
paymentMethods: /* @__PURE__ */ __name((currency) => request(`/store/payment-methods${currency ? `?currency=${enc(currency)}` : ""}`), "paymentMethods"),
|
|
73
|
+
// --------------------------------------------------- checkout (fd_sk_, server)
|
|
74
|
+
/**
|
|
75
|
+
* Open a hosted checkout. SERVER ONLY — needs a secret key.
|
|
76
|
+
*
|
|
77
|
+
* `idempotencyKey` is required by the API, not optional politeness: reuse the same value on a
|
|
78
|
+
* retry and you get the SAME checkout back instead of charging a buyer twice. Derive it from
|
|
79
|
+
* something stable in your own system (your cart id), never a random value per attempt.
|
|
80
|
+
*/
|
|
81
|
+
createCheckout: /* @__PURE__ */ __name((input, idempotencyKey) => request("/store/checkouts", {
|
|
82
|
+
method: "POST",
|
|
83
|
+
body: JSON.stringify(input),
|
|
84
|
+
idempotencyKey
|
|
85
|
+
}), "createCheckout"),
|
|
86
|
+
/**
|
|
87
|
+
* Open a hosted checkout for event tickets. SERVER ONLY — needs a secret key.
|
|
88
|
+
*
|
|
89
|
+
* `GET /store/events/:slug` tells you what to collect first: each tier carries formFields,
|
|
90
|
+
* requiresAttendeeDetails, groupSize and min/max per order; the event carries minAge and dobMode.
|
|
91
|
+
* Everything is re-validated server-side, so prices and availability are never yours to decide.
|
|
92
|
+
*/
|
|
93
|
+
createEventCheckout: /* @__PURE__ */ __name((slug, input, idempotencyKey) => request(`/store/events/${enc(slug)}/checkout`, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
body: JSON.stringify(input),
|
|
96
|
+
idempotencyKey
|
|
97
|
+
}), "createEventCheckout"),
|
|
98
|
+
/**
|
|
99
|
+
* Open a ticket checkout you render yourself, including the payment step. SERVER ONLY, and the
|
|
100
|
+
* workspace must have headless switched on. Name ONE provider from `paymentMethods()`; branch on
|
|
101
|
+
* the provider you asked for, never on which payment field came back filled in.
|
|
102
|
+
*/
|
|
103
|
+
createHeadlessCheckout: /* @__PURE__ */ __name((slug, input, idempotencyKey) => request(`/store/events/${enc(slug)}/checkout/headless`, {
|
|
104
|
+
method: "POST",
|
|
105
|
+
body: JSON.stringify(input),
|
|
106
|
+
idempotencyKey
|
|
107
|
+
}), "createHeadlessCheckout"),
|
|
108
|
+
/**
|
|
109
|
+
* The state of a checkout. THIS is how you confirm a purchase — the return redirect is a browser
|
|
110
|
+
* navigation and can be lost, replayed or forged, so never fulfil on it alone. Safe to poll while
|
|
111
|
+
* a buyer is paying: an open session is verified against the provider before we answer.
|
|
112
|
+
*/
|
|
113
|
+
getCheckout: /* @__PURE__ */ __name((ref) => request(`/store/checkouts/${enc(ref)}`), "getCheckout"),
|
|
114
|
+
/**
|
|
115
|
+
* Cancel an open checkout and release the seats it was holding, instead of leaving them out of
|
|
116
|
+
* stock until the session lapses. Cancelling an already-paid checkout returns 409.
|
|
117
|
+
*/
|
|
118
|
+
cancelCheckout: /* @__PURE__ */ __name((ref) => request(`/store/checkouts/${enc(ref)}/cancel`, {
|
|
119
|
+
method: "POST"
|
|
120
|
+
}), "cancelCheckout")
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
__name(createStoreClient, "createStoreClient");
|
|
124
|
+
async function verifyWebhook(opts) {
|
|
125
|
+
const { createHmac, timingSafeEqual } = await import("crypto");
|
|
126
|
+
const ts = String(opts.timestampHeader ?? "");
|
|
127
|
+
const got = String(opts.signatureHeader ?? "").replace(/^sha256=/, "");
|
|
128
|
+
if (!ts || !got) return false;
|
|
129
|
+
const tolerance = opts.toleranceSec ?? 300;
|
|
130
|
+
const age = Math.abs(Math.floor(Date.now() / 1e3) - Number(ts));
|
|
131
|
+
if (!Number.isFinite(age) || age > tolerance) return false;
|
|
132
|
+
const want = createHmac("sha256", opts.secret).update(`${ts}.${opts.rawBody}`).digest("hex");
|
|
133
|
+
const a = Buffer.from(got, "utf8");
|
|
134
|
+
const b = Buffer.from(want, "utf8");
|
|
135
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
136
|
+
}
|
|
137
|
+
__name(verifyWebhook, "verifyWebhook");
|
|
138
|
+
export {
|
|
139
|
+
StoreApiError,
|
|
140
|
+
createStoreClient,
|
|
141
|
+
verifyWebhook
|
|
142
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@frontdesk-africa/store-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Typed client for the FrontDesk Storefront API: catalogue, events, forms, hosted checkout and signed webhooks.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://api.frontdesk.africa/v1/store/docs",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"frontdesk",
|
|
9
|
+
"storefront",
|
|
10
|
+
"ecommerce",
|
|
11
|
+
"checkout",
|
|
12
|
+
"webhooks",
|
|
13
|
+
"api-client"
|
|
14
|
+
],
|
|
15
|
+
"main": "dist/index.js",
|
|
16
|
+
"module": "dist/index.mjs",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.mjs",
|
|
22
|
+
"require": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup",
|
|
39
|
+
"dev": "tsup --watch",
|
|
40
|
+
"lint": "eslint src --ext .ts",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"release:check": "pnpm build && npm pack --dry-run"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@frontdesk/shared": "workspace:*",
|
|
46
|
+
"@types/node": "^22.10.0",
|
|
47
|
+
"tsup": "^8.5.0",
|
|
48
|
+
"typescript": "^5.7.0"
|
|
49
|
+
}
|
|
50
|
+
}
|