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 @@
1
+ {"version":3,"file":"invoices.js","names":["sanitizeFilterValue","handleInvoices","sb","args","storeId","sid","action","q","from","select","eq","order","ascending","status","payment_status","customer_id","query","sq","String","or","limit","data","error","success","message","count","length","invoiceId","invoice_id","single","customerEmail","customer_email","maxInv","nextNum","invoice_number","parsed","parseInt","replace","isNaN","invoiceNumber","padStart","lineItems","line_items","subtotal","reduce","s","li","quantity","unit_price","taxAmount","tax_amount","discountAmount","discount_amount","totalAmount","total_amount","Math","round","record","store_id","amount_paid","undefined","order_id","customer_name","customer_phone","description","due_date","notes","internal_notes","insert","updates","updated_at","Date","toISOString","update","sent_at","amount","inv","invErr","newAmountPaid","Number","newPaymentStatus","newStatus","amount_due","paid_at","payment_method","transaction_id"],"sources":["../../../src/server/handlers/invoices.ts"],"sourcesContent":["// server/handlers/invoices.ts — Invoice creation and management\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 handleInvoices(\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 invoices ----\n case \"list\": {\n let q = sb.from(\"invoices\")\n .select(\"id, invoice_number, customer_name, customer_email, total_amount, status, payment_status, amount_paid, amount_due, due_date, sent_at, paid_at, created_at\")\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.payment_status) q = q.eq(\"payment_status\", args.payment_status as string);\n if (args.customer_id) q = q.eq(\"customer_id\", args.customer_id as string);\n if (args.query) {\n const sq = sanitizeFilterValue(String(args.query));\n q = q.or(`invoice_number.ilike.%${sq}%,customer_name.ilike.%${sq}%,customer_email.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 invoice detail ----\n case \"get\": {\n const invoiceId = args.invoice_id as string;\n if (!invoiceId) return { success: false, error: \"invoice_id is required\" };\n const { data, error } = await sb.from(\"invoices\")\n .select(\"*\")\n .eq(\"id\", invoiceId)\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 invoice ----\n case \"create\": {\n const customerEmail = args.customer_email as string;\n if (!customerEmail) return { success: false, error: \"customer_email is required\" };\n\n // Generate sequential invoice number\n const { data: maxInv } = await sb.from(\"invoices\")\n .select(\"invoice_number\")\n .eq(\"store_id\", sid)\n .order(\"created_at\", { ascending: false })\n .limit(1)\n .single();\n let nextNum = 1001;\n if (maxInv?.invoice_number) {\n const parsed = parseInt((maxInv.invoice_number as string).replace(/\\D/g, \"\"), 10);\n if (!isNaN(parsed)) nextNum = parsed + 1;\n }\n const invoiceNumber = `INV-${String(nextNum).padStart(5, \"0\")}`;\n\n const lineItems = args.line_items as Array<{ description: string; quantity: number; unit_price: number }> || [];\n const subtotal = lineItems.reduce((s, li) => s + (li.quantity || 0) * (li.unit_price || 0), 0);\n const taxAmount = (args.tax_amount as number) || 0;\n const discountAmount = (args.discount_amount as number) || 0;\n const totalAmount = args.total_amount as number || Math.round((subtotal + taxAmount - discountAmount) * 100) / 100;\n\n const record: Record<string, unknown> = {\n store_id: sid,\n invoice_number: invoiceNumber,\n customer_email: customerEmail,\n line_items: lineItems,\n subtotal: Math.round(subtotal * 100) / 100,\n tax_amount: taxAmount,\n discount_amount: discountAmount,\n total_amount: totalAmount,\n status: \"draft\",\n payment_status: \"pending\",\n amount_paid: 0,\n };\n if (args.customer_id !== undefined) record.customer_id = args.customer_id;\n if (args.order_id !== undefined) record.order_id = args.order_id;\n if (args.customer_name !== undefined) record.customer_name = args.customer_name;\n if (args.customer_phone !== undefined) record.customer_phone = args.customer_phone;\n if (args.description !== undefined) record.description = args.description;\n if (args.due_date !== undefined) record.due_date = args.due_date;\n if (args.notes !== undefined) record.notes = args.notes;\n if (args.internal_notes !== undefined) record.internal_notes = args.internal_notes;\n\n const { data, error } = await sb.from(\"invoices\")\n .insert(record)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- UPDATE: modify an invoice ----\n case \"update\": {\n const invoiceId = args.invoice_id as string;\n if (!invoiceId) return { success: false, error: \"invoice_id is required\" };\n const updates: Record<string, unknown> = { updated_at: new Date().toISOString() };\n if (args.status !== undefined) updates.status = args.status;\n if (args.payment_status !== undefined) updates.payment_status = args.payment_status;\n if (args.line_items !== undefined) updates.line_items = args.line_items;\n if (args.subtotal !== undefined) updates.subtotal = args.subtotal;\n if (args.tax_amount !== undefined) updates.tax_amount = args.tax_amount;\n if (args.discount_amount !== undefined) updates.discount_amount = args.discount_amount;\n if (args.total_amount !== undefined) updates.total_amount = args.total_amount;\n if (args.amount_paid !== undefined) updates.amount_paid = args.amount_paid;\n if (args.due_date !== undefined) updates.due_date = args.due_date;\n if (args.notes !== undefined) updates.notes = args.notes;\n if (args.internal_notes !== undefined) updates.internal_notes = args.internal_notes;\n if (args.customer_name !== undefined) updates.customer_name = args.customer_name;\n if (args.customer_email !== undefined) updates.customer_email = args.customer_email;\n\n const { data, error } = await sb.from(\"invoices\")\n .update(updates)\n .eq(\"id\", invoiceId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- MARK_SENT: mark an invoice as sent ----\n case \"mark_sent\": {\n const invoiceId = args.invoice_id as string;\n if (!invoiceId) return { success: false, error: \"invoice_id is required\" };\n const { data, error } = await sb.from(\"invoices\")\n .update({ status: \"sent\", sent_at: new Date().toISOString(), updated_at: new Date().toISOString() })\n .eq(\"id\", invoiceId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- RECORD_PAYMENT: record a payment against an invoice ----\n case \"record_payment\": {\n const invoiceId = args.invoice_id as string;\n const amount = args.amount as number;\n if (!invoiceId || amount === undefined) return { success: false, error: \"invoice_id and amount are required\" };\n\n const { data: inv, error: invErr } = await sb.from(\"invoices\")\n .select(\"total_amount, amount_paid\")\n .eq(\"id\", invoiceId)\n .eq(\"store_id\", sid)\n .single();\n if (invErr || !inv) return { success: false, error: invErr?.message || \"Invoice not found\" };\n\n const newAmountPaid = Math.round(((Number(inv.amount_paid) || 0) + amount) * 100) / 100;\n const totalAmount = Number(inv.total_amount) || 0;\n const newPaymentStatus = newAmountPaid >= totalAmount ? \"paid\" : \"partial\";\n const newStatus = newAmountPaid >= totalAmount ? \"paid\" : \"partially_paid\";\n\n const updates: Record<string, unknown> = {\n amount_paid: newAmountPaid,\n amount_due: Math.round((totalAmount - newAmountPaid) * 100) / 100,\n payment_status: newPaymentStatus,\n status: newStatus,\n updated_at: new Date().toISOString(),\n };\n if (newAmountPaid >= totalAmount) updates.paid_at = new Date().toISOString();\n if (args.payment_method) updates.payment_method = args.payment_method;\n if (args.transaction_id) updates.transaction_id = args.transaction_id;\n\n const { data, error } = await sb.from(\"invoices\")\n .update(updates)\n .eq(\"id\", invoiceId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- CANCEL: cancel an invoice ----\n case \"cancel\": {\n const invoiceId = args.invoice_id as string;\n if (!invoiceId) return { success: false, error: \"invoice_id is required\" };\n const { data, error } = await sb.from(\"invoices\")\n .update({ status: \"cancelled\", updated_at: new Date().toISOString() })\n .eq(\"id\", invoiceId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n default:\n return { success: false, error: `Unknown invoices action: ${args.action}. Valid: list, get, create, update, mark_sent, record_payment, cancel` };\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 handleLoyalty(sb: SupabaseClient, args: Record<string, unknown>, storeId?: string): Promise<Result>;
9
+ export {};
@@ -0,0 +1,197 @@
1
+ // server/handlers/loyalty.ts — Loyalty programs, rewards, and customer points management
2
+
3
+ export async function handleLoyalty(sb, args, storeId) {
4
+ const sid = storeId;
5
+ switch (args.action) {
6
+ // ---- GET_PROGRAM: fetch the store's loyalty program config ----
7
+ case "get_program":
8
+ {
9
+ const {
10
+ data,
11
+ error
12
+ } = await sb.from("loyalty_programs").select("*").eq("store_id", sid).maybeSingle();
13
+ if (error) return {
14
+ success: false,
15
+ error: error.message
16
+ };
17
+ if (!data) return {
18
+ success: true,
19
+ data: null,
20
+ error: "No loyalty program configured for this store"
21
+ };
22
+ return {
23
+ success: true,
24
+ data
25
+ };
26
+ }
27
+
28
+ // ---- UPDATE_PROGRAM: update loyalty program settings ----
29
+ case "update_program":
30
+ {
31
+ const updates = {
32
+ updated_at: new Date().toISOString()
33
+ };
34
+ if (args.name !== undefined) updates.name = args.name;
35
+ if (args.description !== undefined) updates.description = args.description;
36
+ if (args.points_per_dollar !== undefined) updates.points_per_dollar = args.points_per_dollar;
37
+ if (args.point_value !== undefined) updates.point_value = args.point_value;
38
+ if (args.min_redemption_points !== undefined) updates.min_redemption_points = args.min_redemption_points;
39
+ if (args.points_expiry_days !== undefined) updates.points_expiry_days = args.points_expiry_days;
40
+ if (args.tiers !== undefined) updates.tiers = args.tiers;
41
+ if (args.is_active !== undefined) updates.is_active = args.is_active;
42
+ if (args.allow_points_on_discounted_items !== undefined) updates.allow_points_on_discounted_items = args.allow_points_on_discounted_items;
43
+ if (args.points_on_tax !== undefined) updates.points_on_tax = args.points_on_tax;
44
+ const {
45
+ data,
46
+ error
47
+ } = await sb.from("loyalty_programs").update(updates).eq("store_id", sid).select().single();
48
+ if (error) return {
49
+ success: false,
50
+ error: error.message
51
+ };
52
+ return {
53
+ success: true,
54
+ data
55
+ };
56
+ }
57
+
58
+ // ---- LIST_REWARDS: list available loyalty rewards ----
59
+ case "list_rewards":
60
+ {
61
+ let q = sb.from("loyalty_rewards").select("*").eq("store_id", sid).order("points_required", {
62
+ ascending: true
63
+ });
64
+ if (args.is_active !== undefined) q = q.eq("is_active", args.is_active);
65
+ if (args.limit) q = q.limit(args.limit);
66
+ const {
67
+ data,
68
+ error
69
+ } = await q;
70
+ return error ? {
71
+ success: false,
72
+ error: error.message
73
+ } : {
74
+ success: true,
75
+ count: data?.length,
76
+ data
77
+ };
78
+ }
79
+
80
+ // ---- CREATE_REWARD: add a new redeemable reward ----
81
+ case "create_reward":
82
+ {
83
+ const name = args.name;
84
+ const pointsRequired = args.points_required;
85
+ const rewardType = args.reward_type;
86
+ if (!name || !pointsRequired || !rewardType) {
87
+ return {
88
+ success: false,
89
+ error: "name, points_required, and reward_type are required"
90
+ };
91
+ }
92
+ const record = {
93
+ store_id: sid,
94
+ name,
95
+ points_required: pointsRequired,
96
+ reward_type: rewardType
97
+ };
98
+ if (args.description !== undefined) record.description = args.description;
99
+ if (args.reward_value !== undefined) record.reward_value = args.reward_value;
100
+ if (args.product_id !== undefined) record.product_id = args.product_id;
101
+ if (args.max_redemptions !== undefined) record.max_redemptions = args.max_redemptions;
102
+ const {
103
+ data,
104
+ error
105
+ } = await sb.from("loyalty_rewards").insert(record).select().single();
106
+ return error ? {
107
+ success: false,
108
+ error: error.message
109
+ } : {
110
+ success: true,
111
+ data
112
+ };
113
+ }
114
+
115
+ // ---- UPDATE_REWARD: modify an existing reward ----
116
+ case "update_reward":
117
+ {
118
+ const rewardId = args.reward_id;
119
+ if (!rewardId) return {
120
+ success: false,
121
+ error: "reward_id is required"
122
+ };
123
+ const updates = {};
124
+ if (args.name !== undefined) updates.name = args.name;
125
+ if (args.description !== undefined) updates.description = args.description;
126
+ if (args.points_required !== undefined) updates.points_required = args.points_required;
127
+ if (args.reward_type !== undefined) updates.reward_type = args.reward_type;
128
+ if (args.reward_value !== undefined) updates.reward_value = args.reward_value;
129
+ if (args.is_active !== undefined) updates.is_active = args.is_active;
130
+ if (args.max_redemptions !== undefined) updates.max_redemptions = args.max_redemptions;
131
+ const {
132
+ data,
133
+ error
134
+ } = await sb.from("loyalty_rewards").update(updates).eq("id", rewardId).eq("store_id", sid).select().single();
135
+ return error ? {
136
+ success: false,
137
+ error: error.message
138
+ } : {
139
+ success: true,
140
+ data
141
+ };
142
+ }
143
+
144
+ // ---- TRANSACTIONS: list loyalty point transactions ----
145
+ case "transactions":
146
+ {
147
+ let q = sb.from("loyalty_transactions").select("*").eq("store_id", sid).order("created_at", {
148
+ ascending: false
149
+ });
150
+ if (args.customer_id) q = q.eq("customer_id", args.customer_id);
151
+ if (args.transaction_type) q = q.eq("transaction_type", args.transaction_type);
152
+ q = q.limit(args.limit || 50);
153
+ const {
154
+ data,
155
+ error
156
+ } = await q;
157
+ return error ? {
158
+ success: false,
159
+ error: error.message
160
+ } : {
161
+ success: true,
162
+ count: data?.length,
163
+ data
164
+ };
165
+ }
166
+
167
+ // ---- ANOMALIES: list loyalty fraud/anomaly alerts ----
168
+ case "anomalies":
169
+ {
170
+ let q = sb.from("loyalty_anomalies").select("*").order("detected_at", {
171
+ ascending: false
172
+ });
173
+ if (args.severity) q = q.eq("severity", args.severity);
174
+ if (args.resolved === false) q = q.is("resolved_at", null);
175
+ if (args.resolved === true) q = q.not("resolved_at", "is", null);
176
+ q = q.limit(args.limit || 25);
177
+ const {
178
+ data,
179
+ error
180
+ } = await q;
181
+ return error ? {
182
+ success: false,
183
+ error: error.message
184
+ } : {
185
+ success: true,
186
+ count: data?.length,
187
+ data
188
+ };
189
+ }
190
+ default:
191
+ return {
192
+ success: false,
193
+ error: `Unknown loyalty action: ${args.action}. Valid: get_program, update_program, list_rewards, create_reward, update_reward, transactions, anomalies`
194
+ };
195
+ }
196
+ }
197
+ //# sourceMappingURL=loyalty.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loyalty.js","names":["handleLoyalty","sb","args","storeId","sid","action","data","error","from","select","eq","maybeSingle","success","message","updates","updated_at","Date","toISOString","name","undefined","description","points_per_dollar","point_value","min_redemption_points","points_expiry_days","tiers","is_active","allow_points_on_discounted_items","points_on_tax","update","single","q","order","ascending","limit","count","length","pointsRequired","points_required","rewardType","reward_type","record","store_id","reward_value","product_id","max_redemptions","insert","rewardId","reward_id","customer_id","transaction_type","severity","resolved","is","not"],"sources":["../../../src/server/handlers/loyalty.ts"],"sourcesContent":["// server/handlers/loyalty.ts — Loyalty programs, rewards, and customer points 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 handleLoyalty(\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 // ---- GET_PROGRAM: fetch the store's loyalty program config ----\n case \"get_program\": {\n const { data, error } = await sb.from(\"loyalty_programs\")\n .select(\"*\")\n .eq(\"store_id\", sid)\n .maybeSingle();\n if (error) return { success: false, error: error.message };\n if (!data) return { success: true, data: null, error: \"No loyalty program configured for this store\" };\n return { success: true, data };\n }\n\n // ---- UPDATE_PROGRAM: update loyalty program settings ----\n case \"update_program\": {\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.points_per_dollar !== undefined) updates.points_per_dollar = args.points_per_dollar;\n if (args.point_value !== undefined) updates.point_value = args.point_value;\n if (args.min_redemption_points !== undefined) updates.min_redemption_points = args.min_redemption_points;\n if (args.points_expiry_days !== undefined) updates.points_expiry_days = args.points_expiry_days;\n if (args.tiers !== undefined) updates.tiers = args.tiers;\n if (args.is_active !== undefined) updates.is_active = args.is_active;\n if (args.allow_points_on_discounted_items !== undefined) updates.allow_points_on_discounted_items = args.allow_points_on_discounted_items;\n if (args.points_on_tax !== undefined) updates.points_on_tax = args.points_on_tax;\n\n const { data, error } = await sb.from(\"loyalty_programs\")\n .update(updates)\n .eq(\"store_id\", sid)\n .select()\n .single();\n if (error) return { success: false, error: error.message };\n return { success: true, data };\n }\n\n // ---- LIST_REWARDS: list available loyalty rewards ----\n case \"list_rewards\": {\n let q = sb.from(\"loyalty_rewards\")\n .select(\"*\")\n .eq(\"store_id\", sid)\n .order(\"points_required\", { ascending: true });\n if (args.is_active !== undefined) q = q.eq(\"is_active\", args.is_active as boolean);\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 // ---- CREATE_REWARD: add a new redeemable reward ----\n case \"create_reward\": {\n const name = args.name as string;\n const pointsRequired = args.points_required as number;\n const rewardType = args.reward_type as string;\n if (!name || !pointsRequired || !rewardType) {\n return { success: false, error: \"name, points_required, and reward_type are required\" };\n }\n const record: Record<string, unknown> = {\n store_id: sid,\n name,\n points_required: pointsRequired,\n reward_type: rewardType,\n };\n if (args.description !== undefined) record.description = args.description;\n if (args.reward_value !== undefined) record.reward_value = args.reward_value;\n if (args.product_id !== undefined) record.product_id = args.product_id;\n if (args.max_redemptions !== undefined) record.max_redemptions = args.max_redemptions;\n\n const { data, error } = await sb.from(\"loyalty_rewards\")\n .insert(record)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- UPDATE_REWARD: modify an existing reward ----\n case \"update_reward\": {\n const rewardId = args.reward_id as string;\n if (!rewardId) return { success: false, error: \"reward_id is required\" };\n const updates: Record<string, unknown> = {};\n if (args.name !== undefined) updates.name = args.name;\n if (args.description !== undefined) updates.description = args.description;\n if (args.points_required !== undefined) updates.points_required = args.points_required;\n if (args.reward_type !== undefined) updates.reward_type = args.reward_type;\n if (args.reward_value !== undefined) updates.reward_value = args.reward_value;\n if (args.is_active !== undefined) updates.is_active = args.is_active;\n if (args.max_redemptions !== undefined) updates.max_redemptions = args.max_redemptions;\n\n const { data, error } = await sb.from(\"loyalty_rewards\")\n .update(updates)\n .eq(\"id\", rewardId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- TRANSACTIONS: list loyalty point transactions ----\n case \"transactions\": {\n let q = sb.from(\"loyalty_transactions\")\n .select(\"*\")\n .eq(\"store_id\", sid)\n .order(\"created_at\", { ascending: false });\n if (args.customer_id) q = q.eq(\"customer_id\", args.customer_id as string);\n if (args.transaction_type) q = q.eq(\"transaction_type\", args.transaction_type as string);\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 // ---- ANOMALIES: list loyalty fraud/anomaly alerts ----\n case \"anomalies\": {\n let q = sb.from(\"loyalty_anomalies\")\n .select(\"*\")\n .order(\"detected_at\", { ascending: false });\n if (args.severity) q = q.eq(\"severity\", args.severity as string);\n if (args.resolved === false) q = q.is(\"resolved_at\", null);\n if (args.resolved === true) q = q.not(\"resolved_at\", \"is\", null);\n q = q.limit(args.limit as number || 25);\n const { data, error } = await q;\n return error ? { success: false, error: error.message } : { success: true, count: data?.length, data };\n }\n\n default:\n return { success: false, error: `Unknown loyalty action: ${args.action}. Valid: get_program, update_program, list_rewards, create_reward, update_reward, transactions, anomalies` };\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -102,6 +102,7 @@ export async function graphDelete(path, token) {
102
102
  // CREDENTIALS
103
103
  // ============================================================================
104
104
 
105
+ const TOKEN_EXPIRY_WARNING_DAYS = 7;
105
106
  export async function getIntegration(sb, storeId) {
106
107
  const {
107
108
  data,
@@ -110,11 +111,25 @@ export async function getIntegration(sb, storeId) {
110
111
  if (error || !data?.access_token_encrypted || !data?.ad_account_id) {
111
112
  throw new Error("Meta not connected. Go to Settings → Meta Connection to link your account.");
112
113
  }
113
- // Warn if token is expired (but still return it — some operations may work with refresh)
114
114
  if (data.token_expires_at) {
115
115
  const expiresAt = new Date(data.token_expires_at);
116
- if (expiresAt < new Date()) {
117
- throw new Error(`Meta access token expired at ${expiresAt.toISOString()}. Reconnect in the CRM app (Settings → Meta Connection).`);
116
+ const daysLeft = (expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24);
117
+ if (daysLeft <= 0) {
118
+ // Token expired — update status so CRM shows reconnect prompt
119
+ if (data.status !== "token_expired") {
120
+ await sb.from("meta_integrations").update({
121
+ status: "token_expired",
122
+ updated_at: new Date().toISOString()
123
+ }).eq("store_id", storeId);
124
+ }
125
+ throw new Error(`Meta access token expired. Reconnect in CRM Settings → Meta Connection.`);
126
+ }
127
+ if (daysLeft <= TOKEN_EXPIRY_WARNING_DAYS && data.status !== "expiring_soon") {
128
+ // Proactively mark as expiring so CRM can show warning banner
129
+ await sb.from("meta_integrations").update({
130
+ status: "expiring_soon",
131
+ updated_at: new Date().toISOString()
132
+ }).eq("store_id", storeId);
118
133
  }
119
134
  }
120
135
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"meta-ads-graph-api.js","names":["META_BASE","enc","v","encodeURIComponent","formBody","params","token","parts","k","Object","entries","undefined","push","JSON","stringify","String","join","parseMetaError","body","path","status","json","parse","err","error","userMsg","error_user_msg","message","code","slice","graphGet","fields","extra","url","res","fetch","ok","text","Error","page1","Array","isArray","data","all","next","paging","pages","r","j","graphPost","method","headers","graphDelete","getIntegration","sb","storeId","from","select","eq","limit","single","access_token_encrypted","ad_account_id","token_expires_at","expiresAt","Date","toISOString","accessToken","adAccountId","businessId","business_id","pageId","page_id","pixelId","pixel_id","instagramAccountId","instagram_business_id","tokenExpiresAt","pageTokenCache","Map","getPageToken","int","cacheKey","cached","get","now","fetchedAt","result","pageToken","access_token","set","size","delete","keys"],"sources":["../../../src/server/handlers/meta-ads-graph-api.ts"],"sourcesContent":["/**\n * Meta Ads — Graph API low-level helpers, credentials, and page token management.\n */\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport { META_BASE, type MetaIntegration } from \"./meta-ads-types.js\";\n\n// ============================================================================\n// GRAPH API — low-level Meta helpers\n// ============================================================================\n\n/** RFC 3986 percent-encode. */\nexport function enc(v: string): string {\n return encodeURIComponent(v);\n}\n\n/** Build form-encoded body from params object + access_token. */\nfunction formBody(params: Record<string, unknown>, token: string): string {\n const parts: string[] = [`access_token=${enc(token)}`];\n for (const [k, v] of Object.entries(params)) {\n if (v === null || v === undefined) continue;\n parts.push(`${k}=${enc(typeof v === \"object\" ? JSON.stringify(v) : String(v))}`);\n }\n return parts.join(\"&\");\n}\n\n/**\n * Parse Meta API error responses into human-readable messages.\n * Extracts error_user_msg when available (much better than raw JSON).\n */\nexport function parseMetaError(body: string, path: string, status: number): string {\n try {\n const json = JSON.parse(body);\n const err = json.error || {};\n const userMsg = err.error_user_msg || err.message || \"Unknown error\";\n const code = err.code ? ` (code ${err.code})` : \"\";\n return `Meta API ${path}: ${userMsg}${code}`;\n } catch {\n return `Meta API ${path}: ${status} — ${body.slice(0, 300)}`;\n }\n}\n\n/** GET from Meta Graph API with auto-pagination. */\nexport async function graphGet(\n path: string,\n fields: string,\n token: string,\n extra?: string,\n): Promise<Record<string, unknown>> {\n let url = `${META_BASE}/${path}?fields=${fields}&access_token=${enc(token)}&limit=200`;\n if (extra) url += `&${extra}`;\n\n const res = await fetch(url);\n if (!res.ok) {\n const body = await res.text();\n throw new Error(parseMetaError(body, path, res.status));\n }\n const page1 = (await res.json()) as Record<string, unknown>;\n\n // Single-object response — return as-is\n if (!Array.isArray(page1.data)) return page1;\n\n // List response — paginate up to 20 pages\n const all = [...(page1.data as Record<string, unknown>[])];\n let next = (page1.paging as Record<string, unknown>)?.next as string | undefined;\n let pages = 1;\n while (next && pages < 20) {\n const r = await fetch(next);\n if (!r.ok) break;\n const j = (await r.json()) as Record<string, unknown>;\n if (Array.isArray(j.data)) all.push(...(j.data as Record<string, unknown>[]));\n next = (j.paging as Record<string, unknown>)?.next as string | undefined;\n pages++;\n }\n return { data: all };\n}\n\n/** POST to Meta Graph API with form encoding. */\nexport async function graphPost(\n path: string,\n params: Record<string, unknown>,\n token: string,\n): Promise<Record<string, unknown>> {\n const res = await fetch(`${META_BASE}/${path}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: formBody(params, token),\n });\n if (!res.ok) {\n const body = await res.text();\n throw new Error(parseMetaError(body, path, res.status));\n }\n return (await res.json()) as Record<string, unknown>;\n}\n\n/** DELETE from Meta Graph API. */\nexport async function graphDelete(\n path: string,\n token: string,\n): Promise<Record<string, unknown>> {\n const res = await fetch(`${META_BASE}/${path}?access_token=${enc(token)}`, {\n method: \"DELETE\",\n });\n if (!res.ok) {\n const body = await res.text();\n throw new Error(parseMetaError(body, path, res.status));\n }\n return (await res.json()) as Record<string, unknown>;\n}\n\n// ============================================================================\n// CREDENTIALS\n// ============================================================================\n\nexport async function getIntegration(sb: SupabaseClient, storeId: string): Promise<MetaIntegration> {\n const { data, error } = await sb\n .from(\"meta_integrations\")\n .select(\"access_token_encrypted, ad_account_id, business_id, page_id, pixel_id, instagram_business_id, token_expires_at, status\")\n .eq(\"store_id\", storeId)\n .limit(1)\n .single();\n if (error || !data?.access_token_encrypted || !data?.ad_account_id) {\n throw new Error(\"Meta not connected. Go to Settings → Meta Connection to link your account.\");\n }\n // Warn if token is expired (but still return it — some operations may work with refresh)\n if (data.token_expires_at) {\n const expiresAt = new Date(data.token_expires_at);\n if (expiresAt < new Date()) {\n throw new Error(`Meta access token expired at ${expiresAt.toISOString()}. Reconnect in the CRM app (Settings → Meta Connection).`);\n }\n }\n return {\n accessToken: data.access_token_encrypted,\n adAccountId: data.ad_account_id,\n businessId: data.business_id || null,\n pageId: data.page_id || null,\n pixelId: data.pixel_id || null,\n instagramAccountId: data.instagram_business_id || null,\n tokenExpiresAt: data.token_expires_at || null,\n };\n}\n\n/** Page Access Token cache (user token → page token). Avoids re-fetching every call. */\nconst pageTokenCache = new Map<string, { token: string; fetchedAt: number }>();\n\n/**\n * Exchange user access token for a Page Access Token.\n * Required for lead forms, page-level APIs, and some creative operations.\n * Cached for 5 minutes.\n */\nexport async function getPageToken(int: MetaIntegration): Promise<string> {\n if (!int.pageId) throw new Error(\"No Facebook Page linked. Add page_id in Meta Connection settings.\");\n\n const cacheKey = `${int.pageId}:${int.accessToken.slice(-10)}`;\n const cached = pageTokenCache.get(cacheKey);\n if (cached && Date.now() - cached.fetchedAt < 300_000) return cached.token;\n\n const result = await graphGet(int.pageId, \"access_token\", int.accessToken);\n const pageToken = result.access_token as string;\n if (!pageToken) throw new Error(\"Could not get Page Access Token. Ensure your token has pages_manage_ads permission.\");\n\n pageTokenCache.set(cacheKey, { token: pageToken, fetchedAt: Date.now() });\n // Evict old entries\n if (pageTokenCache.size > 20) pageTokenCache.delete([...pageTokenCache.keys()][0]);\n\n return pageToken;\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"meta-ads-graph-api.js","names":["META_BASE","enc","v","encodeURIComponent","formBody","params","token","parts","k","Object","entries","undefined","push","JSON","stringify","String","join","parseMetaError","body","path","status","json","parse","err","error","userMsg","error_user_msg","message","code","slice","graphGet","fields","extra","url","res","fetch","ok","text","Error","page1","Array","isArray","data","all","next","paging","pages","r","j","graphPost","method","headers","graphDelete","TOKEN_EXPIRY_WARNING_DAYS","getIntegration","sb","storeId","from","select","eq","limit","single","access_token_encrypted","ad_account_id","token_expires_at","expiresAt","Date","daysLeft","getTime","now","update","updated_at","toISOString","accessToken","adAccountId","businessId","business_id","pageId","page_id","pixelId","pixel_id","instagramAccountId","instagram_business_id","tokenExpiresAt","pageTokenCache","Map","getPageToken","int","cacheKey","cached","get","fetchedAt","result","pageToken","access_token","set","size","delete","keys"],"sources":["../../../src/server/handlers/meta-ads-graph-api.ts"],"sourcesContent":["/**\n * Meta Ads — Graph API low-level helpers, credentials, and page token management.\n */\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport { META_BASE, type MetaIntegration } from \"./meta-ads-types.js\";\n\n// ============================================================================\n// GRAPH API — low-level Meta helpers\n// ============================================================================\n\n/** RFC 3986 percent-encode. */\nexport function enc(v: string): string {\n return encodeURIComponent(v);\n}\n\n/** Build form-encoded body from params object + access_token. */\nfunction formBody(params: Record<string, unknown>, token: string): string {\n const parts: string[] = [`access_token=${enc(token)}`];\n for (const [k, v] of Object.entries(params)) {\n if (v === null || v === undefined) continue;\n parts.push(`${k}=${enc(typeof v === \"object\" ? JSON.stringify(v) : String(v))}`);\n }\n return parts.join(\"&\");\n}\n\n/**\n * Parse Meta API error responses into human-readable messages.\n * Extracts error_user_msg when available (much better than raw JSON).\n */\nexport function parseMetaError(body: string, path: string, status: number): string {\n try {\n const json = JSON.parse(body);\n const err = json.error || {};\n const userMsg = err.error_user_msg || err.message || \"Unknown error\";\n const code = err.code ? ` (code ${err.code})` : \"\";\n return `Meta API ${path}: ${userMsg}${code}`;\n } catch {\n return `Meta API ${path}: ${status} — ${body.slice(0, 300)}`;\n }\n}\n\n/** GET from Meta Graph API with auto-pagination. */\nexport async function graphGet(\n path: string,\n fields: string,\n token: string,\n extra?: string,\n): Promise<Record<string, unknown>> {\n let url = `${META_BASE}/${path}?fields=${fields}&access_token=${enc(token)}&limit=200`;\n if (extra) url += `&${extra}`;\n\n const res = await fetch(url);\n if (!res.ok) {\n const body = await res.text();\n throw new Error(parseMetaError(body, path, res.status));\n }\n const page1 = (await res.json()) as Record<string, unknown>;\n\n // Single-object response — return as-is\n if (!Array.isArray(page1.data)) return page1;\n\n // List response — paginate up to 20 pages\n const all = [...(page1.data as Record<string, unknown>[])];\n let next = (page1.paging as Record<string, unknown>)?.next as string | undefined;\n let pages = 1;\n while (next && pages < 20) {\n const r = await fetch(next);\n if (!r.ok) break;\n const j = (await r.json()) as Record<string, unknown>;\n if (Array.isArray(j.data)) all.push(...(j.data as Record<string, unknown>[]));\n next = (j.paging as Record<string, unknown>)?.next as string | undefined;\n pages++;\n }\n return { data: all };\n}\n\n/** POST to Meta Graph API with form encoding. */\nexport async function graphPost(\n path: string,\n params: Record<string, unknown>,\n token: string,\n): Promise<Record<string, unknown>> {\n const res = await fetch(`${META_BASE}/${path}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: formBody(params, token),\n });\n if (!res.ok) {\n const body = await res.text();\n throw new Error(parseMetaError(body, path, res.status));\n }\n return (await res.json()) as Record<string, unknown>;\n}\n\n/** DELETE from Meta Graph API. */\nexport async function graphDelete(\n path: string,\n token: string,\n): Promise<Record<string, unknown>> {\n const res = await fetch(`${META_BASE}/${path}?access_token=${enc(token)}`, {\n method: \"DELETE\",\n });\n if (!res.ok) {\n const body = await res.text();\n throw new Error(parseMetaError(body, path, res.status));\n }\n return (await res.json()) as Record<string, unknown>;\n}\n\n// ============================================================================\n// CREDENTIALS\n// ============================================================================\n\nconst TOKEN_EXPIRY_WARNING_DAYS = 7;\n\nexport async function getIntegration(sb: SupabaseClient, storeId: string): Promise<MetaIntegration> {\n const { data, error } = await sb\n .from(\"meta_integrations\")\n .select(\"access_token_encrypted, ad_account_id, business_id, page_id, pixel_id, instagram_business_id, token_expires_at, status\")\n .eq(\"store_id\", storeId)\n .limit(1)\n .single();\n if (error || !data?.access_token_encrypted || !data?.ad_account_id) {\n throw new Error(\"Meta not connected. Go to Settings → Meta Connection to link your account.\");\n }\n\n if (data.token_expires_at) {\n const expiresAt = new Date(data.token_expires_at);\n const daysLeft = (expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24);\n\n if (daysLeft <= 0) {\n // Token expired — update status so CRM shows reconnect prompt\n if (data.status !== \"token_expired\") {\n await sb.from(\"meta_integrations\")\n .update({ status: \"token_expired\", updated_at: new Date().toISOString() })\n .eq(\"store_id\", storeId);\n }\n throw new Error(`Meta access token expired. Reconnect in CRM Settings → Meta Connection.`);\n }\n\n if (daysLeft <= TOKEN_EXPIRY_WARNING_DAYS && data.status !== \"expiring_soon\") {\n // Proactively mark as expiring so CRM can show warning banner\n await sb.from(\"meta_integrations\")\n .update({ status: \"expiring_soon\", updated_at: new Date().toISOString() })\n .eq(\"store_id\", storeId);\n }\n }\n\n return {\n accessToken: data.access_token_encrypted,\n adAccountId: data.ad_account_id,\n businessId: data.business_id || null,\n pageId: data.page_id || null,\n pixelId: data.pixel_id || null,\n instagramAccountId: data.instagram_business_id || null,\n tokenExpiresAt: data.token_expires_at || null,\n };\n}\n\n/** Page Access Token cache (user token → page token). Avoids re-fetching every call. */\nconst pageTokenCache = new Map<string, { token: string; fetchedAt: number }>();\n\n/**\n * Exchange user access token for a Page Access Token.\n * Required for lead forms, page-level APIs, and some creative operations.\n * Cached for 5 minutes.\n */\nexport async function getPageToken(int: MetaIntegration): Promise<string> {\n if (!int.pageId) throw new Error(\"No Facebook Page linked. Add page_id in Meta Connection settings.\");\n\n const cacheKey = `${int.pageId}:${int.accessToken.slice(-10)}`;\n const cached = pageTokenCache.get(cacheKey);\n if (cached && Date.now() - cached.fetchedAt < 300_000) return cached.token;\n\n const result = await graphGet(int.pageId, \"access_token\", int.accessToken);\n const pageToken = result.access_token as string;\n if (!pageToken) throw new Error(\"Could not get Page Access Token. Ensure your token has pages_manage_ads permission.\");\n\n pageTokenCache.set(cacheKey, { token: pageToken, fetchedAt: Date.now() });\n // Evict old entries\n if (pageTokenCache.size > 20) pageTokenCache.delete([...pageTokenCache.keys()][0]);\n\n return pageToken;\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 handlePhone(sb: SupabaseClient, args: Record<string, unknown>, storeId?: string): Promise<Result>;
9
+ export {};
@@ -0,0 +1,197 @@
1
+ // server/handlers/phone.ts — RingCentral integration: calls, SMS, voicemail
2
+
3
+ export async function handlePhone(sb, args, storeId) {
4
+ const sid = storeId;
5
+ switch (args.action) {
6
+ // ---- STATUS: get RingCentral integration status ----
7
+ case "status":
8
+ {
9
+ const {
10
+ data,
11
+ error
12
+ } = await sb.from("rc_integrations").select("id, status, main_number, webhook_status, sync_enabled, last_synced_at, sync_error, created_at").eq("store_id", sid).maybeSingle();
13
+ if (error) return {
14
+ success: false,
15
+ error: error.message
16
+ };
17
+ if (!data) return {
18
+ success: true,
19
+ data: {
20
+ connected: false,
21
+ message: "RingCentral not configured"
22
+ }
23
+ };
24
+ return {
25
+ success: true,
26
+ data: {
27
+ connected: data.status === "connected",
28
+ ...data
29
+ }
30
+ };
31
+ }
32
+
33
+ // ---- EXTENSIONS: list phone extensions ----
34
+ case "extensions":
35
+ {
36
+ const {
37
+ data,
38
+ error
39
+ } = await sb.from("rc_extensions").select("id, rc_extension_id, extension_number, name, type, status, email, presence_status, telephony_status, dnd_status").eq("store_id", sid).order("extension_number", {
40
+ ascending: true
41
+ });
42
+ return error ? {
43
+ success: false,
44
+ error: error.message
45
+ } : {
46
+ success: true,
47
+ count: data?.length,
48
+ data
49
+ };
50
+ }
51
+
52
+ // ---- CALL_LOGS: list call logs ----
53
+ case "call_logs":
54
+ {
55
+ let q = sb.from("rc_call_logs").select("id, rc_call_id, direction, type, result, from_number, from_name, to_number, to_name, start_time, duration, recording_url, customer_id, created_at").eq("store_id", sid).order("start_time", {
56
+ ascending: false
57
+ });
58
+ if (args.direction) q = q.eq("direction", args.direction);
59
+ if (args.result) q = q.eq("result", args.result);
60
+ if (args.customer_id) q = q.eq("customer_id", args.customer_id);
61
+ if (args.from_number) q = q.eq("from_number", args.from_number);
62
+ if (args.to_number) q = q.eq("to_number", args.to_number);
63
+ q = q.limit(args.limit || 50);
64
+ const {
65
+ data,
66
+ error
67
+ } = await q;
68
+ return error ? {
69
+ success: false,
70
+ error: error.message
71
+ } : {
72
+ success: true,
73
+ count: data?.length,
74
+ data
75
+ };
76
+ }
77
+
78
+ // ---- SMS_MESSAGES: list SMS messages ----
79
+ case "sms_messages":
80
+ {
81
+ let q = sb.from("rc_sms_messages").select("id, rc_message_id, direction, body, from_number, to_numbers, delivery_status, read_status, customer_id, created_at").eq("store_id", sid).order("created_at", {
82
+ ascending: false
83
+ });
84
+ if (args.direction) q = q.eq("direction", args.direction);
85
+ if (args.customer_id) q = q.eq("customer_id", args.customer_id);
86
+ q = q.limit(args.limit || 50);
87
+ const {
88
+ data,
89
+ error
90
+ } = await q;
91
+ return error ? {
92
+ success: false,
93
+ error: error.message
94
+ } : {
95
+ success: true,
96
+ count: data?.length,
97
+ data
98
+ };
99
+ }
100
+
101
+ // ---- SMS_TEMPLATES: list SMS templates ----
102
+ case "sms_templates":
103
+ {
104
+ const {
105
+ data,
106
+ error
107
+ } = await sb.from("rc_sms_templates").select("*").eq("store_id", sid).eq("is_active", true).order("usage_count", {
108
+ ascending: false
109
+ });
110
+ return error ? {
111
+ success: false,
112
+ error: error.message
113
+ } : {
114
+ success: true,
115
+ count: data?.length,
116
+ data
117
+ };
118
+ }
119
+
120
+ // ---- VOICEMAILS: list voicemails ----
121
+ case "voicemails":
122
+ {
123
+ let q = sb.from("rc_voicemails").select("id, rc_message_id, from_number, from_name, to_extension_id, duration, transcription, read_status, customer_id, created_at").eq("store_id", sid).order("created_at", {
124
+ ascending: false
125
+ });
126
+ if (args.read_status) q = q.eq("read_status", args.read_status);
127
+ if (args.customer_id) q = q.eq("customer_id", args.customer_id);
128
+ q = q.limit(args.limit || 50);
129
+ const {
130
+ data,
131
+ error
132
+ } = await q;
133
+ return error ? {
134
+ success: false,
135
+ error: error.message
136
+ } : {
137
+ success: true,
138
+ count: data?.length,
139
+ data
140
+ };
141
+ }
142
+
143
+ // ---- CALL_ANALYTICS: get call analytics for a date range ----
144
+ case "call_analytics":
145
+ {
146
+ let q = sb.from("rc_call_analytics").select("*").eq("store_id", sid).order("date", {
147
+ ascending: false
148
+ });
149
+ if (args.start_date) q = q.gte("date", args.start_date);
150
+ if (args.end_date) q = q.lte("date", args.end_date);
151
+ if (args.extension_id) q = q.eq("extension_id", args.extension_id);
152
+ q = q.limit(args.limit || 30);
153
+ const {
154
+ data,
155
+ error
156
+ } = await q;
157
+ return error ? {
158
+ success: false,
159
+ error: error.message
160
+ } : {
161
+ success: true,
162
+ count: data?.length,
163
+ data
164
+ };
165
+ }
166
+
167
+ // ---- MARK_READ: mark a voicemail as read ----
168
+ case "mark_read":
169
+ {
170
+ const vmId = args.voicemail_id;
171
+ if (!vmId) return {
172
+ success: false,
173
+ error: "voicemail_id is required"
174
+ };
175
+ const {
176
+ data,
177
+ error
178
+ } = await sb.from("rc_voicemails").update({
179
+ read_status: "Read",
180
+ updated_at: new Date().toISOString()
181
+ }).eq("id", vmId).eq("store_id", sid).select().single();
182
+ return error ? {
183
+ success: false,
184
+ error: error.message
185
+ } : {
186
+ success: true,
187
+ data
188
+ };
189
+ }
190
+ default:
191
+ return {
192
+ success: false,
193
+ error: `Unknown phone action: ${args.action}. Valid: status, extensions, call_logs, sms_messages, sms_templates, voicemails, call_analytics, mark_read`
194
+ };
195
+ }
196
+ }
197
+ //# sourceMappingURL=phone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone.js","names":["handlePhone","sb","args","storeId","sid","action","data","error","from","select","eq","maybeSingle","success","message","connected","status","order","ascending","count","length","q","direction","result","customer_id","from_number","to_number","limit","read_status","start_date","gte","end_date","lte","extension_id","vmId","voicemail_id","update","updated_at","Date","toISOString","single"],"sources":["../../../src/server/handlers/phone.ts"],"sourcesContent":["// server/handlers/phone.ts — RingCentral integration: calls, SMS, voicemail\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\n\ntype Result = { success: boolean; data?: unknown; error?: string; [key: string]: unknown };\n\nexport async function handlePhone(\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 // ---- STATUS: get RingCentral integration status ----\n case \"status\": {\n const { data, error } = await sb.from(\"rc_integrations\")\n .select(\"id, status, main_number, webhook_status, sync_enabled, last_synced_at, sync_error, created_at\")\n .eq(\"store_id\", sid)\n .maybeSingle();\n if (error) return { success: false, error: error.message };\n if (!data) return { success: true, data: { connected: false, message: \"RingCentral not configured\" } };\n return { success: true, data: { connected: data.status === \"connected\", ...data } };\n }\n\n // ---- EXTENSIONS: list phone extensions ----\n case \"extensions\": {\n const { data, error } = await sb.from(\"rc_extensions\")\n .select(\"id, rc_extension_id, extension_number, name, type, status, email, presence_status, telephony_status, dnd_status\")\n .eq(\"store_id\", sid)\n .order(\"extension_number\", { ascending: true });\n return error ? { success: false, error: error.message } : { success: true, count: data?.length, data };\n }\n\n // ---- CALL_LOGS: list call logs ----\n case \"call_logs\": {\n let q = sb.from(\"rc_call_logs\")\n .select(\"id, rc_call_id, direction, type, result, from_number, from_name, to_number, to_name, start_time, duration, recording_url, customer_id, created_at\")\n .eq(\"store_id\", sid)\n .order(\"start_time\", { ascending: false });\n if (args.direction) q = q.eq(\"direction\", args.direction as string);\n if (args.result) q = q.eq(\"result\", args.result as string);\n if (args.customer_id) q = q.eq(\"customer_id\", args.customer_id as string);\n if (args.from_number) q = q.eq(\"from_number\", args.from_number as string);\n if (args.to_number) q = q.eq(\"to_number\", args.to_number as string);\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 // ---- SMS_MESSAGES: list SMS messages ----\n case \"sms_messages\": {\n let q = sb.from(\"rc_sms_messages\")\n .select(\"id, rc_message_id, direction, body, from_number, to_numbers, delivery_status, read_status, customer_id, created_at\")\n .eq(\"store_id\", sid)\n .order(\"created_at\", { ascending: false });\n if (args.direction) q = q.eq(\"direction\", args.direction as string);\n if (args.customer_id) q = q.eq(\"customer_id\", args.customer_id as string);\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 // ---- SMS_TEMPLATES: list SMS templates ----\n case \"sms_templates\": {\n const { data, error } = await sb.from(\"rc_sms_templates\")\n .select(\"*\")\n .eq(\"store_id\", sid)\n .eq(\"is_active\", true)\n .order(\"usage_count\", { ascending: false });\n return error ? { success: false, error: error.message } : { success: true, count: data?.length, data };\n }\n\n // ---- VOICEMAILS: list voicemails ----\n case \"voicemails\": {\n let q = sb.from(\"rc_voicemails\")\n .select(\"id, rc_message_id, from_number, from_name, to_extension_id, duration, transcription, read_status, customer_id, created_at\")\n .eq(\"store_id\", sid)\n .order(\"created_at\", { ascending: false });\n if (args.read_status) q = q.eq(\"read_status\", args.read_status as string);\n if (args.customer_id) q = q.eq(\"customer_id\", args.customer_id as string);\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 // ---- CALL_ANALYTICS: get call analytics for a date range ----\n case \"call_analytics\": {\n let q = sb.from(\"rc_call_analytics\")\n .select(\"*\")\n .eq(\"store_id\", sid)\n .order(\"date\", { ascending: false });\n if (args.start_date) q = q.gte(\"date\", args.start_date as string);\n if (args.end_date) q = q.lte(\"date\", args.end_date as string);\n if (args.extension_id) q = q.eq(\"extension_id\", args.extension_id as string);\n q = q.limit(args.limit as number || 30);\n const { data, error } = await q;\n return error ? { success: false, error: error.message } : { success: true, count: data?.length, data };\n }\n\n // ---- MARK_READ: mark a voicemail as read ----\n case \"mark_read\": {\n const vmId = args.voicemail_id as string;\n if (!vmId) return { success: false, error: \"voicemail_id is required\" };\n const { data, error } = await sb.from(\"rc_voicemails\")\n .update({ read_status: \"Read\", updated_at: new Date().toISOString() })\n .eq(\"id\", vmId)\n .eq(\"store_id\", sid)\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n default:\n return { success: false, error: `Unknown phone action: ${args.action}. Valid: status, extensions, call_logs, sms_messages, sms_templates, voicemails, call_analytics, mark_read` };\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 handlePipeline(sb: SupabaseClient, args: Record<string, unknown>, storeId?: string): Promise<Result>;
9
+ export {};