whale-code 6.5.8 → 6.5.10

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/dist/cli/services/agent-loop.js +26 -2
  2. package/dist/cli/services/agent-loop.js.map +1 -1
  3. package/dist/cli/services/config-store.js +2 -3
  4. package/dist/cli/services/config-store.js.map +1 -1
  5. package/dist/cli/services/hooks.js +2 -1
  6. package/dist/cli/services/hooks.js.map +1 -1
  7. package/dist/cli/services/telemetry-spans.js +1 -0
  8. package/dist/cli/services/telemetry-spans.js.map +1 -1
  9. package/dist/cli/services/telemetry.d.ts +23 -0
  10. package/dist/cli/services/telemetry.js +45 -1
  11. package/dist/cli/services/telemetry.js.map +1 -1
  12. package/dist/server/handlers/__test-utils__/test-db.d.ts +17 -3
  13. package/dist/server/handlers/__test-utils__/test-db.js +113 -14
  14. package/dist/server/handlers/__test-utils__/test-db.js.map +1 -1
  15. package/dist/server/handlers/affiliates.d.ts +9 -0
  16. package/dist/server/handlers/affiliates.js +197 -0
  17. package/dist/server/handlers/affiliates.js.map +1 -0
  18. package/dist/server/handlers/api-docs.d.ts +4 -2
  19. package/dist/server/handlers/api-docs.js +204 -1681
  20. package/dist/server/handlers/api-docs.js.map +1 -1
  21. package/dist/server/handlers/campaigns.d.ts +9 -0
  22. package/dist/server/handlers/campaigns.js +237 -0
  23. package/dist/server/handlers/campaigns.js.map +1 -0
  24. package/dist/server/handlers/catalog-schemas.js +9 -9
  25. package/dist/server/handlers/catalog-schemas.js.map +1 -1
  26. package/dist/server/handlers/catalog.js +1 -1
  27. package/dist/server/handlers/catalog.js.map +1 -1
  28. package/dist/server/handlers/comms-documents.js +28 -2
  29. package/dist/server/handlers/comms-documents.js.map +1 -1
  30. package/dist/server/handlers/comms-pdf-generation.js +25 -3
  31. package/dist/server/handlers/comms-pdf-generation.js.map +1 -1
  32. package/dist/server/handlers/comms-pdf-helpers.js +4 -4
  33. package/dist/server/handlers/comms-pdf-helpers.js.map +1 -1
  34. package/dist/server/handlers/comms.d.ts +100 -0
  35. package/dist/server/handlers/comms.js +146 -12
  36. package/dist/server/handlers/comms.js.map +1 -1
  37. package/dist/server/handlers/coupons.d.ts +9 -0
  38. package/dist/server/handlers/coupons.js +220 -0
  39. package/dist/server/handlers/coupons.js.map +1 -0
  40. package/dist/server/handlers/embeddings.js +1 -1
  41. package/dist/server/handlers/embeddings.js.map +1 -1
  42. package/dist/server/handlers/enrichment.js +2 -622
  43. package/dist/server/handlers/enrichment.js.map +1 -1
  44. package/dist/server/handlers/fulfillment.d.ts +9 -0
  45. package/dist/server/handlers/fulfillment.js +209 -0
  46. package/dist/server/handlers/fulfillment.js.map +1 -0
  47. package/dist/server/handlers/google-ads.d.ts +24 -0
  48. package/dist/server/handlers/google-ads.js +2199 -0
  49. package/dist/server/handlers/google-ads.js.map +1 -0
  50. package/dist/server/handlers/invoices.d.ts +9 -0
  51. package/dist/server/handlers/invoices.js +252 -0
  52. package/dist/server/handlers/invoices.js.map +1 -0
  53. package/dist/server/handlers/loyalty.d.ts +9 -0
  54. package/dist/server/handlers/loyalty.js +197 -0
  55. package/dist/server/handlers/loyalty.js.map +1 -0
  56. package/dist/server/handlers/meta-ads-graph-api.js +18 -3
  57. package/dist/server/handlers/meta-ads-graph-api.js.map +1 -1
  58. package/dist/server/handlers/phone.d.ts +9 -0
  59. package/dist/server/handlers/phone.js +197 -0
  60. package/dist/server/handlers/phone.js.map +1 -0
  61. package/dist/server/handlers/pipeline.d.ts +9 -0
  62. package/dist/server/handlers/pipeline.js +277 -0
  63. package/dist/server/handlers/pipeline.js.map +1 -0
  64. package/dist/server/handlers/qr-codes.d.ts +9 -0
  65. package/dist/server/handlers/qr-codes.js +198 -0
  66. package/dist/server/handlers/qr-codes.js.map +1 -0
  67. package/dist/server/handlers/reviews.d.ts +9 -0
  68. package/dist/server/handlers/reviews.js +171 -0
  69. package/dist/server/handlers/reviews.js.map +1 -0
  70. package/dist/server/handlers/segments.d.ts +9 -0
  71. package/dist/server/handlers/segments.js +229 -0
  72. package/dist/server/handlers/segments.js.map +1 -0
  73. package/dist/server/handlers/social.d.ts +9 -0
  74. package/dist/server/handlers/social.js +81 -0
  75. package/dist/server/handlers/social.js.map +1 -0
  76. package/dist/server/handlers/tax.d.ts +9 -0
  77. package/dist/server/handlers/tax.js +182 -0
  78. package/dist/server/handlers/tax.js.map +1 -0
  79. package/dist/server/handlers/wallet.d.ts +9 -0
  80. package/dist/server/handlers/wallet.js +203 -0
  81. package/dist/server/handlers/wallet.js.map +1 -0
  82. package/dist/server/handlers/webhooks-mgmt.d.ts +9 -0
  83. package/dist/server/handlers/webhooks-mgmt.js +181 -0
  84. package/dist/server/handlers/webhooks-mgmt.js.map +1 -0
  85. package/dist/server/handlers/wholesale.d.ts +9 -0
  86. package/dist/server/handlers/wholesale.js +219 -0
  87. package/dist/server/handlers/wholesale.js.map +1 -0
  88. package/dist/server/index.js +20 -9
  89. package/dist/server/index.js.map +1 -1
  90. package/dist/server/lib/clickhouse-buffer.js +1 -0
  91. package/dist/server/lib/clickhouse-buffer.js.map +1 -1
  92. package/dist/server/lib/coa-renderer.d.ts +1 -1
  93. package/dist/server/lib/coa-renderer.js +32 -10
  94. package/dist/server/lib/coa-renderer.js.map +1 -1
  95. package/dist/server/server-worker.d.ts +1 -0
  96. package/dist/server/server-worker.js +464 -3
  97. package/dist/server/server-worker.js.map +1 -1
  98. package/dist/server/tool-router.js +118 -4
  99. package/dist/server/tool-router.js.map +1 -1
  100. package/package.json +26 -3
  101. package/vendor/ink/package.json +0 -2
@@ -35,6 +35,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
35
35
  results?: undefined;
36
36
  errors?: undefined;
37
37
  warnings?: undefined;
38
+ clients?: undefined;
39
+ hint?: undefined;
38
40
  document_ids?: undefined;
39
41
  customer_id?: undefined;
40
42
  customer_email?: undefined;
@@ -72,6 +74,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
72
74
  results?: undefined;
73
75
  errors?: undefined;
74
76
  warnings?: undefined;
77
+ clients?: undefined;
78
+ hint?: undefined;
75
79
  document_ids?: undefined;
76
80
  customer_id?: undefined;
77
81
  customer_email?: undefined;
@@ -101,6 +105,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
101
105
  results?: undefined;
102
106
  errors?: undefined;
103
107
  warnings?: undefined;
108
+ clients?: undefined;
109
+ hint?: undefined;
104
110
  document_ids?: undefined;
105
111
  customer_id?: undefined;
106
112
  customer_email?: undefined;
@@ -130,6 +136,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
130
136
  results?: undefined;
131
137
  errors?: undefined;
132
138
  warnings?: undefined;
139
+ clients?: undefined;
140
+ hint?: undefined;
133
141
  document_ids?: undefined;
134
142
  customer_id?: undefined;
135
143
  customer_email?: undefined;
@@ -166,6 +174,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
166
174
  results?: undefined;
167
175
  errors?: undefined;
168
176
  warnings?: undefined;
177
+ clients?: undefined;
178
+ hint?: undefined;
169
179
  document_ids?: undefined;
170
180
  customer_id?: undefined;
171
181
  customer_email?: undefined;
@@ -195,6 +205,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
195
205
  results?: undefined;
196
206
  errors?: undefined;
197
207
  warnings?: undefined;
208
+ clients?: undefined;
209
+ hint?: undefined;
198
210
  document_ids?: undefined;
199
211
  customer_id?: undefined;
200
212
  customer_email?: undefined;
@@ -230,6 +242,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
230
242
  results?: undefined;
231
243
  errors?: undefined;
232
244
  warnings?: undefined;
245
+ clients?: undefined;
246
+ hint?: undefined;
233
247
  document_ids?: undefined;
234
248
  customer_id?: undefined;
235
249
  customer_email?: undefined;
@@ -266,6 +280,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
266
280
  results?: undefined;
267
281
  errors?: undefined;
268
282
  warnings?: undefined;
283
+ clients?: undefined;
284
+ hint?: undefined;
269
285
  document_ids?: undefined;
270
286
  customer_id?: undefined;
271
287
  customer_email?: undefined;
@@ -299,6 +315,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
299
315
  profiles?: undefined;
300
316
  errors?: undefined;
301
317
  warnings?: undefined;
318
+ clients?: undefined;
319
+ hint?: undefined;
302
320
  document_ids?: undefined;
303
321
  customer_id?: undefined;
304
322
  customer_email?: undefined;
@@ -329,6 +347,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
329
347
  succeeded?: undefined;
330
348
  failed?: undefined;
331
349
  results?: undefined;
350
+ clients?: undefined;
351
+ hint?: undefined;
332
352
  document_ids?: undefined;
333
353
  customer_id?: undefined;
334
354
  customer_email?: undefined;
@@ -357,6 +377,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
357
377
  failed?: undefined;
358
378
  results?: undefined;
359
379
  errors?: undefined;
380
+ clients?: undefined;
381
+ hint?: undefined;
360
382
  document_ids?: undefined;
361
383
  customer_id?: undefined;
362
384
  customer_email?: undefined;
@@ -393,6 +415,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
393
415
  results?: undefined;
394
416
  errors?: undefined;
395
417
  warnings?: undefined;
418
+ clients?: undefined;
419
+ hint?: undefined;
396
420
  document_ids?: undefined;
397
421
  customer_id?: undefined;
398
422
  customer_email?: undefined;
@@ -429,6 +453,78 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
429
453
  results?: undefined;
430
454
  errors?: undefined;
431
455
  warnings?: undefined;
456
+ clients?: undefined;
457
+ hint?: undefined;
458
+ document_ids?: undefined;
459
+ customer_id?: undefined;
460
+ customer_email?: undefined;
461
+ email_sent?: undefined;
462
+ };
463
+ error?: undefined;
464
+ } | {
465
+ success: boolean;
466
+ data: {
467
+ count: number;
468
+ clients: never[];
469
+ hint: string;
470
+ id?: undefined;
471
+ name?: undefined;
472
+ type?: undefined;
473
+ url?: undefined;
474
+ file_name?: undefined;
475
+ size?: undefined;
476
+ documents?: undefined;
477
+ deleted?: undefined;
478
+ template_id?: undefined;
479
+ templates?: undefined;
480
+ template?: undefined;
481
+ stores?: undefined;
482
+ profiles?: undefined;
483
+ total?: undefined;
484
+ succeeded?: undefined;
485
+ failed?: undefined;
486
+ results?: undefined;
487
+ errors?: undefined;
488
+ warnings?: undefined;
489
+ document_ids?: undefined;
490
+ customer_id?: undefined;
491
+ customer_email?: undefined;
492
+ email_sent?: undefined;
493
+ };
494
+ error?: undefined;
495
+ } | {
496
+ success: boolean;
497
+ data: {
498
+ count: number;
499
+ clients: {
500
+ id: any;
501
+ name: any;
502
+ store_name: any;
503
+ address: string;
504
+ license: any;
505
+ phone: any;
506
+ email: any;
507
+ }[];
508
+ id?: undefined;
509
+ name?: undefined;
510
+ type?: undefined;
511
+ url?: undefined;
512
+ file_name?: undefined;
513
+ size?: undefined;
514
+ documents?: undefined;
515
+ deleted?: undefined;
516
+ template_id?: undefined;
517
+ templates?: undefined;
518
+ template?: undefined;
519
+ stores?: undefined;
520
+ profiles?: undefined;
521
+ total?: undefined;
522
+ succeeded?: undefined;
523
+ failed?: undefined;
524
+ results?: undefined;
525
+ errors?: undefined;
526
+ warnings?: undefined;
527
+ hint?: undefined;
432
528
  document_ids?: undefined;
433
529
  customer_id?: undefined;
434
530
  customer_email?: undefined;
@@ -462,6 +558,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
462
558
  results?: undefined;
463
559
  errors?: undefined;
464
560
  warnings?: undefined;
561
+ clients?: undefined;
562
+ hint?: undefined;
465
563
  };
466
564
  error?: undefined;
467
565
  } | {
@@ -496,6 +594,8 @@ export declare function handleDocuments(sb: SupabaseClient, args: Record<string,
496
594
  results?: undefined;
497
595
  errors?: undefined;
498
596
  warnings?: undefined;
597
+ clients?: undefined;
598
+ hint?: undefined;
499
599
  document_ids?: undefined;
500
600
  customer_id?: undefined;
501
601
  customer_email?: undefined;
@@ -1008,12 +1008,12 @@ export async function handleDocuments(sb, args, storeId) {
1008
1008
  };
1009
1009
  }
1010
1010
  }
1011
- // Use profile name as sampleName if not already set
1012
- if (profile.name && !profileConstants.sampleName) {
1013
- profileClientData.sampleName = profile.name;
1014
- }
1011
+ // Profile name is a category (e.g. "THCA Flower"), not a sample name.
1012
+ // sampleName must come from user data (productName or sampleName override).
1015
1013
  if (profile.sample_type) {
1016
1014
  profileClientData.sampleType = profile.sample_type;
1015
+ } else if (profile.name) {
1016
+ profileClientData.sampleType = profile.name;
1017
1017
  }
1018
1018
  if (profile.default_size) {
1019
1019
  profileClientData.sampleSize = profile.default_size;
@@ -1054,15 +1054,32 @@ export async function handleDocuments(sb, args, storeId) {
1054
1054
  cannabinoids: _cfgRanges,
1055
1055
  ...profileDataOnly
1056
1056
  } = profileConfig;
1057
+ // Normalize common field name aliases to what the COA renderer expects
1058
+ const rawOverrides = args.data || {};
1059
+ const userOverrides = {
1060
+ ...rawOverrides
1061
+ };
1062
+ if (userOverrides.productName && !userOverrides.sampleName) {
1063
+ userOverrides.sampleName = userOverrides.productName;
1064
+ }
1065
+ if (userOverrides.dateCompleted && !userOverrides.dateTested) {
1066
+ userOverrides.dateTested = userOverrides.dateCompleted;
1067
+ delete userOverrides.dateCompleted;
1068
+ }
1069
+ if (userOverrides.clientLicense && !userOverrides.licenseNumber) {
1070
+ userOverrides.licenseNumber = userOverrides.clientLicense;
1071
+ delete userOverrides.clientLicense;
1072
+ }
1057
1073
  let mergedData = {
1058
1074
  ...mergedConstants,
1059
1075
  ...profileDataOnly,
1060
1076
  ...profileClientData,
1061
1077
  ...clientData,
1062
- ...(args.data || {}),
1063
- date: new Date().toISOString().slice(0, 10),
1064
- approvalDate: new Date().toISOString().slice(0, 10)
1078
+ ...userOverrides,
1079
+ date: new Date().toISOString().slice(0, 10)
1065
1080
  };
1081
+ // Track if user explicitly set sampleName (so productName doesn't clobber it)
1082
+ const _sampleNameExplicit = !!userOverrides.sampleName;
1066
1083
 
1067
1084
  // 5. Apply generation rules — auto-fill sampleId, dates, etc.
1068
1085
  mergedData = applyGenerationRules(tpl.generation_rules, mergedData);
@@ -1143,12 +1160,23 @@ export async function handleDocuments(sb, args, storeId) {
1143
1160
  mergedData.testsBatch = true;
1144
1161
  }
1145
1162
 
1146
- // 7c. Generate QR code for COA templates links to Quantix COA landing page
1163
+ // 7b3. Resolve product name: productName override sampleName from profile
1164
+ if (mergedData.productName && !_sampleNameExplicit) {
1165
+ mergedData.sampleName = mergedData.productName;
1166
+ }
1167
+
1168
+ // 7c. Generate QR code for COA templates — uses universal resolver URL
1147
1169
  if (tpl.slug?.startsWith("cannabis-coa") && !mergedData.qrCodeDataUrl) {
1148
1170
  const productSlug = (mergedData.sampleName || "certificate").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
1149
- const coaUrl = `https://quantixanalytics.com/coa/${sid}/${productSlug}`;
1171
+ const coaUrl = `https://www.quantixanalytics.com/coa/${sid}/${productSlug}`;
1172
+ mergedData._coaVerificationUrl = coaUrl;
1173
+ // Generate a predictable QR code — will be registered in qr_codes table after document insert
1174
+ const _qrCodePrefix = `DOC-${Date.now().toString(36)}`;
1175
+ mergedData._qrCodePrefix = _qrCodePrefix;
1176
+ const resolverUrl = `https://whale-gateway.fly.dev/q/${_qrCodePrefix}`;
1177
+ mergedData._resolverUrl = resolverUrl;
1150
1178
  try {
1151
- mergedData.qrCodeDataUrl = await QRCode.toDataURL(coaUrl, {
1179
+ mergedData.qrCodeDataUrl = await QRCode.toDataURL(resolverUrl, {
1152
1180
  width: 120,
1153
1181
  margin: 1
1154
1182
  });
@@ -1170,6 +1198,21 @@ export async function handleDocuments(sb, args, storeId) {
1170
1198
  };
1171
1199
  }
1172
1200
 
1201
+ // 8b. Pre-fetch image URLs as base64 data URLs — React-PDF in Node can't fetch external URLs
1202
+ for (const key of ["logoUrl", "signatureUrl"]) {
1203
+ const url = mergedData[key];
1204
+ if (typeof url === "string" && url.startsWith("http")) {
1205
+ try {
1206
+ const res = await fetch(url);
1207
+ if (res.ok) {
1208
+ const buf = Buffer.from(await res.arrayBuffer());
1209
+ const mime = res.headers.get("content-type") || "image/png";
1210
+ mergedData[key] = `data:${mime};base64,${buf.toString("base64")}`;
1211
+ }
1212
+ } catch {/* leave as URL if fetch fails */}
1213
+ }
1214
+ }
1215
+
1173
1216
  // 9-10. Render PDF — all templates use React-PDF
1174
1217
  let pdfBuffer;
1175
1218
  try {
@@ -1196,7 +1239,9 @@ export async function handleDocuments(sb, args, storeId) {
1196
1239
 
1197
1240
  // 11. Upload to Supabase storage
1198
1241
  const sampleName = mergedData.sampleName || mergedData.productName || "";
1199
- const docName = args.name || (sampleName ? `${sampleName} COA` : fillTemplate(tpl.name || "Document", mergedData));
1242
+ const batchId = mergedData.batchId;
1243
+ const defaultName = sampleName ? batchId ? `COA - ${sampleName} - ${batchId}` : `${sampleName} COA` : fillTemplate(tpl.name || "Document", mergedData);
1244
+ const docName = args.name || defaultName;
1200
1245
  const safeName = docName.replace(/[^a-zA-Z0-9_\-]/g, "_");
1201
1246
  const fileName = `${safeName}_${Date.now()}.pdf`;
1202
1247
  const storagePath = `${sid}/${fileName}`;
@@ -1223,6 +1268,7 @@ export async function handleDocuments(sb, args, storeId) {
1223
1268
  };
1224
1269
  if (tpl.slug?.startsWith("cannabis-coa")) {
1225
1270
  coaMetadata.sample_name = sampleName;
1271
+ coaMetadata.product_name = mergedData.productName || sampleName;
1226
1272
  coaMetadata.sample_id = mergedData.sampleId || null;
1227
1273
  coaMetadata.sample_type = mergedData.sampleType || mergedData.strain || null;
1228
1274
  coaMetadata.sample_size = mergedData.sampleSize || null;
@@ -1294,6 +1340,7 @@ export async function handleDocuments(sb, args, storeId) {
1294
1340
  document_date: new Date().toISOString().split("T")[0],
1295
1341
  customer_id: args.customer_id || null,
1296
1342
  client_store_id: resolvedClientStoreId,
1343
+ qr_code_url: mergedData._coaVerificationUrl || null,
1297
1344
  data: {
1298
1345
  template_id: tpl.id,
1299
1346
  template_slug: tpl.slug,
@@ -1306,6 +1353,53 @@ export async function handleDocuments(sb, args, storeId) {
1306
1353
  error: insertErr.message
1307
1354
  };
1308
1355
  await generateThumbnail(sb, record.id, urlData.publicUrl).catch(() => {});
1356
+
1357
+ // 14. Create unified qr_codes record for scan tracking
1358
+ if (mergedData._coaVerificationUrl && mergedData._qrCodePrefix) {
1359
+ const qrCode = mergedData._qrCodePrefix;
1360
+ const resolverUrl = `https://whale-gateway.fly.dev/q/${qrCode}`;
1361
+ sb.from("qr_codes").insert({
1362
+ store_id: sid,
1363
+ code: qrCode,
1364
+ name: docName,
1365
+ type: "document",
1366
+ destination_url: mergedData._coaVerificationUrl,
1367
+ product_id: args.product_id || null,
1368
+ batch_id: args.batch_id || null,
1369
+ is_active: true
1370
+ }).select("id").single().then(({
1371
+ data: qrRecord,
1372
+ error: qrErr
1373
+ }) => {
1374
+ if (qrErr) {
1375
+ console.error("[comms] qr_codes insert error:", qrErr.message);
1376
+ return;
1377
+ }
1378
+ // Link qr_code to the document via qr_code_references
1379
+ if (qrRecord) {
1380
+ sb.from("qr_code_references").insert({
1381
+ store_id: sid,
1382
+ qr_code_id: qrRecord.id,
1383
+ entity_type: "store_document",
1384
+ entity_id: record.id,
1385
+ entity_name: docName,
1386
+ field_name: "coa_verification_qr"
1387
+ }).then(({
1388
+ error: refErr
1389
+ }) => {
1390
+ if (refErr) console.error("[comms] qr_code_references insert error:", refErr.message);
1391
+ });
1392
+ }
1393
+ // Update document with resolver URL
1394
+ sb.from("store_documents").update({
1395
+ qr_code_url: resolverUrl
1396
+ }).eq("id", record.id).then(({
1397
+ error: updErr
1398
+ }) => {
1399
+ if (updErr) console.error("[comms] store_documents qr_code_url update error:", updErr.message);
1400
+ });
1401
+ });
1402
+ }
1309
1403
  return {
1310
1404
  success: true,
1311
1405
  data: {
@@ -1376,10 +1470,50 @@ export async function handleDocuments(sb, args, storeId) {
1376
1470
  };
1377
1471
  }
1378
1472
  case "list_clients":
1473
+ {
1474
+ // List B2B client stores linked via document_profiles.client_store_id
1475
+ const {
1476
+ data: profiles
1477
+ } = await sb.from("document_profiles").select("client_store_id").eq("owner_store_id", sid).eq("is_active", true).not("client_store_id", "is", null);
1478
+ const clientIds = [...new Set((profiles || []).map(p => p.client_store_id).filter(Boolean))];
1479
+ if (!clientIds.length) {
1480
+ return {
1481
+ success: true,
1482
+ data: {
1483
+ count: 0,
1484
+ clients: [],
1485
+ hint: "No client stores linked to document profiles. Use list_customers for retail customers."
1486
+ }
1487
+ };
1488
+ }
1489
+ const {
1490
+ data: stores,
1491
+ error: storesErr
1492
+ } = await sb.from("stores").select("id, store_name, legal_name, address, city, state, zip, distributor_license_number, phone, email").in("id", clientIds);
1493
+ if (storesErr) return {
1494
+ success: false,
1495
+ error: storesErr.message
1496
+ };
1497
+ return {
1498
+ success: true,
1499
+ data: {
1500
+ count: stores?.length || 0,
1501
+ clients: (stores || []).map(s => ({
1502
+ id: s.id,
1503
+ name: s.legal_name || s.store_name,
1504
+ store_name: s.store_name,
1505
+ address: [s.address, s.city, s.state, s.zip].filter(Boolean).join(", "),
1506
+ license: s.distributor_license_number || null,
1507
+ phone: s.phone || null,
1508
+ email: s.email || null
1509
+ }))
1510
+ }
1511
+ };
1512
+ }
1379
1513
  case "list_customers":
1380
1514
  return {
1381
1515
  success: false,
1382
- error: "Use the 'customers' tool instead. Clients are customers."
1516
+ error: "Use the 'customers' tool for retail customers. Use list_clients for B2B client stores."
1383
1517
  };
1384
1518
  case "deliver_documents":
1385
1519
  {