vanilla-agent-proxy 0.2.0 → 1.0.0

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/index.cjs CHANGED
@@ -20,13 +20,269 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ CONVERSATIONAL_FLOW: () => CONVERSATIONAL_FLOW,
24
+ SHOPPING_ASSISTANT_FLOW: () => SHOPPING_ASSISTANT_FLOW,
25
+ SHOPPING_ASSISTANT_METADATA_FLOW: () => SHOPPING_ASSISTANT_METADATA_FLOW,
23
26
  createChatProxyApp: () => createChatProxyApp,
27
+ createCheckoutSession: () => createCheckoutSession,
24
28
  createVercelHandler: () => createVercelHandler,
25
29
  default: () => index_default
26
30
  });
27
31
  module.exports = __toCommonJS(index_exports);
28
32
  var import_hono = require("hono");
29
33
  var import_vercel = require("hono/vercel");
34
+
35
+ // src/flows/conversational.ts
36
+ var CONVERSATIONAL_FLOW = {
37
+ name: "Streaming Prompt Flow",
38
+ description: "Streaming chat generated by the widget",
39
+ steps: [
40
+ {
41
+ id: "widget_prompt",
42
+ name: "Prompt",
43
+ type: "prompt",
44
+ enabled: true,
45
+ config: {
46
+ model: "meta/llama3.1-8b-instruct-free",
47
+ response_format: "markdown",
48
+ output_variable: "prompt_result",
49
+ user_prompt: "{{user_message}}",
50
+ system_prompt: "you are a helpful assistant, chatting with a user",
51
+ previous_messages: "{{messages}}"
52
+ }
53
+ }
54
+ ]
55
+ };
56
+
57
+ // src/flows/shopping-assistant.ts
58
+ var SHOPPING_ASSISTANT_FLOW = {
59
+ name: "Shopping Assistant Flow",
60
+ description: "Returns JSON actions for page interaction",
61
+ steps: [
62
+ {
63
+ id: "action_prompt",
64
+ name: "Action Prompt",
65
+ type: "prompt",
66
+ enabled: true,
67
+ config: {
68
+ model: "qwen/qwen3-8b",
69
+ reasoning: false,
70
+ responseFormat: "JSON",
71
+ outputVariable: "prompt_result",
72
+ userPrompt: "{{user_message}}",
73
+ systemPrompt: `You are a helpful shopping assistant that can interact with web pages.
74
+ You will receive information about the current page's elements (class names and text content)
75
+ and user messages. You must respond with JSON in one of these formats:
76
+
77
+ 1. Simple message:
78
+ {
79
+ "action": "message",
80
+ "text": "Your response text here"
81
+ }
82
+
83
+ 2. Navigate then show message (for navigation to another page):
84
+ {
85
+ "action": "nav_then_click",
86
+ "page": "http://site.com/page-url",
87
+ "on_load_text": "Message to show after navigation"
88
+ }
89
+
90
+ 3. Show message and click an element:
91
+ {
92
+ "action": "message_and_click",
93
+ "element": ".className-of-element",
94
+ "text": "Your message text"
95
+ }
96
+
97
+ 4. Create Stripe checkout:
98
+ {
99
+ "action": "checkout",
100
+ "text": "Your message text",
101
+ "items": [
102
+ {"name": "Product Name", "price": 2999, "quantity": 1}
103
+ ]
104
+ }
105
+
106
+ Guidelines:
107
+ - Use "message" for simple conversational responses
108
+ - Use "nav_then_click" when you need to navigate to a different page (like a product detail page)
109
+ - Use "message_and_click" when you want to click a button or element on the current page
110
+ - Use "checkout" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)
111
+ - When selecting elements, use the class names provided in the page context
112
+ - Always respond with valid JSON only, no additional text
113
+ - For product searches, format results as markdown links: [Product Name](url)
114
+ - Be helpful and conversational in your messages
115
+ - Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)
116
+
117
+ Example conversation flow:
118
+ - User: "I am looking for a black shirt in medium"
119
+ - You: {"action": "message", "text": "Here are the products I found:\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\n\\nWould you like me to navigate to the first result and add it to your cart?"}
120
+
121
+ - User: "No, I would like to add another shirt to the cart"
122
+ - You: {"action": "message_and_click", "element": ".AddToCartButton-blue-shirt-large", "text": "I've added the Blue Shirt - Large to your cart. Ready to checkout?"}
123
+
124
+ - User: "yes"
125
+ - You: {"action": "checkout", "text": "Perfect! I'll set up the checkout for you.", "items": [{"name": "Black Shirt - Medium", "price": 2999, "quantity": 1}]}`,
126
+ previousMessages: "{{messages}}"
127
+ }
128
+ }
129
+ ]
130
+ };
131
+ var SHOPPING_ASSISTANT_METADATA_FLOW = {
132
+ name: "Metadata-Based Shopping Assistant",
133
+ description: "Uses DOM context from record metadata for page interaction",
134
+ steps: [
135
+ {
136
+ id: "metadata_action_prompt",
137
+ name: "Metadata Action Prompt",
138
+ type: "prompt",
139
+ enabled: true,
140
+ config: {
141
+ model: "qwen/qwen3-8b",
142
+ reasoning: false,
143
+ responseFormat: "JSON",
144
+ outputVariable: "prompt_result",
145
+ userPrompt: "{{user_message}}",
146
+ systemPrompt: `You are a helpful shopping assistant that can interact with web pages.
147
+
148
+ IMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:
149
+ - dom_elements: Array of page elements with className, innerText, and tagName
150
+ - dom_body: Complete HTML body of the page (if provided)
151
+ - page_url: Current page URL
152
+ - page_title: Page title
153
+
154
+ The dom_elements array provides information about clickable elements and their text content.
155
+ Use this metadata to understand what's available on the page and help users interact with it.
156
+
157
+ You must respond with JSON in one of these formats:
158
+
159
+ 1. Simple message:
160
+ {
161
+ "action": "message",
162
+ "text": "Your response text here"
163
+ }
164
+
165
+ 2. Navigate then show message (for navigation to another page):
166
+ {
167
+ "action": "nav_then_click",
168
+ "page": "http://site.com/page-url",
169
+ "on_load_text": "Message to show after navigation"
170
+ }
171
+
172
+ 3. Show message and click an element:
173
+ {
174
+ "action": "message_and_click",
175
+ "element": ".className-of-element",
176
+ "text": "Your message text"
177
+ }
178
+
179
+ 4. Create Stripe checkout:
180
+ {
181
+ "action": "checkout",
182
+ "text": "Your message text",
183
+ "items": [
184
+ {"name": "Product Name", "price": 2999, "quantity": 1}
185
+ ]
186
+ }
187
+
188
+ Guidelines:
189
+ - Use "message" for simple conversational responses
190
+ - Use "nav_then_click" when you need to navigate to a different page (like a product detail page)
191
+ - Use "message_and_click" when you want to click a button or element on the current page
192
+ - Use "checkout" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)
193
+ - When selecting elements, use the class names from the dom_elements in the metadata
194
+ - Always respond with valid JSON only, no additional text
195
+ - For product searches, format results as markdown links: [Product Name](url)
196
+ - Be helpful and conversational in your messages
197
+ - Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)
198
+
199
+ Example conversation flow:
200
+ - User: "I am looking for a black shirt in medium"
201
+ - You: {"action": "message", "text": "Here are the products I found:\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\n\\nWould you like me to navigate to the first result and add it to your cart?"}
202
+
203
+ - User: "No, I would like to add another shirt to the cart"
204
+ - You: {"action": "message_and_click", "element": ".AddToCartButton-blue-shirt-large", "text": "I've added the Blue Shirt - Large to your cart. Ready to checkout?"}
205
+
206
+ - User: "yes"
207
+ - You: {"action": "checkout", "text": "Perfect! I'll set up the checkout for you.", "items": [{"name": "Black Shirt - Medium", "price": 2999, "quantity": 1}]}`,
208
+ previousMessages: "{{messages}}"
209
+ }
210
+ }
211
+ ]
212
+ };
213
+
214
+ // src/utils/stripe.ts
215
+ async function createCheckoutSession(options) {
216
+ const { secretKey, items, successUrl, cancelUrl } = options;
217
+ try {
218
+ if (!items || !Array.isArray(items) || items.length === 0) {
219
+ return {
220
+ success: false,
221
+ error: "Items array is required"
222
+ };
223
+ }
224
+ for (const item of items) {
225
+ if (!item.name || typeof item.price !== "number" || typeof item.quantity !== "number") {
226
+ return {
227
+ success: false,
228
+ error: "Each item must have name (string), price (number in cents), and quantity (number)"
229
+ };
230
+ }
231
+ }
232
+ const lineItems = items.map((item) => ({
233
+ price_data: {
234
+ currency: "usd",
235
+ product_data: {
236
+ name: item.name
237
+ },
238
+ unit_amount: item.price
239
+ },
240
+ quantity: item.quantity
241
+ }));
242
+ const params = new URLSearchParams({
243
+ "payment_method_types[0]": "card",
244
+ "mode": "payment",
245
+ "success_url": successUrl,
246
+ "cancel_url": cancelUrl
247
+ });
248
+ lineItems.forEach((item, index) => {
249
+ params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);
250
+ params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);
251
+ params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());
252
+ params.append(`line_items[${index}][quantity]`, item.quantity.toString());
253
+ });
254
+ const stripeResponse = await fetch("https://api.stripe.com/v1/checkout/sessions", {
255
+ method: "POST",
256
+ headers: {
257
+ "Authorization": `Bearer ${secretKey}`,
258
+ "Content-Type": "application/x-www-form-urlencoded"
259
+ },
260
+ body: params
261
+ });
262
+ if (!stripeResponse.ok) {
263
+ const errorData = await stripeResponse.text();
264
+ console.error("Stripe API error:", errorData);
265
+ return {
266
+ success: false,
267
+ error: "Failed to create checkout session"
268
+ };
269
+ }
270
+ const session = await stripeResponse.json();
271
+ return {
272
+ success: true,
273
+ checkoutUrl: session.url,
274
+ sessionId: session.id
275
+ };
276
+ } catch (error) {
277
+ console.error("Stripe checkout error:", error);
278
+ return {
279
+ success: false,
280
+ error: error instanceof Error ? error.message : "Failed to create checkout session"
281
+ };
282
+ }
283
+ }
284
+
285
+ // src/index.ts
30
286
  var DEFAULT_ENDPOINT = "https://api.travrse.ai/v1/dispatch";
31
287
  var DEFAULT_PATH = "/api/chat/dispatch";
32
288
  var DEFAULT_FLOW = {
@@ -112,7 +368,7 @@ var createChatProxyApp = (options = {}) => {
112
368
  record: {
113
369
  name: "Streaming Chat Widget",
114
370
  type: "standalone",
115
- metadata: {}
371
+ metadata: clientPayload.metadata || {}
116
372
  },
117
373
  messages: formattedMessages,
118
374
  options: {
@@ -197,7 +453,11 @@ var createVercelHandler = (options) => (0, import_vercel.handle)(createChatProxy
197
453
  var index_default = createChatProxyApp;
198
454
  // Annotate the CommonJS export names for ESM import in node:
199
455
  0 && (module.exports = {
456
+ CONVERSATIONAL_FLOW,
457
+ SHOPPING_ASSISTANT_FLOW,
458
+ SHOPPING_ASSISTANT_METADATA_FLOW,
200
459
  createChatProxyApp,
460
+ createCheckoutSession,
201
461
  createVercelHandler
202
462
  });
203
463
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\nimport { handle } from \"hono/vercel\";\n\nexport type TravrseFlowStep = {\n id: string;\n name: string;\n type: string;\n enabled: boolean;\n config: Record<string, unknown>;\n};\n\nexport type TravrseFlowConfig = {\n name: string;\n description: string;\n steps: TravrseFlowStep[];\n};\n\nexport type ChatProxyOptions = {\n upstreamUrl?: string;\n apiKey?: string;\n path?: string;\n allowedOrigins?: string[];\n flowId?: string;\n flowConfig?: TravrseFlowConfig;\n};\n\nconst DEFAULT_ENDPOINT = \"https://api.travrse.ai/v1/dispatch\";\nconst DEFAULT_PATH = \"/api/chat/dispatch\";\n\nconst DEFAULT_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n // model: \"gpt-4o\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n // tools: {\n // tool_ids: [\n // \"builtin:dalle\"\n // ]\n // },\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n\nconst withCors =\n (allowedOrigins: string[] | undefined) =>\n async (c: Context, next: () => Promise<void>) => {\n const origin = c.req.header(\"origin\") ?? \"*\";\n const headers: Record<string, string> = {\n \"Access-Control-Allow-Origin\":\n allowedOrigins && allowedOrigins.length\n ? allowedOrigins.includes(origin)\n ? origin\n : allowedOrigins[0]\n : origin,\n \"Access-Control-Allow-Headers\":\n c.req.header(\"access-control-request-headers\") ??\n \"Content-Type, Authorization\",\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n Vary: \"Origin\"\n };\n\n if (c.req.method === \"OPTIONS\") {\n return new Response(null, { status: 204, headers });\n }\n\n await next();\n Object.entries(headers).forEach(([key, value]) =>\n c.header(key, value, { append: false })\n );\n };\n\nexport const createChatProxyApp = (options: ChatProxyOptions = {}) => {\n const app = new Hono();\n const path = options.path ?? DEFAULT_PATH;\n const upstream = options.upstreamUrl ?? DEFAULT_ENDPOINT;\n\n app.use(\"*\", withCors(options.allowedOrigins));\n\n app.post(path, async (c) => {\n const apiKey = options.apiKey ?? process.env.TRAVRSE_API_KEY;\n if (!apiKey) {\n return c.json(\n { error: \"Missing API key. Set TRAVRSE_API_KEY.\" },\n 401\n );\n }\n\n let clientPayload: {\n messages?: Array<{ role: string; content: string; createdAt?: string }>;\n flowId?: string;\n };\n try {\n clientPayload = await c.req.json();\n } catch (error) {\n return c.json(\n { error: \"Invalid JSON body\", details: error },\n 400\n );\n }\n\n // Build the Travrse payload\n const messages = clientPayload.messages ?? [];\n // Sort messages by timestamp to ensure correct order\n const sortedMessages = [...messages].sort((a, b) => {\n const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n return timeA - timeB;\n });\n const formattedMessages = sortedMessages.map((message) => ({\n role: message.role,\n content: message.content\n }));\n\n // Determine which flow to use\n const flowId = clientPayload.flowId ?? options.flowId;\n const flowConfig = options.flowConfig ?? DEFAULT_FLOW;\n\n const travrsePayload: Record<string, unknown> = {\n record: {\n name: \"Streaming Chat Widget\",\n type: \"standalone\",\n metadata: {}\n },\n messages: formattedMessages,\n options: {\n stream_response: true,\n record_mode: \"virtual\",\n flow_mode: flowId ? \"existing\" : \"virtual\",\n auto_append_metadata: false\n }\n };\n\n // Use flow ID if provided, otherwise use flow config\n if (flowId) {\n travrsePayload.flow = {\n \"name\": \"Chat with 8b\",\n \"description\": \"Flow with 1 step\",\n \"steps\": [\n {\n \"id\": \"step_01k8wnwpdcferbrq79tzj49aec\",\n \"name\": \"Prompt 1\",\n \"type\": \"prompt\",\n \"order\": 0,\n \"enabled\": true,\n \"config\": {\n \"text\": \"{{user_message}}\",\n \"model\": \"qwen/qwen3-8b\",\n // \"tools\": {\n // \"tool_ids\": [\n // \"tool_01k8ky2xpjfzybye5ywcmjr379\",\n // \"builtin:firecrawl\"\n // ]\n // },\n \"reasoning\": false,\n \"user_prompt\": \"{{user_message}}\",\n \"output_variable\": \"prompt_result\",\n \"response_format\": \"JSON\"\n }\n }\n ]\n }\n } else {\n travrsePayload.flow = flowConfig;\n }\n\n // Development logging\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n\n if (isDevelopment) {\n console.log(\"\\n=== Travrse Proxy Request ===\");\n console.log(\"URL:\", upstream);\n console.log(\"API Key Used:\", apiKey ? \"Yes\" : \"No\");\n console.log(\"API Key (first 12 chars):\", apiKey ? apiKey.substring(0, 12) : \"N/A\");\n console.log(\"Request Payload:\", JSON.stringify(travrsePayload, null, 2));\n }\n\n const response = await fetch(upstream, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(travrsePayload)\n });\n\n if (isDevelopment) {\n console.log(\"Response Status:\", response.status);\n console.log(\"Response Status Text:\", response.statusText);\n\n // If there's an error, try to read and log the response body\n if (!response.ok) {\n const clonedResponse = response.clone();\n try {\n const errorBody = await clonedResponse.text();\n console.log(\"Error Response Body:\", errorBody);\n } catch (e) {\n console.log(\"Could not read error response body:\", e);\n }\n }\n console.log(\"=== End Travrse Proxy Request ===\\n\");\n }\n\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"Content-Type\":\n response.headers.get(\"content-type\") ?? \"application/json\",\n \"Cache-Control\": \"no-store\"\n }\n });\n });\n\n return app;\n};\n\nexport const createVercelHandler = (options?: ChatProxyOptions) =>\n handle(createChatProxyApp(options));\n\n\nexport default createChatProxyApp;\n\n"],"mappings":"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","names":["_a","_b"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/flows/conversational.ts","../src/flows/shopping-assistant.ts","../src/utils/stripe.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\nimport { handle } from \"hono/vercel\";\n\nexport type TravrseFlowStep = {\n id: string;\n name: string;\n type: string;\n enabled: boolean;\n config: Record<string, unknown>;\n};\n\nexport type TravrseFlowConfig = {\n name: string;\n description: string;\n steps: TravrseFlowStep[];\n};\n\nexport type ChatProxyOptions = {\n upstreamUrl?: string;\n apiKey?: string;\n path?: string;\n allowedOrigins?: string[];\n flowId?: string;\n flowConfig?: TravrseFlowConfig;\n};\n\nconst DEFAULT_ENDPOINT = \"https://api.travrse.ai/v1/dispatch\";\nconst DEFAULT_PATH = \"/api/chat/dispatch\";\n\nconst DEFAULT_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n // model: \"gpt-4o\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n // tools: {\n // tool_ids: [\n // \"builtin:dalle\"\n // ]\n // },\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n\nconst withCors =\n (allowedOrigins: string[] | undefined) =>\n async (c: Context, next: () => Promise<void>) => {\n const origin = c.req.header(\"origin\") ?? \"*\";\n const headers: Record<string, string> = {\n \"Access-Control-Allow-Origin\":\n allowedOrigins && allowedOrigins.length\n ? allowedOrigins.includes(origin)\n ? origin\n : allowedOrigins[0]\n : origin,\n \"Access-Control-Allow-Headers\":\n c.req.header(\"access-control-request-headers\") ??\n \"Content-Type, Authorization\",\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n Vary: \"Origin\"\n };\n\n if (c.req.method === \"OPTIONS\") {\n return new Response(null, { status: 204, headers });\n }\n\n await next();\n Object.entries(headers).forEach(([key, value]) =>\n c.header(key, value, { append: false })\n );\n };\n\nexport const createChatProxyApp = (options: ChatProxyOptions = {}) => {\n const app = new Hono();\n const path = options.path ?? DEFAULT_PATH;\n const upstream = options.upstreamUrl ?? DEFAULT_ENDPOINT;\n\n app.use(\"*\", withCors(options.allowedOrigins));\n\n app.post(path, async (c) => {\n const apiKey = options.apiKey ?? process.env.TRAVRSE_API_KEY;\n if (!apiKey) {\n return c.json(\n { error: \"Missing API key. Set TRAVRSE_API_KEY.\" },\n 401\n );\n }\n\n let clientPayload: {\n messages?: Array<{ role: string; content: string; createdAt?: string }>;\n flowId?: string;\n metadata?: Record<string, unknown>;\n };\n try {\n clientPayload = await c.req.json();\n } catch (error) {\n return c.json(\n { error: \"Invalid JSON body\", details: error },\n 400\n );\n }\n\n // Build the Travrse payload\n const messages = clientPayload.messages ?? [];\n // Sort messages by timestamp to ensure correct order\n const sortedMessages = [...messages].sort((a, b) => {\n const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n return timeA - timeB;\n });\n const formattedMessages = sortedMessages.map((message) => ({\n role: message.role,\n content: message.content\n }));\n\n // Determine which flow to use\n const flowId = clientPayload.flowId ?? options.flowId;\n const flowConfig = options.flowConfig ?? DEFAULT_FLOW;\n\n const travrsePayload: Record<string, unknown> = {\n record: {\n name: \"Streaming Chat Widget\",\n type: \"standalone\",\n metadata: clientPayload.metadata || {}\n },\n messages: formattedMessages,\n options: {\n stream_response: true,\n record_mode: \"virtual\",\n flow_mode: flowId ? \"existing\" : \"virtual\",\n auto_append_metadata: false\n }\n };\n\n // Use flow ID if provided, otherwise use flow config\n if (flowId) {\n travrsePayload.flow = {\n \"name\": \"Chat with 8b\",\n \"description\": \"Flow with 1 step\",\n \"steps\": [\n {\n \"id\": \"step_01k8wnwpdcferbrq79tzj49aec\",\n \"name\": \"Prompt 1\",\n \"type\": \"prompt\",\n \"order\": 0,\n \"enabled\": true,\n \"config\": {\n \"text\": \"{{user_message}}\",\n \"model\": \"qwen/qwen3-8b\",\n // \"tools\": {\n // \"tool_ids\": [\n // \"tool_01k8ky2xpjfzybye5ywcmjr379\",\n // \"builtin:firecrawl\"\n // ]\n // },\n \"reasoning\": false,\n \"user_prompt\": \"{{user_message}}\",\n \"output_variable\": \"prompt_result\",\n \"response_format\": \"JSON\"\n }\n }\n ]\n }\n } else {\n travrsePayload.flow = flowConfig;\n }\n\n // Development logging\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n\n if (isDevelopment) {\n console.log(\"\\n=== Travrse Proxy Request ===\");\n console.log(\"URL:\", upstream);\n console.log(\"API Key Used:\", apiKey ? \"Yes\" : \"No\");\n console.log(\"API Key (first 12 chars):\", apiKey ? apiKey.substring(0, 12) : \"N/A\");\n console.log(\"Request Payload:\", JSON.stringify(travrsePayload, null, 2));\n }\n\n const response = await fetch(upstream, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(travrsePayload)\n });\n\n if (isDevelopment) {\n console.log(\"Response Status:\", response.status);\n console.log(\"Response Status Text:\", response.statusText);\n\n // If there's an error, try to read and log the response body\n if (!response.ok) {\n const clonedResponse = response.clone();\n try {\n const errorBody = await clonedResponse.text();\n console.log(\"Error Response Body:\", errorBody);\n } catch (e) {\n console.log(\"Could not read error response body:\", e);\n }\n }\n console.log(\"=== End Travrse Proxy Request ===\\n\");\n }\n\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"Content-Type\":\n response.headers.get(\"content-type\") ?? \"application/json\",\n \"Cache-Control\": \"no-store\"\n }\n });\n });\n\n return app;\n};\n\nexport const createVercelHandler = (options?: ChatProxyOptions) =>\n handle(createChatProxyApp(options));\n\n// Export pre-configured flows\nexport * from \"./flows/index.js\";\n\n// Export utility functions\nexport * from \"./utils/index.js\";\n\nexport default createChatProxyApp;\n\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Basic conversational assistant flow\n * This is the default flow for simple chat interactions\n */\nexport const CONVERSATIONAL_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Shopping assistant flow configuration\n * This flow returns JSON actions for page interaction including:\n * - Simple messages\n * - Navigation with messages\n * - Element clicks with messages\n * - Stripe checkout\n */\nexport const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig = {\n name: \"Shopping Assistant Flow\",\n description: \"Returns JSON actions for page interaction\",\n steps: [\n {\n id: \"action_prompt\",\n name: \"Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\nYou will receive information about the current page's elements (class names and text content)\nand user messages. You must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names provided in the page context\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n\n/**\n * Metadata-based shopping assistant flow configuration\n * This flow uses DOM context from record metadata instead of user message.\n * The metadata should include dom_elements, dom_body, page_url, and page_title.\n */\nexport const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig = {\n name: \"Metadata-Based Shopping Assistant\",\n description: \"Uses DOM context from record metadata for page interaction\",\n steps: [\n {\n id: \"metadata_action_prompt\",\n name: \"Metadata Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\n\nIMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:\n- dom_elements: Array of page elements with className, innerText, and tagName\n- dom_body: Complete HTML body of the page (if provided)\n- page_url: Current page URL\n- page_title: Page title\n\nThe dom_elements array provides information about clickable elements and their text content.\nUse this metadata to understand what's available on the page and help users interact with it.\n\nYou must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names from the dom_elements in the metadata\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","/**\n * Stripe checkout helpers using the REST API\n * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.\n */\n\nexport interface CheckoutItem {\n name: string;\n price: number; // Price in cents\n quantity: number;\n}\n\nexport interface CreateCheckoutSessionOptions {\n secretKey: string;\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n}\n\nexport interface CheckoutSessionResponse {\n success: boolean;\n checkoutUrl?: string;\n sessionId?: string;\n error?: string;\n}\n\n/**\n * Creates a Stripe checkout session using the REST API\n * @param options - Checkout session configuration\n * @returns Checkout session response with URL and session ID\n */\nexport async function createCheckoutSession(\n options: CreateCheckoutSessionOptions\n): Promise<CheckoutSessionResponse> {\n const { secretKey, items, successUrl, cancelUrl } = options;\n\n try {\n // Validate items\n if (!items || !Array.isArray(items) || items.length === 0) {\n return {\n success: false,\n error: \"Items array is required\"\n };\n }\n\n for (const item of items) {\n if (!item.name || typeof item.price !== \"number\" || typeof item.quantity !== \"number\") {\n return {\n success: false,\n error: \"Each item must have name (string), price (number in cents), and quantity (number)\"\n };\n }\n }\n\n // Build line items for URL encoding\n const lineItems = items.map((item) => ({\n price_data: {\n currency: \"usd\",\n product_data: {\n name: item.name,\n },\n unit_amount: item.price,\n },\n quantity: item.quantity,\n }));\n\n // Convert line items to URL-encoded format\n const params = new URLSearchParams({\n \"payment_method_types[0]\": \"card\",\n \"mode\": \"payment\",\n \"success_url\": successUrl,\n \"cancel_url\": cancelUrl,\n });\n\n // Add line items to params\n lineItems.forEach((item, index) => {\n params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);\n params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);\n params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());\n params.append(`line_items[${index}][quantity]`, item.quantity.toString());\n });\n\n // Create Stripe checkout session using REST API\n const stripeResponse = await fetch(\"https://api.stripe.com/v1/checkout/sessions\", {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${secretKey}`,\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: params,\n });\n\n if (!stripeResponse.ok) {\n const errorData = await stripeResponse.text();\n console.error(\"Stripe API error:\", errorData);\n return {\n success: false,\n error: \"Failed to create checkout session\"\n };\n }\n\n const session = await stripeResponse.json() as { url: string; id: string };\n\n return {\n success: true,\n checkoutUrl: session.url,\n sessionId: session.id,\n };\n } catch (error) {\n console.error(\"Stripe checkout error:\", error);\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Failed to create checkout session\"\n };\n }\n}\n"],"mappings":"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","names":["_a","_b"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,56 @@
1
1
  import * as hono_types from 'hono/types';
2
2
  import { Hono } from 'hono';
3
3
 
4
+ /**
5
+ * Basic conversational assistant flow
6
+ * This is the default flow for simple chat interactions
7
+ */
8
+ declare const CONVERSATIONAL_FLOW: TravrseFlowConfig;
9
+
10
+ /**
11
+ * Shopping assistant flow configuration
12
+ * This flow returns JSON actions for page interaction including:
13
+ * - Simple messages
14
+ * - Navigation with messages
15
+ * - Element clicks with messages
16
+ * - Stripe checkout
17
+ */
18
+ declare const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig;
19
+ /**
20
+ * Metadata-based shopping assistant flow configuration
21
+ * This flow uses DOM context from record metadata instead of user message.
22
+ * The metadata should include dom_elements, dom_body, page_url, and page_title.
23
+ */
24
+ declare const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig;
25
+
26
+ /**
27
+ * Stripe checkout helpers using the REST API
28
+ * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.
29
+ */
30
+ interface CheckoutItem {
31
+ name: string;
32
+ price: number;
33
+ quantity: number;
34
+ }
35
+ interface CreateCheckoutSessionOptions {
36
+ secretKey: string;
37
+ items: CheckoutItem[];
38
+ successUrl: string;
39
+ cancelUrl: string;
40
+ }
41
+ interface CheckoutSessionResponse {
42
+ success: boolean;
43
+ checkoutUrl?: string;
44
+ sessionId?: string;
45
+ error?: string;
46
+ }
47
+ /**
48
+ * Creates a Stripe checkout session using the REST API
49
+ * @param options - Checkout session configuration
50
+ * @returns Checkout session response with URL and session ID
51
+ */
52
+ declare function createCheckoutSession(options: CreateCheckoutSessionOptions): Promise<CheckoutSessionResponse>;
53
+
4
54
  type TravrseFlowStep = {
5
55
  id: string;
6
56
  name: string;
@@ -24,4 +74,4 @@ type ChatProxyOptions = {
24
74
  declare const createChatProxyApp: (options?: ChatProxyOptions) => Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
25
75
  declare const createVercelHandler: (options?: ChatProxyOptions) => (req: Request) => Response | Promise<Response>;
26
76
 
27
- export { type ChatProxyOptions, type TravrseFlowConfig, type TravrseFlowStep, createChatProxyApp, createVercelHandler, createChatProxyApp as default };
77
+ export { CONVERSATIONAL_FLOW, type ChatProxyOptions, type CheckoutItem, type CheckoutSessionResponse, type CreateCheckoutSessionOptions, SHOPPING_ASSISTANT_FLOW, SHOPPING_ASSISTANT_METADATA_FLOW, type TravrseFlowConfig, type TravrseFlowStep, createChatProxyApp, createCheckoutSession, createVercelHandler, createChatProxyApp as default };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,56 @@
1
1
  import * as hono_types from 'hono/types';
2
2
  import { Hono } from 'hono';
3
3
 
4
+ /**
5
+ * Basic conversational assistant flow
6
+ * This is the default flow for simple chat interactions
7
+ */
8
+ declare const CONVERSATIONAL_FLOW: TravrseFlowConfig;
9
+
10
+ /**
11
+ * Shopping assistant flow configuration
12
+ * This flow returns JSON actions for page interaction including:
13
+ * - Simple messages
14
+ * - Navigation with messages
15
+ * - Element clicks with messages
16
+ * - Stripe checkout
17
+ */
18
+ declare const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig;
19
+ /**
20
+ * Metadata-based shopping assistant flow configuration
21
+ * This flow uses DOM context from record metadata instead of user message.
22
+ * The metadata should include dom_elements, dom_body, page_url, and page_title.
23
+ */
24
+ declare const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig;
25
+
26
+ /**
27
+ * Stripe checkout helpers using the REST API
28
+ * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.
29
+ */
30
+ interface CheckoutItem {
31
+ name: string;
32
+ price: number;
33
+ quantity: number;
34
+ }
35
+ interface CreateCheckoutSessionOptions {
36
+ secretKey: string;
37
+ items: CheckoutItem[];
38
+ successUrl: string;
39
+ cancelUrl: string;
40
+ }
41
+ interface CheckoutSessionResponse {
42
+ success: boolean;
43
+ checkoutUrl?: string;
44
+ sessionId?: string;
45
+ error?: string;
46
+ }
47
+ /**
48
+ * Creates a Stripe checkout session using the REST API
49
+ * @param options - Checkout session configuration
50
+ * @returns Checkout session response with URL and session ID
51
+ */
52
+ declare function createCheckoutSession(options: CreateCheckoutSessionOptions): Promise<CheckoutSessionResponse>;
53
+
4
54
  type TravrseFlowStep = {
5
55
  id: string;
6
56
  name: string;
@@ -24,4 +74,4 @@ type ChatProxyOptions = {
24
74
  declare const createChatProxyApp: (options?: ChatProxyOptions) => Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
25
75
  declare const createVercelHandler: (options?: ChatProxyOptions) => (req: Request) => Response | Promise<Response>;
26
76
 
27
- export { type ChatProxyOptions, type TravrseFlowConfig, type TravrseFlowStep, createChatProxyApp, createVercelHandler, createChatProxyApp as default };
77
+ export { CONVERSATIONAL_FLOW, type ChatProxyOptions, type CheckoutItem, type CheckoutSessionResponse, type CreateCheckoutSessionOptions, SHOPPING_ASSISTANT_FLOW, SHOPPING_ASSISTANT_METADATA_FLOW, type TravrseFlowConfig, type TravrseFlowStep, createChatProxyApp, createCheckoutSession, createVercelHandler, createChatProxyApp as default };
package/dist/index.js CHANGED
@@ -1,6 +1,258 @@
1
1
  // src/index.ts
2
2
  import { Hono } from "hono";
3
3
  import { handle } from "hono/vercel";
4
+
5
+ // src/flows/conversational.ts
6
+ var CONVERSATIONAL_FLOW = {
7
+ name: "Streaming Prompt Flow",
8
+ description: "Streaming chat generated by the widget",
9
+ steps: [
10
+ {
11
+ id: "widget_prompt",
12
+ name: "Prompt",
13
+ type: "prompt",
14
+ enabled: true,
15
+ config: {
16
+ model: "meta/llama3.1-8b-instruct-free",
17
+ response_format: "markdown",
18
+ output_variable: "prompt_result",
19
+ user_prompt: "{{user_message}}",
20
+ system_prompt: "you are a helpful assistant, chatting with a user",
21
+ previous_messages: "{{messages}}"
22
+ }
23
+ }
24
+ ]
25
+ };
26
+
27
+ // src/flows/shopping-assistant.ts
28
+ var SHOPPING_ASSISTANT_FLOW = {
29
+ name: "Shopping Assistant Flow",
30
+ description: "Returns JSON actions for page interaction",
31
+ steps: [
32
+ {
33
+ id: "action_prompt",
34
+ name: "Action Prompt",
35
+ type: "prompt",
36
+ enabled: true,
37
+ config: {
38
+ model: "qwen/qwen3-8b",
39
+ reasoning: false,
40
+ responseFormat: "JSON",
41
+ outputVariable: "prompt_result",
42
+ userPrompt: "{{user_message}}",
43
+ systemPrompt: `You are a helpful shopping assistant that can interact with web pages.
44
+ You will receive information about the current page's elements (class names and text content)
45
+ and user messages. You must respond with JSON in one of these formats:
46
+
47
+ 1. Simple message:
48
+ {
49
+ "action": "message",
50
+ "text": "Your response text here"
51
+ }
52
+
53
+ 2. Navigate then show message (for navigation to another page):
54
+ {
55
+ "action": "nav_then_click",
56
+ "page": "http://site.com/page-url",
57
+ "on_load_text": "Message to show after navigation"
58
+ }
59
+
60
+ 3. Show message and click an element:
61
+ {
62
+ "action": "message_and_click",
63
+ "element": ".className-of-element",
64
+ "text": "Your message text"
65
+ }
66
+
67
+ 4. Create Stripe checkout:
68
+ {
69
+ "action": "checkout",
70
+ "text": "Your message text",
71
+ "items": [
72
+ {"name": "Product Name", "price": 2999, "quantity": 1}
73
+ ]
74
+ }
75
+
76
+ Guidelines:
77
+ - Use "message" for simple conversational responses
78
+ - Use "nav_then_click" when you need to navigate to a different page (like a product detail page)
79
+ - Use "message_and_click" when you want to click a button or element on the current page
80
+ - Use "checkout" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)
81
+ - When selecting elements, use the class names provided in the page context
82
+ - Always respond with valid JSON only, no additional text
83
+ - For product searches, format results as markdown links: [Product Name](url)
84
+ - Be helpful and conversational in your messages
85
+ - Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)
86
+
87
+ Example conversation flow:
88
+ - User: "I am looking for a black shirt in medium"
89
+ - You: {"action": "message", "text": "Here are the products I found:\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\n\\nWould you like me to navigate to the first result and add it to your cart?"}
90
+
91
+ - User: "No, I would like to add another shirt to the cart"
92
+ - You: {"action": "message_and_click", "element": ".AddToCartButton-blue-shirt-large", "text": "I've added the Blue Shirt - Large to your cart. Ready to checkout?"}
93
+
94
+ - User: "yes"
95
+ - You: {"action": "checkout", "text": "Perfect! I'll set up the checkout for you.", "items": [{"name": "Black Shirt - Medium", "price": 2999, "quantity": 1}]}`,
96
+ previousMessages: "{{messages}}"
97
+ }
98
+ }
99
+ ]
100
+ };
101
+ var SHOPPING_ASSISTANT_METADATA_FLOW = {
102
+ name: "Metadata-Based Shopping Assistant",
103
+ description: "Uses DOM context from record metadata for page interaction",
104
+ steps: [
105
+ {
106
+ id: "metadata_action_prompt",
107
+ name: "Metadata Action Prompt",
108
+ type: "prompt",
109
+ enabled: true,
110
+ config: {
111
+ model: "qwen/qwen3-8b",
112
+ reasoning: false,
113
+ responseFormat: "JSON",
114
+ outputVariable: "prompt_result",
115
+ userPrompt: "{{user_message}}",
116
+ systemPrompt: `You are a helpful shopping assistant that can interact with web pages.
117
+
118
+ IMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:
119
+ - dom_elements: Array of page elements with className, innerText, and tagName
120
+ - dom_body: Complete HTML body of the page (if provided)
121
+ - page_url: Current page URL
122
+ - page_title: Page title
123
+
124
+ The dom_elements array provides information about clickable elements and their text content.
125
+ Use this metadata to understand what's available on the page and help users interact with it.
126
+
127
+ You must respond with JSON in one of these formats:
128
+
129
+ 1. Simple message:
130
+ {
131
+ "action": "message",
132
+ "text": "Your response text here"
133
+ }
134
+
135
+ 2. Navigate then show message (for navigation to another page):
136
+ {
137
+ "action": "nav_then_click",
138
+ "page": "http://site.com/page-url",
139
+ "on_load_text": "Message to show after navigation"
140
+ }
141
+
142
+ 3. Show message and click an element:
143
+ {
144
+ "action": "message_and_click",
145
+ "element": ".className-of-element",
146
+ "text": "Your message text"
147
+ }
148
+
149
+ 4. Create Stripe checkout:
150
+ {
151
+ "action": "checkout",
152
+ "text": "Your message text",
153
+ "items": [
154
+ {"name": "Product Name", "price": 2999, "quantity": 1}
155
+ ]
156
+ }
157
+
158
+ Guidelines:
159
+ - Use "message" for simple conversational responses
160
+ - Use "nav_then_click" when you need to navigate to a different page (like a product detail page)
161
+ - Use "message_and_click" when you want to click a button or element on the current page
162
+ - Use "checkout" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)
163
+ - When selecting elements, use the class names from the dom_elements in the metadata
164
+ - Always respond with valid JSON only, no additional text
165
+ - For product searches, format results as markdown links: [Product Name](url)
166
+ - Be helpful and conversational in your messages
167
+ - Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)
168
+
169
+ Example conversation flow:
170
+ - User: "I am looking for a black shirt in medium"
171
+ - You: {"action": "message", "text": "Here are the products I found:\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\n\\nWould you like me to navigate to the first result and add it to your cart?"}
172
+
173
+ - User: "No, I would like to add another shirt to the cart"
174
+ - You: {"action": "message_and_click", "element": ".AddToCartButton-blue-shirt-large", "text": "I've added the Blue Shirt - Large to your cart. Ready to checkout?"}
175
+
176
+ - User: "yes"
177
+ - You: {"action": "checkout", "text": "Perfect! I'll set up the checkout for you.", "items": [{"name": "Black Shirt - Medium", "price": 2999, "quantity": 1}]}`,
178
+ previousMessages: "{{messages}}"
179
+ }
180
+ }
181
+ ]
182
+ };
183
+
184
+ // src/utils/stripe.ts
185
+ async function createCheckoutSession(options) {
186
+ const { secretKey, items, successUrl, cancelUrl } = options;
187
+ try {
188
+ if (!items || !Array.isArray(items) || items.length === 0) {
189
+ return {
190
+ success: false,
191
+ error: "Items array is required"
192
+ };
193
+ }
194
+ for (const item of items) {
195
+ if (!item.name || typeof item.price !== "number" || typeof item.quantity !== "number") {
196
+ return {
197
+ success: false,
198
+ error: "Each item must have name (string), price (number in cents), and quantity (number)"
199
+ };
200
+ }
201
+ }
202
+ const lineItems = items.map((item) => ({
203
+ price_data: {
204
+ currency: "usd",
205
+ product_data: {
206
+ name: item.name
207
+ },
208
+ unit_amount: item.price
209
+ },
210
+ quantity: item.quantity
211
+ }));
212
+ const params = new URLSearchParams({
213
+ "payment_method_types[0]": "card",
214
+ "mode": "payment",
215
+ "success_url": successUrl,
216
+ "cancel_url": cancelUrl
217
+ });
218
+ lineItems.forEach((item, index) => {
219
+ params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);
220
+ params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);
221
+ params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());
222
+ params.append(`line_items[${index}][quantity]`, item.quantity.toString());
223
+ });
224
+ const stripeResponse = await fetch("https://api.stripe.com/v1/checkout/sessions", {
225
+ method: "POST",
226
+ headers: {
227
+ "Authorization": `Bearer ${secretKey}`,
228
+ "Content-Type": "application/x-www-form-urlencoded"
229
+ },
230
+ body: params
231
+ });
232
+ if (!stripeResponse.ok) {
233
+ const errorData = await stripeResponse.text();
234
+ console.error("Stripe API error:", errorData);
235
+ return {
236
+ success: false,
237
+ error: "Failed to create checkout session"
238
+ };
239
+ }
240
+ const session = await stripeResponse.json();
241
+ return {
242
+ success: true,
243
+ checkoutUrl: session.url,
244
+ sessionId: session.id
245
+ };
246
+ } catch (error) {
247
+ console.error("Stripe checkout error:", error);
248
+ return {
249
+ success: false,
250
+ error: error instanceof Error ? error.message : "Failed to create checkout session"
251
+ };
252
+ }
253
+ }
254
+
255
+ // src/index.ts
4
256
  var DEFAULT_ENDPOINT = "https://api.travrse.ai/v1/dispatch";
5
257
  var DEFAULT_PATH = "/api/chat/dispatch";
6
258
  var DEFAULT_FLOW = {
@@ -86,7 +338,7 @@ var createChatProxyApp = (options = {}) => {
86
338
  record: {
87
339
  name: "Streaming Chat Widget",
88
340
  type: "standalone",
89
- metadata: {}
341
+ metadata: clientPayload.metadata || {}
90
342
  },
91
343
  messages: formattedMessages,
92
344
  options: {
@@ -170,7 +422,11 @@ var createChatProxyApp = (options = {}) => {
170
422
  var createVercelHandler = (options) => handle(createChatProxyApp(options));
171
423
  var index_default = createChatProxyApp;
172
424
  export {
425
+ CONVERSATIONAL_FLOW,
426
+ SHOPPING_ASSISTANT_FLOW,
427
+ SHOPPING_ASSISTANT_METADATA_FLOW,
173
428
  createChatProxyApp,
429
+ createCheckoutSession,
174
430
  createVercelHandler,
175
431
  index_default as default
176
432
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\nimport { handle } from \"hono/vercel\";\n\nexport type TravrseFlowStep = {\n id: string;\n name: string;\n type: string;\n enabled: boolean;\n config: Record<string, unknown>;\n};\n\nexport type TravrseFlowConfig = {\n name: string;\n description: string;\n steps: TravrseFlowStep[];\n};\n\nexport type ChatProxyOptions = {\n upstreamUrl?: string;\n apiKey?: string;\n path?: string;\n allowedOrigins?: string[];\n flowId?: string;\n flowConfig?: TravrseFlowConfig;\n};\n\nconst DEFAULT_ENDPOINT = \"https://api.travrse.ai/v1/dispatch\";\nconst DEFAULT_PATH = \"/api/chat/dispatch\";\n\nconst DEFAULT_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n // model: \"gpt-4o\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n // tools: {\n // tool_ids: [\n // \"builtin:dalle\"\n // ]\n // },\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n\nconst withCors =\n (allowedOrigins: string[] | undefined) =>\n async (c: Context, next: () => Promise<void>) => {\n const origin = c.req.header(\"origin\") ?? \"*\";\n const headers: Record<string, string> = {\n \"Access-Control-Allow-Origin\":\n allowedOrigins && allowedOrigins.length\n ? allowedOrigins.includes(origin)\n ? origin\n : allowedOrigins[0]\n : origin,\n \"Access-Control-Allow-Headers\":\n c.req.header(\"access-control-request-headers\") ??\n \"Content-Type, Authorization\",\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n Vary: \"Origin\"\n };\n\n if (c.req.method === \"OPTIONS\") {\n return new Response(null, { status: 204, headers });\n }\n\n await next();\n Object.entries(headers).forEach(([key, value]) =>\n c.header(key, value, { append: false })\n );\n };\n\nexport const createChatProxyApp = (options: ChatProxyOptions = {}) => {\n const app = new Hono();\n const path = options.path ?? DEFAULT_PATH;\n const upstream = options.upstreamUrl ?? DEFAULT_ENDPOINT;\n\n app.use(\"*\", withCors(options.allowedOrigins));\n\n app.post(path, async (c) => {\n const apiKey = options.apiKey ?? process.env.TRAVRSE_API_KEY;\n if (!apiKey) {\n return c.json(\n { error: \"Missing API key. Set TRAVRSE_API_KEY.\" },\n 401\n );\n }\n\n let clientPayload: {\n messages?: Array<{ role: string; content: string; createdAt?: string }>;\n flowId?: string;\n };\n try {\n clientPayload = await c.req.json();\n } catch (error) {\n return c.json(\n { error: \"Invalid JSON body\", details: error },\n 400\n );\n }\n\n // Build the Travrse payload\n const messages = clientPayload.messages ?? [];\n // Sort messages by timestamp to ensure correct order\n const sortedMessages = [...messages].sort((a, b) => {\n const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n return timeA - timeB;\n });\n const formattedMessages = sortedMessages.map((message) => ({\n role: message.role,\n content: message.content\n }));\n\n // Determine which flow to use\n const flowId = clientPayload.flowId ?? options.flowId;\n const flowConfig = options.flowConfig ?? DEFAULT_FLOW;\n\n const travrsePayload: Record<string, unknown> = {\n record: {\n name: \"Streaming Chat Widget\",\n type: \"standalone\",\n metadata: {}\n },\n messages: formattedMessages,\n options: {\n stream_response: true,\n record_mode: \"virtual\",\n flow_mode: flowId ? \"existing\" : \"virtual\",\n auto_append_metadata: false\n }\n };\n\n // Use flow ID if provided, otherwise use flow config\n if (flowId) {\n travrsePayload.flow = {\n \"name\": \"Chat with 8b\",\n \"description\": \"Flow with 1 step\",\n \"steps\": [\n {\n \"id\": \"step_01k8wnwpdcferbrq79tzj49aec\",\n \"name\": \"Prompt 1\",\n \"type\": \"prompt\",\n \"order\": 0,\n \"enabled\": true,\n \"config\": {\n \"text\": \"{{user_message}}\",\n \"model\": \"qwen/qwen3-8b\",\n // \"tools\": {\n // \"tool_ids\": [\n // \"tool_01k8ky2xpjfzybye5ywcmjr379\",\n // \"builtin:firecrawl\"\n // ]\n // },\n \"reasoning\": false,\n \"user_prompt\": \"{{user_message}}\",\n \"output_variable\": \"prompt_result\",\n \"response_format\": \"JSON\"\n }\n }\n ]\n }\n } else {\n travrsePayload.flow = flowConfig;\n }\n\n // Development logging\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n\n if (isDevelopment) {\n console.log(\"\\n=== Travrse Proxy Request ===\");\n console.log(\"URL:\", upstream);\n console.log(\"API Key Used:\", apiKey ? \"Yes\" : \"No\");\n console.log(\"API Key (first 12 chars):\", apiKey ? apiKey.substring(0, 12) : \"N/A\");\n console.log(\"Request Payload:\", JSON.stringify(travrsePayload, null, 2));\n }\n\n const response = await fetch(upstream, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(travrsePayload)\n });\n\n if (isDevelopment) {\n console.log(\"Response Status:\", response.status);\n console.log(\"Response Status Text:\", response.statusText);\n\n // If there's an error, try to read and log the response body\n if (!response.ok) {\n const clonedResponse = response.clone();\n try {\n const errorBody = await clonedResponse.text();\n console.log(\"Error Response Body:\", errorBody);\n } catch (e) {\n console.log(\"Could not read error response body:\", e);\n }\n }\n console.log(\"=== End Travrse Proxy Request ===\\n\");\n }\n\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"Content-Type\":\n response.headers.get(\"content-type\") ?? \"application/json\",\n \"Cache-Control\": \"no-store\"\n }\n });\n });\n\n return app;\n};\n\nexport const createVercelHandler = (options?: ChatProxyOptions) =>\n handle(createChatProxyApp(options));\n\n\nexport default createChatProxyApp;\n\n"],"mappings":"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","names":["_a","_b"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/flows/conversational.ts","../src/flows/shopping-assistant.ts","../src/utils/stripe.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\nimport { handle } from \"hono/vercel\";\n\nexport type TravrseFlowStep = {\n id: string;\n name: string;\n type: string;\n enabled: boolean;\n config: Record<string, unknown>;\n};\n\nexport type TravrseFlowConfig = {\n name: string;\n description: string;\n steps: TravrseFlowStep[];\n};\n\nexport type ChatProxyOptions = {\n upstreamUrl?: string;\n apiKey?: string;\n path?: string;\n allowedOrigins?: string[];\n flowId?: string;\n flowConfig?: TravrseFlowConfig;\n};\n\nconst DEFAULT_ENDPOINT = \"https://api.travrse.ai/v1/dispatch\";\nconst DEFAULT_PATH = \"/api/chat/dispatch\";\n\nconst DEFAULT_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n // model: \"gpt-4o\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n // tools: {\n // tool_ids: [\n // \"builtin:dalle\"\n // ]\n // },\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n\nconst withCors =\n (allowedOrigins: string[] | undefined) =>\n async (c: Context, next: () => Promise<void>) => {\n const origin = c.req.header(\"origin\") ?? \"*\";\n const headers: Record<string, string> = {\n \"Access-Control-Allow-Origin\":\n allowedOrigins && allowedOrigins.length\n ? allowedOrigins.includes(origin)\n ? origin\n : allowedOrigins[0]\n : origin,\n \"Access-Control-Allow-Headers\":\n c.req.header(\"access-control-request-headers\") ??\n \"Content-Type, Authorization\",\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n Vary: \"Origin\"\n };\n\n if (c.req.method === \"OPTIONS\") {\n return new Response(null, { status: 204, headers });\n }\n\n await next();\n Object.entries(headers).forEach(([key, value]) =>\n c.header(key, value, { append: false })\n );\n };\n\nexport const createChatProxyApp = (options: ChatProxyOptions = {}) => {\n const app = new Hono();\n const path = options.path ?? DEFAULT_PATH;\n const upstream = options.upstreamUrl ?? DEFAULT_ENDPOINT;\n\n app.use(\"*\", withCors(options.allowedOrigins));\n\n app.post(path, async (c) => {\n const apiKey = options.apiKey ?? process.env.TRAVRSE_API_KEY;\n if (!apiKey) {\n return c.json(\n { error: \"Missing API key. Set TRAVRSE_API_KEY.\" },\n 401\n );\n }\n\n let clientPayload: {\n messages?: Array<{ role: string; content: string; createdAt?: string }>;\n flowId?: string;\n metadata?: Record<string, unknown>;\n };\n try {\n clientPayload = await c.req.json();\n } catch (error) {\n return c.json(\n { error: \"Invalid JSON body\", details: error },\n 400\n );\n }\n\n // Build the Travrse payload\n const messages = clientPayload.messages ?? [];\n // Sort messages by timestamp to ensure correct order\n const sortedMessages = [...messages].sort((a, b) => {\n const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n return timeA - timeB;\n });\n const formattedMessages = sortedMessages.map((message) => ({\n role: message.role,\n content: message.content\n }));\n\n // Determine which flow to use\n const flowId = clientPayload.flowId ?? options.flowId;\n const flowConfig = options.flowConfig ?? DEFAULT_FLOW;\n\n const travrsePayload: Record<string, unknown> = {\n record: {\n name: \"Streaming Chat Widget\",\n type: \"standalone\",\n metadata: clientPayload.metadata || {}\n },\n messages: formattedMessages,\n options: {\n stream_response: true,\n record_mode: \"virtual\",\n flow_mode: flowId ? \"existing\" : \"virtual\",\n auto_append_metadata: false\n }\n };\n\n // Use flow ID if provided, otherwise use flow config\n if (flowId) {\n travrsePayload.flow = {\n \"name\": \"Chat with 8b\",\n \"description\": \"Flow with 1 step\",\n \"steps\": [\n {\n \"id\": \"step_01k8wnwpdcferbrq79tzj49aec\",\n \"name\": \"Prompt 1\",\n \"type\": \"prompt\",\n \"order\": 0,\n \"enabled\": true,\n \"config\": {\n \"text\": \"{{user_message}}\",\n \"model\": \"qwen/qwen3-8b\",\n // \"tools\": {\n // \"tool_ids\": [\n // \"tool_01k8ky2xpjfzybye5ywcmjr379\",\n // \"builtin:firecrawl\"\n // ]\n // },\n \"reasoning\": false,\n \"user_prompt\": \"{{user_message}}\",\n \"output_variable\": \"prompt_result\",\n \"response_format\": \"JSON\"\n }\n }\n ]\n }\n } else {\n travrsePayload.flow = flowConfig;\n }\n\n // Development logging\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n\n if (isDevelopment) {\n console.log(\"\\n=== Travrse Proxy Request ===\");\n console.log(\"URL:\", upstream);\n console.log(\"API Key Used:\", apiKey ? \"Yes\" : \"No\");\n console.log(\"API Key (first 12 chars):\", apiKey ? apiKey.substring(0, 12) : \"N/A\");\n console.log(\"Request Payload:\", JSON.stringify(travrsePayload, null, 2));\n }\n\n const response = await fetch(upstream, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(travrsePayload)\n });\n\n if (isDevelopment) {\n console.log(\"Response Status:\", response.status);\n console.log(\"Response Status Text:\", response.statusText);\n\n // If there's an error, try to read and log the response body\n if (!response.ok) {\n const clonedResponse = response.clone();\n try {\n const errorBody = await clonedResponse.text();\n console.log(\"Error Response Body:\", errorBody);\n } catch (e) {\n console.log(\"Could not read error response body:\", e);\n }\n }\n console.log(\"=== End Travrse Proxy Request ===\\n\");\n }\n\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"Content-Type\":\n response.headers.get(\"content-type\") ?? \"application/json\",\n \"Cache-Control\": \"no-store\"\n }\n });\n });\n\n return app;\n};\n\nexport const createVercelHandler = (options?: ChatProxyOptions) =>\n handle(createChatProxyApp(options));\n\n// Export pre-configured flows\nexport * from \"./flows/index.js\";\n\n// Export utility functions\nexport * from \"./utils/index.js\";\n\nexport default createChatProxyApp;\n\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Basic conversational assistant flow\n * This is the default flow for simple chat interactions\n */\nexport const CONVERSATIONAL_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Shopping assistant flow configuration\n * This flow returns JSON actions for page interaction including:\n * - Simple messages\n * - Navigation with messages\n * - Element clicks with messages\n * - Stripe checkout\n */\nexport const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig = {\n name: \"Shopping Assistant Flow\",\n description: \"Returns JSON actions for page interaction\",\n steps: [\n {\n id: \"action_prompt\",\n name: \"Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\nYou will receive information about the current page's elements (class names and text content)\nand user messages. You must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names provided in the page context\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n\n/**\n * Metadata-based shopping assistant flow configuration\n * This flow uses DOM context from record metadata instead of user message.\n * The metadata should include dom_elements, dom_body, page_url, and page_title.\n */\nexport const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig = {\n name: \"Metadata-Based Shopping Assistant\",\n description: \"Uses DOM context from record metadata for page interaction\",\n steps: [\n {\n id: \"metadata_action_prompt\",\n name: \"Metadata Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\n\nIMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:\n- dom_elements: Array of page elements with className, innerText, and tagName\n- dom_body: Complete HTML body of the page (if provided)\n- page_url: Current page URL\n- page_title: Page title\n\nThe dom_elements array provides information about clickable elements and their text content.\nUse this metadata to understand what's available on the page and help users interact with it.\n\nYou must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names from the dom_elements in the metadata\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","/**\n * Stripe checkout helpers using the REST API\n * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.\n */\n\nexport interface CheckoutItem {\n name: string;\n price: number; // Price in cents\n quantity: number;\n}\n\nexport interface CreateCheckoutSessionOptions {\n secretKey: string;\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n}\n\nexport interface CheckoutSessionResponse {\n success: boolean;\n checkoutUrl?: string;\n sessionId?: string;\n error?: string;\n}\n\n/**\n * Creates a Stripe checkout session using the REST API\n * @param options - Checkout session configuration\n * @returns Checkout session response with URL and session ID\n */\nexport async function createCheckoutSession(\n options: CreateCheckoutSessionOptions\n): Promise<CheckoutSessionResponse> {\n const { secretKey, items, successUrl, cancelUrl } = options;\n\n try {\n // Validate items\n if (!items || !Array.isArray(items) || items.length === 0) {\n return {\n success: false,\n error: \"Items array is required\"\n };\n }\n\n for (const item of items) {\n if (!item.name || typeof item.price !== \"number\" || typeof item.quantity !== \"number\") {\n return {\n success: false,\n error: \"Each item must have name (string), price (number in cents), and quantity (number)\"\n };\n }\n }\n\n // Build line items for URL encoding\n const lineItems = items.map((item) => ({\n price_data: {\n currency: \"usd\",\n product_data: {\n name: item.name,\n },\n unit_amount: item.price,\n },\n quantity: item.quantity,\n }));\n\n // Convert line items to URL-encoded format\n const params = new URLSearchParams({\n \"payment_method_types[0]\": \"card\",\n \"mode\": \"payment\",\n \"success_url\": successUrl,\n \"cancel_url\": cancelUrl,\n });\n\n // Add line items to params\n lineItems.forEach((item, index) => {\n params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);\n params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);\n params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());\n params.append(`line_items[${index}][quantity]`, item.quantity.toString());\n });\n\n // Create Stripe checkout session using REST API\n const stripeResponse = await fetch(\"https://api.stripe.com/v1/checkout/sessions\", {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${secretKey}`,\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: params,\n });\n\n if (!stripeResponse.ok) {\n const errorData = await stripeResponse.text();\n console.error(\"Stripe API error:\", errorData);\n return {\n success: false,\n error: \"Failed to create checkout session\"\n };\n }\n\n const session = await stripeResponse.json() as { url: string; id: string };\n\n return {\n success: true,\n checkoutUrl: session.url,\n sessionId: session.id,\n };\n } catch (error) {\n console.error(\"Stripe checkout error:\", error);\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Failed to create checkout session\"\n };\n }\n}\n"],"mappings":"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","names":["_a","_b"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanilla-agent-proxy",
3
- "version": "0.2.0",
3
+ "version": "1.0.0",
4
4
  "description": "Proxy server for vanilla-agent widget - handles flow configuration and forwards requests to Travrse or other AI backends.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -0,0 +1,26 @@
1
+ import type { TravrseFlowConfig } from "../index.js";
2
+
3
+ /**
4
+ * Basic conversational assistant flow
5
+ * This is the default flow for simple chat interactions
6
+ */
7
+ export const CONVERSATIONAL_FLOW: TravrseFlowConfig = {
8
+ name: "Streaming Prompt Flow",
9
+ description: "Streaming chat generated by the widget",
10
+ steps: [
11
+ {
12
+ id: "widget_prompt",
13
+ name: "Prompt",
14
+ type: "prompt",
15
+ enabled: true,
16
+ config: {
17
+ model: "meta/llama3.1-8b-instruct-free",
18
+ response_format: "markdown",
19
+ output_variable: "prompt_result",
20
+ user_prompt: "{{user_message}}",
21
+ system_prompt: "you are a helpful assistant, chatting with a user",
22
+ previous_messages: "{{messages}}"
23
+ }
24
+ }
25
+ ]
26
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Pre-configured flow templates for common use cases
3
+ */
4
+
5
+ export { CONVERSATIONAL_FLOW } from "./conversational.js";
6
+ export {
7
+ SHOPPING_ASSISTANT_FLOW,
8
+ SHOPPING_ASSISTANT_METADATA_FLOW
9
+ } from "./shopping-assistant.js";
@@ -0,0 +1,171 @@
1
+ import type { TravrseFlowConfig } from "../index.js";
2
+
3
+ /**
4
+ * Shopping assistant flow configuration
5
+ * This flow returns JSON actions for page interaction including:
6
+ * - Simple messages
7
+ * - Navigation with messages
8
+ * - Element clicks with messages
9
+ * - Stripe checkout
10
+ */
11
+ export const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig = {
12
+ name: "Shopping Assistant Flow",
13
+ description: "Returns JSON actions for page interaction",
14
+ steps: [
15
+ {
16
+ id: "action_prompt",
17
+ name: "Action Prompt",
18
+ type: "prompt",
19
+ enabled: true,
20
+ config: {
21
+ model: "qwen/qwen3-8b",
22
+ reasoning: false,
23
+ responseFormat: "JSON",
24
+ outputVariable: "prompt_result",
25
+ userPrompt: "{{user_message}}",
26
+ systemPrompt: `You are a helpful shopping assistant that can interact with web pages.
27
+ You will receive information about the current page's elements (class names and text content)
28
+ and user messages. You must respond with JSON in one of these formats:
29
+
30
+ 1. Simple message:
31
+ {
32
+ "action": "message",
33
+ "text": "Your response text here"
34
+ }
35
+
36
+ 2. Navigate then show message (for navigation to another page):
37
+ {
38
+ "action": "nav_then_click",
39
+ "page": "http://site.com/page-url",
40
+ "on_load_text": "Message to show after navigation"
41
+ }
42
+
43
+ 3. Show message and click an element:
44
+ {
45
+ "action": "message_and_click",
46
+ "element": ".className-of-element",
47
+ "text": "Your message text"
48
+ }
49
+
50
+ 4. Create Stripe checkout:
51
+ {
52
+ "action": "checkout",
53
+ "text": "Your message text",
54
+ "items": [
55
+ {"name": "Product Name", "price": 2999, "quantity": 1}
56
+ ]
57
+ }
58
+
59
+ Guidelines:
60
+ - Use "message" for simple conversational responses
61
+ - Use "nav_then_click" when you need to navigate to a different page (like a product detail page)
62
+ - Use "message_and_click" when you want to click a button or element on the current page
63
+ - Use "checkout" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)
64
+ - When selecting elements, use the class names provided in the page context
65
+ - Always respond with valid JSON only, no additional text
66
+ - For product searches, format results as markdown links: [Product Name](url)
67
+ - Be helpful and conversational in your messages
68
+ - Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)
69
+
70
+ Example conversation flow:
71
+ - User: "I am looking for a black shirt in medium"
72
+ - You: {"action": "message", "text": "Here are the products I found:\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\n\\nWould you like me to navigate to the first result and add it to your cart?"}
73
+
74
+ - User: "No, I would like to add another shirt to the cart"
75
+ - You: {"action": "message_and_click", "element": ".AddToCartButton-blue-shirt-large", "text": "I've added the Blue Shirt - Large to your cart. Ready to checkout?"}
76
+
77
+ - User: "yes"
78
+ - You: {"action": "checkout", "text": "Perfect! I'll set up the checkout for you.", "items": [{"name": "Black Shirt - Medium", "price": 2999, "quantity": 1}]}`,
79
+ previousMessages: "{{messages}}"
80
+ }
81
+ }
82
+ ]
83
+ };
84
+
85
+ /**
86
+ * Metadata-based shopping assistant flow configuration
87
+ * This flow uses DOM context from record metadata instead of user message.
88
+ * The metadata should include dom_elements, dom_body, page_url, and page_title.
89
+ */
90
+ export const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig = {
91
+ name: "Metadata-Based Shopping Assistant",
92
+ description: "Uses DOM context from record metadata for page interaction",
93
+ steps: [
94
+ {
95
+ id: "metadata_action_prompt",
96
+ name: "Metadata Action Prompt",
97
+ type: "prompt",
98
+ enabled: true,
99
+ config: {
100
+ model: "qwen/qwen3-8b",
101
+ reasoning: false,
102
+ responseFormat: "JSON",
103
+ outputVariable: "prompt_result",
104
+ userPrompt: "{{user_message}}",
105
+ systemPrompt: `You are a helpful shopping assistant that can interact with web pages.
106
+
107
+ IMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:
108
+ - dom_elements: Array of page elements with className, innerText, and tagName
109
+ - dom_body: Complete HTML body of the page (if provided)
110
+ - page_url: Current page URL
111
+ - page_title: Page title
112
+
113
+ The dom_elements array provides information about clickable elements and their text content.
114
+ Use this metadata to understand what's available on the page and help users interact with it.
115
+
116
+ You must respond with JSON in one of these formats:
117
+
118
+ 1. Simple message:
119
+ {
120
+ "action": "message",
121
+ "text": "Your response text here"
122
+ }
123
+
124
+ 2. Navigate then show message (for navigation to another page):
125
+ {
126
+ "action": "nav_then_click",
127
+ "page": "http://site.com/page-url",
128
+ "on_load_text": "Message to show after navigation"
129
+ }
130
+
131
+ 3. Show message and click an element:
132
+ {
133
+ "action": "message_and_click",
134
+ "element": ".className-of-element",
135
+ "text": "Your message text"
136
+ }
137
+
138
+ 4. Create Stripe checkout:
139
+ {
140
+ "action": "checkout",
141
+ "text": "Your message text",
142
+ "items": [
143
+ {"name": "Product Name", "price": 2999, "quantity": 1}
144
+ ]
145
+ }
146
+
147
+ Guidelines:
148
+ - Use "message" for simple conversational responses
149
+ - Use "nav_then_click" when you need to navigate to a different page (like a product detail page)
150
+ - Use "message_and_click" when you want to click a button or element on the current page
151
+ - Use "checkout" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)
152
+ - When selecting elements, use the class names from the dom_elements in the metadata
153
+ - Always respond with valid JSON only, no additional text
154
+ - For product searches, format results as markdown links: [Product Name](url)
155
+ - Be helpful and conversational in your messages
156
+ - Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)
157
+
158
+ Example conversation flow:
159
+ - User: "I am looking for a black shirt in medium"
160
+ - You: {"action": "message", "text": "Here are the products I found:\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\n\\nWould you like me to navigate to the first result and add it to your cart?"}
161
+
162
+ - User: "No, I would like to add another shirt to the cart"
163
+ - You: {"action": "message_and_click", "element": ".AddToCartButton-blue-shirt-large", "text": "I've added the Blue Shirt - Large to your cart. Ready to checkout?"}
164
+
165
+ - User: "yes"
166
+ - You: {"action": "checkout", "text": "Perfect! I'll set up the checkout for you.", "items": [{"name": "Black Shirt - Medium", "price": 2999, "quantity": 1}]}`,
167
+ previousMessages: "{{messages}}"
168
+ }
169
+ }
170
+ ]
171
+ };
package/src/index.ts CHANGED
@@ -102,6 +102,7 @@ export const createChatProxyApp = (options: ChatProxyOptions = {}) => {
102
102
  let clientPayload: {
103
103
  messages?: Array<{ role: string; content: string; createdAt?: string }>;
104
104
  flowId?: string;
105
+ metadata?: Record<string, unknown>;
105
106
  };
106
107
  try {
107
108
  clientPayload = await c.req.json();
@@ -133,7 +134,7 @@ export const createChatProxyApp = (options: ChatProxyOptions = {}) => {
133
134
  record: {
134
135
  name: "Streaming Chat Widget",
135
136
  type: "standalone",
136
- metadata: {}
137
+ metadata: clientPayload.metadata || {}
137
138
  },
138
139
  messages: formattedMessages,
139
140
  options: {
@@ -230,6 +231,11 @@ export const createChatProxyApp = (options: ChatProxyOptions = {}) => {
230
231
  export const createVercelHandler = (options?: ChatProxyOptions) =>
231
232
  handle(createChatProxyApp(options));
232
233
 
234
+ // Export pre-configured flows
235
+ export * from "./flows/index.js";
236
+
237
+ // Export utility functions
238
+ export * from "./utils/index.js";
233
239
 
234
240
  export default createChatProxyApp;
235
241
 
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Utility functions for proxy implementations
3
+ */
4
+
5
+ export {
6
+ createCheckoutSession,
7
+ type CheckoutItem,
8
+ type CreateCheckoutSessionOptions,
9
+ type CheckoutSessionResponse
10
+ } from "./stripe.js";
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Stripe checkout helpers using the REST API
3
+ * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.
4
+ */
5
+
6
+ export interface CheckoutItem {
7
+ name: string;
8
+ price: number; // Price in cents
9
+ quantity: number;
10
+ }
11
+
12
+ export interface CreateCheckoutSessionOptions {
13
+ secretKey: string;
14
+ items: CheckoutItem[];
15
+ successUrl: string;
16
+ cancelUrl: string;
17
+ }
18
+
19
+ export interface CheckoutSessionResponse {
20
+ success: boolean;
21
+ checkoutUrl?: string;
22
+ sessionId?: string;
23
+ error?: string;
24
+ }
25
+
26
+ /**
27
+ * Creates a Stripe checkout session using the REST API
28
+ * @param options - Checkout session configuration
29
+ * @returns Checkout session response with URL and session ID
30
+ */
31
+ export async function createCheckoutSession(
32
+ options: CreateCheckoutSessionOptions
33
+ ): Promise<CheckoutSessionResponse> {
34
+ const { secretKey, items, successUrl, cancelUrl } = options;
35
+
36
+ try {
37
+ // Validate items
38
+ if (!items || !Array.isArray(items) || items.length === 0) {
39
+ return {
40
+ success: false,
41
+ error: "Items array is required"
42
+ };
43
+ }
44
+
45
+ for (const item of items) {
46
+ if (!item.name || typeof item.price !== "number" || typeof item.quantity !== "number") {
47
+ return {
48
+ success: false,
49
+ error: "Each item must have name (string), price (number in cents), and quantity (number)"
50
+ };
51
+ }
52
+ }
53
+
54
+ // Build line items for URL encoding
55
+ const lineItems = items.map((item) => ({
56
+ price_data: {
57
+ currency: "usd",
58
+ product_data: {
59
+ name: item.name,
60
+ },
61
+ unit_amount: item.price,
62
+ },
63
+ quantity: item.quantity,
64
+ }));
65
+
66
+ // Convert line items to URL-encoded format
67
+ const params = new URLSearchParams({
68
+ "payment_method_types[0]": "card",
69
+ "mode": "payment",
70
+ "success_url": successUrl,
71
+ "cancel_url": cancelUrl,
72
+ });
73
+
74
+ // Add line items to params
75
+ lineItems.forEach((item, index) => {
76
+ params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);
77
+ params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);
78
+ params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());
79
+ params.append(`line_items[${index}][quantity]`, item.quantity.toString());
80
+ });
81
+
82
+ // Create Stripe checkout session using REST API
83
+ const stripeResponse = await fetch("https://api.stripe.com/v1/checkout/sessions", {
84
+ method: "POST",
85
+ headers: {
86
+ "Authorization": `Bearer ${secretKey}`,
87
+ "Content-Type": "application/x-www-form-urlencoded",
88
+ },
89
+ body: params,
90
+ });
91
+
92
+ if (!stripeResponse.ok) {
93
+ const errorData = await stripeResponse.text();
94
+ console.error("Stripe API error:", errorData);
95
+ return {
96
+ success: false,
97
+ error: "Failed to create checkout session"
98
+ };
99
+ }
100
+
101
+ const session = await stripeResponse.json() as { url: string; id: string };
102
+
103
+ return {
104
+ success: true,
105
+ checkoutUrl: session.url,
106
+ sessionId: session.id,
107
+ };
108
+ } catch (error) {
109
+ console.error("Stripe checkout error:", error);
110
+ return {
111
+ success: false,
112
+ error: error instanceof Error ? error.message : "Failed to create checkout session"
113
+ };
114
+ }
115
+ }