@slotchain/sdk 1.1.0 → 1.1.2
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 +47 -0
- package/dist/index.cjs.js +145 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.mts +204 -17
- package/dist/index.d.ts +204 -17
- package/dist/index.esm.js +145 -2
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/clients/booking-client.ts +87 -10
- package/src/clients/organization-client.ts +83 -0
- package/src/index.ts +8 -0
- package/src/types/api.ts +94 -11
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AxiosInstance } from 'axios';
|
|
2
|
-
import { ApiResponse, Booking } from '../types/api';
|
|
2
|
+
import { ApiResponse, Booking, BookingWithSlot, ListBookingsOptions } from '../types/api';
|
|
3
3
|
|
|
4
4
|
export class BookingClient {
|
|
5
5
|
constructor(private client: AxiosInstance) {}
|
|
@@ -16,23 +16,100 @@ export class BookingClient {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* List bookings
|
|
19
|
+
* List bookings with enhanced filtering
|
|
20
20
|
* GET /api/v1/bookings
|
|
21
|
+
*
|
|
22
|
+
* Supports filtering by tenant_id, slot_id, customer_id, status, and optional nested slot information.
|
|
23
|
+
*
|
|
24
|
+
* @param params - Query options (tenant_id, slot_id, customer_id, status, includeSlot, page, limit)
|
|
25
|
+
* @returns Bookings or BookingsWithSlot based on includeSlot parameter
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* // List bookings by tenant (single query - fast!)
|
|
30
|
+
* const bookings = await slotly.booking.list({
|
|
31
|
+
* tenant_id: 'tenant-123',
|
|
32
|
+
* includeSlot: true,
|
|
33
|
+
* page: 1,
|
|
34
|
+
* limit: 20
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* // List bookings by slot
|
|
38
|
+
* const slotBookings = await slotly.booking.list({
|
|
39
|
+
* slot_id: 'slot-456',
|
|
40
|
+
* status: 'confirmed'
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
21
43
|
*/
|
|
22
|
-
async list(params?: {
|
|
23
|
-
|
|
24
|
-
customer_id?: string;
|
|
25
|
-
status?: string;
|
|
26
|
-
page?: number;
|
|
27
|
-
limit?: number;
|
|
28
|
-
}): Promise<ApiResponse<Booking[]>> {
|
|
29
|
-
const response = await this.client.get<ApiResponse<Booking[]>>(
|
|
44
|
+
async list(params?: ListBookingsOptions): Promise<ApiResponse<Booking[] | BookingWithSlot[]>> {
|
|
45
|
+
const response = await this.client.get<ApiResponse<Booking[] | BookingWithSlot[]>>(
|
|
30
46
|
'/api/v1/bookings',
|
|
31
47
|
{ params }
|
|
32
48
|
);
|
|
33
49
|
return response.data;
|
|
34
50
|
}
|
|
35
51
|
|
|
52
|
+
/**
|
|
53
|
+
* List bookings by tenant (convenience method)
|
|
54
|
+
* GET /api/v1/bookings?tenant_id=:id
|
|
55
|
+
*
|
|
56
|
+
* @param tenantId - Tenant ID
|
|
57
|
+
* @param options - Additional options (includeSlot, page, limit, status)
|
|
58
|
+
* @returns Bookings or BookingsWithSlot based on includeSlot parameter
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const bookings = await slotly.booking.listByTenant('tenant-123', {
|
|
63
|
+
* page: 1,
|
|
64
|
+
* limit: 20,
|
|
65
|
+
* status: 'confirmed'
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
async listByTenant(
|
|
70
|
+
tenantId: string,
|
|
71
|
+
options?: Omit<ListBookingsOptions, 'tenant_id'>
|
|
72
|
+
): Promise<ApiResponse<Booking[] | BookingWithSlot[]>> {
|
|
73
|
+
return this.list({
|
|
74
|
+
tenant_id: tenantId,
|
|
75
|
+
...options,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* List bookings by tenant with nested slot information (convenience method)
|
|
81
|
+
* GET /api/v1/bookings?tenant_id=:id&includeSlot=true
|
|
82
|
+
*
|
|
83
|
+
* @param tenantId - Tenant ID
|
|
84
|
+
* @param options - Additional options (page, limit, status)
|
|
85
|
+
* @returns BookingsWithSlot (includes nested slot information)
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const bookings = await slotly.booking.listByTenantWithSlots('tenant-123', {
|
|
90
|
+
* page: 1,
|
|
91
|
+
* limit: 20
|
|
92
|
+
* });
|
|
93
|
+
*
|
|
94
|
+
* // Access slot information
|
|
95
|
+
* bookings.data.forEach(booking => {
|
|
96
|
+
* if (booking.slots) {
|
|
97
|
+
* console.log('Slot name:', booking.slots.name);
|
|
98
|
+
* }
|
|
99
|
+
* });
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
async listByTenantWithSlots(
|
|
103
|
+
tenantId: string,
|
|
104
|
+
options?: Omit<ListBookingsOptions, 'tenant_id' | 'includeSlot'>
|
|
105
|
+
): Promise<ApiResponse<BookingWithSlot[]>> {
|
|
106
|
+
return this.list({
|
|
107
|
+
tenant_id: tenantId,
|
|
108
|
+
includeSlot: true,
|
|
109
|
+
...options,
|
|
110
|
+
}) as Promise<ApiResponse<BookingWithSlot[]>>;
|
|
111
|
+
}
|
|
112
|
+
|
|
36
113
|
/**
|
|
37
114
|
* Create a new booking (publishes booking.created event)
|
|
38
115
|
* POST /api/v1/bookings
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { AxiosInstance } from 'axios';
|
|
2
|
+
import { ApiResponse, Organization, OrganizationFullConfig, GetOrganizationOptions } from '../types/api';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* OrganizationClient provides methods for managing organizations
|
|
6
|
+
*/
|
|
7
|
+
export class OrganizationClient {
|
|
8
|
+
constructor(private client: AxiosInstance) {}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get organization by ID or slug
|
|
12
|
+
* GET /api/v1/organizations/:id
|
|
13
|
+
*
|
|
14
|
+
* @param identifier - Organization ID or slug
|
|
15
|
+
* @param options - Query options (includeTenants, page, limit, is_public)
|
|
16
|
+
* @returns Organization or OrganizationFullConfig (with nested tenants if includeTenants=true)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Get organization only
|
|
21
|
+
* const org = await slotly.organization.getById('org-123');
|
|
22
|
+
*
|
|
23
|
+
* // Get organization with tenants
|
|
24
|
+
* const orgWithTenants = await slotly.organization.getById('org-123', {
|
|
25
|
+
* includeTenants: true,
|
|
26
|
+
* page: 1,
|
|
27
|
+
* limit: 10,
|
|
28
|
+
* is_public: true
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
async getById(
|
|
33
|
+
identifier: string,
|
|
34
|
+
options?: GetOrganizationOptions
|
|
35
|
+
): Promise<ApiResponse<Organization | OrganizationFullConfig>> {
|
|
36
|
+
const params: Record<string, any> = {};
|
|
37
|
+
|
|
38
|
+
if (options?.includeTenants) {
|
|
39
|
+
params.includeTenants = 'true';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (options?.page !== undefined) {
|
|
43
|
+
params.page = options.page;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (options?.limit !== undefined) {
|
|
47
|
+
params.limit = options.limit;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (options?.is_public !== undefined) {
|
|
51
|
+
params.is_public = options.is_public;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const response = await this.client.get<ApiResponse<Organization | OrganizationFullConfig>>(
|
|
55
|
+
`/api/v1/organizations/${identifier}`,
|
|
56
|
+
{ params }
|
|
57
|
+
);
|
|
58
|
+
return response.data;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get organization by slug (alias for getById)
|
|
63
|
+
* GET /api/v1/organizations/:slug
|
|
64
|
+
*
|
|
65
|
+
* @param slug - Organization slug
|
|
66
|
+
* @param options - Query options (includeTenants, page, limit, is_public)
|
|
67
|
+
* @returns Organization or OrganizationFullConfig (with nested tenants if includeTenants=true)
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const org = await slotly.organization.getBySlug('acme-corp', {
|
|
72
|
+
* includeTenants: true
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
async getBySlug(
|
|
77
|
+
slug: string,
|
|
78
|
+
options?: GetOrganizationOptions
|
|
79
|
+
): Promise<ApiResponse<Organization | OrganizationFullConfig>> {
|
|
80
|
+
return this.getById(slug, options);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { FlowClient } from './clients/flow-client';
|
|
|
9
9
|
import { StudioClient } from './clients/studio-client';
|
|
10
10
|
import { NotificationClient } from './clients/notification-client';
|
|
11
11
|
import { DataQualityClient } from './clients/data-quality-client';
|
|
12
|
+
import { OrganizationClient } from './clients/organization-client';
|
|
12
13
|
import { setupRequestInterceptor, setupResponseInterceptor, setupErrorInterceptor } from './interceptors';
|
|
13
14
|
import { setupRetryInterceptor } from './retry';
|
|
14
15
|
import { SlotlyConfigurationError } from './errors';
|
|
@@ -20,6 +21,8 @@ export type {
|
|
|
20
21
|
TenantFullConfig,
|
|
21
22
|
TenantBranding,
|
|
22
23
|
Booking,
|
|
24
|
+
BookingWithSlot,
|
|
25
|
+
ListBookingsOptions,
|
|
23
26
|
Service,
|
|
24
27
|
ServiceItem,
|
|
25
28
|
ServiceWithItems,
|
|
@@ -32,6 +35,9 @@ export type {
|
|
|
32
35
|
Studio,
|
|
33
36
|
Notification,
|
|
34
37
|
DataQualityIssue,
|
|
38
|
+
Organization,
|
|
39
|
+
OrganizationFullConfig,
|
|
40
|
+
GetOrganizationOptions,
|
|
35
41
|
} from './types/api';
|
|
36
42
|
|
|
37
43
|
// Re-export errors
|
|
@@ -97,6 +103,7 @@ export interface SlotlyApi {
|
|
|
97
103
|
studio: StudioClient;
|
|
98
104
|
notification: NotificationClient;
|
|
99
105
|
dataQuality: DataQualityClient;
|
|
106
|
+
organization: OrganizationClient;
|
|
100
107
|
}
|
|
101
108
|
|
|
102
109
|
const defaultBaseURL = typeof process !== 'undefined' && process.env?.SLOTLY_API_URL
|
|
@@ -289,6 +296,7 @@ export const useSlotly = (options: SlotlyClientOptions): SlotlyApi => {
|
|
|
289
296
|
studio: new StudioClient(client),
|
|
290
297
|
notification: new NotificationClient(client),
|
|
291
298
|
dataQuality: new DataQualityClient(client),
|
|
299
|
+
organization: new OrganizationClient(client),
|
|
292
300
|
};
|
|
293
301
|
};
|
|
294
302
|
|
package/src/types/api.ts
CHANGED
|
@@ -26,7 +26,20 @@ export interface Tenant {
|
|
|
26
26
|
id: string;
|
|
27
27
|
slug: string;
|
|
28
28
|
name: string;
|
|
29
|
-
|
|
29
|
+
primary_domain?: string;
|
|
30
|
+
subdomain?: string;
|
|
31
|
+
custom_domains?: string[];
|
|
32
|
+
branding?: {
|
|
33
|
+
logo?: string;
|
|
34
|
+
colors?: {
|
|
35
|
+
primary?: string;
|
|
36
|
+
secondary?: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
is_public?: boolean;
|
|
40
|
+
metadata?: Record<string, unknown>;
|
|
41
|
+
created_at: string;
|
|
42
|
+
updated_at: string;
|
|
30
43
|
}
|
|
31
44
|
|
|
32
45
|
/**
|
|
@@ -88,11 +101,49 @@ export interface Category {
|
|
|
88
101
|
|
|
89
102
|
export interface Booking {
|
|
90
103
|
id: string;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
slot_id: string;
|
|
105
|
+
customer_id?: string;
|
|
106
|
+
customer_info: {
|
|
107
|
+
name: string;
|
|
108
|
+
email: string;
|
|
109
|
+
phone?: string;
|
|
110
|
+
address?: string;
|
|
111
|
+
city?: string;
|
|
112
|
+
state?: string;
|
|
113
|
+
zipCode?: string;
|
|
114
|
+
isGuestCheckout?: boolean;
|
|
115
|
+
};
|
|
116
|
+
booking_data: {
|
|
117
|
+
services?: string[];
|
|
118
|
+
selected_services?: string[];
|
|
119
|
+
service_items?: string[];
|
|
120
|
+
total?: number;
|
|
121
|
+
delivery_type?: string;
|
|
122
|
+
[key: string]: unknown;
|
|
123
|
+
};
|
|
94
124
|
status?: string;
|
|
95
|
-
|
|
125
|
+
created_at: string;
|
|
126
|
+
updated_at: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Booking with nested slot information
|
|
131
|
+
*/
|
|
132
|
+
export interface BookingWithSlot extends Booking {
|
|
133
|
+
slots?: Slot;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Options for listing bookings
|
|
138
|
+
*/
|
|
139
|
+
export interface ListBookingsOptions {
|
|
140
|
+
tenant_id?: string;
|
|
141
|
+
slot_id?: string;
|
|
142
|
+
customer_id?: string;
|
|
143
|
+
status?: string;
|
|
144
|
+
includeSlot?: boolean;
|
|
145
|
+
page?: number;
|
|
146
|
+
limit?: number;
|
|
96
147
|
}
|
|
97
148
|
|
|
98
149
|
export interface Service {
|
|
@@ -107,12 +158,13 @@ export interface Service {
|
|
|
107
158
|
|
|
108
159
|
export interface Slot {
|
|
109
160
|
id: string;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
161
|
+
tenant_id: string;
|
|
162
|
+
name: string;
|
|
163
|
+
description?: string;
|
|
164
|
+
status?: string;
|
|
165
|
+
is_active?: boolean;
|
|
166
|
+
created_at: string;
|
|
167
|
+
updated_at: string;
|
|
116
168
|
}
|
|
117
169
|
|
|
118
170
|
export interface Customer {
|
|
@@ -166,6 +218,37 @@ export interface DataQualityIssue {
|
|
|
166
218
|
// TODO: Add actual data quality issue properties
|
|
167
219
|
}
|
|
168
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Organization type
|
|
223
|
+
*/
|
|
224
|
+
export interface Organization {
|
|
225
|
+
id: string;
|
|
226
|
+
slug?: string;
|
|
227
|
+
name: string;
|
|
228
|
+
description?: string;
|
|
229
|
+
metadata?: Record<string, unknown>;
|
|
230
|
+
tenant_slugs?: string[];
|
|
231
|
+
created_at: string;
|
|
232
|
+
updated_at: string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Organization with nested tenants
|
|
237
|
+
*/
|
|
238
|
+
export interface OrganizationFullConfig extends Organization {
|
|
239
|
+
tenants: Tenant[];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Options for getting organization
|
|
244
|
+
*/
|
|
245
|
+
export interface GetOrganizationOptions {
|
|
246
|
+
includeTenants?: boolean;
|
|
247
|
+
page?: number;
|
|
248
|
+
limit?: number;
|
|
249
|
+
is_public?: boolean;
|
|
250
|
+
}
|
|
251
|
+
|
|
169
252
|
/**
|
|
170
253
|
* Full tenant configuration including branding, services, and service items
|
|
171
254
|
* Service items are nested within each service object (not as a separate top-level array)
|