recal-sdk 0.3.2 → 1.0.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.
Files changed (198) hide show
  1. package/README.md +24 -792
  2. package/dist/client/client/client.gen.d.ts +3 -0
  3. package/dist/client/client/client.gen.d.ts.map +1 -0
  4. package/dist/client/client/client.gen.js +205 -0
  5. package/dist/client/client/client.gen.js.map +1 -0
  6. package/dist/client/client/index.d.ts +9 -0
  7. package/dist/client/client/index.d.ts.map +1 -0
  8. package/dist/client/client/index.js +7 -0
  9. package/dist/client/client/index.js.map +1 -0
  10. package/dist/client/client/types.gen.d.ts +125 -0
  11. package/dist/client/client/types.gen.d.ts.map +1 -0
  12. package/dist/client/client/types.gen.js +3 -0
  13. package/dist/client/client/types.gen.js.map +1 -0
  14. package/dist/client/client/utils.gen.d.ts +34 -0
  15. package/dist/client/client/utils.gen.d.ts.map +1 -0
  16. package/dist/client/client/utils.gen.js +232 -0
  17. package/dist/client/client/utils.gen.js.map +1 -0
  18. package/dist/client/client.gen.d.ts +13 -0
  19. package/dist/client/client.gen.d.ts.map +1 -0
  20. package/dist/client/client.gen.js +6 -0
  21. package/dist/client/client.gen.js.map +1 -0
  22. package/dist/client/core/auth.gen.d.ts +19 -0
  23. package/dist/client/core/auth.gen.d.ts.map +1 -0
  24. package/dist/client/core/auth.gen.js +15 -0
  25. package/dist/client/core/auth.gen.js.map +1 -0
  26. package/dist/client/core/bodySerializer.gen.d.ts +26 -0
  27. package/dist/client/core/bodySerializer.gen.d.ts.map +1 -0
  28. package/dist/client/core/bodySerializer.gen.js +58 -0
  29. package/dist/client/core/bodySerializer.gen.js.map +1 -0
  30. package/dist/client/core/params.gen.d.ts +34 -0
  31. package/dist/client/core/params.gen.d.ts.map +1 -0
  32. package/dist/client/core/params.gen.js +89 -0
  33. package/dist/client/core/params.gen.js.map +1 -0
  34. package/dist/client/core/pathSerializer.gen.d.ts +34 -0
  35. package/dist/client/core/pathSerializer.gen.d.ts.map +1 -0
  36. package/dist/client/core/pathSerializer.gen.js +115 -0
  37. package/dist/client/core/pathSerializer.gen.js.map +1 -0
  38. package/dist/client/core/queryKeySerializer.gen.d.ts +19 -0
  39. package/dist/client/core/queryKeySerializer.gen.d.ts.map +1 -0
  40. package/dist/client/core/queryKeySerializer.gen.js +100 -0
  41. package/dist/client/core/queryKeySerializer.gen.js.map +1 -0
  42. package/dist/client/core/serverSentEvents.gen.d.ts +72 -0
  43. package/dist/client/core/serverSentEvents.gen.d.ts.map +1 -0
  44. package/dist/client/core/serverSentEvents.gen.js +136 -0
  45. package/dist/client/core/serverSentEvents.gen.js.map +1 -0
  46. package/dist/client/core/types.gen.d.ts +79 -0
  47. package/dist/client/core/types.gen.d.ts.map +1 -0
  48. package/dist/client/core/types.gen.js +3 -0
  49. package/dist/client/core/types.gen.js.map +1 -0
  50. package/dist/client/core/utils.gen.d.ts +20 -0
  51. package/dist/client/core/utils.gen.d.ts.map +1 -0
  52. package/dist/client/core/utils.gen.js +88 -0
  53. package/dist/client/core/utils.gen.js.map +1 -0
  54. package/dist/client/index.d.ts +3 -0
  55. package/dist/client/index.d.ts.map +1 -0
  56. package/dist/client/index.js +3 -0
  57. package/dist/client/index.js.map +1 -0
  58. package/dist/client/sdk.gen.d.ts +170 -0
  59. package/dist/client/sdk.gen.d.ts.map +1 -0
  60. package/dist/client/sdk.gen.js +884 -0
  61. package/dist/client/sdk.gen.js.map +1 -0
  62. package/dist/client/transformers.gen.d.ts +31 -0
  63. package/dist/client/transformers.gen.d.ts.map +1 -0
  64. package/dist/client/transformers.gen.js +263 -0
  65. package/dist/client/transformers.gen.js.map +1 -0
  66. package/dist/client/types.gen.d.ts +1765 -0
  67. package/dist/client/types.gen.d.ts.map +1 -0
  68. package/dist/client/types.gen.js +3 -0
  69. package/dist/client/types.gen.js.map +1 -0
  70. package/dist/client/zod.gen.d.ts +1457 -0
  71. package/dist/client/zod.gen.d.ts.map +1 -0
  72. package/dist/client/zod.gen.js +1214 -0
  73. package/dist/client/zod.gen.js.map +1 -0
  74. package/dist/index.d.ts +5 -33
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +8 -55
  77. package/dist/index.js.map +1 -1
  78. package/dist/recal.d.ts +64 -0
  79. package/dist/recal.d.ts.map +1 -0
  80. package/dist/recal.js +81 -0
  81. package/dist/recal.js.map +1 -0
  82. package/dist/services/calendar.service.d.ts +55 -167
  83. package/dist/services/calendar.service.d.ts.map +1 -1
  84. package/dist/services/calendar.service.js +68 -301
  85. package/dist/services/calendar.service.js.map +1 -1
  86. package/dist/services/events.service.d.ts +167 -0
  87. package/dist/services/events.service.d.ts.map +1 -0
  88. package/dist/services/events.service.js +215 -0
  89. package/dist/services/events.service.js.map +1 -0
  90. package/dist/services/oauth.service.d.ts +123 -60
  91. package/dist/services/oauth.service.d.ts.map +1 -1
  92. package/dist/services/oauth.service.js +166 -142
  93. package/dist/services/oauth.service.js.map +1 -1
  94. package/dist/services/organizations.service.d.ts +137 -36
  95. package/dist/services/organizations.service.d.ts.map +1 -1
  96. package/dist/services/organizations.service.js +164 -90
  97. package/dist/services/organizations.service.js.map +1 -1
  98. package/dist/services/scheduling.service.d.ts +121 -58
  99. package/dist/services/scheduling.service.d.ts.map +1 -1
  100. package/dist/services/scheduling.service.js +98 -140
  101. package/dist/services/scheduling.service.js.map +1 -1
  102. package/dist/services/users.service.d.ts +87 -27
  103. package/dist/services/users.service.d.ts.map +1 -1
  104. package/dist/services/users.service.js +94 -69
  105. package/dist/services/users.service.js.map +1 -1
  106. package/dist/types.d.ts +68 -0
  107. package/dist/types.d.ts.map +1 -0
  108. package/dist/types.js +8 -0
  109. package/dist/types.js.map +1 -0
  110. package/dist/utils/response.d.ts +33 -0
  111. package/dist/utils/response.d.ts.map +1 -0
  112. package/dist/utils/response.js +54 -0
  113. package/dist/utils/response.js.map +1 -0
  114. package/package.json +5 -2
  115. package/dist/entities/organization.d.ts +0 -21
  116. package/dist/entities/organization.d.ts.map +0 -1
  117. package/dist/entities/organization.js +0 -32
  118. package/dist/entities/organization.js.map +0 -1
  119. package/dist/entities/user.d.ts +0 -23
  120. package/dist/entities/user.d.ts.map +0 -1
  121. package/dist/entities/user.js +0 -45
  122. package/dist/entities/user.js.map +0 -1
  123. package/dist/errors.d.ts +0 -22
  124. package/dist/errors.d.ts.map +0 -1
  125. package/dist/errors.js +0 -36
  126. package/dist/errors.js.map +0 -1
  127. package/dist/typebox/calendar.tb.d.ts +0 -113
  128. package/dist/typebox/calendar.tb.d.ts.map +0 -1
  129. package/dist/typebox/calendar.tb.js +0 -92
  130. package/dist/typebox/calendar.tb.js.map +0 -1
  131. package/dist/typebox/oauth.tb.d.ts +0 -14
  132. package/dist/typebox/oauth.tb.d.ts.map +0 -1
  133. package/dist/typebox/oauth.tb.js +0 -16
  134. package/dist/typebox/oauth.tb.js.map +0 -1
  135. package/dist/typebox/organization.stripped.tb.d.ts +0 -6
  136. package/dist/typebox/organization.stripped.tb.d.ts.map +0 -1
  137. package/dist/typebox/organization.stripped.tb.js +0 -7
  138. package/dist/typebox/organization.stripped.tb.js.map +0 -1
  139. package/dist/typebox/organization.tb.d.ts +0 -10
  140. package/dist/typebox/organization.tb.d.ts.map +0 -1
  141. package/dist/typebox/organization.tb.js +0 -8
  142. package/dist/typebox/organization.tb.js.map +0 -1
  143. package/dist/typebox/scheduling.tb.d.ts +0 -107
  144. package/dist/typebox/scheduling.tb.d.ts.map +0 -1
  145. package/dist/typebox/scheduling.tb.js +0 -105
  146. package/dist/typebox/scheduling.tb.js.map +0 -1
  147. package/dist/typebox/timeString.tb.d.ts +0 -3
  148. package/dist/typebox/timeString.tb.d.ts.map +0 -1
  149. package/dist/typebox/timeString.tb.js +0 -7
  150. package/dist/typebox/timeString.tb.js.map +0 -1
  151. package/dist/typebox/user.stripped.tb.d.ts +0 -5
  152. package/dist/typebox/user.stripped.tb.d.ts.map +0 -1
  153. package/dist/typebox/user.stripped.tb.js +0 -6
  154. package/dist/typebox/user.stripped.tb.js.map +0 -1
  155. package/dist/typebox/user.tb.d.ts +0 -19
  156. package/dist/typebox/user.tb.d.ts.map +0 -1
  157. package/dist/typebox/user.tb.js +0 -10
  158. package/dist/typebox/user.tb.js.map +0 -1
  159. package/dist/types/calendar.types.d.ts +0 -124
  160. package/dist/types/calendar.types.d.ts.map +0 -1
  161. package/dist/types/calendar.types.js +0 -27
  162. package/dist/types/calendar.types.js.map +0 -1
  163. package/dist/types/internal.types.d.ts +0 -7
  164. package/dist/types/internal.types.d.ts.map +0 -1
  165. package/dist/types/internal.types.js +0 -2
  166. package/dist/types/internal.types.js.map +0 -1
  167. package/dist/types/oauth.types.d.ts +0 -22
  168. package/dist/types/oauth.types.d.ts.map +0 -1
  169. package/dist/types/oauth.types.js +0 -2
  170. package/dist/types/oauth.types.js.map +0 -1
  171. package/dist/types/organization.types.d.ts +0 -18
  172. package/dist/types/organization.types.d.ts.map +0 -1
  173. package/dist/types/organization.types.js +0 -2
  174. package/dist/types/organization.types.js.map +0 -1
  175. package/dist/types/scheduling.types.d.ts +0 -50
  176. package/dist/types/scheduling.types.d.ts.map +0 -1
  177. package/dist/types/scheduling.types.js +0 -2
  178. package/dist/types/scheduling.types.js.map +0 -1
  179. package/dist/types/user.types.d.ts +0 -11
  180. package/dist/types/user.types.d.ts.map +0 -1
  181. package/dist/types/user.types.js +0 -2
  182. package/dist/types/user.types.js.map +0 -1
  183. package/dist/utils/fetch.helper.d.ts +0 -62
  184. package/dist/utils/fetch.helper.d.ts.map +0 -1
  185. package/dist/utils/fetch.helper.js +0 -116
  186. package/dist/utils/fetch.helper.js.map +0 -1
  187. package/dist/utils/fetchErrorHandler.d.ts +0 -22
  188. package/dist/utils/fetchErrorHandler.d.ts.map +0 -1
  189. package/dist/utils/fetchErrorHandler.js +0 -35
  190. package/dist/utils/fetchErrorHandler.js.map +0 -1
  191. package/dist/utils/includes.helper.d.ts +0 -4
  192. package/dist/utils/includes.helper.d.ts.map +0 -1
  193. package/dist/utils/includes.helper.js +0 -10
  194. package/dist/utils/includes.helper.js.map +0 -1
  195. package/dist/utils/omit.d.ts +0 -2
  196. package/dist/utils/omit.d.ts.map +0 -1
  197. package/dist/utils/omit.js +0 -4
  198. package/dist/utils/omit.js.map +0 -1
package/README.md CHANGED
@@ -59,781 +59,11 @@ The SDK is organized into logical service modules:
59
59
  - **`organizations`** - Team and organization management
60
60
  - **`oauth`** - Calendar provider authentication
61
61
 
62
- ### Time Zones
62
+ ## Documentation
63
63
 
64
- All date/time operations support timezone specification via the `timeZone` parameter.
64
+ Full documentation for the SDK, including usage, API schemas, and integration guides, is available at [docs.recal.dev](https://docs.recal.dev). Refer to the official docs for up-to-date examples and advanced configuration options.
65
65
 
66
- ## API Reference
67
66
 
68
- > TypeScript note
69
- >
70
- > - Use the exported `Provider` enum for provider arguments.
71
- > - Date/time fields in responses are parsed into `Date` objects at runtime.
72
- >
73
- > ```typescript
74
- > import { Provider } from 'recal-sdk'
75
- > ```
76
-
77
- ### Calendar Service
78
-
79
- #### List Calendars
80
-
81
- ```typescript
82
- // Get all calendars for a user
83
- const calendars = await recal.calendar.listCalendars('user_id')
84
-
85
- // Or filter by provider
86
- const googleCalendars = await recal.calendar.listCalendars(
87
- 'user_id',
88
- 'google' // optional: filter by provider
89
- )
90
-
91
- // Or filter by multiple providers
92
- const multiProviderCalendars = await recal.calendar.listCalendars(
93
- 'user_id',
94
- ['google', 'microsoft'] // optional: filter by multiple providers
95
- )
96
- ```
97
-
98
- #### Get Busy Information
99
-
100
- ```typescript
101
- // Get user's availability (simplest form)
102
- const busy = await recal.calendar.getBusy(
103
- 'user_id',
104
- new Date('2024-01-01'),
105
- new Date('2024-01-07')
106
- )
107
-
108
- // Or with optional filters
109
- const busyFiltered = await recal.calendar.getBusy(
110
- 'user_id',
111
- new Date('2024-01-01'),
112
- new Date('2024-01-07'),
113
- {
114
- provider: 'google', // optional: filter by provider
115
- calendarIds: ["calendar_id"] // optional: filter by calendarIds
116
- timeZone: 'America/New_York', // optional: timezone
117
- }
118
- )
119
- ```
120
-
121
- #### List Events
122
-
123
- ```typescript
124
- // Get all events in a date range (simplest form)
125
- const events = await recal.calendar.getEvents(
126
- 'user_id',
127
- new Date('2024-01-01'),
128
- new Date('2024-01-31')
129
- )
130
-
131
- // Or with optional filters
132
- const eventsFiltered = await recal.calendar.getEvents(
133
- 'user_id',
134
- new Date('2024-01-01'),
135
- new Date('2024-01-31'),
136
- {
137
- provider: 'google', // optional: filter by provider
138
- calendarIds: ["calendar_id"] // optional: filter by calendarIds
139
- timeZone: 'Europe/London' // optional: timezone
140
- }
141
- )
142
- ```
143
-
144
- #### Create Event
145
-
146
- ```typescript
147
- // Create a new event (without optional timezone)
148
- const event = await recal.calendar.createEvent({
149
- userId: 'user_id',
150
- provider: 'google',
151
- calendarId: 'calendar_id',
152
- event: {
153
- subject: 'Team Meeting',
154
- description: 'Weekly sync',
155
- start: new Date('2024-01-15T10:00:00Z'),
156
- end: new Date('2024-01-15T11:00:00Z'),
157
- attendees: [
158
- { email: 'colleague@company.com' }
159
- ]
160
- }
161
- })
162
-
163
- // Or with timezone option
164
- const eventWithTZ = await recal.calendar.createEvent({
165
- userId: 'user_id',
166
- provider: 'google',
167
- calendarId: 'calendar_id',
168
- event: {
169
- subject: 'Team Meeting',
170
- description: 'Weekly sync',
171
- start: new Date('2024-01-15T10:00:00Z'),
172
- end: new Date('2024-01-15T11:00:00Z'),
173
- attendees: [
174
- { email: 'colleague@company.com' }
175
- ]
176
- },
177
- options: { timeZone: 'Europe/Berlin' } // optional
178
- })
179
- ```
180
- #### Get Event
181
-
182
- ```typescript
183
- // Get an existing event
184
- const event = await recal.calendar.getEvent({
185
- userId: 'user_id',
186
- provider: 'google',
187
- calendarId: 'calendar_id',
188
- eventId: 'event_id',
189
- options: { timeZone: 'Europe/Berlin' } // optional
190
- })
191
- ```
192
-
193
- #### Update Event
194
-
195
- ```typescript
196
- // Update an existing event (simplest form)
197
- const updated = await recal.calendar.updateEvent({
198
- userId: 'user_id',
199
- provider: 'google',
200
- calendarId: 'calendar_id',
201
- eventId: 'event_id',
202
- event: {
203
- subject: 'Updated Meeting Title',
204
- start: new Date('2024-01-15T14:00:00Z'),
205
- end: new Date('2024-01-15T15:00:00Z')
206
- }
207
- })
208
- ```
209
-
210
- ```typescript
211
- // or with more options
212
- const updated = await recal.calendar.updateEvent({
213
- userId: 'user_id',
214
- provider: 'google',
215
- calendarId: 'calendar_id',
216
- eventId: 'event_id',
217
- event: {
218
- subject: 'Updated Meeting title',
219
- description: 'Updated description',
220
- start: new Date('2024-01-15T11:00:00Z'),
221
- end: new Date('2024-01-15T12:00:00Z'),
222
- attendees: [
223
- { email: 'colleague@company.com' }
224
- ]
225
- },
226
- options: { timeZone: 'Europe/Berlin' } // optional
227
- })
228
- ```
229
-
230
- #### Delete Event
231
-
232
- ```typescript
233
- // Delete an event
234
- await recal.calendar.deleteEvent({
235
- userId: 'user_id',
236
- provider: 'google',
237
- calendarId: 'calendar_id',
238
- eventId: 'event_id'
239
- })
240
- ```
241
-
242
- #### Cross-Calendar Operations (Meta Events)
243
-
244
- Meta events allow you to work with events across multiple calendar providers:
245
-
246
- ```typescript
247
- // Create event across all connected calendars (default behavior)
248
- const metaEvent = await recal.calendar.createEventByMetaId(
249
- 'user_id',
250
- {
251
- subject: 'Cross-platform meeting',
252
- start: new Date('2024-01-20T15:00:00Z'),
253
- end: new Date('2024-01-20T16:00:00Z')
254
- }
255
- )
256
-
257
- // Or specify which providers and timezone to use
258
- const metaEventSpecific = await recal.calendar.createEventByMetaId(
259
- 'user_id',
260
- {
261
- subject: 'Cross-platform meeting',
262
- start: new Date('2024-01-20T15:00:00Z'),
263
- end: new Date('2024-01-20T16:00:00Z')
264
- },
265
- {
266
- provider: ['google', 'microsoft'], // Create on specific providers
267
- timeZone: 'Europe/Berlin' // optional
268
- }
269
- )
270
-
271
- // Get event across all connected calendars (default behavior)
272
- const metaEventGet = await recal.calendar.getEventByMetaId(
273
- 'user_id',
274
- metaEvent.metaId
275
- )
276
-
277
- // Update across all calendars using meta ID
278
- await recal.calendar.updateEventByMetaId(
279
- 'user_id',
280
- metaEvent.metaId,
281
- { subject: 'Updated title' }
282
- )
283
-
284
- // Delete from all calendars
285
- await recal.calendar.deleteEventByMetaId(
286
- 'user_id',
287
- metaEvent.metaId
288
- )
289
- ```
290
-
291
- ### Scheduling Service
292
-
293
- #### Get User Availability (Basic)
294
-
295
- ```typescript
296
- // Find available time slots (minimal config)
297
- const availability = await recal.scheduling.user(
298
- 'user_id',
299
- new Date('2024-01-15'),
300
- new Date('2024-01-20'),
301
- {
302
- slotDuration: 30 // Only required: slot duration in minutes
303
- }
304
- )
305
-
306
- // Or with more options
307
- const availabilityDetailed = await recal.scheduling.user(
308
- 'user_id',
309
- new Date('2024-01-15'),
310
- new Date('2024-01-20'),
311
- {
312
- slotDuration: 30, // Duration of each slot in minutes
313
- padding: 0, // Padding between slots
314
- earliestTimeEachDay: '09:00', // Format: HH:mm
315
- latestTimeEachDay: '17:00', // Format: HH:mm
316
- provider: 'google', // optional: filter by provider
317
- timeZone: 'America/New_York' // optional
318
- }
319
- )
320
- ```
321
-
322
- #### Allow Overlapping Events
323
-
324
- ```typescript
325
- // Find availability even when user already has events scheduled
326
- const availabilityWithOverlaps = await recal.scheduling.user(
327
- 'user_id',
328
- new Date('2024-01-15'),
329
- new Date('2024-01-20'),
330
- {
331
- slotDuration: 30,
332
- maxOverlaps: 2, // Allow up to 2 overlapping events per slot
333
- timeZone: 'America/New_York'
334
- }
335
- )
336
-
337
- // maxOverlaps: 2, means 1 slot is still available even if the user has 2 existing events at the same time.
338
- // This enables booking a n concurrent events - useful for optional meetings,
339
- // tentative invites, or users who can handle multiple events simultaneous, like a team that has just one calendar.
340
- ```
341
-
342
- #### Get User Availability (Advanced)
343
-
344
- ```typescript
345
- // Find available time slots with custom schedules
346
- const schedules = [
347
- {
348
- days: ['monday'], // Monday
349
- start: '09:00',
350
- end: '17:00'
351
- },
352
- // ... more schedule rules
353
- ]
354
-
355
- // Minimal config
356
- const availability = await recal.scheduling.userAdvanced(
357
- 'user_id',
358
- schedules,
359
- new Date('2024-01-15'),
360
- new Date('2024-01-20'),
361
- { slotDuration: 30 } // Only required option
362
- )
363
-
364
- // Or with more options
365
- const availabilityDetailed = await recal.scheduling.userAdvanced(
366
- 'user_id',
367
- schedules,
368
- new Date('2024-01-15'),
369
- new Date('2024-01-20'),
370
- {
371
- slotDuration: 30,
372
- padding: 15,
373
- provider: 'google', // optional
374
- timeZone: 'America/New_York' // optional
375
- }
376
- )
377
- ```
378
-
379
- #### Get Organization-Wide Availability
380
-
381
- ```typescript
382
- // Find organization-wide available time slots (minimal)
383
- const orgAvailability = await recal.scheduling.organization(
384
- 'org-slug',
385
- new Date('2024-01-15'),
386
- new Date('2024-01-20'),
387
- { slotDuration: 60 } // Only required option
388
- )
389
-
390
- // Or with constraints
391
- const orgAvailabilityConstrained = await recal.scheduling.organization(
392
- 'org-slug',
393
- new Date('2024-01-15'),
394
- new Date('2024-01-20'),
395
- {
396
- slotDuration: 60,
397
- padding: 0,
398
- earliestTimeEachDay: '09:00',
399
- latestTimeEachDay: '17:00',
400
- provider: ['google', 'microsoft'], // optional
401
- timeZone: 'America/New_York' // optional
402
- }
403
- )
404
- ```
405
-
406
- ### Users Service
407
-
408
- #### Get User
409
-
410
- ```typescript
411
- // Get user information (basic)
412
- const user = await recal.users.get('user_id', {})
413
-
414
- // Or with additional data
415
- const userWithDetails = await recal.users.get('user_id', {
416
- includeOrgs: true, // Include organizations
417
- includeOAuth: true // Include OAuth connections
418
- })
419
- console.log(user.id)
420
- ```
421
-
422
- #### List All Users
423
-
424
- ```typescript
425
- // Get all users
426
- const users = await recal.users.listAll()
427
- ```
428
-
429
- #### Create User
430
-
431
- ```typescript
432
- // Create a new user (without organizations)
433
- const user = await recal.users.create('user_id')
434
-
435
- // Or with organization memberships
436
- const userWithOrgs = await recal.users.create(
437
- 'user_id',
438
- ['org-slug-1', 'org-slug-2'] // optional: organization slugs
439
- )
440
- ```
441
-
442
- #### Update User
443
-
444
- ```typescript
445
- // Update user ID
446
- const updatedUser = await recal.users.update('old_user_id', {
447
- id: 'new_user_id'
448
- })
449
- ```
450
-
451
- #### Delete User
452
-
453
- ```typescript
454
- // Delete a user
455
- const deletedUser = await recal.users.delete('user_id')
456
- ```
457
-
458
- ### Organizations Service
459
-
460
- #### Get Organization
461
-
462
- ```typescript
463
- // Get organization by slug
464
- const org = await recal.organizations.get('acme-corp')
465
- ```
466
-
467
- #### List All Organizations
468
-
469
- ```typescript
470
- // Get all organizations
471
- const orgs = await recal.organizations.listAll()
472
-
473
- // Get organizations for a specific user
474
- const userOrgs = await recal.organizations.listAllFromUser('user_id')
475
- ```
476
-
477
- #### Create Organization
478
-
479
- ```typescript
480
- // Create a new organization
481
- const org = await recal.organizations.create(
482
- 'acme-corp', // slug
483
- 'Acme Corporation' // name
484
- )
485
- ```
486
-
487
- #### Update Organization
488
-
489
- ```typescript
490
- // Update organization
491
- const updated = await recal.organizations.update('acme-corp', {
492
- slug: 'new-slug',
493
- name: 'New Name'
494
- })
495
- ```
496
-
497
- #### Manage Members
498
-
499
- ```typescript
500
- // Get all members
501
- const members = await recal.organizations.getMembers('acme-corp')
502
-
503
- // Add members
504
- await recal.organizations.addMembers(
505
- 'acme-corp',
506
- ['user_id_1', 'user_id_2']
507
- )
508
-
509
- // Remove members
510
- await recal.organizations.removeMembers(
511
- 'acme-corp',
512
- ['user_id_1', 'user_id_2']
513
- )
514
- ```
515
-
516
- #### Organization-Wide Busy
517
-
518
- ```typescript
519
- // Get team availability (simplest form)
520
- const teamBusy = await recal.calendar.getOrgWideBusy(
521
- 'acme-corp',
522
- new Date('2024-01-15'),
523
- new Date('2024-01-20'),
524
- true // primaryOnly: only check primary calendars
525
- )
526
-
527
- // Or with optional filters
528
- const teamBusyFiltered = await recal.calendar.getOrgWideBusy(
529
- 'acme-corp',
530
- new Date('2024-01-15'),
531
- new Date('2024-01-20'),
532
- true, // primaryOnly: only check primary calendars
533
- {
534
- provider: 'google', // optional: filter by provider
535
- timeZone: 'America/New_York' // optional
536
- }
537
- )
538
- ```
539
-
540
- ### OAuth Service
541
-
542
- #### Get OAuth Link
543
-
544
- ```typescript
545
- // Get OAuth authorization URL (with defaults)
546
- const link = await recal.oauth.getLink(
547
- 'user_id',
548
- 'google'
549
- )
550
-
551
- // Or with custom options
552
- const linkWithOptions = await recal.oauth.getLink(
553
- 'user_id',
554
- 'google',
555
- {
556
- scope: ['edit'], // 'edit' or 'free-busy' (for OAuth scopes)
557
- accessType: 'offline', // 'offline' or 'online'
558
- redirectUrl: 'https://app.example.com/callback' // optional
559
- }
560
- )
561
- console.log(link.url) // Use this URL to redirect user
562
- ```
563
-
564
- #### Get Multiple OAuth Links
565
-
566
- ```typescript
567
- // Get OAuth URLs for all providers (simplest)
568
- const links = await recal.oauth.getBulkLinks('user_id')
569
-
570
- // Or with specific providers and options
571
- const linksFiltered = await recal.oauth.getBulkLinks(
572
- 'user_id',
573
- {
574
- provider: ['google', 'microsoft'],
575
- scope: ['edit'],
576
- accessType: 'offline'
577
- }
578
- )
579
- ```
580
-
581
- #### Manage OAuth Connections
582
-
583
- ```typescript
584
- // Get all OAuth connections for a user
585
- const connections = await recal.oauth.getAllConnections(
586
- 'user_id',
587
- true // redacted (default: true)
588
- )
589
-
590
- // Get specific provider connection
591
- const googleConnection = await recal.oauth.getConnection(
592
- 'user_id',
593
- 'google',
594
- false // redacted
595
- )
596
-
597
- // Set OAuth tokens manually
598
- const connection = await recal.oauth.setConnection(
599
- 'user_id',
600
- 'google',
601
- {
602
- accessToken: 'access_token',
603
- refreshToken: 'refresh_token', // optional
604
- scope: ['edit'],
605
- expiresAt: new Date('2024-12-31'), // optional
606
- email: 'user@example.com' // optional
607
- }
608
- )
609
-
610
- // Disconnect a provider
611
- await recal.oauth.disconnect('user_id', 'google')
612
- ```
613
-
614
- #### Verify OAuth Callback
615
-
616
- ```typescript
617
- // Verify OAuth code from callback
618
- const result = await recal.oauth.verify(
619
- 'google',
620
- 'auth_code_from_callback',
621
- ['edit'], // 'edit' or 'free-busy' - single scope, not array
622
- 'state_parameter',
623
- 'https://app.example.com/callback' // optional
624
- )
625
- ```
626
-
627
- ## Advanced Usage
628
-
629
- ### Error Handling
630
-
631
- The SDK provides specific error types for different scenarios:
632
-
633
- ```typescript
634
- import {
635
- UserNotFoundError,
636
- EventNotFoundError,
637
- OAuthConnectionNotFoundError,
638
- OrganizationNotFoundError
639
- } from 'recal-sdk'
640
-
641
- try {
642
- const event = await recal.calendar.getEvent({
643
- userId: 'user_id',
644
- provider: 'google',
645
- calendarId: 'calendar_id',
646
- eventId: 'event_id'
647
- })
648
- } catch (error) {
649
- if (error instanceof UserNotFoundError) {
650
- console.log('User does not exist:', error.userId)
651
- } else if (error instanceof EventNotFoundError) {
652
- console.log('Event not found:', error.eventId)
653
- } else if (error instanceof OAuthConnectionNotFoundError) {
654
- console.log('Calendar not connected:', error.provider)
655
- }
656
- }
657
- ```
658
-
659
- ### Batch Operations
660
-
661
- ```typescript
662
- // Process multiple users' calendars (simplest form)
663
- const userIds = ['user1', 'user2', 'user3']
664
- const allEvents = await Promise.all(
665
- userIds.map(userId =>
666
- recal.calendar.getEvents(
667
- userId,
668
- new Date('2024-01-01'),
669
- new Date('2024-01-31')
670
- )
671
- )
672
- )
673
- ```
674
-
675
- ### Working with Multiple Providers
676
-
677
- ```typescript
678
- // Get all busy data (without filtering)
679
- const startDate = new Date('2024-01-01')
680
- const endDate = new Date('2024-01-31')
681
-
682
- const allBusy = await recal.calendar.getBusy(
683
- 'user_id',
684
- startDate,
685
- endDate
686
- )
687
-
688
- // Or aggregate by specific providers
689
- const providers: Provider[] = ['google', 'microsoft']
690
- const busyTimes = await Promise.all(
691
- providers.map(provider =>
692
- recal.calendar.getBusy(
693
- 'user_id',
694
- startDate,
695
- endDate,
696
- { provider } // filter by specific provider
697
- )
698
- )
699
- )
700
-
701
- // Process the busy times as needed for your application
702
- // Each element is Busy = TimeRange[]; flatten into a single array of TimeRange
703
- const allBusyPeriods = busyTimes.flat()
704
- ```
705
-
706
- ### Custom Request Configuration
707
-
708
- ```typescript
709
- // Use custom base URL
710
- const recal = new RecalClient({
711
- token: 'recal_token',
712
- url: 'https://api.recal.dev' // optional, this is the default
713
- })
714
- ```
715
-
716
- ## Examples
717
-
718
- ### Building a Booking System
719
-
720
- ```typescript
721
- // 1. Check availability
722
- const availability = await recal.scheduling.user(
723
- 'consultant_id',
724
- new Date(),
725
- new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // Next 7 days
726
- {
727
- slotDuration: 60, // 60-minute slots
728
- padding: 15, // 15-minute padding between slots
729
- earliestTimeEachDay: '09:00',
730
- latestTimeEachDay: '17:00',
731
- timeZone: 'America/New_York'
732
- }
733
- )
734
-
735
- // 2. Display available slots to user
736
- const availableSlots = availability.availableSlots // Already filtered for availability
737
-
738
- // 3. User selects a slot and provides their information
739
- const selectedSlot = availableSlots[0] // Example: first available slot
740
- const clientName = 'John Doe'
741
- const clientEmail = 'john@example.com'
742
-
743
- // 4. Create an event for the selected slot (using calendar service)
744
- const booking = await recal.calendar.createEvent({
745
- userId: 'consultant_id',
746
- provider: 'google',
747
- calendarId: 'primary',
748
- event: {
749
- subject: 'Consultation with ' + clientName,
750
- description: 'Initial consultation',
751
- start: selectedSlot.start,
752
- end: selectedSlot.end,
753
- attendees: [{ email: clientEmail }]
754
- }
755
- })
756
-
757
- // 5. Send confirmation
758
- console.log('Booking confirmed:', booking.id)
759
- ```
760
-
761
- ### Syncing Calendars
762
-
763
- ```typescript
764
- // Sync events between providers
765
- async function syncCalendars(userId: string) {
766
- // Get all events from all providers
767
- const allEvents = await recal.calendar.getEvents(
768
- userId,
769
- new Date(),
770
- new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)
771
- )
772
-
773
- // Or get events from Google only
774
- const googleEvents = await recal.calendar.getEvents(
775
- userId,
776
- new Date(),
777
- new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
778
- { provider: 'google' }
779
- )
780
-
781
- // Copy to Microsoft calendar
782
- for (const event of googleEvents) {
783
- if (!event.metaId) { // Not already synced
784
- await recal.calendar.createEvent({
785
- userId,
786
- provider: 'microsoft',
787
- calendarId: 'primary',
788
- event: {
789
- subject: event.subject,
790
- description: event.description,
791
- start: event.start,
792
- end: event.end,
793
- attendees: event.attendees
794
- }
795
- })
796
- }
797
- }
798
- }
799
- ```
800
-
801
- ### Team Scheduling
802
-
803
- ```typescript
804
- // Find time when entire team is available
805
- async function findTeamSlot(
806
- orgSlug: string,
807
- duration: number,
808
- startDate: Date,
809
- endDate: Date
810
- ) {
811
- // Option 1: Get raw busy times for manual processing
812
- const busyTimes = await recal.calendar.getOrgWideBusy(
813
- orgSlug,
814
- startDate,
815
- endDate,
816
- true // Only check primary calendars
817
- )
818
- // Process busyTimes array to find gaps for your needs
819
-
820
- // Option 2: Use the scheduling service (recommended)
821
- const availability = await recal.scheduling.getOrgWideAvailability(
822
- orgSlug,
823
- startDate,
824
- endDate,
825
- {
826
- slotDuration: duration,
827
- padding: 0,
828
- earliestTimeEachDay: '09:00',
829
- latestTimeEachDay: '17:00'
830
- }
831
- )
832
-
833
- // Returns ready-to-use available time slots
834
- return availability.availableSlots
835
- }
836
- ```
837
67
 
838
68
  ## SDK Development
839
69
 
@@ -864,37 +94,39 @@ bun run build
864
94
 
865
95
  ```
866
96
  src/
867
- ├── index.ts # Main client and exports
97
+ ├── entities/
98
+ │ ├── organization.ts # Domain models
99
+ │ └── user.ts
868
100
  ├── services/ # Service implementations
869
101
  │ ├── calendar.service.ts
870
- │ ├── scheduling.service.ts
871
- │ ├── users.service.ts
102
+ │ ├── oauth.service.ts
872
103
  │ ├── organizations.service.ts
873
- │ └── oauth.service.ts
874
- ├── entities/ # Domain models
875
- │ ├── user.ts
876
- │ └── organization.ts
877
- ├── types/ # TypeScript type definitions
878
- │ ├── calendar.types.ts
879
- │ ├── scheduling.types.ts
880
- │ ├── internal.types.ts
881
- │ └── oauth.types.ts
104
+ │ ├── scheduling.service.ts
105
+ │ └── users.service.ts
882
106
  ├── typebox/ # Runtime validation schemas (auto-generated)
883
107
  │ ├── calendar.tb.ts
884
- │ ├── scheduling.tb.ts
885
108
  │ ├── oauth.tb.ts
109
+ │ ├── organization.stripped.tb.ts
886
110
  │ ├── organization.tb.ts
887
- │ ├── user.tb.ts
111
+ │ ├── scheduling.tb.ts
888
112
  │ ├── timeString.tb.ts
889
- │ ├── organization.stripped.tb.ts
890
- │ └── user.stripped.tb.ts
113
+ │ ├── user.stripped.tb.ts
114
+ │ └── user.tb.ts
115
+ ├── types/ # TypeScript type definitions
116
+ │ ├── calendar.types.ts
117
+ │ ├── internal.types.ts
118
+ │ ├── oauth.types.ts
119
+ │ ├── organization.types.ts
120
+ │ ├── scheduling.types.ts
121
+ │ └── user.types.ts
891
122
  ├── utils/ # Helper utilities
892
123
  │ ├── fetch.helper.ts
893
124
  │ ├── fetchErrorHandler.ts
894
- │ ├── includes.helper.ts
895
125
  │ ├── functionize.ts
126
+ │ ├── includes.helper.ts
896
127
  │ └── omit.ts
897
- └── errors.ts # Custom error classes
128
+ ├── errors.ts # Custom error classes
129
+ └── index.ts # Main client and exports
898
130
  ```
899
131
 
900
132
  ### Code Style
@@ -951,9 +183,9 @@ Found a bug or have a feature request? Please [open an issue](https://github.com
951
183
  ## Support
952
184
 
953
185
  - **Documentation**: [https://docs.recal.dev](https://docs.recal.dev)
954
- - **API Reference**: [https://api.recal.dev/docs](https://api.recal.dev/docs)
186
+ - **API Reference**: [https://api.recal.dev/docs](https://api.recal.dev/v1/swagger)
955
187
  - **Email**: team@recal.dev
956
- - **Discord**: [Join our community](https://discord.gg/recal)
188
+ - **Slack**: [Join our community](https://join.slack.com/t/recal-workspace/shared_invite/zt-394r5j23n-WDr_tz753Cf8lQljrK_0Mw)
957
189
 
958
190
  ## License
959
191