@savvycal/appointments-core 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/dist/index.js ADDED
@@ -0,0 +1,432 @@
1
+ // src/client.ts
2
+ import createClient from "openapi-fetch";
3
+ var DEFAULT_BASE_URL = "https://api.savvycal.app";
4
+ var UNPROTECTED_PATHS = ["/v1/public"];
5
+ var isValidJwt = (token) => {
6
+ const parts = token.split(".");
7
+ if (parts.length !== 3) return false;
8
+ try {
9
+ JSON.parse(atob(parts[1]));
10
+ return true;
11
+ } catch {
12
+ return false;
13
+ }
14
+ };
15
+ var isTokenExpired = (token) => {
16
+ try {
17
+ const payload = token.split(".")[1];
18
+ if (!payload) return true;
19
+ const decoded = JSON.parse(atob(payload));
20
+ if (!decoded.exp) return false;
21
+ return decoded.exp * 1e3 < Date.now();
22
+ } catch {
23
+ return true;
24
+ }
25
+ };
26
+ var createFetchClient = (options = {}) => {
27
+ let accessToken;
28
+ const authMiddleware = {
29
+ async onRequest({ request, schemaPath }) {
30
+ if (UNPROTECTED_PATHS.some((path) => schemaPath.startsWith(path))) {
31
+ return void 0;
32
+ }
33
+ if (options.demo) {
34
+ request.headers.set("Authorization", `Demo ${options.demo}`);
35
+ return request;
36
+ }
37
+ if (!options.fetchAccessToken) {
38
+ throw new Error("No fetchAccessToken provided");
39
+ }
40
+ if (!accessToken || isTokenExpired(accessToken)) {
41
+ const authRes = await options.fetchAccessToken();
42
+ if (!authRes) {
43
+ throw new Error("No access token");
44
+ }
45
+ if (!isValidJwt(authRes)) {
46
+ throw new Error("Invalid access token: expected a JWT");
47
+ }
48
+ accessToken = authRes;
49
+ }
50
+ request.headers.set("Authorization", `Bearer ${accessToken}`);
51
+ return request;
52
+ }
53
+ };
54
+ const clientOptions = {
55
+ baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
56
+ headers: {},
57
+ ...options
58
+ };
59
+ if (options.demo) {
60
+ clientOptions.headers = {
61
+ ...clientOptions.headers,
62
+ Authorization: `Demo ${options.demo}`
63
+ };
64
+ }
65
+ if (options.account) {
66
+ clientOptions.headers = {
67
+ ...clientOptions.headers,
68
+ "X-SavvyCal-Account": options.account
69
+ };
70
+ }
71
+ const client = createClient(clientOptions);
72
+ client.use(authMiddleware);
73
+ return client;
74
+ };
75
+
76
+ // src/operations.ts
77
+ function cancelAppointment(client, path, body) {
78
+ return client.POST("/v1/appointments/{appointment_id}/cancel", {
79
+ body,
80
+ params: { path }
81
+ });
82
+ }
83
+ function cancelPublicAppointment(client, path, body) {
84
+ return client.POST("/v1/public/appointments/{appointment_id}/cancel", {
85
+ body,
86
+ params: { path }
87
+ });
88
+ }
89
+ function confirmAppointment(client, path, body) {
90
+ return client.POST("/v1/appointments/{appointment_id}/confirm", {
91
+ body,
92
+ params: { path }
93
+ });
94
+ }
95
+ function createAccount(client, body) {
96
+ return client.POST("/v1/accounts", {
97
+ body
98
+ });
99
+ }
100
+ function createAccountUser(client, body) {
101
+ return client.POST("/v1/users", {
102
+ body
103
+ });
104
+ }
105
+ function createAppointment(client, body) {
106
+ return client.POST("/v1/appointments", {
107
+ body
108
+ });
109
+ }
110
+ function createBlock(client, body) {
111
+ return client.POST("/v1/blocks", {
112
+ body
113
+ });
114
+ }
115
+ function createCancellationReason(client, body) {
116
+ return client.POST("/v1/cancellation_reasons", {
117
+ body
118
+ });
119
+ }
120
+ function createClient2(client, body) {
121
+ return client.POST("/v1/clients", {
122
+ body
123
+ });
124
+ }
125
+ function createDashboardSession(client, body) {
126
+ return client.POST("/v1/dashboard_sessions", {
127
+ body
128
+ });
129
+ }
130
+ function createProvider(client, body) {
131
+ return client.POST("/v1/providers", {
132
+ body
133
+ });
134
+ }
135
+ function createProviderSchedule(client, path, body) {
136
+ return client.POST("/v1/providers/{provider_id}/schedules", {
137
+ body,
138
+ params: { path }
139
+ });
140
+ }
141
+ function createPublicAppointment(client, body) {
142
+ return client.POST("/v1/public/appointments", {
143
+ body
144
+ });
145
+ }
146
+ function createService(client, body) {
147
+ return client.POST("/v1/services", {
148
+ body
149
+ });
150
+ }
151
+ function createServiceProvider(client, path, body) {
152
+ return client.POST("/v1/services/{service_id}/providers", {
153
+ body,
154
+ params: { path }
155
+ });
156
+ }
157
+ function deactivateProvider(client, path) {
158
+ return client.DELETE("/v1/providers/{provider_id}", {
159
+ params: { path }
160
+ });
161
+ }
162
+ function deleteBlock(client, path) {
163
+ return client.DELETE("/v1/blocks/{block_id}", {
164
+ params: { path }
165
+ });
166
+ }
167
+ function deleteCancellationReason(client, path) {
168
+ return client.DELETE("/v1/cancellation_reasons/{cancellation_reason_id}", {
169
+ params: { path }
170
+ });
171
+ }
172
+ function deleteClient(client, path) {
173
+ return client.DELETE("/v1/clients/{client_id}", {
174
+ params: { path }
175
+ });
176
+ }
177
+ function deleteProviderSchedule(client, path) {
178
+ return client.DELETE("/v1/provider_schedules/{provider_schedule_id}", {
179
+ params: { path }
180
+ });
181
+ }
182
+ function deleteService(client, path) {
183
+ return client.DELETE("/v1/services/{service_id}", {
184
+ params: { path }
185
+ });
186
+ }
187
+ function deleteServiceProvider(client, path) {
188
+ return client.DELETE("/v1/service_providers/{service_provider_id}", {
189
+ params: { path }
190
+ });
191
+ }
192
+ function getAccountById(client, path) {
193
+ return client.GET("/v1/accounts/{account_id}", {
194
+ params: { path }
195
+ });
196
+ }
197
+ function getAppointment(client, path, query) {
198
+ return client.GET("/v1/appointments/{appointment_id}", {
199
+ params: { path, query }
200
+ });
201
+ }
202
+ function getBlock(client, path) {
203
+ return client.GET("/v1/blocks/{block_id}", {
204
+ params: { path }
205
+ });
206
+ }
207
+ function getCancellationReason(client, path) {
208
+ return client.GET("/v1/cancellation_reasons/{cancellation_reason_id}", {
209
+ params: { path }
210
+ });
211
+ }
212
+ function getClient(client, path) {
213
+ return client.GET("/v1/clients/{client_id}", {
214
+ params: { path }
215
+ });
216
+ }
217
+ function getCurrentAccount(client) {
218
+ return client.GET("/v1/account");
219
+ }
220
+ function getCurrentAccountUser(client) {
221
+ return client.GET("/v1/user");
222
+ }
223
+ function getCurrentPlatform(client) {
224
+ return client.GET("/v1/platform");
225
+ }
226
+ function getEarliestPublicServiceSlot(client, path, query) {
227
+ return client.GET("/v1/public/services/{service_id}/earliest_slot", {
228
+ params: { path, query }
229
+ });
230
+ }
231
+ function getProvider(client, path) {
232
+ return client.GET("/v1/providers/{provider_id}", {
233
+ params: { path }
234
+ });
235
+ }
236
+ function getProviderSchedule(client, path) {
237
+ return client.GET("/v1/provider_schedules/{provider_schedule_id}", {
238
+ params: { path }
239
+ });
240
+ }
241
+ function getPublicAppointment(client, path) {
242
+ return client.GET("/v1/public/appointments/{appointment_id}", {
243
+ params: { path }
244
+ });
245
+ }
246
+ function getService(client, path) {
247
+ return client.GET("/v1/services/{service_id}", {
248
+ params: { path }
249
+ });
250
+ }
251
+ function listAccounts(client, query) {
252
+ return client.GET("/v1/accounts", {
253
+ params: { query }
254
+ });
255
+ }
256
+ function listAccountUsers(client) {
257
+ return client.GET("/v1/users");
258
+ }
259
+ function listAppointments(client, query) {
260
+ return client.GET("/v1/appointments", {
261
+ params: { query }
262
+ });
263
+ }
264
+ function listBlocks(client, query) {
265
+ return client.GET("/v1/blocks", {
266
+ params: { query }
267
+ });
268
+ }
269
+ function listCancellationReasons(client) {
270
+ return client.GET("/v1/cancellation_reasons");
271
+ }
272
+ function listClients(client, query) {
273
+ return client.GET("/v1/clients", {
274
+ params: { query }
275
+ });
276
+ }
277
+ function listProviders(client, query) {
278
+ return client.GET("/v1/providers", {
279
+ params: { query }
280
+ });
281
+ }
282
+ function listProviderSchedules(client, query) {
283
+ return client.GET("/v1/provider_schedules", {
284
+ params: { query }
285
+ });
286
+ }
287
+ function listPublicCancellationReasons(client, path) {
288
+ return client.GET(
289
+ "/v1/public/appointments/{appointment_id}/cancellation_reasons",
290
+ {
291
+ params: { path }
292
+ }
293
+ );
294
+ }
295
+ function listPublicServiceSlots(client, path, query) {
296
+ return client.GET("/v1/public/services/{service_id}/slots", {
297
+ params: { path, query }
298
+ });
299
+ }
300
+ function listRoles(client) {
301
+ return client.GET("/v1/roles");
302
+ }
303
+ function listServiceProviders(client, path) {
304
+ return client.GET("/v1/services/{service_id}/providers", {
305
+ params: { path }
306
+ });
307
+ }
308
+ function listServices(client, query) {
309
+ return client.GET("/v1/services", {
310
+ params: { query }
311
+ });
312
+ }
313
+ function listServiceSlots(client, path, query) {
314
+ return client.GET("/v1/services/{service_id}/slots", {
315
+ params: { path, query }
316
+ });
317
+ }
318
+ function rescheduleAppointment(client, path, body) {
319
+ return client.POST("/v1/appointments/{appointment_id}/reschedule", {
320
+ body,
321
+ params: { path }
322
+ });
323
+ }
324
+ function reschedulePublicAppointment(client, path, body) {
325
+ return client.POST("/v1/public/appointments/{appointment_id}/reschedule", {
326
+ body,
327
+ params: { path }
328
+ });
329
+ }
330
+ function updateAccount(client, path, body) {
331
+ return client.PATCH("/v1/accounts/{account_id}", {
332
+ body,
333
+ params: { path }
334
+ });
335
+ }
336
+ function updateBlock(client, path, body) {
337
+ return client.PATCH("/v1/blocks/{block_id}", {
338
+ body,
339
+ params: { path }
340
+ });
341
+ }
342
+ function updateCancellationReason(client, path, body) {
343
+ return client.PATCH("/v1/cancellation_reasons/{cancellation_reason_id}", {
344
+ body,
345
+ params: { path }
346
+ });
347
+ }
348
+ function updateClient(client, path, body) {
349
+ return client.PATCH("/v1/clients/{client_id}", {
350
+ body,
351
+ params: { path }
352
+ });
353
+ }
354
+ function updateProvider(client, path, body) {
355
+ return client.PATCH("/v1/providers/{provider_id}", {
356
+ body,
357
+ params: { path }
358
+ });
359
+ }
360
+ function updateProviderSchedule(client, path, body) {
361
+ return client.PATCH("/v1/provider_schedules/{provider_schedule_id}", {
362
+ body,
363
+ params: { path }
364
+ });
365
+ }
366
+ function updateService(client, path, body) {
367
+ return client.PATCH("/v1/services/{service_id}", {
368
+ body,
369
+ params: { path }
370
+ });
371
+ }
372
+ export {
373
+ cancelAppointment,
374
+ cancelPublicAppointment,
375
+ confirmAppointment,
376
+ createAccount,
377
+ createAccountUser,
378
+ createAppointment,
379
+ createBlock,
380
+ createCancellationReason,
381
+ createClient2 as createClient,
382
+ createDashboardSession,
383
+ createFetchClient,
384
+ createProvider,
385
+ createProviderSchedule,
386
+ createPublicAppointment,
387
+ createService,
388
+ createServiceProvider,
389
+ deactivateProvider,
390
+ deleteBlock,
391
+ deleteCancellationReason,
392
+ deleteClient,
393
+ deleteProviderSchedule,
394
+ deleteService,
395
+ deleteServiceProvider,
396
+ getAccountById,
397
+ getAppointment,
398
+ getBlock,
399
+ getCancellationReason,
400
+ getClient,
401
+ getCurrentAccount,
402
+ getCurrentAccountUser,
403
+ getCurrentPlatform,
404
+ getEarliestPublicServiceSlot,
405
+ getProvider,
406
+ getProviderSchedule,
407
+ getPublicAppointment,
408
+ getService,
409
+ listAccountUsers,
410
+ listAccounts,
411
+ listAppointments,
412
+ listBlocks,
413
+ listCancellationReasons,
414
+ listClients,
415
+ listProviderSchedules,
416
+ listProviders,
417
+ listPublicCancellationReasons,
418
+ listPublicServiceSlots,
419
+ listRoles,
420
+ listServiceProviders,
421
+ listServiceSlots,
422
+ listServices,
423
+ rescheduleAppointment,
424
+ reschedulePublicAppointment,
425
+ updateAccount,
426
+ updateBlock,
427
+ updateCancellationReason,
428
+ updateClient,
429
+ updateProvider,
430
+ updateProviderSchedule,
431
+ updateService
432
+ };
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@savvycal/appointments-core",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "JavaScript/TypeScript client library for the SavvyCal Appointments API",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "keywords": [
20
+ "savvycal",
21
+ "appointments",
22
+ "api",
23
+ "client"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/svycal/appointments.git",
28
+ "directory": "packages/core"
29
+ },
30
+ "license": "MIT",
31
+ "devDependencies": {
32
+ "@types/node": "^22.10.2",
33
+ "concurrently": "^9.2.1",
34
+ "openapi-typescript": "^7.10.1",
35
+ "tsx": "^4.19.2",
36
+ "typescript": "^5.9.3",
37
+ "vitest": "^2.1.8"
38
+ },
39
+ "dependencies": {
40
+ "openapi-fetch": "^0.15.0",
41
+ "openapi-typescript-helpers": "^0.0.15"
42
+ },
43
+ "scripts": {
44
+ "generate": "pnpm run generate:schema && concurrently \"pnpm run generate:schema-types\" \"pnpm run generate:operations\"",
45
+ "generate:schema": "openapi-typescript https://api.savvycal.app/v1/spec --output ./src/schema.d.ts",
46
+ "generate:schema-types": "tsx scripts/generate-schema-types.ts",
47
+ "generate:operations": "tsx scripts/generate-operations.ts",
48
+ "build": "tsup src/index.ts --format esm,cjs --dts",
49
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
50
+ "typecheck": "tsc --noEmit",
51
+ "test": "vitest run",
52
+ "test:watch": "vitest"
53
+ }
54
+ }