@microboxlabs/miot-calendar-client 0.1.2 → 0.1.3

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.
Files changed (2) hide show
  1. package/README.md +567 -45
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # @microboxlabs/miot-calendar-client
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@microboxlabs/miot-calendar-client)](https://www.npmjs.com/package/@microboxlabs/miot-calendar-client)
4
+ [![License](https://img.shields.io/npm/l/@microboxlabs/miot-calendar-client)](./LICENSE)
5
+
3
6
  TypeScript client for the ModularIoT Calendar API. Zero dependencies — uses the native `fetch` API.
4
7
 
5
8
  ## Installation
@@ -10,6 +13,8 @@ npm install @microboxlabs/miot-calendar-client
10
13
 
11
14
  ## Quick Start
12
15
 
16
+ A complete workflow: create a calendar, define a time window, generate slots, and book one.
17
+
13
18
  ```ts
14
19
  import { createMiotCalendarClient } from "@microboxlabs/miot-calendar-client";
15
20
 
@@ -17,76 +22,593 @@ const client = createMiotCalendarClient({
17
22
  baseUrl: "https://your-api-host.com",
18
23
  });
19
24
 
20
- // List calendars
21
- const calendars = await client.calendars.list();
25
+ // 1. Create a calendar
26
+ const calendar = await client.calendars.create({
27
+ code: "maintenance",
28
+ name: "Vehicle Maintenance",
29
+ timezone: "America/New_York", // defaults to "UTC" if omitted
30
+ });
31
+
32
+ // 2. Add a time window (Mon–Fri, 8 AM – 5 PM, 30-min slots)
33
+ const timeWindow = await client.calendars.createTimeWindow(calendar.id, {
34
+ name: "Business Hours",
35
+ startHour: 8,
36
+ endHour: 17,
37
+ validFrom: "2026-03-01",
38
+ daysOfWeek: "1,2,3,4,5", // Mon–Fri
39
+ slotDurationMinutes: 30, // default: 30
40
+ capacityPerSlot: 2, // default: 1
41
+ });
42
+
43
+ // 3. Generate slots for the first two weeks
44
+ const result = await client.slots.generate({
45
+ calendarId: calendar.id,
46
+ startDate: "2026-03-01",
47
+ endDate: "2026-03-14", // max range: 90 days
48
+ });
49
+ console.log(`Created ${result.slotsCreated} slots`);
22
50
 
23
- // Create a booking
24
- const booking = await client.bookings.create({
25
- calendarId: "cal-123",
26
- resource: { id: "truck-42", type: "vehicle", label: "Truck 42" },
27
- slot: { date: "2026-03-01", hour: 10, minutes: 0 },
51
+ // 4. Find available slots
52
+ const { data: slots } = await client.slots.list({
53
+ calendarId: calendar.id, // required
54
+ available: true,
55
+ startDate: "2026-03-03",
56
+ endDate: "2026-03-07",
28
57
  });
58
+
59
+ // 5. Book the first available slot
60
+ const booking = await client.bookings.create(
61
+ {
62
+ calendarId: calendar.id,
63
+ resource: { id: "truck-42", type: "vehicle", label: "Truck 42" },
64
+ slot: { date: slots[0].slotDate, hour: slots[0].slotHour, minutes: slots[0].slotMinutes },
65
+ },
66
+ { userId: "user-abc" }, // sets X-User-Id header → stored as createdBy
67
+ );
29
68
  ```
30
69
 
31
70
  ## Configuration
32
71
 
33
72
  ```ts
34
- createMiotCalendarClient({
35
- baseUrl: "https://your-api-host.com", // Required
36
- headers: { Authorization: "Bearer ..." }, // Optional default headers
37
- fetch: customFetch, // Optional fetch implementation
73
+ const client = createMiotCalendarClient({
74
+ baseUrl: "https://your-api-host.com", // Required — API base URL
75
+ headers: { Authorization: "Bearer ..." }, // Optional merged into every request
76
+ fetch: customFetch, // Optional — custom fetch implementation
38
77
  });
39
78
  ```
40
79
 
80
+ | Option | Type | Required | Description |
81
+ |--------|------|----------|-------------|
82
+ | `baseUrl` | `string` | Yes | Base URL of the Calendar API |
83
+ | `headers` | `Record<string, string>` | No | Default headers sent with every request |
84
+ | `fetch` | `typeof fetch` | No | Custom `fetch` implementation (defaults to `globalThis.fetch`) |
85
+
41
86
  ## API Reference
42
87
 
43
- ### `client.calendars`
44
-
45
- | Method | Description |
46
- |---|---|
47
- | `list(params?)` | List calendars. Filter by `active`. |
48
- | `get(id)` | Get a calendar by ID. |
49
- | `create(body)` | Create a calendar. |
50
- | `update(id, body)` | Update a calendar. |
51
- | `deactivate(id)` | Deactivate a calendar. |
52
- | `listTimeWindows(calendarId)` | List time windows for a calendar. |
53
- | `createTimeWindow(calendarId, body)` | Create a time window. |
54
- | `updateTimeWindow(calendarId, timeWindowId, body)` | Update a time window. |
55
-
56
- ### `client.bookings`
57
-
58
- | Method | Description |
59
- |---|---|
60
- | `list(params?)` | List bookings. Filter by `calendarId`, `startDate`, `endDate`. |
61
- | `get(id)` | Get a booking by ID. |
62
- | `create(body, options?)` | Create a booking. Pass `{ userId }` to set `X-User-Id` header. |
63
- | `cancel(id)` | Cancel a booking. |
64
- | `listByResource(resourceId)` | List bookings for a specific resource. |
65
-
66
- ### `client.slots`
67
-
68
- | Method | Description |
69
- |---|---|
70
- | `list(params)` | List slots. Filter by `calendarId`, `available`, `startDate`, `endDate`. |
71
- | `get(id)` | Get a slot by ID. |
72
- | `generate(body)` | Generate slots for a date range. |
73
- | `updateStatus(id, body)` | Update slot status (`OPEN`, `FULL`, `CLOSED`). |
88
+ ### Calendars
89
+
90
+ #### `calendars.list(params?)`
91
+
92
+ List all calendars, optionally filtered by active status.
93
+
94
+ | Param | Type | Required | Description |
95
+ |-------|------|----------|-------------|
96
+ | `active` | `boolean` | No | Filter by active status |
97
+
98
+ **Returns:** `CalendarResponse[]`
99
+
100
+ #### `calendars.get(id)`
101
+
102
+ Get a single calendar by ID.
103
+
104
+ | Param | Type | Required | Description |
105
+ |-------|------|----------|-------------|
106
+ | `id` | `string` | Yes | Calendar ID |
107
+
108
+ **Returns:** `CalendarResponse`
109
+
110
+ **Throws:** `MiotCalendarApiError` with status `404` if not found.
111
+
112
+ #### `calendars.create(body)`
113
+
114
+ Create a new calendar.
115
+
116
+ | Field | Type | Required | Default | Description |
117
+ |-------|------|----------|---------|-------------|
118
+ | `code` | `string` | Yes | | Unique code identifier |
119
+ | `name` | `string` | Yes | — | Display name |
120
+ | `description` | `string` | No | — | Optional description |
121
+ | `timezone` | `string` | No | `"UTC"` | IANA timezone |
122
+ | `active` | `boolean` | No | `true` | Whether the calendar is active |
123
+
124
+ **Returns:** `CalendarResponse`
125
+
126
+ #### `calendars.update(id, body)`
127
+
128
+ Replace a calendar's fields. Takes the same body as `create`.
129
+
130
+ | Param | Type | Required | Description |
131
+ |-------|------|----------|-------------|
132
+ | `id` | `string` | Yes | Calendar ID |
133
+ | `body` | `CalendarRequest` | Yes | Updated calendar data |
134
+
135
+ **Returns:** `CalendarResponse`
136
+
137
+ #### `calendars.deactivate(id)`
138
+
139
+ Deactivate a calendar (soft delete).
140
+
141
+ | Param | Type | Required | Description |
142
+ |-------|------|----------|-------------|
143
+ | `id` | `string` | Yes | Calendar ID |
144
+
145
+ **Returns:** `void` (HTTP 204 — no content)
146
+
147
+ ---
148
+
149
+ ### Time Windows
150
+
151
+ Time windows are managed through the `calendars` namespace.
152
+
153
+ #### `calendars.listTimeWindows(calendarId)`
154
+
155
+ List all time windows for a calendar.
156
+
157
+ | Param | Type | Required | Description |
158
+ |-------|------|----------|-------------|
159
+ | `calendarId` | `string` | Yes | Calendar ID |
160
+
161
+ **Returns:** `TimeWindowResponse[]`
162
+
163
+ #### `calendars.createTimeWindow(calendarId, body)`
164
+
165
+ Create a time window within a calendar.
166
+
167
+ | Field | Type | Required | Default | Description |
168
+ |-------|------|----------|---------|-------------|
169
+ | `name` | `string` | Yes | — | Time window name |
170
+ | `startHour` | `number` | Yes | — | Start hour (0–23) |
171
+ | `endHour` | `number` | Yes | — | End hour (0–23, must be > startHour) |
172
+ | `validFrom` | `string` | Yes | — | Start date (`YYYY-MM-DD`) |
173
+ | `validTo` | `string` | No | — | End date (`YYYY-MM-DD`) |
174
+ | `slotDurationMinutes` | `number` | No | `30` | Slot duration in minutes |
175
+ | `capacityPerSlot` | `number` | No | `1` | Max bookings per slot |
176
+ | `daysOfWeek` | `string` | No | — | Comma-separated days (1=Mon … 7=Sun) |
177
+ | `active` | `boolean` | No | `true` | Whether the time window is active |
178
+
179
+ **Returns:** `TimeWindowResponse`
180
+
181
+ #### `calendars.updateTimeWindow(calendarId, timeWindowId, body)`
182
+
183
+ Update a time window. Takes the same body as `createTimeWindow`.
184
+
185
+ | Param | Type | Required | Description |
186
+ |-------|------|----------|-------------|
187
+ | `calendarId` | `string` | Yes | Calendar ID |
188
+ | `timeWindowId` | `string` | Yes | Time window ID |
189
+ | `body` | `TimeWindowRequest` | Yes | Updated time window data |
190
+
191
+ **Returns:** `TimeWindowResponse`
192
+
193
+ ---
194
+
195
+ ### Slots
196
+
197
+ #### `slots.list(params)`
198
+
199
+ List slots for a calendar. The `calendarId` parameter is **required**.
200
+
201
+ | Param | Type | Required | Default | Description |
202
+ |-------|------|----------|---------|-------------|
203
+ | `calendarId` | `string` | Yes | — | Calendar ID |
204
+ | `available` | `boolean` | No | — | Filter by availability |
205
+ | `startDate` | `string` | No | today | Start of date range (`YYYY-MM-DD`) |
206
+ | `endDate` | `string` | No | today + 7 days | End of date range (`YYYY-MM-DD`) |
207
+
208
+ **Returns:** `SlotListResponse` — `{ data: SlotResponse[], total: number }`
209
+
210
+ #### `slots.get(id)`
211
+
212
+ Get a single slot by ID.
213
+
214
+ | Param | Type | Required | Description |
215
+ |-------|------|----------|-------------|
216
+ | `id` | `string` | Yes | Slot ID |
217
+
218
+ **Returns:** `SlotResponse`
219
+
220
+ **Throws:** `MiotCalendarApiError` with status `404` if not found.
221
+
222
+ #### `slots.generate(body)`
223
+
224
+ Generate slots for a calendar based on its time windows.
225
+
226
+ | Field | Type | Required | Description |
227
+ |-------|------|----------|-------------|
228
+ | `calendarId` | `string` | Yes | Calendar ID |
229
+ | `startDate` | `string` | Yes | Start date (`YYYY-MM-DD`) |
230
+ | `endDate` | `string` | Yes | End date (`YYYY-MM-DD`) |
231
+
232
+ > **Note:** The date range must not exceed **90 days**. The API returns `400 Bad Request` if the range is larger.
233
+
234
+ **Returns:** `GenerateSlotsResponse` — `{ slotsCreated: number, slotsSkipped: number, message: string }`
235
+
236
+ #### `slots.updateStatus(id, body)`
237
+
238
+ Manually change a slot's status.
239
+
240
+ | Field | Type | Required | Description |
241
+ |-------|------|----------|-------------|
242
+ | `id` | `string` | Yes | Slot ID |
243
+ | `status` | `"OPEN" \| "CLOSED"` | Yes | New status |
244
+
245
+ > **Note:** Only `OPEN` and `CLOSED` are accepted. `FULL` is managed automatically by the system based on occupancy and cannot be set manually. Passing `FULL` returns `400 Bad Request`.
246
+
247
+ **Returns:** `SlotResponse`
248
+
249
+ ---
250
+
251
+ ### Bookings
252
+
253
+ #### `bookings.list(params?)`
254
+
255
+ List bookings, optionally filtered by calendar and date range.
256
+
257
+ | Param | Type | Required | Default | Description |
258
+ |-------|------|----------|---------|-------------|
259
+ | `calendarId` | `string` | No | — | Filter by calendar |
260
+ | `startDate` | `string` | No | today | Start of date range (`YYYY-MM-DD`) |
261
+ | `endDate` | `string` | No | today + 30 days | End of date range (`YYYY-MM-DD`) |
262
+
263
+ **Returns:** `BookingListResponse` — `{ data: BookingResponse[], total: number }`
264
+
265
+ #### `bookings.get(id)`
266
+
267
+ Get a single booking by ID.
268
+
269
+ | Param | Type | Required | Description |
270
+ |-------|------|----------|-------------|
271
+ | `id` | `string` | Yes | Booking ID |
272
+
273
+ **Returns:** `BookingResponse`
274
+
275
+ **Throws:** `MiotCalendarApiError` with status `404` if not found.
276
+
277
+ #### `bookings.create(body, options?)`
278
+
279
+ Create a booking for a specific slot.
280
+
281
+ **Body (`BookingRequest`):**
282
+
283
+ | Field | Type | Required | Description |
284
+ |-------|------|----------|-------------|
285
+ | `calendarId` | `string` | Yes | Calendar ID |
286
+ | `resource` | `ResourceData` | Yes | The resource being booked |
287
+ | `slot` | `SlotData` | Yes | Target slot (date + time) |
288
+
289
+ **Options:**
290
+
291
+ | Field | Type | Required | Description |
292
+ |-------|------|----------|-------------|
293
+ | `userId` | `string` | No | Sets `X-User-Id` header — stored as `createdBy` in the response |
294
+
295
+ **Returns:** `BookingResponse`
296
+
297
+ **Throws:**
298
+
299
+ - `404` — Calendar or slot not found
300
+ - `409` — Slot is full (no available capacity)
301
+
302
+ #### `bookings.cancel(id)`
303
+
304
+ Cancel a booking.
305
+
306
+ | Param | Type | Required | Description |
307
+ |-------|------|----------|-------------|
308
+ | `id` | `string` | Yes | Booking ID |
309
+
310
+ **Returns:** `void` (HTTP 204 — no content)
311
+
312
+ #### `bookings.listByResource(resourceId)`
313
+
314
+ List all bookings for a specific resource.
315
+
316
+ | Param | Type | Required | Description |
317
+ |-------|------|----------|-------------|
318
+ | `resourceId` | `string` | Yes | Resource ID |
319
+
320
+ **Returns:** `BookingListResponse`
321
+
322
+ ## Types
323
+
324
+ ### `CalendarRequest`
325
+
326
+ ```ts
327
+ interface CalendarRequest {
328
+ code: string; // Unique code identifier
329
+ name: string; // Display name
330
+ description?: string; // Optional description
331
+ timezone?: string; // IANA timezone (default: "UTC")
332
+ active?: boolean; // Active status (default: true)
333
+ }
334
+ ```
335
+
336
+ ### `CalendarResponse`
337
+
338
+ ```ts
339
+ interface CalendarResponse {
340
+ id: string;
341
+ code: string;
342
+ name: string;
343
+ description?: string;
344
+ timezone: string; // Always present (default: "UTC")
345
+ active: boolean; // Always present (default: true)
346
+ createdAt: string; // ISO 8601
347
+ updatedAt: string; // ISO 8601
348
+ }
349
+ ```
350
+
351
+ ### `TimeWindowRequest`
352
+
353
+ ```ts
354
+ interface TimeWindowRequest {
355
+ name: string; // Time window name
356
+ startHour: number; // 0–23
357
+ endHour: number; // 0–23 (must be > startHour)
358
+ validFrom: string; // YYYY-MM-DD
359
+ validTo?: string; // YYYY-MM-DD
360
+ slotDurationMinutes?: number; // Default: 30
361
+ capacityPerSlot?: number; // Default: 1
362
+ daysOfWeek?: string; // Comma-separated: "1,2,3,4,5" (1=Mon, 7=Sun)
363
+ active?: boolean; // Default: true
364
+ }
365
+ ```
366
+
367
+ ### `TimeWindowResponse`
368
+
369
+ ```ts
370
+ interface TimeWindowResponse {
371
+ id: string;
372
+ calendarId: string;
373
+ name: string;
374
+ startHour: number;
375
+ endHour: number;
376
+ slotDurationMinutes: number; // Always present (default: 30)
377
+ capacityPerSlot: number; // Always present (default: 1)
378
+ daysOfWeek: string;
379
+ validFrom: string;
380
+ validTo?: string;
381
+ active: boolean; // Always present (default: true)
382
+ createdAt: string; // ISO 8601
383
+ updatedAt: string; // ISO 8601
384
+ }
385
+ ```
386
+
387
+ ### `SlotResponse`
388
+
389
+ ```ts
390
+ interface SlotResponse {
391
+ id: string;
392
+ calendarId: string;
393
+ timeWindowId?: string; // May be absent for manually created slots
394
+ slotDate: string; // YYYY-MM-DD
395
+ slotHour: number; // 0–23
396
+ slotMinutes: number; // 0–59
397
+ capacity: number; // Total capacity
398
+ currentOccupancy: number; // Current bookings count
399
+ availableCapacity: number; // capacity - currentOccupancy
400
+ status: SlotStatus; // "OPEN" | "FULL" | "CLOSED"
401
+ createdAt: string; // ISO 8601
402
+ updatedAt: string; // ISO 8601
403
+ }
404
+ ```
405
+
406
+ ### `SlotListResponse`
407
+
408
+ ```ts
409
+ interface SlotListResponse {
410
+ data: SlotResponse[];
411
+ total: number;
412
+ }
413
+ ```
414
+
415
+ ### `GenerateSlotsRequest`
416
+
417
+ ```ts
418
+ interface GenerateSlotsRequest {
419
+ calendarId: string;
420
+ startDate: string; // YYYY-MM-DD
421
+ endDate: string; // YYYY-MM-DD (max 90 days from startDate)
422
+ }
423
+ ```
424
+
425
+ ### `GenerateSlotsResponse`
426
+
427
+ ```ts
428
+ interface GenerateSlotsResponse {
429
+ slotsCreated: number;
430
+ slotsSkipped: number;
431
+ message: string;
432
+ }
433
+ ```
434
+
435
+ ### `UpdateSlotStatusRequest`
436
+
437
+ ```ts
438
+ interface UpdateSlotStatusRequest {
439
+ status: SlotStatus; // Only "OPEN" or "CLOSED" accepted
440
+ }
441
+ ```
442
+
443
+ ### `BookingRequest`
444
+
445
+ ```ts
446
+ interface BookingRequest {
447
+ calendarId: string;
448
+ resource: ResourceData;
449
+ slot: SlotData;
450
+ }
451
+ ```
452
+
453
+ ### `BookingResponse`
454
+
455
+ ```ts
456
+ interface BookingResponse {
457
+ id: string;
458
+ calendarId: string;
459
+ resource: ResourceData;
460
+ slot: SlotData;
461
+ createdAt: string; // ISO 8601
462
+ createdBy?: string; // Set via X-User-Id header on create
463
+ }
464
+ ```
465
+
466
+ ### `BookingListResponse`
467
+
468
+ ```ts
469
+ interface BookingListResponse {
470
+ data: BookingResponse[];
471
+ total: number;
472
+ }
473
+ ```
474
+
475
+ ### `ResourceData`
476
+
477
+ ```ts
478
+ interface ResourceData {
479
+ id: string; // Resource identifier
480
+ type?: string; // Resource type (e.g. "vehicle", "room")
481
+ label?: string; // Human-readable label
482
+ data?: Record<string, unknown>; // Arbitrary metadata
483
+ }
484
+ ```
485
+
486
+ ### `SlotData`
487
+
488
+ ```ts
489
+ interface SlotData {
490
+ date: string; // YYYY-MM-DD
491
+ hour: number; // 0–23
492
+ minutes: number; // 0–59
493
+ }
494
+ ```
495
+
496
+ ### `SlotStatus`
497
+
498
+ ```ts
499
+ type SlotStatus = "OPEN" | "FULL" | "CLOSED";
500
+ ```
501
+
502
+ ### `ErrorResponse`
503
+
504
+ ```ts
505
+ interface ErrorResponse {
506
+ error: string; // Error type (e.g. "Bad Request")
507
+ message: string; // Detailed error message
508
+ status: number; // HTTP status code
509
+ timestamp: string; // ISO 8601
510
+ }
511
+ ```
512
+
513
+ ### `ClientConfig`
514
+
515
+ ```ts
516
+ interface ClientConfig {
517
+ baseUrl: string;
518
+ headers?: Record<string, string>;
519
+ fetch?: typeof fetch;
520
+ }
521
+ ```
74
522
 
75
523
  ## Error Handling
76
524
 
525
+ All API errors throw `MiotCalendarApiError`.
526
+
77
527
  ```ts
78
528
  import { MiotCalendarApiError } from "@microboxlabs/miot-calendar-client";
79
529
 
80
530
  try {
81
- await client.bookings.get("non-existent");
531
+ await client.bookings.create({
532
+ calendarId: "cal-123",
533
+ resource: { id: "truck-42", type: "vehicle", label: "Truck 42" },
534
+ slot: { date: "2026-03-01", hour: 10, minutes: 0 },
535
+ });
82
536
  } catch (error) {
83
537
  if (error instanceof MiotCalendarApiError) {
84
- console.log(error.status); // HTTP status code
85
- console.log(error.body); // ErrorResponse object or raw string
538
+ console.log(error.status); // HTTP status code (e.g. 409)
539
+ console.log(error.message); // Error message string
540
+ console.log(error.body); // ErrorResponse object or raw string
541
+ }
542
+ }
543
+ ```
544
+
545
+ ### Error Codes
546
+
547
+ | Status | Meaning | Common Causes |
548
+ |--------|---------|---------------|
549
+ | `400` | Bad Request | Validation errors, slot generation range > 90 days, setting status to `FULL` manually |
550
+ | `404` | Not Found | Calendar, slot, or booking does not exist |
551
+ | `409` | Conflict | Slot is full (no available capacity for booking) |
552
+
553
+ ### Error Body
554
+
555
+ The `body` property on `MiotCalendarApiError` can be either:
556
+
557
+ - An **`ErrorResponse` object** with `error`, `message`, `status`, and `timestamp` fields — returned when the API sends a JSON error response.
558
+ - A **plain `string`** — returned as a fallback when the API response is not valid JSON (e.g. gateway errors, load balancer timeouts).
559
+
560
+ ```ts
561
+ if (error instanceof MiotCalendarApiError) {
562
+ if (typeof error.body === "string") {
563
+ // Non-JSON error (gateway, timeout, etc.)
564
+ console.log("Raw error:", error.body);
565
+ } else {
566
+ // Structured API error
567
+ console.log(error.body.error); // "Conflict"
568
+ console.log(error.body.message); // "Slot is full"
569
+ console.log(error.body.timestamp); // "2026-03-01T10:00:00Z"
86
570
  }
87
571
  }
88
572
  ```
89
573
 
574
+ ## Custom Fetch
575
+
576
+ Pass a custom `fetch` implementation for server-side rendering, auth interceptors, or testing.
577
+
578
+ ### Auth interceptor
579
+
580
+ ```ts
581
+ const client = createMiotCalendarClient({
582
+ baseUrl: "https://your-api-host.com",
583
+ fetch: async (input, init) => {
584
+ const token = await getAccessToken(); // your auth logic
585
+ const headers = new Headers(init?.headers);
586
+ headers.set("Authorization", `Bearer ${token}`);
587
+ return globalThis.fetch(input, { ...init, headers });
588
+ },
589
+ });
590
+ ```
591
+
592
+ ### Testing with a mock fetch
593
+
594
+ ```ts
595
+ import { createMiotCalendarClient } from "@microboxlabs/miot-calendar-client";
596
+
597
+ const mockFetch = async (input: RequestInfo | URL, init?: RequestInit) => {
598
+ return new Response(JSON.stringify({ id: "cal-1", code: "test", name: "Test" }), {
599
+ status: 200,
600
+ headers: { "Content-Type": "application/json" },
601
+ });
602
+ };
603
+
604
+ const client = createMiotCalendarClient({
605
+ baseUrl: "https://mock-api",
606
+ fetch: mockFetch,
607
+ });
608
+
609
+ const calendar = await client.calendars.get("cal-1");
610
+ ```
611
+
90
612
  ## License
91
613
 
92
614
  [Apache-2.0](./LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microboxlabs/miot-calendar-client",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",