@atzentis/booking-sdk 0.0.0 → 0.1.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 +89 -0
- package/dist/index.cjs +536 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +209 -2
- package/dist/index.d.ts +209 -2
- package/dist/index.js +518 -2
- package/dist/index.js.map +1 -1
- package/package.json +8 -3
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# @atzentis/booking-sdk
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@atzentis/booking-sdk)
|
|
4
|
+
[](../../LICENCE.md)
|
|
5
|
+
|
|
6
|
+
Core TypeScript client for [atzentis.io](https://atzentis.io) — the Atzentis Hospitality Platform. Framework-agnostic with zero runtime dependencies.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @atzentis/booking-sdk
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { BookingClient } from '@atzentis/booking-sdk';
|
|
18
|
+
|
|
19
|
+
const booking = new BookingClient({
|
|
20
|
+
baseUrl: 'https://api.atzentis.io',
|
|
21
|
+
apiKey: 'your-api-key',
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Properties
|
|
25
|
+
const properties = await booking.properties.list();
|
|
26
|
+
|
|
27
|
+
// Availability
|
|
28
|
+
const availability = await booking.availability.check({
|
|
29
|
+
propertyId: 'prop_123',
|
|
30
|
+
checkIn: '2026-06-01',
|
|
31
|
+
checkOut: '2026-06-05',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Bookings
|
|
35
|
+
const result = await booking.bookings.create({
|
|
36
|
+
propertyId: 'prop_123',
|
|
37
|
+
spaceId: 'space_456',
|
|
38
|
+
guestId: 'guest_789',
|
|
39
|
+
checkIn: '2026-06-01',
|
|
40
|
+
checkOut: '2026-06-05',
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Services
|
|
45
|
+
|
|
46
|
+
Wraps all 205 endpoints of the atzentis.io v4.0 API across 28 services:
|
|
47
|
+
|
|
48
|
+
| Category | Services |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| Inventory | Properties, Spaces |
|
|
51
|
+
| Booking | Availability, Bookings, Groups |
|
|
52
|
+
| Guest | Profiles, Intelligence, ID Scanning |
|
|
53
|
+
| Finance | Folios, Payments, POS Bridge |
|
|
54
|
+
| Operations | Housekeeping, Night Audit, Staff, Supply, Tasks |
|
|
55
|
+
| Rate | Plans, Periods, Restrictions |
|
|
56
|
+
| Distribution | Channels, Mappings, Sync, iCal |
|
|
57
|
+
| AI | Concierge, Revenue |
|
|
58
|
+
| Compliance | Fiscal (myDATA, TSE) |
|
|
59
|
+
| Platform | Webhooks, Settings, Notifications, SSE |
|
|
60
|
+
|
|
61
|
+
## Booking Verticals
|
|
62
|
+
|
|
63
|
+
| Vertical | Space Types | Granularity |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| **Stays** (nights) | room, sunbed, parking | night, day, month |
|
|
66
|
+
| **Tables** (reservations) | table, locker | hour |
|
|
67
|
+
| **Services** (appointments) | service, meeting_room, desk | hour |
|
|
68
|
+
|
|
69
|
+
## Features
|
|
70
|
+
|
|
71
|
+
- ESM and CJS dual output
|
|
72
|
+
- Strict TypeScript with full type coverage
|
|
73
|
+
- Zod validation schemas for all request/response types
|
|
74
|
+
- Tree-shakeable exports
|
|
75
|
+
- Zero runtime dependencies
|
|
76
|
+
|
|
77
|
+
## React
|
|
78
|
+
|
|
79
|
+
For React hooks and components, see [`@atzentis/booking-react`](https://www.npmjs.com/package/@atzentis/booking-react).
|
|
80
|
+
|
|
81
|
+
## Links
|
|
82
|
+
|
|
83
|
+
- [atzentis.io](https://atzentis.io) — Hospitality Platform
|
|
84
|
+
- [API Documentation](https://docs.atzentis.com)
|
|
85
|
+
- [GitHub](https://github.com/atzentis/atzentis-booking-sdk)
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,9 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __typeError = (msg) => {
|
|
7
|
+
throw TypeError(msg);
|
|
8
|
+
};
|
|
6
9
|
var __export = (target, all) => {
|
|
7
10
|
for (var name in all)
|
|
8
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -16,16 +19,546 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
19
|
return to;
|
|
17
20
|
};
|
|
18
21
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
23
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
24
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
25
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
19
26
|
|
|
20
27
|
// src/index.ts
|
|
21
28
|
var index_exports = {};
|
|
22
29
|
__export(index_exports, {
|
|
23
|
-
|
|
30
|
+
AuthenticationError: () => AuthenticationError,
|
|
31
|
+
BookingClient: () => BookingClient,
|
|
32
|
+
BookingError: () => BookingError,
|
|
33
|
+
ConflictError: () => ConflictError,
|
|
34
|
+
ForbiddenError: () => ForbiddenError,
|
|
35
|
+
HttpClient: () => HttpClient,
|
|
36
|
+
NotFoundError: () => NotFoundError,
|
|
37
|
+
PaymentError: () => PaymentError,
|
|
38
|
+
RateLimitError: () => RateLimitError,
|
|
39
|
+
ServerError: () => ServerError,
|
|
40
|
+
TimeoutError: () => TimeoutError,
|
|
41
|
+
VERSION: () => VERSION,
|
|
42
|
+
ValidationError: () => ValidationError,
|
|
43
|
+
bookingClientConfigSchema: () => bookingClientConfigSchema,
|
|
44
|
+
createErrorFromResponse: () => createErrorFromResponse,
|
|
45
|
+
firstPage: () => firstPage,
|
|
46
|
+
paginate: () => paginate
|
|
24
47
|
});
|
|
25
48
|
module.exports = __toCommonJS(index_exports);
|
|
26
|
-
|
|
49
|
+
|
|
50
|
+
// src/config.ts
|
|
51
|
+
var import_zod = require("zod");
|
|
52
|
+
var bookingClientConfigSchema = import_zod.z.object({
|
|
53
|
+
apiKey: import_zod.z.string().min(1, "apiKey is required"),
|
|
54
|
+
baseUrl: import_zod.z.string().url().default("https://api.atzentis.io"),
|
|
55
|
+
tenantId: import_zod.z.string().min(1).optional(),
|
|
56
|
+
timeout: import_zod.z.number().int().positive().default(3e4),
|
|
57
|
+
retry: import_zod.z.object({
|
|
58
|
+
maxRetries: import_zod.z.number().int().min(0).max(10).default(3),
|
|
59
|
+
baseDelay: import_zod.z.number().int().positive().default(500)
|
|
60
|
+
}).optional(),
|
|
61
|
+
debug: import_zod.z.boolean().default(false),
|
|
62
|
+
logger: import_zod.z.object({
|
|
63
|
+
debug: import_zod.z.custom(
|
|
64
|
+
(val) => typeof val === "function"
|
|
65
|
+
)
|
|
66
|
+
}).optional()
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// src/errors.ts
|
|
70
|
+
var BookingError = class extends Error {
|
|
71
|
+
constructor(message, options) {
|
|
72
|
+
super(message);
|
|
73
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
74
|
+
this.name = "BookingError";
|
|
75
|
+
this.code = options.code;
|
|
76
|
+
this.status = options.status;
|
|
77
|
+
this.details = options.details ?? {};
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var AuthenticationError = class extends BookingError {
|
|
81
|
+
constructor(message = "Authentication failed: invalid or missing API key", details) {
|
|
82
|
+
super(message, { code: "AUTHENTICATION_ERROR", status: 401, details });
|
|
83
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
84
|
+
this.name = "AuthenticationError";
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var PaymentError = class extends BookingError {
|
|
88
|
+
constructor(message = "Payment required or payment failed", details) {
|
|
89
|
+
super(message, { code: "PAYMENT_ERROR", status: 402, details });
|
|
90
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
91
|
+
this.name = "PaymentError";
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var ForbiddenError = class extends BookingError {
|
|
95
|
+
constructor(message = "Insufficient permissions to perform this action", details) {
|
|
96
|
+
super(message, { code: "FORBIDDEN_ERROR", status: 403, details });
|
|
97
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
98
|
+
this.name = "ForbiddenError";
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
var NotFoundError = class extends BookingError {
|
|
102
|
+
constructor(message = "The requested resource was not found", details) {
|
|
103
|
+
super(message, { code: "NOT_FOUND_ERROR", status: 404, details });
|
|
104
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
105
|
+
this.name = "NotFoundError";
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var ConflictError = class extends BookingError {
|
|
109
|
+
constructor(message = "Resource conflict \u2014 the booking may already exist", details) {
|
|
110
|
+
super(message, { code: "CONFLICT_ERROR", status: 409, details });
|
|
111
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
112
|
+
this.name = "ConflictError";
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
var ValidationError = class extends BookingError {
|
|
116
|
+
constructor(message = "Request validation failed", fieldErrors = {}, details) {
|
|
117
|
+
super(message, { code: "VALIDATION_ERROR", status: 422, details });
|
|
118
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
119
|
+
this.name = "ValidationError";
|
|
120
|
+
this.fieldErrors = fieldErrors;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
var RateLimitError = class extends BookingError {
|
|
124
|
+
constructor(message = "Rate limit exceeded", retryAfter = 60) {
|
|
125
|
+
super(message, { code: "RATE_LIMIT_ERROR", status: 429 });
|
|
126
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
127
|
+
this.name = "RateLimitError";
|
|
128
|
+
this.retryAfter = retryAfter;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
var ServerError = class extends BookingError {
|
|
132
|
+
constructor(message = "An unexpected server error occurred", status = 500, details) {
|
|
133
|
+
super(message, { code: "SERVER_ERROR", status, details });
|
|
134
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
135
|
+
this.name = "ServerError";
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
var TimeoutError = class extends BookingError {
|
|
139
|
+
constructor(message = "The request timed out") {
|
|
140
|
+
super(message, { code: "TIMEOUT_ERROR" });
|
|
141
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
142
|
+
this.name = "TimeoutError";
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
function parseRetryAfter(header) {
|
|
146
|
+
if (!header) return 60;
|
|
147
|
+
const seconds = Number.parseInt(header, 10);
|
|
148
|
+
if (Number.isFinite(seconds) && seconds > 0) return seconds;
|
|
149
|
+
const date = new Date(header);
|
|
150
|
+
if (!Number.isNaN(date.getTime())) {
|
|
151
|
+
return Math.max(0, Math.round((date.getTime() - Date.now()) / 1e3));
|
|
152
|
+
}
|
|
153
|
+
return 60;
|
|
154
|
+
}
|
|
155
|
+
function extractBody(body) {
|
|
156
|
+
if (typeof body === "object" && body !== null && !Array.isArray(body)) {
|
|
157
|
+
return body;
|
|
158
|
+
}
|
|
159
|
+
return {};
|
|
160
|
+
}
|
|
161
|
+
function extractMessage(body, fallback) {
|
|
162
|
+
if (typeof body.message === "string" && body.message.length > 0) {
|
|
163
|
+
return body.message;
|
|
164
|
+
}
|
|
165
|
+
return fallback;
|
|
166
|
+
}
|
|
167
|
+
function parseFieldErrors(errors) {
|
|
168
|
+
if (typeof errors !== "object" || errors === null || Array.isArray(errors)) {
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
const result = {};
|
|
172
|
+
for (const [key, value] of Object.entries(errors)) {
|
|
173
|
+
if (Array.isArray(value)) {
|
|
174
|
+
result[key] = value.map(String);
|
|
175
|
+
} else if (typeof value === "string") {
|
|
176
|
+
result[key] = [value];
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
function createErrorFromResponse(response, body, retryAfterHeader) {
|
|
182
|
+
const bodyObj = extractBody(body);
|
|
183
|
+
const status = response.status;
|
|
184
|
+
switch (status) {
|
|
185
|
+
case 401:
|
|
186
|
+
return new AuthenticationError(
|
|
187
|
+
extractMessage(bodyObj, "Authentication failed: invalid or missing API key"),
|
|
188
|
+
bodyObj
|
|
189
|
+
);
|
|
190
|
+
case 402:
|
|
191
|
+
return new PaymentError(
|
|
192
|
+
extractMessage(bodyObj, "Payment required or payment failed"),
|
|
193
|
+
bodyObj
|
|
194
|
+
);
|
|
195
|
+
case 403:
|
|
196
|
+
return new ForbiddenError(
|
|
197
|
+
extractMessage(bodyObj, "Insufficient permissions to perform this action"),
|
|
198
|
+
bodyObj
|
|
199
|
+
);
|
|
200
|
+
case 404:
|
|
201
|
+
return new NotFoundError(
|
|
202
|
+
extractMessage(bodyObj, "The requested resource was not found"),
|
|
203
|
+
bodyObj
|
|
204
|
+
);
|
|
205
|
+
case 409:
|
|
206
|
+
return new ConflictError(extractMessage(bodyObj, "Resource conflict"), bodyObj);
|
|
207
|
+
case 422:
|
|
208
|
+
return new ValidationError(
|
|
209
|
+
extractMessage(bodyObj, "Request validation failed"),
|
|
210
|
+
parseFieldErrors(bodyObj.errors),
|
|
211
|
+
bodyObj
|
|
212
|
+
);
|
|
213
|
+
case 429:
|
|
214
|
+
return new RateLimitError(
|
|
215
|
+
extractMessage(bodyObj, "Rate limit exceeded"),
|
|
216
|
+
parseRetryAfter(retryAfterHeader ?? null)
|
|
217
|
+
);
|
|
218
|
+
default:
|
|
219
|
+
if (status >= 500) {
|
|
220
|
+
return new ServerError(
|
|
221
|
+
extractMessage(bodyObj, "An unexpected server error occurred"),
|
|
222
|
+
status,
|
|
223
|
+
bodyObj
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
return new BookingError(extractMessage(bodyObj, `HTTP ${status} error`), {
|
|
227
|
+
code: "HTTP_ERROR",
|
|
228
|
+
status,
|
|
229
|
+
details: bodyObj
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/http.ts
|
|
235
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([500, 502, 503, 504]);
|
|
236
|
+
var DEFAULT_RETRY_CONFIG = {
|
|
237
|
+
maxRetries: 3,
|
|
238
|
+
baseDelay: 500,
|
|
239
|
+
retryOnMethods: ["GET", "DELETE"]
|
|
240
|
+
};
|
|
241
|
+
function parseRetryAfterHeader(header) {
|
|
242
|
+
if (!header) return 1;
|
|
243
|
+
const seconds = Number.parseInt(header, 10);
|
|
244
|
+
if (Number.isNaN(seconds) || seconds < 0) return 1;
|
|
245
|
+
return seconds;
|
|
246
|
+
}
|
|
247
|
+
function createDefaultLogger() {
|
|
248
|
+
return {
|
|
249
|
+
debug(message, ...args) {
|
|
250
|
+
console.debug(message, ...args);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function redactHeaders(headers) {
|
|
255
|
+
const result = { ...headers };
|
|
256
|
+
if (result.Authorization) {
|
|
257
|
+
result.Authorization = "Bearer ***";
|
|
258
|
+
}
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
var _apiKey, _tenantId, _retryConfig, _timeout, _debug, _logger;
|
|
262
|
+
var HttpClient = class {
|
|
263
|
+
constructor(options) {
|
|
264
|
+
__privateAdd(this, _apiKey);
|
|
265
|
+
__privateAdd(this, _tenantId);
|
|
266
|
+
__privateAdd(this, _retryConfig);
|
|
267
|
+
__privateAdd(this, _timeout);
|
|
268
|
+
__privateAdd(this, _debug);
|
|
269
|
+
__privateAdd(this, _logger);
|
|
270
|
+
this.baseUrl = options.baseUrl;
|
|
271
|
+
this.fetchFn = options.fetch ?? globalThis.fetch;
|
|
272
|
+
this.defaultHeaders = { ...options.defaultHeaders };
|
|
273
|
+
__privateSet(this, _apiKey, options.apiKey);
|
|
274
|
+
__privateSet(this, _tenantId, options.tenantId);
|
|
275
|
+
__privateSet(this, _retryConfig, {
|
|
276
|
+
...DEFAULT_RETRY_CONFIG,
|
|
277
|
+
...options.retryConfig
|
|
278
|
+
});
|
|
279
|
+
__privateSet(this, _timeout, options.timeout ?? 3e4);
|
|
280
|
+
__privateSet(this, _debug, options.debug ?? false);
|
|
281
|
+
__privateSet(this, _logger, options.logger ?? createDefaultLogger());
|
|
282
|
+
}
|
|
283
|
+
async request(method, path, options) {
|
|
284
|
+
if (!__privateGet(this, _apiKey)) {
|
|
285
|
+
throw new Error("BookingSDK: apiKey is required but was not provided");
|
|
286
|
+
}
|
|
287
|
+
const url = this.buildUrl(path, options?.query);
|
|
288
|
+
const headers = this.buildHeaders(options?.headers);
|
|
289
|
+
if (options?.body !== void 0) {
|
|
290
|
+
headers["Content-Type"] = "application/json";
|
|
291
|
+
}
|
|
292
|
+
headers.Authorization = `Bearer ${__privateGet(this, _apiKey)}`;
|
|
293
|
+
if (__privateGet(this, _tenantId)) {
|
|
294
|
+
headers["X-Tenant-ID"] = __privateGet(this, _tenantId);
|
|
295
|
+
}
|
|
296
|
+
const init = {
|
|
297
|
+
method,
|
|
298
|
+
headers
|
|
299
|
+
};
|
|
300
|
+
if (options?.body !== void 0) {
|
|
301
|
+
init.body = JSON.stringify(options.body);
|
|
302
|
+
}
|
|
303
|
+
const effectiveRetry = {
|
|
304
|
+
maxRetries: options?.retry?.maxRetries ?? __privateGet(this, _retryConfig).maxRetries,
|
|
305
|
+
baseDelay: options?.retry?.baseDelay ?? __privateGet(this, _retryConfig).baseDelay,
|
|
306
|
+
retryOnMethods: __privateGet(this, _retryConfig).retryOnMethods,
|
|
307
|
+
force: options?.retry?.force ?? false,
|
|
308
|
+
maxRetryAfter: __privateGet(this, _retryConfig).maxRetryAfter ?? 60
|
|
309
|
+
};
|
|
310
|
+
if (__privateGet(this, _debug)) {
|
|
311
|
+
__privateGet(this, _logger).debug(`[BookingSDK] --> ${method} ${url}`, {
|
|
312
|
+
headers: redactHeaders(headers),
|
|
313
|
+
...options?.body ? { body: JSON.stringify(options.body).slice(0, 200) } : {}
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
const timeoutMs = options?.timeout ?? __privateGet(this, _timeout);
|
|
317
|
+
const startTime = Date.now();
|
|
318
|
+
let lastError;
|
|
319
|
+
let wasRateLimited = false;
|
|
320
|
+
for (let attempt = 0; attempt <= effectiveRetry.maxRetries; attempt++) {
|
|
321
|
+
if (attempt > 0 && !wasRateLimited) {
|
|
322
|
+
await this.sleep(this.calculateDelay(attempt - 1, effectiveRetry.baseDelay));
|
|
323
|
+
}
|
|
324
|
+
wasRateLimited = false;
|
|
325
|
+
let timedOut = false;
|
|
326
|
+
const controller = new AbortController();
|
|
327
|
+
const timer = setTimeout(() => {
|
|
328
|
+
timedOut = true;
|
|
329
|
+
controller.abort();
|
|
330
|
+
}, timeoutMs);
|
|
331
|
+
if (options?.signal) {
|
|
332
|
+
if (options.signal.aborted) {
|
|
333
|
+
clearTimeout(timer);
|
|
334
|
+
controller.abort();
|
|
335
|
+
} else {
|
|
336
|
+
options.signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
const response = await this.fetchFn(url, {
|
|
341
|
+
...init,
|
|
342
|
+
signal: controller.signal
|
|
343
|
+
});
|
|
344
|
+
if (__privateGet(this, _debug)) {
|
|
345
|
+
const elapsed = Date.now() - startTime;
|
|
346
|
+
__privateGet(this, _logger).debug(`[BookingSDK] <-- ${response.status} (${elapsed}ms)`);
|
|
347
|
+
}
|
|
348
|
+
if (!response.ok) {
|
|
349
|
+
if (response.status === 429 && this.shouldRetry(method, effectiveRetry, attempt)) {
|
|
350
|
+
const retryAfterHeader2 = response.headers.get("Retry-After");
|
|
351
|
+
const retryAfterSeconds = parseRetryAfterHeader(retryAfterHeader2);
|
|
352
|
+
const cappedSeconds = Math.min(retryAfterSeconds, effectiveRetry.maxRetryAfter);
|
|
353
|
+
if (__privateGet(this, _debug)) {
|
|
354
|
+
__privateGet(this, _logger).debug(
|
|
355
|
+
`[BookingSDK] retry attempt ${attempt + 1}/${effectiveRetry.maxRetries} in ${cappedSeconds * 1e3}ms (reason: 429 Rate Limited)`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
await this.sleep(cappedSeconds * 1e3);
|
|
359
|
+
wasRateLimited = true;
|
|
360
|
+
lastError = response;
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (RETRYABLE_STATUSES.has(response.status) && this.shouldRetry(method, effectiveRetry, attempt)) {
|
|
364
|
+
if (__privateGet(this, _debug)) {
|
|
365
|
+
const delay = this.calculateDelay(attempt, effectiveRetry.baseDelay);
|
|
366
|
+
__privateGet(this, _logger).debug(
|
|
367
|
+
`[BookingSDK] retry attempt ${attempt + 1}/${effectiveRetry.maxRetries} in ${delay}ms (reason: ${response.status})`
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
lastError = response;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const body = await response.json().catch(() => ({}));
|
|
374
|
+
const retryAfterHeader = response.headers.get("Retry-After");
|
|
375
|
+
throw createErrorFromResponse(response, body, retryAfterHeader);
|
|
376
|
+
}
|
|
377
|
+
if (__privateGet(this, _debug)) {
|
|
378
|
+
const text = await response.clone().text().catch(() => "");
|
|
379
|
+
if (text) {
|
|
380
|
+
__privateGet(this, _logger).debug(`[BookingSDK] body preview: ${text.slice(0, 500)}`);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return response.json();
|
|
384
|
+
} catch (error) {
|
|
385
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
386
|
+
if (timedOut) {
|
|
387
|
+
throw new TimeoutError(`Request timed out after ${timeoutMs}ms`);
|
|
388
|
+
}
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
if (!(error instanceof TypeError)) {
|
|
392
|
+
throw error;
|
|
393
|
+
}
|
|
394
|
+
if (!this.shouldRetry(method, effectiveRetry, attempt)) {
|
|
395
|
+
throw error;
|
|
396
|
+
}
|
|
397
|
+
lastError = error;
|
|
398
|
+
} finally {
|
|
399
|
+
clearTimeout(timer);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (lastError instanceof Response) {
|
|
403
|
+
const body = await lastError.json().catch(() => ({}));
|
|
404
|
+
const retryAfterHeader = lastError.headers.get("Retry-After");
|
|
405
|
+
throw createErrorFromResponse(lastError, body, retryAfterHeader);
|
|
406
|
+
}
|
|
407
|
+
throw lastError;
|
|
408
|
+
}
|
|
409
|
+
async get(path, options) {
|
|
410
|
+
return this.request("GET", path, options);
|
|
411
|
+
}
|
|
412
|
+
async post(path, options) {
|
|
413
|
+
return this.request("POST", path, options);
|
|
414
|
+
}
|
|
415
|
+
async put(path, options) {
|
|
416
|
+
return this.request("PUT", path, options);
|
|
417
|
+
}
|
|
418
|
+
async patch(path, options) {
|
|
419
|
+
return this.request("PATCH", path, options);
|
|
420
|
+
}
|
|
421
|
+
async delete(path, options) {
|
|
422
|
+
return this.request("DELETE", path, options);
|
|
423
|
+
}
|
|
424
|
+
setApiKey(key) {
|
|
425
|
+
__privateSet(this, _apiKey, key);
|
|
426
|
+
}
|
|
427
|
+
setTenantId(id) {
|
|
428
|
+
__privateSet(this, _tenantId, id);
|
|
429
|
+
}
|
|
430
|
+
setDefaultHeader(key, value) {
|
|
431
|
+
this.defaultHeaders[key] = value;
|
|
432
|
+
}
|
|
433
|
+
removeDefaultHeader(key) {
|
|
434
|
+
delete this.defaultHeaders[key];
|
|
435
|
+
}
|
|
436
|
+
shouldRetry(method, config, attempt) {
|
|
437
|
+
if (attempt >= config.maxRetries) return false;
|
|
438
|
+
if (config.force) return true;
|
|
439
|
+
return config.retryOnMethods.includes(method);
|
|
440
|
+
}
|
|
441
|
+
calculateDelay(attempt, baseDelay) {
|
|
442
|
+
return baseDelay * 2 ** attempt + Math.floor(Math.random() * 100);
|
|
443
|
+
}
|
|
444
|
+
sleep(ms) {
|
|
445
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
446
|
+
}
|
|
447
|
+
buildUrl(path, query) {
|
|
448
|
+
const cleanPath = path.startsWith("/") ? path.slice(1) : path;
|
|
449
|
+
let url = `${this.baseUrl}/${cleanPath}`;
|
|
450
|
+
if (query) {
|
|
451
|
+
const params = new URLSearchParams();
|
|
452
|
+
for (const [key, value] of Object.entries(query)) {
|
|
453
|
+
if (value === null || value === void 0) {
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
if (Array.isArray(value)) {
|
|
457
|
+
for (const item of value) {
|
|
458
|
+
params.append(key, item);
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
params.set(key, String(value));
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
const qs = params.toString();
|
|
465
|
+
if (qs) {
|
|
466
|
+
url = `${url}?${qs}`;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return url;
|
|
470
|
+
}
|
|
471
|
+
buildHeaders(perRequestHeaders) {
|
|
472
|
+
return {
|
|
473
|
+
Accept: "application/json",
|
|
474
|
+
...this.defaultHeaders,
|
|
475
|
+
...perRequestHeaders
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
_apiKey = new WeakMap();
|
|
480
|
+
_tenantId = new WeakMap();
|
|
481
|
+
_retryConfig = new WeakMap();
|
|
482
|
+
_timeout = new WeakMap();
|
|
483
|
+
_debug = new WeakMap();
|
|
484
|
+
_logger = new WeakMap();
|
|
485
|
+
|
|
486
|
+
// src/client.ts
|
|
487
|
+
var BookingClient = class {
|
|
488
|
+
constructor(config) {
|
|
489
|
+
const validated = bookingClientConfigSchema.parse(config);
|
|
490
|
+
this.httpClient = new HttpClient({
|
|
491
|
+
baseUrl: validated.baseUrl,
|
|
492
|
+
apiKey: validated.apiKey,
|
|
493
|
+
tenantId: validated.tenantId,
|
|
494
|
+
timeout: validated.timeout,
|
|
495
|
+
retryConfig: validated.retry ? {
|
|
496
|
+
maxRetries: validated.retry.maxRetries,
|
|
497
|
+
baseDelay: validated.retry.baseDelay
|
|
498
|
+
} : void 0,
|
|
499
|
+
debug: validated.debug,
|
|
500
|
+
logger: validated.logger
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
setApiKey(key) {
|
|
504
|
+
if (!key || key.trim().length === 0) {
|
|
505
|
+
throw new Error("apiKey must be a non-empty string");
|
|
506
|
+
}
|
|
507
|
+
this.httpClient.setApiKey(key);
|
|
508
|
+
}
|
|
509
|
+
setTenantId(id) {
|
|
510
|
+
if (!id || id.trim().length === 0) {
|
|
511
|
+
throw new Error("tenantId must be a non-empty string");
|
|
512
|
+
}
|
|
513
|
+
this.httpClient.setTenantId(id);
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
// src/pagination.ts
|
|
518
|
+
function paginate(fetcher, options) {
|
|
519
|
+
return {
|
|
520
|
+
[Symbol.asyncIterator]() {
|
|
521
|
+
let cursor = options?.cursor;
|
|
522
|
+
let done = false;
|
|
523
|
+
return {
|
|
524
|
+
async next() {
|
|
525
|
+
if (done) return { value: void 0, done: true };
|
|
526
|
+
const result = await fetcher({ ...options ?? {}, cursor });
|
|
527
|
+
if (!result.hasMore || result.cursor === null) {
|
|
528
|
+
done = true;
|
|
529
|
+
} else {
|
|
530
|
+
cursor = result.cursor;
|
|
531
|
+
}
|
|
532
|
+
return { value: result.data, done: false };
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
async function firstPage(fetcher, options) {
|
|
539
|
+
return fetcher({ ...options ?? {} });
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// src/index.ts
|
|
543
|
+
var VERSION = "0.1.0";
|
|
27
544
|
// Annotate the CommonJS export names for ESM import in node:
|
|
28
545
|
0 && (module.exports = {
|
|
29
|
-
|
|
546
|
+
AuthenticationError,
|
|
547
|
+
BookingClient,
|
|
548
|
+
BookingError,
|
|
549
|
+
ConflictError,
|
|
550
|
+
ForbiddenError,
|
|
551
|
+
HttpClient,
|
|
552
|
+
NotFoundError,
|
|
553
|
+
PaymentError,
|
|
554
|
+
RateLimitError,
|
|
555
|
+
ServerError,
|
|
556
|
+
TimeoutError,
|
|
557
|
+
VERSION,
|
|
558
|
+
ValidationError,
|
|
559
|
+
bookingClientConfigSchema,
|
|
560
|
+
createErrorFromResponse,
|
|
561
|
+
firstPage,
|
|
562
|
+
paginate
|
|
30
563
|
});
|
|
31
564
|
//# sourceMappingURL=index.cjs.map
|