@kasuvia/sdk 0.0.2 → 0.0.5

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 (77) hide show
  1. package/dist/hooks/index.d.mts +430 -0
  2. package/dist/hooks/index.d.ts +430 -0
  3. package/dist/hooks/index.js +3073 -0
  4. package/dist/hooks/index.js.map +1 -0
  5. package/dist/hooks/index.mjs +2962 -0
  6. package/dist/hooks/index.mjs.map +1 -0
  7. package/dist/index-CxNLI4nw.d.ts +786 -0
  8. package/dist/index-CzVMyUs4.d.mts +492 -0
  9. package/dist/index-CzVMyUs4.d.ts +492 -0
  10. package/dist/index-Dowl5224.d.mts +786 -0
  11. package/dist/index.d.mts +48 -1739
  12. package/dist/index.d.ts +48 -1739
  13. package/dist/index.js +1544 -2359
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.mjs +1527 -2258
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/sdk-context-BuarJbeb.d.ts +75 -0
  18. package/dist/sdk-context-Db8kf1Tv.d.mts +75 -0
  19. package/dist/services/index.d.mts +2 -0
  20. package/dist/services/index.d.ts +2 -0
  21. package/dist/services/index.js +2369 -0
  22. package/dist/services/index.js.map +1 -0
  23. package/dist/services/index.mjs +2252 -0
  24. package/dist/services/index.mjs.map +1 -0
  25. package/package.json +11 -2
  26. package/src/config/index.ts +10 -91
  27. package/src/constants.ts +13 -0
  28. package/src/context/sdk-context.tsx +70 -0
  29. package/src/graphql/collections.graphql.ts +2 -10
  30. package/src/graphql/products.graphql.ts +215 -65
  31. package/src/graphql/wishlist.graphql.ts +7 -6
  32. package/src/hooks/index.ts +2 -0
  33. package/src/hooks/use-auth.ts +82 -158
  34. package/src/hooks/use-bespoke-availability.ts +25 -8
  35. package/src/hooks/use-cart.ts +222 -119
  36. package/src/hooks/use-cms.ts +179 -86
  37. package/src/hooks/use-collections.ts +52 -15
  38. package/src/hooks/use-consultation-stream.ts +4 -3
  39. package/src/hooks/use-consultations.ts +120 -51
  40. package/src/hooks/use-countries.ts +35 -13
  41. package/src/hooks/use-currencies.ts +26 -13
  42. package/src/hooks/use-google-translate.ts +22 -8
  43. package/src/hooks/use-languages.ts +40 -20
  44. package/src/hooks/use-mobile.ts +23 -0
  45. package/src/hooks/use-order-stream.ts +9 -5
  46. package/src/hooks/use-orders.ts +99 -44
  47. package/src/hooks/use-payment.ts +108 -40
  48. package/src/hooks/use-products.ts +251 -53
  49. package/src/hooks/use-service-booking.ts +152 -90
  50. package/src/hooks/use-states.ts +35 -15
  51. package/src/hooks/use-wishlist.ts +92 -91
  52. package/src/index.ts +26 -30
  53. package/src/services/auth.service.ts +209 -167
  54. package/src/services/bespoke.service.ts +12 -4
  55. package/src/services/cart.service.ts +172 -70
  56. package/src/services/cms.service.ts +70 -35
  57. package/src/services/collection.service.ts +22 -5
  58. package/src/services/config.service.ts +34 -14
  59. package/src/services/consultation.service.ts +72 -18
  60. package/src/services/logistics.service.ts +35 -11
  61. package/src/services/notifications.service.ts +27 -12
  62. package/src/services/order.service.ts +74 -15
  63. package/src/services/payment.service.ts +86 -31
  64. package/src/services/product.service.ts +279 -39
  65. package/src/services/service-booking.service.ts +98 -26
  66. package/src/services/wishlist.service.ts +69 -25
  67. package/src/types/auth/index.ts +6 -4
  68. package/src/types/business/index.ts +7 -2
  69. package/src/types/payments/index.ts +3 -3
  70. package/src/types/services/index.ts +2 -5
  71. package/src/types/store/index.ts +38 -3
  72. package/src/utils/error-handler.ts +10 -5
  73. package/src/utils/storage.ts +48 -26
  74. package/src/utils/validators.ts +85 -0
  75. package/src/client/authClient.ts +0 -135
  76. package/src/client/graphqlClient.ts +0 -53
  77. package/src/client/httpClient.ts +0 -298
@@ -2,23 +2,45 @@
2
2
  * Countries Hook
3
3
  *
4
4
  * React Query hook for fetching countries list.
5
+ * Stateless - requires config parameter.
5
6
  */
6
7
  import { useQuery } from '@tanstack/react-query'
7
- import { authAxios } from '../client/httpClient'
8
+ import type { SdkConfig } from '../config'
8
9
  import type { Country } from '../types/ui'
10
+ import { logger } from '../utils'
11
+ import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
9
12
 
10
- export async function getCountries(): Promise<Country[]> {
11
- const { data } = await authAxios.get<Country[]>('auth/countries/')
12
- return data
13
+ export async function getCountries(config: SdkConfig): Promise<Country[]> {
14
+ const response = await fetch(`${config.backendUrls.auth}/auth/countries/`, {
15
+ headers: {
16
+ "X-Storefront-Key": config.storefrontApiKey,
17
+ "X-Business-ID": config.businessId,
18
+ },
19
+ })
20
+ if (!response.ok) throw new Error('Failed to fetch countries')
21
+ return response.json()
13
22
  }
14
23
 
15
- export function useCountries() {
16
- return useQuery({
17
- queryKey: ['countries'],
18
- queryFn: () => getCountries(),
19
- retry: 1,
20
- refetchOnWindowFocus: false,
21
- refetchOnReconnect: false,
22
- staleTime: 24 * 60 * 60 * 1000, // 24 hours
23
- })
24
+ export function useCountries(config?: SdkConfig) {
25
+ const ctx = useSdkContext()
26
+ try {
27
+ const { config: cfg } = resolveHookArgs(config, undefined, ctx)
28
+ return useQuery({
29
+ queryKey: ['countries'],
30
+ queryFn: () => getCountries(cfg),
31
+ retry: 1,
32
+ refetchOnWindowFocus: false,
33
+ refetchOnReconnect: false,
34
+ staleTime: 24 * 60 * 60 * 1000,
35
+ })
36
+ } catch (error) {
37
+ logger.warn('[useCountries] Called outside QueryClientProvider, returning empty list')
38
+ return {
39
+ data: [],
40
+ isLoading: false,
41
+ error: null,
42
+ isFetching: false,
43
+ refetch: () => Promise.resolve({ data: [] }),
44
+ } as any
45
+ }
24
46
  }
@@ -2,26 +2,39 @@
2
2
  * Currencies Hook
3
3
  *
4
4
  * React Query hook for fetching supported currencies from the payment service.
5
- * The query is disabled until the SDK is initialized so that no request fires
6
- * before tenant credentials (businessId, storefrontApiKey) are available.
5
+ * Stateless - requires config parameter.
7
6
  */
8
7
  import { useQuery } from '@tanstack/react-query'
9
8
  import { getCacheTier } from '../utils/cache'
10
9
  import { getSupportedCurrencies } from '../services/config.service'
11
- import { isInitialized } from '../config'
10
+ import type { SdkConfig } from '../config'
12
11
  import type { Currency } from '../types/payments'
12
+ import { logger } from '../utils'
13
+ import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
13
14
 
14
- export async function getSupportedCurrenciesList(): Promise<Currency[]> {
15
- const data = await getSupportedCurrencies()
15
+ export async function getSupportedCurrenciesList(config: SdkConfig): Promise<Currency[]> {
16
+ const data = await getSupportedCurrencies(config)
16
17
  return data.currencies || []
17
18
  }
18
19
 
19
- export function useCurrencies() {
20
- return useQuery({
21
- queryKey: ['supported-currencies'],
22
- queryFn: () => getSupportedCurrenciesList(),
23
- enabled: isInitialized(),
24
- retry: 1,
25
- ...getCacheTier('high'),
26
- })
20
+ export function useCurrencies(config?: SdkConfig) {
21
+ const ctx = useSdkContext()
22
+ try {
23
+ const { config: cfg } = resolveHookArgs(config, undefined, ctx)
24
+ return useQuery({
25
+ queryKey: ['supported-currencies'],
26
+ queryFn: () => getSupportedCurrenciesList(cfg),
27
+ retry: 1,
28
+ ...getCacheTier('high'),
29
+ })
30
+ } catch (error) {
31
+ logger.warn('[useCurrencies] Called outside QueryClientProvider, returning empty list')
32
+ return {
33
+ data: [],
34
+ isLoading: false,
35
+ error: null,
36
+ isFetching: false,
37
+ refetch: () => Promise.resolve({ data: [] }),
38
+ } as any
39
+ }
27
40
  }
@@ -1,5 +1,7 @@
1
1
  import { useEffect, useCallback, useState, useRef } from "react";
2
2
  import { useSupportedLanguages } from "./use-languages";
3
+ import type { SdkConfig } from "../config";
4
+ import { useSdkContext, resolveHookArgs } from "../context/sdk-context";
3
5
 
4
6
  interface GoogleTranslateOptions {
5
7
  pageLanguage: string;
@@ -38,10 +40,22 @@ function fireChange(googleCode: string) {
38
40
  return false;
39
41
  }
40
42
 
41
- export function useGoogleTranslate(appLang: string) {
43
+ export function useGoogleTranslate(configOrLang?: SdkConfig | string, appLang?: string) {
44
+ const ctx = useSdkContext();
45
+ let cfg: SdkConfig;
46
+ let lang: string;
47
+
48
+ if (typeof configOrLang === 'string') {
49
+ lang = configOrLang;
50
+ cfg = resolveHookArgs(undefined, undefined, ctx).config;
51
+ } else {
52
+ lang = appLang ?? 'en';
53
+ cfg = resolveHookArgs(configOrLang, undefined, ctx).config;
54
+ }
55
+
42
56
  const [isLoaded, setIsLoaded] = useState(false);
43
57
  const initRef = useRef(false);
44
- const { data: supportedLangs = [] } = useSupportedLanguages();
58
+ const { data: supportedLangs = [] } = useSupportedLanguages(cfg);
45
59
 
46
60
  const clearCookies = useCallback(() => {
47
61
  if (typeof window === "undefined") return;
@@ -117,7 +131,7 @@ export function useGoogleTranslate(appLang: string) {
117
131
  // Load script only when a translation is requested
118
132
  useEffect(() => {
119
133
  if (typeof window === "undefined") return;
120
- if (appLang === "en" && !initRef.current) return;
134
+ if (lang === "en" && !initRef.current) return;
121
135
  if (initRef.current) return;
122
136
  if (supportedLangs.length === 0) return;
123
137
 
@@ -130,7 +144,7 @@ export function useGoogleTranslate(appLang: string) {
130
144
  document.body.appendChild(host);
131
145
  }
132
146
 
133
- const includedLanguages = supportedLangs.map((l) => l.code).join(",");
147
+ const includedLanguages = supportedLangs.map((l: { code: string }) => l.code).join(",");
134
148
 
135
149
  window.googleTranslateElementInit = () => {
136
150
  if (window.google?.translate?.TranslateElement) {
@@ -151,14 +165,14 @@ export function useGoogleTranslate(appLang: string) {
151
165
  } else {
152
166
  if (window.google?.translate) window.googleTranslateElementInit?.();
153
167
  }
154
- }, [appLang, supportedLangs]);
168
+ }, [lang, supportedLangs]);
155
169
 
156
170
  // Sync language changes
157
171
  useEffect(() => {
158
- if (isLoaded || (appLang === "en" && initRef.current)) {
159
- changeLanguage(appLang);
172
+ if (isLoaded || (lang === "en" && initRef.current)) {
173
+ changeLanguage(lang);
160
174
  }
161
- }, [appLang, isLoaded, changeLanguage]);
175
+ }, [lang, isLoaded, changeLanguage]);
162
176
 
163
177
  return { isLoaded };
164
178
  }
@@ -1,19 +1,13 @@
1
- /**
2
- * Languages Hook
3
- *
4
- * React Query hook for fetching supported languages from the payment service.
5
- * The query is disabled until the SDK is initialized so that no request fires
6
- * before tenant credentials (businessId, storefrontApiKey) are available.
7
- */
8
- import { useQuery } from '@tanstack/react-query'
1
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query'
9
2
  import { getCacheTier } from '../utils/cache'
10
3
  import { getSupportedLanguages } from '../services/config.service'
11
- import { isInitialized } from '../config'
4
+ import type { SdkConfig } from '../config'
12
5
  import type { BackendLanguage, SupportedLang } from '../types/payments'
6
+ import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
13
7
 
14
- export async function getSupportedLanguagesList(): Promise<SupportedLang[]> {
15
- const data = await getSupportedLanguages()
16
- return data.languages.map((language: BackendLanguage) => ({
8
+ export async function getSupportedLanguagesList(config: SdkConfig): Promise<SupportedLang[]> {
9
+ const data = await getSupportedLanguages(config)
10
+ return (data.languages || []).map((language: BackendLanguage) => ({
17
11
  code: language.code,
18
12
  appCode: language.code,
19
13
  label: language.label,
@@ -22,12 +16,38 @@ export async function getSupportedLanguagesList(): Promise<SupportedLang[]> {
22
16
  }))
23
17
  }
24
18
 
25
- export function useSupportedLanguages() {
26
- return useQuery({
27
- queryKey: ['supported-languages'],
28
- queryFn: () => getSupportedLanguagesList(),
29
- enabled: isInitialized(),
30
- retry: 1,
31
- ...getCacheTier('high'),
32
- })
19
+ export function useSupportedLanguages(config?: SdkConfig): UseQueryResult<SupportedLang[], Error> {
20
+ const ctx = useSdkContext()
21
+ try {
22
+ const { config: cfg } = resolveHookArgs(config, undefined, ctx)
23
+ return useQuery({
24
+ queryKey: ['supported-languages'],
25
+ queryFn: () => getSupportedLanguagesList(cfg),
26
+ retry: 1,
27
+ ...getCacheTier('high'),
28
+ });
29
+ } catch {
30
+ return {
31
+ data: [],
32
+ isLoading: false,
33
+ error: null,
34
+ isFetching: false,
35
+ isPending: false,
36
+ isError: false,
37
+ isSuccess: true,
38
+ status: 'success',
39
+ fetchStatus: 'idle',
40
+ refetch: async () => ({
41
+ data: [],
42
+ isLoading: false,
43
+ error: null,
44
+ isFetching: false,
45
+ isPending: false,
46
+ isError: false,
47
+ isSuccess: true,
48
+ status: 'success',
49
+ fetchStatus: 'idle',
50
+ } as unknown as UseQueryResult<SupportedLang[], Error>),
51
+ } as unknown as UseQueryResult<SupportedLang[], Error>;
52
+ }
33
53
  }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Mobile Detection Hook
3
+ *
4
+ * React hook for detecting mobile viewport using matchMedia.
5
+ * Generic utility that can be used across different storefronts.
6
+ */
7
+ import { useEffect, useState } from 'react'
8
+
9
+ const MOBILE_BREAKPOINT = 768
10
+
11
+ export function useIsMobile() {
12
+ const [isMobile, setIsMobile] = useState(false)
13
+
14
+ useEffect(() => {
15
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
16
+ const onChange = () => setIsMobile(mql.matches)
17
+ mql.addEventListener('change', onChange)
18
+ setIsMobile(mql.matches)
19
+ return () => mql.removeEventListener('change', onChange)
20
+ }, [])
21
+
22
+ return isMobile
23
+ }
@@ -2,8 +2,9 @@
2
2
 
3
3
  import { useEffect, useRef } from 'react';
4
4
  import { fetchEventSource, EventSourceMessage } from '@microsoft/fetch-event-source';
5
- import { getBackendUrl, getRuntimeConfig, isInitialized } from '../config';
5
+ import type { SdkConfig } from '../config';
6
6
  import { logger } from '../utils';
7
+ import { useSdkContext } from '../context/sdk-context';
7
8
 
8
9
  interface PaymentSuccessData {
9
10
  event: string;
@@ -71,7 +72,8 @@ interface ServiceBookingUpdateData {
71
72
  };
72
73
  }
73
74
 
74
- interface UseOrderStreamOptions {
75
+ export interface UseOrderStreamOptions {
76
+ config?: SdkConfig;
75
77
  orderId: string;
76
78
  onPaymentComplete?: (data: PaymentSuccessData) => void;
77
79
  onDigitalReady?: (data: DigitalReadyData) => void;
@@ -82,6 +84,7 @@ interface UseOrderStreamOptions {
82
84
  }
83
85
 
84
86
  export function useOrderStream({
87
+ config: explicitConfig,
85
88
  orderId,
86
89
  onPaymentComplete,
87
90
  onDigitalReady,
@@ -90,18 +93,19 @@ export function useOrderStream({
90
93
  onServiceBookingUpdate,
91
94
  onError
92
95
  }: UseOrderStreamOptions) {
96
+ const ctx = useSdkContext();
97
+ const config = explicitConfig ?? ctx?.config;
93
98
  const abortControllerRef = useRef<AbortController | null>(null);
94
99
 
95
100
  useEffect(() => {
96
- if (!orderId) {
101
+ if (!orderId || !config) {
97
102
  return;
98
103
  }
99
104
 
100
105
  const abortController = new AbortController();
101
106
  abortControllerRef.current = abortController;
102
107
 
103
- const paymentUrl = getBackendUrl('payment');
104
- const streamUrl = `${paymentUrl}/events/stream/order/${encodeURIComponent(orderId)}`;
108
+ const streamUrl = `${config.backendUrls.payment}/events/stream/order/${encodeURIComponent(orderId)}`;
105
109
 
106
110
  fetchEventSource(streamUrl, {
107
111
  method: 'GET',
@@ -1,64 +1,119 @@
1
1
  /**
2
2
  * Orders Hook
3
- *
4
- * React Query hook for order operations.
3
+ *
4
+ * React Query hooks for order operations.
5
+ * config and accessToken are optional — if omitted, they are read from SdkContext.
5
6
  */
6
7
  import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
7
8
  import { getOrders, findOrder, createOrder, cancelOrder, trackOrder } from '../services/order.service'
8
- import type { Order, FindOrderParams, CreateOrderParams } from '../types/store'
9
+ import type { FindOrderParams, CreateOrderParams } from '../types/store'
10
+ import type { SdkConfig } from '../config'
11
+ import { logger } from '../utils'
12
+ import { useSdkContext, resolveHookArgs } from '../context/sdk-context'
9
13
 
10
- export function useOrders(params?: { email?: string; page?: number; page_size?: number }) {
11
- return useQuery({
12
- queryKey: ['orders', params],
13
- queryFn: () => getOrders(params),
14
- })
15
- }
14
+ export function useOrders(arg1?: SdkConfig | { page?: number; pageSize?: number }, arg2?: string | null, arg3?: { page?: number; pageSize?: number }) {
15
+ const ctx = useSdkContext()
16
+ const isArg1Config = typeof arg1 === 'object' && arg1 !== null && 'businessId' in arg1
17
+ const explicitConfig = isArg1Config ? (arg1 as SdkConfig) : undefined
18
+ const explicitToken = isArg1Config ? arg2 : undefined
19
+ const params = isArg1Config ? arg3 : (arg1 as { page?: number; pageSize?: number } | undefined)
16
20
 
17
- // Alias for useOrders for backward compatibility
18
- export function useOrdersList(params?: { email?: string; page?: number; page_size?: number }) {
19
- return useOrders(params)
21
+ try {
22
+ const { config: cfg, accessToken: token } = resolveHookArgs(explicitConfig, explicitToken, ctx)
23
+ return useQuery({
24
+ queryKey: ['orders', params],
25
+ queryFn: () => token ? getOrders(cfg, token, params || {}) : Promise.resolve(undefined),
26
+ enabled: !!token,
27
+ })
28
+ } catch (error) {
29
+ logger.warn('[useOrders] Called outside QueryClientProvider, returning empty list')
30
+ return { data: undefined, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: undefined }) } as any
31
+ }
20
32
  }
21
33
 
22
- export function useFindOrder(params: FindOrderParams) {
23
- return useQuery({
24
- queryKey: ['order', params],
25
- queryFn: () => findOrder(params),
26
- enabled: !!params.email && !!params.order_id,
27
- })
34
+ export function useOrdersList(arg1?: any, arg2?: any, arg3?: any) {
35
+ return useOrders(arg1, arg2, arg3)
28
36
  }
29
37
 
30
- export function useOrder(params: FindOrderParams) {
31
- return useFindOrder(params)
38
+ export function useFindOrder(arg1?: SdkConfig | string | FindOrderParams, arg2?: FindOrderParams) {
39
+ const ctx = useSdkContext()
40
+ const isArg1Config = typeof arg1 === 'object' && arg1 !== null && 'businessId' in arg1
41
+ const explicitConfig = isArg1Config ? (arg1 as SdkConfig) : undefined
42
+ const params: FindOrderParams | undefined = isArg1Config
43
+ ? arg2
44
+ : typeof arg1 === 'string'
45
+ ? { order_id: arg1, email: '' }
46
+ : (arg1 as FindOrderParams | undefined)
47
+
48
+ try {
49
+ const { config: cfg } = resolveHookArgs(explicitConfig, undefined, ctx)
50
+ return useQuery({
51
+ queryKey: ['order', params],
52
+ queryFn: () => params ? findOrder(cfg, params) : Promise.resolve(undefined),
53
+ enabled: !!params?.order_id,
54
+ })
55
+ } catch (error) {
56
+ logger.warn('[useFindOrder] Called outside QueryClientProvider, returning undefined')
57
+ return { data: undefined, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: undefined }) } as any
58
+ }
32
59
  }
33
60
 
34
- export function useOrderTracking(orderId: string, token?: string) {
35
- return useQuery({
36
- queryKey: ['order-tracking', orderId, token],
37
- queryFn: () => trackOrder(orderId, token),
38
- enabled: !!orderId,
39
- refetchInterval: 30000, // Refetch every 30 seconds for tracking updates
40
- })
61
+ export function useOrder(arg1?: SdkConfig | string | FindOrderParams, arg2?: FindOrderParams) {
62
+ return useFindOrder(arg1, arg2)
41
63
  }
42
64
 
43
- export function useCreateOrder() {
44
- const queryClient = useQueryClient()
65
+ export function useOrderTracking(arg1?: SdkConfig | string, arg2?: string, arg3?: string) {
66
+ const ctx = useSdkContext()
67
+ const isArg1Config = typeof arg1 === 'object' && arg1 !== null && 'businessId' in arg1
68
+ const explicitConfig = isArg1Config ? (arg1 as SdkConfig) : undefined
69
+ const orderId = isArg1Config ? arg2 : (typeof arg1 === 'string' ? arg1 : undefined)
70
+ const guestToken = isArg1Config ? arg3 : (typeof arg2 === 'string' ? arg2 : undefined)
45
71
 
46
- return useMutation({
47
- mutationFn: createOrder,
48
- onSuccess: () => {
49
- queryClient.invalidateQueries({ queryKey: ['orders'] })
50
- },
51
- })
72
+ try {
73
+ const { config: cfg } = resolveHookArgs(explicitConfig, undefined, ctx)
74
+ return useQuery({
75
+ queryKey: ['order-tracking', orderId, guestToken],
76
+ queryFn: () => trackOrder(cfg, orderId!, guestToken),
77
+ enabled: !!orderId,
78
+ refetchInterval: 30000,
79
+ })
80
+ } catch (error) {
81
+ logger.warn('[useOrderTracking] Called outside QueryClientProvider, returning undefined')
82
+ return { data: undefined, isLoading: false, error: null, isFetching: false, refetch: () => Promise.resolve({ data: undefined }) } as any
83
+ }
52
84
  }
53
85
 
54
- export function useCancelOrder() {
55
- const queryClient = useQueryClient()
86
+ export function useCreateOrder(config?: SdkConfig, accessToken?: string | null) {
87
+ const ctx = useSdkContext()
88
+ try {
89
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx)
90
+ const queryClient = useQueryClient()
91
+ return useMutation({
92
+ mutationFn: (payload: CreateOrderParams) => createOrder(cfg, token || '', payload),
93
+ onSuccess: () => {
94
+ queryClient.invalidateQueries({ queryKey: ['orders'] })
95
+ },
96
+ })
97
+ } catch (error) {
98
+ logger.warn('[useCreateOrder] Called outside QueryClientProvider, returning no-op mutation')
99
+ return { mutate: () => {}, mutateAsync: () => Promise.resolve(undefined) } as any
100
+ }
101
+ }
56
102
 
57
- return useMutation({
58
- mutationFn: ({ orderId, reason }: { orderId: string; reason: string }) =>
59
- cancelOrder(orderId, reason),
60
- onSuccess: () => {
61
- queryClient.invalidateQueries({ queryKey: ['orders'] })
62
- },
63
- })
103
+ export function useCancelOrder(config?: SdkConfig, accessToken?: string | null) {
104
+ const ctx = useSdkContext()
105
+ try {
106
+ const { config: cfg, accessToken: token } = resolveHookArgs(config, accessToken, ctx)
107
+ const queryClient = useQueryClient()
108
+ return useMutation({
109
+ mutationFn: ({ orderId, reason = '' }: { orderId: string; reason?: string }) =>
110
+ token ? cancelOrder(cfg, token, orderId, reason) : Promise.reject('No access token'),
111
+ onSuccess: () => {
112
+ queryClient.invalidateQueries({ queryKey: ['orders'] })
113
+ },
114
+ })
115
+ } catch (error) {
116
+ logger.warn('[useCancelOrder] Called outside QueryClientProvider, returning no-op mutation')
117
+ return { mutate: () => {}, mutateAsync: () => Promise.resolve(undefined) } as any
118
+ }
64
119
  }