@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.
- package/dist/hooks/index.d.mts +430 -0
- package/dist/hooks/index.d.ts +430 -0
- package/dist/hooks/index.js +3073 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/index.mjs +2962 -0
- package/dist/hooks/index.mjs.map +1 -0
- package/dist/index-CxNLI4nw.d.ts +786 -0
- package/dist/index-CzVMyUs4.d.mts +492 -0
- package/dist/index-CzVMyUs4.d.ts +492 -0
- package/dist/index-Dowl5224.d.mts +786 -0
- package/dist/index.d.mts +48 -1739
- package/dist/index.d.ts +48 -1739
- package/dist/index.js +1544 -2359
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1527 -2258
- package/dist/index.mjs.map +1 -1
- package/dist/sdk-context-BuarJbeb.d.ts +75 -0
- package/dist/sdk-context-Db8kf1Tv.d.mts +75 -0
- package/dist/services/index.d.mts +2 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.js +2369 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/index.mjs +2252 -0
- package/dist/services/index.mjs.map +1 -0
- package/package.json +11 -2
- package/src/config/index.ts +10 -91
- package/src/constants.ts +13 -0
- package/src/context/sdk-context.tsx +70 -0
- package/src/graphql/collections.graphql.ts +2 -10
- package/src/graphql/products.graphql.ts +215 -65
- package/src/graphql/wishlist.graphql.ts +7 -6
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use-auth.ts +82 -158
- package/src/hooks/use-bespoke-availability.ts +25 -8
- package/src/hooks/use-cart.ts +222 -119
- package/src/hooks/use-cms.ts +179 -86
- package/src/hooks/use-collections.ts +52 -15
- package/src/hooks/use-consultation-stream.ts +4 -3
- package/src/hooks/use-consultations.ts +120 -51
- package/src/hooks/use-countries.ts +35 -13
- package/src/hooks/use-currencies.ts +26 -13
- package/src/hooks/use-google-translate.ts +22 -8
- package/src/hooks/use-languages.ts +40 -20
- package/src/hooks/use-mobile.ts +23 -0
- package/src/hooks/use-order-stream.ts +9 -5
- package/src/hooks/use-orders.ts +99 -44
- package/src/hooks/use-payment.ts +108 -40
- package/src/hooks/use-products.ts +251 -53
- package/src/hooks/use-service-booking.ts +152 -90
- package/src/hooks/use-states.ts +35 -15
- package/src/hooks/use-wishlist.ts +92 -91
- package/src/index.ts +26 -30
- package/src/services/auth.service.ts +209 -167
- package/src/services/bespoke.service.ts +12 -4
- package/src/services/cart.service.ts +172 -70
- package/src/services/cms.service.ts +70 -35
- package/src/services/collection.service.ts +22 -5
- package/src/services/config.service.ts +34 -14
- package/src/services/consultation.service.ts +72 -18
- package/src/services/logistics.service.ts +35 -11
- package/src/services/notifications.service.ts +27 -12
- package/src/services/order.service.ts +74 -15
- package/src/services/payment.service.ts +86 -31
- package/src/services/product.service.ts +279 -39
- package/src/services/service-booking.service.ts +98 -26
- package/src/services/wishlist.service.ts +69 -25
- package/src/types/auth/index.ts +6 -4
- package/src/types/business/index.ts +7 -2
- package/src/types/payments/index.ts +3 -3
- package/src/types/services/index.ts +2 -5
- package/src/types/store/index.ts +38 -3
- package/src/utils/error-handler.ts +10 -5
- package/src/utils/storage.ts +48 -26
- package/src/utils/validators.ts +85 -0
- package/src/client/authClient.ts +0 -135
- package/src/client/graphqlClient.ts +0 -53
- package/src/client/httpClient.ts +0 -298
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Consultation Service
|
|
3
3
|
*
|
|
4
4
|
* Handles consultation operations for bespoke and service products.
|
|
5
|
+
* Stateless - all configuration passed as parameters.
|
|
5
6
|
*/
|
|
6
|
-
import {
|
|
7
|
+
import type { SdkConfig } from '../config'
|
|
7
8
|
import type {
|
|
8
9
|
Consultation,
|
|
9
10
|
ConsultationCreatePayload,
|
|
@@ -11,33 +12,86 @@ import type {
|
|
|
11
12
|
ConsultationQuoteAcceptPayload,
|
|
12
13
|
} from '../types/consultations'
|
|
13
14
|
|
|
14
|
-
export async function createConsultation(payload: ConsultationCreatePayload): Promise<Consultation> {
|
|
15
|
-
const
|
|
16
|
-
|
|
15
|
+
export async function createConsultation(config: SdkConfig, accessToken: string, payload: ConsultationCreatePayload): Promise<Consultation> {
|
|
16
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
|
|
17
|
+
method: 'POST',
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
21
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
22
|
+
"X-Business-ID": config.businessId,
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify(payload),
|
|
25
|
+
})
|
|
26
|
+
if (!response.ok) throw new Error('Failed to create consultation')
|
|
27
|
+
return response.json()
|
|
17
28
|
}
|
|
18
29
|
|
|
19
|
-
export async function getConsultations(): Promise<Consultation[]> {
|
|
20
|
-
const
|
|
21
|
-
|
|
30
|
+
export async function getConsultations(config: SdkConfig, accessToken: string): Promise<Consultation[]> {
|
|
31
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
|
|
32
|
+
headers: {
|
|
33
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
34
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
35
|
+
"X-Business-ID": config.businessId,
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
if (!response.ok) throw new Error('Failed to get consultations')
|
|
39
|
+
return response.json()
|
|
22
40
|
}
|
|
23
41
|
|
|
24
|
-
export async function getConsultation(id: string): Promise<Consultation> {
|
|
25
|
-
const
|
|
26
|
-
|
|
42
|
+
export async function getConsultation(config: SdkConfig, accessToken: string, id: string): Promise<Consultation> {
|
|
43
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}`, {
|
|
44
|
+
headers: {
|
|
45
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
46
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
47
|
+
"X-Business-ID": config.businessId,
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
if (!response.ok) throw new Error('Failed to get consultation')
|
|
51
|
+
return response.json()
|
|
27
52
|
}
|
|
28
53
|
|
|
29
|
-
export async function sendMessage(id: string, payload: ConsultationMessagePayload): Promise<void> {
|
|
30
|
-
await
|
|
54
|
+
export async function sendMessage(config: SdkConfig, accessToken: string, id: string, payload: ConsultationMessagePayload): Promise<void> {
|
|
55
|
+
await fetch(`${config.backendUrls.store}/social/consultations/${id}/messages`, {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
headers: {
|
|
58
|
+
'Content-Type': 'application/json',
|
|
59
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
60
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
61
|
+
"X-Business-ID": config.businessId,
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify(payload),
|
|
64
|
+
})
|
|
31
65
|
}
|
|
32
66
|
|
|
33
|
-
export async function acceptQuote(id: string, payload: ConsultationQuoteAcceptPayload): Promise<Consultation> {
|
|
34
|
-
const
|
|
35
|
-
|
|
67
|
+
export async function acceptQuote(config: SdkConfig, accessToken: string, id: string, payload: ConsultationQuoteAcceptPayload): Promise<Consultation> {
|
|
68
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/accept-quote`, {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
headers: {
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
73
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
74
|
+
"X-Business-ID": config.businessId,
|
|
75
|
+
},
|
|
76
|
+
body: JSON.stringify(payload),
|
|
77
|
+
})
|
|
78
|
+
if (!response.ok) throw new Error('Failed to accept quote')
|
|
79
|
+
return response.json()
|
|
36
80
|
}
|
|
37
81
|
|
|
38
|
-
export async function rejectQuote(id: string, reason?: string): Promise<Consultation> {
|
|
39
|
-
const
|
|
40
|
-
|
|
82
|
+
export async function rejectQuote(config: SdkConfig, accessToken: string, id: string, reason?: string): Promise<Consultation> {
|
|
83
|
+
const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/reject-quote`, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers: {
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
88
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
89
|
+
"X-Business-ID": config.businessId,
|
|
90
|
+
},
|
|
91
|
+
body: JSON.stringify({ reason }),
|
|
92
|
+
})
|
|
93
|
+
if (!response.ok) throw new Error('Failed to reject quote')
|
|
94
|
+
return response.json()
|
|
41
95
|
}
|
|
42
96
|
|
|
43
97
|
// Service object export for backward compatibility
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Logistics Service
|
|
3
3
|
*
|
|
4
4
|
* Handles shipping rates and address validation.
|
|
5
|
+
* Stateless - all configuration passed as parameters.
|
|
5
6
|
*/
|
|
6
|
-
import {
|
|
7
|
+
import type { SdkConfig } from '../config'
|
|
7
8
|
import type { ShippingRatesResponse } from '../types/store/shipping'
|
|
8
9
|
import type { Product, ProductVariant } from '../types/store'
|
|
9
10
|
|
|
@@ -34,19 +35,26 @@ export interface ShippingRatesRequest {
|
|
|
34
35
|
* Fetch shipping rates for a cart.
|
|
35
36
|
*/
|
|
36
37
|
export async function getShippingRates(
|
|
38
|
+
config: SdkConfig,
|
|
37
39
|
payload: ShippingRatesRequest
|
|
38
40
|
): Promise<ShippingRatesResponse> {
|
|
39
|
-
const
|
|
40
|
-
'
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
const response = await fetch(`${config.backendUrls.store}/logistics/shipping/rates`, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: {
|
|
44
|
+
'Content-Type': 'application/json',
|
|
45
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
46
|
+
"X-Business-ID": config.businessId,
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify(payload),
|
|
49
|
+
})
|
|
50
|
+
if (!response.ok) throw new Error('Failed to get shipping rates')
|
|
51
|
+
return response.json()
|
|
44
52
|
}
|
|
45
53
|
|
|
46
54
|
/**
|
|
47
55
|
* Fetch the seller's registered shipping address.
|
|
48
56
|
*/
|
|
49
|
-
export async function getSellerShippingAddress(): Promise<{
|
|
57
|
+
export async function getSellerShippingAddress(config: SdkConfig): Promise<{
|
|
50
58
|
terminal_address_id: string | null
|
|
51
59
|
address_details: {
|
|
52
60
|
city: string
|
|
@@ -59,14 +67,21 @@ export async function getSellerShippingAddress(): Promise<{
|
|
|
59
67
|
business_id: string
|
|
60
68
|
message: string
|
|
61
69
|
}> {
|
|
62
|
-
const
|
|
63
|
-
|
|
70
|
+
const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address`, {
|
|
71
|
+
headers: {
|
|
72
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
73
|
+
"X-Business-ID": config.businessId,
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
if (!response.ok) throw new Error('Failed to get seller shipping address')
|
|
77
|
+
return response.json()
|
|
64
78
|
}
|
|
65
79
|
|
|
66
80
|
/**
|
|
67
81
|
* Validate a shipping address.
|
|
68
82
|
*/
|
|
69
83
|
export async function validateShippingAddress(
|
|
84
|
+
config: SdkConfig,
|
|
70
85
|
payload: {
|
|
71
86
|
first_name: string
|
|
72
87
|
last_name: string
|
|
@@ -83,8 +98,17 @@ export async function validateShippingAddress(
|
|
|
83
98
|
message?: string
|
|
84
99
|
data?: Array<{ name: string; city_id: string; stateCode: string; countryCode: string }>
|
|
85
100
|
}> {
|
|
86
|
-
const
|
|
87
|
-
|
|
101
|
+
const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address/validate`, {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'application/json',
|
|
105
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
106
|
+
"X-Business-ID": config.businessId,
|
|
107
|
+
},
|
|
108
|
+
body: JSON.stringify(payload),
|
|
109
|
+
})
|
|
110
|
+
if (!response.ok) throw new Error('Failed to validate shipping address')
|
|
111
|
+
return response.json()
|
|
88
112
|
}
|
|
89
113
|
|
|
90
114
|
// Service object for backward compatibility
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Notification Service
|
|
3
3
|
*
|
|
4
4
|
* Handles contact form submissions and email notifications.
|
|
5
|
+
* Stateless - all configuration passed as parameters.
|
|
5
6
|
*/
|
|
6
|
-
import {
|
|
7
|
+
import type { SdkConfig } from '../config'
|
|
7
8
|
|
|
8
9
|
export interface ContactFormData {
|
|
9
10
|
name: string
|
|
@@ -17,17 +18,24 @@ export interface ContactFormData {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
|
-
* Send contact email to
|
|
21
|
+
* Send contact email to Kasuvia team.
|
|
21
22
|
* POST /contact/send-contact-email
|
|
22
23
|
*/
|
|
23
24
|
export async function sendContactEmail(
|
|
25
|
+
config: SdkConfig,
|
|
24
26
|
payload: ContactFormData
|
|
25
27
|
): Promise<{ detail: string }> {
|
|
26
|
-
const
|
|
27
|
-
'
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-email`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
33
|
+
"X-Business-ID": config.businessId,
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(payload),
|
|
36
|
+
})
|
|
37
|
+
if (!response.ok) throw new Error('Failed to send contact email')
|
|
38
|
+
return response.json()
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
/**
|
|
@@ -35,13 +43,20 @@ export async function sendContactEmail(
|
|
|
35
43
|
* POST /contact/send-contact-confirmation
|
|
36
44
|
*/
|
|
37
45
|
export async function sendContactConfirmation(
|
|
46
|
+
config: SdkConfig,
|
|
38
47
|
payload: Omit<ContactFormData, 'turnstile_token'>
|
|
39
48
|
): Promise<{ detail: string }> {
|
|
40
|
-
const
|
|
41
|
-
'
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-confirmation`, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
54
|
+
"X-Business-ID": config.businessId,
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify(payload),
|
|
57
|
+
})
|
|
58
|
+
if (!response.ok) throw new Error('Failed to send contact confirmation')
|
|
59
|
+
return response.json()
|
|
45
60
|
}
|
|
46
61
|
|
|
47
62
|
export const notificationsService = {
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Order Service
|
|
3
3
|
*
|
|
4
4
|
* Handles order operations including creation, lookup, and tracking.
|
|
5
|
+
* Stateless - all configuration passed as parameters.
|
|
5
6
|
*/
|
|
6
|
-
import {
|
|
7
|
+
import type { SdkConfig } from '../config'
|
|
7
8
|
import type { Order, OrderStatus, FindOrderParams, CreateOrderParams, OrderItem } from '../types/store'
|
|
8
9
|
import type { DeliveryAddress } from '../types/store'
|
|
9
10
|
|
|
@@ -133,37 +134,95 @@ function normaliseStorefrontOrder(raw: RawOrder): Order {
|
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
export async function createOrder(payload: CreateOrderParams): Promise<Order> {
|
|
137
|
-
const
|
|
137
|
+
export async function createOrder(config: SdkConfig, accessToken: string, payload: CreateOrderParams): Promise<Order> {
|
|
138
|
+
const response = await fetch(`${config.backendUrls.store}/orders/storefront`, {
|
|
139
|
+
method: 'POST',
|
|
140
|
+
headers: {
|
|
141
|
+
'Content-Type': 'application/json',
|
|
142
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
143
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
144
|
+
"X-Business-ID": config.businessId,
|
|
145
|
+
},
|
|
146
|
+
body: JSON.stringify(payload),
|
|
147
|
+
})
|
|
148
|
+
if (!response.ok) throw new Error('Failed to create order')
|
|
149
|
+
const data = await response.json()
|
|
138
150
|
return normaliseStorefrontOrder(data)
|
|
139
151
|
}
|
|
140
152
|
|
|
141
|
-
export async function findOrder(params: FindOrderParams): Promise<Order> {
|
|
142
|
-
const
|
|
153
|
+
export async function findOrder(config: SdkConfig, params: FindOrderParams & { guest_token?: string }): Promise<Order> {
|
|
154
|
+
const queryParams = new URLSearchParams()
|
|
155
|
+
if (params.email) queryParams.set('email', params.email)
|
|
156
|
+
if (params.order_id) queryParams.set('order_id', params.order_id)
|
|
157
|
+
if (params.guest_token) queryParams.set('guest_token', params.guest_token)
|
|
158
|
+
|
|
159
|
+
const response = await fetch(`${config.backendUrls.store}/orders/find/?${queryParams.toString()}`, {
|
|
160
|
+
headers: {
|
|
161
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
162
|
+
"X-Business-ID": config.businessId,
|
|
163
|
+
},
|
|
164
|
+
})
|
|
165
|
+
if (!response.ok) throw new Error('Failed to find order')
|
|
166
|
+
const data = await response.json()
|
|
143
167
|
return normaliseStorefrontOrder(data)
|
|
144
168
|
}
|
|
145
169
|
|
|
146
|
-
export async function findOrderByToken(token: string): Promise<Order> {
|
|
147
|
-
const
|
|
148
|
-
|
|
170
|
+
export async function findOrderByToken(config: SdkConfig, token: string): Promise<Order> {
|
|
171
|
+
const response = await fetch(`${config.backendUrls.store}/orders/find/?guest_token=${token}`, {
|
|
172
|
+
headers: {
|
|
173
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
174
|
+
"X-Business-ID": config.businessId,
|
|
175
|
+
},
|
|
149
176
|
})
|
|
177
|
+
if (!response.ok) throw new Error('Failed to find order by token')
|
|
178
|
+
const data = await response.json()
|
|
150
179
|
return normaliseStorefrontOrder(data)
|
|
151
180
|
}
|
|
152
181
|
|
|
153
|
-
export async function getOrders(params?: { email?: string; page?: number; page_size?: number }): Promise<Order[]> {
|
|
154
|
-
const
|
|
182
|
+
export async function getOrders(config: SdkConfig, accessToken: string, params?: { email?: string; page?: number; page_size?: number }): Promise<Order[]> {
|
|
183
|
+
const queryParams = new URLSearchParams()
|
|
184
|
+
if (params?.email) queryParams.set('email', params.email)
|
|
185
|
+
if (params?.page) queryParams.set('page', params.page.toString())
|
|
186
|
+
if (params?.page_size) queryParams.set('page_size', params.page_size.toString())
|
|
187
|
+
|
|
188
|
+
const response = await fetch(`${config.backendUrls.store}/orders/?${queryParams.toString()}`, {
|
|
189
|
+
headers: {
|
|
190
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
191
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
192
|
+
"X-Business-ID": config.businessId,
|
|
193
|
+
},
|
|
194
|
+
})
|
|
195
|
+
if (!response.ok) throw new Error('Failed to get orders')
|
|
196
|
+
const data = await response.json()
|
|
155
197
|
const items: RawOrder[] = Array.isArray(data) ? data : (data.items ?? [])
|
|
156
198
|
return items.map(normaliseStorefrontOrder)
|
|
157
199
|
}
|
|
158
200
|
|
|
159
|
-
export async function cancelOrder(orderId: string, reason: string): Promise<Order> {
|
|
160
|
-
const
|
|
201
|
+
export async function cancelOrder(config: SdkConfig, accessToken: string, orderId: string, reason: string): Promise<Order> {
|
|
202
|
+
const response = await fetch(`${config.backendUrls.store}/orders/${orderId}/cancel/`, {
|
|
203
|
+
method: 'POST',
|
|
204
|
+
headers: {
|
|
205
|
+
'Content-Type': 'application/json',
|
|
206
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
207
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
208
|
+
"X-Business-ID": config.businessId,
|
|
209
|
+
},
|
|
210
|
+
body: JSON.stringify({ reason }),
|
|
211
|
+
})
|
|
212
|
+
if (!response.ok) throw new Error('Failed to cancel order')
|
|
213
|
+
const data = await response.json()
|
|
161
214
|
return normaliseStorefrontOrder(data)
|
|
162
215
|
}
|
|
163
216
|
|
|
164
|
-
export async function trackOrder(orderId: string, token?: string): Promise<Order> {
|
|
165
|
-
const
|
|
166
|
-
|
|
217
|
+
export async function trackOrder(config: SdkConfig, orderId: string, token?: string): Promise<Order> {
|
|
218
|
+
const queryParams = token ? `?token=${token}` : ''
|
|
219
|
+
const response = await fetch(`${config.backendUrls.store}/orders/track/${orderId}${queryParams}`, {
|
|
220
|
+
headers: {
|
|
221
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
222
|
+
"X-Business-ID": config.businessId,
|
|
223
|
+
},
|
|
167
224
|
})
|
|
225
|
+
if (!response.ok) throw new Error('Failed to track order')
|
|
226
|
+
const data = await response.json()
|
|
168
227
|
return normaliseStorefrontOrder(data)
|
|
169
228
|
}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Payment Service
|
|
3
3
|
*
|
|
4
4
|
* Customer-facing payment API for payment initiation and verification.
|
|
5
|
+
* Stateless - all configuration passed as parameters.
|
|
5
6
|
*/
|
|
6
|
-
import {
|
|
7
|
+
import type { SdkConfig } from '../config'
|
|
7
8
|
import type {
|
|
8
9
|
ConversionQuote,
|
|
9
10
|
DVACreateRequest,
|
|
@@ -19,6 +20,8 @@ import type {
|
|
|
19
20
|
* will reject non-NGN requests for this payment method.
|
|
20
21
|
*/
|
|
21
22
|
export async function createDedicatedAccount(
|
|
23
|
+
config: SdkConfig,
|
|
24
|
+
accessToken: string,
|
|
22
25
|
request: DVACreateRequest
|
|
23
26
|
): Promise<DVADetails> {
|
|
24
27
|
const isValidUUID = (str: string) => {
|
|
@@ -26,17 +29,25 @@ export async function createDedicatedAccount(
|
|
|
26
29
|
return uuidRegex.test(str);
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
const
|
|
30
|
-
'
|
|
31
|
-
{
|
|
32
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/dedicated-account`, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: {
|
|
35
|
+
'Content-Type': 'application/json',
|
|
36
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
37
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
38
|
+
"X-Business-ID": config.businessId,
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify({
|
|
32
41
|
order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : undefined,
|
|
33
42
|
amount: request.amount,
|
|
34
43
|
customer_email: request.customer_email,
|
|
35
44
|
customer_name: request.customer_name,
|
|
36
45
|
currency: request.currency,
|
|
37
46
|
idempotency_key: request.idempotency_key,
|
|
38
|
-
}
|
|
39
|
-
)
|
|
47
|
+
}),
|
|
48
|
+
})
|
|
49
|
+
if (!response.ok) throw new Error('Failed to create dedicated account')
|
|
50
|
+
const data = await response.json()
|
|
40
51
|
return data
|
|
41
52
|
}
|
|
42
53
|
|
|
@@ -46,6 +57,8 @@ export async function createDedicatedAccount(
|
|
|
46
57
|
* Returns a checkout_url to redirect the customer to the gateway.
|
|
47
58
|
*/
|
|
48
59
|
export async function initiatePayment(
|
|
60
|
+
config: SdkConfig,
|
|
61
|
+
accessToken: string,
|
|
49
62
|
request: PaymentInitiateRequest
|
|
50
63
|
): Promise<PaymentInitiateResponse> {
|
|
51
64
|
const isValidUUID = (str: string) => {
|
|
@@ -55,25 +68,30 @@ export async function initiatePayment(
|
|
|
55
68
|
|
|
56
69
|
const validOrderId = request.order_id && isValidUUID(request.order_id) ? request.order_id : undefined;
|
|
57
70
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
amount: request.amount,
|
|
66
|
-
currency: request.currency,
|
|
67
|
-
order_id: validOrderId,
|
|
68
|
-
quote_id: request.quote_id,
|
|
69
|
-
metadata_json: {
|
|
70
|
-
customer_email: request.customer_email,
|
|
71
|
-
customer_name: request.customer_name ?? '',
|
|
72
|
-
order_id: validOrderId,
|
|
73
|
-
...(request.metadata ?? {}),
|
|
71
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/storefront/initiate`, {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
headers: {
|
|
74
|
+
'Content-Type': 'application/json',
|
|
75
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
76
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
77
|
+
"X-Business-ID": config.businessId,
|
|
74
78
|
},
|
|
75
|
-
|
|
79
|
+
body: JSON.stringify({
|
|
80
|
+
amount: request.amount,
|
|
81
|
+
currency: request.currency,
|
|
82
|
+
order_id: validOrderId,
|
|
83
|
+
quote_id: request.quote_id,
|
|
84
|
+
metadata_json: {
|
|
85
|
+
customer_email: request.customer_email,
|
|
86
|
+
customer_name: request.customer_name ?? '',
|
|
87
|
+
order_id: validOrderId,
|
|
88
|
+
...(request.metadata ?? {}),
|
|
89
|
+
},
|
|
90
|
+
idempotency_key: request.idempotency_key,
|
|
91
|
+
}),
|
|
76
92
|
})
|
|
93
|
+
if (!response.ok) throw new Error('Failed to initiate payment')
|
|
94
|
+
const data = await response.json()
|
|
77
95
|
|
|
78
96
|
return {
|
|
79
97
|
id: data.id,
|
|
@@ -88,9 +106,20 @@ export async function initiatePayment(
|
|
|
88
106
|
* Request a 15-minute rate-locked conversion quote for non-NGN transactions.
|
|
89
107
|
*/
|
|
90
108
|
export async function requestQuote(
|
|
109
|
+
config: SdkConfig,
|
|
91
110
|
amount: number
|
|
92
111
|
): Promise<ConversionQuote> {
|
|
93
|
-
const
|
|
112
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/quote`, {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: {
|
|
115
|
+
'Content-Type': 'application/json',
|
|
116
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
117
|
+
"X-Business-ID": config.businessId,
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify({ amount }),
|
|
120
|
+
})
|
|
121
|
+
if (!response.ok) throw new Error('Failed to request quote')
|
|
122
|
+
const data = await response.json()
|
|
94
123
|
return data
|
|
95
124
|
}
|
|
96
125
|
|
|
@@ -98,11 +127,31 @@ export async function requestQuote(
|
|
|
98
127
|
* Verify a payment after the gateway redirects back to /checkout/verify.
|
|
99
128
|
*/
|
|
100
129
|
export async function verifyTransaction(
|
|
101
|
-
|
|
130
|
+
configOrReference: SdkConfig | string,
|
|
131
|
+
reference?: string
|
|
102
132
|
): Promise<TransactionVerifyResponse> {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
133
|
+
if (typeof configOrReference === 'string') {
|
|
134
|
+
const ref = configOrReference
|
|
135
|
+
const response = await fetch(`/api/payments/verify/${ref}`, {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: { 'Content-Type': 'application/json' },
|
|
138
|
+
})
|
|
139
|
+
if (!response.ok) throw new Error('Failed to verify transaction')
|
|
140
|
+
return response.json()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const config = configOrReference
|
|
144
|
+
const ref = reference || ''
|
|
145
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/verify/${ref}`, {
|
|
146
|
+
method: 'POST',
|
|
147
|
+
headers: {
|
|
148
|
+
'Content-Type': 'application/json',
|
|
149
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
150
|
+
"X-Business-ID": config.businessId,
|
|
151
|
+
},
|
|
152
|
+
})
|
|
153
|
+
if (!response.ok) throw new Error('Failed to verify transaction')
|
|
154
|
+
const data = await response.json()
|
|
106
155
|
return data
|
|
107
156
|
}
|
|
108
157
|
|
|
@@ -110,11 +159,17 @@ export async function verifyTransaction(
|
|
|
110
159
|
* Poll transaction status by internal transaction ID.
|
|
111
160
|
*/
|
|
112
161
|
export async function getTransactionStatus(
|
|
162
|
+
config: SdkConfig,
|
|
113
163
|
transactionId: string
|
|
114
164
|
): Promise<TransactionVerifyResponse> {
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
165
|
+
const response = await fetch(`${config.backendUrls.payment}/payments/transactions/${transactionId}`, {
|
|
166
|
+
headers: {
|
|
167
|
+
"X-Storefront-Key": config.storefrontApiKey,
|
|
168
|
+
"X-Business-ID": config.businessId,
|
|
169
|
+
},
|
|
170
|
+
})
|
|
171
|
+
if (!response.ok) throw new Error('Failed to get transaction status')
|
|
172
|
+
const data = await response.json()
|
|
118
173
|
return data
|
|
119
174
|
}
|
|
120
175
|
|