@debugged-development/ticketapp-sdk 0.0.3 → 1.0.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 CHANGED
@@ -1,196 +1,682 @@
1
- # Basket Manager Usage Guide
1
+ # Ticketapp SDK
2
+
3
+ A TypeScript SDK for integrating Ticketapp's event ticketing and package management system into your application.
2
4
 
3
5
  ## Installation
4
6
 
5
7
  ```bash
6
- npm install @your-scope/basket-manager luxon
8
+ npm install @debugged-development/ticketapp-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { TicketappSDK } from '@ticketapp/sdk';
15
+
16
+ const sdk = new TicketappSDK({
17
+ organizationId: 'your-organization-id',
18
+ shopId: 'your-shop-id',
19
+ shopSlug: 'your-shop-slug',
20
+ debug: true, // Enable debug logging (optional)
21
+ });
7
22
  ```
8
23
 
9
- ## Setup
24
+ ## Table of Contents
25
+
26
+ - [Configuration](#configuration)
27
+ - [Events](#events)
28
+ - [Basket (Cart)](#basket-cart)
29
+ - [Packages](#packages)
30
+ - [Payment](#payment)
31
+ - [Examples](#examples)
32
+
33
+ ---
10
34
 
11
- You need to provide your GraphQL API client when initializing the BasketService:
35
+ ## Configuration
36
+
37
+ ### Basic Configuration
12
38
 
13
39
  ```typescript
14
- import { BasketService, store } from '@your-scope/basket-manager';
15
- import { ApolloClient } from '@apollo/client';
40
+ const sdk = new TicketappSDK({
41
+ organizationId: 'eed7fb11-f5c4-4467-8393-6da072b7f752',
42
+ shopId: '1fbdf73d-6ee6-438b-b8e5-a76907a6d76b',
43
+ shopSlug: 'hvrmq',
44
+ debug: true,
45
+ });
46
+ ```
16
47
 
17
- // Your GraphQL mutations (from your generated types)
18
- import {
19
- useAddToOrderMutation,
20
- useRemoveFromOrderMutation,
21
- useConfigurePackageMutation,
22
- useConfigureOrderDeliveryOptionMutation,
23
- useCreateOrderCustomerMutation,
24
- useDeleteOrderMutation,
25
- } from './order-provider.generated';
48
+ ### Advanced Configuration
26
49
 
27
- // Create API client wrapper
28
- const apiClient = {
29
- addToOrder: async (variables) => {
30
- const [mutate] = useAddToOrderMutation();
31
- return await mutate({ variables });
32
- },
33
- removeFromOrder: async (variables) => {
34
- const [mutate] = useRemoveFromOrderMutation();
35
- return await mutate({ variables });
36
- },
37
- configurePackage: async (variables) => {
38
- const [mutate] = useConfigurePackageMutation();
39
- return await mutate({ variables });
40
- },
41
- configureDeliveryOption: async (variables) => {
42
- const [mutate] = useConfigureOrderDeliveryOptionMutation();
43
- return await mutate({ variables });
44
- },
45
- createCustomer: async (variables) => {
46
- const [mutate] = useCreateOrderCustomerMutation();
47
- return await mutate({ variables });
50
+ ```typescript
51
+ const sdk = new TicketappSDK({
52
+ organizationId: 'your-organization-id',
53
+ shopId: 'your-shop-id',
54
+ shopSlug: 'your-shop-slug',
55
+ debug: true,
56
+ filteredLocationIds: ['location-id-1', 'location-id-2'], // Optional: Filter events by location
57
+ filteredHostingIds: ['host-id-1', 'host-id-2'], // Optional: Filter events by host
58
+ enableDoorTickets: true, // Optional: Include door tickets
59
+ });
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Events
65
+
66
+ ### Fetching Events
67
+
68
+ Load all available events for your organization:
69
+
70
+ ```typescript
71
+ await sdk.event.fetchEvents();
72
+ ```
73
+
74
+ ### Subscribing to Event Updates
75
+
76
+ Get real-time updates when events change:
77
+
78
+ ```typescript
79
+ const unsubscribe = sdk.event.subscribe(() => {
80
+ const state = sdk.event.getState();
81
+ console.log('Events:', state.events);
82
+ console.log('Loading:', state.processing);
83
+ console.log('Error:', state.error);
84
+ });
85
+
86
+ // Later, when you want to stop listening:
87
+ unsubscribe();
88
+ ```
89
+
90
+ ### Getting Current Event State
91
+
92
+ ```typescript
93
+ const state = sdk.event.getState();
94
+
95
+ // state structure:
96
+ {
97
+ events: Event[], // Array of events
98
+ processing: boolean, // Loading state
99
+ error: string | null, // Error message if any
100
+ loadingProducts: {} // Products loading state per event
101
+ }
102
+ ```
103
+
104
+ ### Fetching Products for an Event
105
+
106
+ ```typescript
107
+ // Fetch all ticket types
108
+ await sdk.event.fetchProductsForEvent(
109
+ 'event-id',
110
+ ['TICKET', 'DOOR', 'ADDON']
111
+ );
112
+
113
+ // Fetch only regular tickets
114
+ await sdk.event.fetchProductsForEvent(
115
+ 'event-id',
116
+ ['TICKET']
117
+ );
118
+
119
+ // Fetch with promo code
120
+ await sdk.event.fetchProductsForEvent(
121
+ 'event-id',
122
+ ['TICKET'],
123
+ 'PROMO2024'
124
+ );
125
+ ```
126
+
127
+ ### Event Object Structure
128
+
129
+ ```typescript
130
+ {
131
+ id: string,
132
+ name: string,
133
+ icon: string | null,
134
+ banner: string | null,
135
+ description: string | null,
136
+ startAt: DateTime, // Luxon DateTime object
137
+ endAt: DateTime,
138
+ timezone: string,
139
+ location: {
140
+ id: string,
141
+ name: string,
142
+ address: string | null
48
143
  },
49
- cancelOrder: async (variables) => {
50
- const [mutate] = useDeleteOrderMutation();
51
- return await mutate({ variables });
144
+ products: Product[] // Available after fetchProductsForEvent
145
+ }
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Basket (Cart)
151
+
152
+ The basket manages the user's shopping cart and order.
153
+
154
+ ### Adding a Product
155
+
156
+ ```typescript
157
+ await sdk.basket.addProduct({
158
+ id: 'product-id',
159
+ name: 'VIP Ticket',
160
+ price: 50,
161
+ serviceFee: 5,
162
+ amount: 2,
163
+ currency: 'EUR',
164
+ });
165
+ ```
166
+
167
+ ### Adding a Product with Seat Assignment
168
+
169
+ ```typescript
170
+ await sdk.basket.addProduct({
171
+ id: 'product-id',
172
+ name: 'VIP Ticket',
173
+ price: 50,
174
+ serviceFee: 5,
175
+ amount: 1,
176
+ currency: 'EUR',
177
+ seat: {
178
+ id: 'seat-a1',
179
+ label: 'A1',
180
+ holdToken: 'hold-token-123'
181
+ }
182
+ });
183
+ ```
184
+
185
+ ### Removing a Product
186
+
187
+ ```typescript
188
+ await sdk.basket.removeProduct({
189
+ id: 'product-id',
190
+ name: 'VIP Ticket',
191
+ currency: 'EUR',
192
+ amount: 1,
193
+ });
194
+ ```
195
+
196
+ ### Adding Customer Information
197
+
198
+ ```typescript
199
+ await sdk.basket.createCustomer({
200
+ email: 'customer@example.com',
201
+ firstName: 'John',
202
+ lastName: 'Doe',
203
+ age: 30, // Optional
204
+ gender: 'Male', // Optional
205
+ residence: 'Amsterdam', // Optional
206
+ extraInfo: [ // Optional: Custom key-value pairs
207
+ { key: 'dietaryRestrictions', value: 'Vegetarian' },
208
+ { key: 'tshirtSize', value: 'L' },
209
+ { key: 'emergencyContact', value: '+31612345678' }
210
+ ]
211
+ });
212
+ ```
213
+
214
+ ### Getting Current Order
215
+
216
+ ```typescript
217
+ const order = sdk.basket.getCurrentOrder();
218
+
219
+ // order structure:
220
+ {
221
+ id: string,
222
+ currency: string,
223
+ items: OrderItem[],
224
+ customer: Customer,
225
+ count: number, // Total number of items
226
+ expiredAt: string
227
+ }
228
+ ```
229
+
230
+ ### Subscribing to Basket Updates
231
+
232
+ ```typescript
233
+ const unsubscribe = sdk.basket.subscribe(() => {
234
+ const order = sdk.basket.getCurrentOrder();
235
+ console.log('Order updated:', order);
236
+ });
237
+
238
+ // Cleanup
239
+ unsubscribe();
240
+ ```
241
+
242
+ ### Canceling an Order
243
+
244
+ ```typescript
245
+ await sdk.basket.cancelOrder();
246
+ ```
247
+
248
+ ### Clearing Session
249
+
250
+ ```typescript
251
+ sdk.basket.clearOrderFromSession();
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Packages
257
+
258
+ Packages are bundled event tickets (e.g., weekend passes, season tickets).
259
+
260
+ ### Fetching Packages
261
+
262
+ ```typescript
263
+ const result = await sdk.package.getPackages();
264
+
265
+ console.log('Total packages:', result.count);
266
+ console.log('Packages:', result.data);
267
+ ```
268
+
269
+ ### Fetching Package Items
270
+
271
+ Get the individual events/items that make up a package:
272
+
273
+ ```typescript
274
+ const result = await sdk.package.getPackageItems(
275
+ 'package-id',
276
+ ['REGULAR', 'ADDITIONAL_EVENT']
277
+ );
278
+
279
+ console.log('Package items:', result.data);
280
+ ```
281
+
282
+ ### Configuring and Adding a Package to Order
283
+
284
+ ```typescript
285
+ await sdk.basket.configurePackage({
286
+ id: 'package-id',
287
+ name: 'Weekend Pass',
288
+ currency: 'EUR',
289
+ price: 200,
290
+ depositPrice: 200,
291
+ serviceFee: 20,
292
+ amount: 1, // Number of persons
293
+ items: [
294
+ {
295
+ packageItemId: 'item-1-id',
296
+ eventId: 'event-1-id',
297
+ },
298
+ {
299
+ packageItemId: 'item-2-id',
300
+ eventId: 'event-2-id',
301
+ }
302
+ ]
303
+ });
304
+ ```
305
+
306
+ ### Adding Additional Package Items
307
+
308
+ Add extra events to an existing package order:
309
+
310
+ ```typescript
311
+ const sessionId = sessionStorage.getItem('ORDER_ID_hvrmq');
312
+
313
+ await sdk.package.setAdditionalPackageItem(
314
+ sessionId,
315
+ 'package-item-id',
316
+ 'event-id',
317
+ 1 // amount
318
+ );
319
+ ```
320
+
321
+ ### Package Object Structure
322
+
323
+ ```typescript
324
+ {
325
+ id: string,
326
+ name: string,
327
+ shortDescription: string,
328
+ status: 'ACTIVE' | 'PAUSED' | 'SOLD_OUT' | 'CONCEPT',
329
+ prices: {
330
+ price: number,
331
+ discount: number | null
52
332
  },
333
+ amountOfEvents: number,
334
+ maxAmountOfPersonsPerOrder: number | null
335
+ }
336
+ ```
337
+
338
+ ---
339
+
340
+ ## Payment
341
+
342
+ ### Getting Payment Methods
343
+
344
+ Fetch available payment methods for an order:
345
+
346
+ ```typescript
347
+ const paymentDetails = await sdk.payment.getPaymentMethods({
348
+ orderId: 'order-id',
349
+ orderItemId: 'item-id', // Optional
350
+ amountOfTickets: 2, // Optional
351
+ paymentMethodId: 'method-id' // Optional
352
+ });
353
+
354
+ // paymentDetails structure:
355
+ {
356
+ transactionPrice: number,
357
+ baseTransactionFee: number | null,
358
+ additionalTransactionFee: number | null,
359
+ methods: PaymentMethod[]
360
+ }
361
+ ```
362
+
363
+ ### Payment Method Structure
364
+
365
+ ```typescript
366
+ {
367
+ id: number,
368
+ name: string,
369
+ image: string,
370
+ fee: {
371
+ type: 'FIXED' | 'PERCENTAGE',
372
+ value: number
373
+ } | null,
374
+ issuers: Array<{
375
+ id: number,
376
+ name: string,
377
+ image: string
378
+ }> | null
379
+ }
380
+ ```
381
+
382
+ ### Calculating Payment Fees
383
+
384
+ ```typescript
385
+ const paymentMethod = {
386
+ id: 1,
387
+ name: 'iDEAL',
388
+ image: 'https://...',
389
+ fee: { type: 'FIXED', value: 0.29 }
53
390
  };
54
391
 
55
- // Initialize the basket service
56
- const basketService = new BasketService({
392
+ // Calculate fee amount
393
+ const fee = sdk.payment.calculateFee(50, paymentMethod);
394
+ console.log('Fee:', fee); // 0.29
395
+
396
+ // Calculate total with fee
397
+ const total = sdk.payment.calculateTotalWithFee(50, paymentMethod);
398
+ console.log('Total:', total); // 50.29
399
+
400
+ // Format fee for display
401
+ const formatted = sdk.payment.formatFee(paymentMethod);
402
+ console.log('Fee:', formatted); // "€0.29"
403
+ ```
404
+
405
+ ### Creating a Payment
406
+
407
+ ```typescript
408
+ const response = await sdk.payment.createPayment({
409
+ orderId: 'order-id',
410
+ paymentMethodId: '1',
411
+ redirectUrl: 'https://yoursite.com/payment/return',
412
+ customer: {
413
+ firstName: 'John',
414
+ lastName: 'Doe',
415
+ email: 'john@example.com',
416
+ phone: '+31612345678',
417
+ gender: 'Male',
418
+ company: { // Optional
419
+ name: 'Company BV',
420
+ cocNumber: '12345678',
421
+ vatNumber: 'NL123456789B01'
422
+ }
423
+ },
424
+ issuerId: '1234', // Required for bank selection (iDEAL, etc.)
425
+ orderItemId: 'item-id', // Optional
426
+ amountOfTickets: 2, // Optional
427
+ });
428
+
429
+ // Open payment URL
430
+ window.open(response.paymentUrl, '_blank');
431
+ ```
432
+
433
+ ---
434
+
435
+ ## Examples
436
+
437
+ ### Complete Event Browsing Flow
438
+
439
+ ```typescript
440
+ import { TicketappSDK } from '@ticketapp/sdk';
441
+
442
+ const sdk = new TicketappSDK({
443
+ organizationId: 'your-org-id',
57
444
  shopId: 'your-shop-id',
58
445
  shopSlug: 'your-shop-slug',
59
- apiClient,
60
- });
61
- ```
62
-
63
- ## Usage in React
64
-
65
- ```typescript
66
- import { useEffect, useState } from 'react';
67
- import { store, Currency } from '@your-scope/basket-manager';
68
-
69
- function MyComponent() {
70
- const [order, setOrder] = useState(store.getState().basket.order);
71
-
72
- // Subscribe to store changes
73
- useEffect(() => {
74
- const unsubscribe = store.subscribe(() => {
75
- setOrder(store.getState().basket.order);
76
- });
77
- return unsubscribe;
78
- }, []);
79
-
80
- const handleAddProduct = async () => {
81
- await basketService.addProduct({
82
- id: 'product-123',
83
- name: 'My Product',
84
- price: 29.99,
85
- currency: Currency.EUR,
86
- amount: 1,
87
- });
88
- };
89
-
90
- return (
91
- <div>
92
- <h1>Basket</h1>
93
- {order && (
94
- <div>
95
- <p>Order ID: {order.id}</p>
96
- <p>Items: {order.items.length}</p>
97
- </div>
98
- )}
99
- <button onClick={handleAddProduct}>Add Product</button>
100
- </div>
101
- );
102
- }
446
+ });
447
+
448
+ // 1. Fetch and display events
449
+ await sdk.event.fetchEvents();
450
+ const { events } = sdk.event.getState();
451
+
452
+ // 2. Load products for selected event
453
+ await sdk.event.fetchProductsForEvent(events[0].id, ['TICKET']);
454
+
455
+ // 3. Add product to basket
456
+ await sdk.basket.addProduct({
457
+ id: events[0].products[0].id,
458
+ name: events[0].products[0].name,
459
+ price: events[0].products[0].price,
460
+ serviceFee: events[0].products[0].serviceFee,
461
+ amount: 1,
462
+ currency: 'EUR',
463
+ });
464
+
465
+ // 4. Check basket
466
+ const order = sdk.basket.getCurrentOrder();
467
+ console.log('Items in basket:', order.count);
103
468
  ```
104
469
 
105
- ## Usage in Vue
470
+ ### Complete Package Purchase Flow
106
471
 
107
472
  ```typescript
108
- import { ref, onMounted, onUnmounted } from 'vue';
109
- import { store, Currency } from '@your-scope/basket-manager';
473
+ // 1. Fetch available packages
474
+ const packagesResult = await sdk.package.getPackages();
475
+ const selectedPackage = packagesResult.data[0];
476
+
477
+ // 2. Get package items
478
+ const itemsResult = await sdk.package.getPackageItems(
479
+ selectedPackage.id,
480
+ ['REGULAR']
481
+ );
482
+
483
+ // 3. User selects events for each item
484
+ const items = itemsResult.data.map(item => ({
485
+ packageItemId: item.id,
486
+ eventId: item.activeEvents[0].id // User's selection
487
+ }));
488
+
489
+ // 4. Add package to basket
490
+ await sdk.basket.configurePackage({
491
+ id: selectedPackage.id,
492
+ name: selectedPackage.name,
493
+ currency: 'EUR',
494
+ price: selectedPackage.prices.discount ?? selectedPackage.prices.price,
495
+ depositPrice: selectedPackage.prices.discount ?? selectedPackage.prices.price,
496
+ serviceFee: 0,
497
+ amount: 1,
498
+ items: items,
499
+ });
500
+ ```
501
+
502
+ ### Complete Payment Flow
503
+
504
+ ```typescript
505
+ // 1. Get current order
506
+ const order = sdk.basket.getCurrentOrder();
507
+
508
+ // 2. Fetch payment methods
509
+ const paymentDetails = await sdk.payment.getPaymentMethods({
510
+ orderId: order.id,
511
+ });
110
512
 
111
- export default {
112
- setup() {
113
- const order = ref(store.getState().basket.order);
114
- let unsubscribe;
513
+ // 3. User selects payment method
514
+ const selectedMethod = paymentDetails.methods[0];
515
+
516
+ // 4. Calculate total with fees
517
+ const total = sdk.payment.calculateTotalWithFee(
518
+ paymentDetails.transactionPrice,
519
+ selectedMethod
520
+ );
521
+
522
+ // 5. Add customer info if not already added
523
+ await sdk.basket.createCustomer({
524
+ email: 'customer@example.com',
525
+ firstName: 'John',
526
+ lastName: 'Doe',
527
+ extraInfo: [
528
+ { key: 'phoneNumber', value: '+31612345678' }
529
+ ]
530
+ });
115
531
 
116
- onMounted(() => {
117
- unsubscribe = store.subscribe(() => {
118
- order.value = store.getState().basket.order;
119
- });
120
- });
532
+ // 6. Create payment
533
+ const paymentResponse = await sdk.payment.createPayment({
534
+ orderId: order.id,
535
+ paymentMethodId: selectedMethod.id.toString(),
536
+ redirectUrl: 'https://yoursite.com/payment/return',
537
+ customer: {
538
+ firstName: 'John',
539
+ lastName: 'Doe',
540
+ email: 'customer@example.com',
541
+ phone: '+31612345678',
542
+ },
543
+ issuerId: '1234', // If required by payment method
544
+ });
121
545
 
122
- onUnmounted(() => {
123
- if (unsubscribe) unsubscribe();
124
- });
546
+ // 7. Redirect to payment page
547
+ window.location.href = paymentResponse.paymentUrl;
548
+ ```
125
549
 
126
- const handleAddProduct = async () => {
127
- await basketService.addProduct({
128
- id: 'product-123',
129
- name: 'My Product',
130
- price: 29.99,
131
- currency: Currency.EUR,
132
- amount: 1,
133
- });
134
- };
550
+ ### Reactive UI Updates
551
+
552
+ ```typescript
553
+ // Subscribe to basket changes
554
+ const unsubscribeBasket = sdk.basket.subscribe(() => {
555
+ const order = sdk.basket.getCurrentOrder();
556
+ updateBasketIcon(order?.count || 0);
557
+ updateOrderSummary(order);
558
+ });
135
559
 
136
- return { order, handleAddProduct };
560
+ // Subscribe to event changes
561
+ const unsubscribeEvents = sdk.event.subscribe(() => {
562
+ const state = sdk.event.getState();
563
+
564
+ if (state.processing) {
565
+ showLoadingSpinner();
566
+ } else if (state.error) {
567
+ showError(state.error);
568
+ } else {
569
+ displayEvents(state.events);
137
570
  }
138
- };
571
+ });
572
+
573
+ // Cleanup when component unmounts
574
+ function cleanup() {
575
+ unsubscribeBasket();
576
+ unsubscribeEvents();
577
+ }
578
+ ```
579
+
580
+ ---
581
+
582
+ ## TypeScript Support
583
+
584
+ The SDK is written in TypeScript and exports all necessary types:
585
+
586
+ ```typescript
587
+ import {
588
+ TicketappSDK,
589
+ ProductInput,
590
+ PackageInput,
591
+ // ... other types
592
+ } from '@ticketapp/sdk';
139
593
  ```
140
594
 
141
- ## Usage in Vanilla JS
595
+ However, if you prefer to avoid importing types, you can use `any`:
142
596
 
143
597
  ```typescript
144
- import { store, basketService, Currency } from '@your-scope/basket-manager';
598
+ const productInput: any = {
599
+ id: 'product-id',
600
+ name: 'Ticket',
601
+ price: 50,
602
+ // ...
603
+ };
604
+ ```
145
605
 
146
- // Subscribe to changes
147
- store.subscribe(() => {
148
- const order = store.getState().basket.order;
149
- console.log('Order updated:', order);
150
- updateUI(order);
151
- });
152
-
153
- // Add product
154
- document.querySelector('#add-btn').addEventListener('click', async () => {
155
- await basketService.addProduct({
156
- id: 'product-123',
157
- name: 'My Product',
158
- price: 29.99,
159
- currency: Currency.EUR,
160
- amount: 1,
161
- });
162
- });
163
-
164
- function updateUI(order) {
165
- const orderElement = document.querySelector('#order-display');
166
- if (order) {
167
- orderElement.innerHTML = `
168
- <p>Order ID: ${order.id}</p>
169
- <p>Items: ${order.items.length}</p>
170
- `;
606
+ ---
607
+
608
+ ## Error Handling
609
+
610
+ All async methods can throw errors. Always wrap them in try-catch blocks:
611
+
612
+ ```typescript
613
+ try {
614
+ await sdk.basket.addProduct(productInput);
615
+ } catch (error) {
616
+ console.error('Failed to add product:', error.message);
617
+
618
+ // Handle specific GraphQL errors
619
+ if (error.response?.errors) {
620
+ const graphQLError = error.response.errors[0];
621
+ console.error('GraphQL error:', graphQLError.message);
622
+
623
+ // Check for specific error codes
624
+ if (graphQLError.extensions?.status === 'SOLD_OUT') {
625
+ alert('This product is sold out');
626
+ }
171
627
  }
172
628
  }
173
629
  ```
174
630
 
175
- ## API Methods
631
+ ---
632
+
633
+ ## Session Management
634
+
635
+ The SDK automatically manages sessions using `sessionStorage`:
636
+
637
+ - Order ID is stored as `ORDER_ID_{shopSlug}`
638
+ - Session persists across page reloads
639
+ - Use `sdk.basket.clearOrderFromSession()` to clear
640
+
641
+ ---
642
+
643
+ ## Debug Mode
644
+
645
+ Enable debug mode to see detailed logs:
646
+
647
+ ```typescript
648
+ const sdk = new TicketappSDK({
649
+ organizationId: 'your-org-id',
650
+ shopId: 'your-shop-id',
651
+ shopSlug: 'your-shop-slug',
652
+ debug: true, // Enable logging
653
+ });
654
+ ```
655
+
656
+ Debug logs will appear in the browser console with prefixes like:
657
+ - `[EventService]`
658
+ - `[BasketService]`
659
+ - `[PackageService]`
660
+ - `[PaymentService]`
661
+
662
+ ---
663
+
664
+ ## Browser Support
176
665
 
177
- ### `addProduct(input: ProductInput)`
178
- Add a product to the basket.
666
+ The SDK works in all modern browsers that support:
667
+ - ES6+
668
+ - Fetch API
669
+ - sessionStorage
670
+ - Promise
179
671
 
180
- ### `removeProduct(input: ProductInput)`
181
- Remove a product from the basket.
672
+ ---
182
673
 
183
- ### `configurePackage(input: PackageInput)`
184
- Configure a package in the basket.
674
+ ## License
185
675
 
186
- ### `configureDeliveryOption(input?: DeliveryInput)`
187
- Set or remove delivery option.
676
+ MIT
188
677
 
189
- ### `createCustomer(input: CreateCustomerInput)`
190
- Add customer information to the order.
678
+ ---
191
679
 
192
- ### `cancelOrder()`
193
- Cancel the current order.
680
+ ## Support
194
681
 
195
- ### `clearOrderFromSession()`
196
- Clear the order from session storage and state.
682
+ For issues, questions, or feature requests, please contact support or open an issue on GitHub.