whale-code 6.5.7 → 6.5.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +14 -2
  2. package/dist/cli/services/agent-loop.js +26 -2
  3. package/dist/cli/services/agent-loop.js.map +1 -1
  4. package/dist/cli/services/hooks.js +2 -1
  5. package/dist/cli/services/hooks.js.map +1 -1
  6. package/dist/cli/services/telemetry-spans.js +1 -0
  7. package/dist/cli/services/telemetry-spans.js.map +1 -1
  8. package/dist/cli/services/telemetry.d.ts +23 -0
  9. package/dist/cli/services/telemetry.js +45 -1
  10. package/dist/cli/services/telemetry.js.map +1 -1
  11. package/dist/server/handlers/__test-utils__/test-db.d.ts +17 -3
  12. package/dist/server/handlers/__test-utils__/test-db.js +113 -14
  13. package/dist/server/handlers/__test-utils__/test-db.js.map +1 -1
  14. package/dist/server/handlers/affiliates.d.ts +9 -0
  15. package/dist/server/handlers/affiliates.js +197 -0
  16. package/dist/server/handlers/affiliates.js.map +1 -0
  17. package/dist/server/handlers/api-docs.d.ts +4 -2
  18. package/dist/server/handlers/api-docs.js +204 -1681
  19. package/dist/server/handlers/api-docs.js.map +1 -1
  20. package/dist/server/handlers/campaigns.d.ts +9 -0
  21. package/dist/server/handlers/campaigns.js +237 -0
  22. package/dist/server/handlers/campaigns.js.map +1 -0
  23. package/dist/server/handlers/catalog-schemas.js +9 -9
  24. package/dist/server/handlers/catalog-schemas.js.map +1 -1
  25. package/dist/server/handlers/catalog.js +1 -1
  26. package/dist/server/handlers/catalog.js.map +1 -1
  27. package/dist/server/handlers/comms-documents.js +28 -2
  28. package/dist/server/handlers/comms-documents.js.map +1 -1
  29. package/dist/server/handlers/comms-pdf-generation.js +25 -3
  30. package/dist/server/handlers/comms-pdf-generation.js.map +1 -1
  31. package/dist/server/handlers/comms-pdf-helpers.js +4 -4
  32. package/dist/server/handlers/comms-pdf-helpers.js.map +1 -1
  33. package/dist/server/handlers/comms.d.ts +100 -0
  34. package/dist/server/handlers/comms.js +146 -12
  35. package/dist/server/handlers/comms.js.map +1 -1
  36. package/dist/server/handlers/coupons.d.ts +9 -0
  37. package/dist/server/handlers/coupons.js +220 -0
  38. package/dist/server/handlers/coupons.js.map +1 -0
  39. package/dist/server/handlers/embeddings.js +1 -1
  40. package/dist/server/handlers/embeddings.js.map +1 -1
  41. package/dist/server/handlers/enrichment.js +2 -622
  42. package/dist/server/handlers/enrichment.js.map +1 -1
  43. package/dist/server/handlers/fulfillment.d.ts +9 -0
  44. package/dist/server/handlers/fulfillment.js +209 -0
  45. package/dist/server/handlers/fulfillment.js.map +1 -0
  46. package/dist/server/handlers/google-ads.d.ts +24 -0
  47. package/dist/server/handlers/google-ads.js +2199 -0
  48. package/dist/server/handlers/google-ads.js.map +1 -0
  49. package/dist/server/handlers/invoices.d.ts +9 -0
  50. package/dist/server/handlers/invoices.js +252 -0
  51. package/dist/server/handlers/invoices.js.map +1 -0
  52. package/dist/server/handlers/loyalty.d.ts +9 -0
  53. package/dist/server/handlers/loyalty.js +197 -0
  54. package/dist/server/handlers/loyalty.js.map +1 -0
  55. package/dist/server/handlers/meta-ads-graph-api.js +18 -3
  56. package/dist/server/handlers/meta-ads-graph-api.js.map +1 -1
  57. package/dist/server/handlers/phone.d.ts +9 -0
  58. package/dist/server/handlers/phone.js +197 -0
  59. package/dist/server/handlers/phone.js.map +1 -0
  60. package/dist/server/handlers/pipeline.d.ts +9 -0
  61. package/dist/server/handlers/pipeline.js +277 -0
  62. package/dist/server/handlers/pipeline.js.map +1 -0
  63. package/dist/server/handlers/qr-codes.d.ts +9 -0
  64. package/dist/server/handlers/qr-codes.js +198 -0
  65. package/dist/server/handlers/qr-codes.js.map +1 -0
  66. package/dist/server/handlers/reviews.d.ts +9 -0
  67. package/dist/server/handlers/reviews.js +171 -0
  68. package/dist/server/handlers/reviews.js.map +1 -0
  69. package/dist/server/handlers/segments.d.ts +9 -0
  70. package/dist/server/handlers/segments.js +229 -0
  71. package/dist/server/handlers/segments.js.map +1 -0
  72. package/dist/server/handlers/social.d.ts +9 -0
  73. package/dist/server/handlers/social.js +81 -0
  74. package/dist/server/handlers/social.js.map +1 -0
  75. package/dist/server/handlers/tax.d.ts +9 -0
  76. package/dist/server/handlers/tax.js +182 -0
  77. package/dist/server/handlers/tax.js.map +1 -0
  78. package/dist/server/handlers/wallet.d.ts +9 -0
  79. package/dist/server/handlers/wallet.js +203 -0
  80. package/dist/server/handlers/wallet.js.map +1 -0
  81. package/dist/server/handlers/webhooks-mgmt.d.ts +9 -0
  82. package/dist/server/handlers/webhooks-mgmt.js +181 -0
  83. package/dist/server/handlers/webhooks-mgmt.js.map +1 -0
  84. package/dist/server/handlers/wholesale.d.ts +9 -0
  85. package/dist/server/handlers/wholesale.js +219 -0
  86. package/dist/server/handlers/wholesale.js.map +1 -0
  87. package/dist/server/index.js +20 -9
  88. package/dist/server/index.js.map +1 -1
  89. package/dist/server/lib/clickhouse-buffer.js +1 -0
  90. package/dist/server/lib/clickhouse-buffer.js.map +1 -1
  91. package/dist/server/lib/coa-renderer.d.ts +1 -1
  92. package/dist/server/lib/coa-renderer.js +32 -10
  93. package/dist/server/lib/coa-renderer.js.map +1 -1
  94. package/dist/server/server-worker.d.ts +1 -0
  95. package/dist/server/server-worker.js +464 -3
  96. package/dist/server/server-worker.js.map +1 -1
  97. package/dist/server/tool-router.js +118 -4
  98. package/dist/server/tool-router.js.map +1 -1
  99. package/package.json +28 -4
  100. package/vendor/ink/package.json +0 -2
  101. package/whale-logo.png +0 -0
@@ -0,0 +1,220 @@
1
+ // server/handlers/coupons.ts — Coupon code management (create, list, validate)
2
+
3
+ import { sanitizeFilterValue } from "../lib/utils.js";
4
+ export async function handleCoupons(sb, args, storeId) {
5
+ const sid = storeId;
6
+ switch (args.action) {
7
+ // ---- LIST: list coupons with optional filters ----
8
+ case "list":
9
+ {
10
+ let q = sb.from("coupons").select("*").eq("store_id", sid).order("created_at", {
11
+ ascending: false
12
+ });
13
+ if (args.is_active !== undefined) q = q.eq("is_active", args.is_active);
14
+ if (args.discount_type) q = q.eq("discount_type", args.discount_type);
15
+ if (args.query) {
16
+ const sq = sanitizeFilterValue(String(args.query));
17
+ q = q.or(`code.ilike.%${sq}%,description.ilike.%${sq}%`);
18
+ }
19
+ q = q.limit(args.limit || 50);
20
+ const {
21
+ data,
22
+ error
23
+ } = await q;
24
+ return error ? {
25
+ success: false,
26
+ error: error.message
27
+ } : {
28
+ success: true,
29
+ count: data?.length,
30
+ data
31
+ };
32
+ }
33
+
34
+ // ---- GET: get a single coupon by ID ----
35
+ case "get":
36
+ {
37
+ const couponId = args.coupon_id;
38
+ if (!couponId) return {
39
+ success: false,
40
+ error: "coupon_id is required"
41
+ };
42
+ const {
43
+ data,
44
+ error
45
+ } = await sb.from("coupons").select("*").eq("id", couponId).eq("store_id", sid).single();
46
+ if (error) return {
47
+ success: false,
48
+ error: error.message
49
+ };
50
+
51
+ // Include usage stats
52
+ const {
53
+ data: usage
54
+ } = await sb.from("coupon_usage").select("id, customer_id, order_id, discount_amount, created_at").eq("coupon_id", couponId).order("created_at", {
55
+ ascending: false
56
+ }).limit(20);
57
+ return {
58
+ success: true,
59
+ data: {
60
+ ...data,
61
+ recent_usage: usage || []
62
+ }
63
+ };
64
+ }
65
+
66
+ // ---- CREATE: create a new coupon ----
67
+ case "create":
68
+ {
69
+ const code = args.code;
70
+ const discountType = args.discount_type;
71
+ const discountAmount = args.discount_amount;
72
+ if (!code || !discountType || discountAmount === undefined) {
73
+ return {
74
+ success: false,
75
+ error: "code, discount_type, and discount_amount are required"
76
+ };
77
+ }
78
+ const record = {
79
+ store_id: sid,
80
+ code: code.toUpperCase(),
81
+ discount_type: discountType,
82
+ discount_amount: discountAmount
83
+ };
84
+ if (args.description !== undefined) record.description = args.description;
85
+ if (args.free_shipping !== undefined) record.free_shipping = args.free_shipping;
86
+ if (args.minimum_amount !== undefined) record.minimum_amount = args.minimum_amount;
87
+ if (args.maximum_amount !== undefined) record.maximum_amount = args.maximum_amount;
88
+ if (args.usage_limit !== undefined) record.usage_limit = args.usage_limit;
89
+ if (args.usage_limit_per_user !== undefined) record.usage_limit_per_user = args.usage_limit_per_user;
90
+ if (args.individual_use !== undefined) record.individual_use = args.individual_use;
91
+ if (args.exclude_sale_items !== undefined) record.exclude_sale_items = args.exclude_sale_items;
92
+ if (args.start_date !== undefined) record.start_date = args.start_date;
93
+ if (args.end_date !== undefined) record.end_date = args.end_date;
94
+ if (args.allowed_products !== undefined) record.allowed_products = args.allowed_products;
95
+ if (args.excluded_products !== undefined) record.excluded_products = args.excluded_products;
96
+ if (args.allowed_categories !== undefined) record.allowed_categories = args.allowed_categories;
97
+ if (args.excluded_categories !== undefined) record.excluded_categories = args.excluded_categories;
98
+ if (args.allowed_emails !== undefined) record.allowed_emails = args.allowed_emails;
99
+ const {
100
+ data,
101
+ error
102
+ } = await sb.from("coupons").insert(record).select().single();
103
+ return error ? {
104
+ success: false,
105
+ error: error.message
106
+ } : {
107
+ success: true,
108
+ data
109
+ };
110
+ }
111
+
112
+ // ---- UPDATE: modify a coupon ----
113
+ case "update":
114
+ {
115
+ const couponId = args.coupon_id;
116
+ if (!couponId) return {
117
+ success: false,
118
+ error: "coupon_id is required"
119
+ };
120
+ const updates = {
121
+ updated_at: new Date().toISOString()
122
+ };
123
+ if (args.code !== undefined) updates.code = args.code.toUpperCase();
124
+ if (args.description !== undefined) updates.description = args.description;
125
+ if (args.discount_type !== undefined) updates.discount_type = args.discount_type;
126
+ if (args.discount_amount !== undefined) updates.discount_amount = args.discount_amount;
127
+ if (args.is_active !== undefined) updates.is_active = args.is_active;
128
+ if (args.free_shipping !== undefined) updates.free_shipping = args.free_shipping;
129
+ if (args.minimum_amount !== undefined) updates.minimum_amount = args.minimum_amount;
130
+ if (args.maximum_amount !== undefined) updates.maximum_amount = args.maximum_amount;
131
+ if (args.usage_limit !== undefined) updates.usage_limit = args.usage_limit;
132
+ if (args.start_date !== undefined) updates.start_date = args.start_date;
133
+ if (args.end_date !== undefined) updates.end_date = args.end_date;
134
+ const {
135
+ data,
136
+ error
137
+ } = await sb.from("coupons").update(updates).eq("id", couponId).eq("store_id", sid).select().single();
138
+ return error ? {
139
+ success: false,
140
+ error: error.message
141
+ } : {
142
+ success: true,
143
+ data
144
+ };
145
+ }
146
+
147
+ // ---- VALIDATE: check if a coupon code is valid for use ----
148
+ case "validate":
149
+ {
150
+ const code = args.code;
151
+ if (!code) return {
152
+ success: false,
153
+ error: "code is required"
154
+ };
155
+ const {
156
+ data: coupon,
157
+ error
158
+ } = await sb.from("coupons").select("*").eq("code", code.toUpperCase()).eq("store_id", sid).maybeSingle();
159
+ if (error) return {
160
+ success: false,
161
+ error: error.message
162
+ };
163
+ if (!coupon) return {
164
+ success: false,
165
+ error: "Coupon code not found"
166
+ };
167
+ const now = new Date();
168
+ const issues = [];
169
+ if (!coupon.is_active) issues.push("Coupon is inactive");
170
+ if (coupon.start_date && new Date(coupon.start_date) > now) issues.push("Coupon has not started yet");
171
+ if (coupon.end_date && new Date(coupon.end_date) < now) issues.push("Coupon has expired");
172
+ if (coupon.usage_limit && coupon.usage_count >= coupon.usage_limit) issues.push("Usage limit reached");
173
+ return {
174
+ success: true,
175
+ data: {
176
+ valid: issues.length === 0,
177
+ coupon: {
178
+ id: coupon.id,
179
+ code: coupon.code,
180
+ discount_type: coupon.discount_type,
181
+ discount_amount: coupon.discount_amount,
182
+ free_shipping: coupon.free_shipping
183
+ },
184
+ issues: issues.length > 0 ? issues : undefined
185
+ }
186
+ };
187
+ }
188
+
189
+ // ---- DELETE: deactivate a coupon ----
190
+ case "delete":
191
+ {
192
+ const couponId = args.coupon_id;
193
+ if (!couponId) return {
194
+ success: false,
195
+ error: "coupon_id is required"
196
+ };
197
+ const {
198
+ error
199
+ } = await sb.from("coupons").update({
200
+ is_active: false,
201
+ updated_at: new Date().toISOString()
202
+ }).eq("id", couponId).eq("store_id", sid);
203
+ return error ? {
204
+ success: false,
205
+ error: error.message
206
+ } : {
207
+ success: true,
208
+ data: {
209
+ deactivated: true
210
+ }
211
+ };
212
+ }
213
+ default:
214
+ return {
215
+ success: false,
216
+ error: `Unknown coupons action: ${args.action}. Valid: list, get, create, update, validate, delete`
217
+ };
218
+ }
219
+ }
220
+ //# sourceMappingURL=coupons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coupons.js","names":["sanitizeFilterValue","handleCoupons","sb","args","storeId","sid","action","q","from","select","eq","order","ascending","is_active","undefined","discount_type","query","sq","String","or","limit","data","error","success","message","count","length","couponId","coupon_id","single","usage","recent_usage","code","discountType","discountAmount","discount_amount","record","store_id","toUpperCase","description","free_shipping","minimum_amount","maximum_amount","usage_limit","usage_limit_per_user","individual_use","exclude_sale_items","start_date","end_date","allowed_products","excluded_products","allowed_categories","excluded_categories","allowed_emails","insert","updates","updated_at","Date","toISOString","update","coupon","maybeSingle","now","issues","push","usage_count","valid","id","deactivated"],"sources":["../../../src/server/handlers/coupons.ts"],"sourcesContent":["// server/handlers/coupons.ts — Coupon code management (create, list, validate)\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport { sanitizeFilterValue } from \"../lib/utils.js\";\n\ntype Result = { success: boolean; data?: unknown; error?: string; [key: string]: unknown };\n\nexport async function handleCoupons(\n sb: SupabaseClient,\n args: Record<string, unknown>,\n storeId?: string,\n): Promise<Result> {\n const sid = storeId as string;\n\n switch (args.action) {\n // ---- LIST: list coupons with optional filters ----\n case \"list\": {\n let q = sb.from(\"coupons\")\n .select(\"*\")\n .eq(\"store_id\", sid)\n .order(\"created_at\", { ascending: false });\n if (args.is_active !== undefined) q = q.eq(\"is_active\", args.is_active as boolean);\n if (args.discount_type) q = q.eq(\"discount_type\", args.discount_type as string);\n if (args.query) {\n const sq = sanitizeFilterValue(String(args.query));\n q = q.or(`code.ilike.%${sq}%,description.ilike.%${sq}%`);\n }\n q = q.limit(args.limit as number || 50);\n const { data, error } = await q;\n return error ? { success: false, error: error.message } : { success: true, count: data?.length, data };\n }\n\n // ---- GET: get a single coupon by ID ----\n case \"get\": {\n const couponId = args.coupon_id as string;\n if (!couponId) return { success: false, error: \"coupon_id is required\" };\n const { data, error } = await sb.from(\"coupons\")\n .select(\"*\")\n .eq(\"id\", couponId)\n .eq(\"store_id\", sid)\n .single();\n if (error) return { success: false, error: error.message };\n\n // Include usage stats\n const { data: usage } = await sb.from(\"coupon_usage\")\n .select(\"id, customer_id, order_id, discount_amount, created_at\")\n .eq(\"coupon_id\", couponId)\n .order(\"created_at\", { ascending: false })\n .limit(20);\n return { success: true, data: { ...data, recent_usage: usage || [] } };\n }\n\n // ---- CREATE: create a new coupon ----\n case \"create\": {\n const code = args.code as string;\n const discountType = args.discount_type as string;\n const discountAmount = args.discount_amount as number;\n if (!code || !discountType || discountAmount === undefined) {\n return { success: false, error: \"code, discount_type, and discount_amount are required\" };\n }\n const record: Record<string, unknown> = {\n store_id: sid,\n code: code.toUpperCase(),\n discount_type: discountType,\n discount_amount: discountAmount,\n };\n if (args.description !== undefined) record.description = args.description;\n if (args.free_shipping !== undefined) record.free_shipping = args.free_shipping;\n if (args.minimum_amount !== undefined) record.minimum_amount = args.minimum_amount;\n if (args.maximum_amount !== undefined) record.maximum_amount = args.maximum_amount;\n if (args.usage_limit !== undefined) record.usage_limit = args.usage_limit;\n if (args.usage_limit_per_user !== undefined) record.usage_limit_per_user = args.usage_limit_per_user;\n if (args.individual_use !== undefined) record.individual_use = args.individual_use;\n if (args.exclude_sale_items !== undefined) record.exclude_sale_items = args.exclude_sale_items;\n if (args.start_date !== undefined) record.start_date = args.start_date;\n if (args.end_date !== undefined) record.end_date = args.end_date;\n if (args.allowed_products !== undefined) record.allowed_products = args.allowed_products;\n if (args.excluded_products !== undefined) record.excluded_products = args.excluded_products;\n if (args.allowed_categories !== undefined) record.allowed_categories = args.allowed_categories;\n if (args.excluded_categories !== undefined) record.excluded_categories = args.excluded_categories;\n if (args.allowed_emails !== undefined) record.allowed_emails = args.allowed_emails;\n\n const { data, error } = await sb.from(\"coupons\")\n .insert(record)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- UPDATE: modify a coupon ----\n case \"update\": {\n const couponId = args.coupon_id as string;\n if (!couponId) return { success: false, error: \"coupon_id is required\" };\n const updates: Record<string, unknown> = { updated_at: new Date().toISOString() };\n if (args.code !== undefined) updates.code = (args.code as string).toUpperCase();\n if (args.description !== undefined) updates.description = args.description;\n if (args.discount_type !== undefined) updates.discount_type = args.discount_type;\n if (args.discount_amount !== undefined) updates.discount_amount = args.discount_amount;\n if (args.is_active !== undefined) updates.is_active = args.is_active;\n if (args.free_shipping !== undefined) updates.free_shipping = args.free_shipping;\n if (args.minimum_amount !== undefined) updates.minimum_amount = args.minimum_amount;\n if (args.maximum_amount !== undefined) updates.maximum_amount = args.maximum_amount;\n if (args.usage_limit !== undefined) updates.usage_limit = args.usage_limit;\n if (args.start_date !== undefined) updates.start_date = args.start_date;\n if (args.end_date !== undefined) updates.end_date = args.end_date;\n\n const { data, error } = await sb.from(\"coupons\")\n .update(updates)\n .eq(\"id\", couponId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- VALIDATE: check if a coupon code is valid for use ----\n case \"validate\": {\n const code = args.code as string;\n if (!code) return { success: false, error: \"code is required\" };\n const { data: coupon, error } = await sb.from(\"coupons\")\n .select(\"*\")\n .eq(\"code\", code.toUpperCase())\n .eq(\"store_id\", sid)\n .maybeSingle();\n if (error) return { success: false, error: error.message };\n if (!coupon) return { success: false, error: \"Coupon code not found\" };\n\n const now = new Date();\n const issues: string[] = [];\n if (!coupon.is_active) issues.push(\"Coupon is inactive\");\n if (coupon.start_date && new Date(coupon.start_date) > now) issues.push(\"Coupon has not started yet\");\n if (coupon.end_date && new Date(coupon.end_date) < now) issues.push(\"Coupon has expired\");\n if (coupon.usage_limit && coupon.usage_count >= coupon.usage_limit) issues.push(\"Usage limit reached\");\n\n return {\n success: true,\n data: {\n valid: issues.length === 0,\n coupon: { id: coupon.id, code: coupon.code, discount_type: coupon.discount_type, discount_amount: coupon.discount_amount, free_shipping: coupon.free_shipping },\n issues: issues.length > 0 ? issues : undefined,\n },\n };\n }\n\n // ---- DELETE: deactivate a coupon ----\n case \"delete\": {\n const couponId = args.coupon_id as string;\n if (!couponId) return { success: false, error: \"coupon_id is required\" };\n const { error } = await sb.from(\"coupons\")\n .update({ is_active: false, updated_at: new Date().toISOString() })\n .eq(\"id\", couponId)\n .eq(\"store_id\", sid);\n return error ? { success: false, error: error.message } : { success: true, data: { deactivated: true } };\n }\n\n default:\n return { success: false, error: `Unknown coupons action: ${args.action}. Valid: list, get, create, update, validate, delete` };\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -151,7 +151,7 @@ export async function handleEmbeddings(sb, args, storeId) {
151
151
  const {
152
152
  data: products,
153
153
  error: fetchErr
154
- } = await sb.from("products").select("id, name, description, short_description, custom_fields").eq("store_id", sid);
154
+ } = await sb.from("products").select("id, name, description, short_description, custom_fields").eq("store_id", sid).neq("status", "archived");
155
155
  if (fetchErr) return {
156
156
  success: false,
157
157
  error: fetchErr.message
@@ -1 +1 @@
1
- {"version":3,"file":"embeddings.js","names":["OpenAI","EMBEDDING_MODEL","MAX_CHARS","BATCH_SIZE","truncateText","text","length","slice","getOpenAIClient","sb","storeId","data","apiKey","error","rpc","p_name","p_store_id","Error","generateEmbeddings","openai","texts","results","i","batch","map","response","embeddings","create","model","input","item","push","embedding","productToText","product","parts","name","String","short_description","description","custom_fields","fv","key","val","Object","entries","undefined","join","handleEmbeddings","args","sid","action","content","success","sourceType","source_type","sourceId","source_id","metadata","from","delete","eq","insert","store_id","JSON","stringify","select","single","message","query","matchCount","match_count","threshold","similarity_threshold","queryEmbedding","p_query_embedding","p_match_count","p_source_type","p_similarity_threshold","count","products","fetchErr","indexed","inserted","rows","p","id","insErr","total_products","q","deleted","counts","total","row","st","by_source_type"],"sources":["../../../src/server/handlers/embeddings.ts"],"sourcesContent":["import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport OpenAI from \"openai\";\n\n// ============================================================================\n// EMBEDDINGS — Semantic vector search via OpenAI + pgvector\n// Actions: embed, search, index_products, delete, stats\n// ============================================================================\n\nconst EMBEDDING_MODEL = \"text-embedding-3-small\";\nconst MAX_CHARS = 32_000; // ~8000 tokens\nconst BATCH_SIZE = 100; // OpenAI max per request\n\n/** Truncate text to stay within token limits */\nfunction truncateText(text: string): string {\n return text.length > MAX_CHARS ? text.slice(0, MAX_CHARS) : text;\n}\n\n/** Get an OpenAI client by decrypting the stored API key */\nasync function getOpenAIClient(sb: SupabaseClient, storeId: string): Promise<OpenAI> {\n const { data: apiKey, error } = await sb.rpc(\"decrypt_secret\", {\n p_name: \"OPENAI_API_KEY\",\n p_store_id: storeId,\n });\n if (error || !apiKey) {\n throw new Error(\"OpenAI API key not found. Add OPENAI_API_KEY to your tool secrets.\");\n }\n return new OpenAI({ apiKey });\n}\n\n/** Generate embeddings for one or more texts (batched) */\nasync function generateEmbeddings(\n openai: OpenAI,\n texts: string[]\n): Promise<number[][]> {\n const results: number[][] = [];\n for (let i = 0; i < texts.length; i += BATCH_SIZE) {\n const batch = texts.slice(i, i + BATCH_SIZE).map(truncateText);\n const response = await openai.embeddings.create({\n model: EMBEDDING_MODEL,\n input: batch,\n });\n for (const item of response.data) {\n results.push(item.embedding);\n }\n }\n return results;\n}\n\n/** Build a text representation of a product for embedding */\nfunction productToText(product: Record<string, unknown>): string {\n const parts: string[] = [];\n if (product.name) parts.push(String(product.name));\n if (product.short_description) parts.push(String(product.short_description));\n if (product.description) parts.push(String(product.description));\n if (product.custom_fields && typeof product.custom_fields === \"object\") {\n const fv = product.custom_fields as Record<string, unknown>;\n for (const [key, val] of Object.entries(fv)) {\n if (val !== null && val !== undefined && val !== \"\") {\n parts.push(`${key}: ${String(val)}`);\n }\n }\n }\n return parts.join(\". \");\n}\n\n// ============================================================================\n// MAIN HANDLER\n// ============================================================================\n\nexport async function handleEmbeddings(\n sb: SupabaseClient,\n args: Record<string, unknown>,\n storeId?: string\n) {\n const sid = storeId as string;\n const action = args.action as string;\n\n switch (action) {\n\n // ======================== EMBED ========================\n case \"embed\": {\n const content = args.content as string;\n if (!content) return { success: false, error: \"content is required for embed action\" };\n\n const openai = await getOpenAIClient(sb, sid);\n const [embedding] = await generateEmbeddings(openai, [content]);\n\n const sourceType = (args.source_type as string) || \"text\";\n const sourceId = args.source_id as string | undefined;\n const metadata = (args.metadata as Record<string, unknown>) || {};\n\n // Upsert: delete existing embedding for same source_id if provided\n if (sourceId) {\n await sb.from(\"embeddings\")\n .delete()\n .eq(\"store_id\", sid)\n .eq(\"source_type\", sourceType)\n .eq(\"source_id\", sourceId);\n }\n\n const { data, error } = await sb.from(\"embeddings\").insert({\n store_id: sid,\n content: truncateText(content),\n embedding: JSON.stringify(embedding),\n metadata,\n source_type: sourceType,\n source_id: sourceId || null,\n }).select(\"id, source_type, source_id, created_at\").single();\n\n if (error) return { success: false, error: error.message };\n return { success: true, data };\n }\n\n // ======================== SEARCH ========================\n case \"search\": {\n const query = args.query as string;\n if (!query) return { success: false, error: \"query is required for search action\" };\n\n const matchCount = (args.match_count as number) || 10;\n const sourceType = (args.source_type as string) || null;\n const threshold = (args.similarity_threshold as number) || 0.5;\n\n const openai = await getOpenAIClient(sb, sid);\n const [queryEmbedding] = await generateEmbeddings(openai, [query]);\n\n const { data, error } = await sb.rpc(\"search_embeddings\", {\n p_store_id: sid,\n p_query_embedding: JSON.stringify(queryEmbedding),\n p_match_count: matchCount,\n p_source_type: sourceType,\n p_similarity_threshold: threshold,\n });\n\n if (error) return { success: false, error: error.message };\n return { success: true, count: data?.length ?? 0, data };\n }\n\n // ======================== INDEX PRODUCTS ========================\n case \"index_products\": {\n const { data: products, error: fetchErr } = await sb\n .from(\"products\")\n .select(\"id, name, description, short_description, custom_fields\")\n .eq(\"store_id\", sid);\n\n if (fetchErr) return { success: false, error: fetchErr.message };\n if (!products || products.length === 0) {\n return { success: true, data: { indexed: 0, message: \"No products found to index.\" } };\n }\n\n const openai = await getOpenAIClient(sb, sid);\n const texts = products.map(productToText);\n const embeddings = await generateEmbeddings(openai, texts);\n\n // Delete all existing product embeddings for this store\n await sb.from(\"embeddings\")\n .delete()\n .eq(\"store_id\", sid)\n .eq(\"source_type\", \"product\");\n\n // Insert in batches\n let inserted = 0;\n const rows = products.map((p, i) => ({\n store_id: sid,\n content: truncateText(texts[i]),\n embedding: JSON.stringify(embeddings[i]),\n metadata: { name: p.name },\n source_type: \"product\" as const,\n source_id: p.id,\n }));\n\n for (let i = 0; i < rows.length; i += 500) {\n const batch = rows.slice(i, i + 500);\n const { error: insErr } = await sb.from(\"embeddings\").insert(batch);\n if (insErr) return { success: false, error: insErr.message, data: { indexed: inserted } };\n inserted += batch.length;\n }\n\n return {\n success: true,\n data: { indexed: inserted, total_products: products.length },\n };\n }\n\n // ======================== DELETE ========================\n case \"delete\": {\n const sourceType = args.source_type as string | undefined;\n const sourceId = args.source_id as string | undefined;\n\n if (!sourceType && !sourceId) {\n return { success: false, error: \"Provide source_type and/or source_id to delete embeddings.\" };\n }\n\n let q = sb.from(\"embeddings\").delete().eq(\"store_id\", sid);\n if (sourceType) q = q.eq(\"source_type\", sourceType);\n if (sourceId) q = q.eq(\"source_id\", sourceId);\n\n const { error } = await q;\n if (error) return { success: false, error: error.message };\n return { success: true, data: { deleted: true, source_type: sourceType, source_id: sourceId } };\n }\n\n // ======================== STATS ========================\n case \"stats\": {\n const { data, error } = await sb\n .from(\"embeddings\")\n .select(\"source_type\")\n .eq(\"store_id\", sid);\n\n if (error) return { success: false, error: error.message };\n\n const counts: Record<string, number> = {};\n let total = 0;\n for (const row of data || []) {\n const st = (row.source_type as string) || \"unknown\";\n counts[st] = (counts[st] || 0) + 1;\n total++;\n }\n\n return { success: true, data: { total, by_source_type: counts } };\n }\n\n default:\n return {\n success: false,\n error: `Unknown embeddings action: ${action}. Valid actions: embed, search, index_products, delete, stats`,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"embeddings.js","names":["OpenAI","EMBEDDING_MODEL","MAX_CHARS","BATCH_SIZE","truncateText","text","length","slice","getOpenAIClient","sb","storeId","data","apiKey","error","rpc","p_name","p_store_id","Error","generateEmbeddings","openai","texts","results","i","batch","map","response","embeddings","create","model","input","item","push","embedding","productToText","product","parts","name","String","short_description","description","custom_fields","fv","key","val","Object","entries","undefined","join","handleEmbeddings","args","sid","action","content","success","sourceType","source_type","sourceId","source_id","metadata","from","delete","eq","insert","store_id","JSON","stringify","select","single","message","query","matchCount","match_count","threshold","similarity_threshold","queryEmbedding","p_query_embedding","p_match_count","p_source_type","p_similarity_threshold","count","products","fetchErr","neq","indexed","inserted","rows","p","id","insErr","total_products","q","deleted","counts","total","row","st","by_source_type"],"sources":["../../../src/server/handlers/embeddings.ts"],"sourcesContent":["import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport OpenAI from \"openai\";\n\n// ============================================================================\n// EMBEDDINGS — Semantic vector search via OpenAI + pgvector\n// Actions: embed, search, index_products, delete, stats\n// ============================================================================\n\nconst EMBEDDING_MODEL = \"text-embedding-3-small\";\nconst MAX_CHARS = 32_000; // ~8000 tokens\nconst BATCH_SIZE = 100; // OpenAI max per request\n\n/** Truncate text to stay within token limits */\nfunction truncateText(text: string): string {\n return text.length > MAX_CHARS ? text.slice(0, MAX_CHARS) : text;\n}\n\n/** Get an OpenAI client by decrypting the stored API key */\nasync function getOpenAIClient(sb: SupabaseClient, storeId: string): Promise<OpenAI> {\n const { data: apiKey, error } = await sb.rpc(\"decrypt_secret\", {\n p_name: \"OPENAI_API_KEY\",\n p_store_id: storeId,\n });\n if (error || !apiKey) {\n throw new Error(\"OpenAI API key not found. Add OPENAI_API_KEY to your tool secrets.\");\n }\n return new OpenAI({ apiKey });\n}\n\n/** Generate embeddings for one or more texts (batched) */\nasync function generateEmbeddings(\n openai: OpenAI,\n texts: string[]\n): Promise<number[][]> {\n const results: number[][] = [];\n for (let i = 0; i < texts.length; i += BATCH_SIZE) {\n const batch = texts.slice(i, i + BATCH_SIZE).map(truncateText);\n const response = await openai.embeddings.create({\n model: EMBEDDING_MODEL,\n input: batch,\n });\n for (const item of response.data) {\n results.push(item.embedding);\n }\n }\n return results;\n}\n\n/** Build a text representation of a product for embedding */\nfunction productToText(product: Record<string, unknown>): string {\n const parts: string[] = [];\n if (product.name) parts.push(String(product.name));\n if (product.short_description) parts.push(String(product.short_description));\n if (product.description) parts.push(String(product.description));\n if (product.custom_fields && typeof product.custom_fields === \"object\") {\n const fv = product.custom_fields as Record<string, unknown>;\n for (const [key, val] of Object.entries(fv)) {\n if (val !== null && val !== undefined && val !== \"\") {\n parts.push(`${key}: ${String(val)}`);\n }\n }\n }\n return parts.join(\". \");\n}\n\n// ============================================================================\n// MAIN HANDLER\n// ============================================================================\n\nexport async function handleEmbeddings(\n sb: SupabaseClient,\n args: Record<string, unknown>,\n storeId?: string\n) {\n const sid = storeId as string;\n const action = args.action as string;\n\n switch (action) {\n\n // ======================== EMBED ========================\n case \"embed\": {\n const content = args.content as string;\n if (!content) return { success: false, error: \"content is required for embed action\" };\n\n const openai = await getOpenAIClient(sb, sid);\n const [embedding] = await generateEmbeddings(openai, [content]);\n\n const sourceType = (args.source_type as string) || \"text\";\n const sourceId = args.source_id as string | undefined;\n const metadata = (args.metadata as Record<string, unknown>) || {};\n\n // Upsert: delete existing embedding for same source_id if provided\n if (sourceId) {\n await sb.from(\"embeddings\")\n .delete()\n .eq(\"store_id\", sid)\n .eq(\"source_type\", sourceType)\n .eq(\"source_id\", sourceId);\n }\n\n const { data, error } = await sb.from(\"embeddings\").insert({\n store_id: sid,\n content: truncateText(content),\n embedding: JSON.stringify(embedding),\n metadata,\n source_type: sourceType,\n source_id: sourceId || null,\n }).select(\"id, source_type, source_id, created_at\").single();\n\n if (error) return { success: false, error: error.message };\n return { success: true, data };\n }\n\n // ======================== SEARCH ========================\n case \"search\": {\n const query = args.query as string;\n if (!query) return { success: false, error: \"query is required for search action\" };\n\n const matchCount = (args.match_count as number) || 10;\n const sourceType = (args.source_type as string) || null;\n const threshold = (args.similarity_threshold as number) || 0.5;\n\n const openai = await getOpenAIClient(sb, sid);\n const [queryEmbedding] = await generateEmbeddings(openai, [query]);\n\n const { data, error } = await sb.rpc(\"search_embeddings\", {\n p_store_id: sid,\n p_query_embedding: JSON.stringify(queryEmbedding),\n p_match_count: matchCount,\n p_source_type: sourceType,\n p_similarity_threshold: threshold,\n });\n\n if (error) return { success: false, error: error.message };\n return { success: true, count: data?.length ?? 0, data };\n }\n\n // ======================== INDEX PRODUCTS ========================\n case \"index_products\": {\n const { data: products, error: fetchErr } = await sb\n .from(\"products\")\n .select(\"id, name, description, short_description, custom_fields\")\n .eq(\"store_id\", sid)\n .neq(\"status\", \"archived\");\n\n if (fetchErr) return { success: false, error: fetchErr.message };\n if (!products || products.length === 0) {\n return { success: true, data: { indexed: 0, message: \"No products found to index.\" } };\n }\n\n const openai = await getOpenAIClient(sb, sid);\n const texts = products.map(productToText);\n const embeddings = await generateEmbeddings(openai, texts);\n\n // Delete all existing product embeddings for this store\n await sb.from(\"embeddings\")\n .delete()\n .eq(\"store_id\", sid)\n .eq(\"source_type\", \"product\");\n\n // Insert in batches\n let inserted = 0;\n const rows = products.map((p, i) => ({\n store_id: sid,\n content: truncateText(texts[i]),\n embedding: JSON.stringify(embeddings[i]),\n metadata: { name: p.name },\n source_type: \"product\" as const,\n source_id: p.id,\n }));\n\n for (let i = 0; i < rows.length; i += 500) {\n const batch = rows.slice(i, i + 500);\n const { error: insErr } = await sb.from(\"embeddings\").insert(batch);\n if (insErr) return { success: false, error: insErr.message, data: { indexed: inserted } };\n inserted += batch.length;\n }\n\n return {\n success: true,\n data: { indexed: inserted, total_products: products.length },\n };\n }\n\n // ======================== DELETE ========================\n case \"delete\": {\n const sourceType = args.source_type as string | undefined;\n const sourceId = args.source_id as string | undefined;\n\n if (!sourceType && !sourceId) {\n return { success: false, error: \"Provide source_type and/or source_id to delete embeddings.\" };\n }\n\n let q = sb.from(\"embeddings\").delete().eq(\"store_id\", sid);\n if (sourceType) q = q.eq(\"source_type\", sourceType);\n if (sourceId) q = q.eq(\"source_id\", sourceId);\n\n const { error } = await q;\n if (error) return { success: false, error: error.message };\n return { success: true, data: { deleted: true, source_type: sourceType, source_id: sourceId } };\n }\n\n // ======================== STATS ========================\n case \"stats\": {\n const { data, error } = await sb\n .from(\"embeddings\")\n .select(\"source_type\")\n .eq(\"store_id\", sid);\n\n if (error) return { success: false, error: error.message };\n\n const counts: Record<string, number> = {};\n let total = 0;\n for (const row of data || []) {\n const st = (row.source_type as string) || \"unknown\";\n counts[st] = (counts[st] || 0) + 1;\n total++;\n }\n\n return { success: true, data: { total, by_source_type: counts } };\n }\n\n default:\n return {\n success: false,\n error: `Unknown embeddings action: ${action}. Valid actions: embed, search, index_products, delete, stats`,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}