@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slotchain/sdk",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "TypeScript SDK for Slotly API",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
@@ -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
- slot_id?: string;
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
- // TODO: Add actual tenant properties
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
- tenantId: string;
92
- slotId?: string;
93
- customerId?: string;
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
- // TODO: Add actual booking properties
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
- tenantId: string;
111
- serviceId?: string;
112
- startTime: string;
113
- endTime: string;
114
- available: boolean;
115
- // TODO: Add actual slot properties
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)