@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.js CHANGED
@@ -1313,17 +1313,17 @@ var PolyDateFormatter = class {
1313
1313
  constructor(dt, intl, opts) {
1314
1314
  this.opts = opts;
1315
1315
  this.originalZone = void 0;
1316
- let z55 = void 0;
1316
+ let z56 = void 0;
1317
1317
  if (this.opts.timeZone) {
1318
1318
  this.dt = dt;
1319
1319
  } else if (dt.zone.type === "fixed") {
1320
1320
  const gmtOffset = -1 * (dt.offset / 60);
1321
1321
  const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
1322
1322
  if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
1323
- z55 = offsetZ;
1323
+ z56 = offsetZ;
1324
1324
  this.dt = dt;
1325
1325
  } else {
1326
- z55 = "UTC";
1326
+ z56 = "UTC";
1327
1327
  this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
1328
1328
  this.originalZone = dt.zone;
1329
1329
  }
@@ -1331,14 +1331,14 @@ var PolyDateFormatter = class {
1331
1331
  this.dt = dt;
1332
1332
  } else if (dt.zone.type === "iana") {
1333
1333
  this.dt = dt;
1334
- z55 = dt.zone.name;
1334
+ z56 = dt.zone.name;
1335
1335
  } else {
1336
- z55 = "UTC";
1336
+ z56 = "UTC";
1337
1337
  this.dt = dt.setZone("UTC").plus({ minutes: dt.offset });
1338
1338
  this.originalZone = dt.zone;
1339
1339
  }
1340
1340
  const intlOpts = __spreadValues({}, this.opts);
1341
- intlOpts.timeZone = intlOpts.timeZone || z55;
1341
+ intlOpts.timeZone = intlOpts.timeZone || z56;
1342
1342
  this.dtf = getCachedDTF(intl, intlOpts);
1343
1343
  }
1344
1344
  format() {
@@ -11488,6 +11488,50 @@ zod.z.object({
11488
11488
  endDate: zod.z.date()
11489
11489
  })
11490
11490
  });
11491
+ var DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
11492
+ var utcDateSchema = (endOfDay) => zod.z.preprocess((value) => {
11493
+ if (typeof value !== "string") {
11494
+ return value;
11495
+ }
11496
+ const parsed = DateTime.fromISO(value, { zone: "utc" });
11497
+ if (!parsed.isValid) {
11498
+ return new Date(Number.NaN);
11499
+ }
11500
+ return endOfDay && DATE_ONLY_PATTERN.test(value) ? parsed.endOf("day").toJSDate() : parsed.toJSDate();
11501
+ }, zod.z.coerce.date());
11502
+ var funnelCountsSchema = zod.z.object({
11503
+ blocked: zod.z.number().int().nonnegative().describe(
11504
+ "Distinct assets whose earliest report for this org falls in the range and whose current status or pending status is BLOCKED"
11505
+ )
11506
+ });
11507
+ zod.z.object({
11508
+ slug: zod.z.string().min(1).describe("Organization slug"),
11509
+ startDate: utcDateSchema(false).describe(
11510
+ "Only include assets whose earliest report was created on or after this date. A date-only value (YYYY-MM-DD) starts at midnight UTC"
11511
+ ),
11512
+ endDate: utcDateSchema(true).describe(
11513
+ "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"
11514
+ ),
11515
+ brandIds: zod.z.array(zod.z.number().int().positive()).optional().describe("Only include assets belonging to these brands")
11516
+ }).refine((input) => input.startDate.getTime() <= input.endDate.getTime(), {
11517
+ message: "startDate must be on or before endDate",
11518
+ path: ["startDate"]
11519
+ });
11520
+ zod.z.object({
11521
+ range: zod.z.object({
11522
+ startDate: zod.z.date(),
11523
+ endDate: zod.z.date()
11524
+ }),
11525
+ customer: funnelCountsSchema.describe(
11526
+ "Currently blocked assets first reported by the customer (reportedByCustomer, external reporter, or customer-role user)"
11527
+ ),
11528
+ chainpatrol: funnelCountsSchema.describe(
11529
+ "Currently blocked assets first reported by ChainPatrol staff or automation. Staff and automation are collapsed together."
11530
+ ),
11531
+ totals: funnelCountsSchema.describe(
11532
+ "customer + chainpatrol. This is a first-report blocked cohort and does not equal metrics/found, which counts assets by blockedAt."
11533
+ )
11534
+ });
11491
11535
  zod.z.object({
11492
11536
  slug: zod.z.string().min(1),
11493
11537
  startDate: zod.z.date().optional(),
@@ -11519,8 +11563,8 @@ zod.z.object({
11519
11563
  })
11520
11564
  )
11521
11565
  });
11522
- var DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
11523
- var utcDateSchema = (endOfDay) => zod.z.preprocess((value) => {
11566
+ var DATE_ONLY_PATTERN2 = /^\d{4}-\d{2}-\d{2}$/;
11567
+ var utcDateSchema2 = (endOfDay) => zod.z.preprocess((value) => {
11524
11568
  if (typeof value !== "string") {
11525
11569
  return value;
11526
11570
  }
@@ -11528,14 +11572,14 @@ var utcDateSchema = (endOfDay) => zod.z.preprocess((value) => {
11528
11572
  if (!parsed.isValid) {
11529
11573
  return new Date(Number.NaN);
11530
11574
  }
11531
- return endOfDay && DATE_ONLY_PATTERN.test(value) ? parsed.endOf("day").toJSDate() : parsed.toJSDate();
11575
+ return endOfDay && DATE_ONLY_PATTERN2.test(value) ? parsed.endOf("day").toJSDate() : parsed.toJSDate();
11532
11576
  }, zod.z.coerce.date());
11533
11577
  zod.z.object({
11534
11578
  slug: zod.z.string().min(1).describe("Organization slug"),
11535
- startDate: utcDateSchema(false).optional().describe(
11579
+ startDate: utcDateSchema2(false).optional().describe(
11536
11580
  "Only include takedowns completed on or after this date. A date-only value (YYYY-MM-DD) starts at midnight UTC"
11537
11581
  ),
11538
- endDate: utcDateSchema(true).optional().describe(
11582
+ endDate: utcDateSchema2(true).optional().describe(
11539
11583
  "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"
11540
11584
  ),
11541
11585
  blockLabel: zod.z.string().optional().describe(
@@ -11993,7 +12037,9 @@ var organizationMetricsIncludeFieldSchema = zod.z.enum([
11993
12037
  "newThreats",
11994
12038
  "threatsWatchlisted",
11995
12039
  "takedownsFiled",
12040
+ "takedownsInProgress",
11996
12041
  "takedownsCompleted",
12042
+ "takedownsCancelled",
11997
12043
  "domainThreats",
11998
12044
  "twitterThreats",
11999
12045
  "telegramThreats",
@@ -12035,7 +12081,7 @@ zod.z.object({
12035
12081
  startDate: zod.z.coerce.date().optional(),
12036
12082
  endDate: zod.z.coerce.date().optional(),
12037
12083
  include: zod.z.array(organizationMetricsIncludeFieldSchema).optional().describe(
12038
- "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`."
12084
+ "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."
12039
12085
  )
12040
12086
  }).refine(
12041
12087
  (value) => {
@@ -12063,7 +12109,9 @@ var metricsObjectSchema = zod.z.object({
12063
12109
  newThreats: metricValue,
12064
12110
  threatsWatchlisted: metricValue,
12065
12111
  takedownsFiled: metricValue,
12112
+ takedownsInProgress: metricValue,
12066
12113
  takedownsCompleted: metricValue,
12114
+ takedownsCancelled: metricValue,
12067
12115
  domainThreats: metricValue,
12068
12116
  twitterThreats: metricValue,
12069
12117
  telegramThreats: metricValue,
@@ -13446,20 +13494,20 @@ var convertA98ToXyz65_default = convertA98ToXyz65;
13446
13494
 
13447
13495
  // ../../node_modules/culori/src/a98/convertXyz65ToA98.js
13448
13496
  var gamma = (v) => Math.pow(Math.abs(v), 256 / 563) * Math.sign(v);
13449
- var convertXyz65ToA98 = ({ x, y, z: z55, alpha }) => {
13497
+ var convertXyz65ToA98 = ({ x, y, z: z56, alpha }) => {
13450
13498
  if (x === void 0) x = 0;
13451
13499
  if (y === void 0) y = 0;
13452
- if (z55 === void 0) z55 = 0;
13500
+ if (z56 === void 0) z56 = 0;
13453
13501
  let res = {
13454
13502
  mode: "a98",
13455
13503
  r: gamma(
13456
- x * 2.0415879038107465 - y * 0.5650069742788597 - 0.3447313507783297 * z55
13504
+ x * 2.0415879038107465 - y * 0.5650069742788597 - 0.3447313507783297 * z56
13457
13505
  ),
13458
13506
  g: gamma(
13459
- x * -0.9692436362808798 + y * 1.8759675015077206 + 0.0415550574071756 * z55
13507
+ x * -0.9692436362808798 + y * 1.8759675015077206 + 0.0415550574071756 * z56
13460
13508
  ),
13461
13509
  b: gamma(
13462
- x * 0.0134442806320312 - y * 0.1183623922310184 + 1.0151749943912058 * z55
13510
+ x * 0.0134442806320312 - y * 0.1183623922310184 + 1.0151749943912058 * z56
13463
13511
  )
13464
13512
  };
13465
13513
  if (alpha !== void 0) {
@@ -13526,14 +13574,14 @@ var convertLrgbToRgb = ({ r, g, b, alpha }, mode = "rgb") => {
13526
13574
  var convertLrgbToRgb_default = convertLrgbToRgb;
13527
13575
 
13528
13576
  // ../../node_modules/culori/src/xyz65/convertXyz65ToRgb.js
13529
- var convertXyz65ToRgb = ({ x, y, z: z55, alpha }) => {
13577
+ var convertXyz65ToRgb = ({ x, y, z: z56, alpha }) => {
13530
13578
  if (x === void 0) x = 0;
13531
13579
  if (y === void 0) y = 0;
13532
- if (z55 === void 0) z55 = 0;
13580
+ if (z56 === void 0) z56 = 0;
13533
13581
  let res = convertLrgbToRgb_default({
13534
- r: x * 3.2409699419045226 - y * 1.537383177570094 - 0.4986107602930034 * z55,
13535
- g: x * -0.9692436362808796 + y * 1.8759675015077204 + 0.0415550574071756 * z55,
13536
- b: x * 0.0556300796969936 - y * 0.2039769588889765 + 1.0569715142428784 * z55
13582
+ r: x * 3.2409699419045226 - y * 1.537383177570094 - 0.4986107602930034 * z56,
13583
+ g: x * -0.9692436362808796 + y * 1.8759675015077204 + 0.0415550574071756 * z56,
13584
+ b: x * 0.0556300796969936 - y * 0.2039769588889765 + 1.0569715142428784 * z56
13537
13585
  });
13538
13586
  if (alpha !== void 0) {
13539
13587
  res.alpha = alpha;
@@ -13783,13 +13831,13 @@ var convertLab65ToRgb_default = convertLab65ToRgb;
13783
13831
 
13784
13832
  // ../../node_modules/culori/src/lab65/convertXyz65ToLab65.js
13785
13833
  var f = (value) => value > e ? Math.cbrt(value) : (k * value + 16) / 116;
13786
- var convertXyz65ToLab65 = ({ x, y, z: z55, alpha }) => {
13834
+ var convertXyz65ToLab65 = ({ x, y, z: z56, alpha }) => {
13787
13835
  if (x === void 0) x = 0;
13788
13836
  if (y === void 0) y = 0;
13789
- if (z55 === void 0) z55 = 0;
13837
+ if (z56 === void 0) z56 = 0;
13790
13838
  let f0 = f(x / D65.X);
13791
13839
  let f1 = f(y / D65.Y);
13792
- let f22 = f(z55 / D65.Z);
13840
+ let f22 = f(z56 / D65.Z);
13793
13841
  let res = {
13794
13842
  mode: "lab65",
13795
13843
  l: 116 * f1 - 16,
@@ -14446,10 +14494,10 @@ var convertItpToXyz65_default = convertItpToXyz65;
14446
14494
 
14447
14495
  // ../../node_modules/culori/src/itp/convertXyz65ToItp.js
14448
14496
  var toAbs = (c2 = 0) => Math.max(c2 * YW, 0);
14449
- var convertXyz65ToItp = ({ x, y, z: z55, alpha }) => {
14497
+ var convertXyz65ToItp = ({ x, y, z: z56, alpha }) => {
14450
14498
  const absX = toAbs(x);
14451
14499
  const absY = toAbs(y);
14452
- const absZ = toAbs(z55);
14500
+ const absZ = toAbs(z56);
14453
14501
  const l2 = transferPqEncode(
14454
14502
  0.3592832590121217 * absX + 0.6976051147779502 * absY - 0.0358915932320289 * absZ
14455
14503
  );
@@ -14507,15 +14555,15 @@ var jabPqEncode = (v) => {
14507
14555
  return Math.pow((C1 + C2 * vn3) / (1 + C3 * vn3), p);
14508
14556
  };
14509
14557
  var abs = (v = 0) => Math.max(v * 203, 0);
14510
- var convertXyz65ToJab = ({ x, y, z: z55, alpha }) => {
14558
+ var convertXyz65ToJab = ({ x, y, z: z56, alpha }) => {
14511
14559
  x = abs(x);
14512
14560
  y = abs(y);
14513
- z55 = abs(z55);
14514
- let xp = 1.15 * x - 0.15 * z55;
14561
+ z56 = abs(z56);
14562
+ let xp = 1.15 * x - 0.15 * z56;
14515
14563
  let yp = 0.66 * y + 0.34 * x;
14516
- let l2 = jabPqEncode(0.41478972 * xp + 0.579999 * yp + 0.014648 * z55);
14517
- let m = jabPqEncode(-0.20151 * xp + 1.120649 * yp + 0.0531008 * z55);
14518
- let s2 = jabPqEncode(-0.0166008 * xp + 0.2648 * yp + 0.6684799 * z55);
14564
+ let l2 = jabPqEncode(0.41478972 * xp + 0.579999 * yp + 0.014648 * z56);
14565
+ let m = jabPqEncode(-0.20151 * xp + 1.120649 * yp + 0.0531008 * z56);
14566
+ let s2 = jabPqEncode(-0.0166008 * xp + 0.2648 * yp + 0.6684799 * z56);
14519
14567
  let i = (l2 + m) / 2;
14520
14568
  let res = {
14521
14569
  mode: "jab",
@@ -14701,14 +14749,14 @@ var convertLabToXyz50 = ({ l: l2, a, b, alpha }) => {
14701
14749
  var convertLabToXyz50_default = convertLabToXyz50;
14702
14750
 
14703
14751
  // ../../node_modules/culori/src/xyz50/convertXyz50ToRgb.js
14704
- var convertXyz50ToRgb = ({ x, y, z: z55, alpha }) => {
14752
+ var convertXyz50ToRgb = ({ x, y, z: z56, alpha }) => {
14705
14753
  if (x === void 0) x = 0;
14706
14754
  if (y === void 0) y = 0;
14707
- if (z55 === void 0) z55 = 0;
14755
+ if (z56 === void 0) z56 = 0;
14708
14756
  let res = convertLrgbToRgb_default({
14709
- r: x * 3.1341359569958707 - y * 1.6173863321612538 - 0.4906619460083532 * z55,
14710
- g: x * -0.978795502912089 + y * 1.916254567259524 + 0.03344273116131949 * z55,
14711
- b: x * 0.07195537988411677 - y * 0.2289768264158322 + 1.405386058324125 * z55
14757
+ r: x * 3.1341359569958707 - y * 1.6173863321612538 - 0.4906619460083532 * z56,
14758
+ g: x * -0.978795502912089 + y * 1.916254567259524 + 0.03344273116131949 * z56,
14759
+ b: x * 0.07195537988411677 - y * 0.2289768264158322 + 1.405386058324125 * z56
14712
14760
  });
14713
14761
  if (alpha !== void 0) {
14714
14762
  res.alpha = alpha;
@@ -14739,13 +14787,13 @@ var convertRgbToXyz50_default = convertRgbToXyz50;
14739
14787
 
14740
14788
  // ../../node_modules/culori/src/lab/convertXyz50ToLab.js
14741
14789
  var f2 = (value) => value > e3 ? Math.cbrt(value) : (k3 * value + 16) / 116;
14742
- var convertXyz50ToLab = ({ x, y, z: z55, alpha }) => {
14790
+ var convertXyz50ToLab = ({ x, y, z: z56, alpha }) => {
14743
14791
  if (x === void 0) x = 0;
14744
14792
  if (y === void 0) y = 0;
14745
- if (z55 === void 0) z55 = 0;
14793
+ if (z56 === void 0) z56 = 0;
14746
14794
  let f0 = f2(x / D50.X);
14747
14795
  let f1 = f2(y / D50.Y);
14748
- let f22 = f2(z55 / D50.Z);
14796
+ let f22 = f2(z56 / D50.Z);
14749
14797
  let res = {
14750
14798
  mode: "lab",
14751
14799
  l: 116 * f1 - 16,
@@ -14980,18 +15028,18 @@ var convertLchuvToLuv = ({ l: l2, c: c2, h, alpha }) => {
14980
15028
  var convertLchuvToLuv_default = convertLchuvToLuv;
14981
15029
 
14982
15030
  // ../../node_modules/culori/src/luv/convertXyz50ToLuv.js
14983
- var u_fn = (x, y, z55) => 4 * x / (x + 15 * y + 3 * z55);
14984
- var v_fn = (x, y, z55) => 9 * y / (x + 15 * y + 3 * z55);
15031
+ var u_fn = (x, y, z56) => 4 * x / (x + 15 * y + 3 * z56);
15032
+ var v_fn = (x, y, z56) => 9 * y / (x + 15 * y + 3 * z56);
14985
15033
  var un = u_fn(D50.X, D50.Y, D50.Z);
14986
15034
  var vn = v_fn(D50.X, D50.Y, D50.Z);
14987
15035
  var l_fn = (value) => value <= e3 ? k3 * value : 116 * Math.cbrt(value) - 16;
14988
- var convertXyz50ToLuv = ({ x, y, z: z55, alpha }) => {
15036
+ var convertXyz50ToLuv = ({ x, y, z: z56, alpha }) => {
14989
15037
  if (x === void 0) x = 0;
14990
15038
  if (y === void 0) y = 0;
14991
- if (z55 === void 0) z55 = 0;
15039
+ if (z56 === void 0) z56 = 0;
14992
15040
  let l2 = l_fn(y / D50.Y);
14993
- let u = u_fn(x, y, z55);
14994
- let v = v_fn(x, y, z55);
15041
+ let u = u_fn(x, y, z56);
15042
+ let v = v_fn(x, y, z56);
14995
15043
  if (!isFinite(u) || !isFinite(v)) {
14996
15044
  l2 = u = v = 0;
14997
15045
  } else {
@@ -15012,8 +15060,8 @@ var convertXyz50ToLuv = ({ x, y, z: z55, alpha }) => {
15012
15060
  var convertXyz50ToLuv_default = convertXyz50ToLuv;
15013
15061
 
15014
15062
  // ../../node_modules/culori/src/luv/convertLuvToXyz50.js
15015
- var u_fn2 = (x, y, z55) => 4 * x / (x + 15 * y + 3 * z55);
15016
- var v_fn2 = (x, y, z55) => 9 * y / (x + 15 * y + 3 * z55);
15063
+ var u_fn2 = (x, y, z56) => 4 * x / (x + 15 * y + 3 * z56);
15064
+ var v_fn2 = (x, y, z56) => 9 * y / (x + 15 * y + 3 * z56);
15017
15065
  var un2 = u_fn2(D50.X, D50.Y, D50.Z);
15018
15066
  var vn2 = v_fn2(D50.X, D50.Y, D50.Z);
15019
15067
  var convertLuvToXyz50 = ({ l: l2, u, v, alpha }) => {
@@ -15027,8 +15075,8 @@ var convertLuvToXyz50 = ({ l: l2, u, v, alpha }) => {
15027
15075
  let vp = v / (13 * l2) + vn2;
15028
15076
  let y = D50.Y * (l2 <= 8 ? l2 / k3 : Math.pow((l2 + 16) / 116, 3));
15029
15077
  let x = y * (9 * up) / (4 * vp);
15030
- let z55 = y * (12 - 3 * up - 20 * vp) / (4 * vp);
15031
- let res = { mode: "xyz50", x, y, z: z55 };
15078
+ let z56 = y * (12 - 3 * up - 20 * vp) / (4 * vp);
15079
+ let res = { mode: "xyz50", x, y, z: z56 };
15032
15080
  if (alpha !== void 0) {
15033
15081
  res.alpha = alpha;
15034
15082
  }
@@ -15645,15 +15693,15 @@ var convertP3ToXyz65 = (rgb2) => {
15645
15693
  var convertP3ToXyz65_default = convertP3ToXyz65;
15646
15694
 
15647
15695
  // ../../node_modules/culori/src/p3/convertXyz65ToP3.js
15648
- var convertXyz65ToP3 = ({ x, y, z: z55, alpha }) => {
15696
+ var convertXyz65ToP3 = ({ x, y, z: z56, alpha }) => {
15649
15697
  if (x === void 0) x = 0;
15650
15698
  if (y === void 0) y = 0;
15651
- if (z55 === void 0) z55 = 0;
15699
+ if (z56 === void 0) z56 = 0;
15652
15700
  let res = convertLrgbToRgb_default(
15653
15701
  {
15654
- r: x * 2.4934969119414263 - y * 0.9313836179191242 - 0.402710784450717 * z55,
15655
- g: x * -0.8294889695615749 + y * 1.7626640603183465 + 0.0236246858419436 * z55,
15656
- b: x * 0.0358458302437845 - y * 0.0761723892680418 + 0.9568845240076871 * z55
15702
+ r: x * 2.4934969119414263 - y * 0.9313836179191242 - 0.402710784450717 * z56,
15703
+ g: x * -0.8294889695615749 + y * 1.7626640603183465 + 0.0236246858419436 * z56,
15704
+ b: x * 0.0358458302437845 - y * 0.0761723892680418 + 0.9568845240076871 * z56
15657
15705
  },
15658
15706
  "p3"
15659
15707
  );
@@ -15688,19 +15736,19 @@ var gamma2 = (v) => {
15688
15736
  }
15689
15737
  return 16 * v;
15690
15738
  };
15691
- var convertXyz50ToProphoto = ({ x, y, z: z55, alpha }) => {
15739
+ var convertXyz50ToProphoto = ({ x, y, z: z56, alpha }) => {
15692
15740
  if (x === void 0) x = 0;
15693
15741
  if (y === void 0) y = 0;
15694
- if (z55 === void 0) z55 = 0;
15742
+ if (z56 === void 0) z56 = 0;
15695
15743
  let res = {
15696
15744
  mode: "prophoto",
15697
15745
  r: gamma2(
15698
- x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z55
15746
+ x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z56
15699
15747
  ),
15700
15748
  g: gamma2(
15701
- x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z55
15749
+ x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z56
15702
15750
  ),
15703
- b: gamma2(x * 0 + y * 0 + 1.2119675456389452 * z55)
15751
+ b: gamma2(x * 0 + y * 0 + 1.2119675456389452 * z56)
15704
15752
  };
15705
15753
  if (alpha !== void 0) {
15706
15754
  res.alpha = alpha;
@@ -15760,20 +15808,20 @@ var gamma3 = (v) => {
15760
15808
  }
15761
15809
  return 4.5 * v;
15762
15810
  };
15763
- var convertXyz65ToRec2020 = ({ x, y, z: z55, alpha }) => {
15811
+ var convertXyz65ToRec2020 = ({ x, y, z: z56, alpha }) => {
15764
15812
  if (x === void 0) x = 0;
15765
15813
  if (y === void 0) y = 0;
15766
- if (z55 === void 0) z55 = 0;
15814
+ if (z56 === void 0) z56 = 0;
15767
15815
  let res = {
15768
15816
  mode: "rec2020",
15769
15817
  r: gamma3(
15770
- x * 1.7166511879712683 - y * 0.3556707837763925 - 0.2533662813736599 * z55
15818
+ x * 1.7166511879712683 - y * 0.3556707837763925 - 0.2533662813736599 * z56
15771
15819
  ),
15772
15820
  g: gamma3(
15773
- x * -0.6666843518324893 + y * 1.6164812366349395 + 0.0157685458139111 * z55
15821
+ x * -0.6666843518324893 + y * 1.6164812366349395 + 0.0157685458139111 * z56
15774
15822
  ),
15775
15823
  b: gamma3(
15776
- x * 0.0176398574453108 - y * 0.0427706132578085 + 0.9421031212354739 * z55
15824
+ x * 0.0176398574453108 - y * 0.0427706132578085 + 0.9421031212354739 * z56
15777
15825
  )
15778
15826
  };
15779
15827
  if (alpha !== void 0) {
@@ -15926,15 +15974,15 @@ var definition_default26 = definition26;
15926
15974
 
15927
15975
  // ../../node_modules/culori/src/xyz65/convertXyz65ToXyz50.js
15928
15976
  var convertXyz65ToXyz50 = (xyz652) => {
15929
- let { x, y, z: z55, alpha } = xyz652;
15977
+ let { x, y, z: z56, alpha } = xyz652;
15930
15978
  if (x === void 0) x = 0;
15931
15979
  if (y === void 0) y = 0;
15932
- if (z55 === void 0) z55 = 0;
15980
+ if (z56 === void 0) z56 = 0;
15933
15981
  let res = {
15934
15982
  mode: "xyz50",
15935
- x: 1.0479298208405488 * x + 0.0229467933410191 * y - 0.0501922295431356 * z55,
15936
- y: 0.0296278156881593 * x + 0.990434484573249 * y - 0.0170738250293851 * z55,
15937
- z: -0.0092430581525912 * x + 0.0150551448965779 * y + 0.7518742899580008 * z55
15983
+ x: 1.0479298208405488 * x + 0.0229467933410191 * y - 0.0501922295431356 * z56,
15984
+ y: 0.0296278156881593 * x + 0.990434484573249 * y - 0.0170738250293851 * z56,
15985
+ z: -0.0092430581525912 * x + 0.0150551448965779 * y + 0.7518742899580008 * z56
15938
15986
  };
15939
15987
  if (alpha !== void 0) {
15940
15988
  res.alpha = alpha;
@@ -15945,15 +15993,15 @@ var convertXyz65ToXyz50_default = convertXyz65ToXyz50;
15945
15993
 
15946
15994
  // ../../node_modules/culori/src/xyz65/convertXyz50ToXyz65.js
15947
15995
  var convertXyz50ToXyz65 = (xyz502) => {
15948
- let { x, y, z: z55, alpha } = xyz502;
15996
+ let { x, y, z: z56, alpha } = xyz502;
15949
15997
  if (x === void 0) x = 0;
15950
15998
  if (y === void 0) y = 0;
15951
- if (z55 === void 0) z55 = 0;
15999
+ if (z56 === void 0) z56 = 0;
15952
16000
  let res = {
15953
16001
  mode: "xyz65",
15954
- x: 0.9554734527042182 * x - 0.0230985368742614 * y + 0.0632593086610217 * z55,
15955
- y: -0.0283697069632081 * x + 1.0099954580058226 * y + 0.021041398966943 * z55,
15956
- z: 0.0123140016883199 * x - 0.0205076964334779 * y + 1.3303659366080753 * z55
16002
+ x: 0.9554734527042182 * x - 0.0230985368742614 * y + 0.0632593086610217 * z56,
16003
+ y: -0.0283697069632081 * x + 1.0099954580058226 * y + 0.021041398966943 * z56,
16004
+ z: 0.0123140016883199 * x - 0.0205076964334779 * y + 1.3303659366080753 * z56
15957
16005
  };
15958
16006
  if (alpha !== void 0) {
15959
16007
  res.alpha = alpha;
@@ -16223,6 +16271,571 @@ zod.z.string().optional().nullable().transform((value) => {
16223
16271
  }
16224
16272
  );
16225
16273
 
16274
+ // ../../internal/utils/src/industry.ts
16275
+ var Industry = {
16276
+ // Finance
16277
+ BANKING: "banking",
16278
+ FINANCIAL_SERVICES: "financial_services",
16279
+ FINTECH: "fintech",
16280
+ PAYMENTS: "payments"};
16281
+
16282
+ // ../../internal/validation/src/dark-web/templates.ts
16283
+ var BRAND = { kind: "brand" };
16284
+ var lit = (value) => ({ kind: "literal", value });
16285
+ var phrase = (...tokens) => ({ type: "phrase", tokens });
16286
+ var bn = (slop, ...words) => ({
16287
+ type: "phrase",
16288
+ tokens: [BRAND, ...words.map(lit)],
16289
+ slop
16290
+ });
16291
+ var nb = (slop, ...words) => ({
16292
+ type: "phrase",
16293
+ tokens: [...words.map(lit), BRAND],
16294
+ slop
16295
+ });
16296
+ var word = (value) => ({ type: "term", value, match: "word" });
16297
+ var prefix = (value) => ({
16298
+ type: "term",
16299
+ value,
16300
+ match: "prefix"
16301
+ });
16302
+ var or = (...children) => ({
16303
+ type: "group",
16304
+ op: "OR",
16305
+ children
16306
+ });
16307
+ var and = (...children) => ({
16308
+ type: "group",
16309
+ op: "AND",
16310
+ children
16311
+ });
16312
+ var notOneOf = (...children) => ({
16313
+ type: "group",
16314
+ op: "OR",
16315
+ children,
16316
+ negated: true
16317
+ });
16318
+ var brandWith = (...values) => and(phrase(BRAND), or(...values.map(word)));
16319
+ var SCAN_TEMPLATES = [
16320
+ {
16321
+ id: "p2p-instant-transfer",
16322
+ category: "payment-fraud",
16323
+ title: "P2P and instant transfer abuse",
16324
+ 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.",
16325
+ // Source rows: 1, 55. The original ("[brand]"~3) was proximity on one
16326
+ // position, a no-op; dropped rather than ported.
16327
+ query: and(
16328
+ or(
16329
+ phrase(BRAND, lit("to"), BRAND),
16330
+ bn(2, "instant"),
16331
+ bn(2, "anyone"),
16332
+ bn(1, "pay"),
16333
+ bn(3, "pay anyone"),
16334
+ bn(2, "p2p"),
16335
+ bn(3, "instant transfer"),
16336
+ bn(3, "receive from anyone"),
16337
+ bn(4, "phone number"),
16338
+ bn(2, "member to member"),
16339
+ nb(3, "send")
16340
+ ),
16341
+ notOneOf(word("rate"), word("price"))
16342
+ )
16343
+ },
16344
+ {
16345
+ id: "transfers-ach-direct-debit",
16346
+ category: "payment-fraud",
16347
+ title: "Transfers, ACH and direct debit",
16348
+ description: "Discussion of pushing or pulling funds via ACH, direct debit or bill pay, including chatter about pending and settlement timing.",
16349
+ // Source rows: 6, 8, 18, 41. Row 18 was missing an OR before "Direct Debit".
16350
+ query: or(
16351
+ bn(1, "transfer"),
16352
+ nb(1, "transfer"),
16353
+ bn(5, "ach"),
16354
+ nb(4, "pull"),
16355
+ nb(4, "push"),
16356
+ bn(4, "pending"),
16357
+ bn(4, "settle"),
16358
+ nb(4, "link"),
16359
+ brandWith("billpay", "acctverify"),
16360
+ and(phrase(BRAND), or(phrase(lit("direct debit")), phrase(lit("direct deposit"))))
16361
+ )
16362
+ },
16363
+ {
16364
+ id: "wallet-linking",
16365
+ category: "payment-fraud",
16366
+ title: "Wallet linking and instant funding",
16367
+ description: "Linking the brand to mobile wallets for instant funding, and 'linkable' account trading where a name match is being sold.",
16368
+ // Source rows: 19, 44, 51
16369
+ query: and(
16370
+ or(
16371
+ bn(5, "apple pay"),
16372
+ bn(5, "apple"),
16373
+ bn(3, "apple linkable"),
16374
+ bn(2, "linkable"),
16375
+ bn(2, "linkables"),
16376
+ nb(2, "linkable"),
16377
+ nb(2, "link"),
16378
+ and(phrase(BRAND), phrase(lit("name match")))
16379
+ ),
16380
+ notOneOf(word("espn"), word("airtag"))
16381
+ )
16382
+ },
16383
+ {
16384
+ id: "card-data-exposure",
16385
+ category: "payment-fraud",
16386
+ title: "Card data and virtual cards",
16387
+ description: "Brand-issued card details being traded: expiry, CVV, virtual card numbers and card activation.",
16388
+ // Source rows: 43
16389
+ query: and(
16390
+ brandWith("exp", "cvv", "vcc", "debit"),
16391
+ notOneOf(word("checking"), word("limits"))
16392
+ )
16393
+ },
16394
+ {
16395
+ id: "card-loading",
16396
+ category: "payment-fraud",
16397
+ title: "Card and account loading",
16398
+ description: "'Loading' services that push stolen funds onto brand accounts or cards for a cut.",
16399
+ // Source rows: 42
16400
+ query: or(
16401
+ nb(1, "loading"),
16402
+ nb(1, "load"),
16403
+ bn(1, "loads"),
16404
+ bn(1, "loading"),
16405
+ bn(3, "drop"),
16406
+ bn(2, "cash"),
16407
+ and(
16408
+ phrase(BRAND),
16409
+ or(
16410
+ phrase(lit("loading method")),
16411
+ phrase(lit("loading guide")),
16412
+ phrase(lit("loading tut")),
16413
+ phrase(lit("loading tutorial"))
16414
+ )
16415
+ )
16416
+ )
16417
+ },
16418
+ {
16419
+ id: "cross-platform-cashout",
16420
+ category: "payment-fraud",
16421
+ title: "Cross-platform cash-out",
16422
+ description: "Moving funds from the brand into other consumer payment apps to break the trail.",
16423
+ // Source rows: 56
16424
+ query: and(
16425
+ phrase(BRAND),
16426
+ or(
16427
+ phrase(lit("cash app")),
16428
+ word("venmo"),
16429
+ phrase(lit("transfer to paypal")),
16430
+ phrase(lit("visa money transfer"))
16431
+ )
16432
+ )
16433
+ },
16434
+ {
16435
+ id: "crypto-offramp",
16436
+ category: "payment-fraud",
16437
+ title: "Crypto off-ramp",
16438
+ description: "Converting funds held at the brand into cryptocurrency through exchanges and P2P markets.",
16439
+ // Source rows: 63
16440
+ query: and(
16441
+ phrase(BRAND),
16442
+ or(
16443
+ word("crypto"),
16444
+ word("moonpay"),
16445
+ word("switchere"),
16446
+ word("kraken"),
16447
+ word("paxful"),
16448
+ word("noones"),
16449
+ word("coinomi"),
16450
+ word("coinzoom"),
16451
+ word("bitcoin"),
16452
+ word("btc")
16453
+ )
16454
+ )
16455
+ },
16456
+ {
16457
+ id: "mobile-check-deposit",
16458
+ category: "deposit-fraud",
16459
+ title: "Mobile check deposit fraud",
16460
+ description: "Check fraud against mobile deposit, traded under slang including 'glass', 'MCD', 'slips' and 'persy'.",
16461
+ // Source rows: 2, 13, 35, 46
16462
+ industries: [
16463
+ Industry.BANKING,
16464
+ Industry.FINANCIAL_SERVICES,
16465
+ Industry.FINTECH,
16466
+ Industry.PAYMENTS
16467
+ ],
16468
+ query: or(
16469
+ bn(5, "checks"),
16470
+ bn(5, "check"),
16471
+ bn(5, "mobile deposit"),
16472
+ nb(5, "mobile deposit"),
16473
+ bn(5, "slip"),
16474
+ bn(5, "slips"),
16475
+ bn(5, "glass"),
16476
+ bn(5, "md"),
16477
+ bn(5, "mcd"),
16478
+ bn(5, "treasury"),
16479
+ nb(5, "treasury"),
16480
+ bn(5, "persy"),
16481
+ bn(5, "deposit limit"),
16482
+ and(phrase(BRAND), or(prefix("stimm"), word("mcd"), phrase(lit("pop on"))))
16483
+ )
16484
+ },
16485
+ {
16486
+ id: "atm-abuse",
16487
+ category: "deposit-fraud",
16488
+ title: "ATM abuse and 'box work'",
16489
+ description: "ATM deposit and withdrawal manipulation, including dispute-driven 'box work' against cash machines.",
16490
+ // Source rows: 9, 47, 57, 70
16491
+ industries: [
16492
+ Industry.BANKING,
16493
+ Industry.FINANCIAL_SERVICES,
16494
+ Industry.FINTECH,
16495
+ Industry.PAYMENTS
16496
+ ],
16497
+ query: or(
16498
+ bn(2, "atm"),
16499
+ bn(2, "withdrawal"),
16500
+ and(phrase(BRAND), phrase(lit("box work"))),
16501
+ and(
16502
+ phrase(BRAND),
16503
+ or(
16504
+ phrase(lit("atm deposit")),
16505
+ phrase(lit("atm withdrawal")),
16506
+ phrase(lit("atm withdraw")),
16507
+ phrase(lit("atm limit")),
16508
+ phrase(lit("atm card")),
16509
+ phrase(lit("cash withdrawal fee"))
16510
+ )
16511
+ )
16512
+ )
16513
+ },
16514
+ {
16515
+ id: "retail-cashout-network",
16516
+ category: "deposit-fraud",
16517
+ title: "Retail cash-out network",
16518
+ description: "Cash-out through retail and ATM partner networks, where funds are pulled at a storefront rather than a branch.",
16519
+ // Source rows: 30
16520
+ industries: [
16521
+ Industry.BANKING,
16522
+ Industry.FINANCIAL_SERVICES,
16523
+ Industry.FINTECH,
16524
+ Industry.PAYMENTS
16525
+ ],
16526
+ query: or(
16527
+ bn(5, "allpoint"),
16528
+ bn(5, "walgreens"),
16529
+ bn(5, "cvs"),
16530
+ bn(5, "7-eleven"),
16531
+ bn(5, "7eleven"),
16532
+ bn(5, "711"),
16533
+ bn(5, "circle k"),
16534
+ bn(5, "target"),
16535
+ bn(5, "visa plus alliance"),
16536
+ bn(3, "moneypass"),
16537
+ bn(3, "vanilladirect"),
16538
+ bn(3, "vanilla"),
16539
+ bn(3, "dollar general"),
16540
+ bn(3, "dollar tree"),
16541
+ bn(3, "safeway"),
16542
+ bn(3, "walmart"),
16543
+ bn(3, "speedway")
16544
+ )
16545
+ },
16546
+ {
16547
+ id: "otp-bots",
16548
+ category: "account-takeover",
16549
+ title: "OTP bots and 2FA bypass",
16550
+ description: "Automated one-time-passcode interception services targeting the brand's login and step-up flows.",
16551
+ // Source rows: 34
16552
+ query: or(
16553
+ bn(2, "otp"),
16554
+ nb(1, "otp"),
16555
+ phrase(BRAND, lit("otp bot")),
16556
+ bn(2, "2fa"),
16557
+ bn(2, "code"),
16558
+ bn(2, "bypass"),
16559
+ bn(2, "bot"),
16560
+ bn(2, "bots")
16561
+ )
16562
+ },
16563
+ {
16564
+ id: "remote-access-tooling",
16565
+ category: "account-takeover",
16566
+ title: "Remote-access tooling",
16567
+ description: "Legitimate remote-management tools named alongside the brand, the standard toolkit for support-impersonation account takeover.",
16568
+ // Source rows: 29, 64. Truncated by the export; recoverable portion only.
16569
+ query: and(
16570
+ phrase(BRAND),
16571
+ or(
16572
+ word("action1"),
16573
+ phrase(lit("ammy admin")),
16574
+ word("ammyadmin"),
16575
+ word("anydesk"),
16576
+ phrase(lit("any desk")),
16577
+ word("atera"),
16578
+ word("beanywhere"),
16579
+ phrase(lit("chrome remote desktop")),
16580
+ word("connectwise"),
16581
+ word("screenconnect"),
16582
+ word("dameware"),
16583
+ word("domotz"),
16584
+ word("dwservice"),
16585
+ word("fleetdeck"),
16586
+ word("intelliadmin"),
16587
+ phrase(lit("itarian endpoint manager")),
16588
+ phrase(lit("level.io")),
16589
+ word("meshcentral"),
16590
+ word("mremoteng"),
16591
+ phrase(lit("n-able")),
16592
+ word("ngrok"),
16593
+ phrase(lit("pdq deploy")),
16594
+ word("pulseway"),
16595
+ word("realvnc"),
16596
+ phrase(lit("remote utilities")),
16597
+ word("rport")
16598
+ )
16599
+ )
16600
+ },
16601
+ {
16602
+ id: "antidetect-kyc-evasion",
16603
+ category: "account-takeover",
16604
+ title: "Anti-detect and KYC evasion tooling",
16605
+ description: "Fingerprint spoofing, residential proxies and emulators used to defeat the brand's device and identity checks.",
16606
+ // Source row: 40. The original filtered to Telegram OR Dread; DarkOwl's
16607
+ // `source` takes one value, so precision comes from the tooling terms.
16608
+ query: and(
16609
+ phrase(BRAND),
16610
+ or(
16611
+ word("tlo"),
16612
+ word("scamalytics"),
16613
+ word("burner"),
16614
+ prefix("prox"),
16615
+ word("vpn"),
16616
+ word("vps"),
16617
+ word("antidetect"),
16618
+ phrase(lit("anti-detect")),
16619
+ prefix("emulat")
16620
+ )
16621
+ )
16622
+ },
16623
+ {
16624
+ id: "brand-domains-sso",
16625
+ category: "account-takeover",
16626
+ title: "Brand domains and SSO endpoints",
16627
+ description: "The brand's own domains and identity-provider endpoints appearing in credential and access chatter.",
16628
+ // Source row: 31, as proximity not literal hostnames — the index tokenizes
16629
+ // `chime.okta.com`, so a glued literal would never match. Row 23's
16630
+ // "[brand] pass*"~1 is omitted: no wildcards inside a phrase.
16631
+ query: and(
16632
+ or(bn(2, "okta"), bn(2, "login"), bn(2, "portal"), bn(1, "bank")),
16633
+ notOneOf(word("zendesk"))
16634
+ )
16635
+ },
16636
+ {
16637
+ id: "account-opening-abuse",
16638
+ category: "onboarding-abuse",
16639
+ title: "Account opening and self-registration",
16640
+ description: "Bulk or fraudulent account creation against the brand, including 'self-reg' and 'drop' accounts opened on stolen identities.",
16641
+ // Source rows: 5, 17, 54
16642
+ query: or(
16643
+ bn(5, "enroll"),
16644
+ nb(5, "enroll"),
16645
+ bn(5, "open"),
16646
+ nb(5, "open"),
16647
+ bn(5, "drop"),
16648
+ nb(5, "drop"),
16649
+ nb(5, "make"),
16650
+ nb(5, "create"),
16651
+ nb(5, "fresh"),
16652
+ nb(5, "register"),
16653
+ bn(5, "self-reg"),
16654
+ bn(5, "selfreg"),
16655
+ bn(5, "self-registered"),
16656
+ bn(5, "self register"),
16657
+ bn(1, "fullz")
16658
+ )
16659
+ },
16660
+ {
16661
+ id: "identity-documents",
16662
+ category: "onboarding-abuse",
16663
+ title: "Identity documents and fullz",
16664
+ 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.",
16665
+ // Source row: 15. Lexicon-only, so the renderer AND-s the anchor on.
16666
+ query: or(
16667
+ word("fullz"),
16668
+ phrase(lit("get pros")),
16669
+ phrase(lit("driver's license")),
16670
+ phrase(lit("tlo bot")),
16671
+ phrase(lit("tlo plug")),
16672
+ phrase(lit("need dl")),
16673
+ phrase(lit("get id"))
16674
+ )
16675
+ },
16676
+ {
16677
+ id: "referral-bonus-abuse",
16678
+ category: "onboarding-abuse",
16679
+ title: "Referral and bonus abuse",
16680
+ description: "Methods for farming the brand's referral bonuses and promotional offers, often paired with fake direct deposits.",
16681
+ // Source rows: 48
16682
+ query: and(
16683
+ or(bn(3, "referral"), bn(3, "bonus"), bn(3, "promotion"), bn(3, "offer")),
16684
+ or(
16685
+ word("bypass"),
16686
+ word("dd"),
16687
+ phrase(lit("direct deposit")),
16688
+ phrase(lit("work around")),
16689
+ word("trick"),
16690
+ word("method"),
16691
+ word("glitch"),
16692
+ word("tutorial"),
16693
+ word("tut"),
16694
+ word("wave"),
16695
+ word("sauce")
16696
+ )
16697
+ )
16698
+ },
16699
+ {
16700
+ id: "insider-recruitment",
16701
+ category: "insider-threat",
16702
+ title: "Insider recruitment",
16703
+ description: "Actors seeking or advertising an employee on the inside ('inny'), the highest-severity signal in this catalog.",
16704
+ // Source rows: 7, 38
16705
+ query: and(
16706
+ or(
16707
+ bn(4, "inny"),
16708
+ bn(4, "insider"),
16709
+ and(
16710
+ phrase(BRAND),
16711
+ or(
16712
+ word("insider"),
16713
+ word("inny"),
16714
+ phrase(lit("in office")),
16715
+ word("employee"),
16716
+ phrase(lit("i work at")),
16717
+ phrase(lit("i am an employee")),
16718
+ phrase(lit("i can get access")),
16719
+ phrase(lit("i have access to")),
16720
+ phrase(lit("employed at")),
16721
+ word("occupation")
16722
+ )
16723
+ )
16724
+ ),
16725
+ notOneOf(phrase(lit("welcome to insider chat")))
16726
+ )
16727
+ },
16728
+ {
16729
+ id: "mule-crew-recruitment",
16730
+ category: "insider-threat",
16731
+ title: "Mule and cash-out crew recruitment",
16732
+ description: "Recruitment of account holders to receive and forward funds, priced as a revenue split ('50/50', '60/40').",
16733
+ // Source rows: 39
16734
+ query: or(
16735
+ bn(5, "cl"),
16736
+ bn(5, "mule"),
16737
+ bn(5, "tap in"),
16738
+ bn(5, "50/50"),
16739
+ bn(5, "60/40"),
16740
+ bn(5, "striker")
16741
+ )
16742
+ },
16743
+ {
16744
+ id: "methods-and-tutorials",
16745
+ category: "tradecraft",
16746
+ title: "Methods, 'sauce' and tutorials",
16747
+ description: "Fraud methods being taught or sold against the brand, under the usual slang: sauce, glitch, tut, wave, motion, tap in.",
16748
+ // Source rows: 4, 21, 59
16749
+ query: or(
16750
+ bn(3, "sauce"),
16751
+ bn(3, "method"),
16752
+ bn(3, "guide"),
16753
+ bn(3, "tut"),
16754
+ bn(3, "tutorial"),
16755
+ bn(4, "hack"),
16756
+ bn(4, "glitch"),
16757
+ bn(4, "wave"),
16758
+ bn(4, "motion"),
16759
+ bn(4, "walkthrough"),
16760
+ bn(4, "walk through"),
16761
+ bn(2, "tap in"),
16762
+ bn(2, "tapin"),
16763
+ nb(2, "tapn")
16764
+ )
16765
+ },
16766
+ {
16767
+ id: "hack-leak-chatter",
16768
+ category: "tradecraft",
16769
+ title: "Hack and leak chatter",
16770
+ description: "Claims of having hacked, breached or leaked the brand, whether credible or not.",
16771
+ // Source rows: 28
16772
+ query: or(
16773
+ bn(4, "hack"),
16774
+ bn(4, "glitch"),
16775
+ nb(4, "hacking"),
16776
+ bn(4, "leak"),
16777
+ bn(4, "leaked")
16778
+ )
16779
+ },
16780
+ {
16781
+ id: "support-impersonation",
16782
+ category: "brand-abuse",
16783
+ title: "Support impersonation",
16784
+ description: "Actors impersonating the brand's support or service staff to social-engineer customers.",
16785
+ // Source rows: 36
16786
+ query: or(
16787
+ bn(1, "agent"),
16788
+ bn(1, "support"),
16789
+ bn(1, "service"),
16790
+ bn(1, "customer"),
16791
+ nb(1, "impersonate"),
16792
+ bn(1, "impersonation"),
16793
+ bn(3, "scam"),
16794
+ nb(1, "scam")
16795
+ )
16796
+ },
16797
+ {
16798
+ id: "social-impersonation",
16799
+ category: "brand-abuse",
16800
+ title: "Social account impersonation",
16801
+ description: "The brand discussed alongside social platforms, where fake support and giveaway accounts are staged.",
16802
+ // Source rows: 25
16803
+ query: or(
16804
+ bn(5, "instagram"),
16805
+ bn(5, "insta"),
16806
+ bn(5, "facebook"),
16807
+ bn(5, "twitter"),
16808
+ bn(5, "tiktok")
16809
+ )
16810
+ },
16811
+ {
16812
+ id: "vendor-supply-chain",
16813
+ category: "data-exposure",
16814
+ title: "Vendor and BPO supply chain",
16815
+ description: "Outsourced support and processing vendors named alongside the brand, where a third-party breach exposes brand customer data.",
16816
+ // Source row: 60, truncated by the export. Generic BPO/CX providers; a
16817
+ // per-org vendor list would be materially better.
16818
+ query: and(
16819
+ phrase(BRAND),
16820
+ or(
16821
+ word("zendesk"),
16822
+ word("teleperformance"),
16823
+ word("concentrix"),
16824
+ word("taskus"),
16825
+ word("genpact"),
16826
+ word("ubiquity"),
16827
+ word("hioperator"),
16828
+ word("galileo"),
16829
+ word("fiserv"),
16830
+ phrase(lit("etech global"))
16831
+ )
16832
+ )
16833
+ }
16834
+ ];
16835
+ new Map(
16836
+ SCAN_TEMPLATES.map((template) => [template.id, template])
16837
+ );
16838
+
16226
16839
  // src/client.ts
16227
16840
  function trimTrailingSlashes(url) {
16228
16841
  return url.replace(/\/+$/, "");