whale-code 6.5.8 → 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 (99) hide show
  1. package/dist/cli/services/agent-loop.js +26 -2
  2. package/dist/cli/services/agent-loop.js.map +1 -1
  3. package/dist/cli/services/hooks.js +2 -1
  4. package/dist/cli/services/hooks.js.map +1 -1
  5. package/dist/cli/services/telemetry-spans.js +1 -0
  6. package/dist/cli/services/telemetry-spans.js.map +1 -1
  7. package/dist/cli/services/telemetry.d.ts +23 -0
  8. package/dist/cli/services/telemetry.js +45 -1
  9. package/dist/cli/services/telemetry.js.map +1 -1
  10. package/dist/server/handlers/__test-utils__/test-db.d.ts +17 -3
  11. package/dist/server/handlers/__test-utils__/test-db.js +113 -14
  12. package/dist/server/handlers/__test-utils__/test-db.js.map +1 -1
  13. package/dist/server/handlers/affiliates.d.ts +9 -0
  14. package/dist/server/handlers/affiliates.js +197 -0
  15. package/dist/server/handlers/affiliates.js.map +1 -0
  16. package/dist/server/handlers/api-docs.d.ts +4 -2
  17. package/dist/server/handlers/api-docs.js +204 -1681
  18. package/dist/server/handlers/api-docs.js.map +1 -1
  19. package/dist/server/handlers/campaigns.d.ts +9 -0
  20. package/dist/server/handlers/campaigns.js +237 -0
  21. package/dist/server/handlers/campaigns.js.map +1 -0
  22. package/dist/server/handlers/catalog-schemas.js +9 -9
  23. package/dist/server/handlers/catalog-schemas.js.map +1 -1
  24. package/dist/server/handlers/catalog.js +1 -1
  25. package/dist/server/handlers/catalog.js.map +1 -1
  26. package/dist/server/handlers/comms-documents.js +28 -2
  27. package/dist/server/handlers/comms-documents.js.map +1 -1
  28. package/dist/server/handlers/comms-pdf-generation.js +25 -3
  29. package/dist/server/handlers/comms-pdf-generation.js.map +1 -1
  30. package/dist/server/handlers/comms-pdf-helpers.js +4 -4
  31. package/dist/server/handlers/comms-pdf-helpers.js.map +1 -1
  32. package/dist/server/handlers/comms.d.ts +100 -0
  33. package/dist/server/handlers/comms.js +146 -12
  34. package/dist/server/handlers/comms.js.map +1 -1
  35. package/dist/server/handlers/coupons.d.ts +9 -0
  36. package/dist/server/handlers/coupons.js +220 -0
  37. package/dist/server/handlers/coupons.js.map +1 -0
  38. package/dist/server/handlers/embeddings.js +1 -1
  39. package/dist/server/handlers/embeddings.js.map +1 -1
  40. package/dist/server/handlers/enrichment.js +2 -622
  41. package/dist/server/handlers/enrichment.js.map +1 -1
  42. package/dist/server/handlers/fulfillment.d.ts +9 -0
  43. package/dist/server/handlers/fulfillment.js +209 -0
  44. package/dist/server/handlers/fulfillment.js.map +1 -0
  45. package/dist/server/handlers/google-ads.d.ts +24 -0
  46. package/dist/server/handlers/google-ads.js +2199 -0
  47. package/dist/server/handlers/google-ads.js.map +1 -0
  48. package/dist/server/handlers/invoices.d.ts +9 -0
  49. package/dist/server/handlers/invoices.js +252 -0
  50. package/dist/server/handlers/invoices.js.map +1 -0
  51. package/dist/server/handlers/loyalty.d.ts +9 -0
  52. package/dist/server/handlers/loyalty.js +197 -0
  53. package/dist/server/handlers/loyalty.js.map +1 -0
  54. package/dist/server/handlers/meta-ads-graph-api.js +18 -3
  55. package/dist/server/handlers/meta-ads-graph-api.js.map +1 -1
  56. package/dist/server/handlers/phone.d.ts +9 -0
  57. package/dist/server/handlers/phone.js +197 -0
  58. package/dist/server/handlers/phone.js.map +1 -0
  59. package/dist/server/handlers/pipeline.d.ts +9 -0
  60. package/dist/server/handlers/pipeline.js +277 -0
  61. package/dist/server/handlers/pipeline.js.map +1 -0
  62. package/dist/server/handlers/qr-codes.d.ts +9 -0
  63. package/dist/server/handlers/qr-codes.js +198 -0
  64. package/dist/server/handlers/qr-codes.js.map +1 -0
  65. package/dist/server/handlers/reviews.d.ts +9 -0
  66. package/dist/server/handlers/reviews.js +171 -0
  67. package/dist/server/handlers/reviews.js.map +1 -0
  68. package/dist/server/handlers/segments.d.ts +9 -0
  69. package/dist/server/handlers/segments.js +229 -0
  70. package/dist/server/handlers/segments.js.map +1 -0
  71. package/dist/server/handlers/social.d.ts +9 -0
  72. package/dist/server/handlers/social.js +81 -0
  73. package/dist/server/handlers/social.js.map +1 -0
  74. package/dist/server/handlers/tax.d.ts +9 -0
  75. package/dist/server/handlers/tax.js +182 -0
  76. package/dist/server/handlers/tax.js.map +1 -0
  77. package/dist/server/handlers/wallet.d.ts +9 -0
  78. package/dist/server/handlers/wallet.js +203 -0
  79. package/dist/server/handlers/wallet.js.map +1 -0
  80. package/dist/server/handlers/webhooks-mgmt.d.ts +9 -0
  81. package/dist/server/handlers/webhooks-mgmt.js +181 -0
  82. package/dist/server/handlers/webhooks-mgmt.js.map +1 -0
  83. package/dist/server/handlers/wholesale.d.ts +9 -0
  84. package/dist/server/handlers/wholesale.js +219 -0
  85. package/dist/server/handlers/wholesale.js.map +1 -0
  86. package/dist/server/index.js +20 -9
  87. package/dist/server/index.js.map +1 -1
  88. package/dist/server/lib/clickhouse-buffer.js +1 -0
  89. package/dist/server/lib/clickhouse-buffer.js.map +1 -1
  90. package/dist/server/lib/coa-renderer.d.ts +1 -1
  91. package/dist/server/lib/coa-renderer.js +32 -10
  92. package/dist/server/lib/coa-renderer.js.map +1 -1
  93. package/dist/server/server-worker.d.ts +1 -0
  94. package/dist/server/server-worker.js +464 -3
  95. package/dist/server/server-worker.js.map +1 -1
  96. package/dist/server/tool-router.js +118 -4
  97. package/dist/server/tool-router.js.map +1 -1
  98. package/package.json +26 -3
  99. package/vendor/ink/package.json +0 -2
@@ -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 handleWholesale(sb: SupabaseClient, args: Record<string, unknown>, storeId?: string): Promise<Result>;
9
+ export {};
@@ -0,0 +1,219 @@
1
+ // server/handlers/wholesale.ts — Wholesale pricing, applications, and purchase orders
2
+
3
+ import { sanitizeFilterValue } from "../lib/utils.js";
4
+ export async function handleWholesale(sb, args, storeId) {
5
+ const sid = storeId;
6
+ switch (args.action) {
7
+ // ---- LIST_PRICING: list wholesale pricing tiers ----
8
+ case "list_pricing":
9
+ {
10
+ let q = sb.from("wholesale_pricing").select("*, product:products!product_id(name, sku)").eq("store_id", sid).order("product_id", {
11
+ ascending: true
12
+ }).order("minimum_quantity", {
13
+ ascending: true
14
+ });
15
+ if (args.product_id) q = q.eq("product_id", args.product_id);
16
+ if (args.is_active !== undefined) q = q.eq("is_active", args.is_active);
17
+ if (args.tier_name) q = q.eq("tier_name", args.tier_name);
18
+ q = q.limit(args.limit || 100);
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
+ // ---- SET_PRICING: create or update wholesale pricing for a product ----
34
+ case "set_pricing":
35
+ {
36
+ const productId = args.product_id;
37
+ const tierName = args.tier_name;
38
+ const minimumQuantity = args.minimum_quantity;
39
+ const unitPrice = args.unit_price;
40
+ if (!productId || !tierName || minimumQuantity === undefined || unitPrice === undefined) {
41
+ return {
42
+ success: false,
43
+ error: "product_id, tier_name, minimum_quantity, and unit_price are required"
44
+ };
45
+ }
46
+ const record = {
47
+ store_id: sid,
48
+ product_id: productId,
49
+ tier_name: tierName,
50
+ minimum_quantity: minimumQuantity,
51
+ unit_price: unitPrice
52
+ };
53
+ if (args.discount_percentage !== undefined) record.discount_percentage = args.discount_percentage;
54
+ if (args.description !== undefined) record.description = args.description;
55
+ if (args.terms !== undefined) record.terms = args.terms;
56
+ if (args.starts_at !== undefined) record.starts_at = args.starts_at;
57
+ if (args.ends_at !== undefined) record.ends_at = args.ends_at;
58
+ const {
59
+ data,
60
+ error
61
+ } = await sb.from("wholesale_pricing").upsert(record, {
62
+ onConflict: "product_id,minimum_quantity"
63
+ }).select().single();
64
+ return error ? {
65
+ success: false,
66
+ error: error.message
67
+ } : {
68
+ success: true,
69
+ data
70
+ };
71
+ }
72
+
73
+ // ---- DELETE_PRICING: remove a wholesale pricing tier ----
74
+ case "delete_pricing":
75
+ {
76
+ const pricingId = args.pricing_id;
77
+ if (!pricingId) return {
78
+ success: false,
79
+ error: "pricing_id is required"
80
+ };
81
+ const {
82
+ error
83
+ } = await sb.from("wholesale_pricing").delete().eq("id", pricingId).eq("store_id", sid);
84
+ return error ? {
85
+ success: false,
86
+ error: error.message
87
+ } : {
88
+ success: true,
89
+ data: {
90
+ deleted: true
91
+ }
92
+ };
93
+ }
94
+
95
+ // ---- LIST_APPLICATIONS: list wholesale applications ----
96
+ case "list_applications":
97
+ {
98
+ let q = sb.from("wholesale_applications").select("id, customer_id, business_name, business_type, license_number, license_expiry, contact_person, contact_email, status, reviewed_at, created_at").order("created_at", {
99
+ ascending: false
100
+ });
101
+ if (args.status) q = q.eq("status", args.status);
102
+ q = q.limit(args.limit || 50);
103
+ const {
104
+ data,
105
+ error
106
+ } = await q;
107
+ return error ? {
108
+ success: false,
109
+ error: error.message
110
+ } : {
111
+ success: true,
112
+ count: data?.length,
113
+ data
114
+ };
115
+ }
116
+
117
+ // ---- GET_APPLICATION: get application detail ----
118
+ case "get_application":
119
+ {
120
+ const appId = args.application_id;
121
+ if (!appId) return {
122
+ success: false,
123
+ error: "application_id is required"
124
+ };
125
+ const {
126
+ data,
127
+ error
128
+ } = await sb.from("wholesale_applications").select("*").eq("id", appId).single();
129
+ return error ? {
130
+ success: false,
131
+ error: error.message
132
+ } : {
133
+ success: true,
134
+ data
135
+ };
136
+ }
137
+
138
+ // ---- REVIEW_APPLICATION: approve or reject a wholesale application ----
139
+ case "review_application":
140
+ {
141
+ const appId = args.application_id;
142
+ const decision = args.decision;
143
+ if (!appId || !decision) return {
144
+ success: false,
145
+ error: "application_id and decision (approved/rejected) are required"
146
+ };
147
+ if (decision !== "approved" && decision !== "rejected") {
148
+ return {
149
+ success: false,
150
+ error: "decision must be 'approved' or 'rejected'"
151
+ };
152
+ }
153
+ const updates = {
154
+ status: decision,
155
+ reviewed_at: new Date().toISOString(),
156
+ updated_at: new Date().toISOString()
157
+ };
158
+ if (args.review_notes) updates.review_notes = args.review_notes;
159
+ if (decision === "rejected" && args.rejection_reason) updates.rejection_reason = args.rejection_reason;
160
+ const {
161
+ data,
162
+ error
163
+ } = await sb.from("wholesale_applications").update(updates).eq("id", appId).select().single();
164
+ if (error) return {
165
+ success: false,
166
+ error: error.message
167
+ };
168
+
169
+ // If approved, update customer profile with wholesale status
170
+ if (decision === "approved") {
171
+ const app = data;
172
+ const custId = app.customer_id;
173
+ if (custId) {
174
+ await sb.from("store_customer_profiles").update({
175
+ is_wholesale_approved: true,
176
+ wholesale_business_name: app.business_name,
177
+ wholesale_business_type: app.business_type,
178
+ wholesale_license_number: app.license_number,
179
+ wholesale_tax_id: app.tax_id,
180
+ updated_at: new Date().toISOString()
181
+ }).eq("relationship_id", custId);
182
+ }
183
+ }
184
+ return {
185
+ success: true,
186
+ data
187
+ };
188
+ }
189
+
190
+ // ---- LIST_CUSTOMERS: list wholesale-approved customers ----
191
+ case "list_customers":
192
+ {
193
+ let q = sb.from("store_customer_profiles").select("relationship_id, wholesale_business_name, wholesale_business_type, wholesale_tier, wholesale_discount_percent, wholesale_payment_terms, wholesale_credit_limit, is_wholesale_approved, updated_at").eq("is_wholesale_approved", true);
194
+ if (args.query) {
195
+ const sq = sanitizeFilterValue(String(args.query));
196
+ q = q.ilike("wholesale_business_name", `%${sq}%`);
197
+ }
198
+ q = q.limit(args.limit || 50);
199
+ const {
200
+ data,
201
+ error
202
+ } = await q;
203
+ return error ? {
204
+ success: false,
205
+ error: error.message
206
+ } : {
207
+ success: true,
208
+ count: data?.length,
209
+ data
210
+ };
211
+ }
212
+ default:
213
+ return {
214
+ success: false,
215
+ error: `Unknown wholesale action: ${args.action}. Valid: list_pricing, set_pricing, delete_pricing, list_applications, get_application, review_application, list_customers`
216
+ };
217
+ }
218
+ }
219
+ //# sourceMappingURL=wholesale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wholesale.js","names":["sanitizeFilterValue","handleWholesale","sb","args","storeId","sid","action","q","from","select","eq","order","ascending","product_id","is_active","undefined","tier_name","limit","data","error","success","message","count","length","productId","tierName","minimumQuantity","minimum_quantity","unitPrice","unit_price","record","store_id","discount_percentage","description","terms","starts_at","ends_at","upsert","onConflict","single","pricingId","pricing_id","delete","deleted","status","appId","application_id","decision","updates","reviewed_at","Date","toISOString","updated_at","review_notes","rejection_reason","update","app","custId","customer_id","is_wholesale_approved","wholesale_business_name","business_name","wholesale_business_type","business_type","wholesale_license_number","license_number","wholesale_tax_id","tax_id","query","sq","String","ilike"],"sources":["../../../src/server/handlers/wholesale.ts"],"sourcesContent":["// server/handlers/wholesale.ts — Wholesale pricing, applications, and purchase orders\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 handleWholesale(\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_PRICING: list wholesale pricing tiers ----\n case \"list_pricing\": {\n let q = sb.from(\"wholesale_pricing\")\n .select(\"*, product:products!product_id(name, sku)\")\n .eq(\"store_id\", sid)\n .order(\"product_id\", { ascending: true })\n .order(\"minimum_quantity\", { ascending: true });\n if (args.product_id) q = q.eq(\"product_id\", args.product_id as string);\n if (args.is_active !== undefined) q = q.eq(\"is_active\", args.is_active as boolean);\n if (args.tier_name) q = q.eq(\"tier_name\", args.tier_name as string);\n q = q.limit(args.limit as number || 100);\n const { data, error } = await q;\n return error ? { success: false, error: error.message } : { success: true, count: data?.length, data };\n }\n\n // ---- SET_PRICING: create or update wholesale pricing for a product ----\n case \"set_pricing\": {\n const productId = args.product_id as string;\n const tierName = args.tier_name as string;\n const minimumQuantity = args.minimum_quantity as number;\n const unitPrice = args.unit_price as number;\n if (!productId || !tierName || minimumQuantity === undefined || unitPrice === undefined) {\n return { success: false, error: \"product_id, tier_name, minimum_quantity, and unit_price are required\" };\n }\n const record: Record<string, unknown> = {\n store_id: sid,\n product_id: productId,\n tier_name: tierName,\n minimum_quantity: minimumQuantity,\n unit_price: unitPrice,\n };\n if (args.discount_percentage !== undefined) record.discount_percentage = args.discount_percentage;\n if (args.description !== undefined) record.description = args.description;\n if (args.terms !== undefined) record.terms = args.terms;\n if (args.starts_at !== undefined) record.starts_at = args.starts_at;\n if (args.ends_at !== undefined) record.ends_at = args.ends_at;\n\n const { data, error } = await sb.from(\"wholesale_pricing\")\n .upsert(record, { onConflict: \"product_id,minimum_quantity\" })\n .select()\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- DELETE_PRICING: remove a wholesale pricing tier ----\n case \"delete_pricing\": {\n const pricingId = args.pricing_id as string;\n if (!pricingId) return { success: false, error: \"pricing_id is required\" };\n const { error } = await sb.from(\"wholesale_pricing\")\n .delete()\n .eq(\"id\", pricingId)\n .eq(\"store_id\", sid);\n return error ? { success: false, error: error.message } : { success: true, data: { deleted: true } };\n }\n\n // ---- LIST_APPLICATIONS: list wholesale applications ----\n case \"list_applications\": {\n let q = sb.from(\"wholesale_applications\")\n .select(\"id, customer_id, business_name, business_type, license_number, license_expiry, contact_person, contact_email, status, reviewed_at, created_at\")\n .order(\"created_at\", { ascending: false });\n if (args.status) q = q.eq(\"status\", args.status 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 // ---- GET_APPLICATION: get application detail ----\n case \"get_application\": {\n const appId = args.application_id as string;\n if (!appId) return { success: false, error: \"application_id is required\" };\n const { data, error } = await sb.from(\"wholesale_applications\")\n .select(\"*\")\n .eq(\"id\", appId)\n .single();\n return error ? { success: false, error: error.message } : { success: true, data };\n }\n\n // ---- REVIEW_APPLICATION: approve or reject a wholesale application ----\n case \"review_application\": {\n const appId = args.application_id as string;\n const decision = args.decision as string;\n if (!appId || !decision) return { success: false, error: \"application_id and decision (approved/rejected) are required\" };\n if (decision !== \"approved\" && decision !== \"rejected\") {\n return { success: false, error: \"decision must be 'approved' or 'rejected'\" };\n }\n\n const updates: Record<string, unknown> = {\n status: decision,\n reviewed_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n };\n if (args.review_notes) updates.review_notes = args.review_notes;\n if (decision === \"rejected\" && args.rejection_reason) updates.rejection_reason = args.rejection_reason;\n\n const { data, error } = await sb.from(\"wholesale_applications\")\n .update(updates)\n .eq(\"id\", appId)\n .select()\n .single();\n if (error) return { success: false, error: error.message };\n\n // If approved, update customer profile with wholesale status\n if (decision === \"approved\") {\n const app = data as Record<string, unknown>;\n const custId = app.customer_id as string;\n if (custId) {\n await sb.from(\"store_customer_profiles\").update({\n is_wholesale_approved: true,\n wholesale_business_name: app.business_name as string,\n wholesale_business_type: app.business_type as string,\n wholesale_license_number: app.license_number as string,\n wholesale_tax_id: app.tax_id as string,\n updated_at: new Date().toISOString(),\n }).eq(\"relationship_id\", custId);\n }\n }\n\n return { success: true, data };\n }\n\n // ---- LIST_CUSTOMERS: list wholesale-approved customers ----\n case \"list_customers\": {\n let q = sb.from(\"store_customer_profiles\")\n .select(\"relationship_id, wholesale_business_name, wholesale_business_type, wholesale_tier, wholesale_discount_percent, wholesale_payment_terms, wholesale_credit_limit, is_wholesale_approved, updated_at\")\n .eq(\"is_wholesale_approved\", true);\n if (args.query) {\n const sq = sanitizeFilterValue(String(args.query));\n q = q.ilike(\"wholesale_business_name\", `%${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 default:\n return { success: false, error: `Unknown wholesale action: ${args.action}. Valid: list_pricing, set_pricing, delete_pricing, list_applications, get_application, review_application, list_customers` };\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -21,7 +21,7 @@ import { initSupabase, getServiceClient } from "./lib/supabase-client.js";
21
21
  import { loadCheckpoint, markOrphaned } from "./lib/session-checkpoint.js";
22
22
  import { rateLimiter } from "./lib/rate-limiter.js";
23
23
  import { sanitizeAndLog } from "./lib/prompt-sanitizer.js";
24
- import { generateOpenApiSpec } from "./handlers/api-docs.js";
24
+ import { generateOpenApiSpec, generateOpenApiSpecSync } from "./handlers/api-docs.js";
25
25
  import { processWorkflowSteps, handleWebhookIngestion, executeInlineChain, initWorkerPool, getPoolStats, shutdownPool, verifyGuestApprovalSignature } from "./handlers/workflows.js";
26
26
  import { loadUserTools, executeTool, flushSpans } from "./tool-router.js";
27
27
  import { queueSpan, auditRowToSpan } from "./lib/clickhouse-buffer.js";
@@ -110,15 +110,26 @@ const server = http.createServer(async (req, res) => {
110
110
  return;
111
111
  }
112
112
 
113
- // OpenAPI spec — public, no auth required (for Scalar docs viewer)
113
+ // OpenAPI spec — proxy from gateway, no auth required (for Scalar docs viewer)
114
114
  if (req.method === "GET" && req.url === "/openapi.json") {
115
- const spec = generateOpenApiSpec();
116
- res.writeHead(200, {
117
- ...corsHeaders,
118
- "Content-Type": "application/json",
119
- "Cache-Control": "public, max-age=3600"
120
- });
121
- res.end(JSON.stringify(spec));
115
+ try {
116
+ const spec = await generateOpenApiSpec();
117
+ res.writeHead(200, {
118
+ ...corsHeaders,
119
+ "Content-Type": "application/json",
120
+ "Cache-Control": "public, max-age=300"
121
+ });
122
+ res.end(JSON.stringify(spec));
123
+ } catch {
124
+ // Fall back to cached or minimal spec
125
+ const fallback = generateOpenApiSpecSync();
126
+ res.writeHead(200, {
127
+ ...corsHeaders,
128
+ "Content-Type": "application/json",
129
+ "Cache-Control": "public, max-age=60"
130
+ });
131
+ res.end(JSON.stringify(fallback));
132
+ }
122
133
  return;
123
134
  }
124
135