hospitable 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.
@@ -0,0 +1,390 @@
1
+ interface RetryConfig {
2
+ maxAttempts?: number;
3
+ baseDelay?: number;
4
+ maxDelay?: number;
5
+ onRateLimit?: (info: {
6
+ retryAfter: number;
7
+ endpoint: string;
8
+ attempt: number;
9
+ }) => void;
10
+ }
11
+
12
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
13
+ interface RequestOptions {
14
+ method?: HttpMethod;
15
+ params?: Record<string, string | number | boolean | string[] | undefined>;
16
+ body?: unknown;
17
+ headers?: Record<string, string>;
18
+ }
19
+ interface HttpClientConfig {
20
+ baseURL: string;
21
+ getAuthHeader: () => Promise<string>;
22
+ onUnauthorized?: () => Promise<void>;
23
+ debug?: boolean;
24
+ retryConfig?: RetryConfig;
25
+ }
26
+ declare class HttpClient {
27
+ private readonly config;
28
+ constructor(config: HttpClientConfig);
29
+ request<T>(path: string, options?: RequestOptions): Promise<T>;
30
+ get<T>(path: string, params?: RequestOptions['params']): Promise<T>;
31
+ post<T>(path: string, body?: unknown): Promise<T>;
32
+ put<T>(path: string, body?: unknown): Promise<T>;
33
+ patch<T>(path: string, body?: unknown): Promise<T>;
34
+ delete<T>(path: string): Promise<T>;
35
+ }
36
+
37
+ interface PriceAmount {
38
+ amount: number;
39
+ currency: string;
40
+ }
41
+ interface CalendarDay {
42
+ date: string;
43
+ available: boolean;
44
+ price: PriceAmount;
45
+ minStay: number;
46
+ maxStay: number | null;
47
+ notes: string | null;
48
+ blockedReason: string | null;
49
+ }
50
+ interface CalendarUpdate {
51
+ date: string;
52
+ price?: {
53
+ amount: number;
54
+ };
55
+ available?: boolean;
56
+ minStay?: number;
57
+ maxStay?: number | null;
58
+ notes?: string | null;
59
+ }
60
+ interface CalendarGetParams {
61
+ startDate: string;
62
+ endDate: string;
63
+ }
64
+
65
+ interface PaginatedResponse<T> {
66
+ data: T[];
67
+ meta: {
68
+ nextCursor: string | null;
69
+ total: number;
70
+ perPage: number;
71
+ };
72
+ }
73
+
74
+ declare class CalendarResource {
75
+ private readonly http;
76
+ constructor(http: HttpClient);
77
+ get(propertyId: string, startDate: string, endDate: string): Promise<PaginatedResponse<CalendarDay>>;
78
+ update(propertyId: string, updates: CalendarUpdate[]): Promise<void>;
79
+ block(propertyId: string, startDate: string, endDate: string, reason?: string): Promise<void>;
80
+ unblock(propertyId: string, startDate: string, endDate: string): Promise<void>;
81
+ }
82
+
83
+ type MessageDirection = 'outbound' | 'inbound';
84
+ interface Message {
85
+ id: string;
86
+ reservationId: string;
87
+ direction: MessageDirection;
88
+ body: string;
89
+ sentAt: string;
90
+ readAt: string | null;
91
+ senderName: string;
92
+ }
93
+ interface MessageThread {
94
+ reservationId: string;
95
+ messages: Message[];
96
+ unreadCount: number;
97
+ }
98
+ interface SendMessageRequest {
99
+ body: string;
100
+ }
101
+ interface MessageTemplate {
102
+ id: string;
103
+ name: string;
104
+ body: string;
105
+ variables: string[];
106
+ }
107
+
108
+ declare class MessagesResource {
109
+ private readonly http;
110
+ constructor(http: HttpClient);
111
+ list(reservationId: string): Promise<MessageThread>;
112
+ send(reservationId: string, body: string): Promise<Message>;
113
+ listTemplates(): Promise<MessageTemplate[]>;
114
+ sendTemplate(reservationId: string, templateId: string, variables?: Record<string, string>): Promise<Message>;
115
+ }
116
+
117
+ type PropertyPlatform = 'airbnb' | 'vrbo' | 'booking_com' | 'direct' | string;
118
+ interface PropertyTag {
119
+ id: string;
120
+ name: string;
121
+ }
122
+ interface Property {
123
+ id: string;
124
+ name: string;
125
+ platform: PropertyPlatform;
126
+ platformId: string;
127
+ active: boolean;
128
+ timezone: string;
129
+ currency: string;
130
+ address: {
131
+ street: string;
132
+ city: string;
133
+ state: string;
134
+ country: string;
135
+ zipCode: string;
136
+ };
137
+ tags: PropertyTag[];
138
+ createdAt: string;
139
+ updatedAt: string;
140
+ }
141
+ type PropertyList = PaginatedResponse<Property>;
142
+
143
+ interface PropertyListParams {
144
+ cursor?: string;
145
+ perPage?: number;
146
+ tags?: string[];
147
+ }
148
+ declare class PropertiesResource {
149
+ private readonly http;
150
+ constructor(http: HttpClient);
151
+ list(params?: PropertyListParams): Promise<PropertyList>;
152
+ get(id: string): Promise<Property>;
153
+ listTags(id: string): Promise<PropertyTag[]>;
154
+ getCalendar(id: string, startDate: string, endDate: string): Promise<PaginatedResponse<CalendarDay>>;
155
+ updateCalendar(id: string, updates: CalendarUpdate[]): Promise<void>;
156
+ iter(params?: Omit<PropertyListParams, 'cursor'>): AsyncGenerator<Property>;
157
+ }
158
+
159
+ type ReservationStatus = 'confirmed' | 'pending' | 'cancelled' | 'inquiry' | 'declined' | 'expired';
160
+ type ReservationPlatform = 'airbnb' | 'vrbo' | 'booking_com' | 'direct' | string;
161
+ interface Guest {
162
+ id: string;
163
+ firstName: string;
164
+ lastName: string;
165
+ email: string;
166
+ phone: string;
167
+ avatarUrl: string | null;
168
+ verified: boolean;
169
+ }
170
+ interface ReservationMoney {
171
+ amount: number;
172
+ currency: string;
173
+ }
174
+ interface Reservation {
175
+ id: string;
176
+ propertyId: string;
177
+ platform: ReservationPlatform;
178
+ platformId: string;
179
+ status: ReservationStatus;
180
+ checkinDate: string;
181
+ checkoutDate: string;
182
+ nights: number;
183
+ guestCount: number;
184
+ guest?: Guest;
185
+ totalAmount: ReservationMoney;
186
+ cleaningFee: ReservationMoney;
187
+ platformFee: ReservationMoney;
188
+ createdAt: string;
189
+ updatedAt: string;
190
+ }
191
+ type ReservationList = PaginatedResponse<Reservation>;
192
+ interface ReservationListParams {
193
+ properties?: string[];
194
+ startDate?: string;
195
+ endDate?: string;
196
+ status?: ReservationStatus | ReservationStatus[];
197
+ include?: string;
198
+ cursor?: string;
199
+ perPage?: number;
200
+ }
201
+
202
+ declare class ReservationsResource {
203
+ private readonly http;
204
+ constructor(http: HttpClient);
205
+ list(params?: ReservationListParams): Promise<ReservationList>;
206
+ get(id: string, include?: string): Promise<Reservation>;
207
+ getUpcoming(propertyIds: string[], options?: {
208
+ include?: string;
209
+ }): Promise<ReservationList>;
210
+ iter(params?: Omit<ReservationListParams, 'cursor'>): AsyncGenerator<Reservation>;
211
+ }
212
+
213
+ interface ReviewRatings {
214
+ overall: number;
215
+ cleanliness: number | null;
216
+ communication: number | null;
217
+ checkIn: number | null;
218
+ accuracy: number | null;
219
+ location: number | null;
220
+ value: number | null;
221
+ }
222
+ interface Review {
223
+ id: string;
224
+ reservationId: string;
225
+ propertyId: string;
226
+ guestName: string;
227
+ ratings: ReviewRatings;
228
+ body: string;
229
+ response: string | null;
230
+ submittedAt: string;
231
+ respondedAt: string | null;
232
+ }
233
+ type ReviewList = PaginatedResponse<Review>;
234
+ interface ReviewListParams {
235
+ propertyId?: string;
236
+ responded?: boolean;
237
+ cursor?: string;
238
+ perPage?: number;
239
+ }
240
+
241
+ declare class ReviewsResource {
242
+ private readonly http;
243
+ constructor(http: HttpClient);
244
+ list(params?: ReviewListParams): Promise<ReviewList>;
245
+ get(id: string): Promise<Review>;
246
+ respond(id: string, responseText: string): Promise<Review>;
247
+ iter(params?: Omit<ReviewListParams, 'cursor'>): AsyncGenerator<Review>;
248
+ }
249
+
250
+ interface HospitableClientConfig {
251
+ /** Personal Access Token. Also read from HOSPITABLE_PAT env var. */
252
+ token?: string;
253
+ /** OAuth2 refresh token */
254
+ refreshToken?: string;
255
+ /** OAuth2 client ID */
256
+ clientId?: string;
257
+ /** OAuth2 client secret */
258
+ clientSecret?: string;
259
+ /** API base URL. Defaults to https://api.hospitable.com */
260
+ baseURL?: string;
261
+ /** Retry configuration */
262
+ retry?: RetryConfig;
263
+ /** Enable debug logging */
264
+ debug?: boolean;
265
+ }
266
+ declare class HospitableClient {
267
+ readonly properties: PropertiesResource;
268
+ readonly reservations: ReservationsResource;
269
+ readonly calendar: CalendarResource;
270
+ readonly messages: MessagesResource;
271
+ readonly reviews: ReviewsResource;
272
+ constructor(config?: HospitableClientConfig);
273
+ }
274
+
275
+ declare class HospitableError extends Error {
276
+ readonly statusCode: number;
277
+ readonly requestId: string | undefined;
278
+ constructor(message: string, statusCode: number, requestId?: string);
279
+ }
280
+ declare class AuthenticationError extends HospitableError {
281
+ constructor(message?: string, requestId?: string);
282
+ }
283
+ declare class RateLimitError extends HospitableError {
284
+ readonly retryAfter: number;
285
+ constructor(retryAfter: number, requestId?: string);
286
+ }
287
+ declare class NotFoundError extends HospitableError {
288
+ readonly resource: string | undefined;
289
+ constructor(message?: string, requestId?: string, resource?: string);
290
+ }
291
+ declare class ValidationError extends HospitableError {
292
+ readonly fields: Record<string, string[]>;
293
+ constructor(message: string, fields?: Record<string, string[]>, requestId?: string);
294
+ }
295
+ declare class ForbiddenError extends HospitableError {
296
+ constructor(message?: string, requestId?: string);
297
+ }
298
+ declare class ServerError extends HospitableError {
299
+ readonly attempts: number;
300
+ constructor(message: string, statusCode: number, attempts: number, requestId?: string);
301
+ }
302
+ declare function createErrorFromResponse(statusCode: number, body: Record<string, unknown>, requestId?: string, attempts?: number): HospitableError;
303
+
304
+ interface ClientConfig {
305
+ token?: string;
306
+ refreshToken?: string;
307
+ clientId?: string;
308
+ clientSecret?: string;
309
+ baseURL?: string;
310
+ onRateLimit?: (info: RateLimitInfo) => void;
311
+ debug?: boolean;
312
+ }
313
+ interface TokenResponse {
314
+ accessToken: string;
315
+ refreshToken: string;
316
+ expiresIn: number;
317
+ tokenType: string;
318
+ }
319
+ interface RateLimitInfo {
320
+ retryAfter: number;
321
+ endpoint: string;
322
+ attempt: number;
323
+ }
324
+
325
+ interface TokenManagerConfig {
326
+ token?: string;
327
+ refreshToken?: string;
328
+ clientId?: string;
329
+ clientSecret?: string;
330
+ baseURL: string;
331
+ }
332
+ declare class TokenManager {
333
+ private readonly config;
334
+ private accessToken;
335
+ private refreshToken;
336
+ private expiresAt;
337
+ private refreshPromise;
338
+ constructor(config: TokenManagerConfig);
339
+ getAuthHeader(): Promise<string>;
340
+ private needsRefresh;
341
+ private ensureRefreshed;
342
+ private doRefresh;
343
+ handleUnauthorized(): Promise<void>;
344
+ }
345
+
346
+ interface PageFetcher<T, P extends {
347
+ cursor?: string;
348
+ perPage?: number;
349
+ }> {
350
+ (params: P): Promise<PaginatedResponse<T>>;
351
+ }
352
+ declare function paginate<T, P extends {
353
+ cursor?: string;
354
+ perPage?: number;
355
+ }>(fetcher: PageFetcher<T, P>, params: Omit<P, 'cursor'>, perPage?: number): AsyncGenerator<T>;
356
+ declare function collectAll<T, P extends {
357
+ cursor?: string;
358
+ perPage?: number;
359
+ }>(fetcher: PageFetcher<T, P>, params: Omit<P, 'cursor'>, perPage?: number): Promise<T[]>;
360
+
361
+ /**
362
+ * Recursively masks PII and sensitive fields in an object for safe logging.
363
+ * Does NOT mutate the original — returns a new object with masked values.
364
+ * Only affects log output; never called on actual API payloads.
365
+ */
366
+ declare function sanitize(value: unknown, depth?: number): unknown;
367
+
368
+ declare class ReservationFilter {
369
+ private readonly params;
370
+ constructor(params?: ReservationListParams);
371
+ checkinAfter(date: string): ReservationFilter;
372
+ checkinBefore(date: string): ReservationFilter;
373
+ status(status: ReservationStatus | ReservationStatus[]): ReservationFilter;
374
+ properties(ids: string[]): ReservationFilter;
375
+ include(...fields: string[]): ReservationFilter;
376
+ perPage(n: number): ReservationFilter;
377
+ toParams(): ReservationListParams;
378
+ }
379
+
380
+ declare class PropertyFilter {
381
+ private readonly params;
382
+ constructor(params?: PropertyListParams);
383
+ tags(tagIds: string[]): PropertyFilter;
384
+ perPage(n: number): PropertyFilter;
385
+ toParams(): PropertyListParams;
386
+ }
387
+
388
+ declare const VERSION = "0.1.0";
389
+
390
+ export { AuthenticationError, type CalendarDay, type CalendarGetParams, CalendarResource, type CalendarUpdate, type ClientConfig, ForbiddenError, type Guest, HospitableClient, type HospitableClientConfig, HospitableError, type Message, type MessageDirection, type MessageTemplate, type MessageThread, MessagesResource, NotFoundError, type PageFetcher, type PaginatedResponse, type PriceAmount, PropertiesResource, type Property, PropertyFilter, type PropertyList, type PropertyListParams, type PropertyPlatform, type PropertyTag, RateLimitError, type RateLimitInfo, type Reservation, ReservationFilter, type ReservationList, type ReservationListParams, type ReservationMoney, type ReservationPlatform, type ReservationStatus, ReservationsResource, type Review, type ReviewList, type ReviewListParams, type ReviewRatings, ReviewsResource, type SendMessageRequest, ServerError, TokenManager, type TokenManagerConfig, type TokenResponse, VERSION, ValidationError, collectAll, createErrorFromResponse, paginate, sanitize };