recal-sdk 0.3.3 → 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 -796
  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 +120 -66
  91. package/dist/services/oauth.service.d.ts.map +1 -1
  92. package/dist/services/oauth.service.js +162 -151
  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,785 +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
- // Get a fresh access token (useful when you need to make direct API calls)
614
- const tokenData = await recal.oauth.getFreshAccessToken('user_id', 'google')
615
- console.log(tokenData.accessToken)
616
- ```
617
-
618
- #### Verify OAuth Callback
619
-
620
- ```typescript
621
- // Verify OAuth code from callback
622
- const result = await recal.oauth.verify(
623
- 'google',
624
- 'auth_code_from_callback',
625
- ['edit'], // 'edit' or 'free-busy' - single scope, not array
626
- 'state_parameter',
627
- 'https://app.example.com/callback' // optional
628
- )
629
- ```
630
-
631
- ## Advanced Usage
632
-
633
- ### Error Handling
634
-
635
- The SDK provides specific error types for different scenarios:
636
-
637
- ```typescript
638
- import {
639
- UserNotFoundError,
640
- EventNotFoundError,
641
- OAuthConnectionNotFoundError,
642
- OrganizationNotFoundError
643
- } from 'recal-sdk'
644
-
645
- try {
646
- const event = await recal.calendar.getEvent({
647
- userId: 'user_id',
648
- provider: 'google',
649
- calendarId: 'calendar_id',
650
- eventId: 'event_id'
651
- })
652
- } catch (error) {
653
- if (error instanceof UserNotFoundError) {
654
- console.log('User does not exist:', error.userId)
655
- } else if (error instanceof EventNotFoundError) {
656
- console.log('Event not found:', error.eventId)
657
- } else if (error instanceof OAuthConnectionNotFoundError) {
658
- console.log('Calendar not connected:', error.provider)
659
- }
660
- }
661
- ```
662
-
663
- ### Batch Operations
664
-
665
- ```typescript
666
- // Process multiple users' calendars (simplest form)
667
- const userIds = ['user1', 'user2', 'user3']
668
- const allEvents = await Promise.all(
669
- userIds.map(userId =>
670
- recal.calendar.getEvents(
671
- userId,
672
- new Date('2024-01-01'),
673
- new Date('2024-01-31')
674
- )
675
- )
676
- )
677
- ```
678
-
679
- ### Working with Multiple Providers
680
-
681
- ```typescript
682
- // Get all busy data (without filtering)
683
- const startDate = new Date('2024-01-01')
684
- const endDate = new Date('2024-01-31')
685
-
686
- const allBusy = await recal.calendar.getBusy(
687
- 'user_id',
688
- startDate,
689
- endDate
690
- )
691
-
692
- // Or aggregate by specific providers
693
- const providers: Provider[] = ['google', 'microsoft']
694
- const busyTimes = await Promise.all(
695
- providers.map(provider =>
696
- recal.calendar.getBusy(
697
- 'user_id',
698
- startDate,
699
- endDate,
700
- { provider } // filter by specific provider
701
- )
702
- )
703
- )
704
-
705
- // Process the busy times as needed for your application
706
- // Each element is Busy = TimeRange[]; flatten into a single array of TimeRange
707
- const allBusyPeriods = busyTimes.flat()
708
- ```
709
-
710
- ### Custom Request Configuration
711
-
712
- ```typescript
713
- // Use custom base URL
714
- const recal = new RecalClient({
715
- token: 'recal_token',
716
- url: 'https://api.recal.dev' // optional, this is the default
717
- })
718
- ```
719
-
720
- ## Examples
721
-
722
- ### Building a Booking System
723
-
724
- ```typescript
725
- // 1. Check availability
726
- const availability = await recal.scheduling.user(
727
- 'consultant_id',
728
- new Date(),
729
- new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // Next 7 days
730
- {
731
- slotDuration: 60, // 60-minute slots
732
- padding: 15, // 15-minute padding between slots
733
- earliestTimeEachDay: '09:00',
734
- latestTimeEachDay: '17:00',
735
- timeZone: 'America/New_York'
736
- }
737
- )
738
-
739
- // 2. Display available slots to user
740
- const availableSlots = availability.availableSlots // Already filtered for availability
741
-
742
- // 3. User selects a slot and provides their information
743
- const selectedSlot = availableSlots[0] // Example: first available slot
744
- const clientName = 'John Doe'
745
- const clientEmail = 'john@example.com'
746
-
747
- // 4. Create an event for the selected slot (using calendar service)
748
- const booking = await recal.calendar.createEvent({
749
- userId: 'consultant_id',
750
- provider: 'google',
751
- calendarId: 'primary',
752
- event: {
753
- subject: 'Consultation with ' + clientName,
754
- description: 'Initial consultation',
755
- start: selectedSlot.start,
756
- end: selectedSlot.end,
757
- attendees: [{ email: clientEmail }]
758
- }
759
- })
760
-
761
- // 5. Send confirmation
762
- console.log('Booking confirmed:', booking.id)
763
- ```
764
-
765
- ### Syncing Calendars
766
-
767
- ```typescript
768
- // Sync events between providers
769
- async function syncCalendars(userId: string) {
770
- // Get all events from all providers
771
- const allEvents = await recal.calendar.getEvents(
772
- userId,
773
- new Date(),
774
- new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)
775
- )
776
-
777
- // Or get events from Google only
778
- const googleEvents = await recal.calendar.getEvents(
779
- userId,
780
- new Date(),
781
- new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
782
- { provider: 'google' }
783
- )
784
-
785
- // Copy to Microsoft calendar
786
- for (const event of googleEvents) {
787
- if (!event.metaId) { // Not already synced
788
- await recal.calendar.createEvent({
789
- userId,
790
- provider: 'microsoft',
791
- calendarId: 'primary',
792
- event: {
793
- subject: event.subject,
794
- description: event.description,
795
- start: event.start,
796
- end: event.end,
797
- attendees: event.attendees
798
- }
799
- })
800
- }
801
- }
802
- }
803
- ```
804
-
805
- ### Team Scheduling
806
-
807
- ```typescript
808
- // Find time when entire team is available
809
- async function findTeamSlot(
810
- orgSlug: string,
811
- duration: number,
812
- startDate: Date,
813
- endDate: Date
814
- ) {
815
- // Option 1: Get raw busy times for manual processing
816
- const busyTimes = await recal.calendar.getOrgWideBusy(
817
- orgSlug,
818
- startDate,
819
- endDate,
820
- true // Only check primary calendars
821
- )
822
- // Process busyTimes array to find gaps for your needs
823
-
824
- // Option 2: Use the scheduling service (recommended)
825
- const availability = await recal.scheduling.getOrgWideAvailability(
826
- orgSlug,
827
- startDate,
828
- endDate,
829
- {
830
- slotDuration: duration,
831
- padding: 0,
832
- earliestTimeEachDay: '09:00',
833
- latestTimeEachDay: '17:00'
834
- }
835
- )
836
-
837
- // Returns ready-to-use available time slots
838
- return availability.availableSlots
839
- }
840
- ```
841
67
 
842
68
  ## SDK Development
843
69
 
@@ -868,37 +94,39 @@ bun run build
868
94
 
869
95
  ```
870
96
  src/
871
- ├── index.ts # Main client and exports
97
+ ├── entities/
98
+ │ ├── organization.ts # Domain models
99
+ │ └── user.ts
872
100
  ├── services/ # Service implementations
873
101
  │ ├── calendar.service.ts
874
- │ ├── scheduling.service.ts
875
- │ ├── users.service.ts
102
+ │ ├── oauth.service.ts
876
103
  │ ├── organizations.service.ts
877
- │ └── oauth.service.ts
878
- ├── entities/ # Domain models
879
- │ ├── user.ts
880
- │ └── organization.ts
881
- ├── types/ # TypeScript type definitions
882
- │ ├── calendar.types.ts
883
- │ ├── scheduling.types.ts
884
- │ ├── internal.types.ts
885
- │ └── oauth.types.ts
104
+ │ ├── scheduling.service.ts
105
+ │ └── users.service.ts
886
106
  ├── typebox/ # Runtime validation schemas (auto-generated)
887
107
  │ ├── calendar.tb.ts
888
- │ ├── scheduling.tb.ts
889
108
  │ ├── oauth.tb.ts
109
+ │ ├── organization.stripped.tb.ts
890
110
  │ ├── organization.tb.ts
891
- │ ├── user.tb.ts
111
+ │ ├── scheduling.tb.ts
892
112
  │ ├── timeString.tb.ts
893
- │ ├── organization.stripped.tb.ts
894
- │ └── 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
895
122
  ├── utils/ # Helper utilities
896
123
  │ ├── fetch.helper.ts
897
124
  │ ├── fetchErrorHandler.ts
898
- │ ├── includes.helper.ts
899
125
  │ ├── functionize.ts
126
+ │ ├── includes.helper.ts
900
127
  │ └── omit.ts
901
- └── errors.ts # Custom error classes
128
+ ├── errors.ts # Custom error classes
129
+ └── index.ts # Main client and exports
902
130
  ```
903
131
 
904
132
  ### Code Style
@@ -955,9 +183,9 @@ Found a bug or have a feature request? Please [open an issue](https://github.com
955
183
  ## Support
956
184
 
957
185
  - **Documentation**: [https://docs.recal.dev](https://docs.recal.dev)
958
- - **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)
959
187
  - **Email**: team@recal.dev
960
- - **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)
961
189
 
962
190
  ## License
963
191