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,171 @@
1
+ // server/handlers/reviews.ts — Product review listing and moderation
2
+
3
+ export async function handleReviews(sb, args, storeId) {
4
+ const sid = storeId;
5
+ switch (args.action) {
6
+ // ---- LIST: list reviews with filters ----
7
+ case "list":
8
+ {
9
+ let q = sb.from("product_reviews").select("id, product_id, customer_id, order_id, rating, title, review_text, verified_purchase, status, helpful_count, not_helpful_count, store_response, responded_at, review_images, created_at, product:products!product_id(name, sku)").eq("store_id", sid).order("created_at", {
10
+ ascending: false
11
+ });
12
+ if (args.status) q = q.eq("status", args.status);
13
+ if (args.product_id) q = q.eq("product_id", args.product_id);
14
+ if (args.rating) q = q.eq("rating", args.rating);
15
+ if (args.min_rating) q = q.gte("rating", args.min_rating);
16
+ if (args.max_rating) q = q.lte("rating", args.max_rating);
17
+ if (args.verified_only === true) q = q.eq("verified_purchase", true);
18
+ q = q.limit(args.limit || 50);
19
+ const {
20
+ data,
21
+ error
22
+ } = await q;
23
+ return error ? {
24
+ success: false,
25
+ error: error.message
26
+ } : {
27
+ success: true,
28
+ count: data?.length,
29
+ data
30
+ };
31
+ }
32
+
33
+ // ---- GET: get a single review ----
34
+ case "get":
35
+ {
36
+ const reviewId = args.review_id;
37
+ if (!reviewId) return {
38
+ success: false,
39
+ error: "review_id is required"
40
+ };
41
+ const {
42
+ data,
43
+ error
44
+ } = await sb.from("product_reviews").select("*, product:products!product_id(name, sku)").eq("id", reviewId).eq("store_id", sid).single();
45
+ return error ? {
46
+ success: false,
47
+ error: error.message
48
+ } : {
49
+ success: true,
50
+ data
51
+ };
52
+ }
53
+
54
+ // ---- APPROVE: approve a pending review ----
55
+ case "approve":
56
+ {
57
+ const reviewId = args.review_id;
58
+ if (!reviewId) return {
59
+ success: false,
60
+ error: "review_id is required"
61
+ };
62
+ const {
63
+ data,
64
+ error
65
+ } = await sb.from("product_reviews").update({
66
+ status: "approved",
67
+ updated_at: new Date().toISOString()
68
+ }).eq("id", reviewId).eq("store_id", sid).select().single();
69
+ return error ? {
70
+ success: false,
71
+ error: error.message
72
+ } : {
73
+ success: true,
74
+ data
75
+ };
76
+ }
77
+
78
+ // ---- REJECT: reject a review ----
79
+ case "reject":
80
+ {
81
+ const reviewId = args.review_id;
82
+ if (!reviewId) return {
83
+ success: false,
84
+ error: "review_id is required"
85
+ };
86
+ const {
87
+ data,
88
+ error
89
+ } = await sb.from("product_reviews").update({
90
+ status: "rejected",
91
+ updated_at: new Date().toISOString()
92
+ }).eq("id", reviewId).eq("store_id", sid).select().single();
93
+ return error ? {
94
+ success: false,
95
+ error: error.message
96
+ } : {
97
+ success: true,
98
+ data
99
+ };
100
+ }
101
+
102
+ // ---- RESPOND: add a store response to a review ----
103
+ case "respond":
104
+ {
105
+ const reviewId = args.review_id;
106
+ const response = args.response;
107
+ if (!reviewId || !response) return {
108
+ success: false,
109
+ error: "review_id and response are required"
110
+ };
111
+ const {
112
+ data,
113
+ error
114
+ } = await sb.from("product_reviews").update({
115
+ store_response: response,
116
+ responded_at: new Date().toISOString(),
117
+ updated_at: new Date().toISOString()
118
+ }).eq("id", reviewId).eq("store_id", sid).select().single();
119
+ return error ? {
120
+ success: false,
121
+ error: error.message
122
+ } : {
123
+ success: true,
124
+ data
125
+ };
126
+ }
127
+
128
+ // ---- SUMMARY: get review stats per product or store ----
129
+ case "summary":
130
+ {
131
+ let q = sb.from("product_reviews").select("product_id, rating, status").eq("store_id", sid);
132
+ if (args.product_id) q = q.eq("product_id", args.product_id);
133
+ const {
134
+ data,
135
+ error
136
+ } = await q;
137
+ if (error) return {
138
+ success: false,
139
+ error: error.message
140
+ };
141
+ const reviews = data || [];
142
+ const approved = reviews.filter(r => r.status === "approved");
143
+ const pending = reviews.filter(r => r.status === "pending");
144
+ const avgRating = approved.length > 0 ? Math.round(approved.reduce((s, r) => s + r.rating, 0) / approved.length * 10) / 10 : 0;
145
+ const ratingDist = {
146
+ 1: 0,
147
+ 2: 0,
148
+ 3: 0,
149
+ 4: 0,
150
+ 5: 0
151
+ };
152
+ for (const r of approved) ratingDist[r.rating] = (ratingDist[r.rating] || 0) + 1;
153
+ return {
154
+ success: true,
155
+ data: {
156
+ total_reviews: reviews.length,
157
+ approved_count: approved.length,
158
+ pending_count: pending.length,
159
+ average_rating: avgRating,
160
+ rating_distribution: ratingDist
161
+ }
162
+ };
163
+ }
164
+ default:
165
+ return {
166
+ success: false,
167
+ error: `Unknown reviews action: ${args.action}. Valid: list, get, approve, reject, respond, summary`
168
+ };
169
+ }
170
+ }
171
+ //# sourceMappingURL=reviews.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviews.js","names":["handleReviews","sb","args","storeId","sid","action","q","from","select","eq","order","ascending","status","product_id","rating","min_rating","gte","max_rating","lte","verified_only","limit","data","error","success","message","count","length","reviewId","review_id","single","update","updated_at","Date","toISOString","response","store_response","responded_at","reviews","approved","filter","r","pending","avgRating","Math","round","reduce","s","ratingDist","total_reviews","approved_count","pending_count","average_rating","rating_distribution"],"sources":["../../../src/server/handlers/reviews.ts"],"sourcesContent":["// server/handlers/reviews.ts — Product review listing and moderation\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\n\ntype Result = { success: boolean; data?: unknown; error?: string; [key: string]: unknown };\n\nexport async function handleReviews(\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 reviews with filters ----\n case \"list\": {\n let q = sb.from(\"product_reviews\")\n .select(\"id, product_id, customer_id, order_id, rating, title, review_text, verified_purchase, status, helpful_count, not_helpful_count, store_response, responded_at, review_images, created_at, product:products!product_id(name, sku)\")\n .eq(\"store_id\", sid)\n .order(\"created_at\", { ascending: false });\n if (args.status) q = q.eq(\"status\", args.status as string);\n if (args.product_id) q = q.eq(\"product_id\", args.product_id as string);\n if (args.rating) q = q.eq(\"rating\", args.rating as number);\n if (args.min_rating) q = q.gte(\"rating\", args.min_rating as number);\n if (args.max_rating) q = q.lte(\"rating\", args.max_rating as number);\n if (args.verified_only === true) q = q.eq(\"verified_purchase\", true);\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 review ----\n case \"get\": {\n const reviewId = args.review_id as string;\n if (!reviewId) return { success: false, error: \"review_id is required\" };\n const { data, error } = await sb.from(\"product_reviews\")\n .select(\"*, product:products!product_id(name, sku)\")\n .eq(\"id\", reviewId)\n .eq(\"store_id\", sid)\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- APPROVE: approve a pending review ----\n case \"approve\": {\n const reviewId = args.review_id as string;\n if (!reviewId) return { success: false, error: \"review_id is required\" };\n const { data, error } = await sb.from(\"product_reviews\")\n .update({ status: \"approved\", updated_at: new Date().toISOString() })\n .eq(\"id\", reviewId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- REJECT: reject a review ----\n case \"reject\": {\n const reviewId = args.review_id as string;\n if (!reviewId) return { success: false, error: \"review_id is required\" };\n const { data, error } = await sb.from(\"product_reviews\")\n .update({ status: \"rejected\", updated_at: new Date().toISOString() })\n .eq(\"id\", reviewId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- RESPOND: add a store response to a review ----\n case \"respond\": {\n const reviewId = args.review_id as string;\n const response = args.response as string;\n if (!reviewId || !response) return { success: false, error: \"review_id and response are required\" };\n const { data, error } = await sb.from(\"product_reviews\")\n .update({ store_response: response, responded_at: new Date().toISOString(), updated_at: new Date().toISOString() })\n .eq(\"id\", reviewId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- SUMMARY: get review stats per product or store ----\n case \"summary\": {\n let q = sb.from(\"product_reviews\")\n .select(\"product_id, rating, status\")\n .eq(\"store_id\", sid);\n if (args.product_id) q = q.eq(\"product_id\", args.product_id as string);\n const { data, error } = await q;\n if (error) return { success: false, error: error.message };\n\n const reviews = data || [];\n const approved = reviews.filter(r => r.status === \"approved\");\n const pending = reviews.filter(r => r.status === \"pending\");\n const avgRating = approved.length > 0\n ? Math.round((approved.reduce((s, r) => s + r.rating, 0) / approved.length) * 10) / 10\n : 0;\n const ratingDist: Record<number, number> = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };\n for (const r of approved) ratingDist[r.rating] = (ratingDist[r.rating] || 0) + 1;\n\n return {\n success: true,\n data: {\n total_reviews: reviews.length,\n approved_count: approved.length,\n pending_count: pending.length,\n average_rating: avgRating,\n rating_distribution: ratingDist,\n },\n };\n }\n\n default:\n return { success: false, error: `Unknown reviews action: ${args.action}. Valid: list, get, approve, reject, respond, summary` };\n }\n}\n"],"mappings":"AAAA;;AAMA,OAAO,eAAeA,aAAaA,CACjCC,EAAkB,EAClBC,IAA6B,EAC7BC,OAAgB,EACC;EACjB,MAAMC,GAAG,GAAGD,OAAiB;EAE7B,QAAQD,IAAI,CAACG,MAAM;IACjB;IACA,KAAK,MAAM;MAAE;QACX,IAAIC,CAAC,GAAGL,EAAE,CAACM,IAAI,CAAC,iBAAiB,CAAC,CAC/BC,MAAM,CAAC,iOAAiO,CAAC,CACzOC,EAAE,CAAC,UAAU,EAAEL,GAAG,CAAC,CACnBM,KAAK,CAAC,YAAY,EAAE;UAAEC,SAAS,EAAE;QAAM,CAAC,CAAC;QAC5C,IAAIT,IAAI,CAACU,MAAM,EAAEN,CAAC,GAAGA,CAAC,CAACG,EAAE,CAAC,QAAQ,EAAEP,IAAI,CAACU,MAAgB,CAAC;QAC1D,IAAIV,IAAI,CAACW,UAAU,EAAEP,CAAC,GAAGA,CAAC,CAACG,EAAE,CAAC,YAAY,EAAEP,IAAI,CAACW,UAAoB,CAAC;QACtE,IAAIX,IAAI,CAACY,MAAM,EAAER,CAAC,GAAGA,CAAC,CAACG,EAAE,CAAC,QAAQ,EAAEP,IAAI,CAACY,MAAgB,CAAC;QAC1D,IAAIZ,IAAI,CAACa,UAAU,EAAET,CAAC,GAAGA,CAAC,CAACU,GAAG,CAAC,QAAQ,EAAEd,IAAI,CAACa,UAAoB,CAAC;QACnE,IAAIb,IAAI,CAACe,UAAU,EAAEX,CAAC,GAAGA,CAAC,CAACY,GAAG,CAAC,QAAQ,EAAEhB,IAAI,CAACe,UAAoB,CAAC;QACnE,IAAIf,IAAI,CAACiB,aAAa,KAAK,IAAI,EAAEb,CAAC,GAAGA,CAAC,CAACG,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;QACpEH,CAAC,GAAGA,CAAC,CAACc,KAAK,CAAClB,IAAI,CAACkB,KAAK,IAAc,EAAE,CAAC;QACvC,MAAM;UAAEC,IAAI;UAAEC;QAAM,CAAC,GAAG,MAAMhB,CAAC;QAC/B,OAAOgB,KAAK,GAAG;UAAEC,OAAO,EAAE,KAAK;UAAED,KAAK,EAAEA,KAAK,CAACE;QAAQ,CAAC,GAAG;UAAED,OAAO,EAAE,IAAI;UAAEE,KAAK,EAAEJ,IAAI,EAAEK,MAAM;UAAEL;QAAK,CAAC;MACxG;;IAEA;IACA,KAAK,KAAK;MAAE;QACV,MAAMM,QAAQ,GAAGzB,IAAI,CAAC0B,SAAmB;QACzC,IAAI,CAACD,QAAQ,EAAE,OAAO;UAAEJ,OAAO,EAAE,KAAK;UAAED,KAAK,EAAE;QAAwB,CAAC;QACxE,MAAM;UAAED,IAAI;UAAEC;QAAM,CAAC,GAAG,MAAMrB,EAAE,CAACM,IAAI,CAAC,iBAAiB,CAAC,CACrDC,MAAM,CAAC,2CAA2C,CAAC,CACnDC,EAAE,CAAC,IAAI,EAAEkB,QAAQ,CAAC,CAClBlB,EAAE,CAAC,UAAU,EAAEL,GAAG,CAAC,CACnByB,MAAM,CAAC,CAAC;QACX,OAAOP,KAAK,GAAG;UAAEC,OAAO,EAAE,KAAK;UAAED,KAAK,EAAEA,KAAK,CAACE;QAAQ,CAAC,GAAG;UAAED,OAAO,EAAE,IAAI;UAAEF;QAAK,CAAC;MACnF;;IAEA;IACA,KAAK,SAAS;MAAE;QACd,MAAMM,QAAQ,GAAGzB,IAAI,CAAC0B,SAAmB;QACzC,IAAI,CAACD,QAAQ,EAAE,OAAO;UAAEJ,OAAO,EAAE,KAAK;UAAED,KAAK,EAAE;QAAwB,CAAC;QACxE,MAAM;UAAED,IAAI;UAAEC;QAAM,CAAC,GAAG,MAAMrB,EAAE,CAACM,IAAI,CAAC,iBAAiB,CAAC,CACrDuB,MAAM,CAAC;UAAElB,MAAM,EAAE,UAAU;UAAEmB,UAAU,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC;QAAE,CAAC,CAAC,CACpExB,EAAE,CAAC,IAAI,EAAEkB,QAAQ,CAAC,CAClBlB,EAAE,CAAC,UAAU,EAAEL,GAAG,CAAC,CACnBI,MAAM,CAAC,CAAC,CACRqB,MAAM,CAAC,CAAC;QACX,OAAOP,KAAK,GAAG;UAAEC,OAAO,EAAE,KAAK;UAAED,KAAK,EAAEA,KAAK,CAACE;QAAQ,CAAC,GAAG;UAAED,OAAO,EAAE,IAAI;UAAEF;QAAK,CAAC;MACnF;;IAEA;IACA,KAAK,QAAQ;MAAE;QACb,MAAMM,QAAQ,GAAGzB,IAAI,CAAC0B,SAAmB;QACzC,IAAI,CAACD,QAAQ,EAAE,OAAO;UAAEJ,OAAO,EAAE,KAAK;UAAED,KAAK,EAAE;QAAwB,CAAC;QACxE,MAAM;UAAED,IAAI;UAAEC;QAAM,CAAC,GAAG,MAAMrB,EAAE,CAACM,IAAI,CAAC,iBAAiB,CAAC,CACrDuB,MAAM,CAAC;UAAElB,MAAM,EAAE,UAAU;UAAEmB,UAAU,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC;QAAE,CAAC,CAAC,CACpExB,EAAE,CAAC,IAAI,EAAEkB,QAAQ,CAAC,CAClBlB,EAAE,CAAC,UAAU,EAAEL,GAAG,CAAC,CACnBI,MAAM,CAAC,CAAC,CACRqB,MAAM,CAAC,CAAC;QACX,OAAOP,KAAK,GAAG;UAAEC,OAAO,EAAE,KAAK;UAAED,KAAK,EAAEA,KAAK,CAACE;QAAQ,CAAC,GAAG;UAAED,OAAO,EAAE,IAAI;UAAEF;QAAK,CAAC;MACnF;;IAEA;IACA,KAAK,SAAS;MAAE;QACd,MAAMM,QAAQ,GAAGzB,IAAI,CAAC0B,SAAmB;QACzC,MAAMM,QAAQ,GAAGhC,IAAI,CAACgC,QAAkB;QACxC,IAAI,CAACP,QAAQ,IAAI,CAACO,QAAQ,EAAE,OAAO;UAAEX,OAAO,EAAE,KAAK;UAAED,KAAK,EAAE;QAAsC,CAAC;QACnG,MAAM;UAAED,IAAI;UAAEC;QAAM,CAAC,GAAG,MAAMrB,EAAE,CAACM,IAAI,CAAC,iBAAiB,CAAC,CACrDuB,MAAM,CAAC;UAAEK,cAAc,EAAED,QAAQ;UAAEE,YAAY,EAAE,IAAIJ,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;UAAEF,UAAU,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC;QAAE,CAAC,CAAC,CAClHxB,EAAE,CAAC,IAAI,EAAEkB,QAAQ,CAAC,CAClBlB,EAAE,CAAC,UAAU,EAAEL,GAAG,CAAC,CACnBI,MAAM,CAAC,CAAC,CACRqB,MAAM,CAAC,CAAC;QACX,OAAOP,KAAK,GAAG;UAAEC,OAAO,EAAE,KAAK;UAAED,KAAK,EAAEA,KAAK,CAACE;QAAQ,CAAC,GAAG;UAAED,OAAO,EAAE,IAAI;UAAEF;QAAK,CAAC;MACnF;;IAEA;IACA,KAAK,SAAS;MAAE;QACd,IAAIf,CAAC,GAAGL,EAAE,CAACM,IAAI,CAAC,iBAAiB,CAAC,CAC/BC,MAAM,CAAC,4BAA4B,CAAC,CACpCC,EAAE,CAAC,UAAU,EAAEL,GAAG,CAAC;QACtB,IAAIF,IAAI,CAACW,UAAU,EAAEP,CAAC,GAAGA,CAAC,CAACG,EAAE,CAAC,YAAY,EAAEP,IAAI,CAACW,UAAoB,CAAC;QACtE,MAAM;UAAEQ,IAAI;UAAEC;QAAM,CAAC,GAAG,MAAMhB,CAAC;QAC/B,IAAIgB,KAAK,EAAE,OAAO;UAAEC,OAAO,EAAE,KAAK;UAAED,KAAK,EAAEA,KAAK,CAACE;QAAQ,CAAC;QAE1D,MAAMa,OAAO,GAAGhB,IAAI,IAAI,EAAE;QAC1B,MAAMiB,QAAQ,GAAGD,OAAO,CAACE,MAAM,CAACC,CAAC,IAAIA,CAAC,CAAC5B,MAAM,KAAK,UAAU,CAAC;QAC7D,MAAM6B,OAAO,GAAGJ,OAAO,CAACE,MAAM,CAACC,CAAC,IAAIA,CAAC,CAAC5B,MAAM,KAAK,SAAS,CAAC;QAC3D,MAAM8B,SAAS,GAAGJ,QAAQ,CAACZ,MAAM,GAAG,CAAC,GACjCiB,IAAI,CAACC,KAAK,CAAEN,QAAQ,CAACO,MAAM,CAAC,CAACC,CAAC,EAAEN,CAAC,KAAKM,CAAC,GAAGN,CAAC,CAAC1B,MAAM,EAAE,CAAC,CAAC,GAAGwB,QAAQ,CAACZ,MAAM,GAAI,EAAE,CAAC,GAAG,EAAE,GACpF,CAAC;QACL,MAAMqB,UAAkC,GAAG;UAAE,CAAC,EAAE,CAAC;UAAE,CAAC,EAAE,CAAC;UAAE,CAAC,EAAE,CAAC;UAAE,CAAC,EAAE,CAAC;UAAE,CAAC,EAAE;QAAE,CAAC;QAC3E,KAAK,MAAMP,CAAC,IAAIF,QAAQ,EAAES,UAAU,CAACP,CAAC,CAAC1B,MAAM,CAAC,GAAG,CAACiC,UAAU,CAACP,CAAC,CAAC1B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QAEhF,OAAO;UACLS,OAAO,EAAE,IAAI;UACbF,IAAI,EAAE;YACJ2B,aAAa,EAAEX,OAAO,CAACX,MAAM;YAC7BuB,cAAc,EAAEX,QAAQ,CAACZ,MAAM;YAC/BwB,aAAa,EAAET,OAAO,CAACf,MAAM;YAC7ByB,cAAc,EAAET,SAAS;YACzBU,mBAAmB,EAAEL;UACvB;QACF,CAAC;MACH;IAEA;MACE,OAAO;QAAExB,OAAO,EAAE,KAAK;QAAED,KAAK,EAAE,2BAA2BpB,IAAI,CAACG,MAAM;MAAwD,CAAC;EACnI;AACF","ignoreList":[]}
@@ -0,0 +1,9 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ type Result = {
3
+ success: boolean;
4
+ data?: unknown;
5
+ error?: string;
6
+ [key: string]: unknown;
7
+ };
8
+ export declare function handleSegments(sb: SupabaseClient, args: Record<string, unknown>, storeId?: string): Promise<Result>;
9
+ export {};
@@ -0,0 +1,229 @@
1
+ // server/handlers/segments.ts — Customer segment creation and management
2
+
3
+ export async function handleSegments(sb, args, storeId) {
4
+ const sid = storeId;
5
+ switch (args.action) {
6
+ // ---- LIST: list all segments ----
7
+ case "list":
8
+ {
9
+ let q = sb.from("customer_segments").select("id, name, description, ai_description, type, segment_rules, filter_criteria, customer_count, is_active, color, icon, targeting_tips, is_system, auto_refresh, last_refreshed_at, created_at").eq("store_id", sid).order("customer_count", {
10
+ ascending: false
11
+ });
12
+ if (args.is_active !== undefined) q = q.eq("is_active", args.is_active);
13
+ if (args.type) q = q.eq("type", args.type);
14
+ if (args.limit) q = q.limit(args.limit);
15
+ const {
16
+ data,
17
+ error
18
+ } = await q;
19
+ return error ? {
20
+ success: false,
21
+ error: error.message
22
+ } : {
23
+ success: true,
24
+ count: data?.length,
25
+ data
26
+ };
27
+ }
28
+
29
+ // ---- GET: get a segment with member count ----
30
+ case "get":
31
+ {
32
+ const segId = args.segment_id;
33
+ if (!segId) return {
34
+ success: false,
35
+ error: "segment_id is required"
36
+ };
37
+ const {
38
+ data,
39
+ error
40
+ } = await sb.from("customer_segments").select("*").eq("id", segId).eq("store_id", sid).single();
41
+ return error ? {
42
+ success: false,
43
+ error: error.message
44
+ } : {
45
+ success: true,
46
+ data
47
+ };
48
+ }
49
+
50
+ // ---- CREATE: create a new segment ----
51
+ case "create":
52
+ {
53
+ const name = args.name;
54
+ if (!name) return {
55
+ success: false,
56
+ error: "name is required"
57
+ };
58
+ const record = {
59
+ store_id: sid,
60
+ name,
61
+ segment_rules: args.segment_rules || {},
62
+ filter_criteria: args.filter_criteria || {}
63
+ };
64
+ if (args.description !== undefined) record.description = args.description;
65
+ if (args.ai_description !== undefined) record.ai_description = args.ai_description;
66
+ if (args.type !== undefined) record.type = args.type;
67
+ if (args.color !== undefined) record.color = args.color;
68
+ if (args.icon !== undefined) record.icon = args.icon;
69
+ if (args.is_dynamic !== undefined) record.is_dynamic = args.is_dynamic;
70
+ if (args.auto_refresh !== undefined) record.auto_refresh = args.auto_refresh;
71
+ if (args.targeting_tips !== undefined) record.targeting_tips = args.targeting_tips;
72
+ const {
73
+ data,
74
+ error
75
+ } = await sb.from("customer_segments").insert(record).select().single();
76
+ return error ? {
77
+ success: false,
78
+ error: error.message
79
+ } : {
80
+ success: true,
81
+ data
82
+ };
83
+ }
84
+
85
+ // ---- UPDATE: modify a segment ----
86
+ case "update":
87
+ {
88
+ const segId = args.segment_id;
89
+ if (!segId) return {
90
+ success: false,
91
+ error: "segment_id is required"
92
+ };
93
+ const updates = {
94
+ updated_at: new Date().toISOString()
95
+ };
96
+ if (args.name !== undefined) updates.name = args.name;
97
+ if (args.description !== undefined) updates.description = args.description;
98
+ if (args.ai_description !== undefined) updates.ai_description = args.ai_description;
99
+ if (args.segment_rules !== undefined) updates.segment_rules = args.segment_rules;
100
+ if (args.filter_criteria !== undefined) updates.filter_criteria = args.filter_criteria;
101
+ if (args.is_active !== undefined) updates.is_active = args.is_active;
102
+ if (args.color !== undefined) updates.color = args.color;
103
+ if (args.icon !== undefined) updates.icon = args.icon;
104
+ if (args.targeting_tips !== undefined) updates.targeting_tips = args.targeting_tips;
105
+ const {
106
+ data,
107
+ error
108
+ } = await sb.from("customer_segments").update(updates).eq("id", segId).eq("store_id", sid).select().single();
109
+ return error ? {
110
+ success: false,
111
+ error: error.message
112
+ } : {
113
+ success: true,
114
+ data
115
+ };
116
+ }
117
+
118
+ // ---- MEMBERS: list members of a segment ----
119
+ case "members":
120
+ {
121
+ const segId = args.segment_id;
122
+ if (!segId) return {
123
+ success: false,
124
+ error: "segment_id is required"
125
+ };
126
+ const {
127
+ data,
128
+ error
129
+ } = await sb.from("customer_segment_memberships").select("added_at, customer:v_segment_customers!customer_id(id, first_name, last_name, email, phone, total_spent, total_orders, loyalty_tier, rfm_segment)").eq("segment_id", segId).order("added_at", {
130
+ ascending: false
131
+ }).limit(args.limit || 50);
132
+ if (error) return {
133
+ success: false,
134
+ error: error.message
135
+ };
136
+ const members = (data || []).map(r => ({
137
+ added_at: r.added_at,
138
+ ...r.customer
139
+ })).filter(m => m.store_id === sid);
140
+ return {
141
+ success: true,
142
+ count: members.length,
143
+ data: members
144
+ };
145
+ }
146
+
147
+ // ---- ADD_MEMBER: manually add a customer to a segment ----
148
+ case "add_member":
149
+ {
150
+ const segId = args.segment_id;
151
+ const custId = args.customer_id;
152
+ if (!segId || !custId) return {
153
+ success: false,
154
+ error: "segment_id and customer_id are required"
155
+ };
156
+ const {
157
+ data,
158
+ error
159
+ } = await sb.from("customer_segment_memberships").upsert({
160
+ segment_id: segId,
161
+ customer_id: custId,
162
+ added_at: new Date().toISOString()
163
+ }, {
164
+ onConflict: "segment_id,customer_id"
165
+ }).select().single();
166
+ return error ? {
167
+ success: false,
168
+ error: error.message
169
+ } : {
170
+ success: true,
171
+ data
172
+ };
173
+ }
174
+
175
+ // ---- REMOVE_MEMBER: remove a customer from a segment ----
176
+ case "remove_member":
177
+ {
178
+ const segId = args.segment_id;
179
+ const custId = args.customer_id;
180
+ if (!segId || !custId) return {
181
+ success: false,
182
+ error: "segment_id and customer_id are required"
183
+ };
184
+ const {
185
+ error
186
+ } = await sb.from("customer_segment_memberships").delete().eq("segment_id", segId).eq("customer_id", custId);
187
+ return error ? {
188
+ success: false,
189
+ error: error.message
190
+ } : {
191
+ success: true,
192
+ data: {
193
+ removed: true
194
+ }
195
+ };
196
+ }
197
+
198
+ // ---- DELETE: deactivate a segment ----
199
+ case "delete":
200
+ {
201
+ const segId = args.segment_id;
202
+ if (!segId) return {
203
+ success: false,
204
+ error: "segment_id is required"
205
+ };
206
+ const {
207
+ error
208
+ } = await sb.from("customer_segments").update({
209
+ is_active: false,
210
+ updated_at: new Date().toISOString()
211
+ }).eq("id", segId).eq("store_id", sid);
212
+ return error ? {
213
+ success: false,
214
+ error: error.message
215
+ } : {
216
+ success: true,
217
+ data: {
218
+ deactivated: true
219
+ }
220
+ };
221
+ }
222
+ default:
223
+ return {
224
+ success: false,
225
+ error: `Unknown segments action: ${args.action}. Valid: list, get, create, update, members, add_member, remove_member, delete`
226
+ };
227
+ }
228
+ }
229
+ //# sourceMappingURL=segments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segments.js","names":["handleSegments","sb","args","storeId","sid","action","q","from","select","eq","order","ascending","is_active","undefined","type","limit","data","error","success","message","count","length","segId","segment_id","single","name","record","store_id","segment_rules","filter_criteria","description","ai_description","color","icon","is_dynamic","auto_refresh","targeting_tips","insert","updates","updated_at","Date","toISOString","update","members","map","r","added_at","customer","filter","m","custId","customer_id","upsert","onConflict","delete","removed","deactivated"],"sources":["../../../src/server/handlers/segments.ts"],"sourcesContent":["// server/handlers/segments.ts — Customer segment creation and management\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\n\ntype Result = { success: boolean; data?: unknown; error?: string; [key: string]: unknown };\n\nexport async function handleSegments(\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 all segments ----\n case \"list\": {\n let q = sb.from(\"customer_segments\")\n .select(\"id, name, description, ai_description, type, segment_rules, filter_criteria, customer_count, is_active, color, icon, targeting_tips, is_system, auto_refresh, last_refreshed_at, created_at\")\n .eq(\"store_id\", sid)\n .order(\"customer_count\", { ascending: false });\n if (args.is_active !== undefined) q = q.eq(\"is_active\", args.is_active as boolean);\n if (args.type) q = q.eq(\"type\", args.type as string);\n if (args.limit) q = q.limit(args.limit as number);\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 segment with member count ----\n case \"get\": {\n const segId = args.segment_id as string;\n if (!segId) return { success: false, error: \"segment_id is required\" };\n const { data, error } = await sb.from(\"customer_segments\")\n .select(\"*\")\n .eq(\"id\", segId)\n .eq(\"store_id\", sid)\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- CREATE: create a new segment ----\n case \"create\": {\n const name = args.name as string;\n if (!name) return { success: false, error: \"name is required\" };\n const record: Record<string, unknown> = {\n store_id: sid,\n name,\n segment_rules: args.segment_rules || {},\n filter_criteria: args.filter_criteria || {},\n };\n if (args.description !== undefined) record.description = args.description;\n if (args.ai_description !== undefined) record.ai_description = args.ai_description;\n if (args.type !== undefined) record.type = args.type;\n if (args.color !== undefined) record.color = args.color;\n if (args.icon !== undefined) record.icon = args.icon;\n if (args.is_dynamic !== undefined) record.is_dynamic = args.is_dynamic;\n if (args.auto_refresh !== undefined) record.auto_refresh = args.auto_refresh;\n if (args.targeting_tips !== undefined) record.targeting_tips = args.targeting_tips;\n\n const { data, error } = await sb.from(\"customer_segments\")\n .insert(record)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- UPDATE: modify a segment ----\n case \"update\": {\n const segId = args.segment_id as string;\n if (!segId) return { success: false, error: \"segment_id is required\" };\n const updates: Record<string, unknown> = { updated_at: new Date().toISOString() };\n if (args.name !== undefined) updates.name = args.name;\n if (args.description !== undefined) updates.description = args.description;\n if (args.ai_description !== undefined) updates.ai_description = args.ai_description;\n if (args.segment_rules !== undefined) updates.segment_rules = args.segment_rules;\n if (args.filter_criteria !== undefined) updates.filter_criteria = args.filter_criteria;\n if (args.is_active !== undefined) updates.is_active = args.is_active;\n if (args.color !== undefined) updates.color = args.color;\n if (args.icon !== undefined) updates.icon = args.icon;\n if (args.targeting_tips !== undefined) updates.targeting_tips = args.targeting_tips;\n\n const { data, error } = await sb.from(\"customer_segments\")\n .update(updates)\n .eq(\"id\", segId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- MEMBERS: list members of a segment ----\n case \"members\": {\n const segId = args.segment_id as string;\n if (!segId) return { success: false, error: \"segment_id is required\" };\n const { data, error } = await sb.from(\"customer_segment_memberships\")\n .select(\"added_at, customer:v_segment_customers!customer_id(id, first_name, last_name, email, phone, total_spent, total_orders, loyalty_tier, rfm_segment)\")\n .eq(\"segment_id\", segId)\n .order(\"added_at\", { ascending: false })\n .limit(args.limit as number || 50);\n if (error) return { success: false, error: error.message };\n const members = (data || [])\n .map((r: any) => ({ added_at: r.added_at, ...r.customer }))\n .filter((m: any) => m.store_id === sid);\n return { success: true, count: members.length, data: members };\n }\n\n // ---- ADD_MEMBER: manually add a customer to a segment ----\n case \"add_member\": {\n const segId = args.segment_id as string;\n const custId = args.customer_id as string;\n if (!segId || !custId) return { success: false, error: \"segment_id and customer_id are required\" };\n const { data, error } = await sb.from(\"customer_segment_memberships\")\n .upsert({ segment_id: segId, customer_id: custId, added_at: new Date().toISOString() }, { onConflict: \"segment_id,customer_id\" })\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- REMOVE_MEMBER: remove a customer from a segment ----\n case \"remove_member\": {\n const segId = args.segment_id as string;\n const custId = args.customer_id as string;\n if (!segId || !custId) return { success: false, error: \"segment_id and customer_id are required\" };\n const { error } = await sb.from(\"customer_segment_memberships\")\n .delete()\n .eq(\"segment_id\", segId)\n .eq(\"customer_id\", custId);\n return error ? { success: false, error: error.message } : { success: true, data: { removed: true } };\n }\n\n // ---- DELETE: deactivate a segment ----\n case \"delete\": {\n const segId = args.segment_id as string;\n if (!segId) return { success: false, error: \"segment_id is required\" };\n const { error } = await sb.from(\"customer_segments\")\n .update({ is_active: false, updated_at: new Date().toISOString() })\n .eq(\"id\", segId)\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 segments action: ${args.action}. Valid: list, get, create, update, members, add_member, remove_member, delete` };\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,9 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ type Result = {
3
+ success: boolean;
4
+ data?: unknown;
5
+ error?: string;
6
+ [key: string]: unknown;
7
+ };
8
+ export declare function handleSocial(sb: SupabaseClient, args: Record<string, unknown>, storeId?: string): Promise<Result>;
9
+ export {};
@@ -0,0 +1,81 @@
1
+ // server/handlers/social.ts — Unified Meta/Google ad campaign management
2
+ // Delegates to meta-ads.ts and google-ads.ts handlers for platform-specific operations.
3
+ // This tool provides a single entry point for multi-platform ad management.
4
+
5
+ import { handleMetaAds } from "./meta-ads.js";
6
+ import { handleGoogleAds } from "./google-ads.js";
7
+ export async function handleSocial(sb, args, storeId) {
8
+ const platform = args.platform;
9
+ if (!platform) {
10
+ return {
11
+ success: false,
12
+ error: "platform is required ('meta' or 'google')"
13
+ };
14
+ }
15
+ switch (platform.toLowerCase()) {
16
+ case "meta":
17
+ case "facebook":
18
+ case "instagram":
19
+ {
20
+ // Delegate to meta_ads handler
21
+ const {
22
+ platform: _,
23
+ ...metaArgs
24
+ } = args;
25
+ return handleMetaAds(sb, metaArgs, storeId);
26
+ }
27
+ case "google":
28
+ {
29
+ // Delegate to google_ads handler
30
+ const {
31
+ platform: _,
32
+ ...googleArgs
33
+ } = args;
34
+ return handleGoogleAds(sb, googleArgs, storeId);
35
+ }
36
+ case "all":
37
+ {
38
+ // Cross-platform summary: fetch campaigns from both platforms
39
+ if (args.action !== "summary") {
40
+ return {
41
+ success: false,
42
+ error: "platform 'all' only supports action 'summary'"
43
+ };
44
+ }
45
+ const [metaResult, googleResult] = await Promise.all([handleMetaAds(sb, {
46
+ action: "list"
47
+ }, storeId).catch(e => ({
48
+ success: false,
49
+ error: e.message,
50
+ data: []
51
+ })), handleGoogleAds(sb, {
52
+ action: "list"
53
+ }, storeId).catch(e => ({
54
+ success: false,
55
+ error: e.message,
56
+ data: []
57
+ }))]);
58
+ return {
59
+ success: true,
60
+ data: {
61
+ meta: {
62
+ connected: metaResult.success,
63
+ campaigns: metaResult.success ? metaResult.data : [],
64
+ error: metaResult.success ? undefined : metaResult.error
65
+ },
66
+ google: {
67
+ connected: googleResult.success,
68
+ campaigns: googleResult.success ? googleResult.data : [],
69
+ error: googleResult.success ? undefined : googleResult.error
70
+ }
71
+ }
72
+ };
73
+ }
74
+ default:
75
+ return {
76
+ success: false,
77
+ error: `Unknown platform: ${platform}. Valid: meta, google, all`
78
+ };
79
+ }
80
+ }
81
+ //# sourceMappingURL=social.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"social.js","names":["handleMetaAds","handleGoogleAds","handleSocial","sb","args","storeId","platform","success","error","toLowerCase","_","metaArgs","googleArgs","action","metaResult","googleResult","Promise","all","catch","e","message","data","meta","connected","campaigns","undefined","google"],"sources":["../../../src/server/handlers/social.ts"],"sourcesContent":["// server/handlers/social.ts — Unified Meta/Google ad campaign management\n// Delegates to meta-ads.ts and google-ads.ts handlers for platform-specific operations.\n// This tool provides a single entry point for multi-platform ad management.\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport { handleMetaAds } from \"./meta-ads.js\";\nimport { handleGoogleAds } from \"./google-ads.js\";\n\ntype Result = { success: boolean; data?: unknown; error?: string; [key: string]: unknown };\n\nexport async function handleSocial(\n sb: SupabaseClient,\n args: Record<string, unknown>,\n storeId?: string,\n): Promise<Result> {\n const platform = args.platform as string;\n if (!platform) {\n return { success: false, error: \"platform is required ('meta' or 'google')\" };\n }\n\n switch (platform.toLowerCase()) {\n case \"meta\":\n case \"facebook\":\n case \"instagram\": {\n // Delegate to meta_ads handler\n const { platform: _, ...metaArgs } = args;\n return handleMetaAds(sb, metaArgs, storeId);\n }\n\n case \"google\": {\n // Delegate to google_ads handler\n const { platform: _, ...googleArgs } = args;\n return handleGoogleAds(sb, googleArgs, storeId);\n }\n\n case \"all\": {\n // Cross-platform summary: fetch campaigns from both platforms\n if (args.action !== \"summary\") {\n return { success: false, error: \"platform 'all' only supports action 'summary'\" };\n }\n\n const [metaResult, googleResult] = await Promise.all([\n handleMetaAds(sb, { action: \"list\" }, storeId).catch(e => ({ success: false, error: e.message, data: [] })),\n handleGoogleAds(sb, { action: \"list\" }, storeId).catch(e => ({ success: false, error: e.message, data: [] })),\n ]);\n\n return {\n success: true,\n data: {\n meta: {\n connected: metaResult.success,\n campaigns: metaResult.success ? metaResult.data : [],\n error: metaResult.success ? undefined : (metaResult as any).error,\n },\n google: {\n connected: googleResult.success,\n campaigns: googleResult.success ? googleResult.data : [],\n error: googleResult.success ? undefined : (googleResult as any).error,\n },\n },\n };\n }\n\n default:\n return { success: false, error: `Unknown platform: ${platform}. Valid: meta, google, all` };\n }\n}\n"],"mappings":"AAAA;AACA;AACA;;AAGA,SAASA,aAAa,QAAQ,eAAe;AAC7C,SAASC,eAAe,QAAQ,iBAAiB;AAIjD,OAAO,eAAeC,YAAYA,CAChCC,EAAkB,EAClBC,IAA6B,EAC7BC,OAAgB,EACC;EACjB,MAAMC,QAAQ,GAAGF,IAAI,CAACE,QAAkB;EACxC,IAAI,CAACA,QAAQ,EAAE;IACb,OAAO;MAAEC,OAAO,EAAE,KAAK;MAAEC,KAAK,EAAE;IAA4C,CAAC;EAC/E;EAEA,QAAQF,QAAQ,CAACG,WAAW,CAAC,CAAC;IAC5B,KAAK,MAAM;IACX,KAAK,UAAU;IACf,KAAK,WAAW;MAAE;QAChB;QACA,MAAM;UAAEH,QAAQ,EAAEI,CAAC;UAAE,GAAGC;QAAS,CAAC,GAAGP,IAAI;QACzC,OAAOJ,aAAa,CAACG,EAAE,EAAEQ,QAAQ,EAAEN,OAAO,CAAC;MAC7C;IAEA,KAAK,QAAQ;MAAE;QACb;QACA,MAAM;UAAEC,QAAQ,EAAEI,CAAC;UAAE,GAAGE;QAAW,CAAC,GAAGR,IAAI;QAC3C,OAAOH,eAAe,CAACE,EAAE,EAAES,UAAU,EAAEP,OAAO,CAAC;MACjD;IAEA,KAAK,KAAK;MAAE;QACV;QACA,IAAID,IAAI,CAACS,MAAM,KAAK,SAAS,EAAE;UAC7B,OAAO;YAAEN,OAAO,EAAE,KAAK;YAAEC,KAAK,EAAE;UAAgD,CAAC;QACnF;QAEA,MAAM,CAACM,UAAU,EAAEC,YAAY,CAAC,GAAG,MAAMC,OAAO,CAACC,GAAG,CAAC,CACnDjB,aAAa,CAACG,EAAE,EAAE;UAAEU,MAAM,EAAE;QAAO,CAAC,EAAER,OAAO,CAAC,CAACa,KAAK,CAACC,CAAC,KAAK;UAAEZ,OAAO,EAAE,KAAK;UAAEC,KAAK,EAAEW,CAAC,CAACC,OAAO;UAAEC,IAAI,EAAE;QAAG,CAAC,CAAC,CAAC,EAC3GpB,eAAe,CAACE,EAAE,EAAE;UAAEU,MAAM,EAAE;QAAO,CAAC,EAAER,OAAO,CAAC,CAACa,KAAK,CAACC,CAAC,KAAK;UAAEZ,OAAO,EAAE,KAAK;UAAEC,KAAK,EAAEW,CAAC,CAACC,OAAO;UAAEC,IAAI,EAAE;QAAG,CAAC,CAAC,CAAC,CAC9G,CAAC;QAEF,OAAO;UACLd,OAAO,EAAE,IAAI;UACbc,IAAI,EAAE;YACJC,IAAI,EAAE;cACJC,SAAS,EAAET,UAAU,CAACP,OAAO;cAC7BiB,SAAS,EAAEV,UAAU,CAACP,OAAO,GAAGO,UAAU,CAACO,IAAI,GAAG,EAAE;cACpDb,KAAK,EAAEM,UAAU,CAACP,OAAO,GAAGkB,SAAS,GAAIX,UAAU,CAASN;YAC9D,CAAC;YACDkB,MAAM,EAAE;cACNH,SAAS,EAAER,YAAY,CAACR,OAAO;cAC/BiB,SAAS,EAAET,YAAY,CAACR,OAAO,GAAGQ,YAAY,CAACM,IAAI,GAAG,EAAE;cACxDb,KAAK,EAAEO,YAAY,CAACR,OAAO,GAAGkB,SAAS,GAAIV,YAAY,CAASP;YAClE;UACF;QACF,CAAC;MACH;IAEA;MACE,OAAO;QAAED,OAAO,EAAE,KAAK;QAAEC,KAAK,EAAE,qBAAqBF,QAAQ;MAA6B,CAAC;EAC/F;AACF","ignoreList":[]}
@@ -0,0 +1,9 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ type Result = {
3
+ success: boolean;
4
+ data?: unknown;
5
+ error?: string;
6
+ [key: string]: unknown;
7
+ };
8
+ export declare function handleTax(sb: SupabaseClient, args: Record<string, unknown>, storeId?: string): Promise<Result>;
9
+ export {};