more-apartments-astro-integration 1.0.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/dist/index.mjs ADDED
@@ -0,0 +1,964 @@
1
+ import { z } from 'zod';
2
+
3
+ // src/client.ts
4
+ var PaginationLinksSchema = z.object({
5
+ first: z.string().nullable(),
6
+ last: z.string().nullable(),
7
+ prev: z.string().nullable(),
8
+ next: z.string().nullable()
9
+ });
10
+ var PaginationMetaSchema = z.object({
11
+ current_page: z.number(),
12
+ from: z.number().nullable(),
13
+ last_page: z.number(),
14
+ links: z.array(z.object({
15
+ url: z.string().nullable(),
16
+ label: z.string(),
17
+ active: z.boolean()
18
+ })),
19
+ path: z.string(),
20
+ per_page: z.number(),
21
+ to: z.number().nullable(),
22
+ total: z.number()
23
+ });
24
+ var PaginatedResponseSchema = (dataSchema) => z.object({
25
+ data: z.array(dataSchema),
26
+ links: PaginationLinksSchema,
27
+ meta: PaginationMetaSchema
28
+ });
29
+ var ApiErrorSchema = z.object({
30
+ message: z.string(),
31
+ errors: z.record(z.array(z.string())).optional()
32
+ });
33
+ var PropertyImageSchema = z.object({
34
+ id: z.number(),
35
+ url: z.string(),
36
+ alt: z.string().optional()
37
+ });
38
+ var PropertySchema = z.object({
39
+ id: z.number(),
40
+ external_id: z.number().optional(),
41
+ name: z.string(),
42
+ slug: z.string(),
43
+ // Descriptions
44
+ short_description: z.string().nullable(),
45
+ description: z.string(),
46
+ area_description: z.string().nullable(),
47
+ arrival_description: z.string().nullable(),
48
+ // Property type & capacity
49
+ type: z.string().nullable(),
50
+ max_persons: z.number().nullable(),
51
+ bedrooms: z.number().nullable(),
52
+ bathrooms: z.number().nullable(),
53
+ toilets: z.number().nullable(),
54
+ size: z.number().nullable(),
55
+ floor: z.number().nullable(),
56
+ // Location
57
+ street: z.string().nullable(),
58
+ zipcode: z.string().nullable(),
59
+ area: z.string().nullable(),
60
+ city: z.string(),
61
+ country: z.string(),
62
+ latitude: z.number(),
63
+ longitude: z.number(),
64
+ // Beds
65
+ single_bed: z.number().nullable(),
66
+ double_bed: z.number().nullable(),
67
+ single_sofa: z.number().nullable(),
68
+ double_sofa: z.number().nullable(),
69
+ single_bunk: z.number().nullable(),
70
+ // Amenities - Outdoor
71
+ balcony: z.boolean(),
72
+ terrace: z.boolean(),
73
+ view: z.string().nullable(),
74
+ // Amenities - Climate
75
+ airco: z.boolean(),
76
+ fans: z.boolean(),
77
+ heating: z.boolean(),
78
+ // Amenities - Connectivity
79
+ internet: z.string().nullable(),
80
+ internet_connection: z.string().nullable(),
81
+ tv: z.string().nullable(),
82
+ tv_connection: z.string().nullable(),
83
+ dvd: z.boolean(),
84
+ computer: z.boolean(),
85
+ printer: z.boolean(),
86
+ // Amenities - Kitchen
87
+ dishwasher: z.boolean(),
88
+ oven: z.boolean(),
89
+ microwave: z.boolean(),
90
+ fridge: z.boolean(),
91
+ freezer: z.boolean(),
92
+ toaster: z.boolean(),
93
+ kettle: z.boolean(),
94
+ coffeemachine: z.boolean(),
95
+ // Amenities - Laundry
96
+ washingmachine: z.boolean(),
97
+ dryer: z.boolean(),
98
+ iron: z.boolean(),
99
+ // Amenities - Bathroom
100
+ bathtub: z.boolean(),
101
+ jacuzzi: z.boolean(),
102
+ shower_regular: z.boolean(),
103
+ shower_steam: z.boolean(),
104
+ hairdryer: z.boolean(),
105
+ // Amenities - Recreation
106
+ swimmingpool: z.string().nullable(),
107
+ sauna: z.string().nullable(),
108
+ // Amenities - General
109
+ parking: z.string().nullable(),
110
+ entresol: z.boolean(),
111
+ wheelchair_friendly: z.boolean(),
112
+ smoking_allowed: z.boolean(),
113
+ pets_allowed: z.boolean(),
114
+ // Supplies
115
+ supplies_coffee: z.boolean(),
116
+ supplies_tea: z.boolean(),
117
+ supplies_milk: z.boolean(),
118
+ supplies_sugar: z.boolean(),
119
+ supplies_dishwasher_tablets: z.boolean(),
120
+ // Services
121
+ service_linen: z.boolean(),
122
+ service_towels: z.boolean(),
123
+ // Costs & Policies
124
+ cleaning_costs: z.number().nullable(),
125
+ deposit_costs: z.number().nullable(),
126
+ min_rate: z.number().nullable(),
127
+ minimal_nights: z.number().nullable(),
128
+ maximal_nights: z.number().nullable(),
129
+ // Check-in/out
130
+ check_in: z.string().nullable(),
131
+ check_out: z.string().nullable(),
132
+ // Media
133
+ images: z.array(z.object({
134
+ id: z.number(),
135
+ url: z.string(),
136
+ thumb_url: z.string(),
137
+ alt: z.string()
138
+ })).optional(),
139
+ // Metadata
140
+ status: z.string().nullable(),
141
+ provider_name: z.string().nullable(),
142
+ created_at: z.string(),
143
+ updated_at: z.string()
144
+ });
145
+ var AvailableDay = z.object({
146
+ available: z.boolean(),
147
+ morning_available: z.boolean(),
148
+ date: z.string(),
149
+ day: z.number()
150
+ });
151
+ var AvailabilitySchema = z.object({
152
+ days: z.record(z.string(), AvailableDay)
153
+ });
154
+ var PropertySearchParamsSchema = z.object({
155
+ // Date filters
156
+ arrival: z.string().optional(),
157
+ departure: z.string().optional(),
158
+ // Guest capacity
159
+ guests: z.number().optional(),
160
+ // General search (deprecated in favor of direct column filters)
161
+ destination: z.string().optional(),
162
+ segment: z.string().optional(),
163
+ // DEPRECATED: use city/area instead
164
+ // Direct column filters (preferred for headless instances)
165
+ city: z.string().optional(),
166
+ area: z.string().optional(),
167
+ propertyType: z.string().optional(),
168
+ bedrooms: z.number().optional(),
169
+ bathrooms: z.number().optional(),
170
+ maxPersons: z.number().optional(),
171
+ elevator: z.boolean().optional(),
172
+ parking: z.boolean().optional(),
173
+ balcony: z.boolean().optional()
174
+ });
175
+ var PropertySearchResultSchema = z.object({
176
+ data: z.array(PropertySchema)
177
+ });
178
+ var PropertyPageSettingsSchema = z.object({
179
+ routing: z.object({
180
+ base_url: z.string()
181
+ }),
182
+ index: z.object({
183
+ seo: z.object({
184
+ title: z.string(),
185
+ description: z.string(),
186
+ openGraphTitle: z.string().optional(),
187
+ tags: z.array(z.string()).optional()
188
+ })
189
+ }),
190
+ show: z.object({
191
+ hero: z.object({
192
+ provider: z.boolean().optional(),
193
+ address: z.boolean().optional()
194
+ }).optional(),
195
+ cancellation_policy: z.object({
196
+ description: z.string()
197
+ }).optional(),
198
+ related_properties: z.object({
199
+ title: z.string()
200
+ }).optional()
201
+ }).optional()
202
+ });
203
+ var PageSchema = z.object({
204
+ id: z.string(),
205
+ slug: z.string(),
206
+ title: z.string().nullable(),
207
+ description: z.string().nullable(),
208
+ content: z.string().nullable(),
209
+ sections: z.array(z.any()),
210
+ seo: z.object({
211
+ title: z.string(),
212
+ description: z.string(),
213
+ image: z.string().nullable()
214
+ }),
215
+ route_name: z.string()
216
+ });
217
+ var PostSchema = z.object({
218
+ id: z.string(),
219
+ slug: z.string(),
220
+ title: z.string(),
221
+ description: z.string().nullable(),
222
+ content: z.string().nullable(),
223
+ excerpt: z.string().nullable(),
224
+ author: z.string().nullable(),
225
+ date: z.string(),
226
+ // ISO date string
227
+ image: z.string().nullable(),
228
+ tags: z.array(z.string()),
229
+ reading_time: z.string().nullable(),
230
+ sections: z.array(z.any()),
231
+ seo: z.object({
232
+ title: z.string(),
233
+ description: z.string(),
234
+ image: z.string().nullable()
235
+ }),
236
+ route_name: z.string()
237
+ });
238
+ var CategorySchema = z.object({
239
+ slug: z.string(),
240
+ name: z.string(),
241
+ title: z.string(),
242
+ description: z.string().nullable(),
243
+ content: z.string().nullable(),
244
+ segments: z.union([z.array(z.string()), z.number()]).optional()
245
+ });
246
+ var CategorySegmentSchema = z.object({
247
+ name: z.string(),
248
+ slug: z.string(),
249
+ title: z.string(),
250
+ description: z.string().nullable(),
251
+ tags: z.array(z.string()).optional(),
252
+ sections: z.array(z.any()),
253
+ content: z.string().nullable(),
254
+ image: z.string()
255
+ });
256
+ var MainSettingsSchema = z.object({
257
+ site: z.object({
258
+ name: z.string(),
259
+ domain: z.string(),
260
+ locale: z.string()
261
+ }),
262
+ contact: z.object({
263
+ email: z.string(),
264
+ phone: z.string().optional()
265
+ }),
266
+ social: z.object({
267
+ facebook: z.string().optional(),
268
+ instagram: z.string().optional()
269
+ }).optional(),
270
+ mail: z.object({
271
+ from: z.object({
272
+ address: z.string(),
273
+ name: z.string()
274
+ }),
275
+ contact_form_to: z.string()
276
+ }).optional(),
277
+ pms: z.object({
278
+ property_providers: z.array(z.object({
279
+ name: z.string(),
280
+ system: z.string(),
281
+ api_key: z.string().optional(),
282
+ base_url: z.string().optional(),
283
+ discount: z.number().optional(),
284
+ enabled: z.boolean().optional()
285
+ }))
286
+ }).optional(),
287
+ pricing: z.object({
288
+ vat: z.number(),
289
+ tourist_tax: z.object({
290
+ type: z.string(),
291
+ value: z.number()
292
+ })
293
+ }).optional(),
294
+ discount: z.number().optional()
295
+ });
296
+ var ThemeSettingsSchema = z.object({
297
+ logo: z.object({
298
+ path: z.string(),
299
+ height: z.number().optional()
300
+ }).optional(),
301
+ favicon_path: z.string().optional(),
302
+ colors: z.object({
303
+ primary: z.string(),
304
+ secondary: z.string()
305
+ }),
306
+ layout: z.object({
307
+ homepage_style: z.string().optional(),
308
+ navigation: z.object({
309
+ variant: z.string().optional(),
310
+ items: z.array(z.any()),
311
+ buttons: z.array(z.any()).optional()
312
+ }).optional(),
313
+ footer: z.object({
314
+ blog_title: z.string().optional(),
315
+ contact_title: z.string().optional(),
316
+ categories: z.array(z.any()).optional()
317
+ }).optional()
318
+ }).optional()
319
+ });
320
+ var PropertySettingsSchema = z.object({
321
+ routing: z.object({
322
+ base_url: z.string()
323
+ }),
324
+ seo: z.object({
325
+ title: z.string(),
326
+ description: z.string(),
327
+ openGraphTitle: z.string().optional(),
328
+ tags: z.array(z.string()).optional()
329
+ }).optional(),
330
+ index: z.object({
331
+ seo: z.object({
332
+ title: z.string(),
333
+ description: z.string(),
334
+ openGraphTitle: z.string().optional(),
335
+ tags: z.array(z.string()).optional()
336
+ })
337
+ }),
338
+ show: z.object({
339
+ hero: z.object({
340
+ provider: z.boolean().optional(),
341
+ address: z.boolean().optional()
342
+ }).optional(),
343
+ cancellation_policy: z.object({
344
+ description: z.string()
345
+ }).optional(),
346
+ related_properties: z.object({
347
+ title: z.string()
348
+ }).optional()
349
+ }).optional()
350
+ });
351
+ var BookingSettingsSchema = z.object({
352
+ booking_confirmation: z.object({
353
+ sections: z.object({
354
+ arrival_description: z.boolean().optional()
355
+ }).optional(),
356
+ content: z.object({
357
+ body: z.string().optional(),
358
+ help: z.string().optional()
359
+ }).optional()
360
+ }).optional()
361
+ });
362
+ var BookingRequestSchema = z.object({
363
+ property_id: z.number(),
364
+ check_in: z.string(),
365
+ check_out: z.string(),
366
+ guests: z.number(),
367
+ first_name: z.string(),
368
+ last_name: z.string(),
369
+ email: z.string().email(),
370
+ phone: z.string().optional(),
371
+ notes: z.string().optional(),
372
+ total_amount: z.number(),
373
+ payment_method: z.enum(["stripe", "cash", "bank_transfer"]).optional()
374
+ });
375
+ var BookingResponseSchema = z.object({
376
+ id: z.string(),
377
+ property_id: z.number(),
378
+ check_in: z.string(),
379
+ check_out: z.string(),
380
+ guests: z.number(),
381
+ status: z.enum(["pending", "confirmed", "cancelled", "completed"]),
382
+ total_amount: z.number(),
383
+ payment_status: z.enum(["pending", "paid", "refunded"]),
384
+ confirmation_code: z.string(),
385
+ created_at: z.string(),
386
+ updated_at: z.string()
387
+ });
388
+ var MoreApartmentsConfigSchema = z.object({
389
+ baseUrl: z.string().optional(),
390
+ apiKey: z.string().optional(),
391
+ instance: z.string().optional(),
392
+ timeout: z.number().optional(),
393
+ retry: z.object({
394
+ attempts: z.number(),
395
+ delay: z.number()
396
+ }).optional(),
397
+ cache: z.object({
398
+ enabled: z.boolean(),
399
+ ttl: z.number()
400
+ }).optional()
401
+ });
402
+
403
+ // src/client.ts
404
+ var MoreApartmentsClient = class {
405
+ config;
406
+ cache = /* @__PURE__ */ new Map();
407
+ /**
408
+ * Clear all cached data
409
+ */
410
+ clearCache() {
411
+ this.cache.clear();
412
+ }
413
+ /**
414
+ * Get cache statistics
415
+ */
416
+ getCacheStats() {
417
+ return {
418
+ entries: this.cache.size,
419
+ size: Array.from(this.cache.values()).reduce((total, entry) => {
420
+ return total + JSON.stringify(entry.data).length;
421
+ }, 0)
422
+ };
423
+ }
424
+ constructor(config) {
425
+ this.config = {
426
+ baseUrl: config.baseUrl?.replace(/\/$/, "") || "",
427
+ apiKey: config.apiKey || "",
428
+ instance: config.instance || "",
429
+ timeout: config.timeout || 3e4,
430
+ retry: {
431
+ attempts: config.retry?.attempts || 3,
432
+ delay: config.retry?.delay || 1e3
433
+ },
434
+ cache: {
435
+ enabled: config.cache?.enabled ?? true,
436
+ ttl: config.cache?.ttl || 3e5
437
+ // 5 minutes default
438
+ }
439
+ };
440
+ }
441
+ async fetchWithRetry(url, options = {}, schema) {
442
+ const cacheKey = `${options.method || "GET"}:${url}`;
443
+ if (this.config.cache?.enabled && (!options.method || options.method === "GET")) {
444
+ const cached = this.cache.get(cacheKey);
445
+ if (cached && this.config.cache?.ttl && Date.now() - cached.timestamp < this.config.cache.ttl) {
446
+ return cached.data;
447
+ }
448
+ }
449
+ const headers = {
450
+ "Content-Type": "application/json",
451
+ "Accept": "application/json",
452
+ ...this.config.apiKey && { "Authorization": `Bearer ${this.config.apiKey}` },
453
+ ...this.config.instance && { "X-Instance": this.config.instance },
454
+ ...options.headers
455
+ };
456
+ let lastError = null;
457
+ for (let attempt = 0; attempt < (this.config.retry?.attempts ?? 3); attempt++) {
458
+ try {
459
+ const controller = new AbortController();
460
+ const timeoutId = setTimeout(() => {
461
+ controller.abort();
462
+ }, this.config.timeout);
463
+ const response = await fetch(url, {
464
+ ...options,
465
+ headers,
466
+ signal: controller.signal
467
+ });
468
+ clearTimeout(timeoutId);
469
+ if (!response.ok) {
470
+ const error = await response.json().catch(() => ({ message: response.statusText }));
471
+ throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`);
472
+ }
473
+ const data = await response.json();
474
+ if (schema) {
475
+ const result = schema.safeParse(data);
476
+ if (!result.success) {
477
+ throw new Error(`Invalid response format: ${result.error.message}`);
478
+ }
479
+ const validatedData = result.data;
480
+ if (this.config.cache?.enabled && (!options.method || options.method === "GET")) {
481
+ this.cache.set(cacheKey, { data: validatedData, timestamp: Date.now() });
482
+ }
483
+ return validatedData;
484
+ }
485
+ if (this.config.cache?.enabled && (!options.method || options.method === "GET")) {
486
+ this.cache.set(cacheKey, { data, timestamp: Date.now() });
487
+ }
488
+ return data;
489
+ } catch (error) {
490
+ lastError = error;
491
+ if (attempt < (this.config.retry?.attempts ?? 3) - 1) {
492
+ await new Promise((resolve) => setTimeout(resolve, (this.config.retry?.delay ?? 1e3) * (attempt + 1)));
493
+ }
494
+ }
495
+ }
496
+ throw lastError || new Error("Request failed");
497
+ }
498
+ // Property endpoints
499
+ async getProperties(params) {
500
+ const queryParams = new URLSearchParams();
501
+ if (params?.page) queryParams.append("page", params.page.toString());
502
+ if (params?.per_page) queryParams.append("per_page", params.per_page.toString());
503
+ const url = `${this.config.baseUrl}/api/v1/properties${queryParams.toString() ? "?" + queryParams.toString() : ""}`;
504
+ return this.fetchWithRetry(url, {}, PaginatedResponseSchema(PropertySchema));
505
+ }
506
+ async getProperty(propertyIdOrSlug) {
507
+ const url = `${this.config.baseUrl}/api/v1/properties/${propertyIdOrSlug}`;
508
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: PropertySchema }));
509
+ return response.data;
510
+ }
511
+ // Availability endpoints
512
+ async getAvailability(propertySlug, startDate, endDate) {
513
+ const queryParams = new URLSearchParams({
514
+ start_date: startDate,
515
+ end_date: endDate
516
+ });
517
+ const url = `${this.config.baseUrl}/api/v1/properties/${propertySlug}/availability?${queryParams}`;
518
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: AvailabilitySchema }));
519
+ return response.data;
520
+ }
521
+ // Content endpoints
522
+ async getPages() {
523
+ const url = `${this.config.baseUrl}/api/v1/pages`;
524
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: z.array(PageSchema) }));
525
+ return response.data;
526
+ }
527
+ async getPage(slug) {
528
+ const url = `${this.config.baseUrl}/api/v1/pages/${slug}`;
529
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: PageSchema }));
530
+ return response.data;
531
+ }
532
+ async getPosts(params) {
533
+ const queryParams = new URLSearchParams();
534
+ if (params?.page) queryParams.append("page", params.page.toString());
535
+ if (params?.per_page) queryParams.append("per_page", params.per_page.toString());
536
+ if (params?.tag) queryParams.append("tag", params.tag);
537
+ const url = `${this.config.baseUrl}/api/v1/posts${queryParams.toString() ? "?" + queryParams.toString() : ""}`;
538
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: z.array(PostSchema) }));
539
+ return response.data;
540
+ }
541
+ async getPost(slug) {
542
+ const url = `${this.config.baseUrl}/api/v1/posts/${slug}`;
543
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: PostSchema }));
544
+ return response.data;
545
+ }
546
+ async getLocations() {
547
+ const url = `${this.config.baseUrl}/api/v1/locations`;
548
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: z.array(z.string()) }));
549
+ return response.data;
550
+ }
551
+ async getCategories() {
552
+ const url = `${this.config.baseUrl}/api/v1/categories`;
553
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: z.array(CategorySchema) }));
554
+ return response.data;
555
+ }
556
+ async getCategory(slug) {
557
+ const url = `${this.config.baseUrl}/api/v1/categories/${slug}`;
558
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: CategorySchema }));
559
+ return response.data;
560
+ }
561
+ async getCategorySegments(slug) {
562
+ const url = `${this.config.baseUrl}/api/v1/categories/${slug}/segments`;
563
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: z.array(CategorySegmentSchema) }));
564
+ return response.data;
565
+ }
566
+ async getCategorySegment(slug, segment) {
567
+ const url = `${this.config.baseUrl}/api/v1/categories/${slug}/segments/${segment}`;
568
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: CategorySegmentSchema }));
569
+ return response.data;
570
+ }
571
+ // Settings endpoints
572
+ async getMainSettings() {
573
+ const url = `${this.config.baseUrl}/api/v1/settings/main`;
574
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: MainSettingsSchema }));
575
+ return response.data;
576
+ }
577
+ async getThemeSettings() {
578
+ const url = `${this.config.baseUrl}/api/v1/settings/theme`;
579
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: ThemeSettingsSchema }));
580
+ return response.data;
581
+ }
582
+ async getPropertySettings() {
583
+ const url = `${this.config.baseUrl}/api/v1/settings/properties`;
584
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: PropertySettingsSchema }));
585
+ return response.data;
586
+ }
587
+ async getBookingSettings() {
588
+ const url = `${this.config.baseUrl}/api/v1/settings/booking`;
589
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: BookingSettingsSchema }));
590
+ return response.data;
591
+ }
592
+ // Booking endpoints
593
+ async createBooking(booking) {
594
+ const url = `${this.config.baseUrl}/api/v1/bookings`;
595
+ const response = await this.fetchWithRetry(
596
+ url,
597
+ {
598
+ method: "POST",
599
+ body: JSON.stringify(booking)
600
+ },
601
+ z.object({ data: BookingResponseSchema })
602
+ );
603
+ return response.data;
604
+ }
605
+ async getBooking(bookingId) {
606
+ const url = `${this.config.baseUrl}/api/v1/bookings/${bookingId}`;
607
+ const response = await this.fetchWithRetry(url, {}, z.object({ data: BookingResponseSchema }));
608
+ return response.data;
609
+ }
610
+ /**
611
+ * Search properties with advanced filtering
612
+ */
613
+ async searchProperties(params) {
614
+ const searchParams = new URLSearchParams();
615
+ if (params.arrival) searchParams.set("arrival", params.arrival);
616
+ if (params.departure) searchParams.set("departure", params.departure);
617
+ if (params.guests) searchParams.set("guests", params.guests.toString());
618
+ if (params.destination) searchParams.set("destination", params.destination);
619
+ if (params.segment) searchParams.set("segment", params.segment);
620
+ if (params.city) searchParams.set("city", params.city);
621
+ if (params.area) searchParams.set("area", params.area);
622
+ if (params.propertyType) searchParams.set("property_type", params.propertyType);
623
+ if (params.bedrooms !== void 0) searchParams.set("bedrooms", params.bedrooms.toString());
624
+ if (params.bathrooms !== void 0) searchParams.set("bathrooms", params.bathrooms.toString());
625
+ if (params.maxPersons !== void 0) searchParams.set("max_persons", params.maxPersons.toString());
626
+ if (params.elevator !== void 0) searchParams.set("elevator", params.elevator ? "1" : "0");
627
+ if (params.parking !== void 0) searchParams.set("parking", params.parking ? "1" : "0");
628
+ if (params.balcony !== void 0) searchParams.set("balcony", params.balcony ? "1" : "0");
629
+ const url = `${this.config.baseUrl}/api/v1/properties/search?${searchParams.toString()}`;
630
+ const response = await this.fetchWithRetry(url, {}, PropertySearchResultSchema);
631
+ return response.data;
632
+ }
633
+ };
634
+
635
+ // src/utils/images.ts
636
+ function getPrimaryImageUrl(property, fallbackUrl) {
637
+ if (property.images && property.images.length > 0) {
638
+ return property.images[0].url;
639
+ }
640
+ if (fallbackUrl) {
641
+ return fallbackUrl;
642
+ }
643
+ throw new Error(`Property "${property.name}" (ID: ${property.id}) has no images`);
644
+ }
645
+ function getThumbnailUrl(property, fallbackUrl) {
646
+ if (property.images && property.images.length > 0) {
647
+ return property.images[0].thumb_url;
648
+ }
649
+ if (fallbackUrl) {
650
+ return fallbackUrl;
651
+ }
652
+ throw new Error(`Property "${property.name}" (ID: ${property.id}) has no thumbnail images`);
653
+ }
654
+ function getAllImageUrls(property) {
655
+ return property.images?.map((img) => img.url) || [];
656
+ }
657
+ function getAllThumbnailUrls(property) {
658
+ return property.images?.map((img) => img.thumb_url) || [];
659
+ }
660
+ function getImageWithAlt(property, index = 0) {
661
+ const image = property.images?.[index];
662
+ if (!image?.url) {
663
+ throw new Error(`Property "${property.name}" (ID: ${property.id}) has no image at index ${index}`);
664
+ }
665
+ return {
666
+ url: image.url,
667
+ alt: image.alt || property.name
668
+ };
669
+ }
670
+ function getImage(property, index = 0) {
671
+ return property.images?.[index] || null;
672
+ }
673
+ function hasImages(property) {
674
+ return !!(property.images && Array.isArray(property.images) && property.images.length > 0);
675
+ }
676
+ function getImageCount(property) {
677
+ return Array.isArray(property.images) ? property.images.length : 0;
678
+ }
679
+
680
+ // src/index.ts
681
+ function moreApartmentsIntegration(options) {
682
+ return {
683
+ name: "@shelfwood/more-apartments-astro-integration",
684
+ hooks: {
685
+ "astro:config:setup": async ({
686
+ config: astroConfig,
687
+ updateConfig,
688
+ injectScript,
689
+ injectRoute,
690
+ logger
691
+ }) => {
692
+ let apiKey = options.apiKey;
693
+ let apiKeySource = "environment variable";
694
+ if (options.instancePath && !apiKey) {
695
+ try {
696
+ const fs = await import('fs');
697
+ const path = await import('path');
698
+ const resolvedInstancePath = path.resolve(process.cwd(), options.instancePath);
699
+ const devKeyPath = path.join(resolvedInstancePath, ".dev-api-key");
700
+ if (fs.existsSync(devKeyPath)) {
701
+ apiKey = fs.readFileSync(devKeyPath, "utf-8").trim();
702
+ apiKeySource = `${path.basename(resolvedInstancePath)}/.dev-api-key`;
703
+ logger.info(`\u2713 Using development API key from ${apiKeySource}`);
704
+ } else {
705
+ logger.warn(`Instance directory configured but .dev-api-key not found. Run: php artisan dev:generate-api-key --instance=${path.basename(resolvedInstancePath)}`);
706
+ }
707
+ } catch (error) {
708
+ logger.debug(`Could not read .dev-api-key: ${error}`);
709
+ }
710
+ } else if (apiKey) {
711
+ logger.info(`\u2713 Using API key from ${apiKeySource}`);
712
+ } else {
713
+ logger.warn("\u26A0\uFE0F No API key configured. Set MORE_APARTMENTS_API_KEY or configure instancePath for auto-discovery");
714
+ }
715
+ const clientOptions = { ...options, apiKey };
716
+ new MoreApartmentsClient(clientOptions);
717
+ if (options.virtualModules !== false) {
718
+ updateConfig({
719
+ vite: {
720
+ plugins: [
721
+ {
722
+ name: "more-apartments-virtual-modules",
723
+ resolveId(id) {
724
+ if (id === "virtual:more-apartments/client") {
725
+ return "\0virtual:more-apartments/client";
726
+ }
727
+ if (id === "virtual:more-apartments/config") {
728
+ return "\0virtual:more-apartments/config";
729
+ }
730
+ },
731
+ load(id) {
732
+ if (id === "\0virtual:more-apartments/client") {
733
+ const clientConfig = {
734
+ baseUrl: options.baseUrl,
735
+ instance: options.instance
736
+ // Never include apiKey in client-side code
737
+ };
738
+ return `
739
+ import { MoreApartmentsClient } from '@shelfwood/more-apartments-astro-integration';
740
+
741
+ const config = ${JSON.stringify(clientConfig)};
742
+ export const client = new MoreApartmentsClient(config);
743
+ export default client;
744
+ `;
745
+ }
746
+ if (id === "\0virtual:more-apartments/config") {
747
+ const clientConfig = {
748
+ baseUrl: options.baseUrl,
749
+ instance: options.instance
750
+ };
751
+ return `export default ${JSON.stringify(clientConfig)};`;
752
+ }
753
+ }
754
+ }
755
+ ]
756
+ }
757
+ });
758
+ logger.info("Virtual modules configured for More Apartments API");
759
+ }
760
+ if (options.injectClient !== false) {
761
+ injectScript(
762
+ "before-hydration",
763
+ `
764
+ window.__moreApartments = {
765
+ baseUrl: '${options.baseUrl}',
766
+ instance: '${options.instance || ""}',
767
+ // apiKey intentionally excluded for security
768
+ };
769
+ `
770
+ );
771
+ logger.info("Global More Apartments client injected (client-side safe config)");
772
+ }
773
+ if (options.addApiRoutes !== false) {
774
+ const routePrefix = options.apiRoutePrefix || "/api/apartments";
775
+ injectRoute({
776
+ pattern: `${routePrefix}/properties`,
777
+ entrypoint: "@shelfwood/more-apartments-astro-integration/routes/properties.js"
778
+ });
779
+ injectRoute({
780
+ pattern: `${routePrefix}/properties/[id]`,
781
+ entrypoint: "@shelfwood/more-apartments-astro-integration/routes/property.js"
782
+ });
783
+ injectRoute({
784
+ pattern: `${routePrefix}/properties/[id]/availability`,
785
+ entrypoint: "@shelfwood/more-apartments-astro-integration/routes/availability.js"
786
+ });
787
+ injectRoute({
788
+ pattern: `${routePrefix}/pages`,
789
+ entrypoint: "@shelfwood/more-apartments-astro-integration/routes/pages.js"
790
+ });
791
+ injectRoute({
792
+ pattern: `${routePrefix}/pages/[slug]`,
793
+ entrypoint: "@shelfwood/more-apartments-astro-integration/routes/page.js"
794
+ });
795
+ injectRoute({
796
+ pattern: `${routePrefix}/posts`,
797
+ entrypoint: "@shelfwood/more-apartments-astro-integration/routes/posts.js"
798
+ });
799
+ injectRoute({
800
+ pattern: `${routePrefix}/posts/[slug]`,
801
+ entrypoint: "@shelfwood/more-apartments-astro-integration/routes/post.js"
802
+ });
803
+ injectRoute({
804
+ pattern: `${routePrefix}/settings/[type]`,
805
+ entrypoint: "@shelfwood/more-apartments-astro-integration/routes/settings.js"
806
+ });
807
+ injectRoute({
808
+ pattern: `${routePrefix}/bookings`,
809
+ entrypoint: "@shelfwood/more-apartments-astro-integration/routes/bookings.js"
810
+ });
811
+ logger.info(`API proxy routes added at ${routePrefix}`);
812
+ }
813
+ },
814
+ "astro:config:done": ({ config: finalConfig, logger }) => {
815
+ logger.info("More Apartments integration configured successfully");
816
+ },
817
+ "astro:server:setup": async ({ server, logger }) => {
818
+ server.middlewares.use((req, res, next) => {
819
+ if (req.url?.startsWith("/api/apartments")) {
820
+ logger.debug(`API request: ${req.method} ${req.url}`);
821
+ }
822
+ next();
823
+ });
824
+ logger.info(`Instance path config: ${options.instancePath || "not set"}`);
825
+ if (options.instancePath) {
826
+ const path = await import('path');
827
+ const chokidar = await import('chokidar');
828
+ const resolvedPath = path.resolve(process.cwd(), options.instancePath);
829
+ logger.info(`Watching instance directory: ${resolvedPath}`);
830
+ const watcher = chokidar.watch(resolvedPath, {
831
+ ignored: /(^|[\/\\])\../,
832
+ // ignore dotfiles
833
+ persistent: true,
834
+ ignoreInitial: true
835
+ });
836
+ watcher.on("change", (filePath) => {
837
+ logger.info(`Instance file changed: ${path.relative(resolvedPath, filePath)}`);
838
+ server.ws.send({
839
+ type: "full-reload",
840
+ path: "*"
841
+ });
842
+ });
843
+ watcher.on("add", (filePath) => {
844
+ logger.info(`Instance file added: ${path.relative(resolvedPath, filePath)}`);
845
+ server.ws.send({
846
+ type: "full-reload",
847
+ path: "*"
848
+ });
849
+ });
850
+ watcher.on("unlink", (filePath) => {
851
+ logger.info(`Instance file removed: ${path.relative(resolvedPath, filePath)}`);
852
+ server.ws.send({
853
+ type: "full-reload",
854
+ path: "*"
855
+ });
856
+ });
857
+ server.httpServer?.on("close", () => {
858
+ watcher.close();
859
+ });
860
+ }
861
+ },
862
+ "astro:build:done": ({ logger }) => {
863
+ logger.info("More Apartments integration build complete");
864
+ }
865
+ }
866
+ };
867
+ }
868
+ async function fetchProperties(client, params) {
869
+ try {
870
+ return await client.getProperties(params);
871
+ } catch (error) {
872
+ console.error("Error fetching properties:", error);
873
+ return { data: [], links: {}, meta: {} };
874
+ }
875
+ }
876
+ async function fetchProperty(client, idOrSlug) {
877
+ try {
878
+ return await client.getProperty(idOrSlug);
879
+ } catch (error) {
880
+ console.error("Error fetching property:", error);
881
+ return null;
882
+ }
883
+ }
884
+ async function fetchAvailability(client, propertySlug, startDate, endDate) {
885
+ try {
886
+ return await client.getAvailability(propertySlug, startDate, endDate);
887
+ } catch (error) {
888
+ console.error("Error fetching availability:", error);
889
+ return null;
890
+ }
891
+ }
892
+ async function fetchPages(client) {
893
+ try {
894
+ return await client.getPages();
895
+ } catch (error) {
896
+ console.error("Error fetching pages:", error);
897
+ return [];
898
+ }
899
+ }
900
+ async function fetchPage(client, slug) {
901
+ try {
902
+ return await client.getPage(slug);
903
+ } catch (error) {
904
+ console.error("Error fetching page:", error);
905
+ return null;
906
+ }
907
+ }
908
+ async function fetchPosts(client, params) {
909
+ try {
910
+ return await client.getPosts(params);
911
+ } catch (error) {
912
+ console.error("Error fetching posts:", error);
913
+ return { data: [], links: {}, meta: {} };
914
+ }
915
+ }
916
+ async function fetchPost(client, slug) {
917
+ try {
918
+ return await client.getPost(slug);
919
+ } catch (error) {
920
+ console.error("Error fetching post:", error);
921
+ return null;
922
+ }
923
+ }
924
+ async function fetchSettings(client, type) {
925
+ try {
926
+ switch (type) {
927
+ case "main":
928
+ return await client.getMainSettings();
929
+ case "theme":
930
+ return await client.getThemeSettings();
931
+ case "properties":
932
+ return await client.getPropertySettings();
933
+ case "booking":
934
+ return await client.getBookingSettings();
935
+ default:
936
+ throw new Error(`Unknown settings type: ${type}`);
937
+ }
938
+ } catch (error) {
939
+ console.error(`Error fetching ${type} settings:`, error);
940
+ return null;
941
+ }
942
+ }
943
+ function generateBookingUrl(propertyExternalId, arrival, departure, guests, baseUrl) {
944
+ const bookingBaseUrl = baseUrl || import.meta.env.PUBLIC_LARAVEL_BOOKING_URL || "http://prj-more-apartments.test/booking/initiate";
945
+ const params = new URLSearchParams({
946
+ property_external_id: propertyExternalId.toString(),
947
+ arrival,
948
+ departure,
949
+ guests: guests.toString()
950
+ });
951
+ return `${bookingBaseUrl}?${params.toString()}`;
952
+ }
953
+ async function searchProperties(client, params) {
954
+ try {
955
+ return await client.searchProperties(params);
956
+ } catch (error) {
957
+ console.error("Error searching properties:", error);
958
+ return [];
959
+ }
960
+ }
961
+
962
+ export { ApiErrorSchema, AvailabilitySchema, AvailableDay, BookingRequestSchema, BookingResponseSchema, BookingSettingsSchema, CategorySchema, CategorySegmentSchema, MainSettingsSchema, MoreApartmentsClient, MoreApartmentsConfigSchema, PageSchema, PaginatedResponseSchema, PaginationLinksSchema, PaginationMetaSchema, PostSchema, PropertyImageSchema, PropertyPageSettingsSchema, PropertySchema, PropertySearchParamsSchema, PropertySearchResultSchema, PropertySettingsSchema, ThemeSettingsSchema, moreApartmentsIntegration as default, fetchAvailability, fetchPage, fetchPages, fetchPost, fetchPosts, fetchProperties, fetchProperty, fetchSettings, generateBookingUrl, getAllImageUrls, getAllThumbnailUrls, getImage, getImageCount, getImageWithAlt, getPrimaryImageUrl, getThumbnailUrl, hasImages, searchProperties };
963
+ //# sourceMappingURL=index.mjs.map
964
+ //# sourceMappingURL=index.mjs.map