@shop-prompter/react 0.1.1
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/CHANGELOG.md +13 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1181 -0
- package/dist/index.mjs +1144 -0
- package/package.json +25 -0
- package/src/api/session-handler.ts +80 -0
- package/src/api/shop-prompter-api.ts +389 -0
- package/src/api/shop-prompter.types.ts +87 -0
- package/src/index.ts +1 -0
- package/src/product.types.ts +32 -0
- package/src/shop-prompter.component.jsx +728 -0
- package/src/shop-prompter.service.ts +135 -0
- package/tsconfig.json +15 -0
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shop-prompter/react",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"module": "dist/index.mjs",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"react": "^18.0.0"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup src/index.ts --format cjs,esm --dts"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"react": "^19.2.7",
|
|
18
|
+
"@shop-prompter/core": "workspace:*",
|
|
19
|
+
"tsup": "^8.5.1",
|
|
20
|
+
"typescript": "^6.0.3"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"uuid": "^14.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
|
|
3
|
+
const SESSION_KEY = 'shopprompter_sessionId';
|
|
4
|
+
const USER_KEY = 'shopprompter_userId';
|
|
5
|
+
|
|
6
|
+
export interface SessionHandler {
|
|
7
|
+
initialize(userIdentifier?: string): void;
|
|
8
|
+
regenerate(): void;
|
|
9
|
+
getSessionId(): string;
|
|
10
|
+
getUserId(): string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class DefaultSessionHandler implements SessionHandler {
|
|
14
|
+
private sessionId: string = '';
|
|
15
|
+
private userId: string = '';
|
|
16
|
+
|
|
17
|
+
initialize(userIdentifier?: string): void {
|
|
18
|
+
// Get or create user identifier
|
|
19
|
+
this.userId = userIdentifier || this.getPersistedUserId() || uuidv4();
|
|
20
|
+
this.persistUserId(this.userId);
|
|
21
|
+
|
|
22
|
+
// Get or create session ID
|
|
23
|
+
this.sessionId = this.getPersistedSessionId() || this.userId;
|
|
24
|
+
this.persistSessionId(this.sessionId);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
regenerate(): void {
|
|
28
|
+
this.sessionId = uuidv4();
|
|
29
|
+
this.persistSessionId(this.sessionId);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getSessionId(): string {
|
|
33
|
+
if (!this.sessionId) {
|
|
34
|
+
this.initialize();
|
|
35
|
+
}
|
|
36
|
+
return this.sessionId;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getUserId(): string {
|
|
40
|
+
if (!this.userId) {
|
|
41
|
+
this.initialize();
|
|
42
|
+
}
|
|
43
|
+
return this.userId;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private getPersistedSessionId(): string | null {
|
|
47
|
+
try {
|
|
48
|
+
return localStorage.getItem(SESSION_KEY);
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private persistSessionId(sessionId: string): void {
|
|
55
|
+
try {
|
|
56
|
+
localStorage.setItem(SESSION_KEY, sessionId);
|
|
57
|
+
} catch {
|
|
58
|
+
// localStorage not available
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private getPersistedUserId(): string | null {
|
|
63
|
+
try {
|
|
64
|
+
return localStorage.getItem(USER_KEY);
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private persistUserId(userId: string): void {
|
|
71
|
+
try {
|
|
72
|
+
localStorage.setItem(USER_KEY, userId);
|
|
73
|
+
} catch {
|
|
74
|
+
// localStorage not available
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Singleton instance
|
|
80
|
+
export const sessionHandler = new DefaultSessionHandler();
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ShopPrompterApiConfiguration,
|
|
5
|
+
ShopPrompterResponse,
|
|
6
|
+
ShopPrompterStreamEvent,
|
|
7
|
+
ShopPrompterStreamTextEvent,
|
|
8
|
+
ShopPrompterStreamProductSkusEvent,
|
|
9
|
+
ShopPrompterStreamNavigationEvent,
|
|
10
|
+
ShopPrompterStreamCartEvent,
|
|
11
|
+
ShopPrompterNavigationOperation,
|
|
12
|
+
ShopPrompterCartOperation,
|
|
13
|
+
AgentExperience,
|
|
14
|
+
} from './shop-prompter.types'
|
|
15
|
+
|
|
16
|
+
export interface ShopPrompterApi {
|
|
17
|
+
setApiConfig(config: ShopPrompterApiConfiguration): void
|
|
18
|
+
execute(
|
|
19
|
+
prompt: string,
|
|
20
|
+
userId: string,
|
|
21
|
+
sessionId: string,
|
|
22
|
+
): Promise<ShopPrompterResponse>
|
|
23
|
+
executeStream(
|
|
24
|
+
prompt: string,
|
|
25
|
+
userId: string,
|
|
26
|
+
sessionId: string,
|
|
27
|
+
onEvent: (event: ShopPrompterStreamEvent) => void,
|
|
28
|
+
): Promise<void>
|
|
29
|
+
getAgentExperience(): Promise<AgentExperience | null>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class DefaultShopPrompterApi implements ShopPrompterApi {
|
|
33
|
+
private config: ShopPrompterApiConfiguration | null = null
|
|
34
|
+
|
|
35
|
+
setApiConfig(config: ShopPrompterApiConfiguration): void {
|
|
36
|
+
this.config = config
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async execute(
|
|
40
|
+
prompt: string,
|
|
41
|
+
userId: string,
|
|
42
|
+
sessionId: string,
|
|
43
|
+
): Promise<ShopPrompterResponse> {
|
|
44
|
+
if (!this.config) {
|
|
45
|
+
throw new Error('API configuration not set. Call setApiConfig first.')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const response = await fetch(`${this.config.baseUrl}/interaction`, {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
'X-Api-Key': this.config.apiKey,
|
|
53
|
+
},
|
|
54
|
+
body: JSON.stringify({
|
|
55
|
+
prompt,
|
|
56
|
+
userId,
|
|
57
|
+
sessionId,
|
|
58
|
+
}),
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
throw new Error(`API error: ${response.status}`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return response.json()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async executeStream(
|
|
69
|
+
prompt: string,
|
|
70
|
+
userId: string,
|
|
71
|
+
sessionId: string,
|
|
72
|
+
onEvent: (event: ShopPrompterStreamEvent) => void,
|
|
73
|
+
cartContext?: { sku: string; quantity: number }[],
|
|
74
|
+
): Promise<void> {
|
|
75
|
+
if (!this.config) {
|
|
76
|
+
throw new Error('API configuration not set. Call setApiConfig first.')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const url = `${this.config.baseUrl}/interaction/stream`
|
|
80
|
+
console.log('ShopPrompter Request:', {
|
|
81
|
+
url,
|
|
82
|
+
prompt,
|
|
83
|
+
userId,
|
|
84
|
+
sessionId,
|
|
85
|
+
cartContext,
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
let response: Response
|
|
89
|
+
try {
|
|
90
|
+
response = await fetch(url, {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
headers: {
|
|
93
|
+
'Content-Type': 'application/json',
|
|
94
|
+
'X-Api-Key': this.config.apiKey,
|
|
95
|
+
Accept: 'text/event-stream',
|
|
96
|
+
'Cache-Control': 'no-cache',
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify({
|
|
99
|
+
prompt,
|
|
100
|
+
userId,
|
|
101
|
+
sessionId,
|
|
102
|
+
cart: cartContext,
|
|
103
|
+
}),
|
|
104
|
+
})
|
|
105
|
+
} catch (fetchError) {
|
|
106
|
+
console.error('ShopPrompter Fetch Error:', fetchError)
|
|
107
|
+
onEvent({
|
|
108
|
+
type: 'error',
|
|
109
|
+
reason: `Failed to fetch: ${fetchError instanceof Error ? fetchError.message : 'Network error'}`,
|
|
110
|
+
})
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
console.log('ShopPrompter Response:', response.status)
|
|
115
|
+
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const errorText = await response.text().catch(() => '')
|
|
118
|
+
console.error('ShopPrompter API Error:', response.status, errorText)
|
|
119
|
+
onEvent({
|
|
120
|
+
type: 'error',
|
|
121
|
+
reason: `API error: ${response.status} - ${errorText}`,
|
|
122
|
+
})
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const reader = response.body?.getReader()
|
|
127
|
+
if (!reader) {
|
|
128
|
+
onEvent({ type: 'error', reason: 'No response body' })
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const decoder = new TextDecoder()
|
|
133
|
+
let buffer = ''
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
while (true) {
|
|
137
|
+
const { done, value } = await reader.read()
|
|
138
|
+
|
|
139
|
+
if (done) {
|
|
140
|
+
console.log('ShopPrompter Stream done')
|
|
141
|
+
onEvent({ type: 'close' })
|
|
142
|
+
break
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const chunk = decoder.decode(value, { stream: true })
|
|
146
|
+
console.log('ShopPrompter Raw chunk:', chunk)
|
|
147
|
+
buffer += chunk
|
|
148
|
+
const lines = buffer.split('\n')
|
|
149
|
+
buffer = lines.pop() || ''
|
|
150
|
+
|
|
151
|
+
let currentEventType = ''
|
|
152
|
+
for (const line of lines) {
|
|
153
|
+
console.log('ShopPrompter Line:', line)
|
|
154
|
+
if (line.startsWith('event:')) {
|
|
155
|
+
// Capture the event type for the next data line
|
|
156
|
+
currentEventType = line.slice(6).trim()
|
|
157
|
+
console.log('ShopPrompter Event type:', currentEventType)
|
|
158
|
+
|
|
159
|
+
// If it's an error event, we need to handle it
|
|
160
|
+
if (currentEventType === 'error') {
|
|
161
|
+
onEvent({
|
|
162
|
+
type: 'error',
|
|
163
|
+
reason:
|
|
164
|
+
'Server returned an error event. Check backend configuration.',
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
} else if (line.startsWith('data:')) {
|
|
168
|
+
const data = line.slice(5).trim()
|
|
169
|
+
console.log('ShopPrompter Data:', data)
|
|
170
|
+
if (data) {
|
|
171
|
+
// If we got an error event type, try to parse error details
|
|
172
|
+
if (currentEventType === 'error') {
|
|
173
|
+
try {
|
|
174
|
+
const errorData = JSON.parse(data)
|
|
175
|
+
onEvent({
|
|
176
|
+
type: 'error',
|
|
177
|
+
reason:
|
|
178
|
+
errorData.message ||
|
|
179
|
+
errorData.error ||
|
|
180
|
+
'Unknown server error',
|
|
181
|
+
})
|
|
182
|
+
} catch {
|
|
183
|
+
onEvent({
|
|
184
|
+
type: 'error',
|
|
185
|
+
reason: data || 'Unknown server error',
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
const event = this.parseEvent(data)
|
|
190
|
+
console.log('ShopPrompter Parsed event:', event)
|
|
191
|
+
if (event) {
|
|
192
|
+
onEvent(event)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
currentEventType = '' // Reset after processing data
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error('ShopPrompter Stream error:', error)
|
|
202
|
+
onEvent({
|
|
203
|
+
type: 'error',
|
|
204
|
+
reason: error instanceof Error ? error.message : 'Unknown error',
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async getAgentExperience(): Promise<AgentExperience | null> {
|
|
210
|
+
// todo: Return cached version if available
|
|
211
|
+
|
|
212
|
+
if (!this.config) {
|
|
213
|
+
console.warn('API configuration not set. Call setApiConfig first.')
|
|
214
|
+
return null
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
const response = await fetch(`${this.config.baseUrl}/agent-experience`, {
|
|
219
|
+
method: 'GET',
|
|
220
|
+
headers: {
|
|
221
|
+
'Content-Type': 'application/json',
|
|
222
|
+
'X-Api-Key': this.config.apiKey,
|
|
223
|
+
},
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
if (!response.ok) {
|
|
227
|
+
console.error(`Failed to fetch agent experience: ${response.status}`)
|
|
228
|
+
return null
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const data: AgentExperience = await response.json()
|
|
232
|
+
|
|
233
|
+
console.log(
|
|
234
|
+
'## ~ DefaultShopPrompterApi ~ getAgentExperience ~ data:',
|
|
235
|
+
data,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
return data
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error('Error fetching agent experience:', error)
|
|
241
|
+
return null
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private parseEvent(data: string): ShopPrompterStreamEvent | null {
|
|
246
|
+
try {
|
|
247
|
+
const json = JSON.parse(data)
|
|
248
|
+
|
|
249
|
+
// Parse based on event type
|
|
250
|
+
// Handle both "token" and "text" fields for text events
|
|
251
|
+
if (json.token !== undefined) {
|
|
252
|
+
// Skip "close" token - it's a signal to end the stream
|
|
253
|
+
if (json.token === 'close') {
|
|
254
|
+
return { type: 'close' }
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
type: 'text',
|
|
258
|
+
text: json.token,
|
|
259
|
+
} as ShopPrompterStreamTextEvent
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (json.text !== undefined) {
|
|
263
|
+
return {
|
|
264
|
+
type: 'text',
|
|
265
|
+
text: json.text,
|
|
266
|
+
} as ShopPrompterStreamTextEvent
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (json.skus !== undefined) {
|
|
270
|
+
return {
|
|
271
|
+
type: 'productSkus',
|
|
272
|
+
skus: json.skus,
|
|
273
|
+
} as ShopPrompterStreamProductSkusEvent
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Also check for products array with SKUs
|
|
277
|
+
if (json.products !== undefined && Array.isArray(json.products)) {
|
|
278
|
+
const skus = json.products.map((p: any) => p.sku).filter(Boolean)
|
|
279
|
+
if (skus.length > 0) {
|
|
280
|
+
return {
|
|
281
|
+
type: 'productSkus',
|
|
282
|
+
skus: skus,
|
|
283
|
+
} as ShopPrompterStreamProductSkusEvent
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Check for productSkus field directly
|
|
288
|
+
if (json.productSkus !== undefined) {
|
|
289
|
+
return {
|
|
290
|
+
type: 'productSkus',
|
|
291
|
+
skus: json.productSkus,
|
|
292
|
+
} as ShopPrompterStreamProductSkusEvent
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Handle output array format: {"output": [{"type": "product", "data": [...]}]}
|
|
296
|
+
if (json.output !== undefined && Array.isArray(json.output)) {
|
|
297
|
+
for (const item of json.output) {
|
|
298
|
+
if (
|
|
299
|
+
item.type === 'product' &&
|
|
300
|
+
item.data &&
|
|
301
|
+
Array.isArray(item.data)
|
|
302
|
+
) {
|
|
303
|
+
// Extract SKUs from product data - handle both sku field and direct string SKUs
|
|
304
|
+
const skus = item.data
|
|
305
|
+
.filter((p: any) => p !== null)
|
|
306
|
+
.map((p: any) => (typeof p === 'string' ? p : p?.sku))
|
|
307
|
+
.filter(Boolean)
|
|
308
|
+
if (skus.length > 0) {
|
|
309
|
+
return {
|
|
310
|
+
type: 'productSkus',
|
|
311
|
+
skus: skus,
|
|
312
|
+
} as ShopPrompterStreamProductSkusEvent
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Also check for skus directly in output item
|
|
316
|
+
if (
|
|
317
|
+
item.type === 'product' &&
|
|
318
|
+
item.skus &&
|
|
319
|
+
Array.isArray(item.skus)
|
|
320
|
+
) {
|
|
321
|
+
return {
|
|
322
|
+
type: 'productSkus',
|
|
323
|
+
skus: item.skus,
|
|
324
|
+
} as ShopPrompterStreamProductSkusEvent
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (json.navigation !== undefined) {
|
|
330
|
+
return {
|
|
331
|
+
type: 'navigation',
|
|
332
|
+
navigationOperations: json.navigation.map((nav: any) => ({
|
|
333
|
+
name: nav.name,
|
|
334
|
+
route: nav.path || nav.route,
|
|
335
|
+
description: nav.description,
|
|
336
|
+
})) as ShopPrompterNavigationOperation[],
|
|
337
|
+
} as ShopPrompterStreamNavigationEvent
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (json.cart !== undefined) {
|
|
341
|
+
return {
|
|
342
|
+
type: 'cart',
|
|
343
|
+
operations: json.cart.map((op: any) => ({
|
|
344
|
+
sku: op.sku,
|
|
345
|
+
action: op.action,
|
|
346
|
+
quantity: op.quantity || 1,
|
|
347
|
+
})) as ShopPrompterCartOperation[],
|
|
348
|
+
} as ShopPrompterStreamCartEvent
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Also check for cart in output array format
|
|
352
|
+
if (json.output !== undefined && Array.isArray(json.output)) {
|
|
353
|
+
for (const item of json.output) {
|
|
354
|
+
if (item.type === 'cart' && item.data) {
|
|
355
|
+
return {
|
|
356
|
+
type: 'cart',
|
|
357
|
+
operations: (Array.isArray(item.data)
|
|
358
|
+
? item.data
|
|
359
|
+
: [item.data]
|
|
360
|
+
).map((op: any) => ({
|
|
361
|
+
sku: op.sku,
|
|
362
|
+
action: op.action || 'add',
|
|
363
|
+
quantity: op.quantity || 1,
|
|
364
|
+
})) as ShopPrompterCartOperation[],
|
|
365
|
+
} as ShopPrompterStreamCartEvent
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (json.close !== undefined || json.type === 'close') {
|
|
371
|
+
return { type: 'close' }
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return null
|
|
375
|
+
} catch {
|
|
376
|
+
// If it's plain text, treat it as a text event
|
|
377
|
+
if (data && typeof data === 'string') {
|
|
378
|
+
return {
|
|
379
|
+
type: 'text',
|
|
380
|
+
text: data,
|
|
381
|
+
} as ShopPrompterStreamTextEvent
|
|
382
|
+
}
|
|
383
|
+
return null
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Singleton instance
|
|
389
|
+
export const shopPrompterApi = new DefaultShopPrompterApi()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// ShopPrompter API Types
|
|
2
|
+
|
|
3
|
+
export interface ShopPrompterApiConfiguration {
|
|
4
|
+
baseUrl: string
|
|
5
|
+
apiKey: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ShopPrompterResponse {
|
|
9
|
+
text?: string
|
|
10
|
+
products?: ShopPrompterProduct[]
|
|
11
|
+
skus?: string[]
|
|
12
|
+
navigation?: ShopPrompterNavigationOperation[]
|
|
13
|
+
cart?: ShopPrompterCartOperation[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ShopPrompterProduct {
|
|
17
|
+
sku: string
|
|
18
|
+
name: string
|
|
19
|
+
price: number
|
|
20
|
+
currency: string
|
|
21
|
+
images: string[]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Stream Events
|
|
25
|
+
export type ShopPrompterStreamEvent =
|
|
26
|
+
| ShopPrompterStreamTextEvent
|
|
27
|
+
| ShopPrompterStreamProductSkusEvent
|
|
28
|
+
| ShopPrompterStreamNavigationEvent
|
|
29
|
+
| ShopPrompterStreamCartEvent
|
|
30
|
+
| ShopPrompterStreamCloseEvent
|
|
31
|
+
| ShopPrompterErrorEvent
|
|
32
|
+
|
|
33
|
+
export interface ShopPrompterStreamTextEvent {
|
|
34
|
+
type: 'text'
|
|
35
|
+
text: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ShopPrompterStreamProductSkusEvent {
|
|
39
|
+
type: 'productSkus'
|
|
40
|
+
skus: string[]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ShopPrompterStreamNavigationEvent {
|
|
44
|
+
type: 'navigation'
|
|
45
|
+
navigationOperations: ShopPrompterNavigationOperation[]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ShopPrompterNavigationOperation {
|
|
49
|
+
name: string
|
|
50
|
+
route: string
|
|
51
|
+
description: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ShopPrompterStreamCartEvent {
|
|
55
|
+
type: 'cart'
|
|
56
|
+
operations: ShopPrompterCartOperation[]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ShopPrompterCartOperation {
|
|
60
|
+
sku: string
|
|
61
|
+
action: 'add' | 'remove'
|
|
62
|
+
quantity: number
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface ShopPrompterStreamCloseEvent {
|
|
66
|
+
type: 'close'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ShopPrompterErrorEvent {
|
|
70
|
+
type: 'error'
|
|
71
|
+
reason: string
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Agent Experience Types
|
|
75
|
+
export interface AgentExperience {
|
|
76
|
+
agentName: string
|
|
77
|
+
agentLogoUrl: string
|
|
78
|
+
loadingIndicatorUrl: string
|
|
79
|
+
greeting: {
|
|
80
|
+
title: string
|
|
81
|
+
message: string
|
|
82
|
+
}
|
|
83
|
+
hintText: string
|
|
84
|
+
predefinedPrompts: Array<{
|
|
85
|
+
prompt: string
|
|
86
|
+
}>
|
|
87
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as ShopPrompter } from './shop-prompter.component';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface ProductCategory {
|
|
2
|
+
id: number;
|
|
3
|
+
name: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface Product {
|
|
7
|
+
name: string;
|
|
8
|
+
sku: string;
|
|
9
|
+
images: string[];
|
|
10
|
+
category: ProductCategory | null;
|
|
11
|
+
price: number;
|
|
12
|
+
currency: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
extras: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Pagination {
|
|
18
|
+
last: number;
|
|
19
|
+
current: number;
|
|
20
|
+
numItemsPerPage: number;
|
|
21
|
+
pageCount: number;
|
|
22
|
+
totalCount: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ProductSearchResponse {
|
|
26
|
+
products: Product[];
|
|
27
|
+
pagination: Pagination;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ProductSkuResponse {
|
|
31
|
+
products: Product[];
|
|
32
|
+
}
|