@resira/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # @resira/sdk
2
+
3
+ TypeScript SDK for the Resira public reservation API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @resira/sdk
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ ```typescript
14
+ import { Resira } from "@resira/sdk";
15
+
16
+ const resira = new Resira({
17
+ apiKey: "resira_live_your_api_key_here",
18
+ });
19
+ ```
20
+
21
+ ## API reference
22
+
23
+ ### `new Resira(config)`
24
+
25
+ | Option | Type | Default | Description |
26
+ | ---------------- | ---------- | --------------------------- | ------------------------------------------------- |
27
+ | `apiKey` | `string` | **(required)** | API key (`resira_live_…`) |
28
+ | `baseUrl` | `string` | `https://api.resira.io` | Base URL of the API |
29
+ | `maxRetries` | `number` | `3` | Max retry attempts for 429 / 5xx |
30
+ | `retryBaseDelay` | `number` | `500` | Base delay (ms) for exponential backoff |
31
+ | `fetch` | `function` | `globalThis.fetch` | Custom fetch implementation |
32
+
33
+ ---
34
+
35
+ ### `resira.getAvailability(resourceId, params?)`
36
+
37
+ Query availability for a resource.
38
+
39
+ **Property (date-based):**
40
+ ```typescript
41
+ const avail = await resira.getAvailability("prop-1", {
42
+ startDate: "2026-07-01",
43
+ endDate: "2026-07-07",
44
+ });
45
+
46
+ console.log(avail.dates?.available); // true
47
+ console.log(avail.dates?.totalPrice); // 85000 (cents)
48
+ console.log(avail.dates?.blockedDates); // ["2026-07-15", …]
49
+ ```
50
+
51
+ **Restaurant (time-slot):**
52
+ ```typescript
53
+ const avail = await resira.getAvailability("table-5", {
54
+ date: "2026-07-01",
55
+ partySize: 4,
56
+ });
57
+
58
+ for (const slot of avail.timeSlots ?? []) {
59
+ console.log(`${slot.start} → ${slot.end}: ${slot.remaining} seats`);
60
+ }
61
+ ```
62
+
63
+ ---
64
+
65
+ ### `resira.createReservation(payload, options?)`
66
+
67
+ Create a reservation. The `resourceId` is included in the request body.
68
+ An `Idempotency-Key` header is automatically generated to prevent
69
+ duplicate bookings on retries.
70
+
71
+ ```typescript
72
+ const { reservation } = await resira.createReservation({
73
+ resourceId: "prop-1",
74
+ guestName: "Jane Doe",
75
+ guestEmail: "jane@example.com",
76
+ startDate: "2026-07-01",
77
+ endDate: "2026-07-07",
78
+ partySize: 3,
79
+ });
80
+
81
+ console.log(reservation.id); // "uuid-…"
82
+ console.log(reservation.status); // "pending"
83
+ console.log(reservation.totalPrice);// 85000
84
+ ```
85
+
86
+ **Custom idempotency key:**
87
+ ```typescript
88
+ const { reservation } = await resira.createReservation(
89
+ payload,
90
+ { idempotencyKey: "form-submit-abc123" },
91
+ );
92
+ ```
93
+
94
+ ---
95
+
96
+ ### `resira.listReservations(resourceId, params?)`
97
+
98
+ List reservations (paginated).
99
+
100
+ ```typescript
101
+ const page = await resira.listReservations("prop-1", {
102
+ status: "confirmed",
103
+ page: 1,
104
+ limit: 50,
105
+ });
106
+
107
+ console.log(page.data); // Reservation[]
108
+ console.log(page.total); // 142
109
+ console.log(page.totalPages); // 3
110
+ ```
111
+
112
+ ---
113
+
114
+ ### `resira.getReservation(resourceId, reservationId)`
115
+
116
+ Get a single reservation by ID.
117
+
118
+ ```typescript
119
+ const { reservation } = await resira.getReservation("prop-1", "res-uuid");
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Error handling
125
+
126
+ All errors extend `ResiraError`. Use `instanceof` to discriminate:
127
+
128
+ ```typescript
129
+ import {
130
+ Resira,
131
+ ResiraApiError,
132
+ ResiraRateLimitError,
133
+ ResiraNetworkError,
134
+ } from "@resira/sdk";
135
+
136
+ try {
137
+ await resira.createReservation(payload);
138
+ } catch (error) {
139
+ if (error instanceof ResiraRateLimitError) {
140
+ // 429 — SDK already retried `maxRetries` times
141
+ console.log(`Rate limited. Retry after ${error.retryAfter}s`);
142
+ } else if (error instanceof ResiraApiError) {
143
+ // 4xx / 5xx
144
+ console.log(`${error.status}: ${error.message}`);
145
+ console.log(error.retryable); // true for 5xx
146
+ } else if (error instanceof ResiraNetworkError) {
147
+ // DNS / TLS / offline
148
+ console.log("Network error:", error.message);
149
+ }
150
+ }
151
+ ```
152
+
153
+ | Error class | When | Retried automatically? |
154
+ | ---------------------- | ----------------------------- | ---------------------- |
155
+ | `ResiraRateLimitError` | 429 Too Many Requests | ✓ (respects Retry-After) |
156
+ | `ResiraApiError` | Any non-2xx | ✓ for 5xx only |
157
+ | `ResiraNetworkError` | fetch failed (DNS, offline…) | ✓ |
158
+
159
+ ---
160
+
161
+ ## Retry behaviour
162
+
163
+ The SDK retries failed requests with **exponential backoff + jitter**:
164
+
165
+ - **Attempt 1**: 0 – 500 ms
166
+ - **Attempt 2**: 0 – 1 000 ms
167
+ - **Attempt 3**: 0 – 2 000 ms
168
+
169
+ For 429 responses, the `Retry-After` header value is used as a minimum delay.
170
+
171
+ Idempotency keys ensure that retried POST requests don't create
172
+ duplicate reservations.
173
+
174
+ ---
175
+
176
+ ## Requirements
177
+
178
+ - Node.js ≥ 18 (uses native `fetch`)
179
+ - No runtime dependencies