@chainpatrol/sdk 1.8.0 → 1.9.0

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.
package/dist/index.mjs CHANGED
@@ -1255,17 +1255,17 @@ var PolyDateFormatter = class {
1255
1255
  constructor(dt, intl, opts) {
1256
1256
  this.opts = opts;
1257
1257
  this.originalZone = void 0;
1258
- let z55 = void 0;
1258
+ let z56 = void 0;
1259
1259
  if (this.opts.timeZone) {
1260
1260
  this.dt = dt;
1261
1261
  } else if (dt.zone.type === "fixed") {
1262
1262
  const gmtOffset = -1 * (dt.offset / 60);
1263
1263
  const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
1264
1264
  if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
1265
- z55 = offsetZ;
1265
+ z56 = offsetZ;
1266
1266
  this.dt = dt;
1267
1267
  } else {
1268
- z55 = "UTC";
1268
+ z56 = "UTC";
1269
1269
  this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
1270
1270
  this.originalZone = dt.zone;
1271
1271
  }
@@ -1273,14 +1273,14 @@ var PolyDateFormatter = class {
1273
1273
  this.dt = dt;
1274
1274
  } else if (dt.zone.type === "iana") {
1275
1275
  this.dt = dt;
1276
- z55 = dt.zone.name;
1276
+ z56 = dt.zone.name;
1277
1277
  } else {
1278
- z55 = "UTC";
1278
+ z56 = "UTC";
1279
1279
  this.dt = dt.setZone("UTC").plus({ minutes: dt.offset });
1280
1280
  this.originalZone = dt.zone;
1281
1281
  }
1282
1282
  const intlOpts = __spreadValues({}, this.opts);
1283
- intlOpts.timeZone = intlOpts.timeZone || z55;
1283
+ intlOpts.timeZone = intlOpts.timeZone || z56;
1284
1284
  this.dtf = getCachedDTF(intl, intlOpts);
1285
1285
  }
1286
1286
  format() {
@@ -11430,6 +11430,50 @@ z.object({
11430
11430
  endDate: z.date()
11431
11431
  })
11432
11432
  });
11433
+ var DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
11434
+ var utcDateSchema = (endOfDay) => z.preprocess((value) => {
11435
+ if (typeof value !== "string") {
11436
+ return value;
11437
+ }
11438
+ const parsed = DateTime.fromISO(value, { zone: "utc" });
11439
+ if (!parsed.isValid) {
11440
+ return new Date(Number.NaN);
11441
+ }
11442
+ return endOfDay && DATE_ONLY_PATTERN.test(value) ? parsed.endOf("day").toJSDate() : parsed.toJSDate();
11443
+ }, z.coerce.date());
11444
+ var funnelCountsSchema = z.object({
11445
+ blocked: z.number().int().nonnegative().describe(
11446
+ "Distinct assets whose earliest report for this org falls in the range and whose current status or pending status is BLOCKED"
11447
+ )
11448
+ });
11449
+ z.object({
11450
+ slug: z.string().min(1).describe("Organization slug"),
11451
+ startDate: utcDateSchema(false).describe(
11452
+ "Only include assets whose earliest report was created on or after this date. A date-only value (YYYY-MM-DD) starts at midnight UTC"
11453
+ ),
11454
+ endDate: utcDateSchema(true).describe(
11455
+ "Only include assets whose earliest report was created on or before this date. A date-only value (YYYY-MM-DD) covers the whole day in UTC; pass a full timestamp for a precise cut-off"
11456
+ ),
11457
+ brandIds: z.array(z.number().int().positive()).optional().describe("Only include assets belonging to these brands")
11458
+ }).refine((input) => input.startDate.getTime() <= input.endDate.getTime(), {
11459
+ message: "startDate must be on or before endDate",
11460
+ path: ["startDate"]
11461
+ });
11462
+ z.object({
11463
+ range: z.object({
11464
+ startDate: z.date(),
11465
+ endDate: z.date()
11466
+ }),
11467
+ customer: funnelCountsSchema.describe(
11468
+ "Currently blocked assets first reported by the customer (reportedByCustomer, external reporter, or customer-role user)"
11469
+ ),
11470
+ chainpatrol: funnelCountsSchema.describe(
11471
+ "Currently blocked assets first reported by ChainPatrol staff or automation. Staff and automation are collapsed together."
11472
+ ),
11473
+ totals: funnelCountsSchema.describe(
11474
+ "customer + chainpatrol. This is a first-report blocked cohort and does not equal metrics/found, which counts assets by blockedAt."
11475
+ )
11476
+ });
11433
11477
  z.object({
11434
11478
  slug: z.string().min(1),
11435
11479
  startDate: z.date().optional(),
@@ -11461,8 +11505,8 @@ z.object({
11461
11505
  })
11462
11506
  )
11463
11507
  });
11464
- var DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
11465
- var utcDateSchema = (endOfDay) => z.preprocess((value) => {
11508
+ var DATE_ONLY_PATTERN2 = /^\d{4}-\d{2}-\d{2}$/;
11509
+ var utcDateSchema2 = (endOfDay) => z.preprocess((value) => {
11466
11510
  if (typeof value !== "string") {
11467
11511
  return value;
11468
11512
  }
@@ -11470,14 +11514,14 @@ var utcDateSchema = (endOfDay) => z.preprocess((value) => {
11470
11514
  if (!parsed.isValid) {
11471
11515
  return new Date(Number.NaN);
11472
11516
  }
11473
- return endOfDay && DATE_ONLY_PATTERN.test(value) ? parsed.endOf("day").toJSDate() : parsed.toJSDate();
11517
+ return endOfDay && DATE_ONLY_PATTERN2.test(value) ? parsed.endOf("day").toJSDate() : parsed.toJSDate();
11474
11518
  }, z.coerce.date());
11475
11519
  z.object({
11476
11520
  slug: z.string().min(1).describe("Organization slug"),
11477
- startDate: utcDateSchema(false).optional().describe(
11521
+ startDate: utcDateSchema2(false).optional().describe(
11478
11522
  "Only include takedowns completed on or after this date. A date-only value (YYYY-MM-DD) starts at midnight UTC"
11479
11523
  ),
11480
- endDate: utcDateSchema(true).optional().describe(
11524
+ endDate: utcDateSchema2(true).optional().describe(
11481
11525
  "Only include takedowns completed on or before this date. A date-only value (YYYY-MM-DD) covers the whole day in UTC; pass a full timestamp for a precise cut-off"
11482
11526
  ),
11483
11527
  blockLabel: z.string().optional().describe(
@@ -11935,7 +11979,9 @@ var organizationMetricsIncludeFieldSchema = z.enum([
11935
11979
  "newThreats",
11936
11980
  "threatsWatchlisted",
11937
11981
  "takedownsFiled",
11982
+ "takedownsInProgress",
11938
11983
  "takedownsCompleted",
11984
+ "takedownsCancelled",
11939
11985
  "domainThreats",
11940
11986
  "twitterThreats",
11941
11987
  "telegramThreats",
@@ -11977,7 +12023,7 @@ z.object({
11977
12023
  startDate: z.coerce.date().optional(),
11978
12024
  endDate: z.coerce.date().optional(),
11979
12025
  include: z.array(organizationMetricsIncludeFieldSchema).optional().describe(
11980
- "Subset of metrics to compute. When omitted or empty, every metric is computed (legacy behavior). Each value in `include` costs roughly one Prisma aggregate, so narrow the list when an agent only needs a couple of numbers \u2014 this is the main lever for keeping big-org calls inside the 30s function cap. Fields not in `include` come back as `null`."
12026
+ "Subset of metrics to compute. When omitted or empty, every metric is computed (legacy behavior). Each value in `include` costs roughly one aggregate query, so narrow the list when an agent only needs a couple of numbers \u2014 this is the main lever for keeping big-org calls inside the 30s function cap. Fields not in `include` come back as `null`. `takedownsInProgress` and `takedownsCancelled` count takedowns currently in that status whose `updatedAt` falls in the window (same windowing as `takedownsFiled`), so they reconcile with the takedowns list filtered by status over the same date range."
11981
12027
  )
11982
12028
  }).refine(
11983
12029
  (value) => {
@@ -12005,7 +12051,9 @@ var metricsObjectSchema = z.object({
12005
12051
  newThreats: metricValue,
12006
12052
  threatsWatchlisted: metricValue,
12007
12053
  takedownsFiled: metricValue,
12054
+ takedownsInProgress: metricValue,
12008
12055
  takedownsCompleted: metricValue,
12056
+ takedownsCancelled: metricValue,
12009
12057
  domainThreats: metricValue,
12010
12058
  twitterThreats: metricValue,
12011
12059
  telegramThreats: metricValue,
@@ -13388,20 +13436,20 @@ var convertA98ToXyz65_default = convertA98ToXyz65;
13388
13436
 
13389
13437
  // ../../node_modules/culori/src/a98/convertXyz65ToA98.js
13390
13438
  var gamma = (v) => Math.pow(Math.abs(v), 256 / 563) * Math.sign(v);
13391
- var convertXyz65ToA98 = ({ x, y, z: z55, alpha }) => {
13439
+ var convertXyz65ToA98 = ({ x, y, z: z56, alpha }) => {
13392
13440
  if (x === void 0) x = 0;
13393
13441
  if (y === void 0) y = 0;
13394
- if (z55 === void 0) z55 = 0;
13442
+ if (z56 === void 0) z56 = 0;
13395
13443
  let res = {
13396
13444
  mode: "a98",
13397
13445
  r: gamma(
13398
- x * 2.0415879038107465 - y * 0.5650069742788597 - 0.3447313507783297 * z55
13446
+ x * 2.0415879038107465 - y * 0.5650069742788597 - 0.3447313507783297 * z56
13399
13447
  ),
13400
13448
  g: gamma(
13401
- x * -0.9692436362808798 + y * 1.8759675015077206 + 0.0415550574071756 * z55
13449
+ x * -0.9692436362808798 + y * 1.8759675015077206 + 0.0415550574071756 * z56
13402
13450
  ),
13403
13451
  b: gamma(
13404
- x * 0.0134442806320312 - y * 0.1183623922310184 + 1.0151749943912058 * z55
13452
+ x * 0.0134442806320312 - y * 0.1183623922310184 + 1.0151749943912058 * z56
13405
13453
  )
13406
13454
  };
13407
13455
  if (alpha !== void 0) {
@@ -13468,14 +13516,14 @@ var convertLrgbToRgb = ({ r, g, b, alpha }, mode = "rgb") => {
13468
13516
  var convertLrgbToRgb_default = convertLrgbToRgb;
13469
13517
 
13470
13518
  // ../../node_modules/culori/src/xyz65/convertXyz65ToRgb.js
13471
- var convertXyz65ToRgb = ({ x, y, z: z55, alpha }) => {
13519
+ var convertXyz65ToRgb = ({ x, y, z: z56, alpha }) => {
13472
13520
  if (x === void 0) x = 0;
13473
13521
  if (y === void 0) y = 0;
13474
- if (z55 === void 0) z55 = 0;
13522
+ if (z56 === void 0) z56 = 0;
13475
13523
  let res = convertLrgbToRgb_default({
13476
- r: x * 3.2409699419045226 - y * 1.537383177570094 - 0.4986107602930034 * z55,
13477
- g: x * -0.9692436362808796 + y * 1.8759675015077204 + 0.0415550574071756 * z55,
13478
- b: x * 0.0556300796969936 - y * 0.2039769588889765 + 1.0569715142428784 * z55
13524
+ r: x * 3.2409699419045226 - y * 1.537383177570094 - 0.4986107602930034 * z56,
13525
+ g: x * -0.9692436362808796 + y * 1.8759675015077204 + 0.0415550574071756 * z56,
13526
+ b: x * 0.0556300796969936 - y * 0.2039769588889765 + 1.0569715142428784 * z56
13479
13527
  });
13480
13528
  if (alpha !== void 0) {
13481
13529
  res.alpha = alpha;
@@ -13725,13 +13773,13 @@ var convertLab65ToRgb_default = convertLab65ToRgb;
13725
13773
 
13726
13774
  // ../../node_modules/culori/src/lab65/convertXyz65ToLab65.js
13727
13775
  var f = (value) => value > e ? Math.cbrt(value) : (k * value + 16) / 116;
13728
- var convertXyz65ToLab65 = ({ x, y, z: z55, alpha }) => {
13776
+ var convertXyz65ToLab65 = ({ x, y, z: z56, alpha }) => {
13729
13777
  if (x === void 0) x = 0;
13730
13778
  if (y === void 0) y = 0;
13731
- if (z55 === void 0) z55 = 0;
13779
+ if (z56 === void 0) z56 = 0;
13732
13780
  let f0 = f(x / D65.X);
13733
13781
  let f1 = f(y / D65.Y);
13734
- let f22 = f(z55 / D65.Z);
13782
+ let f22 = f(z56 / D65.Z);
13735
13783
  let res = {
13736
13784
  mode: "lab65",
13737
13785
  l: 116 * f1 - 16,
@@ -14388,10 +14436,10 @@ var convertItpToXyz65_default = convertItpToXyz65;
14388
14436
 
14389
14437
  // ../../node_modules/culori/src/itp/convertXyz65ToItp.js
14390
14438
  var toAbs = (c2 = 0) => Math.max(c2 * YW, 0);
14391
- var convertXyz65ToItp = ({ x, y, z: z55, alpha }) => {
14439
+ var convertXyz65ToItp = ({ x, y, z: z56, alpha }) => {
14392
14440
  const absX = toAbs(x);
14393
14441
  const absY = toAbs(y);
14394
- const absZ = toAbs(z55);
14442
+ const absZ = toAbs(z56);
14395
14443
  const l2 = transferPqEncode(
14396
14444
  0.3592832590121217 * absX + 0.6976051147779502 * absY - 0.0358915932320289 * absZ
14397
14445
  );
@@ -14449,15 +14497,15 @@ var jabPqEncode = (v) => {
14449
14497
  return Math.pow((C1 + C2 * vn3) / (1 + C3 * vn3), p);
14450
14498
  };
14451
14499
  var abs = (v = 0) => Math.max(v * 203, 0);
14452
- var convertXyz65ToJab = ({ x, y, z: z55, alpha }) => {
14500
+ var convertXyz65ToJab = ({ x, y, z: z56, alpha }) => {
14453
14501
  x = abs(x);
14454
14502
  y = abs(y);
14455
- z55 = abs(z55);
14456
- let xp = 1.15 * x - 0.15 * z55;
14503
+ z56 = abs(z56);
14504
+ let xp = 1.15 * x - 0.15 * z56;
14457
14505
  let yp = 0.66 * y + 0.34 * x;
14458
- let l2 = jabPqEncode(0.41478972 * xp + 0.579999 * yp + 0.014648 * z55);
14459
- let m = jabPqEncode(-0.20151 * xp + 1.120649 * yp + 0.0531008 * z55);
14460
- let s2 = jabPqEncode(-0.0166008 * xp + 0.2648 * yp + 0.6684799 * z55);
14506
+ let l2 = jabPqEncode(0.41478972 * xp + 0.579999 * yp + 0.014648 * z56);
14507
+ let m = jabPqEncode(-0.20151 * xp + 1.120649 * yp + 0.0531008 * z56);
14508
+ let s2 = jabPqEncode(-0.0166008 * xp + 0.2648 * yp + 0.6684799 * z56);
14461
14509
  let i = (l2 + m) / 2;
14462
14510
  let res = {
14463
14511
  mode: "jab",
@@ -14643,14 +14691,14 @@ var convertLabToXyz50 = ({ l: l2, a, b, alpha }) => {
14643
14691
  var convertLabToXyz50_default = convertLabToXyz50;
14644
14692
 
14645
14693
  // ../../node_modules/culori/src/xyz50/convertXyz50ToRgb.js
14646
- var convertXyz50ToRgb = ({ x, y, z: z55, alpha }) => {
14694
+ var convertXyz50ToRgb = ({ x, y, z: z56, alpha }) => {
14647
14695
  if (x === void 0) x = 0;
14648
14696
  if (y === void 0) y = 0;
14649
- if (z55 === void 0) z55 = 0;
14697
+ if (z56 === void 0) z56 = 0;
14650
14698
  let res = convertLrgbToRgb_default({
14651
- r: x * 3.1341359569958707 - y * 1.6173863321612538 - 0.4906619460083532 * z55,
14652
- g: x * -0.978795502912089 + y * 1.916254567259524 + 0.03344273116131949 * z55,
14653
- b: x * 0.07195537988411677 - y * 0.2289768264158322 + 1.405386058324125 * z55
14699
+ r: x * 3.1341359569958707 - y * 1.6173863321612538 - 0.4906619460083532 * z56,
14700
+ g: x * -0.978795502912089 + y * 1.916254567259524 + 0.03344273116131949 * z56,
14701
+ b: x * 0.07195537988411677 - y * 0.2289768264158322 + 1.405386058324125 * z56
14654
14702
  });
14655
14703
  if (alpha !== void 0) {
14656
14704
  res.alpha = alpha;
@@ -14681,13 +14729,13 @@ var convertRgbToXyz50_default = convertRgbToXyz50;
14681
14729
 
14682
14730
  // ../../node_modules/culori/src/lab/convertXyz50ToLab.js
14683
14731
  var f2 = (value) => value > e3 ? Math.cbrt(value) : (k3 * value + 16) / 116;
14684
- var convertXyz50ToLab = ({ x, y, z: z55, alpha }) => {
14732
+ var convertXyz50ToLab = ({ x, y, z: z56, alpha }) => {
14685
14733
  if (x === void 0) x = 0;
14686
14734
  if (y === void 0) y = 0;
14687
- if (z55 === void 0) z55 = 0;
14735
+ if (z56 === void 0) z56 = 0;
14688
14736
  let f0 = f2(x / D50.X);
14689
14737
  let f1 = f2(y / D50.Y);
14690
- let f22 = f2(z55 / D50.Z);
14738
+ let f22 = f2(z56 / D50.Z);
14691
14739
  let res = {
14692
14740
  mode: "lab",
14693
14741
  l: 116 * f1 - 16,
@@ -14922,18 +14970,18 @@ var convertLchuvToLuv = ({ l: l2, c: c2, h, alpha }) => {
14922
14970
  var convertLchuvToLuv_default = convertLchuvToLuv;
14923
14971
 
14924
14972
  // ../../node_modules/culori/src/luv/convertXyz50ToLuv.js
14925
- var u_fn = (x, y, z55) => 4 * x / (x + 15 * y + 3 * z55);
14926
- var v_fn = (x, y, z55) => 9 * y / (x + 15 * y + 3 * z55);
14973
+ var u_fn = (x, y, z56) => 4 * x / (x + 15 * y + 3 * z56);
14974
+ var v_fn = (x, y, z56) => 9 * y / (x + 15 * y + 3 * z56);
14927
14975
  var un = u_fn(D50.X, D50.Y, D50.Z);
14928
14976
  var vn = v_fn(D50.X, D50.Y, D50.Z);
14929
14977
  var l_fn = (value) => value <= e3 ? k3 * value : 116 * Math.cbrt(value) - 16;
14930
- var convertXyz50ToLuv = ({ x, y, z: z55, alpha }) => {
14978
+ var convertXyz50ToLuv = ({ x, y, z: z56, alpha }) => {
14931
14979
  if (x === void 0) x = 0;
14932
14980
  if (y === void 0) y = 0;
14933
- if (z55 === void 0) z55 = 0;
14981
+ if (z56 === void 0) z56 = 0;
14934
14982
  let l2 = l_fn(y / D50.Y);
14935
- let u = u_fn(x, y, z55);
14936
- let v = v_fn(x, y, z55);
14983
+ let u = u_fn(x, y, z56);
14984
+ let v = v_fn(x, y, z56);
14937
14985
  if (!isFinite(u) || !isFinite(v)) {
14938
14986
  l2 = u = v = 0;
14939
14987
  } else {
@@ -14954,8 +15002,8 @@ var convertXyz50ToLuv = ({ x, y, z: z55, alpha }) => {
14954
15002
  var convertXyz50ToLuv_default = convertXyz50ToLuv;
14955
15003
 
14956
15004
  // ../../node_modules/culori/src/luv/convertLuvToXyz50.js
14957
- var u_fn2 = (x, y, z55) => 4 * x / (x + 15 * y + 3 * z55);
14958
- var v_fn2 = (x, y, z55) => 9 * y / (x + 15 * y + 3 * z55);
15005
+ var u_fn2 = (x, y, z56) => 4 * x / (x + 15 * y + 3 * z56);
15006
+ var v_fn2 = (x, y, z56) => 9 * y / (x + 15 * y + 3 * z56);
14959
15007
  var un2 = u_fn2(D50.X, D50.Y, D50.Z);
14960
15008
  var vn2 = v_fn2(D50.X, D50.Y, D50.Z);
14961
15009
  var convertLuvToXyz50 = ({ l: l2, u, v, alpha }) => {
@@ -14969,8 +15017,8 @@ var convertLuvToXyz50 = ({ l: l2, u, v, alpha }) => {
14969
15017
  let vp = v / (13 * l2) + vn2;
14970
15018
  let y = D50.Y * (l2 <= 8 ? l2 / k3 : Math.pow((l2 + 16) / 116, 3));
14971
15019
  let x = y * (9 * up) / (4 * vp);
14972
- let z55 = y * (12 - 3 * up - 20 * vp) / (4 * vp);
14973
- let res = { mode: "xyz50", x, y, z: z55 };
15020
+ let z56 = y * (12 - 3 * up - 20 * vp) / (4 * vp);
15021
+ let res = { mode: "xyz50", x, y, z: z56 };
14974
15022
  if (alpha !== void 0) {
14975
15023
  res.alpha = alpha;
14976
15024
  }
@@ -15587,15 +15635,15 @@ var convertP3ToXyz65 = (rgb2) => {
15587
15635
  var convertP3ToXyz65_default = convertP3ToXyz65;
15588
15636
 
15589
15637
  // ../../node_modules/culori/src/p3/convertXyz65ToP3.js
15590
- var convertXyz65ToP3 = ({ x, y, z: z55, alpha }) => {
15638
+ var convertXyz65ToP3 = ({ x, y, z: z56, alpha }) => {
15591
15639
  if (x === void 0) x = 0;
15592
15640
  if (y === void 0) y = 0;
15593
- if (z55 === void 0) z55 = 0;
15641
+ if (z56 === void 0) z56 = 0;
15594
15642
  let res = convertLrgbToRgb_default(
15595
15643
  {
15596
- r: x * 2.4934969119414263 - y * 0.9313836179191242 - 0.402710784450717 * z55,
15597
- g: x * -0.8294889695615749 + y * 1.7626640603183465 + 0.0236246858419436 * z55,
15598
- b: x * 0.0358458302437845 - y * 0.0761723892680418 + 0.9568845240076871 * z55
15644
+ r: x * 2.4934969119414263 - y * 0.9313836179191242 - 0.402710784450717 * z56,
15645
+ g: x * -0.8294889695615749 + y * 1.7626640603183465 + 0.0236246858419436 * z56,
15646
+ b: x * 0.0358458302437845 - y * 0.0761723892680418 + 0.9568845240076871 * z56
15599
15647
  },
15600
15648
  "p3"
15601
15649
  );
@@ -15630,19 +15678,19 @@ var gamma2 = (v) => {
15630
15678
  }
15631
15679
  return 16 * v;
15632
15680
  };
15633
- var convertXyz50ToProphoto = ({ x, y, z: z55, alpha }) => {
15681
+ var convertXyz50ToProphoto = ({ x, y, z: z56, alpha }) => {
15634
15682
  if (x === void 0) x = 0;
15635
15683
  if (y === void 0) y = 0;
15636
- if (z55 === void 0) z55 = 0;
15684
+ if (z56 === void 0) z56 = 0;
15637
15685
  let res = {
15638
15686
  mode: "prophoto",
15639
15687
  r: gamma2(
15640
- x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z55
15688
+ x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z56
15641
15689
  ),
15642
15690
  g: gamma2(
15643
- x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z55
15691
+ x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z56
15644
15692
  ),
15645
- b: gamma2(x * 0 + y * 0 + 1.2119675456389452 * z55)
15693
+ b: gamma2(x * 0 + y * 0 + 1.2119675456389452 * z56)
15646
15694
  };
15647
15695
  if (alpha !== void 0) {
15648
15696
  res.alpha = alpha;
@@ -15702,20 +15750,20 @@ var gamma3 = (v) => {
15702
15750
  }
15703
15751
  return 4.5 * v;
15704
15752
  };
15705
- var convertXyz65ToRec2020 = ({ x, y, z: z55, alpha }) => {
15753
+ var convertXyz65ToRec2020 = ({ x, y, z: z56, alpha }) => {
15706
15754
  if (x === void 0) x = 0;
15707
15755
  if (y === void 0) y = 0;
15708
- if (z55 === void 0) z55 = 0;
15756
+ if (z56 === void 0) z56 = 0;
15709
15757
  let res = {
15710
15758
  mode: "rec2020",
15711
15759
  r: gamma3(
15712
- x * 1.7166511879712683 - y * 0.3556707837763925 - 0.2533662813736599 * z55
15760
+ x * 1.7166511879712683 - y * 0.3556707837763925 - 0.2533662813736599 * z56
15713
15761
  ),
15714
15762
  g: gamma3(
15715
- x * -0.6666843518324893 + y * 1.6164812366349395 + 0.0157685458139111 * z55
15763
+ x * -0.6666843518324893 + y * 1.6164812366349395 + 0.0157685458139111 * z56
15716
15764
  ),
15717
15765
  b: gamma3(
15718
- x * 0.0176398574453108 - y * 0.0427706132578085 + 0.9421031212354739 * z55
15766
+ x * 0.0176398574453108 - y * 0.0427706132578085 + 0.9421031212354739 * z56
15719
15767
  )
15720
15768
  };
15721
15769
  if (alpha !== void 0) {
@@ -15868,15 +15916,15 @@ var definition_default26 = definition26;
15868
15916
 
15869
15917
  // ../../node_modules/culori/src/xyz65/convertXyz65ToXyz50.js
15870
15918
  var convertXyz65ToXyz50 = (xyz652) => {
15871
- let { x, y, z: z55, alpha } = xyz652;
15919
+ let { x, y, z: z56, alpha } = xyz652;
15872
15920
  if (x === void 0) x = 0;
15873
15921
  if (y === void 0) y = 0;
15874
- if (z55 === void 0) z55 = 0;
15922
+ if (z56 === void 0) z56 = 0;
15875
15923
  let res = {
15876
15924
  mode: "xyz50",
15877
- x: 1.0479298208405488 * x + 0.0229467933410191 * y - 0.0501922295431356 * z55,
15878
- y: 0.0296278156881593 * x + 0.990434484573249 * y - 0.0170738250293851 * z55,
15879
- z: -0.0092430581525912 * x + 0.0150551448965779 * y + 0.7518742899580008 * z55
15925
+ x: 1.0479298208405488 * x + 0.0229467933410191 * y - 0.0501922295431356 * z56,
15926
+ y: 0.0296278156881593 * x + 0.990434484573249 * y - 0.0170738250293851 * z56,
15927
+ z: -0.0092430581525912 * x + 0.0150551448965779 * y + 0.7518742899580008 * z56
15880
15928
  };
15881
15929
  if (alpha !== void 0) {
15882
15930
  res.alpha = alpha;
@@ -15887,15 +15935,15 @@ var convertXyz65ToXyz50_default = convertXyz65ToXyz50;
15887
15935
 
15888
15936
  // ../../node_modules/culori/src/xyz65/convertXyz50ToXyz65.js
15889
15937
  var convertXyz50ToXyz65 = (xyz502) => {
15890
- let { x, y, z: z55, alpha } = xyz502;
15938
+ let { x, y, z: z56, alpha } = xyz502;
15891
15939
  if (x === void 0) x = 0;
15892
15940
  if (y === void 0) y = 0;
15893
- if (z55 === void 0) z55 = 0;
15941
+ if (z56 === void 0) z56 = 0;
15894
15942
  let res = {
15895
15943
  mode: "xyz65",
15896
- x: 0.9554734527042182 * x - 0.0230985368742614 * y + 0.0632593086610217 * z55,
15897
- y: -0.0283697069632081 * x + 1.0099954580058226 * y + 0.021041398966943 * z55,
15898
- z: 0.0123140016883199 * x - 0.0205076964334779 * y + 1.3303659366080753 * z55
15944
+ x: 0.9554734527042182 * x - 0.0230985368742614 * y + 0.0632593086610217 * z56,
15945
+ y: -0.0283697069632081 * x + 1.0099954580058226 * y + 0.021041398966943 * z56,
15946
+ z: 0.0123140016883199 * x - 0.0205076964334779 * y + 1.3303659366080753 * z56
15899
15947
  };
15900
15948
  if (alpha !== void 0) {
15901
15949
  res.alpha = alpha;
@@ -16165,6 +16213,571 @@ z.string().optional().nullable().transform((value) => {
16165
16213
  }
16166
16214
  );
16167
16215
 
16216
+ // ../../internal/utils/src/industry.ts
16217
+ var Industry = {
16218
+ // Finance
16219
+ BANKING: "banking",
16220
+ FINANCIAL_SERVICES: "financial_services",
16221
+ FINTECH: "fintech",
16222
+ PAYMENTS: "payments"};
16223
+
16224
+ // ../../internal/validation/src/dark-web/templates.ts
16225
+ var BRAND = { kind: "brand" };
16226
+ var lit = (value) => ({ kind: "literal", value });
16227
+ var phrase = (...tokens) => ({ type: "phrase", tokens });
16228
+ var bn = (slop, ...words) => ({
16229
+ type: "phrase",
16230
+ tokens: [BRAND, ...words.map(lit)],
16231
+ slop
16232
+ });
16233
+ var nb = (slop, ...words) => ({
16234
+ type: "phrase",
16235
+ tokens: [...words.map(lit), BRAND],
16236
+ slop
16237
+ });
16238
+ var word = (value) => ({ type: "term", value, match: "word" });
16239
+ var prefix = (value) => ({
16240
+ type: "term",
16241
+ value,
16242
+ match: "prefix"
16243
+ });
16244
+ var or = (...children) => ({
16245
+ type: "group",
16246
+ op: "OR",
16247
+ children
16248
+ });
16249
+ var and = (...children) => ({
16250
+ type: "group",
16251
+ op: "AND",
16252
+ children
16253
+ });
16254
+ var notOneOf = (...children) => ({
16255
+ type: "group",
16256
+ op: "OR",
16257
+ children,
16258
+ negated: true
16259
+ });
16260
+ var brandWith = (...values) => and(phrase(BRAND), or(...values.map(word)));
16261
+ var SCAN_TEMPLATES = [
16262
+ {
16263
+ id: "p2p-instant-transfer",
16264
+ category: "payment-fraud",
16265
+ title: "P2P and instant transfer abuse",
16266
+ description: "Actors advertising instant peer-to-peer transfers into or out of the brand, a common way to move stolen funds before a hold clears.",
16267
+ // Source rows: 1, 55. The original ("[brand]"~3) was proximity on one
16268
+ // position, a no-op; dropped rather than ported.
16269
+ query: and(
16270
+ or(
16271
+ phrase(BRAND, lit("to"), BRAND),
16272
+ bn(2, "instant"),
16273
+ bn(2, "anyone"),
16274
+ bn(1, "pay"),
16275
+ bn(3, "pay anyone"),
16276
+ bn(2, "p2p"),
16277
+ bn(3, "instant transfer"),
16278
+ bn(3, "receive from anyone"),
16279
+ bn(4, "phone number"),
16280
+ bn(2, "member to member"),
16281
+ nb(3, "send")
16282
+ ),
16283
+ notOneOf(word("rate"), word("price"))
16284
+ )
16285
+ },
16286
+ {
16287
+ id: "transfers-ach-direct-debit",
16288
+ category: "payment-fraud",
16289
+ title: "Transfers, ACH and direct debit",
16290
+ description: "Discussion of pushing or pulling funds via ACH, direct debit or bill pay, including chatter about pending and settlement timing.",
16291
+ // Source rows: 6, 8, 18, 41. Row 18 was missing an OR before "Direct Debit".
16292
+ query: or(
16293
+ bn(1, "transfer"),
16294
+ nb(1, "transfer"),
16295
+ bn(5, "ach"),
16296
+ nb(4, "pull"),
16297
+ nb(4, "push"),
16298
+ bn(4, "pending"),
16299
+ bn(4, "settle"),
16300
+ nb(4, "link"),
16301
+ brandWith("billpay", "acctverify"),
16302
+ and(phrase(BRAND), or(phrase(lit("direct debit")), phrase(lit("direct deposit"))))
16303
+ )
16304
+ },
16305
+ {
16306
+ id: "wallet-linking",
16307
+ category: "payment-fraud",
16308
+ title: "Wallet linking and instant funding",
16309
+ description: "Linking the brand to mobile wallets for instant funding, and 'linkable' account trading where a name match is being sold.",
16310
+ // Source rows: 19, 44, 51
16311
+ query: and(
16312
+ or(
16313
+ bn(5, "apple pay"),
16314
+ bn(5, "apple"),
16315
+ bn(3, "apple linkable"),
16316
+ bn(2, "linkable"),
16317
+ bn(2, "linkables"),
16318
+ nb(2, "linkable"),
16319
+ nb(2, "link"),
16320
+ and(phrase(BRAND), phrase(lit("name match")))
16321
+ ),
16322
+ notOneOf(word("espn"), word("airtag"))
16323
+ )
16324
+ },
16325
+ {
16326
+ id: "card-data-exposure",
16327
+ category: "payment-fraud",
16328
+ title: "Card data and virtual cards",
16329
+ description: "Brand-issued card details being traded: expiry, CVV, virtual card numbers and card activation.",
16330
+ // Source rows: 43
16331
+ query: and(
16332
+ brandWith("exp", "cvv", "vcc", "debit"),
16333
+ notOneOf(word("checking"), word("limits"))
16334
+ )
16335
+ },
16336
+ {
16337
+ id: "card-loading",
16338
+ category: "payment-fraud",
16339
+ title: "Card and account loading",
16340
+ description: "'Loading' services that push stolen funds onto brand accounts or cards for a cut.",
16341
+ // Source rows: 42
16342
+ query: or(
16343
+ nb(1, "loading"),
16344
+ nb(1, "load"),
16345
+ bn(1, "loads"),
16346
+ bn(1, "loading"),
16347
+ bn(3, "drop"),
16348
+ bn(2, "cash"),
16349
+ and(
16350
+ phrase(BRAND),
16351
+ or(
16352
+ phrase(lit("loading method")),
16353
+ phrase(lit("loading guide")),
16354
+ phrase(lit("loading tut")),
16355
+ phrase(lit("loading tutorial"))
16356
+ )
16357
+ )
16358
+ )
16359
+ },
16360
+ {
16361
+ id: "cross-platform-cashout",
16362
+ category: "payment-fraud",
16363
+ title: "Cross-platform cash-out",
16364
+ description: "Moving funds from the brand into other consumer payment apps to break the trail.",
16365
+ // Source rows: 56
16366
+ query: and(
16367
+ phrase(BRAND),
16368
+ or(
16369
+ phrase(lit("cash app")),
16370
+ word("venmo"),
16371
+ phrase(lit("transfer to paypal")),
16372
+ phrase(lit("visa money transfer"))
16373
+ )
16374
+ )
16375
+ },
16376
+ {
16377
+ id: "crypto-offramp",
16378
+ category: "payment-fraud",
16379
+ title: "Crypto off-ramp",
16380
+ description: "Converting funds held at the brand into cryptocurrency through exchanges and P2P markets.",
16381
+ // Source rows: 63
16382
+ query: and(
16383
+ phrase(BRAND),
16384
+ or(
16385
+ word("crypto"),
16386
+ word("moonpay"),
16387
+ word("switchere"),
16388
+ word("kraken"),
16389
+ word("paxful"),
16390
+ word("noones"),
16391
+ word("coinomi"),
16392
+ word("coinzoom"),
16393
+ word("bitcoin"),
16394
+ word("btc")
16395
+ )
16396
+ )
16397
+ },
16398
+ {
16399
+ id: "mobile-check-deposit",
16400
+ category: "deposit-fraud",
16401
+ title: "Mobile check deposit fraud",
16402
+ description: "Check fraud against mobile deposit, traded under slang including 'glass', 'MCD', 'slips' and 'persy'.",
16403
+ // Source rows: 2, 13, 35, 46
16404
+ industries: [
16405
+ Industry.BANKING,
16406
+ Industry.FINANCIAL_SERVICES,
16407
+ Industry.FINTECH,
16408
+ Industry.PAYMENTS
16409
+ ],
16410
+ query: or(
16411
+ bn(5, "checks"),
16412
+ bn(5, "check"),
16413
+ bn(5, "mobile deposit"),
16414
+ nb(5, "mobile deposit"),
16415
+ bn(5, "slip"),
16416
+ bn(5, "slips"),
16417
+ bn(5, "glass"),
16418
+ bn(5, "md"),
16419
+ bn(5, "mcd"),
16420
+ bn(5, "treasury"),
16421
+ nb(5, "treasury"),
16422
+ bn(5, "persy"),
16423
+ bn(5, "deposit limit"),
16424
+ and(phrase(BRAND), or(prefix("stimm"), word("mcd"), phrase(lit("pop on"))))
16425
+ )
16426
+ },
16427
+ {
16428
+ id: "atm-abuse",
16429
+ category: "deposit-fraud",
16430
+ title: "ATM abuse and 'box work'",
16431
+ description: "ATM deposit and withdrawal manipulation, including dispute-driven 'box work' against cash machines.",
16432
+ // Source rows: 9, 47, 57, 70
16433
+ industries: [
16434
+ Industry.BANKING,
16435
+ Industry.FINANCIAL_SERVICES,
16436
+ Industry.FINTECH,
16437
+ Industry.PAYMENTS
16438
+ ],
16439
+ query: or(
16440
+ bn(2, "atm"),
16441
+ bn(2, "withdrawal"),
16442
+ and(phrase(BRAND), phrase(lit("box work"))),
16443
+ and(
16444
+ phrase(BRAND),
16445
+ or(
16446
+ phrase(lit("atm deposit")),
16447
+ phrase(lit("atm withdrawal")),
16448
+ phrase(lit("atm withdraw")),
16449
+ phrase(lit("atm limit")),
16450
+ phrase(lit("atm card")),
16451
+ phrase(lit("cash withdrawal fee"))
16452
+ )
16453
+ )
16454
+ )
16455
+ },
16456
+ {
16457
+ id: "retail-cashout-network",
16458
+ category: "deposit-fraud",
16459
+ title: "Retail cash-out network",
16460
+ description: "Cash-out through retail and ATM partner networks, where funds are pulled at a storefront rather than a branch.",
16461
+ // Source rows: 30
16462
+ industries: [
16463
+ Industry.BANKING,
16464
+ Industry.FINANCIAL_SERVICES,
16465
+ Industry.FINTECH,
16466
+ Industry.PAYMENTS
16467
+ ],
16468
+ query: or(
16469
+ bn(5, "allpoint"),
16470
+ bn(5, "walgreens"),
16471
+ bn(5, "cvs"),
16472
+ bn(5, "7-eleven"),
16473
+ bn(5, "7eleven"),
16474
+ bn(5, "711"),
16475
+ bn(5, "circle k"),
16476
+ bn(5, "target"),
16477
+ bn(5, "visa plus alliance"),
16478
+ bn(3, "moneypass"),
16479
+ bn(3, "vanilladirect"),
16480
+ bn(3, "vanilla"),
16481
+ bn(3, "dollar general"),
16482
+ bn(3, "dollar tree"),
16483
+ bn(3, "safeway"),
16484
+ bn(3, "walmart"),
16485
+ bn(3, "speedway")
16486
+ )
16487
+ },
16488
+ {
16489
+ id: "otp-bots",
16490
+ category: "account-takeover",
16491
+ title: "OTP bots and 2FA bypass",
16492
+ description: "Automated one-time-passcode interception services targeting the brand's login and step-up flows.",
16493
+ // Source rows: 34
16494
+ query: or(
16495
+ bn(2, "otp"),
16496
+ nb(1, "otp"),
16497
+ phrase(BRAND, lit("otp bot")),
16498
+ bn(2, "2fa"),
16499
+ bn(2, "code"),
16500
+ bn(2, "bypass"),
16501
+ bn(2, "bot"),
16502
+ bn(2, "bots")
16503
+ )
16504
+ },
16505
+ {
16506
+ id: "remote-access-tooling",
16507
+ category: "account-takeover",
16508
+ title: "Remote-access tooling",
16509
+ description: "Legitimate remote-management tools named alongside the brand, the standard toolkit for support-impersonation account takeover.",
16510
+ // Source rows: 29, 64. Truncated by the export; recoverable portion only.
16511
+ query: and(
16512
+ phrase(BRAND),
16513
+ or(
16514
+ word("action1"),
16515
+ phrase(lit("ammy admin")),
16516
+ word("ammyadmin"),
16517
+ word("anydesk"),
16518
+ phrase(lit("any desk")),
16519
+ word("atera"),
16520
+ word("beanywhere"),
16521
+ phrase(lit("chrome remote desktop")),
16522
+ word("connectwise"),
16523
+ word("screenconnect"),
16524
+ word("dameware"),
16525
+ word("domotz"),
16526
+ word("dwservice"),
16527
+ word("fleetdeck"),
16528
+ word("intelliadmin"),
16529
+ phrase(lit("itarian endpoint manager")),
16530
+ phrase(lit("level.io")),
16531
+ word("meshcentral"),
16532
+ word("mremoteng"),
16533
+ phrase(lit("n-able")),
16534
+ word("ngrok"),
16535
+ phrase(lit("pdq deploy")),
16536
+ word("pulseway"),
16537
+ word("realvnc"),
16538
+ phrase(lit("remote utilities")),
16539
+ word("rport")
16540
+ )
16541
+ )
16542
+ },
16543
+ {
16544
+ id: "antidetect-kyc-evasion",
16545
+ category: "account-takeover",
16546
+ title: "Anti-detect and KYC evasion tooling",
16547
+ description: "Fingerprint spoofing, residential proxies and emulators used to defeat the brand's device and identity checks.",
16548
+ // Source row: 40. The original filtered to Telegram OR Dread; DarkOwl's
16549
+ // `source` takes one value, so precision comes from the tooling terms.
16550
+ query: and(
16551
+ phrase(BRAND),
16552
+ or(
16553
+ word("tlo"),
16554
+ word("scamalytics"),
16555
+ word("burner"),
16556
+ prefix("prox"),
16557
+ word("vpn"),
16558
+ word("vps"),
16559
+ word("antidetect"),
16560
+ phrase(lit("anti-detect")),
16561
+ prefix("emulat")
16562
+ )
16563
+ )
16564
+ },
16565
+ {
16566
+ id: "brand-domains-sso",
16567
+ category: "account-takeover",
16568
+ title: "Brand domains and SSO endpoints",
16569
+ description: "The brand's own domains and identity-provider endpoints appearing in credential and access chatter.",
16570
+ // Source row: 31, as proximity not literal hostnames — the index tokenizes
16571
+ // `chime.okta.com`, so a glued literal would never match. Row 23's
16572
+ // "[brand] pass*"~1 is omitted: no wildcards inside a phrase.
16573
+ query: and(
16574
+ or(bn(2, "okta"), bn(2, "login"), bn(2, "portal"), bn(1, "bank")),
16575
+ notOneOf(word("zendesk"))
16576
+ )
16577
+ },
16578
+ {
16579
+ id: "account-opening-abuse",
16580
+ category: "onboarding-abuse",
16581
+ title: "Account opening and self-registration",
16582
+ description: "Bulk or fraudulent account creation against the brand, including 'self-reg' and 'drop' accounts opened on stolen identities.",
16583
+ // Source rows: 5, 17, 54
16584
+ query: or(
16585
+ bn(5, "enroll"),
16586
+ nb(5, "enroll"),
16587
+ bn(5, "open"),
16588
+ nb(5, "open"),
16589
+ bn(5, "drop"),
16590
+ nb(5, "drop"),
16591
+ nb(5, "make"),
16592
+ nb(5, "create"),
16593
+ nb(5, "fresh"),
16594
+ nb(5, "register"),
16595
+ bn(5, "self-reg"),
16596
+ bn(5, "selfreg"),
16597
+ bn(5, "self-registered"),
16598
+ bn(5, "self register"),
16599
+ bn(1, "fullz")
16600
+ )
16601
+ },
16602
+ {
16603
+ id: "identity-documents",
16604
+ category: "onboarding-abuse",
16605
+ title: "Identity documents and fullz",
16606
+ description: "Trade in identity packages and lookup services used to pass onboarding checks. Anchored to the brand at the root, since the source query was brand-independent.",
16607
+ // Source row: 15. Lexicon-only, so the renderer AND-s the anchor on.
16608
+ query: or(
16609
+ word("fullz"),
16610
+ phrase(lit("get pros")),
16611
+ phrase(lit("driver's license")),
16612
+ phrase(lit("tlo bot")),
16613
+ phrase(lit("tlo plug")),
16614
+ phrase(lit("need dl")),
16615
+ phrase(lit("get id"))
16616
+ )
16617
+ },
16618
+ {
16619
+ id: "referral-bonus-abuse",
16620
+ category: "onboarding-abuse",
16621
+ title: "Referral and bonus abuse",
16622
+ description: "Methods for farming the brand's referral bonuses and promotional offers, often paired with fake direct deposits.",
16623
+ // Source rows: 48
16624
+ query: and(
16625
+ or(bn(3, "referral"), bn(3, "bonus"), bn(3, "promotion"), bn(3, "offer")),
16626
+ or(
16627
+ word("bypass"),
16628
+ word("dd"),
16629
+ phrase(lit("direct deposit")),
16630
+ phrase(lit("work around")),
16631
+ word("trick"),
16632
+ word("method"),
16633
+ word("glitch"),
16634
+ word("tutorial"),
16635
+ word("tut"),
16636
+ word("wave"),
16637
+ word("sauce")
16638
+ )
16639
+ )
16640
+ },
16641
+ {
16642
+ id: "insider-recruitment",
16643
+ category: "insider-threat",
16644
+ title: "Insider recruitment",
16645
+ description: "Actors seeking or advertising an employee on the inside ('inny'), the highest-severity signal in this catalog.",
16646
+ // Source rows: 7, 38
16647
+ query: and(
16648
+ or(
16649
+ bn(4, "inny"),
16650
+ bn(4, "insider"),
16651
+ and(
16652
+ phrase(BRAND),
16653
+ or(
16654
+ word("insider"),
16655
+ word("inny"),
16656
+ phrase(lit("in office")),
16657
+ word("employee"),
16658
+ phrase(lit("i work at")),
16659
+ phrase(lit("i am an employee")),
16660
+ phrase(lit("i can get access")),
16661
+ phrase(lit("i have access to")),
16662
+ phrase(lit("employed at")),
16663
+ word("occupation")
16664
+ )
16665
+ )
16666
+ ),
16667
+ notOneOf(phrase(lit("welcome to insider chat")))
16668
+ )
16669
+ },
16670
+ {
16671
+ id: "mule-crew-recruitment",
16672
+ category: "insider-threat",
16673
+ title: "Mule and cash-out crew recruitment",
16674
+ description: "Recruitment of account holders to receive and forward funds, priced as a revenue split ('50/50', '60/40').",
16675
+ // Source rows: 39
16676
+ query: or(
16677
+ bn(5, "cl"),
16678
+ bn(5, "mule"),
16679
+ bn(5, "tap in"),
16680
+ bn(5, "50/50"),
16681
+ bn(5, "60/40"),
16682
+ bn(5, "striker")
16683
+ )
16684
+ },
16685
+ {
16686
+ id: "methods-and-tutorials",
16687
+ category: "tradecraft",
16688
+ title: "Methods, 'sauce' and tutorials",
16689
+ description: "Fraud methods being taught or sold against the brand, under the usual slang: sauce, glitch, tut, wave, motion, tap in.",
16690
+ // Source rows: 4, 21, 59
16691
+ query: or(
16692
+ bn(3, "sauce"),
16693
+ bn(3, "method"),
16694
+ bn(3, "guide"),
16695
+ bn(3, "tut"),
16696
+ bn(3, "tutorial"),
16697
+ bn(4, "hack"),
16698
+ bn(4, "glitch"),
16699
+ bn(4, "wave"),
16700
+ bn(4, "motion"),
16701
+ bn(4, "walkthrough"),
16702
+ bn(4, "walk through"),
16703
+ bn(2, "tap in"),
16704
+ bn(2, "tapin"),
16705
+ nb(2, "tapn")
16706
+ )
16707
+ },
16708
+ {
16709
+ id: "hack-leak-chatter",
16710
+ category: "tradecraft",
16711
+ title: "Hack and leak chatter",
16712
+ description: "Claims of having hacked, breached or leaked the brand, whether credible or not.",
16713
+ // Source rows: 28
16714
+ query: or(
16715
+ bn(4, "hack"),
16716
+ bn(4, "glitch"),
16717
+ nb(4, "hacking"),
16718
+ bn(4, "leak"),
16719
+ bn(4, "leaked")
16720
+ )
16721
+ },
16722
+ {
16723
+ id: "support-impersonation",
16724
+ category: "brand-abuse",
16725
+ title: "Support impersonation",
16726
+ description: "Actors impersonating the brand's support or service staff to social-engineer customers.",
16727
+ // Source rows: 36
16728
+ query: or(
16729
+ bn(1, "agent"),
16730
+ bn(1, "support"),
16731
+ bn(1, "service"),
16732
+ bn(1, "customer"),
16733
+ nb(1, "impersonate"),
16734
+ bn(1, "impersonation"),
16735
+ bn(3, "scam"),
16736
+ nb(1, "scam")
16737
+ )
16738
+ },
16739
+ {
16740
+ id: "social-impersonation",
16741
+ category: "brand-abuse",
16742
+ title: "Social account impersonation",
16743
+ description: "The brand discussed alongside social platforms, where fake support and giveaway accounts are staged.",
16744
+ // Source rows: 25
16745
+ query: or(
16746
+ bn(5, "instagram"),
16747
+ bn(5, "insta"),
16748
+ bn(5, "facebook"),
16749
+ bn(5, "twitter"),
16750
+ bn(5, "tiktok")
16751
+ )
16752
+ },
16753
+ {
16754
+ id: "vendor-supply-chain",
16755
+ category: "data-exposure",
16756
+ title: "Vendor and BPO supply chain",
16757
+ description: "Outsourced support and processing vendors named alongside the brand, where a third-party breach exposes brand customer data.",
16758
+ // Source row: 60, truncated by the export. Generic BPO/CX providers; a
16759
+ // per-org vendor list would be materially better.
16760
+ query: and(
16761
+ phrase(BRAND),
16762
+ or(
16763
+ word("zendesk"),
16764
+ word("teleperformance"),
16765
+ word("concentrix"),
16766
+ word("taskus"),
16767
+ word("genpact"),
16768
+ word("ubiquity"),
16769
+ word("hioperator"),
16770
+ word("galileo"),
16771
+ word("fiserv"),
16772
+ phrase(lit("etech global"))
16773
+ )
16774
+ )
16775
+ }
16776
+ ];
16777
+ new Map(
16778
+ SCAN_TEMPLATES.map((template) => [template.id, template])
16779
+ );
16780
+
16168
16781
  // src/client.ts
16169
16782
  function trimTrailingSlashes(url) {
16170
16783
  return url.replace(/\/+$/, "");