@chainpatrol/sdk 1.5.0 → 1.7.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 z50 = void 0;
1316
+ let z54 = 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
- z50 = offsetZ;
1323
+ z54 = offsetZ;
1324
1324
  this.dt = dt;
1325
1325
  } else {
1326
- z50 = "UTC";
1326
+ z54 = "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
- z50 = dt.zone.name;
1334
+ z54 = dt.zone.name;
1335
1335
  } else {
1336
- z50 = "UTC";
1336
+ z54 = "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 || z50;
1341
+ intlOpts.timeZone = intlOpts.timeZone || z54;
1342
1342
  this.dtf = getCachedDTF(intl, intlOpts);
1343
1343
  }
1344
1344
  format() {
@@ -7058,7 +7058,8 @@ function friendlyDateTime(dateTimeish) {
7058
7058
  // ../../internal/database/src/generated/prisma/enums.ts
7059
7059
  var BrandType = {
7060
7060
  INDIVIDUAL: "INDIVIDUAL",
7061
- ORGANIZATION: "ORGANIZATION"
7061
+ ORGANIZATION: "ORGANIZATION",
7062
+ PRODUCT: "PRODUCT"
7062
7063
  };
7063
7064
  var SubscriptionStatus = {
7064
7065
  POC: "POC",
@@ -7172,7 +7173,8 @@ var AssetType = {
7172
7173
  ARCHIVE_ORG: "ARCHIVE_ORG",
7173
7174
  FIVE_HUNDRED_PX: "FIVE_HUNDRED_PX",
7174
7175
  LUMA: "LUMA",
7175
- SMARTMONEYMATCH: "SMARTMONEYMATCH"
7176
+ SMARTMONEYMATCH: "SMARTMONEYMATCH",
7177
+ APK_GOLD: "APK_GOLD"
7176
7178
  };
7177
7179
  var LivenessStatus = {
7178
7180
  UNKNOWN: "UNKNOWN",
@@ -7462,856 +7464,69 @@ zod.z.object({
7462
7464
  zod.z.object({
7463
7465
  result: zod.z.string()
7464
7466
  });
7465
- zod.z.object({
7466
- slug: zod.z.string().min(1),
7467
- configId: zod.z.number().int().positive(),
7468
- status: zod.z.nativeEnum(ThreatDetectionConfigStatus).optional(),
7469
- title: zod.z.string().trim().optional(),
7470
- description: zod.z.string().trim().nullable().optional(),
7471
- cron: zod.z.string().trim().nullable().optional(),
7472
- config: zod.z.record(zod.z.unknown()).optional(),
7473
- mergeConfig: zod.z.boolean().default(false),
7474
- brandId: zod.z.number().int().positive().nullable().optional().describe(
7475
- "Optional brand connection for this detection config. Pass null to clear the link. Only valid for org-scoped configs; the brand must belong to the same organization."
7476
- )
7477
- });
7478
- zod.z.object({
7479
- config: zod.z.object({
7480
- id: zod.z.number(),
7481
- source: zod.z.string(),
7482
- status: zod.z.nativeEnum(ThreatDetectionConfigStatus),
7483
- title: zod.z.string(),
7484
- description: zod.z.string().nullable(),
7485
- cron: zod.z.string().nullable(),
7486
- config: zod.z.record(zod.z.unknown()),
7487
- updatedAt: zod.z.date(),
7488
- brandId: zod.z.number().nullable()
7489
- })
7490
- });
7491
- zod.z.object({
7492
- slug: zod.z.string().min(1),
7493
- source: zod.z.string().optional(),
7494
- minResults: zod.z.number().int().min(0).default(1),
7495
- lookbackHours: zod.z.number().int().min(1).default(24 * 7),
7496
- runBeforeValidate: zod.z.boolean().default(false),
7497
- includeDisabled: zod.z.boolean().default(false)
7498
- });
7499
- zod.z.object({
7500
- ok: zod.z.boolean(),
7501
- summary: zod.z.object({
7502
- checkedConfigs: zod.z.number(),
7503
- passingConfigs: zod.z.number(),
7504
- failingConfigs: zod.z.number(),
7505
- lookbackHours: zod.z.number(),
7506
- minResults: zod.z.number()
7507
- }),
7508
- validations: zod.z.array(
7509
- zod.z.object({
7510
- configId: zod.z.number(),
7511
- source: zod.z.string(),
7512
- status: zod.z.nativeEnum(ThreatDetectionConfigStatus),
7513
- ran: zod.z.boolean(),
7514
- runOk: zod.z.boolean(),
7515
- runMessage: zod.z.string().nullable(),
7516
- recentResultCount: zod.z.number(),
7517
- valid: zod.z.boolean()
7518
- })
7519
- )
7520
- });
7521
- zod.z.object({
7522
- slug: zod.z.string().min(1),
7523
- configId: zod.z.number().int().positive().optional(),
7524
- source: zod.z.string().min(1).optional(),
7525
- includeDisabled: zod.z.boolean().default(false)
7526
- });
7527
- zod.z.object({
7528
- ranCount: zod.z.number(),
7529
- successCount: zod.z.number(),
7530
- failedCount: zod.z.number(),
7531
- results: zod.z.array(
7532
- zod.z.object({
7533
- configId: zod.z.number(),
7534
- source: zod.z.string(),
7535
- ok: zod.z.boolean(),
7536
- message: zod.z.string().nullable(),
7537
- assetsCount: zod.z.number()
7538
- })
7539
- )
7540
- });
7541
- var DetectionDriftThresholdsSchema = zod.z.object({
7542
- zeroResultsMaxHours: zod.z.number().int().positive().default(72),
7543
- noisyResultsPerDay: zod.z.number().positive().default(100),
7544
- noisyAllowedRatioThreshold: zod.z.number().min(0).max(1).default(0.6),
7545
- staleConfigDays: zod.z.number().int().positive().default(30)
7546
- });
7547
- zod.z.object({
7548
- slug: zod.z.string().min(1),
7549
- lookbackHours: zod.z.number().int().positive().default(168),
7550
- startDate: zod.z.date().optional(),
7551
- endDate: zod.z.date().optional(),
7552
- source: zod.z.string().min(1).optional(),
7553
- configIds: zod.z.array(zod.z.number().int().positive()).optional(),
7554
- includeDisabled: zod.z.boolean().default(false),
7555
- thresholds: DetectionDriftThresholdsSchema.optional()
7556
- }).refine(
7557
- (value) => !value.startDate && !value.endDate || Boolean(value.startDate) && Boolean(value.endDate),
7558
- {
7559
- message: "Provide both startDate and endDate when using explicit date range",
7560
- path: ["startDate"]
7561
- }
7562
- );
7563
- var DetectionDriftSignalSchema = zod.z.object({
7564
- signal: zod.z.enum(["zero_results_too_long", "noisy_source", "stale_query"]),
7565
- configId: zod.z.number().int().positive(),
7566
- source: zod.z.string(),
7567
- title: zod.z.string().nullable(),
7568
- status: zod.z.string(),
7569
- severity: zod.z.enum(["low", "medium", "high"]),
7570
- details: zod.z.record(zod.z.unknown())
7571
- });
7572
- zod.z.object({
7573
- ok: zod.z.boolean(),
7574
- range: zod.z.object({
7575
- startDate: zod.z.date(),
7576
- endDate: zod.z.date(),
7577
- lookbackHours: zod.z.number().int().positive()
7578
- }),
7579
- thresholds: DetectionDriftThresholdsSchema,
7580
- summary: zod.z.object({
7581
- checkedConfigs: zod.z.number().int().nonnegative(),
7582
- signalCount: zod.z.number().int().nonnegative(),
7583
- zeroResultsCount: zod.z.number().int().nonnegative(),
7584
- noisyCount: zod.z.number().int().nonnegative(),
7585
- staleCount: zod.z.number().int().nonnegative()
7586
- }),
7587
- signals: zod.z.array(DetectionDriftSignalSchema)
7588
- });
7589
- var BucketsSchema = zod.z.object({
7590
- lt24h: zod.z.number().int().nonnegative(),
7591
- h24to72: zod.z.number().int().nonnegative(),
7592
- h72to168: zod.z.number().int().nonnegative(),
7593
- gte168h: zod.z.number().int().nonnegative()
7594
- });
7595
- zod.z.object({
7596
- slug: zod.z.string().min(1).optional(),
7597
- all: zod.z.boolean().default(false),
7598
- windowHours: zod.z.number().int().positive().default(168)
7599
- });
7600
- zod.z.object({
7601
- generatedAt: zod.z.date(),
7602
- scope: zod.z.object({
7603
- slug: zod.z.string().nullable(),
7604
- all: zod.z.boolean()
7605
- }),
7606
- reviewQueue: zod.z.object({
7607
- totalPendingProposals: zod.z.number().int().nonnegative(),
7608
- distinctReports: zod.z.number().int().nonnegative(),
7609
- ageBuckets: BucketsSchema,
7610
- slaBuckets: zod.z.object({
7611
- breached: zod.z.number().int().nonnegative(),
7612
- dueWithin24h: zod.z.number().int().nonnegative(),
7613
- dueWithin72h: zod.z.number().int().nonnegative(),
7614
- beyond72h: zod.z.number().int().nonnegative(),
7615
- missingSla: zod.z.number().int().nonnegative()
7616
- }),
7617
- byOrg: zod.z.array(
7618
- zod.z.object({
7619
- slug: zod.z.string(),
7620
- pendingProposals: zod.z.number().int().nonnegative()
7621
- })
7622
- )
7623
- }),
7624
- takedownQueue: zod.z.object({
7625
- totalOpen: zod.z.number().int().nonnegative(),
7626
- statusCounts: zod.z.object({
7627
- todo: zod.z.number().int().nonnegative(),
7628
- inProgress: zod.z.number().int().nonnegative(),
7629
- pendingInput: zod.z.number().int().nonnegative()
7630
- }),
7631
- ageBuckets: BucketsSchema,
7632
- staleInProgress: zod.z.number().int().nonnegative(),
7633
- byOrg: zod.z.array(
7634
- zod.z.object({
7635
- slug: zod.z.string(),
7636
- openTakedowns: zod.z.number().int().nonnegative()
7637
- })
7638
- )
7639
- })
7640
- });
7641
- var HealthcheckCategorySchema = zod.z.enum([
7642
- "detection",
7643
- "reviewing",
7644
- "blocklisting",
7645
- "takedowns",
7646
- "assets",
7647
- "organization"
7648
- ]);
7649
- var HealthcheckSeveritySchema = zod.z.enum(["ok", "warn", "fail"]);
7650
- var HealthcheckFindingSchema = zod.z.object({
7651
- kind: zod.z.string(),
7652
- ref: zod.z.string().nullable(),
7653
- message: zod.z.string(),
7654
- severity: zod.z.enum(["warn", "fail"])
7655
- });
7656
- zod.z.object({
7657
- id: zod.z.string(),
7658
- title: zod.z.string(),
7659
- category: HealthcheckCategorySchema,
7660
- generatedAt: zod.z.date(),
7661
- scope: zod.z.object({
7662
- slug: zod.z.string().nullable()
7663
- }),
7664
- ok: zod.z.boolean(),
7665
- severity: HealthcheckSeveritySchema,
7666
- observed: zod.z.record(zod.z.union([zod.z.number(), zod.z.string(), zod.z.boolean()]).nullable()),
7667
- threshold: zod.z.record(zod.z.union([zod.z.number(), zod.z.string(), zod.z.boolean()]).nullable()),
7668
- findings: zod.z.array(HealthcheckFindingSchema),
7669
- suggestedAction: zod.z.string().nullable(),
7670
- appUrl: zod.z.string().nullable()
7671
- });
7672
-
7673
- // ../../internal/validation/src/public/healthchecks/assets-dead-asset-spike.ts
7674
- zod.z.object({
7675
- slug: zod.z.string().min(1),
7676
- windowHours: zod.z.number().int().positive().default(24),
7677
- baselineDays: zod.z.number().int().positive().default(7),
7678
- warnMultiplier: zod.z.number().positive().default(2),
7679
- failMultiplier: zod.z.number().positive().default(4),
7680
- minSpikeCount: zod.z.number().int().min(1).default(10)
7681
- });
7682
- zod.z.object({});
7683
- var HealthcheckRegistryEntrySchema = zod.z.object({
7684
- id: zod.z.string(),
7685
- title: zod.z.string(),
7686
- description: zod.z.string(),
7687
- category: HealthcheckCategorySchema,
7688
- implemented: zod.z.boolean(),
7689
- endpoint: zod.z.string().nullable(),
7690
- defaultThreshold: zod.z.record(zod.z.union([zod.z.number(), zod.z.string()])).optional(),
7691
- notImplementedReason: zod.z.string().optional()
7692
- });
7693
- zod.z.object({
7694
- checks: zod.z.array(HealthcheckRegistryEntrySchema)
7695
- });
7696
- zod.z.object({
7697
- slug: zod.z.string().min(1)
7698
- });
7699
- zod.z.object({
7700
- slug: zod.z.string().min(1),
7701
- warnThreshold: zod.z.number().int().nonnegative().default(50),
7702
- failThreshold: zod.z.number().int().nonnegative().default(100)
7703
- });
7704
- zod.z.object({
7705
- slug: zod.z.string().min(1),
7706
- warnAgeHours: zod.z.number().int().positive().default(24 * 7),
7707
- failAgeHours: zod.z.number().int().positive().default(24 * 14)
7708
- });
7709
- zod.z.object({
7710
- slug: zod.z.string().min(1),
7711
- warnAgeHours: zod.z.number().int().nonnegative().default(24 * 30),
7712
- failAgeHours: zod.z.number().int().nonnegative().default(24 * 60)
7713
- });
7714
- zod.z.object({
7715
- slug: zod.z.string().min(1),
7716
- lookbackHours: zod.z.number().int().positive().default(24 * 7),
7717
- warnThreshold: zod.z.number().int().nonnegative().default(3),
7718
- failThreshold: zod.z.number().int().nonnegative().default(10)
7719
- });
7720
- zod.z.object({
7721
- slug: zod.z.string().min(1),
7722
- warnThreshold: zod.z.number().int().nonnegative().default(30),
7723
- failThreshold: zod.z.number().int().nonnegative().default(75)
7724
- });
7725
- zod.z.object({
7726
- slug: zod.z.string().min(1),
7727
- staleThresholdHours: zod.z.number().int().positive().default(24 * 7),
7728
- warnThreshold: zod.z.number().int().nonnegative().default(1),
7729
- failThreshold: zod.z.number().int().nonnegative().default(5)
7730
- });
7731
- zod.z.object({
7732
- slug: zod.z.string().min(1),
7733
- warnThreshold: zod.z.number().int().nonnegative().default(50),
7734
- failThreshold: zod.z.number().int().nonnegative().default(100)
7735
- });
7736
- var BreakdownBySchema = zod.z.enum(["day", "type", "brand"]);
7737
- zod.z.object({
7738
- slug: zod.z.string().min(1),
7739
- by: BreakdownBySchema,
7740
- startDate: zod.z.date().optional(),
7741
- endDate: zod.z.date().optional(),
7742
- brandIds: zod.z.array(zod.z.number().int().positive()).optional()
7743
- });
7744
- zod.z.object({
7745
- by: BreakdownBySchema,
7746
- points: zod.z.array(
7747
- zod.z.object({
7748
- key: zod.z.string(),
7749
- count: zod.z.number(),
7750
- date: zod.z.string().optional(),
7751
- type: zod.z.string().optional(),
7752
- brandId: zod.z.number().optional(),
7753
- brandSlug: zod.z.string().optional(),
7754
- brandName: zod.z.string().optional()
7755
- })
7756
- )
7757
- });
7758
- zod.z.object({
7759
- slug: zod.z.string().min(1),
7760
- startDate: zod.z.date(),
7761
- endDate: zod.z.date(),
7762
- brandIds: zod.z.array(zod.z.number().int().positive()).optional()
7763
- });
7764
- zod.z.object({
7765
- metric: zod.z.literal("new_threats"),
7766
- found: zod.z.number(),
7767
- range: zod.z.object({
7768
- startDate: zod.z.date(),
7769
- endDate: zod.z.date()
7770
- })
7771
- });
7772
- zod.z.object({
7773
- slug: zod.z.string().min(1),
7774
- startDate: zod.z.date().optional(),
7775
- endDate: zod.z.date().optional(),
7776
- brandIds: zod.z.array(zod.z.number().int().positive()).optional()
7777
- });
7778
- zod.z.object({
7779
- metrics: zod.z.object({
7780
- reports: zod.z.number(),
7781
- newThreats: zod.z.number(),
7782
- threatsWatchlisted: zod.z.number(),
7783
- takedownsFiled: zod.z.number(),
7784
- takedownsCompleted: zod.z.number(),
7785
- domainThreats: zod.z.number(),
7786
- twitterThreats: zod.z.number(),
7787
- telegramThreats: zod.z.number(),
7788
- otherThreats: zod.z.number()
7789
- }),
7790
- blockedByDay: zod.z.array(
7791
- zod.z.object({
7792
- date: zod.z.string(),
7793
- count: zod.z.number()
7794
- })
7795
- ),
7796
- blockedByType: zod.z.array(
7797
- zod.z.object({
7798
- type: zod.z.string(),
7799
- count: zod.z.number()
7800
- })
7801
- )
7802
- });
7803
- zod.z.object({
7804
- type: zod.z.nativeEnum(AssetType).optional().describe("Filter by asset type (URL, ADDRESS, etc.)"),
7805
- groupId: zod.z.number().int().optional().describe(
7806
- "Filter by group ID. Use -1 for ungrouped assets only. Omit for all assets."
7807
- ),
7808
- query: zod.z.string().optional().describe("Search query to filter assets by content"),
7809
- per_page: zod.z.number().int().min(1).max(1e3).optional().default(100).describe("The number of assets to return per page (max 1000)"),
7810
- next_page: zod.z.string().optional().nullable().describe("Cursor for fetching the next page of results")
7811
- }).describe(
7812
- `List organization assets request body
7813
-
7814
- Returns all assets belonging to the organization associated with your API key.
7815
- Supports filtering by type, group, and search query.`
7816
- );
7817
- var organizationAssetItemSchema = zod.z.object({
7818
- id: zod.z.number().describe("Asset ID"),
7819
- content: zod.z.string().describe("Asset content (URL, address, handle, etc.)"),
7820
- type: zod.z.nativeEnum(AssetType).describe("Asset type"),
7821
- status: zod.z.nativeEnum(AssetStatus).describe("Asset status"),
7822
- name: zod.z.string().nullable().describe("Asset display name"),
7823
- description: zod.z.string().nullable().describe("Asset description"),
7824
- group: zod.z.object({
7825
- id: zod.z.number().describe("Group ID"),
7826
- name: zod.z.string().describe("Group name")
7827
- }).nullable().describe("Asset group information"),
7828
- livenessStatus: zod.z.nativeEnum(LivenessStatus).nullable().describe(
7829
- "Whether the asset is currently reachable (`ALIVE`), gone (`DEAD`), or hasn't been checked (`UNKNOWN`). `null` when liveness has never been evaluated."
7830
- ),
7831
- blockedAt: zod.z.date().nullable().describe(
7832
- "When the asset transitioned to BLOCKED status. `null` for non-blocked assets. Distinct from `updatedAt`."
7833
- ),
7834
- createdAt: zod.z.date().describe("When the asset was created"),
7835
- updatedAt: zod.z.date().describe("When the asset was last updated")
7836
- });
7837
- zod.z.object({
7838
- assets: zod.z.array(organizationAssetItemSchema).describe("List of assets"),
7839
- next_page: zod.z.string().nullable().optional().describe("Cursor for fetching the next page of results")
7840
- }).describe("Successful operation");
7841
- var addAssetItemSchema = zod.z.object({
7842
- content: zod.z.string().describe("Asset content (URL, address, handle, etc.)"),
7843
- name: zod.z.string().optional().describe("Optional display name for the asset"),
7844
- description: zod.z.string().optional().describe("Optional description for the asset"),
7845
- groupId: zod.z.number().int().positive().optional().describe("Optional group ID to assign the asset to")
7846
- });
7847
- zod.z.object({
7848
- assets: zod.z.array(addAssetItemSchema).min(1).max(1e3).describe("Array of assets to add (max 1000 per request)")
7849
- }).describe(
7850
- `Add assets to organization allowlist
7851
-
7852
- Batch add multiple assets to your organization's allowlist.
7853
- Each asset will be automatically parsed and classified.
7854
- Assets will be auto-approved as ALLOWED status.`
7855
- );
7856
- var addAssetResultSchema = zod.z.object({
7857
- content: zod.z.string().describe("Asset content"),
7858
- success: zod.z.boolean().describe("Whether the asset was added successfully"),
7859
- id: zod.z.number().optional().describe("Asset ID if successful"),
7860
- error: zod.z.string().optional().describe("Error message if failed")
7861
- });
7862
- zod.z.object({
7863
- results: zod.z.array(addAssetResultSchema).describe("Results for each asset"),
7864
- successCount: zod.z.number().describe("Number of assets successfully added"),
7865
- errorCount: zod.z.number().describe("Number of assets that failed to add")
7866
- }).describe("Batch add operation results");
7867
- zod.z.object({
7868
- assetId: zod.z.number().int().positive().describe("ID of the asset to update"),
7869
- name: zod.z.string().optional().describe("New display name for the asset"),
7870
- description: zod.z.string().nullable().optional().describe("New description for the asset"),
7871
- groupId: zod.z.number().int().positive().nullable().optional().describe("New group ID (null to ungroup)")
7872
- }).describe(
7873
- `Update an organization asset
7874
-
7875
- Update the name, description, or group assignment of an asset.`
7876
- );
7877
- zod.z.object({
7878
- id: zod.z.number().describe("Asset ID"),
7879
- content: zod.z.string().describe("Asset content"),
7880
- name: zod.z.string().nullable().describe("Asset display name"),
7881
- description: zod.z.string().nullable().describe("Asset description"),
7882
- groupId: zod.z.number().nullable().describe("Group ID")
7883
- }).describe("Updated asset");
7884
- zod.z.object({
7885
- assetId: zod.z.number().int().positive().describe("ID of the asset to remove")
7886
- }).describe(
7887
- `Remove an asset from the organization
7888
-
7889
- This removes the asset from the organization's allowlist.`
7890
- );
7891
- zod.z.object({
7892
- success: zod.z.boolean().describe("Whether the asset was removed successfully"),
7893
- id: zod.z.number().describe("Asset ID that was removed")
7894
- }).describe("Delete operation result");
7895
- zod.z.object({}).describe(
7896
- `List organization asset groups
7897
-
7898
- Returns all asset groups belonging to the organization associated with your API key.`
7899
- );
7900
- var assetGroupItemSchema = zod.z.object({
7901
- id: zod.z.number().describe("Group ID"),
7902
- name: zod.z.string().describe("Group name"),
7903
- assetCount: zod.z.number().describe("Number of assets in this group")
7904
- });
7905
- zod.z.object({
7906
- groups: zod.z.array(assetGroupItemSchema).describe("List of asset groups")
7907
- }).describe("Successful operation");
7908
- zod.z.object({
7909
- name: zod.z.string().min(1).max(255).describe("Name for the new group")
7910
- }).describe(
7911
- `Create a new asset group
7912
-
7913
- Creates a new asset group for organizing your organization's assets.`
7914
- );
7915
- zod.z.object({
7916
- id: zod.z.number().describe("Created group ID"),
7917
- name: zod.z.string().describe("Group name")
7918
- }).describe("Created group");
7919
- zod.z.object({
7920
- groupId: zod.z.number().int().positive().describe("ID of the group to update"),
7921
- name: zod.z.string().min(1).max(255).describe("New name for the group")
7922
- }).describe(
7923
- `Update an asset group
7924
-
7925
- Rename an existing asset group.`
7926
- );
7927
- zod.z.object({
7928
- id: zod.z.number().describe("Group ID"),
7929
- name: zod.z.string().describe("Updated group name")
7930
- }).describe("Updated group");
7931
- zod.z.object({
7932
- groupId: zod.z.number().int().positive().describe("ID of the group to delete")
7933
- }).describe(
7934
- `Delete an asset group
7935
-
7936
- Deletes an asset group. Assets in this group will become ungrouped.`
7937
- );
7938
- zod.z.object({
7939
- success: zod.z.boolean().describe("Whether the group was deleted successfully"),
7940
- id: zod.z.number().describe("Group ID that was deleted"),
7941
- unassignedAssetCount: zod.z.number().describe("Number of assets that were unassigned from this group")
7942
- }).describe("Delete operation result");
7943
- zod.z.object({}).describe(
7944
- `List organization brands
7945
-
7946
- Returns all brands belonging to the organization associated with your API key,
7947
- including sub-brands (\`ORGANIZATION\`) and individual / employee brands
7948
- (\`INDIVIDUAL\`). Soft-deleted brands are excluded.`
7949
- );
7950
- var brandLegalDocumentSchema = zod.z.object({
7951
- present: zod.z.boolean().describe("Whether the brand has this document attached"),
7952
- fileName: zod.z.string().nullable().describe("Original filename of the uploaded document (null when not present)"),
7953
- fileUrl: zod.z.string().nullable().describe("Direct URL to view or download the document (null when not present)")
7954
- });
7955
- var brandTrademarkRegistrationSchema = zod.z.object({
7956
- id: zod.z.number().describe("Trademark registration ID"),
7957
- brandName: zod.z.string().describe("Trademarked brand name as it appears on the registration"),
7958
- trademarkOffice: zod.z.string().describe("Issuing trademark office (e.g. `USPTO`, `EUIPO`)"),
7959
- registrationNumber: zod.z.string().describe("Registration number assigned by the office"),
7960
- goodsAndServicesClass: zod.z.string().describe("Nice Classification class(es) the registration covers"),
7961
- rightsOwnerName: zod.z.string().nullable().describe("Legal entity the trademark is registered to, if recorded"),
7962
- registrationPageUrl: zod.z.string().nullable().describe("Public URL on the trademark office's site, if recorded"),
7963
- certificateFileName: zod.z.string().nullable().describe(
7964
- "Original filename of the uploaded certificate PDF (null when no certificate is attached)"
7965
- ),
7966
- certificateFileUrl: zod.z.string().nullable().describe(
7967
- "Direct URL to view or download the certificate PDF (null when no certificate is attached)"
7968
- )
7969
- });
7970
- var brandItemSchema = zod.z.object({
7971
- id: zod.z.number().describe("Brand ID"),
7972
- slug: zod.z.string().describe("Brand slug (stable, URL-safe identifier)"),
7973
- name: zod.z.string().describe("Display name"),
7974
- type: zod.z.nativeEnum(BrandType).describe(
7975
- "Brand type: `ORGANIZATION` for parent / product brands, `INDIVIDUAL` for employee or person brands"
7976
- ),
7977
- description: zod.z.string().nullable().describe("Free-form description, if set"),
7978
- avatarUrl: zod.z.string().nullable().describe("URL of the brand's avatar / logo image"),
7979
- websiteUrl: zod.z.string().nullable().describe("Official brand website URL"),
7980
- twitterHandle: zod.z.string().nullable().describe("Official Twitter / X handle (without @)"),
7981
- brandColors: zod.z.array(zod.z.string()).describe("HEX color strings associated with the brand (e.g. `#FF0000`)"),
7982
- includedTerms: zod.z.array(zod.z.string()).describe("Terms that should be included when matching this brand"),
7983
- excludedTerms: zod.z.array(zod.z.string()).describe("Terms that should be excluded when matching this brand"),
7984
- tickers: zod.z.array(zod.z.string()).describe("Ticker symbols associated with the brand (e.g. `$JUP`)"),
7985
- brandGroupId: zod.z.number().nullable().describe("Group this brand belongs to (only set for `INDIVIDUAL` brands)"),
7986
- createdAt: zod.z.date().describe("When the brand was created"),
7987
- useOrganizationDocs: zod.z.boolean().describe(
7988
- "When true, this brand inherits its Letter of Authorization and Power of Attorney from the organization rather than carrying its own. The `legalDocuments` block below always reflects the brand-level attachments \u2014 read `/user/orgs/{slug}` for the org-level fallbacks."
7989
- ),
7990
- legalDocuments: zod.z.object({
7991
- letterOfAuthorization: brandLegalDocumentSchema,
7992
- powerOfAttorney: brandLegalDocumentSchema
7993
- }).describe("Brand-level Letter of Authorization and Power of Attorney attachments"),
7994
- trademarkRegistrations: zod.z.array(brandTrademarkRegistrationSchema).describe(
7995
- "Trademark registrations attached to this brand. An empty array means no trademarks are on file for the brand \u2014 use this to identify brands that still need them added."
7996
- )
7997
- });
7998
- zod.z.object({
7999
- brands: zod.z.array(brandItemSchema).describe("List of brands")
8000
- }).describe("Successful operation");
8001
- var FILTERABLE_SUBSCRIPTION_STATUSES = [
8002
- SubscriptionStatus.PROSPECT,
8003
- SubscriptionStatus.POC,
8004
- SubscriptionStatus.ACTIVE,
8005
- SubscriptionStatus.INTEGRATION
8006
- ];
8007
- var UserOrgsSubscriptionStatusSchema = zod.z.enum(
8008
- FILTERABLE_SUBSCRIPTION_STATUSES
8009
- );
8010
- var takedownsServiceFilterSchema = zod.z.object({
8011
- active: zod.z.boolean().optional(),
8012
- automated: zod.z.boolean().optional()
8013
- }).optional();
8014
- var singleServiceFilterSchema = zod.z.object({
8015
- active: zod.z.boolean().optional()
8016
- }).optional();
8017
- var userOrgsServicesFilterObjectSchema = zod.z.object({
8018
- reporting: singleServiceFilterSchema,
8019
- reviewing: singleServiceFilterSchema,
8020
- protection: singleServiceFilterSchema,
8021
- takedowns: takedownsServiceFilterSchema,
8022
- detection: singleServiceFilterSchema,
8023
- darkWebMonitoring: singleServiceFilterSchema
8024
- });
8025
- var userOrgsObligatoryAdminApprovalFilterSchema = zod.z.object({
8026
- active: zod.z.boolean().optional(),
8027
- assetTypes: zod.z.array(zod.z.nativeEnum(AssetType)).min(1).optional()
8028
- }).optional();
8029
- var PendingApprovalServiceSchema = zod.z.enum(["protection", "takedowns"]);
8030
- var userOrgsPendingServiceApprovalFilterSchema = zod.z.object({
8031
- active: zod.z.boolean().optional(),
8032
- services: zod.z.array(PendingApprovalServiceSchema).min(1).optional()
8033
- }).optional();
8034
- zod.z.object({
8035
- query: zod.z.string().default(""),
8036
- subscriptionStatus: zod.z.array(UserOrgsSubscriptionStatusSchema).min(1).optional(),
8037
- services: userOrgsServicesFilterObjectSchema.optional(),
8038
- obligatoryAdminApproval: userOrgsObligatoryAdminApprovalFilterSchema,
8039
- pendingServiceApproval: userOrgsPendingServiceApprovalFilterSchema
8040
- });
8041
- var takedownsServiceSchema = zod.z.object({
8042
- active: zod.z.boolean(),
8043
- automated: zod.z.boolean()
8044
- });
8045
- var singleServiceSchema = zod.z.object({
8046
- active: zod.z.boolean()
8047
- });
8048
- var UserOrgObligatoryAdminApprovalSchema = zod.z.object({
8049
- active: zod.z.boolean(),
8050
- assetTypes: zod.z.array(zod.z.nativeEnum(AssetType))
8051
- });
8052
- var PendingServiceApprovalSchema = zod.z.object({
8053
- // Friendly service family, matching a key in the `services` object.
8054
- service: PendingApprovalServiceSchema,
8055
- // Whether the request is for the automated variant of the service
8056
- // (e.g. "Automated Wallet Blocking" rather than "Wallet Blocking").
8057
- automated: zod.z.boolean(),
8058
- // Raw `ServiceType` enum value, e.g. "isProtectionActive". Lets callers
8059
- // distinguish the exact column without re-deriving it from `service` +
8060
- // `automated`.
8061
- serviceType: zod.z.nativeEnum(ServiceType),
8062
- // Human-readable service label, e.g. "Wallet Blocking".
8063
- serviceName: zod.z.string(),
8064
- // When the enable request was submitted (ISO 8601, UTC).
8065
- requestedAt: zod.z.string()
8066
- });
8067
- var UserOrgIntegrationsSchema = zod.z.object({
8068
- slack: zod.z.boolean(),
8069
- discord: zod.z.boolean(),
8070
- telegram: zod.z.object({
8071
- connected: zod.z.boolean(),
8072
- groupCount: zod.z.number()
8073
- }),
8074
- vercel: zod.z.boolean(),
8075
- intercom: zod.z.boolean(),
8076
- moderation: zod.z.boolean()
8077
- });
8078
- var UserOrgLegalDocumentSchema = zod.z.object({
8079
- present: zod.z.boolean().describe("Whether the organization has this document attached"),
8080
- fileName: zod.z.string().nullable().describe("Original filename of the uploaded document (null when not present)"),
8081
- fileUrl: zod.z.string().nullable().describe("Direct URL to view or download the document (null when not present)")
8082
- });
8083
- var UserOrgLegalDocumentsSchema = zod.z.object({
8084
- letterOfAuthorization: UserOrgLegalDocumentSchema,
8085
- powerOfAttorney: UserOrgLegalDocumentSchema
8086
- });
8087
- var UserOrgTrademarkRegistrationSchema = zod.z.object({
8088
- id: zod.z.number().describe("Trademark registration ID"),
8089
- brandName: zod.z.string().describe("Trademarked brand name as it appears on the registration"),
8090
- trademarkOffice: zod.z.string().describe("Issuing trademark office (e.g. `USPTO`, `EUIPO`)"),
8091
- registrationNumber: zod.z.string().describe("Registration number assigned by the office"),
8092
- goodsAndServicesClass: zod.z.string().describe("Nice Classification class(es) the registration covers"),
8093
- rightsOwnerName: zod.z.string().nullable().describe("Legal entity the trademark is registered to, if recorded"),
8094
- registrationPageUrl: zod.z.string().nullable().describe("Public URL on the trademark office's site, if recorded"),
8095
- certificateFileName: zod.z.string().nullable().describe(
8096
- "Original filename of the uploaded certificate PDF (null when no certificate is attached)"
8097
- ),
8098
- certificateFileUrl: zod.z.string().nullable().describe(
8099
- "Direct URL to view or download the certificate PDF (null when no certificate is attached)"
8100
- )
8101
- });
8102
- var UserOrgBrandMetadataSchema = zod.z.object({
8103
- websiteUrl: zod.z.string().nullable().describe("Public website URL of the brand (linked from the portal header)"),
8104
- twitterHandle: zod.z.string().nullable().describe(
8105
- "Public Twitter/X handle of the brand, stored with the leading `@` (e.g. `@acme`)"
8106
- ),
8107
- securityContactEmail: zod.z.string().nullable().describe(
8108
- "Email address for security correspondence \u2014 used by takedown providers and researchers, distinct from the internal customer POC email"
8109
- ),
8110
- industry: zod.z.string().nullable().describe('Free-form industry label (e.g. "DeFi", "CEX", "NFT", "Wallet")')
8111
- });
8112
- var UserOrgPortalCustomizationSchema = zod.z.object({
8113
- useCustomDetails: zod.z.boolean().describe(
8114
- "When true, the portal uses `name`/`slug`/`avatarUrl` from this object instead of the org's own name/slug/avatar"
8115
- ),
8116
- name: zod.z.string().nullable().describe(
8117
- "Custom display name shown on the portal (used only when `useCustomDetails=true`)"
8118
- ),
8119
- slug: zod.z.string().nullable().describe(
8120
- "Custom URL slug (`chainpatrol.io/<slug>`) \u2014 takes precedence over the org's own slug when set, regardless of `useCustomDetails`"
8121
- ),
8122
- avatarUrl: zod.z.string().nullable().describe(
8123
- "Custom avatar URL shown on the portal (used only when `useCustomDetails=true`)"
8124
- ),
8125
- bannerEnabled: zod.z.boolean().describe(
8126
- "When true, the portal renders `bannerContent` as a highlighted banner at the top of the page"
8127
- ),
8128
- bannerContent: zod.z.string().nullable().describe(
8129
- "Markdown body of the portal banner. Null (or empty) with `bannerEnabled=true` means the toggle is on but no content has been written yet"
8130
- )
8131
- });
8132
- var UserOrgSchema = zod.z.object({
8133
- id: zod.z.number(),
8134
- name: zod.z.string(),
8135
- slug: zod.z.string(),
8136
- avatarUrl: zod.z.string().nullable(),
8137
- contactUrl: zod.z.string().nullable(),
8138
- subscriptionStatus: zod.z.nativeEnum(SubscriptionStatus),
8139
- portalVisibility: zod.z.nativeEnum(OrganizationPortalVisibility).describe(
8140
- "Visibility of the org's public security portal (chainpatrol.io/<slug>). `PUBLIC` is discoverable; `PRIVATE` renders only the report form (no metrics or listings); `DISABLED` returns a 404."
8141
- ),
8142
- reportVisibility: zod.z.nativeEnum(ReportVisibility).describe(
8143
- "Whether the report listings on the public portal are visible to visitors. `PUBLIC` shows the org's reports; `PRIVATE` hides the report list even when the portal is discoverable."
8144
- ),
8145
- metricsVisibility: zod.z.nativeEnum(MetricsVisibility).describe(
8146
- "Whether the metrics/threats-blocked stats render on the public portal. `PUBLIC` shows the metrics tab; `PRIVATE` hides it from anonymous visitors; `DISABLED` doesn't compute metrics at all."
8147
- ),
8148
- brandMetadata: UserOrgBrandMetadataSchema.describe(
8149
- "Public brand-facing metadata (website, twitter, security contact, industry) shown on the portal and used by staff for outbound"
8150
- ),
8151
- portalCustomization: UserOrgPortalCustomizationSchema.describe(
8152
- "Customer-configurable presentation of the public security portal \u2014 custom name/slug/avatar and the banner content"
8153
- ),
8154
- services: zod.z.object({
8155
- reporting: singleServiceSchema,
8156
- reviewing: singleServiceSchema,
8157
- protection: singleServiceSchema,
8158
- takedowns: takedownsServiceSchema,
8159
- detection: singleServiceSchema,
8160
- darkWebMonitoring: singleServiceSchema
8161
- }),
8162
- integrations: UserOrgIntegrationsSchema,
8163
- obligatoryAdminApproval: UserOrgObligatoryAdminApprovalSchema,
8164
- pendingServiceApprovals: zod.z.array(PendingServiceApprovalSchema),
8165
- legalDocuments: UserOrgLegalDocumentsSchema.describe(
8166
- "Org-level Letter of Authorization and Power of Attorney attachments"
8167
- ),
8168
- trademarkRegistrations: zod.z.array(UserOrgTrademarkRegistrationSchema).describe(
8169
- "Org-level trademark registrations attached to the organization. An empty array means no trademarks are on file \u2014 use this to identify customers who still need to add them."
8170
- )
8171
- });
8172
- zod.z.object({
8173
- organizations: zod.z.array(UserOrgSchema)
8174
- });
8175
7467
 
8176
- // ../../internal/validation/src/public/organization/metrics-get.ts
8177
- var organizationMetricsIncludeFieldSchema = zod.z.enum([
8178
- "reports",
8179
- "newThreats",
8180
- "threatsWatchlisted",
8181
- "takedownsFiled",
8182
- "takedownsCompleted",
8183
- "domainThreats",
8184
- "twitterThreats",
8185
- "telegramThreats",
8186
- "otherThreats",
8187
- "blockedByType",
8188
- "blockedByDay"
8189
- ]);
8190
- organizationMetricsIncludeFieldSchema.options;
8191
- var ORGANIZATION_METRICS_MAX_SLUGS = 500;
8192
- var organizationMetricsServicesFilterSchema = zod.z.preprocess((value) => {
8193
- if (typeof value !== "string") return value;
8194
- try {
8195
- return JSON.parse(value);
8196
- } catch (e4) {
8197
- return value;
8198
- }
8199
- }, userOrgsServicesFilterObjectSchema).optional();
8200
- zod.z.object({
8201
- organizationSlug: zod.z.string().optional().describe(
8202
- "Organization slug. Required when authenticating with a user session (Bearer token) and `slugs`/`allMyOrgs` are not supplied; ignored when using an org-scoped API key (org is derived from the key). Mutually exclusive with `slugs` and `allMyOrgs`."
8203
- ),
8204
- slugs: zod.z.array(zod.z.string()).max(ORGANIZATION_METRICS_MAX_SLUGS).optional().describe(
8205
- "Multi-org form. Each slug is auth-checked individually (org-scoped API keys may only pass their own org; sessions and user API keys must have membership or staff role per slug). When supplied with more than one slug, the response includes a `perOrg` breakdown plus `metrics` rolled up across all of them. Capped at " + String(ORGANIZATION_METRICS_MAX_SLUGS) + " slugs per call. Mutually exclusive with `organizationSlug` and `allMyOrgs`."
8206
- ),
8207
- allMyOrgs: zod.z.preprocess((value) => {
8208
- if (value === "true") return true;
8209
- if (value === "false") return false;
8210
- return value;
8211
- }, zod.z.boolean()).optional().describe(
8212
- "Shortcut for 'every org the caller is authorized to read'. Reuses the same filter logic as `/user/orgs`: org-scoped API keys are rejected (they're pinned to one org \u2014 use the default form); user API keys / Bearer sessions resolve to the user's memberships (or every active org for staff). Combine with `subscriptionStatus` and `services` to narrow (e.g. only paying customers with takedowns enabled). The resolved org set is still capped at " + String(ORGANIZATION_METRICS_MAX_SLUGS) + " and a 413 is returned if exceeded. Mutually exclusive with `organizationSlug`, `slugs`, and `brandSlug`."
8213
- ),
8214
- subscriptionStatus: zod.z.array(UserOrgsSubscriptionStatusSchema).min(1).optional().describe(
8215
- "Only meaningful with `allMyOrgs: true`. Defaults to the same set `/user/orgs` uses (ACTIVE/POC/PROSPECT/INTEGRATION \u2014 INACTIVE is always excluded)."
8216
- ),
8217
- services: organizationMetricsServicesFilterSchema.describe(
8218
- "Only meaningful with `allMyOrgs: true`. Same shape as `/user/orgs`'s `services` filter \u2014 every service accepts `{ active }`, and **only `takedowns` additionally accepts `automated`** (the one service where manual-vs-automated changes real platform behavior). E.g. `{ takedowns: { active: true, automated: false } }` for 'orgs with takedowns enabled but automation off'."
8219
- ),
8220
- brandSlug: zod.z.string().optional(),
8221
- startDate: zod.z.coerce.date().optional(),
8222
- endDate: zod.z.coerce.date().optional(),
8223
- include: zod.z.array(organizationMetricsIncludeFieldSchema).optional().describe(
8224
- "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`."
8225
- )
8226
- }).refine(
8227
- (value) => {
8228
- const explicitForms = [
8229
- Boolean(value.organizationSlug),
8230
- Boolean(value.slugs && value.slugs.length > 0),
8231
- Boolean(value.allMyOrgs)
8232
- ].filter(Boolean).length;
8233
- return explicitForms <= 1;
8234
- },
8235
- {
8236
- message: "Pass at most one of `organizationSlug`, `slugs`, or `allMyOrgs`.",
8237
- path: ["allMyOrgs"]
8238
- }
8239
- ).refine((value) => !(value.brandSlug && value.slugs && value.slugs.length > 1), {
8240
- message: "`brandSlug` is only valid alongside a single organization, not `slugs`.",
8241
- path: ["brandSlug"]
8242
- }).refine((value) => !(value.brandSlug && value.allMyOrgs), {
8243
- message: "`brandSlug` is only valid for a single org, not `allMyOrgs`.",
8244
- path: ["brandSlug"]
8245
- });
8246
- var metricValue = zod.z.number().nullable();
8247
- var metricsObjectSchema = zod.z.object({
8248
- reports: metricValue,
8249
- newThreats: metricValue,
8250
- threatsWatchlisted: metricValue,
8251
- takedownsFiled: metricValue,
8252
- takedownsCompleted: metricValue,
8253
- domainThreats: metricValue,
8254
- twitterThreats: metricValue,
8255
- telegramThreats: metricValue,
8256
- otherThreats: metricValue
8257
- });
8258
- var blockedByTypeSchema = zod.z.array(
8259
- zod.z.object({
8260
- type: zod.z.string(),
8261
- count: zod.z.number()
8262
- })
8263
- ).nullable();
8264
- var blockedByDaySchema = zod.z.array(
8265
- zod.z.object({
8266
- date: zod.z.string(),
8267
- count: zod.z.number()
8268
- })
8269
- ).nullable();
8270
- zod.z.object({
8271
- /**
8272
- * Aggregate metrics. For single-org callers this is just that org's
8273
- * numbers; for multi-org callers (`slugs.length > 1` or `allMyOrgs`)
8274
- * it is the sum across all queried orgs.
8275
- */
8276
- metrics: metricsObjectSchema,
8277
- blockedByType: blockedByTypeSchema,
8278
- blockedByDay: blockedByDaySchema,
8279
- /**
8280
- * Derived averages over the time window (and, in multi-org mode,
8281
- * across orgs). `perDay = metrics / windowDays`. In multi-org mode
8282
- * `perOrgPerDay = metrics / numOrgs / windowDays`; in single-org
8283
- * mode it is `null`. Counts are floats here — the underlying
8284
- * `metrics` fields stay integer counts.
8285
- */
8286
- averages: zod.z.object({
8287
- perDay: metricsObjectSchema.nullable(),
8288
- perOrgPerDay: metricsObjectSchema.nullable(),
8289
- windowDays: zod.z.number().nullable()
8290
- }),
8291
- /**
8292
- * Per-org breakdown. Only populated in multi-org mode; `null` for
8293
- * single-org callers.
8294
- */
8295
- perOrg: zod.z.record(
8296
- zod.z.string(),
8297
- zod.z.object({
8298
- metrics: metricsObjectSchema,
8299
- blockedByType: blockedByTypeSchema,
8300
- blockedByDay: blockedByDaySchema
8301
- })
8302
- ).nullable(),
8303
- /**
8304
- * Echoes the actual orgs the response covers, in the order they
8305
- * were resolved. Single-org responses always have length 1. The
8306
- * `resolvedFrom` field distinguishes how the caller asked for the
8307
- * scope (useful for agent reporting).
8308
- */
8309
- scope: zod.z.object({
8310
- mode: zod.z.enum(["single", "multi"]),
8311
- orgs: zod.z.array(zod.z.string()),
8312
- resolvedFrom: zod.z.enum(["api-key", "organizationSlug", "slugs", "allMyOrgs"])
8313
- })
8314
- });
7468
+ // ../../internal/utils/src/detection.ts
7469
+ var ThreatDetectionSourceKey = /* @__PURE__ */ ((ThreatDetectionSourceKey2) => {
7470
+ ThreatDetectionSourceKey2["META_ADS_SEARCH"] = "meta_ads_search";
7471
+ ThreatDetectionSourceKey2["TELEGRAM_CHANNELS_SEARCH"] = "telegram_channels_search";
7472
+ ThreatDetectionSourceKey2["TELEGRAM_USER_SEARCH"] = "telegram_user_search";
7473
+ ThreatDetectionSourceKey2["TELEGRAM_CHANNELS_SEARCH_VETRIC"] = "telegram_channels_search_vetric";
7474
+ ThreatDetectionSourceKey2["TELEGRAM_USER_SEARCH_VETRIC"] = "telegram_user_search_vetric";
7475
+ ThreatDetectionSourceKey2["FACEBOOK_PAGE_SEARCH_VETRIC"] = "facebook_page_search_vetric";
7476
+ ThreatDetectionSourceKey2["INSTAGRAM_ACCOUNT_SEARCH_VETRIC"] = "instagram_account_search_vetric";
7477
+ ThreatDetectionSourceKey2["TWITTER_SEARCH_VETRIC"] = "twitter_search_vetric";
7478
+ ThreatDetectionSourceKey2["LINKEDIN_PEOPLE_SEARCH_VETRIC"] = "linkedin_people_search_vetric";
7479
+ ThreatDetectionSourceKey2["LINKEDIN_COMPANY_SEARCH_VETRIC"] = "linkedin_company_search_vetric";
7480
+ ThreatDetectionSourceKey2["META_ADS_SEARCH_VETRIC"] = "meta_ads_search_vetric";
7481
+ ThreatDetectionSourceKey2["TIK_TOK_VIDEO_SEARCH"] = "tik_tok_video_search";
7482
+ ThreatDetectionSourceKey2["TIK_TOK_USER_SEARCH"] = "tik_tok_user_search";
7483
+ ThreatDetectionSourceKey2["TIK_TOK_USER_SEARCH_VETRIC"] = "tik_tok_user_search_vetric";
7484
+ ThreatDetectionSourceKey2["TIK_TOK_VIDEO_SEARCH_VETRIC"] = "tik_tok_video_search_vetric";
7485
+ ThreatDetectionSourceKey2["BLOCKLIST"] = "blocklist";
7486
+ ThreatDetectionSourceKey2["APPLE_APP_STORE"] = "apple_app_store";
7487
+ ThreatDetectionSourceKey2["GOOGLE_ADS_SEARCH"] = "google_ads_search";
7488
+ ThreatDetectionSourceKey2["MOZILLA_ADDON_SEARCH"] = "mozilla_addon_search";
7489
+ ThreatDetectionSourceKey2["REDDIT_SUBREDDIT_SEARCH"] = "reddit_subreddit_search";
7490
+ ThreatDetectionSourceKey2["ASSET_CHECK"] = "asset_check";
7491
+ ThreatDetectionSourceKey2["TWITTER_POST_SEARCH"] = "twitter_post_search";
7492
+ ThreatDetectionSourceKey2["MEDIUM_TAG_RSS"] = "medium_tag_rss";
7493
+ ThreatDetectionSourceKey2["TWITTER_SEARCH"] = "twitter_search";
7494
+ ThreatDetectionSourceKey2["YAHOO_SEARCH"] = "yahoo_search";
7495
+ ThreatDetectionSourceKey2["DUCK_DUCK_GO_SEARCH"] = "duck_duck_go_search";
7496
+ ThreatDetectionSourceKey2["BING_SEARCH"] = "bing_search";
7497
+ ThreatDetectionSourceKey2["GUESTBOOK"] = "guestbook";
7498
+ ThreatDetectionSourceKey2["CERTSTREAM"] = "certstream";
7499
+ ThreatDetectionSourceKey2["EXTERNAL"] = "external";
7500
+ ThreatDetectionSourceKey2["GOOGLE_SEARCH"] = "google_search";
7501
+ ThreatDetectionSourceKey2["DNS_TWIST"] = "dns_twist";
7502
+ ThreatDetectionSourceKey2["TWITTER"] = "twitter";
7503
+ ThreatDetectionSourceKey2["TWITTER_USERNAME_MONITOR"] = "twitter_username_monitor";
7504
+ ThreatDetectionSourceKey2["URLSCAN"] = "urlscan";
7505
+ ThreatDetectionSourceKey2["URLSCAN_HOSTNAME_SEARCH"] = "urlscan_hostname_search";
7506
+ ThreatDetectionSourceKey2["YOUTUBE_SEARCH"] = "youtube_search";
7507
+ ThreatDetectionSourceKey2["GOOGLE_PLAY_SEARCH"] = "google_play_search";
7508
+ ThreatDetectionSourceKey2["DEXSCREENER_SEARCH"] = "dexscreener_search";
7509
+ ThreatDetectionSourceKey2["BLOCKED_IP_SCAN"] = "blocked_ip_scan";
7510
+ ThreatDetectionSourceKey2["BLOCKED_BILIBILI_SUGGESTED"] = "blocked_bilibili_suggested";
7511
+ ThreatDetectionSourceKey2["GROK_POST_SEARCH"] = "grok_post_search";
7512
+ ThreatDetectionSourceKey2["GROK_USER_SEARCH"] = "grok_user_search";
7513
+ ThreatDetectionSourceKey2["GOOGLE_LENS_IMAGE_SEARCH"] = "google_lens_image_search";
7514
+ ThreatDetectionSourceKey2["YANDEX_SEARCH"] = "yandex_search";
7515
+ ThreatDetectionSourceKey2["LINKEDIN_EMPLOYEE_DETECTION"] = "linkedin_employee_detection";
7516
+ ThreatDetectionSourceKey2["LINKEDIN_POST_SEARCH"] = "linkedin_post_search";
7517
+ ThreatDetectionSourceKey2["LINKEDIN_COMPANY_SEARCH"] = "linkedin_company_search";
7518
+ ThreatDetectionSourceKey2["BING_ADS_SEARCH"] = "bing_ads_search";
7519
+ ThreatDetectionSourceKey2["TIK_TOK_ADS_SEARCH"] = "tik_tok_ads_search";
7520
+ ThreatDetectionSourceKey2["DNSDB"] = "dnsdb";
7521
+ ThreatDetectionSourceKey2["DAILY_MOTION_SEARCH"] = "daily_motion_search";
7522
+ ThreatDetectionSourceKey2["WATCHLIST"] = "watchlist";
7523
+ return ThreatDetectionSourceKey2;
7524
+ })(ThreatDetectionSourceKey || {});
7525
+ var ThreatDetectionScope = /* @__PURE__ */ ((ThreatDetectionScope2) => {
7526
+ ThreatDetectionScope2["ORGANIZATION"] = "organization";
7527
+ ThreatDetectionScope2["GLOBAL"] = "global";
7528
+ return ThreatDetectionScope2;
7529
+ })(ThreatDetectionScope || {});
8315
7530
 
8316
7531
  // ../../internal/utils/src/enrichments.ts
8317
7532
  var enrichments_exports = {};
@@ -10905,977 +10120,1963 @@ var doCustomReplacements = (string, replacements2) => {
10905
10120
  for (const [key, value] of replacements2) {
10906
10121
  string = string.replace(new RegExp(escapeStringRegexp2(key), "g"), value);
10907
10122
  }
10908
- return string;
10123
+ return string;
10124
+ };
10125
+ function transliterate(string, options) {
10126
+ if (typeof string !== "string") {
10127
+ throw new TypeError(`Expected a string, got \`${typeof string}\``);
10128
+ }
10129
+ options = __spreadValues({
10130
+ customReplacements: []
10131
+ }, options);
10132
+ const customReplacements = new Map([
10133
+ ...replacements_default,
10134
+ ...options.customReplacements
10135
+ ]);
10136
+ string = string.normalize();
10137
+ string = doCustomReplacements(string, customReplacements);
10138
+ string = string.normalize("NFD").replace(new RegExp("\\p{Diacritic}", "gu"), "").normalize();
10139
+ return string;
10140
+ }
10141
+
10142
+ // ../../node_modules/@sindresorhus/slugify/overridable-replacements.js
10143
+ var overridableReplacements = [
10144
+ ["&", " and "],
10145
+ ["\u{1F984}", " unicorn "],
10146
+ ["\u2665", " love "]
10147
+ ];
10148
+ var overridable_replacements_default = overridableReplacements;
10149
+
10150
+ // ../../node_modules/@sindresorhus/slugify/index.js
10151
+ var decamelize = (string) => {
10152
+ return string.replace(/([A-Z]{2,})(\d+)/g, "$1 $2").replace(/([a-z\d]+)([A-Z]{2,})/g, "$1 $2").replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-rt-z\d]+)/g, "$1 $2");
10153
+ };
10154
+ var removeMootSeparators = (string, separator) => {
10155
+ const escapedSeparator = escapeStringRegexp(separator);
10156
+ return string.replace(new RegExp(`${escapedSeparator}{2,}`, "g"), separator).replace(new RegExp(`^${escapedSeparator}|${escapedSeparator}$`, "g"), "");
10157
+ };
10158
+ var buildPatternSlug = (options) => {
10159
+ let negationSetPattern = "a-z\\d";
10160
+ negationSetPattern += options.lowercase ? "" : "A-Z";
10161
+ if (options.preserveCharacters.length > 0) {
10162
+ for (const character of options.preserveCharacters) {
10163
+ if (character === options.separator) {
10164
+ throw new Error(`The separator character \`${options.separator}\` cannot be included in preserved characters: ${options.preserveCharacters}`);
10165
+ }
10166
+ negationSetPattern += escapeStringRegexp(character);
10167
+ }
10168
+ }
10169
+ return new RegExp(`[^${negationSetPattern}]+`, "g");
10170
+ };
10171
+ function slugify(string, options) {
10172
+ if (typeof string !== "string") {
10173
+ throw new TypeError(`Expected a string, got \`${typeof string}\``);
10174
+ }
10175
+ options = __spreadValues({
10176
+ separator: "-",
10177
+ lowercase: true,
10178
+ decamelize: true,
10179
+ customReplacements: [],
10180
+ preserveLeadingUnderscore: false,
10181
+ preserveTrailingDash: false,
10182
+ preserveCharacters: []
10183
+ }, options);
10184
+ const shouldPrependUnderscore = options.preserveLeadingUnderscore && string.startsWith("_");
10185
+ const shouldAppendDash = options.preserveTrailingDash && string.endsWith("-");
10186
+ const customReplacements = new Map([
10187
+ ...overridable_replacements_default,
10188
+ ...options.customReplacements
10189
+ ]);
10190
+ string = transliterate(string, { customReplacements });
10191
+ if (options.decamelize) {
10192
+ string = decamelize(string);
10193
+ }
10194
+ const patternSlug = buildPatternSlug(options);
10195
+ if (options.lowercase) {
10196
+ string = string.toLowerCase();
10197
+ }
10198
+ string = string.replace(/([a-zA-Z\d]+)'([ts])(\s|$)/g, "$1$2$3");
10199
+ string = string.replace(patternSlug, options.separator);
10200
+ string = string.replace(/\\/g, "");
10201
+ if (options.separator) {
10202
+ string = removeMootSeparators(string, options.separator);
10203
+ }
10204
+ if (shouldPrependUnderscore) {
10205
+ string = `_${string}`;
10206
+ }
10207
+ if (shouldAppendDash) {
10208
+ string = `${string}-`;
10209
+ }
10210
+ return string;
10211
+ }
10212
+
10213
+ // ../asset-parse/src/model.ts
10214
+ var AssetModel = /* @__PURE__ */ ((AssetModel2) => {
10215
+ AssetModel2["Addon"] = "addon";
10216
+ AssetModel2["App"] = "app";
10217
+ AssetModel2["Bot"] = "bot";
10218
+ AssetModel2["BusinessProfile"] = "business-profile";
10219
+ AssetModel2["Catalog"] = "catalog";
10220
+ AssetModel2["Collection"] = "collection";
10221
+ AssetModel2["Channel"] = "channel";
10222
+ AssetModel2["Group"] = "group";
10223
+ AssetModel2["Post"] = "post";
10224
+ AssetModel2["Profile"] = "profile";
10225
+ AssetModel2["Short"] = "short";
10226
+ AssetModel2["Video"] = "video";
10227
+ AssetModel2["Space"] = "space";
10228
+ AssetModel2["Issue"] = "issue";
10229
+ AssetModel2["PullRequest"] = "pull-request";
10230
+ AssetModel2["Discussion"] = "discussion";
10231
+ AssetModel2["Repository"] = "repository";
10232
+ AssetModel2["Article"] = "Article";
10233
+ AssetModel2["Comment"] = "comment";
10234
+ AssetModel2["List"] = "list";
10235
+ AssetModel2["Subreddit"] = "subreddit";
10236
+ AssetModel2["Community"] = "community";
10237
+ AssetModel2["MiniApp"] = "mini-app";
10238
+ AssetModel2["Developer"] = "developer";
10239
+ return AssetModel2;
10240
+ })(AssetModel || {});
10241
+ function isUrl(input) {
10242
+ if (input.trim() === "") {
10243
+ return false;
10244
+ }
10245
+ if (input.startsWith("/") || input.startsWith("#") || input.startsWith("?") || input.startsWith(".") || !input.includes(".")) {
10246
+ return false;
10247
+ }
10248
+ return URL.canParse(input) || URL.canParse(`https://${input}`);
10249
+ }
10250
+ function getNormalizedUrl(input) {
10251
+ if (!isUrl(input)) {
10252
+ throw new Error(`Invalid URL: ${input}`);
10253
+ }
10254
+ let url;
10255
+ try {
10256
+ url = new URL(input);
10257
+ } catch (e4) {
10258
+ try {
10259
+ url = new URL(`https://${input}`);
10260
+ } catch (e5) {
10261
+ throw new Error(`Invalid URL: ${input}`);
10262
+ }
10263
+ }
10264
+ const normalizedUrl = normalizeUrl(url.toString(), {
10265
+ defaultProtocol: "https"
10266
+ });
10267
+ try {
10268
+ return new URL(normalizedUrl);
10269
+ } catch (e4) {
10270
+ throw new Error(`Invalid URL: ${input}`);
10271
+ }
10272
+ }
10273
+ var ensureHttpsPrefix = (url) => {
10274
+ if (!url.startsWith("http")) {
10275
+ return `https://${url}`;
10276
+ }
10277
+ return url.replace(/^https?:\/{1,2}/, "https://");
10909
10278
  };
10910
- function transliterate(string, options) {
10911
- if (typeof string !== "string") {
10912
- throw new TypeError(`Expected a string, got \`${typeof string}\``);
10279
+ function getHostname(input) {
10280
+ try {
10281
+ return getNormalizedUrl(input).hostname;
10282
+ } catch (e4) {
10283
+ return null;
10913
10284
  }
10914
- options = __spreadValues({
10915
- customReplacements: []
10916
- }, options);
10917
- const customReplacements = new Map([
10918
- ...replacements_default,
10919
- ...options.customReplacements
10920
- ]);
10921
- string = string.normalize();
10922
- string = doCustomReplacements(string, customReplacements);
10923
- string = string.normalize("NFD").replace(new RegExp("\\p{Diacritic}", "gu"), "").normalize();
10924
- return string;
10285
+ }
10286
+ function getParentDomains(input) {
10287
+ const domain = getHostname(input);
10288
+ if (!domain) {
10289
+ return [];
10290
+ }
10291
+ const subdomain = tldts.getSubdomain(domain, { mixedInputs: false });
10292
+ if (!subdomain) {
10293
+ return [domain];
10294
+ }
10295
+ const domainWithSuffix = tldts.getDomain(domain, { mixedInputs: false });
10296
+ if (!domainWithSuffix) {
10297
+ return [];
10298
+ }
10299
+ const parentDomains = [domainWithSuffix];
10300
+ const parentDomainParts = subdomain.split(".");
10301
+ for (let i = parentDomainParts.length - 1; i >= 0; i--) {
10302
+ const parentDomainPart = parentDomainParts.slice(i).join(".");
10303
+ parentDomains.push(`${parentDomainPart}.${domainWithSuffix}`);
10304
+ }
10305
+ return parentDomains.reverse();
10306
+ }
10307
+ function trimDomainToLevels(domain, options = { levels: 4 }) {
10308
+ var _a;
10309
+ const parsed = tldts.parse(domain);
10310
+ const eTLDPlusOne = (_a = parsed.domain) != null ? _a : "";
10311
+ const subdomains = domain.replace(/https?:\/\/(www\.)?/, "").split(".");
10312
+ const eTLDPlusOneIndex = subdomains.findIndex(
10313
+ (_, i) => subdomains.slice(i).join(".") === eTLDPlusOne
10314
+ );
10315
+ const trimmedSubdomains = subdomains.slice(Math.max(eTLDPlusOneIndex - (options.levels - 1), 0)).join(".");
10316
+ return trimmedSubdomains;
10925
10317
  }
10926
10318
 
10927
- // ../../node_modules/@sindresorhus/slugify/overridable-replacements.js
10928
- var overridableReplacements = [
10929
- ["&", " and "],
10930
- ["\u{1F984}", " unicorn "],
10931
- ["\u2665", " love "]
10932
- ];
10933
- var overridable_replacements_default = overridableReplacements;
10319
+ // ../asset-parse/src/phone.ts
10320
+ var phone_exports = {};
10321
+ __export(phone_exports, {
10322
+ PHONE_NUMBER_REGEX: () => PHONE_NUMBER_REGEX,
10323
+ isPhoneNumber: () => isPhoneNumber,
10324
+ normalizePhoneNumber: () => normalizePhoneNumber
10325
+ });
10326
+ var PHONE_NUMBER_REGEX = /(?:\+?\d{1,4}[\s.-]?)?(?:\(\d{1,4}\)|\d{1,4})[\s.-]?\d{1,4}[\s.-]?\d{1,4}[\s.-]?\d{0,4}(?:\s*(?:ext|x|extension)[\s.]*\d{1,6})?/gi;
10327
+ function preparePhoneInput(input) {
10328
+ let s2 = input.trim();
10329
+ s2 = s2.replace(/^\s*tel:\s*(?:\/\/)?\s*/i, "");
10330
+ s2 = s2.trim();
10331
+ s2 = s2.replace(/[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g, " ");
10332
+ s2 = s2.replace(/[\u2010\u2011\u2012\u2013\u2014\u2015\u2212\uFE58\uFE63\uFF0D]/g, "-");
10333
+ s2 = s2.replace(/\uFF0B/g, "+");
10334
+ s2 = s2.replace(/\uFF08/g, "(");
10335
+ s2 = s2.replace(/\uFF09/g, ")");
10336
+ return s2.trim();
10337
+ }
10338
+ function isAllSameDigit(digits2) {
10339
+ return /^(\d)\1+$/.test(digits2);
10340
+ }
10341
+ function isStrictlyMonotonicStep1(digits2) {
10342
+ if (digits2.length < 8) {
10343
+ return false;
10344
+ }
10345
+ let increasing = true;
10346
+ let decreasing = true;
10347
+ for (let i = 1; i < digits2.length; i++) {
10348
+ const curr = digits2.charCodeAt(i) - 48;
10349
+ const prev = digits2.charCodeAt(i - 1) - 48;
10350
+ if (curr !== prev + 1) {
10351
+ increasing = false;
10352
+ }
10353
+ if (curr !== prev - 1) {
10354
+ decreasing = false;
10355
+ }
10356
+ }
10357
+ return increasing || decreasing;
10358
+ }
10359
+ function isValidNanpNational10(d10) {
10360
+ if (d10.length !== 10) {
10361
+ return false;
10362
+ }
10363
+ const npaFirst = d10.charCodeAt(0) - 48;
10364
+ const nxxFirst = d10.charCodeAt(3) - 48;
10365
+ if (npaFirst < 2 || npaFirst > 9) {
10366
+ return false;
10367
+ }
10368
+ if (nxxFirst < 2 || nxxFirst > 9) {
10369
+ return false;
10370
+ }
10371
+ return true;
10372
+ }
10373
+ function isPlausiblePhoneDigits(withoutExt) {
10374
+ const hasPlus = withoutExt.startsWith("+");
10375
+ const d = withoutExt.replace(/\D/g, "");
10376
+ if (d.length < 8 || d.length > 15) {
10377
+ return false;
10378
+ }
10379
+ if (isAllSameDigit(d) || isStrictlyMonotonicStep1(d)) {
10380
+ return false;
10381
+ }
10382
+ const onlyDigits = /^\d+$/.test(withoutExt);
10383
+ if (hasPlus) {
10384
+ if (d.length === 11 && d.startsWith("1")) {
10385
+ return isValidNanpNational10(d.slice(1));
10386
+ }
10387
+ return true;
10388
+ }
10389
+ if (onlyDigits) {
10390
+ if (d.length === 10) {
10391
+ return isValidNanpNational10(d);
10392
+ }
10393
+ if (d.length === 11 && d.startsWith("1")) {
10394
+ return isValidNanpNational10(d.slice(1));
10395
+ }
10396
+ if (d.length === 11 && d.startsWith("0")) {
10397
+ return true;
10398
+ }
10399
+ return false;
10400
+ }
10401
+ if (d.length === 10) {
10402
+ return isValidNanpNational10(d);
10403
+ }
10404
+ if (d.length === 11 && d.startsWith("1")) {
10405
+ return isValidNanpNational10(d.slice(1));
10406
+ }
10407
+ if (d.length === 11 && d.startsWith("0")) {
10408
+ return true;
10409
+ }
10410
+ if (d.length >= 12 && d.length <= 15) {
10411
+ return true;
10412
+ }
10413
+ return false;
10414
+ }
10415
+ function isPhoneNumber(input) {
10416
+ const trimmed = preparePhoneInput(input);
10417
+ if (trimmed === "") {
10418
+ return false;
10419
+ }
10420
+ if (!/^[+\d(]/.test(trimmed)) {
10421
+ return false;
10422
+ }
10423
+ const withoutExt = trimmed.replace(/\s*(ext|extension|x)\s*\d+$/i, "");
10424
+ if (/[a-zA-Z]/.test(withoutExt)) {
10425
+ return false;
10426
+ }
10427
+ const hasPhoneMarker = /[+()\s-]/.test(trimmed);
10428
+ const isPureDotSeparated = /^\d+(\.\d+)+$/.test(trimmed);
10429
+ if (isPureDotSeparated && !hasPhoneMarker) {
10430
+ return false;
10431
+ }
10432
+ const phoneRegex = /^(?:\+?\d{1,4}[\s.-]?)?(?:\(\d{1,4}\)|\d{1,4})[\s.-]?\d{1,4}[\s.-]?\d{1,4}[\s.-]?\d{0,4}(?:\s*(?:ext|x|extension)[\s.]*\d{1,6})?$/i;
10433
+ if (!phoneRegex.test(trimmed)) {
10434
+ return false;
10435
+ }
10436
+ return isPlausiblePhoneDigits(withoutExt);
10437
+ }
10438
+ function normalizePhoneNumber(phone) {
10439
+ const trimmed = preparePhoneInput(phone);
10440
+ const withoutExt = trimmed.replace(/\s*(ext|extension|x)\s*\d+$/i, "");
10441
+ const hasPlus = withoutExt.startsWith("+");
10442
+ const digitsOnly = withoutExt.replace(/\D/g, "");
10443
+ return hasPlus ? `+${digitsOnly}` : digitsOnly;
10444
+ }
10934
10445
 
10935
- // ../../node_modules/@sindresorhus/slugify/index.js
10936
- var decamelize = (string) => {
10937
- return string.replace(/([A-Z]{2,})(\d+)/g, "$1 $2").replace(/([a-z\d]+)([A-Z]{2,})/g, "$1 $2").replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-rt-z\d]+)/g, "$1 $2");
10938
- };
10939
- var removeMootSeparators = (string, separator) => {
10940
- const escapedSeparator = escapeStringRegexp(separator);
10941
- return string.replace(new RegExp(`${escapedSeparator}{2,}`, "g"), separator).replace(new RegExp(`^${escapedSeparator}|${escapedSeparator}$`, "g"), "");
10446
+ // ../../internal/utils/src/punycode.ts
10447
+ var maxInt = 2147483647;
10448
+ var base = 36;
10449
+ var tMin = 1;
10450
+ var tMax = 26;
10451
+ var skew = 38;
10452
+ var damp = 700;
10453
+ var initialBias = 72;
10454
+ var initialN = 128;
10455
+ var delimiter = "-";
10456
+ var regexPunycode = /^xn--/;
10457
+ var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g;
10458
+ var errors = {
10459
+ overflow: "Overflow: input needs wider integers to process",
10460
+ "not-basic": "Illegal input >= 0x80 (not a basic code point)",
10461
+ "invalid-input": "Invalid input"
10942
10462
  };
10943
- var buildPatternSlug = (options) => {
10944
- let negationSetPattern = "a-z\\d";
10945
- negationSetPattern += options.lowercase ? "" : "A-Z";
10946
- if (options.preserveCharacters.length > 0) {
10947
- for (const character of options.preserveCharacters) {
10948
- if (character === options.separator) {
10949
- throw new Error(`The separator character \`${options.separator}\` cannot be included in preserved characters: ${options.preserveCharacters}`);
10950
- }
10951
- negationSetPattern += escapeStringRegexp(character);
10952
- }
10463
+ var baseMinusTMin = base - tMin;
10464
+ var floor = Math.floor;
10465
+ function error(type) {
10466
+ throw new RangeError(errors[type]);
10467
+ }
10468
+ function mapDomain(domain, callback) {
10469
+ const parts = domain.split("@");
10470
+ let result = "";
10471
+ if (parts.length > 1) {
10472
+ result = parts[0] + "@";
10473
+ domain = parts[1];
10953
10474
  }
10954
- return new RegExp(`[^${negationSetPattern}]+`, "g");
10955
- };
10956
- function slugify(string, options) {
10957
- if (typeof string !== "string") {
10958
- throw new TypeError(`Expected a string, got \`${typeof string}\``);
10475
+ domain = domain.replace(regexSeparators, ".");
10476
+ const labels = domain.split(".");
10477
+ const encoded = labels.map(callback).join(".");
10478
+ return result + encoded;
10479
+ }
10480
+ function basicToDigit(codePoint) {
10481
+ if (codePoint >= 48 && codePoint < 58) {
10482
+ return 26 + (codePoint - 48);
10959
10483
  }
10960
- options = __spreadValues({
10961
- separator: "-",
10962
- lowercase: true,
10963
- decamelize: true,
10964
- customReplacements: [],
10965
- preserveLeadingUnderscore: false,
10966
- preserveTrailingDash: false,
10967
- preserveCharacters: []
10968
- }, options);
10969
- const shouldPrependUnderscore = options.preserveLeadingUnderscore && string.startsWith("_");
10970
- const shouldAppendDash = options.preserveTrailingDash && string.endsWith("-");
10971
- const customReplacements = new Map([
10972
- ...overridable_replacements_default,
10973
- ...options.customReplacements
10974
- ]);
10975
- string = transliterate(string, { customReplacements });
10976
- if (options.decamelize) {
10977
- string = decamelize(string);
10484
+ if (codePoint >= 65 && codePoint < 91) {
10485
+ return codePoint - 65;
10978
10486
  }
10979
- const patternSlug = buildPatternSlug(options);
10980
- if (options.lowercase) {
10981
- string = string.toLowerCase();
10487
+ if (codePoint >= 97 && codePoint < 123) {
10488
+ return codePoint - 97;
10982
10489
  }
10983
- string = string.replace(/([a-zA-Z\d]+)'([ts])(\s|$)/g, "$1$2$3");
10984
- string = string.replace(patternSlug, options.separator);
10985
- string = string.replace(/\\/g, "");
10986
- if (options.separator) {
10987
- string = removeMootSeparators(string, options.separator);
10490
+ return base;
10491
+ }
10492
+ function adapt(delta, numPoints, firstTime) {
10493
+ let k4 = 0;
10494
+ delta = firstTime ? floor(delta / damp) : delta >> 1;
10495
+ delta += floor(delta / numPoints);
10496
+ for (
10497
+ ;
10498
+ /* no initialization */
10499
+ delta > baseMinusTMin * tMax >> 1;
10500
+ k4 += base
10501
+ ) {
10502
+ delta = floor(delta / baseMinusTMin);
10988
10503
  }
10989
- if (shouldPrependUnderscore) {
10990
- string = `_${string}`;
10504
+ return floor(k4 + (baseMinusTMin + 1) * delta / (delta + skew));
10505
+ }
10506
+ function decode(input) {
10507
+ const output = [];
10508
+ const inputLength = input.length;
10509
+ let i = 0;
10510
+ let n2 = initialN;
10511
+ let bias2 = initialBias;
10512
+ let basic = input.lastIndexOf(delimiter);
10513
+ if (basic < 0) {
10514
+ basic = 0;
10991
10515
  }
10992
- if (shouldAppendDash) {
10993
- string = `${string}-`;
10516
+ for (let j = 0; j < basic; ++j) {
10517
+ if (input.charCodeAt(j) >= 128) {
10518
+ error("not-basic");
10519
+ }
10520
+ output.push(input.charCodeAt(j));
10994
10521
  }
10995
- return string;
10522
+ for (let index = basic > 0 ? basic + 1 : 0; index < inputLength; ) {
10523
+ const oldi = i;
10524
+ for (let w = 1, k4 = base; ; k4 += base) {
10525
+ if (index >= inputLength) {
10526
+ error("invalid-input");
10527
+ }
10528
+ const digit = basicToDigit(input.charCodeAt(index++));
10529
+ if (digit >= base) {
10530
+ error("invalid-input");
10531
+ }
10532
+ if (digit > floor((maxInt - i) / w)) {
10533
+ error("overflow");
10534
+ }
10535
+ i += digit * w;
10536
+ const t = k4 <= bias2 ? tMin : k4 >= bias2 + tMax ? tMax : k4 - bias2;
10537
+ if (digit < t) {
10538
+ break;
10539
+ }
10540
+ const baseMinusT = base - t;
10541
+ if (w > floor(maxInt / baseMinusT)) {
10542
+ error("overflow");
10543
+ }
10544
+ w *= baseMinusT;
10545
+ }
10546
+ const out = output.length + 1;
10547
+ bias2 = adapt(i - oldi, out, oldi == 0);
10548
+ if (floor(i / out) > maxInt - n2) {
10549
+ error("overflow");
10550
+ }
10551
+ n2 += floor(i / out);
10552
+ i %= out;
10553
+ output.splice(i++, 0, n2);
10554
+ }
10555
+ return String.fromCodePoint(...output);
10556
+ }
10557
+ function toUnicode(input) {
10558
+ return mapDomain(input, function(string) {
10559
+ return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string;
10560
+ });
10996
10561
  }
10997
10562
 
10998
- // ../asset-parse/src/model.ts
10999
- var AssetModel = /* @__PURE__ */ ((AssetModel2) => {
11000
- AssetModel2["Addon"] = "addon";
11001
- AssetModel2["App"] = "app";
11002
- AssetModel2["Bot"] = "bot";
11003
- AssetModel2["BusinessProfile"] = "business-profile";
11004
- AssetModel2["Catalog"] = "catalog";
11005
- AssetModel2["Collection"] = "collection";
11006
- AssetModel2["Channel"] = "channel";
11007
- AssetModel2["Group"] = "group";
11008
- AssetModel2["Post"] = "post";
11009
- AssetModel2["Profile"] = "profile";
11010
- AssetModel2["Short"] = "short";
11011
- AssetModel2["Video"] = "video";
11012
- AssetModel2["Space"] = "space";
11013
- AssetModel2["Issue"] = "issue";
11014
- AssetModel2["PullRequest"] = "pull-request";
11015
- AssetModel2["Discussion"] = "discussion";
11016
- AssetModel2["Repository"] = "repository";
11017
- AssetModel2["Article"] = "Article";
11018
- AssetModel2["Comment"] = "comment";
11019
- AssetModel2["List"] = "list";
11020
- AssetModel2["Subreddit"] = "subreddit";
11021
- AssetModel2["Community"] = "community";
11022
- AssetModel2["MiniApp"] = "mini-app";
11023
- AssetModel2["Developer"] = "developer";
11024
- return AssetModel2;
11025
- })(AssetModel || {});
11026
- function isUrl(input) {
10563
+ // ../../internal/utils/src/url.ts
10564
+ function isEmail(input) {
11027
10565
  if (input.trim() === "") {
11028
10566
  return false;
11029
10567
  }
11030
- if (input.startsWith("/") || input.startsWith("#") || input.startsWith("?") || input.startsWith(".") || !input.includes(".")) {
11031
- return false;
11032
- }
11033
- return URL.canParse(input) || URL.canParse(`https://${input}`);
10568
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
10569
+ return emailRegex.test(input);
11034
10570
  }
11035
- function getNormalizedUrl(input) {
10571
+ function removeHttpProtocol(input) {
10572
+ return input.replace(/^https?:\/\//, "");
10573
+ }
10574
+ function stripDomainWildcardPrefix(domain) {
10575
+ const trimmedDomain = domain.trim();
10576
+ const strippedDomain = trimmedDomain.startsWith("*.") ? trimmedDomain.slice(2) : trimmedDomain;
10577
+ return strippedDomain.length > 0 ? strippedDomain : null;
10578
+ }
10579
+ function getDefangedUrl(input) {
11036
10580
  if (!isUrl(input)) {
11037
- throw new Error(`Invalid URL: ${input}`);
10581
+ console.warn(`[getDefangedUrl] Invalid URL: ${input}, returning input as-is`);
10582
+ return input;
11038
10583
  }
11039
- let url;
11040
- try {
11041
- url = new URL(input);
11042
- } catch (e4) {
11043
- try {
11044
- url = new URL(`https://${input}`);
11045
- } catch (e5) {
11046
- throw new Error(`Invalid URL: ${input}`);
11047
- }
10584
+ return input.replace(/\./g, "[.]").replace(/(https:\/\/)/g, "hxxps://").replace(/(http:\/\/)/g, "hxxp://").replace(/:\/\//g, "[://]");
10585
+ }
10586
+ function getRefangedUrl(input) {
10587
+ return input.replace(/hxxps/gi, "https").replace(/hxxp/gi, "http").replace(/\[:\/{2}\]/g, "://").replace(/\[\.\]/g, ".");
10588
+ }
10589
+ function containsPunycode(url) {
10590
+ return url.indexOf("xn--") !== -1;
10591
+ }
10592
+ function toUnicode2(url) {
10593
+ return toUnicode(url);
10594
+ }
10595
+ function convertHttpsToHttp(url) {
10596
+ if (url.startsWith("https://")) {
10597
+ const httpUrl = new URL(url);
10598
+ httpUrl.protocol = "http:";
10599
+ return httpUrl.toString();
11048
10600
  }
11049
- const normalizedUrl = normalizeUrl(url.toString(), {
11050
- defaultProtocol: "https"
11051
- });
11052
- try {
11053
- return new URL(normalizedUrl);
11054
- } catch (e4) {
11055
- throw new Error(`Invalid URL: ${input}`);
10601
+ throw new Error(`URL is not HTTPS: ${url}`);
10602
+ }
10603
+ function generateCanonicalIPFSUrl(content) {
10604
+ if (!content) {
10605
+ return content;
11056
10606
  }
10607
+ if (content.includes("ipfs.io")) {
10608
+ return content;
10609
+ }
10610
+ if (content.startsWith("Qm") || content.startsWith("bafy")) {
10611
+ return `ipfs.io/ipfs/${content}`;
10612
+ }
10613
+ return content;
11057
10614
  }
11058
- var ensureHttpsPrefix = (url) => {
11059
- if (!url.startsWith("http")) {
11060
- return `https://${url}`;
10615
+ function isWalrusSite(content) {
10616
+ return content.includes(".walrus.site") || content.includes(".walrus.host") || content.includes(".wal.app") || content.includes(".wal.site");
10617
+ }
10618
+ function getFaviconUrl(content) {
10619
+ const normalizedUrl = getNormalizedUrl(content);
10620
+ return `https://icons.duckduckgo.com/ip3/${normalizedUrl.hostname}.ico`;
10621
+ }
10622
+ function sanitizeHttpUrl(value) {
10623
+ if (typeof value !== "string" || value.length === 0) {
10624
+ return null;
11061
10625
  }
11062
- return url.replace(/^https?:\/{1,2}/, "https://");
11063
- };
11064
- function getHostname(input) {
11065
10626
  try {
11066
- return getNormalizedUrl(input).hostname;
10627
+ const parsed = new URL(value);
10628
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
10629
+ return null;
10630
+ }
10631
+ return parsed.toString();
11067
10632
  } catch (e4) {
11068
10633
  return null;
11069
10634
  }
11070
10635
  }
11071
- function getParentDomains(input) {
11072
- const domain = getHostname(input);
11073
- if (!domain) {
11074
- return [];
11075
- }
11076
- const subdomain = tldts.getSubdomain(domain, { mixedInputs: false });
11077
- if (!subdomain) {
11078
- return [domain];
11079
- }
11080
- const domainWithSuffix = tldts.getDomain(domain, { mixedInputs: false });
11081
- if (!domainWithSuffix) {
11082
- return [];
10636
+ var URL_REGEX = /https?:\/\/[^\s"'<>\])]*/g;
10637
+
10638
+ // ../../internal/utils/src/email.ts
10639
+ var email_exports = {};
10640
+ __export(email_exports, {
10641
+ extractTextFromGmailPayload: () => extractTextFromGmailPayload,
10642
+ getDomainFromEmail: () => getDomainFromEmail,
10643
+ getNameFromEmail: () => getNameFromEmail
10644
+ });
10645
+ function getDomainFromEmail(email) {
10646
+ return email.split("@")[1];
10647
+ }
10648
+ function getNameFromEmail(email) {
10649
+ return email.split("@")[0];
10650
+ }
10651
+ function extractTextFromGmailPayload(payload) {
10652
+ var _a;
10653
+ if (!payload) return "";
10654
+ if ((_a = payload.body) == null ? void 0 : _a.data) {
10655
+ if (payload.mimeType === "text/plain" || payload.mimeType === "text/html") {
10656
+ return Buffer.from(payload.body.data, "base64url").toString("utf-8");
10657
+ }
11083
10658
  }
11084
- const parentDomains = [domainWithSuffix];
11085
- const parentDomainParts = subdomain.split(".");
11086
- for (let i = parentDomainParts.length - 1; i >= 0; i--) {
11087
- const parentDomainPart = parentDomainParts.slice(i).join(".");
11088
- parentDomains.push(`${parentDomainPart}.${domainWithSuffix}`);
10659
+ if (payload.parts) {
10660
+ if (payload.mimeType === "multipart/alternative") {
10661
+ const plainTextPart = payload.parts.find((part) => part.mimeType === "text/plain");
10662
+ if (plainTextPart) {
10663
+ return extractTextFromGmailPayload(plainTextPart);
10664
+ }
10665
+ const htmlPart = payload.parts.find((part) => part.mimeType === "text/html");
10666
+ if (htmlPart) {
10667
+ return extractTextFromGmailPayload(htmlPart);
10668
+ }
10669
+ for (const part of payload.parts) {
10670
+ const text = extractTextFromGmailPayload(part);
10671
+ if (text) return text;
10672
+ }
10673
+ }
10674
+ return payload.parts.map((part) => extractTextFromGmailPayload(part)).join("\n");
11089
10675
  }
11090
- return parentDomains.reverse();
10676
+ return "";
11091
10677
  }
11092
- function trimDomainToLevels(domain, options = { levels: 4 }) {
10678
+
10679
+ // ../../internal/utils/src/vercel.ts
10680
+ var vercel_exports = {};
10681
+ __export(vercel_exports, {
10682
+ checkVercelEnv: () => checkVercelEnv
10683
+ });
10684
+ var checkVercelEnv = ({ envs }) => {
11093
10685
  var _a;
11094
- const parsed = tldts.parse(domain);
11095
- const eTLDPlusOne = (_a = parsed.domain) != null ? _a : "";
11096
- const subdomains = domain.replace(/https?:\/\/(www\.)?/, "").split(".");
11097
- const eTLDPlusOneIndex = subdomains.findIndex(
11098
- (_, i) => subdomains.slice(i).join(".") === eTLDPlusOne
11099
- );
11100
- const trimmedSubdomains = subdomains.slice(Math.max(eTLDPlusOneIndex - (options.levels - 1), 0)).join(".");
11101
- return trimmedSubdomains;
11102
- }
10686
+ const vercelEnv = (_a = process.env.VERCEL_ENV) != null ? _a : "development";
10687
+ if (!envs.includes(vercelEnv)) {
10688
+ return {
10689
+ ok: false,
10690
+ message: `Vercel environment is ${vercelEnv}, but expected ${envs.join(" or ")}`
10691
+ };
10692
+ }
10693
+ return { ok: true, message: "" };
10694
+ };
11103
10695
 
11104
- // ../asset-parse/src/phone.ts
11105
- var phone_exports = {};
11106
- __export(phone_exports, {
11107
- PHONE_NUMBER_REGEX: () => PHONE_NUMBER_REGEX,
11108
- isPhoneNumber: () => isPhoneNumber,
11109
- normalizePhoneNumber: () => normalizePhoneNumber
10696
+ // ../../internal/utils/src/delay.ts
10697
+ var delay_exports = {};
10698
+ __export(delay_exports, {
10699
+ delay: () => delay
11110
10700
  });
11111
- var PHONE_NUMBER_REGEX = /(?:\+?\d{1,4}[\s.-]?)?(?:\(\d{1,4}\)|\d{1,4})[\s.-]?\d{1,4}[\s.-]?\d{1,4}[\s.-]?\d{0,4}(?:\s*(?:ext|x|extension)[\s.]*\d{1,6})?/gi;
11112
- function preparePhoneInput(input) {
11113
- let s2 = input.trim();
11114
- s2 = s2.replace(/^\s*tel:\s*(?:\/\/)?\s*/i, "");
11115
- s2 = s2.trim();
11116
- s2 = s2.replace(/[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g, " ");
11117
- s2 = s2.replace(/[\u2010\u2011\u2012\u2013\u2014\u2015\u2212\uFE58\uFE63\uFF0D]/g, "-");
11118
- s2 = s2.replace(/\uFF0B/g, "+");
11119
- s2 = s2.replace(/\uFF08/g, "(");
11120
- s2 = s2.replace(/\uFF09/g, ")");
11121
- return s2.trim();
10701
+ var delay = (ms) => {
10702
+ return new Promise((resolve) => setTimeout(resolve, ms));
10703
+ };
10704
+
10705
+ // ../../internal/utils/src/whois.ts
10706
+ var whois_exports = {};
10707
+ __export(whois_exports, {
10708
+ extractWhoisCountry: () => extractWhoisCountry,
10709
+ extractWhoisPayload: () => extractWhoisPayload,
10710
+ normalizeRegistrar: () => normalizeRegistrar
10711
+ });
10712
+ function extractWhoisPayload(raw) {
10713
+ var _a;
10714
+ const first = Array.isArray(raw) ? (_a = raw.find((entry) => entry !== null && typeof entry === "object")) != null ? _a : {} : raw;
10715
+ if (!first || typeof first !== "object") {
10716
+ return {};
10717
+ }
10718
+ const maybeData = first.data;
10719
+ if (maybeData && typeof maybeData === "object" && !Array.isArray(maybeData)) {
10720
+ return maybeData;
10721
+ }
10722
+ return first;
11122
10723
  }
11123
- function isAllSameDigit(digits2) {
11124
- return /^(\d)\1+$/.test(digits2);
10724
+ var WHOIS_EMPTY_VALUES = /* @__PURE__ */ new Set(["", "none", "null"]);
10725
+ var WHOIS_COUNTRY_CODE_KEY_ALIASES = /* @__PURE__ */ new Set(["countrycode", "registrantcountrycode"]);
10726
+ var WHOIS_COUNTRY_KEY_ALIASES = /* @__PURE__ */ new Set([
10727
+ "country",
10728
+ "countryname",
10729
+ "registrantcountry",
10730
+ "registrantcountryname"
10731
+ ]);
10732
+ function normalizeWhoisKey(key) {
10733
+ return key.toLowerCase().replace(/[^a-z0-9]/g, "");
11125
10734
  }
11126
- function isStrictlyMonotonicStep1(digits2) {
11127
- if (digits2.length < 8) {
11128
- return false;
10735
+ function normalizeRegistrar(value) {
10736
+ return value.toLowerCase().replace(/[^a-z0-9]/g, "");
10737
+ }
10738
+ function parseWhoisString(value) {
10739
+ if (typeof value !== "string") {
10740
+ return void 0;
11129
10741
  }
11130
- let increasing = true;
11131
- let decreasing = true;
11132
- for (let i = 1; i < digits2.length; i++) {
11133
- const curr = digits2.charCodeAt(i) - 48;
11134
- const prev = digits2.charCodeAt(i - 1) - 48;
11135
- if (curr !== prev + 1) {
11136
- increasing = false;
10742
+ const trimmedValue = value.trim();
10743
+ if (WHOIS_EMPTY_VALUES.has(trimmedValue.toLowerCase())) {
10744
+ return void 0;
10745
+ }
10746
+ return trimmedValue;
10747
+ }
10748
+ function extractWhoisFieldByAliases(payload, aliases) {
10749
+ for (const [key, value] of Object.entries(payload)) {
10750
+ if (!aliases.has(normalizeWhoisKey(key))) {
10751
+ continue;
11137
10752
  }
11138
- if (curr !== prev - 1) {
11139
- decreasing = false;
10753
+ const parsedValue = parseWhoisString(value);
10754
+ if (parsedValue) {
10755
+ return parsedValue;
11140
10756
  }
11141
10757
  }
11142
- return increasing || decreasing;
10758
+ return void 0;
11143
10759
  }
11144
- function isValidNanpNational10(d10) {
11145
- if (d10.length !== 10) {
11146
- return false;
11147
- }
11148
- const npaFirst = d10.charCodeAt(0) - 48;
11149
- const nxxFirst = d10.charCodeAt(3) - 48;
11150
- if (npaFirst < 2 || npaFirst > 9) {
11151
- return false;
11152
- }
11153
- if (nxxFirst < 2 || nxxFirst > 9) {
11154
- return false;
10760
+ function extractWhoisCountry(payload) {
10761
+ const countryCode = extractWhoisFieldByAliases(payload, WHOIS_COUNTRY_CODE_KEY_ALIASES);
10762
+ const country = extractWhoisFieldByAliases(payload, WHOIS_COUNTRY_KEY_ALIASES);
10763
+ return {
10764
+ countryCode: countryCode != null ? countryCode : void 0,
10765
+ country: country != null ? country : void 0
10766
+ };
10767
+ }
10768
+
10769
+ // ../../internal/utils/src/safe-preview.ts
10770
+ var safe_preview_exports = {};
10771
+ __export(safe_preview_exports, {
10772
+ buildSafePreviewUrl: () => buildSafePreviewUrl,
10773
+ normalizeSafeNavigationTarget: () => normalizeSafeNavigationTarget
10774
+ });
10775
+ var SAFE_NAVIGATION_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
10776
+ var PREVIEW_PATH = "/preview";
10777
+ var URL_BASE = "https://app.chainpatrol.io";
10778
+ function normalizeSafeNavigationTarget(target) {
10779
+ const normalizedTarget = getNormalizedUrl(target);
10780
+ if (!SAFE_NAVIGATION_PROTOCOLS.has(normalizedTarget.protocol)) {
10781
+ throw new Error(`Unsupported URL protocol: ${normalizedTarget.protocol}`);
11155
10782
  }
11156
- return true;
10783
+ return normalizedTarget;
11157
10784
  }
11158
- function isPlausiblePhoneDigits(withoutExt) {
11159
- const hasPlus = withoutExt.startsWith("+");
11160
- const d = withoutExt.replace(/\D/g, "");
11161
- if (d.length < 8 || d.length > 15) {
11162
- return false;
10785
+ function buildSafePreviewUrl({
10786
+ target,
10787
+ assetId,
10788
+ policy
10789
+ }) {
10790
+ const normalizedTarget = normalizeSafeNavigationTarget(target);
10791
+ const previewUrl = new URL(PREVIEW_PATH, URL_BASE);
10792
+ previewUrl.searchParams.set("target", normalizedTarget.toString());
10793
+ if (Number.isInteger(assetId) && assetId && assetId >= 1) {
10794
+ previewUrl.searchParams.set("asset_id", String(assetId));
11163
10795
  }
11164
- if (isAllSameDigit(d) || isStrictlyMonotonicStep1(d)) {
11165
- return false;
10796
+ if (policy) {
10797
+ previewUrl.searchParams.set("policy", policy);
11166
10798
  }
11167
- const onlyDigits = /^\d+$/.test(withoutExt);
11168
- if (hasPlus) {
11169
- if (d.length === 11 && d.startsWith("1")) {
11170
- return isValidNanpNational10(d.slice(1));
10799
+ return `${previewUrl.pathname}?${previewUrl.searchParams.toString()}`;
10800
+ }
10801
+
10802
+ // ../../internal/utils/src/parse.ts
10803
+ var parse_exports = {};
10804
+ __export(parse_exports, {
10805
+ parseTerms: () => parseTerms,
10806
+ stringifyTerms: () => stringifyTerms
10807
+ });
10808
+ function parseTerms(terms, {
10809
+ forceExact = false
10810
+ } = {}) {
10811
+ if (!terms) return [];
10812
+ return terms.split(",").map((term) => {
10813
+ const trimmed = term.trim();
10814
+ if (!trimmed) return null;
10815
+ const isWrappedExact = trimmed.startsWith("*") && trimmed.endsWith("*") && trimmed.length > 2;
10816
+ if (isWrappedExact) {
10817
+ return {
10818
+ value: trimmed.slice(1, -1).toLowerCase(),
10819
+ type: "exact"
10820
+ };
10821
+ } else {
10822
+ return {
10823
+ value: trimmed.toLowerCase(),
10824
+ type: forceExact ? "exact" : "loose"
10825
+ };
11171
10826
  }
11172
- return true;
10827
+ }).filter((term) => term !== null);
10828
+ }
10829
+ function stringifyTerms(parsedTerms) {
10830
+ return parsedTerms.map((term) => term.type === "exact" ? `*${term.value}*` : term.value).join(", ");
10831
+ }
10832
+
10833
+ // ../../internal/utils/src/brand-pattern.ts
10834
+ var brand_pattern_exports = {};
10835
+ __export(brand_pattern_exports, {
10836
+ anyPatternMatches: () => anyPatternMatches,
10837
+ compileBrandPattern: () => compileBrandPattern,
10838
+ countPatternMatches: () => countPatternMatches,
10839
+ findMatchingPatterns: () => findMatchingPatterns
10840
+ });
10841
+ var DEFAULT_MAX_MATCHES = 50;
10842
+ function compileBrandPattern(input) {
10843
+ var _a;
10844
+ try {
10845
+ return new RegExp(input.pattern, (_a = input.flags) != null ? _a : void 0);
10846
+ } catch (e4) {
10847
+ return null;
11173
10848
  }
11174
- if (onlyDigits) {
11175
- if (d.length === 10) {
11176
- return isValidNanpNational10(d);
11177
- }
11178
- if (d.length === 11 && d.startsWith("1")) {
11179
- return isValidNanpNational10(d.slice(1));
11180
- }
11181
- if (d.length === 11 && d.startsWith("0")) {
10849
+ }
10850
+ function anyPatternMatches(content, patterns, kind) {
10851
+ for (const input of patterns) {
10852
+ if (input.kind !== kind) continue;
10853
+ const regex = compileBrandPattern(input);
10854
+ if (!regex) continue;
10855
+ if (regex.test(content)) {
11182
10856
  return true;
11183
10857
  }
11184
- return false;
11185
10858
  }
11186
- if (d.length === 10) {
11187
- return isValidNanpNational10(d);
10859
+ return false;
10860
+ }
10861
+ function findMatchingPatterns(content, patterns, kind) {
10862
+ const matched = [];
10863
+ for (const input of patterns) {
10864
+ if (input.kind !== kind) continue;
10865
+ const regex = compileBrandPattern(input);
10866
+ if (!regex) continue;
10867
+ if (regex.test(content)) {
10868
+ matched.push(input);
10869
+ }
11188
10870
  }
11189
- if (d.length === 11 && d.startsWith("1")) {
11190
- return isValidNanpNational10(d.slice(1));
10871
+ return matched;
10872
+ }
10873
+ function countPatternMatches(content, pattern, maxMatches = DEFAULT_MAX_MATCHES) {
10874
+ const compiled = compileBrandPattern(pattern);
10875
+ if (!compiled) return 0;
10876
+ const flags = compiled.flags.includes("g") ? compiled.flags : `${compiled.flags}g`;
10877
+ const globalRegex = new RegExp(compiled.source, flags);
10878
+ let count = 0;
10879
+ let match2;
10880
+ while ((match2 = globalRegex.exec(content)) !== null) {
10881
+ count += 1;
10882
+ if (count >= maxMatches) break;
10883
+ if (match2[0].length === 0) globalRegex.lastIndex += 1;
11191
10884
  }
11192
- if (d.length === 11 && d.startsWith("0")) {
11193
- return true;
10885
+ return count;
10886
+ }
10887
+
10888
+ // ../../internal/utils/src/text.ts
10889
+ var text_exports = {};
10890
+ __export(text_exports, {
10891
+ HOMOGLYPH_MAPPINGS: () => HOMOGLYPH_MAPPINGS,
10892
+ LETTER_TO_HOMOGLYPH_MAPPINGS: () => LETTER_TO_HOMOGLYPH_MAPPINGS,
10893
+ generateHomoglyphSearchTerms: () => generateHomoglyphSearchTerms,
10894
+ normalizeHomoglyphs: () => normalizeHomoglyphs
10895
+ });
10896
+ var HOMOGLYPH_MAPPINGS = {
10897
+ "0": "o",
10898
+ "1": "i",
10899
+ "3": "e",
10900
+ "4": "a",
10901
+ "5": "s",
10902
+ "7": "t",
10903
+ "8": "b"
10904
+ };
10905
+ var LETTER_TO_HOMOGLYPH_MAPPINGS = {
10906
+ a: ["4", "\u0430"],
10907
+ b: ["8", "6"],
10908
+ c: ["\u0441"],
10909
+ e: ["3", "\u0435"],
10910
+ g: ["9"],
10911
+ i: ["1", "l", "\u0456"],
10912
+ l: ["1"],
10913
+ o: ["0", "\u043E"],
10914
+ s: ["5", "\u0455"],
10915
+ t: ["7"],
10916
+ x: ["\u0445"],
10917
+ z: ["2"]
10918
+ };
10919
+ var DEFAULT_MAX_HOMOGLYPH_VARIANTS = 20;
10920
+ function isCyrillic(char) {
10921
+ return char.charCodeAt(0) > 127;
10922
+ }
10923
+ function buildReplacementOps(term) {
10924
+ const ops = [];
10925
+ for (let i = 0; i < term.length; i++) {
10926
+ const homoglyphs = LETTER_TO_HOMOGLYPH_MAPPINGS[term[i]];
10927
+ if (!homoglyphs) continue;
10928
+ for (const replacement of homoglyphs) {
10929
+ ops.push({ index: i, replacement });
10930
+ }
11194
10931
  }
11195
- if (d.length >= 12 && d.length <= 15) {
11196
- return true;
10932
+ return ops;
10933
+ }
10934
+ function applyOps(term, ops, selected) {
10935
+ const chars = Array.from(term);
10936
+ for (const idx of selected) {
10937
+ chars[ops[idx].index] = ops[idx].replacement;
11197
10938
  }
11198
- return false;
10939
+ return chars.join("");
11199
10940
  }
11200
- function isPhoneNumber(input) {
11201
- const trimmed = preparePhoneInput(input);
11202
- if (trimmed === "") {
10941
+ function generateCombinations(ops, opIndices, term, maxVariants, addFn, variants) {
10942
+ const generate = (startIdx, depth, selected, usedPositions) => {
10943
+ if (selected.length === depth) return addFn(applyOps(term, ops, selected));
10944
+ for (let i = startIdx; i < opIndices.length && variants.length < maxVariants; i++) {
10945
+ const opIdx = opIndices[i];
10946
+ if (usedPositions.has(ops[opIdx].index)) continue;
10947
+ selected.push(opIdx);
10948
+ usedPositions.add(ops[opIdx].index);
10949
+ if (generate(i + 1, depth, selected, usedPositions)) return true;
10950
+ selected.pop();
10951
+ usedPositions.delete(ops[opIdx].index);
10952
+ }
11203
10953
  return false;
10954
+ };
10955
+ for (let depth = 2; depth <= opIndices.length && variants.length < maxVariants; depth++) {
10956
+ if (generate(0, depth, [], /* @__PURE__ */ new Set())) break;
11204
10957
  }
11205
- if (!/^[+\d(]/.test(trimmed)) {
11206
- return false;
10958
+ }
10959
+ function generateHomoglyphSearchTerms(term, maxVariants = DEFAULT_MAX_HOMOGLYPH_VARIANTS) {
10960
+ if (term.length === 0 || maxVariants <= 0) return [];
10961
+ const lowerTerm = term.toLowerCase();
10962
+ const seen = /* @__PURE__ */ new Set();
10963
+ const variants = [];
10964
+ const add = (v) => {
10965
+ if (v === lowerTerm || seen.has(v)) return false;
10966
+ seen.add(v);
10967
+ variants.push(v);
10968
+ return variants.length >= maxVariants;
10969
+ };
10970
+ const allOps = buildReplacementOps(lowerTerm);
10971
+ for (let i = 0; i < allOps.length && variants.length < maxVariants; i++) {
10972
+ add(applyOps(lowerTerm, allOps, [i]));
11207
10973
  }
11208
- const withoutExt = trimmed.replace(/\s*(ext|extension|x)\s*\d+$/i, "");
11209
- if (/[a-zA-Z]/.test(withoutExt)) {
11210
- return false;
10974
+ if (variants.length < maxVariants) {
10975
+ const cyrillicComposite = lowerTerm.split("").map((char) => {
10976
+ var _a;
10977
+ const homoglyphs = LETTER_TO_HOMOGLYPH_MAPPINGS[char];
10978
+ return (_a = homoglyphs == null ? void 0 : homoglyphs.find((h) => isCyrillic(h))) != null ? _a : char;
10979
+ }).join("");
10980
+ add(cyrillicComposite);
11211
10981
  }
11212
- const hasPhoneMarker = /[+()\s-]/.test(trimmed);
11213
- const isPureDotSeparated = /^\d+(\.\d+)+$/.test(trimmed);
11214
- if (isPureDotSeparated && !hasPhoneMarker) {
11215
- return false;
10982
+ const cyrillicOpIndices = allOps.map((op, i) => isCyrillic(op.replacement) ? i : -1).filter((i) => i >= 0);
10983
+ if (variants.length < maxVariants && cyrillicOpIndices.length >= 2) {
10984
+ generateCombinations(
10985
+ allOps,
10986
+ cyrillicOpIndices,
10987
+ lowerTerm,
10988
+ maxVariants,
10989
+ add,
10990
+ variants
10991
+ );
11216
10992
  }
11217
- const phoneRegex = /^(?:\+?\d{1,4}[\s.-]?)?(?:\(\d{1,4}\)|\d{1,4})[\s.-]?\d{1,4}[\s.-]?\d{1,4}[\s.-]?\d{0,4}(?:\s*(?:ext|x|extension)[\s.]*\d{1,6})?$/i;
11218
- if (!phoneRegex.test(trimmed)) {
11219
- return false;
10993
+ if (variants.length < maxVariants) {
10994
+ const allOpIndices = allOps.map((_, i) => i);
10995
+ generateCombinations(allOps, allOpIndices, lowerTerm, maxVariants, add, variants);
11220
10996
  }
11221
- return isPlausiblePhoneDigits(withoutExt);
10997
+ return variants;
11222
10998
  }
11223
- function normalizePhoneNumber(phone) {
11224
- const trimmed = preparePhoneInput(phone);
11225
- const withoutExt = trimmed.replace(/\s*(ext|extension|x)\s*\d+$/i, "");
11226
- const hasPlus = withoutExt.startsWith("+");
11227
- const digitsOnly = withoutExt.replace(/\D/g, "");
11228
- return hasPlus ? `+${digitsOnly}` : digitsOnly;
10999
+ function normalizeHomoglyphs(text, customMappings = {}) {
11000
+ const mappings = __spreadValues(__spreadValues({}, HOMOGLYPH_MAPPINGS), customMappings);
11001
+ return text.toLowerCase().split("").map((char) => mappings[char] || char).join("");
11229
11002
  }
11230
11003
 
11231
- // ../../internal/utils/src/punycode.ts
11232
- var maxInt = 2147483647;
11233
- var base = 36;
11234
- var tMin = 1;
11235
- var tMax = 26;
11236
- var skew = 38;
11237
- var damp = 700;
11238
- var initialBias = 72;
11239
- var initialN = 128;
11240
- var delimiter = "-";
11241
- var regexPunycode = /^xn--/;
11242
- var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g;
11243
- var errors = {
11244
- overflow: "Overflow: input needs wider integers to process",
11245
- "not-basic": "Illegal input >= 0x80 (not a basic code point)",
11246
- "invalid-input": "Invalid input"
11247
- };
11248
- var baseMinusTMin = base - tMin;
11249
- var floor = Math.floor;
11250
- function error(type) {
11251
- throw new RangeError(errors[type]);
11252
- }
11253
- function mapDomain(domain, callback) {
11254
- const parts = domain.split("@");
11255
- let result = "";
11256
- if (parts.length > 1) {
11257
- result = parts[0] + "@";
11258
- domain = parts[1];
11004
+ // ../../internal/utils/src/format.ts
11005
+ var format_exports = {};
11006
+ __export(format_exports, {
11007
+ formatCompactNumber: () => formatCompactNumber,
11008
+ formatFileSize: () => formatFileSize
11009
+ });
11010
+ function formatCompactNumber(num3, options = {}) {
11011
+ const { decimals = 1, fallback = "-" } = options;
11012
+ if (num3 === void 0 || num3 === null) {
11013
+ return fallback;
11259
11014
  }
11260
- domain = domain.replace(regexSeparators, ".");
11261
- const labels = domain.split(".");
11262
- const encoded = labels.map(callback).join(".");
11263
- return result + encoded;
11015
+ if (num3 >= 1e9) {
11016
+ return `${(num3 / 1e9).toFixed(decimals)}B`;
11017
+ }
11018
+ if (num3 >= 1e6) {
11019
+ return `${(num3 / 1e6).toFixed(decimals)}M`;
11020
+ }
11021
+ if (num3 >= 1e3) {
11022
+ return `${(num3 / 1e3).toFixed(decimals)}K`;
11023
+ }
11024
+ return num3.toString();
11264
11025
  }
11265
- function basicToDigit(codePoint) {
11266
- if (codePoint >= 48 && codePoint < 58) {
11267
- return 26 + (codePoint - 48);
11026
+ function formatFileSize(bytes, options = {}) {
11027
+ const { decimals = 1, binary = true, showUnknown = true } = options;
11028
+ if (bytes === null || bytes === void 0 || bytes === "") {
11029
+ return showUnknown ? "Unknown" : "0 B";
11268
11030
  }
11269
- if (codePoint >= 65 && codePoint < 91) {
11270
- return codePoint - 65;
11031
+ const size = typeof bytes === "string" ? parseInt(bytes, 10) : bytes;
11032
+ if (isNaN(size) || size < 0) {
11033
+ return showUnknown ? "Unknown" : "0 B";
11271
11034
  }
11272
- if (codePoint >= 97 && codePoint < 123) {
11273
- return codePoint - 97;
11035
+ if (size === 0) {
11036
+ return "0 B";
11274
11037
  }
11275
- return base;
11276
- }
11277
- function adapt(delta, numPoints, firstTime) {
11278
- let k4 = 0;
11279
- delta = firstTime ? floor(delta / damp) : delta >> 1;
11280
- delta += floor(delta / numPoints);
11281
- for (
11282
- ;
11283
- /* no initialization */
11284
- delta > baseMinusTMin * tMax >> 1;
11285
- k4 += base
11286
- ) {
11287
- delta = floor(delta / baseMinusTMin);
11038
+ const unit = binary ? 1024 : 1e3;
11039
+ const units = binary ? ["B", "KB", "MB", "GB", "TB", "PB"] : ["B", "kB", "MB", "GB", "TB", "PB"];
11040
+ const unitIndex = Math.floor(Math.log(size) / Math.log(unit));
11041
+ const finalUnitIndex = Math.min(unitIndex, units.length - 1);
11042
+ const value = size / Math.pow(unit, finalUnitIndex);
11043
+ if (finalUnitIndex === 0) {
11044
+ return `${size} B`;
11288
11045
  }
11289
- return floor(k4 + (baseMinusTMin + 1) * delta / (delta + skew));
11046
+ return `${value.toFixed(decimals)} ${units[finalUnitIndex]}`;
11290
11047
  }
11291
- function decode(input) {
11292
- const output = [];
11293
- const inputLength = input.length;
11294
- let i = 0;
11295
- let n2 = initialN;
11296
- let bias2 = initialBias;
11297
- let basic = input.lastIndexOf(delimiter);
11298
- if (basic < 0) {
11299
- basic = 0;
11300
- }
11301
- for (let j = 0; j < basic; ++j) {
11302
- if (input.charCodeAt(j) >= 128) {
11303
- error("not-basic");
11304
- }
11305
- output.push(input.charCodeAt(j));
11048
+
11049
+ // ../../internal/utils/src/social-profile-url.ts
11050
+ var social_profile_url_exports = {};
11051
+ __export(social_profile_url_exports, {
11052
+ LINKEDIN_PROFILE_URL_PATTERN: () => LINKEDIN_PROFILE_URL_PATTERN,
11053
+ TWITTER_PROFILE_URL_PATTERN: () => TWITTER_PROFILE_URL_PATTERN,
11054
+ isLinkedInProfileUrl: () => isLinkedInProfileUrl,
11055
+ isSupportedSocialProfileUrl: () => isSupportedSocialProfileUrl,
11056
+ isTwitterProfileUrl: () => isTwitterProfileUrl,
11057
+ parseLinkedInProfileUrl: () => parseLinkedInProfileUrl
11058
+ });
11059
+ var TWITTER_PROFILE_URL_PATTERN = /^https?:\/\/(?:www\.)?(?:twitter\.com|x\.com)\/[^/?#]+\/?(?:[?#].*)?$/i;
11060
+ var LINKEDIN_PROFILE_URL_PATTERN = /^https?:\/\/(?:[a-z]{2,3}\.)?linkedin\.com\/(in|company|school)\/([^/?#]+)/i;
11061
+ function isTwitterProfileUrl(url) {
11062
+ return TWITTER_PROFILE_URL_PATTERN.test(url);
11063
+ }
11064
+ function isLinkedInProfileUrl(url) {
11065
+ return LINKEDIN_PROFILE_URL_PATTERN.test(url);
11066
+ }
11067
+ function isSupportedSocialProfileUrl(url) {
11068
+ return isTwitterProfileUrl(url) || isLinkedInProfileUrl(url);
11069
+ }
11070
+ function humanizeLinkedInHandle(handle) {
11071
+ const withoutTrailingDigits = handle.replace(/-[0-9a-f]{6,}$/i, "");
11072
+ return withoutTrailingDigits.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
11073
+ }
11074
+ function parseLinkedInProfileUrl(url) {
11075
+ var _a;
11076
+ const match2 = url.match(LINKEDIN_PROFILE_URL_PATTERN);
11077
+ if (!match2) return null;
11078
+ const pathSegment = (_a = match2[1]) == null ? void 0 : _a.toLowerCase();
11079
+ const rawHandle = match2[2];
11080
+ if (!pathSegment || !rawHandle) return null;
11081
+ let handle;
11082
+ try {
11083
+ handle = decodeURIComponent(rawHandle).trim();
11084
+ } catch (e4) {
11085
+ return null;
11306
11086
  }
11307
- for (let index = basic > 0 ? basic + 1 : 0; index < inputLength; ) {
11308
- const oldi = i;
11309
- for (let w = 1, k4 = base; ; k4 += base) {
11310
- if (index >= inputLength) {
11311
- error("invalid-input");
11312
- }
11313
- const digit = basicToDigit(input.charCodeAt(index++));
11314
- if (digit >= base) {
11315
- error("invalid-input");
11316
- }
11317
- if (digit > floor((maxInt - i) / w)) {
11318
- error("overflow");
11319
- }
11320
- i += digit * w;
11321
- const t = k4 <= bias2 ? tMin : k4 >= bias2 + tMax ? tMax : k4 - bias2;
11322
- if (digit < t) {
11323
- break;
11324
- }
11325
- const baseMinusT = base - t;
11326
- if (w > floor(maxInt / baseMinusT)) {
11327
- error("overflow");
11328
- }
11329
- w *= baseMinusT;
11330
- }
11331
- const out = output.length + 1;
11332
- bias2 = adapt(i - oldi, out, oldi == 0);
11333
- if (floor(i / out) > maxInt - n2) {
11334
- error("overflow");
11335
- }
11336
- n2 += floor(i / out);
11337
- i %= out;
11338
- output.splice(i++, 0, n2);
11087
+ if (!handle) return null;
11088
+ const name = humanizeLinkedInHandle(handle) || handle;
11089
+ const profileUrl = `https://www.linkedin.com/${pathSegment}/${handle}`;
11090
+ return { pathSegment, handle, name, profileUrl };
11091
+ }
11092
+
11093
+ // ../../internal/validation/src/public/detection/configs-create.ts
11094
+ zod.z.object({
11095
+ slug: zod.z.string().min(1).optional().describe(
11096
+ "Organization slug. Defaults to the organization your API key is scoped to, so you only need this when authenticating with a key that spans organizations."
11097
+ ),
11098
+ source: zod.z.nativeEnum(ThreatDetectionSourceKey).describe(
11099
+ "Detection source key, from `GET /detection/sources`. The source must support the `organization` scope; global-only sources cannot be configured per organization."
11100
+ ),
11101
+ status: zod.z.nativeEnum(ThreatDetectionConfigStatus).default(ThreatDetectionConfigStatus.ENABLED).describe("Status to create the config with. Defaults to `ENABLED`."),
11102
+ title: zod.z.string().trim().optional().describe("Optional label for this config"),
11103
+ description: zod.z.string().trim().nullable().optional().describe("Optional human-readable description of what the config does"),
11104
+ cron: zod.z.string().trim().nullable().optional().describe(
11105
+ "Optional custom CRON schedule. Only accepted for sources that run on a schedule; the source's default schedule is used when omitted."
11106
+ ),
11107
+ config: zod.z.record(zod.z.unknown()).optional().describe(
11108
+ "Source-specific configuration, validated against that source's `configSchema` from `GET /detection/sources`. When omitted the source's schema defaults are applied."
11109
+ ),
11110
+ brandId: zod.z.number().int().positive().nullable().optional().describe(
11111
+ "Optional brand to scope this config to. The brand must belong to the same organization. Omit for an organization-wide config."
11112
+ )
11113
+ }).describe(
11114
+ `Create a threat detection config
11115
+
11116
+ Creates the config row that makes a detection source run for your organization. Sources that are disabled by default have no config row, so they cannot be enabled through \`/detection/configs/update\` until one exists.
11117
+
11118
+ A source can have several configs, each scanning with its own query, schedule or brand. Use \`title\` to tell them apart.`
11119
+ );
11120
+ zod.z.object({
11121
+ config: zod.z.object({
11122
+ id: zod.z.number(),
11123
+ source: zod.z.string(),
11124
+ status: zod.z.nativeEnum(ThreatDetectionConfigStatus),
11125
+ title: zod.z.string(),
11126
+ description: zod.z.string().nullable(),
11127
+ cron: zod.z.string().nullable(),
11128
+ config: zod.z.record(zod.z.unknown()),
11129
+ updatedAt: zod.z.date(),
11130
+ brandId: zod.z.number().nullable()
11131
+ })
11132
+ }).describe("Created detection config");
11133
+ zod.z.object({
11134
+ slug: zod.z.string().min(1).optional().describe(
11135
+ "Organization slug. Defaults to the organization your API key is scoped to, so you only need this when authenticating with a key that spans organizations."
11136
+ ),
11137
+ configId: zod.z.number().int().positive().describe("ID of the config to delete, from `/detection/configs/list`")
11138
+ }).describe(
11139
+ `Delete a threat detection config
11140
+
11141
+ Deletes one detection config so it stops scanning. Deleting a config that shares a source with others leaves the others running.
11142
+
11143
+ Deleting the *last* config for a source that is enabled by default for your organization is not permanent: automation re-creates a default config for that source on its next run. To stop such a source durably, set \`status\` to \`DISABLED\` through \`/detection/configs/update\` instead, which automation will not override.`
11144
+ );
11145
+ zod.z.object({
11146
+ success: zod.z.boolean(),
11147
+ id: zod.z.number().describe("ID of the deleted config")
11148
+ }).describe("Deleted detection config");
11149
+ zod.z.object({
11150
+ slug: zod.z.string().min(1),
11151
+ configId: zod.z.number().int().positive(),
11152
+ status: zod.z.nativeEnum(ThreatDetectionConfigStatus).optional(),
11153
+ title: zod.z.string().trim().optional(),
11154
+ description: zod.z.string().trim().nullable().optional(),
11155
+ cron: zod.z.string().trim().nullable().optional(),
11156
+ config: zod.z.record(zod.z.unknown()).optional(),
11157
+ mergeConfig: zod.z.boolean().default(false),
11158
+ brandId: zod.z.number().int().positive().nullable().optional().describe(
11159
+ "Optional brand connection for this detection config. Pass null to clear the link. Only valid for org-scoped configs; the brand must belong to the same organization."
11160
+ )
11161
+ });
11162
+ zod.z.object({
11163
+ config: zod.z.object({
11164
+ id: zod.z.number(),
11165
+ source: zod.z.string(),
11166
+ status: zod.z.nativeEnum(ThreatDetectionConfigStatus),
11167
+ title: zod.z.string(),
11168
+ description: zod.z.string().nullable(),
11169
+ cron: zod.z.string().nullable(),
11170
+ config: zod.z.record(zod.z.unknown()),
11171
+ updatedAt: zod.z.date(),
11172
+ brandId: zod.z.number().nullable()
11173
+ })
11174
+ });
11175
+ zod.z.object({
11176
+ slug: zod.z.string().min(1),
11177
+ source: zod.z.string().optional(),
11178
+ minResults: zod.z.number().int().min(0).default(1),
11179
+ lookbackHours: zod.z.number().int().min(1).default(24 * 7),
11180
+ runBeforeValidate: zod.z.boolean().default(false),
11181
+ includeDisabled: zod.z.boolean().default(false)
11182
+ });
11183
+ zod.z.object({
11184
+ ok: zod.z.boolean(),
11185
+ summary: zod.z.object({
11186
+ checkedConfigs: zod.z.number(),
11187
+ passingConfigs: zod.z.number(),
11188
+ failingConfigs: zod.z.number(),
11189
+ lookbackHours: zod.z.number(),
11190
+ minResults: zod.z.number()
11191
+ }),
11192
+ validations: zod.z.array(
11193
+ zod.z.object({
11194
+ configId: zod.z.number(),
11195
+ source: zod.z.string(),
11196
+ status: zod.z.nativeEnum(ThreatDetectionConfigStatus),
11197
+ ran: zod.z.boolean(),
11198
+ runOk: zod.z.boolean(),
11199
+ runMessage: zod.z.string().nullable(),
11200
+ recentResultCount: zod.z.number(),
11201
+ valid: zod.z.boolean()
11202
+ })
11203
+ )
11204
+ });
11205
+ zod.z.object({
11206
+ slug: zod.z.string().min(1),
11207
+ configId: zod.z.number().int().positive().optional(),
11208
+ source: zod.z.string().min(1).optional(),
11209
+ includeDisabled: zod.z.boolean().default(false)
11210
+ });
11211
+ zod.z.object({
11212
+ ranCount: zod.z.number(),
11213
+ successCount: zod.z.number(),
11214
+ failedCount: zod.z.number(),
11215
+ results: zod.z.array(
11216
+ zod.z.object({
11217
+ configId: zod.z.number(),
11218
+ source: zod.z.string(),
11219
+ ok: zod.z.boolean(),
11220
+ message: zod.z.string().nullable(),
11221
+ assetsCount: zod.z.number()
11222
+ })
11223
+ )
11224
+ });
11225
+ zod.z.object({
11226
+ slug: zod.z.string().min(1).optional().describe(
11227
+ "Organization slug. Defaults to the organization your API key is scoped to, so you only need this when authenticating with a key that spans organizations. Sources that do not apply to the organization's industry are omitted."
11228
+ )
11229
+ }).describe(
11230
+ `List available threat detection sources
11231
+
11232
+ Returns the catalog of detection sources ChainPatrol can run, including the scopes each source supports and the JSON Schema its \`config\` object must satisfy. Use this to discover valid \`source\` keys before creating or updating a detection config.`
11233
+ );
11234
+ var detectionSourceSchema = zod.z.object({
11235
+ key: zod.z.string().describe("Detection source key (e.g. google_search, certstream, dns_twist)"),
11236
+ label: zod.z.string().describe("Human-readable source name"),
11237
+ description: zod.z.string().describe("What this source detects"),
11238
+ scopes: zod.z.array(zod.z.nativeEnum(ThreatDetectionScope)).describe(
11239
+ "Scopes this source supports. A source without `organization` cannot be configured per-org and runs globally for all organizations."
11240
+ ),
11241
+ isPullBased: zod.z.boolean().describe(
11242
+ "Whether the source runs on a schedule (pull-based). Push-based sources such as webhooks ignore `cron` and cannot be run on demand."
11243
+ ),
11244
+ brandScope: zod.z.enum(["organization_only", "all_brands"]).describe(
11245
+ "Which brands this source fans out to. `organization_only` sources only use brands of type `ORGANIZATION`; `all_brands` sources use every brand in the organization."
11246
+ ),
11247
+ industries: zod.z.array(zod.z.string()).describe(
11248
+ "Industries this source applies to. Empty means it applies to every industry."
11249
+ ),
11250
+ protectedAssetTypes: zod.z.array(zod.z.string()).describe(
11251
+ "Asset types this source monitors. Empty when the source does not key off protected assets."
11252
+ ),
11253
+ configSchema: zod.z.record(zod.z.unknown()).nullable().describe(
11254
+ "JSON Schema for this source's `config` object, for use with `/detection/configs/update`. `null` when the source takes no configuration."
11255
+ )
11256
+ });
11257
+ zod.z.object({
11258
+ sources: zod.z.array(detectionSourceSchema).describe("Available detection sources")
11259
+ }).describe("Successful operation");
11260
+ var DetectionDriftThresholdsSchema = zod.z.object({
11261
+ zeroResultsMaxHours: zod.z.number().int().positive().default(72),
11262
+ noisyResultsPerDay: zod.z.number().positive().default(100),
11263
+ noisyAllowedRatioThreshold: zod.z.number().min(0).max(1).default(0.6),
11264
+ staleConfigDays: zod.z.number().int().positive().default(30)
11265
+ });
11266
+ zod.z.object({
11267
+ slug: zod.z.string().min(1),
11268
+ lookbackHours: zod.z.number().int().positive().default(168),
11269
+ startDate: zod.z.date().optional(),
11270
+ endDate: zod.z.date().optional(),
11271
+ source: zod.z.string().min(1).optional(),
11272
+ configIds: zod.z.array(zod.z.number().int().positive()).optional(),
11273
+ includeDisabled: zod.z.boolean().default(false),
11274
+ thresholds: DetectionDriftThresholdsSchema.optional()
11275
+ }).refine(
11276
+ (value) => !value.startDate && !value.endDate || Boolean(value.startDate) && Boolean(value.endDate),
11277
+ {
11278
+ message: "Provide both startDate and endDate when using explicit date range",
11279
+ path: ["startDate"]
11339
11280
  }
11340
- return String.fromCodePoint(...output);
11341
- }
11342
- function toUnicode(input) {
11343
- return mapDomain(input, function(string) {
11344
- return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string;
11345
- });
11346
- }
11281
+ );
11282
+ var DetectionDriftSignalSchema = zod.z.object({
11283
+ signal: zod.z.enum(["zero_results_too_long", "noisy_source", "stale_query"]),
11284
+ configId: zod.z.number().int().positive(),
11285
+ source: zod.z.string(),
11286
+ title: zod.z.string().nullable(),
11287
+ status: zod.z.string(),
11288
+ severity: zod.z.enum(["low", "medium", "high"]),
11289
+ details: zod.z.record(zod.z.unknown())
11290
+ });
11291
+ zod.z.object({
11292
+ ok: zod.z.boolean(),
11293
+ range: zod.z.object({
11294
+ startDate: zod.z.date(),
11295
+ endDate: zod.z.date(),
11296
+ lookbackHours: zod.z.number().int().positive()
11297
+ }),
11298
+ thresholds: DetectionDriftThresholdsSchema,
11299
+ summary: zod.z.object({
11300
+ checkedConfigs: zod.z.number().int().nonnegative(),
11301
+ signalCount: zod.z.number().int().nonnegative(),
11302
+ zeroResultsCount: zod.z.number().int().nonnegative(),
11303
+ noisyCount: zod.z.number().int().nonnegative(),
11304
+ staleCount: zod.z.number().int().nonnegative()
11305
+ }),
11306
+ signals: zod.z.array(DetectionDriftSignalSchema)
11307
+ });
11308
+ var BucketsSchema = zod.z.object({
11309
+ lt24h: zod.z.number().int().nonnegative(),
11310
+ h24to72: zod.z.number().int().nonnegative(),
11311
+ h72to168: zod.z.number().int().nonnegative(),
11312
+ gte168h: zod.z.number().int().nonnegative()
11313
+ });
11314
+ zod.z.object({
11315
+ slug: zod.z.string().min(1).optional(),
11316
+ all: zod.z.boolean().default(false),
11317
+ windowHours: zod.z.number().int().positive().default(168)
11318
+ });
11319
+ zod.z.object({
11320
+ generatedAt: zod.z.date(),
11321
+ scope: zod.z.object({
11322
+ slug: zod.z.string().nullable(),
11323
+ all: zod.z.boolean()
11324
+ }),
11325
+ reviewQueue: zod.z.object({
11326
+ totalPendingProposals: zod.z.number().int().nonnegative(),
11327
+ distinctReports: zod.z.number().int().nonnegative(),
11328
+ ageBuckets: BucketsSchema,
11329
+ slaBuckets: zod.z.object({
11330
+ breached: zod.z.number().int().nonnegative(),
11331
+ dueWithin24h: zod.z.number().int().nonnegative(),
11332
+ dueWithin72h: zod.z.number().int().nonnegative(),
11333
+ beyond72h: zod.z.number().int().nonnegative(),
11334
+ missingSla: zod.z.number().int().nonnegative()
11335
+ }),
11336
+ byOrg: zod.z.array(
11337
+ zod.z.object({
11338
+ slug: zod.z.string(),
11339
+ pendingProposals: zod.z.number().int().nonnegative()
11340
+ })
11341
+ )
11342
+ }),
11343
+ takedownQueue: zod.z.object({
11344
+ totalOpen: zod.z.number().int().nonnegative(),
11345
+ statusCounts: zod.z.object({
11346
+ todo: zod.z.number().int().nonnegative(),
11347
+ inProgress: zod.z.number().int().nonnegative(),
11348
+ pendingInput: zod.z.number().int().nonnegative()
11349
+ }),
11350
+ ageBuckets: BucketsSchema,
11351
+ staleInProgress: zod.z.number().int().nonnegative(),
11352
+ byOrg: zod.z.array(
11353
+ zod.z.object({
11354
+ slug: zod.z.string(),
11355
+ openTakedowns: zod.z.number().int().nonnegative()
11356
+ })
11357
+ )
11358
+ })
11359
+ });
11360
+ var HealthcheckCategorySchema = zod.z.enum([
11361
+ "detection",
11362
+ "reviewing",
11363
+ "blocklisting",
11364
+ "takedowns",
11365
+ "assets",
11366
+ "organization"
11367
+ ]);
11368
+ var HealthcheckSeveritySchema = zod.z.enum(["ok", "warn", "fail"]);
11369
+ var HealthcheckFindingSchema = zod.z.object({
11370
+ kind: zod.z.string(),
11371
+ ref: zod.z.string().nullable(),
11372
+ message: zod.z.string(),
11373
+ severity: zod.z.enum(["warn", "fail"])
11374
+ });
11375
+ zod.z.object({
11376
+ id: zod.z.string(),
11377
+ title: zod.z.string(),
11378
+ category: HealthcheckCategorySchema,
11379
+ generatedAt: zod.z.date(),
11380
+ scope: zod.z.object({
11381
+ slug: zod.z.string().nullable()
11382
+ }),
11383
+ ok: zod.z.boolean(),
11384
+ severity: HealthcheckSeveritySchema,
11385
+ observed: zod.z.record(zod.z.union([zod.z.number(), zod.z.string(), zod.z.boolean()]).nullable()),
11386
+ threshold: zod.z.record(zod.z.union([zod.z.number(), zod.z.string(), zod.z.boolean()]).nullable()),
11387
+ findings: zod.z.array(HealthcheckFindingSchema),
11388
+ suggestedAction: zod.z.string().nullable(),
11389
+ appUrl: zod.z.string().nullable()
11390
+ });
11347
11391
 
11348
- // ../../internal/utils/src/url.ts
11349
- function isEmail(input) {
11350
- if (input.trim() === "") {
11351
- return false;
11352
- }
11353
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
11354
- return emailRegex.test(input);
11355
- }
11356
- function removeHttpProtocol(input) {
11357
- return input.replace(/^https?:\/\//, "");
11358
- }
11359
- function stripDomainWildcardPrefix(domain) {
11360
- const trimmedDomain = domain.trim();
11361
- const strippedDomain = trimmedDomain.startsWith("*.") ? trimmedDomain.slice(2) : trimmedDomain;
11362
- return strippedDomain.length > 0 ? strippedDomain : null;
11363
- }
11364
- function getDefangedUrl(input) {
11365
- if (!isUrl(input)) {
11366
- console.warn(`[getDefangedUrl] Invalid URL: ${input}, returning input as-is`);
11367
- return input;
11368
- }
11369
- return input.replace(/\./g, "[.]").replace(/(https:\/\/)/g, "hxxps://").replace(/(http:\/\/)/g, "hxxp://").replace(/:\/\//g, "[://]");
11370
- }
11371
- function getRefangedUrl(input) {
11372
- return input.replace(/hxxps/gi, "https").replace(/hxxp/gi, "http").replace(/\[:\/{2}\]/g, "://").replace(/\[\.\]/g, ".");
11373
- }
11374
- function containsPunycode(url) {
11375
- return url.indexOf("xn--") !== -1;
11376
- }
11377
- function toUnicode2(url) {
11378
- return toUnicode(url);
11379
- }
11380
- function convertHttpsToHttp(url) {
11381
- if (url.startsWith("https://")) {
11382
- const httpUrl = new URL(url);
11383
- httpUrl.protocol = "http:";
11384
- return httpUrl.toString();
11385
- }
11386
- throw new Error(`URL is not HTTPS: ${url}`);
11387
- }
11388
- function generateCanonicalIPFSUrl(content) {
11389
- if (!content) {
11390
- return content;
11391
- }
11392
- if (content.includes("ipfs.io")) {
11393
- return content;
11394
- }
11395
- if (content.startsWith("Qm") || content.startsWith("bafy")) {
11396
- return `ipfs.io/ipfs/${content}`;
11397
- }
11398
- return content;
11399
- }
11400
- function isWalrusSite(content) {
11401
- return content.includes(".walrus.site") || content.includes(".walrus.host") || content.includes(".wal.app") || content.includes(".wal.site");
11402
- }
11403
- function getFaviconUrl(content) {
11404
- const normalizedUrl = getNormalizedUrl(content);
11405
- return `https://icons.duckduckgo.com/ip3/${normalizedUrl.hostname}.ico`;
11406
- }
11407
- function sanitizeHttpUrl(value) {
11408
- if (typeof value !== "string" || value.length === 0) {
11409
- return null;
11392
+ // ../../internal/validation/src/public/healthchecks/assets-dead-asset-spike.ts
11393
+ zod.z.object({
11394
+ slug: zod.z.string().min(1),
11395
+ windowHours: zod.z.number().int().positive().default(24),
11396
+ baselineDays: zod.z.number().int().positive().default(7),
11397
+ warnMultiplier: zod.z.number().positive().default(2),
11398
+ failMultiplier: zod.z.number().positive().default(4),
11399
+ minSpikeCount: zod.z.number().int().min(1).default(10)
11400
+ });
11401
+ zod.z.object({});
11402
+ var HealthcheckRegistryEntrySchema = zod.z.object({
11403
+ id: zod.z.string(),
11404
+ title: zod.z.string(),
11405
+ description: zod.z.string(),
11406
+ category: HealthcheckCategorySchema,
11407
+ implemented: zod.z.boolean(),
11408
+ endpoint: zod.z.string().nullable(),
11409
+ defaultThreshold: zod.z.record(zod.z.union([zod.z.number(), zod.z.string()])).optional(),
11410
+ notImplementedReason: zod.z.string().optional()
11411
+ });
11412
+ zod.z.object({
11413
+ checks: zod.z.array(HealthcheckRegistryEntrySchema)
11414
+ });
11415
+ zod.z.object({
11416
+ slug: zod.z.string().min(1)
11417
+ });
11418
+ zod.z.object({
11419
+ slug: zod.z.string().min(1),
11420
+ warnThreshold: zod.z.number().int().nonnegative().default(50),
11421
+ failThreshold: zod.z.number().int().nonnegative().default(100)
11422
+ });
11423
+ zod.z.object({
11424
+ slug: zod.z.string().min(1),
11425
+ warnAgeHours: zod.z.number().int().positive().default(24 * 7),
11426
+ failAgeHours: zod.z.number().int().positive().default(24 * 14)
11427
+ });
11428
+ zod.z.object({
11429
+ slug: zod.z.string().min(1),
11430
+ warnAgeHours: zod.z.number().int().nonnegative().default(24 * 30),
11431
+ failAgeHours: zod.z.number().int().nonnegative().default(24 * 60)
11432
+ });
11433
+ zod.z.object({
11434
+ slug: zod.z.string().min(1),
11435
+ lookbackHours: zod.z.number().int().positive().default(24 * 7),
11436
+ warnThreshold: zod.z.number().int().nonnegative().default(3),
11437
+ failThreshold: zod.z.number().int().nonnegative().default(10)
11438
+ });
11439
+ zod.z.object({
11440
+ slug: zod.z.string().min(1),
11441
+ warnThreshold: zod.z.number().int().nonnegative().default(30),
11442
+ failThreshold: zod.z.number().int().nonnegative().default(75)
11443
+ });
11444
+ zod.z.object({
11445
+ slug: zod.z.string().min(1),
11446
+ staleThresholdHours: zod.z.number().int().positive().default(24 * 7),
11447
+ warnThreshold: zod.z.number().int().nonnegative().default(1),
11448
+ failThreshold: zod.z.number().int().nonnegative().default(5)
11449
+ });
11450
+ zod.z.object({
11451
+ slug: zod.z.string().min(1),
11452
+ warnThreshold: zod.z.number().int().nonnegative().default(50),
11453
+ failThreshold: zod.z.number().int().nonnegative().default(100)
11454
+ });
11455
+ var BreakdownBySchema = zod.z.enum(["day", "type", "brand"]);
11456
+ zod.z.object({
11457
+ slug: zod.z.string().min(1),
11458
+ by: BreakdownBySchema,
11459
+ startDate: zod.z.date().optional(),
11460
+ endDate: zod.z.date().optional(),
11461
+ brandIds: zod.z.array(zod.z.number().int().positive()).optional()
11462
+ });
11463
+ zod.z.object({
11464
+ by: BreakdownBySchema,
11465
+ points: zod.z.array(
11466
+ zod.z.object({
11467
+ key: zod.z.string(),
11468
+ count: zod.z.number(),
11469
+ date: zod.z.string().optional(),
11470
+ type: zod.z.string().optional(),
11471
+ brandId: zod.z.number().optional(),
11472
+ brandSlug: zod.z.string().optional(),
11473
+ brandName: zod.z.string().optional()
11474
+ })
11475
+ )
11476
+ });
11477
+ zod.z.object({
11478
+ slug: zod.z.string().min(1),
11479
+ startDate: zod.z.date(),
11480
+ endDate: zod.z.date(),
11481
+ brandIds: zod.z.array(zod.z.number().int().positive()).optional()
11482
+ });
11483
+ zod.z.object({
11484
+ metric: zod.z.literal("new_threats"),
11485
+ found: zod.z.number(),
11486
+ range: zod.z.object({
11487
+ startDate: zod.z.date(),
11488
+ endDate: zod.z.date()
11489
+ })
11490
+ });
11491
+ zod.z.object({
11492
+ slug: zod.z.string().min(1),
11493
+ startDate: zod.z.date().optional(),
11494
+ endDate: zod.z.date().optional(),
11495
+ brandIds: zod.z.array(zod.z.number().int().positive()).optional()
11496
+ });
11497
+ zod.z.object({
11498
+ metrics: zod.z.object({
11499
+ reports: zod.z.number(),
11500
+ newThreats: zod.z.number(),
11501
+ threatsWatchlisted: zod.z.number(),
11502
+ takedownsFiled: zod.z.number(),
11503
+ takedownsCompleted: zod.z.number(),
11504
+ domainThreats: zod.z.number(),
11505
+ twitterThreats: zod.z.number(),
11506
+ telegramThreats: zod.z.number(),
11507
+ otherThreats: zod.z.number()
11508
+ }),
11509
+ blockedByDay: zod.z.array(
11510
+ zod.z.object({
11511
+ date: zod.z.string(),
11512
+ count: zod.z.number()
11513
+ })
11514
+ ),
11515
+ blockedByType: zod.z.array(
11516
+ zod.z.object({
11517
+ type: zod.z.string(),
11518
+ count: zod.z.number()
11519
+ })
11520
+ )
11521
+ });
11522
+ var DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
11523
+ var utcDateSchema = (endOfDay) => zod.z.preprocess((value) => {
11524
+ if (typeof value !== "string") {
11525
+ return value;
11410
11526
  }
11411
- try {
11412
- const parsed = new URL(value);
11413
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
11414
- return null;
11415
- }
11416
- return parsed.toString();
11417
- } catch (e4) {
11418
- return null;
11527
+ const parsed = DateTime.fromISO(value, { zone: "utc" });
11528
+ if (!parsed.isValid) {
11529
+ return new Date(Number.NaN);
11419
11530
  }
11420
- }
11421
- var URL_REGEX = /https?:\/\/[^\s"'<>\])]*/g;
11531
+ return endOfDay && DATE_ONLY_PATTERN.test(value) ? parsed.endOf("day").toJSDate() : parsed.toJSDate();
11532
+ }, zod.z.coerce.date());
11533
+ zod.z.object({
11534
+ slug: zod.z.string().min(1).describe("Organization slug"),
11535
+ startDate: utcDateSchema(false).optional().describe(
11536
+ "Only include takedowns completed on or after this date. A date-only value (YYYY-MM-DD) starts at midnight UTC"
11537
+ ),
11538
+ endDate: utcDateSchema(true).optional().describe(
11539
+ "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
+ ),
11541
+ blockLabel: zod.z.string().optional().describe(
11542
+ 'Only include assets blocked with this review label, e.g. "Brand Impersonation", "Employee Impersonation" or "Targeting Org Users"'
11543
+ ),
11544
+ brandType: zod.z.nativeEnum(BrandType).optional().describe("Only include assets belonging to brands of this type"),
11545
+ countryCodes: zod.z.array(zod.z.string().length(2)).optional().describe("Only include assets scanned from these ISO 3166-1 alpha-2 countries"),
11546
+ brandIds: zod.z.array(zod.z.number().int().positive()).optional().describe("Only include assets belonging to these brands")
11547
+ });
11548
+ zod.z.object({
11549
+ byAssetType: zod.z.array(
11550
+ zod.z.object({
11551
+ assetType: zod.z.nativeEnum(AssetType).describe("Asset type the median is computed over"),
11552
+ medianTakedownMinutes: zod.z.number(),
11553
+ medianTakedownHours: zod.z.number(),
11554
+ medianTakedownDays: zod.z.number(),
11555
+ count: zod.z.number().describe("Number of completed takedowns behind the median")
11556
+ })
11557
+ ).describe(
11558
+ "Median time from takedown start to completion, one entry per asset type, ascending by median"
11559
+ )
11560
+ });
11561
+ zod.z.object({
11562
+ slug: zod.z.string().optional().describe(
11563
+ "Organization slug. Optional for organization-scoped API keys, which resolve the organization from the key itself. Required when your credentials can reach more than one organization."
11564
+ ),
11565
+ type: zod.z.nativeEnum(AssetType).optional().describe("Filter by asset type (URL, ADDRESS, etc.)"),
11566
+ groupId: zod.z.number().int().optional().describe(
11567
+ "Filter by group ID. Use -1 for ungrouped assets only. Omit for all assets."
11568
+ ),
11569
+ query: zod.z.string().optional().describe("Search query to filter assets by content"),
11570
+ per_page: zod.z.number().int().min(1).max(1e3).optional().default(100).describe("The number of assets to return per page (max 1000)"),
11571
+ next_page: zod.z.string().optional().nullable().describe("Cursor for fetching the next page of results")
11572
+ }).describe(
11573
+ `List organization assets request body
11422
11574
 
11423
- // ../../internal/utils/src/email.ts
11424
- var email_exports = {};
11425
- __export(email_exports, {
11426
- extractTextFromGmailPayload: () => extractTextFromGmailPayload,
11427
- getDomainFromEmail: () => getDomainFromEmail,
11428
- getNameFromEmail: () => getNameFromEmail
11575
+ Returns all assets belonging to the organization identified by \`slug\`, or \u2014
11576
+ when \`slug\` is omitted \u2014 the organization associated with your API key.
11577
+ Supports filtering by type, group, and search query.`
11578
+ );
11579
+ var organizationAssetItemSchema = zod.z.object({
11580
+ id: zod.z.number().describe("Asset ID"),
11581
+ content: zod.z.string().describe("Asset content (URL, address, handle, etc.)"),
11582
+ type: zod.z.nativeEnum(AssetType).describe("Asset type"),
11583
+ status: zod.z.nativeEnum(AssetStatus).describe("Asset status"),
11584
+ name: zod.z.string().nullable().describe("Asset display name"),
11585
+ description: zod.z.string().nullable().describe("Asset description"),
11586
+ group: zod.z.object({
11587
+ id: zod.z.number().describe("Group ID"),
11588
+ name: zod.z.string().describe("Group name")
11589
+ }).nullable().describe("Asset group information"),
11590
+ livenessStatus: zod.z.nativeEnum(LivenessStatus).nullable().describe(
11591
+ "Whether the asset is currently reachable (`ALIVE`), gone (`DEAD`), or hasn't been checked (`UNKNOWN`). `null` when liveness has never been evaluated."
11592
+ ),
11593
+ blockedAt: zod.z.date().nullable().describe(
11594
+ "When the asset transitioned to BLOCKED status. `null` for non-blocked assets. Distinct from `updatedAt`."
11595
+ ),
11596
+ createdAt: zod.z.date().describe("When the asset was created"),
11597
+ updatedAt: zod.z.date().describe("When the asset was last updated")
11429
11598
  });
11430
- function getDomainFromEmail(email) {
11431
- return email.split("@")[1];
11432
- }
11433
- function getNameFromEmail(email) {
11434
- return email.split("@")[0];
11435
- }
11436
- function extractTextFromGmailPayload(payload) {
11437
- var _a;
11438
- if (!payload) return "";
11439
- if ((_a = payload.body) == null ? void 0 : _a.data) {
11440
- if (payload.mimeType === "text/plain" || payload.mimeType === "text/html") {
11441
- return Buffer.from(payload.body.data, "base64url").toString("utf-8");
11442
- }
11443
- }
11444
- if (payload.parts) {
11445
- if (payload.mimeType === "multipart/alternative") {
11446
- const plainTextPart = payload.parts.find((part) => part.mimeType === "text/plain");
11447
- if (plainTextPart) {
11448
- return extractTextFromGmailPayload(plainTextPart);
11449
- }
11450
- const htmlPart = payload.parts.find((part) => part.mimeType === "text/html");
11451
- if (htmlPart) {
11452
- return extractTextFromGmailPayload(htmlPart);
11453
- }
11454
- for (const part of payload.parts) {
11455
- const text = extractTextFromGmailPayload(part);
11456
- if (text) return text;
11457
- }
11458
- }
11459
- return payload.parts.map((part) => extractTextFromGmailPayload(part)).join("\n");
11460
- }
11461
- return "";
11462
- }
11599
+ zod.z.object({
11600
+ assets: zod.z.array(organizationAssetItemSchema).describe("List of assets"),
11601
+ next_page: zod.z.string().nullable().optional().describe("Cursor for fetching the next page of results")
11602
+ }).describe("Successful operation");
11603
+ var addAssetItemSchema = zod.z.object({
11604
+ content: zod.z.string().describe("Asset content (URL, address, handle, etc.)"),
11605
+ name: zod.z.string().optional().describe("Optional display name for the asset"),
11606
+ description: zod.z.string().optional().describe("Optional description for the asset"),
11607
+ groupId: zod.z.number().int().positive().optional().describe("Optional group ID to assign the asset to")
11608
+ });
11609
+ zod.z.object({
11610
+ assets: zod.z.array(addAssetItemSchema).min(1).max(1e3).describe("Array of assets to add (max 1000 per request)")
11611
+ }).describe(
11612
+ `Add assets to organization allowlist
11613
+
11614
+ Batch add multiple assets to your organization's allowlist.
11615
+ Each asset will be automatically parsed and classified.
11616
+ Assets will be auto-approved as ALLOWED status.`
11617
+ );
11618
+ var addAssetResultSchema = zod.z.object({
11619
+ content: zod.z.string().describe("Asset content"),
11620
+ success: zod.z.boolean().describe("Whether the asset was added successfully"),
11621
+ id: zod.z.number().optional().describe("Asset ID if successful"),
11622
+ error: zod.z.string().optional().describe("Error message if failed")
11623
+ });
11624
+ zod.z.object({
11625
+ results: zod.z.array(addAssetResultSchema).describe("Results for each asset"),
11626
+ successCount: zod.z.number().describe("Number of assets successfully added"),
11627
+ errorCount: zod.z.number().describe("Number of assets that failed to add")
11628
+ }).describe("Batch add operation results");
11629
+ zod.z.object({
11630
+ assetId: zod.z.number().int().positive().describe("ID of the asset to update"),
11631
+ name: zod.z.string().optional().describe("New display name for the asset"),
11632
+ description: zod.z.string().nullable().optional().describe("New description for the asset"),
11633
+ groupId: zod.z.number().int().positive().nullable().optional().describe("New group ID (null to ungroup)")
11634
+ }).describe(
11635
+ `Update an organization asset
11636
+
11637
+ Update the name, description, or group assignment of an asset.`
11638
+ );
11639
+ zod.z.object({
11640
+ id: zod.z.number().describe("Asset ID"),
11641
+ content: zod.z.string().describe("Asset content"),
11642
+ name: zod.z.string().nullable().describe("Asset display name"),
11643
+ description: zod.z.string().nullable().describe("Asset description"),
11644
+ groupId: zod.z.number().nullable().describe("Group ID")
11645
+ }).describe("Updated asset");
11646
+ zod.z.object({
11647
+ assetId: zod.z.number().int().positive().describe("ID of the asset to remove")
11648
+ }).describe(
11649
+ `Remove an asset from the organization
11650
+
11651
+ This removes the asset from the organization's allowlist.`
11652
+ );
11653
+ zod.z.object({
11654
+ success: zod.z.boolean().describe("Whether the asset was removed successfully"),
11655
+ id: zod.z.number().describe("Asset ID that was removed")
11656
+ }).describe("Delete operation result");
11657
+ zod.z.object({}).describe(
11658
+ `List organization asset groups
11659
+
11660
+ Returns all asset groups belonging to the organization associated with your API key.`
11661
+ );
11662
+ var assetGroupItemSchema = zod.z.object({
11663
+ id: zod.z.number().describe("Group ID"),
11664
+ name: zod.z.string().describe("Group name"),
11665
+ assetCount: zod.z.number().describe("Number of assets in this group")
11666
+ });
11667
+ zod.z.object({
11668
+ groups: zod.z.array(assetGroupItemSchema).describe("List of asset groups")
11669
+ }).describe("Successful operation");
11670
+ zod.z.object({
11671
+ name: zod.z.string().min(1).max(255).describe("Name for the new group")
11672
+ }).describe(
11673
+ `Create a new asset group
11674
+
11675
+ Creates a new asset group for organizing your organization's assets.`
11676
+ );
11677
+ zod.z.object({
11678
+ id: zod.z.number().describe("Created group ID"),
11679
+ name: zod.z.string().describe("Group name")
11680
+ }).describe("Created group");
11681
+ zod.z.object({
11682
+ groupId: zod.z.number().int().positive().describe("ID of the group to update"),
11683
+ name: zod.z.string().min(1).max(255).describe("New name for the group")
11684
+ }).describe(
11685
+ `Update an asset group
11686
+
11687
+ Rename an existing asset group.`
11688
+ );
11689
+ zod.z.object({
11690
+ id: zod.z.number().describe("Group ID"),
11691
+ name: zod.z.string().describe("Updated group name")
11692
+ }).describe("Updated group");
11693
+ zod.z.object({
11694
+ groupId: zod.z.number().int().positive().describe("ID of the group to delete")
11695
+ }).describe(
11696
+ `Delete an asset group
11463
11697
 
11464
- // ../../internal/utils/src/vercel.ts
11465
- var vercel_exports = {};
11466
- __export(vercel_exports, {
11467
- checkVercelEnv: () => checkVercelEnv
11468
- });
11469
- var checkVercelEnv = ({ envs }) => {
11470
- var _a;
11471
- const vercelEnv = (_a = process.env.VERCEL_ENV) != null ? _a : "development";
11472
- if (!envs.includes(vercelEnv)) {
11473
- return {
11474
- ok: false,
11475
- message: `Vercel environment is ${vercelEnv}, but expected ${envs.join(" or ")}`
11476
- };
11477
- }
11478
- return { ok: true, message: "" };
11479
- };
11698
+ Deletes an asset group. Assets in this group will become ungrouped.`
11699
+ );
11700
+ zod.z.object({
11701
+ success: zod.z.boolean().describe("Whether the group was deleted successfully"),
11702
+ id: zod.z.number().describe("Group ID that was deleted"),
11703
+ unassignedAssetCount: zod.z.number().describe("Number of assets that were unassigned from this group")
11704
+ }).describe("Delete operation result");
11705
+ zod.z.object({}).describe(
11706
+ `List organization brands
11480
11707
 
11481
- // ../../internal/utils/src/delay.ts
11482
- var delay_exports = {};
11483
- __export(delay_exports, {
11484
- delay: () => delay
11708
+ Returns all brands belonging to the organization associated with your API key,
11709
+ including sub-brands (\`ORGANIZATION\`), individual / employee brands
11710
+ (\`INDIVIDUAL\`), and product brands (\`PRODUCT\`). Soft-deleted brands are
11711
+ excluded.`
11712
+ );
11713
+ var brandLegalDocumentSchema = zod.z.object({
11714
+ present: zod.z.boolean().describe("Whether the brand has this document attached"),
11715
+ fileName: zod.z.string().nullable().describe("Original filename of the uploaded document (null when not present)"),
11716
+ fileUrl: zod.z.string().nullable().describe("Direct URL to view or download the document (null when not present)")
11485
11717
  });
11486
- var delay = (ms) => {
11487
- return new Promise((resolve) => setTimeout(resolve, ms));
11488
- };
11489
-
11490
- // ../../internal/utils/src/whois.ts
11491
- var whois_exports = {};
11492
- __export(whois_exports, {
11493
- extractWhoisCountry: () => extractWhoisCountry,
11494
- extractWhoisPayload: () => extractWhoisPayload,
11495
- normalizeRegistrar: () => normalizeRegistrar
11718
+ var brandTrademarkRegistrationSchema = zod.z.object({
11719
+ id: zod.z.number().describe("Trademark registration ID"),
11720
+ brandName: zod.z.string().describe("Trademarked brand name as it appears on the registration"),
11721
+ trademarkOffice: zod.z.string().describe("Issuing trademark office (e.g. `USPTO`, `EUIPO`)"),
11722
+ registrationNumber: zod.z.string().describe("Registration number assigned by the office"),
11723
+ goodsAndServicesClass: zod.z.string().describe("Nice Classification class(es) the registration covers"),
11724
+ rightsOwnerName: zod.z.string().nullable().describe("Legal entity the trademark is registered to, if recorded"),
11725
+ registrationPageUrl: zod.z.string().nullable().describe("Public URL on the trademark office's site, if recorded"),
11726
+ certificateFileName: zod.z.string().nullable().describe(
11727
+ "Original filename of the uploaded certificate PDF (null when no certificate is attached)"
11728
+ ),
11729
+ certificateFileUrl: zod.z.string().nullable().describe(
11730
+ "Direct URL to view or download the certificate PDF (null when no certificate is attached)"
11731
+ )
11496
11732
  });
11497
- function extractWhoisPayload(raw) {
11498
- var _a;
11499
- const first = Array.isArray(raw) ? (_a = raw.find((entry) => entry !== null && typeof entry === "object")) != null ? _a : {} : raw;
11500
- if (!first || typeof first !== "object") {
11501
- return {};
11502
- }
11503
- const maybeData = first.data;
11504
- if (maybeData && typeof maybeData === "object" && !Array.isArray(maybeData)) {
11505
- return maybeData;
11506
- }
11507
- return first;
11508
- }
11509
- var WHOIS_EMPTY_VALUES = /* @__PURE__ */ new Set(["", "none", "null"]);
11510
- var WHOIS_COUNTRY_CODE_KEY_ALIASES = /* @__PURE__ */ new Set(["countrycode", "registrantcountrycode"]);
11511
- var WHOIS_COUNTRY_KEY_ALIASES = /* @__PURE__ */ new Set([
11512
- "country",
11513
- "countryname",
11514
- "registrantcountry",
11515
- "registrantcountryname"
11516
- ]);
11517
- function normalizeWhoisKey(key) {
11518
- return key.toLowerCase().replace(/[^a-z0-9]/g, "");
11519
- }
11520
- function normalizeRegistrar(value) {
11521
- return value.toLowerCase().replace(/[^a-z0-9]/g, "");
11522
- }
11523
- function parseWhoisString(value) {
11524
- if (typeof value !== "string") {
11525
- return void 0;
11526
- }
11527
- const trimmedValue = value.trim();
11528
- if (WHOIS_EMPTY_VALUES.has(trimmedValue.toLowerCase())) {
11529
- return void 0;
11530
- }
11531
- return trimmedValue;
11532
- }
11533
- function extractWhoisFieldByAliases(payload, aliases) {
11534
- for (const [key, value] of Object.entries(payload)) {
11535
- if (!aliases.has(normalizeWhoisKey(key))) {
11536
- continue;
11537
- }
11538
- const parsedValue = parseWhoisString(value);
11539
- if (parsedValue) {
11540
- return parsedValue;
11541
- }
11542
- }
11543
- return void 0;
11544
- }
11545
- function extractWhoisCountry(payload) {
11546
- const countryCode = extractWhoisFieldByAliases(payload, WHOIS_COUNTRY_CODE_KEY_ALIASES);
11547
- const country = extractWhoisFieldByAliases(payload, WHOIS_COUNTRY_KEY_ALIASES);
11548
- return {
11549
- countryCode: countryCode != null ? countryCode : void 0,
11550
- country: country != null ? country : void 0
11551
- };
11552
- }
11553
-
11554
- // ../../internal/utils/src/safe-preview.ts
11555
- var safe_preview_exports = {};
11556
- __export(safe_preview_exports, {
11557
- buildSafePreviewUrl: () => buildSafePreviewUrl,
11558
- normalizeSafeNavigationTarget: () => normalizeSafeNavigationTarget
11733
+ var brandItemSchema = zod.z.object({
11734
+ id: zod.z.number().describe("Brand ID"),
11735
+ slug: zod.z.string().describe("Brand slug (stable, URL-safe identifier)"),
11736
+ name: zod.z.string().describe("Display name"),
11737
+ type: zod.z.nativeEnum(BrandType).describe(
11738
+ "Brand type: `ORGANIZATION` for parent brands, `INDIVIDUAL` for employee or person brands, `PRODUCT` for a specific product or service offering"
11739
+ ),
11740
+ description: zod.z.string().nullable().describe("Free-form description, if set"),
11741
+ avatarUrl: zod.z.string().nullable().describe("URL of the brand's avatar / logo image"),
11742
+ websiteUrl: zod.z.string().nullable().describe("Official brand website URL"),
11743
+ twitterHandle: zod.z.string().nullable().describe("Official Twitter / X handle (without @)"),
11744
+ brandColors: zod.z.array(zod.z.string()).describe("HEX color strings associated with the brand (e.g. `#FF0000`)"),
11745
+ includedTerms: zod.z.array(zod.z.string()).describe("Terms that should be included when matching this brand"),
11746
+ excludedTerms: zod.z.array(zod.z.string()).describe("Terms that should be excluded when matching this brand"),
11747
+ tickers: zod.z.array(zod.z.string()).describe("Ticker symbols associated with the brand (e.g. `$JUP`)"),
11748
+ brandGroupId: zod.z.number().nullable().describe(
11749
+ "Group this brand belongs to (only set for `INDIVIDUAL` and `PRODUCT` brands)"
11750
+ ),
11751
+ createdAt: zod.z.date().describe("When the brand was created"),
11752
+ useOrganizationDocs: zod.z.boolean().describe(
11753
+ "When true, this brand inherits its Letter of Authorization and Power of Attorney from the organization rather than carrying its own. The `legalDocuments` block below always reflects the brand-level attachments \u2014 read `/user/orgs/{slug}` for the org-level fallbacks."
11754
+ ),
11755
+ legalDocuments: zod.z.object({
11756
+ letterOfAuthorization: brandLegalDocumentSchema,
11757
+ powerOfAttorney: brandLegalDocumentSchema
11758
+ }).describe("Brand-level Letter of Authorization and Power of Attorney attachments"),
11759
+ trademarkRegistrations: zod.z.array(brandTrademarkRegistrationSchema).describe(
11760
+ "Trademark registrations attached to this brand. An empty array means no trademarks are on file for the brand \u2014 use this to identify brands that still need them added."
11761
+ )
11559
11762
  });
11560
- var SAFE_NAVIGATION_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
11561
- var PREVIEW_PATH = "/preview";
11562
- var URL_BASE = "https://app.chainpatrol.io";
11563
- function normalizeSafeNavigationTarget(target) {
11564
- const normalizedTarget = getNormalizedUrl(target);
11565
- if (!SAFE_NAVIGATION_PROTOCOLS.has(normalizedTarget.protocol)) {
11566
- throw new Error(`Unsupported URL protocol: ${normalizedTarget.protocol}`);
11567
- }
11568
- return normalizedTarget;
11569
- }
11570
- function buildSafePreviewUrl({
11571
- target,
11572
- assetId,
11573
- policy
11574
- }) {
11575
- const normalizedTarget = normalizeSafeNavigationTarget(target);
11576
- const previewUrl = new URL(PREVIEW_PATH, URL_BASE);
11577
- previewUrl.searchParams.set("target", normalizedTarget.toString());
11578
- if (Number.isInteger(assetId) && assetId && assetId >= 1) {
11579
- previewUrl.searchParams.set("asset_id", String(assetId));
11580
- }
11581
- if (policy) {
11582
- previewUrl.searchParams.set("policy", policy);
11583
- }
11584
- return `${previewUrl.pathname}?${previewUrl.searchParams.toString()}`;
11585
- }
11586
-
11587
- // ../../internal/utils/src/parse.ts
11588
- var parse_exports = {};
11589
- __export(parse_exports, {
11590
- parseTerms: () => parseTerms,
11591
- stringifyTerms: () => stringifyTerms
11763
+ zod.z.object({
11764
+ brands: zod.z.array(brandItemSchema).describe("List of brands")
11765
+ }).describe("Successful operation");
11766
+ var FILTERABLE_SUBSCRIPTION_STATUSES = [
11767
+ SubscriptionStatus.PROSPECT,
11768
+ SubscriptionStatus.POC,
11769
+ SubscriptionStatus.ACTIVE,
11770
+ SubscriptionStatus.INTEGRATION
11771
+ ];
11772
+ var UserOrgsSubscriptionStatusSchema = zod.z.enum(
11773
+ FILTERABLE_SUBSCRIPTION_STATUSES
11774
+ );
11775
+ var takedownsServiceFilterSchema = zod.z.object({
11776
+ active: zod.z.boolean().optional(),
11777
+ automated: zod.z.boolean().optional()
11778
+ }).optional();
11779
+ var singleServiceFilterSchema = zod.z.object({
11780
+ active: zod.z.boolean().optional()
11781
+ }).optional();
11782
+ var userOrgsServicesFilterObjectSchema = zod.z.object({
11783
+ reporting: singleServiceFilterSchema,
11784
+ reviewing: singleServiceFilterSchema,
11785
+ protection: singleServiceFilterSchema,
11786
+ takedowns: takedownsServiceFilterSchema,
11787
+ detection: singleServiceFilterSchema,
11788
+ darkWebMonitoring: singleServiceFilterSchema
11789
+ });
11790
+ var userOrgsObligatoryAdminApprovalFilterSchema = zod.z.object({
11791
+ active: zod.z.boolean().optional(),
11792
+ assetTypes: zod.z.array(zod.z.nativeEnum(AssetType)).min(1).optional()
11793
+ }).optional();
11794
+ var PendingApprovalServiceSchema = zod.z.enum(["protection", "takedowns"]);
11795
+ var userOrgsPendingServiceApprovalFilterSchema = zod.z.object({
11796
+ active: zod.z.boolean().optional(),
11797
+ services: zod.z.array(PendingApprovalServiceSchema).min(1).optional()
11798
+ }).optional();
11799
+ zod.z.object({
11800
+ query: zod.z.string().default(""),
11801
+ subscriptionStatus: zod.z.array(UserOrgsSubscriptionStatusSchema).min(1).optional(),
11802
+ services: userOrgsServicesFilterObjectSchema.optional(),
11803
+ obligatoryAdminApproval: userOrgsObligatoryAdminApprovalFilterSchema,
11804
+ pendingServiceApproval: userOrgsPendingServiceApprovalFilterSchema
11805
+ });
11806
+ var takedownsServiceSchema = zod.z.object({
11807
+ active: zod.z.boolean(),
11808
+ automated: zod.z.boolean()
11809
+ });
11810
+ var singleServiceSchema = zod.z.object({
11811
+ active: zod.z.boolean()
11812
+ });
11813
+ var UserOrgObligatoryAdminApprovalSchema = zod.z.object({
11814
+ active: zod.z.boolean(),
11815
+ assetTypes: zod.z.array(zod.z.nativeEnum(AssetType))
11816
+ });
11817
+ var PendingServiceApprovalSchema = zod.z.object({
11818
+ // Friendly service family, matching a key in the `services` object.
11819
+ service: PendingApprovalServiceSchema,
11820
+ // Whether the request is for the automated variant of the service
11821
+ // (e.g. "Automated Wallet Blocking" rather than "Wallet Blocking").
11822
+ automated: zod.z.boolean(),
11823
+ // Raw `ServiceType` enum value, e.g. "isProtectionActive". Lets callers
11824
+ // distinguish the exact column without re-deriving it from `service` +
11825
+ // `automated`.
11826
+ serviceType: zod.z.nativeEnum(ServiceType),
11827
+ // Human-readable service label, e.g. "Wallet Blocking".
11828
+ serviceName: zod.z.string(),
11829
+ // When the enable request was submitted (ISO 8601, UTC).
11830
+ requestedAt: zod.z.string()
11831
+ });
11832
+ var UserOrgIntegrationsSchema = zod.z.object({
11833
+ slack: zod.z.boolean(),
11834
+ discord: zod.z.boolean(),
11835
+ telegram: zod.z.object({
11836
+ connected: zod.z.boolean(),
11837
+ groupCount: zod.z.number()
11838
+ }),
11839
+ vercel: zod.z.boolean(),
11840
+ intercom: zod.z.boolean(),
11841
+ moderation: zod.z.boolean()
11592
11842
  });
11593
- function parseTerms(terms, {
11594
- forceExact = false
11595
- } = {}) {
11596
- if (!terms) return [];
11597
- return terms.split(",").map((term) => {
11598
- const trimmed = term.trim();
11599
- if (!trimmed) return null;
11600
- const isWrappedExact = trimmed.startsWith("*") && trimmed.endsWith("*") && trimmed.length > 2;
11601
- if (isWrappedExact) {
11602
- return {
11603
- value: trimmed.slice(1, -1).toLowerCase(),
11604
- type: "exact"
11605
- };
11606
- } else {
11607
- return {
11608
- value: trimmed.toLowerCase(),
11609
- type: forceExact ? "exact" : "loose"
11610
- };
11611
- }
11612
- }).filter((term) => term !== null);
11613
- }
11614
- function stringifyTerms(parsedTerms) {
11615
- return parsedTerms.map((term) => term.type === "exact" ? `*${term.value}*` : term.value).join(", ");
11616
- }
11617
-
11618
- // ../../internal/utils/src/brand-pattern.ts
11619
- var brand_pattern_exports = {};
11620
- __export(brand_pattern_exports, {
11621
- anyPatternMatches: () => anyPatternMatches,
11622
- compileBrandPattern: () => compileBrandPattern,
11623
- countPatternMatches: () => countPatternMatches,
11624
- findMatchingPatterns: () => findMatchingPatterns
11843
+ var UserOrgLegalDocumentSchema = zod.z.object({
11844
+ present: zod.z.boolean().describe("Whether the organization has this document attached"),
11845
+ fileName: zod.z.string().nullable().describe("Original filename of the uploaded document (null when not present)"),
11846
+ fileUrl: zod.z.string().nullable().describe("Direct URL to view or download the document (null when not present)")
11625
11847
  });
11626
- var DEFAULT_MAX_MATCHES = 50;
11627
- function compileBrandPattern(input) {
11628
- var _a;
11629
- try {
11630
- return new RegExp(input.pattern, (_a = input.flags) != null ? _a : void 0);
11631
- } catch (e4) {
11632
- return null;
11633
- }
11634
- }
11635
- function anyPatternMatches(content, patterns, kind) {
11636
- for (const input of patterns) {
11637
- if (input.kind !== kind) continue;
11638
- const regex = compileBrandPattern(input);
11639
- if (!regex) continue;
11640
- if (regex.test(content)) {
11641
- return true;
11642
- }
11643
- }
11644
- return false;
11645
- }
11646
- function findMatchingPatterns(content, patterns, kind) {
11647
- const matched = [];
11648
- for (const input of patterns) {
11649
- if (input.kind !== kind) continue;
11650
- const regex = compileBrandPattern(input);
11651
- if (!regex) continue;
11652
- if (regex.test(content)) {
11653
- matched.push(input);
11654
- }
11655
- }
11656
- return matched;
11657
- }
11658
- function countPatternMatches(content, pattern, maxMatches = DEFAULT_MAX_MATCHES) {
11659
- const compiled = compileBrandPattern(pattern);
11660
- if (!compiled) return 0;
11661
- const flags = compiled.flags.includes("g") ? compiled.flags : `${compiled.flags}g`;
11662
- const globalRegex = new RegExp(compiled.source, flags);
11663
- let count = 0;
11664
- let match2;
11665
- while ((match2 = globalRegex.exec(content)) !== null) {
11666
- count += 1;
11667
- if (count >= maxMatches) break;
11668
- if (match2[0].length === 0) globalRegex.lastIndex += 1;
11669
- }
11670
- return count;
11671
- }
11672
-
11673
- // ../../internal/utils/src/text.ts
11674
- var text_exports = {};
11675
- __export(text_exports, {
11676
- HOMOGLYPH_MAPPINGS: () => HOMOGLYPH_MAPPINGS,
11677
- LETTER_TO_HOMOGLYPH_MAPPINGS: () => LETTER_TO_HOMOGLYPH_MAPPINGS,
11678
- generateHomoglyphSearchTerms: () => generateHomoglyphSearchTerms,
11679
- normalizeHomoglyphs: () => normalizeHomoglyphs
11848
+ var UserOrgLegalDocumentsSchema = zod.z.object({
11849
+ letterOfAuthorization: UserOrgLegalDocumentSchema,
11850
+ powerOfAttorney: UserOrgLegalDocumentSchema
11680
11851
  });
11681
- var HOMOGLYPH_MAPPINGS = {
11682
- "0": "o",
11683
- "1": "i",
11684
- "3": "e",
11685
- "4": "a",
11686
- "5": "s",
11687
- "7": "t",
11688
- "8": "b"
11689
- };
11690
- var LETTER_TO_HOMOGLYPH_MAPPINGS = {
11691
- a: ["4", "\u0430"],
11692
- b: ["8", "6"],
11693
- c: ["\u0441"],
11694
- e: ["3", "\u0435"],
11695
- g: ["9"],
11696
- i: ["1", "l", "\u0456"],
11697
- l: ["1"],
11698
- o: ["0", "\u043E"],
11699
- s: ["5", "\u0455"],
11700
- t: ["7"],
11701
- x: ["\u0445"],
11702
- z: ["2"]
11703
- };
11704
- var DEFAULT_MAX_HOMOGLYPH_VARIANTS = 20;
11705
- function isCyrillic(char) {
11706
- return char.charCodeAt(0) > 127;
11707
- }
11708
- function buildReplacementOps(term) {
11709
- const ops = [];
11710
- for (let i = 0; i < term.length; i++) {
11711
- const homoglyphs = LETTER_TO_HOMOGLYPH_MAPPINGS[term[i]];
11712
- if (!homoglyphs) continue;
11713
- for (const replacement of homoglyphs) {
11714
- ops.push({ index: i, replacement });
11715
- }
11716
- }
11717
- return ops;
11718
- }
11719
- function applyOps(term, ops, selected) {
11720
- const chars = Array.from(term);
11721
- for (const idx of selected) {
11722
- chars[ops[idx].index] = ops[idx].replacement;
11723
- }
11724
- return chars.join("");
11725
- }
11726
- function generateCombinations(ops, opIndices, term, maxVariants, addFn, variants) {
11727
- const generate = (startIdx, depth, selected, usedPositions) => {
11728
- if (selected.length === depth) return addFn(applyOps(term, ops, selected));
11729
- for (let i = startIdx; i < opIndices.length && variants.length < maxVariants; i++) {
11730
- const opIdx = opIndices[i];
11731
- if (usedPositions.has(ops[opIdx].index)) continue;
11732
- selected.push(opIdx);
11733
- usedPositions.add(ops[opIdx].index);
11734
- if (generate(i + 1, depth, selected, usedPositions)) return true;
11735
- selected.pop();
11736
- usedPositions.delete(ops[opIdx].index);
11737
- }
11738
- return false;
11739
- };
11740
- for (let depth = 2; depth <= opIndices.length && variants.length < maxVariants; depth++) {
11741
- if (generate(0, depth, [], /* @__PURE__ */ new Set())) break;
11742
- }
11743
- }
11744
- function generateHomoglyphSearchTerms(term, maxVariants = DEFAULT_MAX_HOMOGLYPH_VARIANTS) {
11745
- if (term.length === 0 || maxVariants <= 0) return [];
11746
- const lowerTerm = term.toLowerCase();
11747
- const seen = /* @__PURE__ */ new Set();
11748
- const variants = [];
11749
- const add = (v) => {
11750
- if (v === lowerTerm || seen.has(v)) return false;
11751
- seen.add(v);
11752
- variants.push(v);
11753
- return variants.length >= maxVariants;
11754
- };
11755
- const allOps = buildReplacementOps(lowerTerm);
11756
- for (let i = 0; i < allOps.length && variants.length < maxVariants; i++) {
11757
- add(applyOps(lowerTerm, allOps, [i]));
11758
- }
11759
- if (variants.length < maxVariants) {
11760
- const cyrillicComposite = lowerTerm.split("").map((char) => {
11761
- var _a;
11762
- const homoglyphs = LETTER_TO_HOMOGLYPH_MAPPINGS[char];
11763
- return (_a = homoglyphs == null ? void 0 : homoglyphs.find((h) => isCyrillic(h))) != null ? _a : char;
11764
- }).join("");
11765
- add(cyrillicComposite);
11766
- }
11767
- const cyrillicOpIndices = allOps.map((op, i) => isCyrillic(op.replacement) ? i : -1).filter((i) => i >= 0);
11768
- if (variants.length < maxVariants && cyrillicOpIndices.length >= 2) {
11769
- generateCombinations(
11770
- allOps,
11771
- cyrillicOpIndices,
11772
- lowerTerm,
11773
- maxVariants,
11774
- add,
11775
- variants
11776
- );
11777
- }
11778
- if (variants.length < maxVariants) {
11779
- const allOpIndices = allOps.map((_, i) => i);
11780
- generateCombinations(allOps, allOpIndices, lowerTerm, maxVariants, add, variants);
11781
- }
11782
- return variants;
11783
- }
11784
- function normalizeHomoglyphs(text, customMappings = {}) {
11785
- const mappings = __spreadValues(__spreadValues({}, HOMOGLYPH_MAPPINGS), customMappings);
11786
- return text.toLowerCase().split("").map((char) => mappings[char] || char).join("");
11787
- }
11788
-
11789
- // ../../internal/utils/src/format.ts
11790
- var format_exports = {};
11791
- __export(format_exports, {
11792
- formatCompactNumber: () => formatCompactNumber,
11793
- formatFileSize: () => formatFileSize
11852
+ var UserOrgTrademarkRegistrationSchema = zod.z.object({
11853
+ id: zod.z.number().describe("Trademark registration ID"),
11854
+ brandName: zod.z.string().describe("Trademarked brand name as it appears on the registration"),
11855
+ trademarkOffice: zod.z.string().describe("Issuing trademark office (e.g. `USPTO`, `EUIPO`)"),
11856
+ registrationNumber: zod.z.string().describe("Registration number assigned by the office"),
11857
+ goodsAndServicesClass: zod.z.string().describe("Nice Classification class(es) the registration covers"),
11858
+ rightsOwnerName: zod.z.string().nullable().describe("Legal entity the trademark is registered to, if recorded"),
11859
+ registrationPageUrl: zod.z.string().nullable().describe("Public URL on the trademark office's site, if recorded"),
11860
+ certificateFileName: zod.z.string().nullable().describe(
11861
+ "Original filename of the uploaded certificate PDF (null when no certificate is attached)"
11862
+ ),
11863
+ certificateFileUrl: zod.z.string().nullable().describe(
11864
+ "Direct URL to view or download the certificate PDF (null when no certificate is attached)"
11865
+ )
11866
+ });
11867
+ var UserOrgBrandMetadataSchema = zod.z.object({
11868
+ websiteUrl: zod.z.string().nullable().describe("Public website URL of the brand (linked from the portal header)"),
11869
+ twitterHandle: zod.z.string().nullable().describe(
11870
+ "Public Twitter/X handle of the brand, stored with the leading `@` (e.g. `@acme`)"
11871
+ ),
11872
+ securityContactEmail: zod.z.string().nullable().describe(
11873
+ "Email address for security correspondence \u2014 used by takedown providers and researchers, distinct from the internal customer POC email"
11874
+ ),
11875
+ industry: zod.z.string().nullable().describe('Free-form industry label (e.g. "DeFi", "CEX", "NFT", "Wallet")')
11876
+ });
11877
+ var UserOrgPortalCustomizationSchema = zod.z.object({
11878
+ useCustomDetails: zod.z.boolean().describe(
11879
+ "When true, the portal uses `name`/`slug`/`avatarUrl` from this object instead of the org's own name/slug/avatar"
11880
+ ),
11881
+ name: zod.z.string().nullable().describe(
11882
+ "Custom display name shown on the portal (used only when `useCustomDetails=true`)"
11883
+ ),
11884
+ slug: zod.z.string().nullable().describe(
11885
+ "Custom URL slug (`chainpatrol.io/<slug>`) \u2014 takes precedence over the org's own slug when set, regardless of `useCustomDetails`"
11886
+ ),
11887
+ avatarUrl: zod.z.string().nullable().describe(
11888
+ "Custom avatar URL shown on the portal (used only when `useCustomDetails=true`)"
11889
+ ),
11890
+ bannerEnabled: zod.z.boolean().describe(
11891
+ "When true, the portal renders `bannerContent` as a highlighted banner at the top of the page"
11892
+ ),
11893
+ bannerContent: zod.z.string().nullable().describe(
11894
+ "Markdown body of the portal banner. Null (or empty) with `bannerEnabled=true` means the toggle is on but no content has been written yet"
11895
+ )
11896
+ });
11897
+ var UserOrgSchema = zod.z.object({
11898
+ id: zod.z.number(),
11899
+ name: zod.z.string(),
11900
+ slug: zod.z.string(),
11901
+ avatarUrl: zod.z.string().nullable(),
11902
+ contactUrl: zod.z.string().nullable(),
11903
+ subscriptionStatus: zod.z.nativeEnum(SubscriptionStatus),
11904
+ portalVisibility: zod.z.nativeEnum(OrganizationPortalVisibility).describe(
11905
+ "Visibility of the org's public security portal (chainpatrol.io/<slug>). `PUBLIC` is discoverable; `PRIVATE` renders only the report form (no metrics or listings); `DISABLED` returns a 404."
11906
+ ),
11907
+ reportVisibility: zod.z.nativeEnum(ReportVisibility).describe(
11908
+ "Whether the report listings on the public portal are visible to visitors. `PUBLIC` shows the org's reports; `PRIVATE` hides the report list even when the portal is discoverable."
11909
+ ),
11910
+ metricsVisibility: zod.z.nativeEnum(MetricsVisibility).describe(
11911
+ "Whether the metrics/threats-blocked stats render on the public portal. `PUBLIC` shows the metrics tab; `PRIVATE` hides it from anonymous visitors; `DISABLED` doesn't compute metrics at all."
11912
+ ),
11913
+ brandMetadata: UserOrgBrandMetadataSchema.describe(
11914
+ "Public brand-facing metadata (website, twitter, security contact, industry) shown on the portal and used by staff for outbound"
11915
+ ),
11916
+ portalCustomization: UserOrgPortalCustomizationSchema.describe(
11917
+ "Customer-configurable presentation of the public security portal \u2014 custom name/slug/avatar and the banner content"
11918
+ ),
11919
+ services: zod.z.object({
11920
+ reporting: singleServiceSchema,
11921
+ reviewing: singleServiceSchema,
11922
+ protection: singleServiceSchema,
11923
+ takedowns: takedownsServiceSchema,
11924
+ detection: singleServiceSchema,
11925
+ darkWebMonitoring: singleServiceSchema
11926
+ }),
11927
+ integrations: UserOrgIntegrationsSchema,
11928
+ obligatoryAdminApproval: UserOrgObligatoryAdminApprovalSchema,
11929
+ pendingServiceApprovals: zod.z.array(PendingServiceApprovalSchema),
11930
+ legalDocuments: UserOrgLegalDocumentsSchema.describe(
11931
+ "Org-level Letter of Authorization and Power of Attorney attachments"
11932
+ ),
11933
+ trademarkRegistrations: zod.z.array(UserOrgTrademarkRegistrationSchema).describe(
11934
+ "Org-level trademark registrations attached to the organization. An empty array means no trademarks are on file \u2014 use this to identify customers who still need to add them."
11935
+ )
11794
11936
  });
11795
- function formatCompactNumber(num3, options = {}) {
11796
- const { decimals = 1, fallback = "-" } = options;
11797
- if (num3 === void 0 || num3 === null) {
11798
- return fallback;
11799
- }
11800
- if (num3 >= 1e9) {
11801
- return `${(num3 / 1e9).toFixed(decimals)}B`;
11802
- }
11803
- if (num3 >= 1e6) {
11804
- return `${(num3 / 1e6).toFixed(decimals)}M`;
11805
- }
11806
- if (num3 >= 1e3) {
11807
- return `${(num3 / 1e3).toFixed(decimals)}K`;
11808
- }
11809
- return num3.toString();
11810
- }
11811
- function formatFileSize(bytes, options = {}) {
11812
- const { decimals = 1, binary = true, showUnknown = true } = options;
11813
- if (bytes === null || bytes === void 0 || bytes === "") {
11814
- return showUnknown ? "Unknown" : "0 B";
11815
- }
11816
- const size = typeof bytes === "string" ? parseInt(bytes, 10) : bytes;
11817
- if (isNaN(size) || size < 0) {
11818
- return showUnknown ? "Unknown" : "0 B";
11819
- }
11820
- if (size === 0) {
11821
- return "0 B";
11822
- }
11823
- const unit = binary ? 1024 : 1e3;
11824
- const units = binary ? ["B", "KB", "MB", "GB", "TB", "PB"] : ["B", "kB", "MB", "GB", "TB", "PB"];
11825
- const unitIndex = Math.floor(Math.log(size) / Math.log(unit));
11826
- const finalUnitIndex = Math.min(unitIndex, units.length - 1);
11827
- const value = size / Math.pow(unit, finalUnitIndex);
11828
- if (finalUnitIndex === 0) {
11829
- return `${size} B`;
11830
- }
11831
- return `${value.toFixed(decimals)} ${units[finalUnitIndex]}`;
11832
- }
11833
-
11834
- // ../../internal/utils/src/social-profile-url.ts
11835
- var social_profile_url_exports = {};
11836
- __export(social_profile_url_exports, {
11837
- LINKEDIN_PROFILE_URL_PATTERN: () => LINKEDIN_PROFILE_URL_PATTERN,
11838
- TWITTER_PROFILE_URL_PATTERN: () => TWITTER_PROFILE_URL_PATTERN,
11839
- isLinkedInProfileUrl: () => isLinkedInProfileUrl,
11840
- isSupportedSocialProfileUrl: () => isSupportedSocialProfileUrl,
11841
- isTwitterProfileUrl: () => isTwitterProfileUrl,
11842
- parseLinkedInProfileUrl: () => parseLinkedInProfileUrl
11937
+ zod.z.object({
11938
+ organizations: zod.z.array(UserOrgSchema)
11843
11939
  });
11844
- var TWITTER_PROFILE_URL_PATTERN = /^https?:\/\/(?:www\.)?(?:twitter\.com|x\.com)\/[^/?#]+\/?(?:[?#].*)?$/i;
11845
- var LINKEDIN_PROFILE_URL_PATTERN = /^https?:\/\/(?:[a-z]{2,3}\.)?linkedin\.com\/(in|company|school)\/([^/?#]+)/i;
11846
- function isTwitterProfileUrl(url) {
11847
- return TWITTER_PROFILE_URL_PATTERN.test(url);
11848
- }
11849
- function isLinkedInProfileUrl(url) {
11850
- return LINKEDIN_PROFILE_URL_PATTERN.test(url);
11851
- }
11852
- function isSupportedSocialProfileUrl(url) {
11853
- return isTwitterProfileUrl(url) || isLinkedInProfileUrl(url);
11854
- }
11855
- function humanizeLinkedInHandle(handle) {
11856
- const withoutTrailingDigits = handle.replace(/-[0-9a-f]{6,}$/i, "");
11857
- return withoutTrailingDigits.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
11858
- }
11859
- function parseLinkedInProfileUrl(url) {
11860
- var _a;
11861
- const match2 = url.match(LINKEDIN_PROFILE_URL_PATTERN);
11862
- if (!match2) return null;
11863
- const pathSegment = (_a = match2[1]) == null ? void 0 : _a.toLowerCase();
11864
- const rawHandle = match2[2];
11865
- if (!pathSegment || !rawHandle) return null;
11866
- let handle;
11940
+
11941
+ // ../../internal/validation/src/public/organization/metrics-get.ts
11942
+ var organizationMetricsIncludeFieldSchema = zod.z.enum([
11943
+ "reports",
11944
+ "newThreats",
11945
+ "threatsWatchlisted",
11946
+ "takedownsFiled",
11947
+ "takedownsCompleted",
11948
+ "domainThreats",
11949
+ "twitterThreats",
11950
+ "telegramThreats",
11951
+ "otherThreats",
11952
+ "blockedByType",
11953
+ "blockedByDay"
11954
+ ]);
11955
+ organizationMetricsIncludeFieldSchema.options;
11956
+ var ORGANIZATION_METRICS_MAX_SLUGS = 500;
11957
+ var organizationMetricsServicesFilterSchema = zod.z.preprocess((value) => {
11958
+ if (typeof value !== "string") return value;
11867
11959
  try {
11868
- handle = decodeURIComponent(rawHandle).trim();
11960
+ return JSON.parse(value);
11869
11961
  } catch (e4) {
11870
- return null;
11962
+ return value;
11871
11963
  }
11872
- if (!handle) return null;
11873
- const name = humanizeLinkedInHandle(handle) || handle;
11874
- const profileUrl = `https://www.linkedin.com/${pathSegment}/${handle}`;
11875
- return { pathSegment, handle, name, profileUrl };
11876
- }
11877
-
11878
- // ../../internal/validation/src/public/report/create.ts
11964
+ }, userOrgsServicesFilterObjectSchema).optional();
11965
+ zod.z.object({
11966
+ organizationSlug: zod.z.string().optional().describe(
11967
+ "Organization slug. Required when authenticating with a user session (Bearer token) and `slugs`/`allMyOrgs` are not supplied; ignored when using an org-scoped API key (org is derived from the key). Mutually exclusive with `slugs` and `allMyOrgs`."
11968
+ ),
11969
+ slugs: zod.z.array(zod.z.string()).max(ORGANIZATION_METRICS_MAX_SLUGS).optional().describe(
11970
+ "Multi-org form. Each slug is auth-checked individually (org-scoped API keys may only pass their own org; sessions and user API keys must have membership or staff role per slug). When supplied with more than one slug, the response includes a `perOrg` breakdown plus `metrics` rolled up across all of them. Capped at " + String(ORGANIZATION_METRICS_MAX_SLUGS) + " slugs per call. Mutually exclusive with `organizationSlug` and `allMyOrgs`."
11971
+ ),
11972
+ allMyOrgs: zod.z.preprocess((value) => {
11973
+ if (value === "true") return true;
11974
+ if (value === "false") return false;
11975
+ return value;
11976
+ }, zod.z.boolean()).optional().describe(
11977
+ "Shortcut for 'every org the caller is authorized to read'. Reuses the same filter logic as `/user/orgs`: org-scoped API keys are rejected (they're pinned to one org \u2014 use the default form); user API keys / Bearer sessions resolve to the user's memberships (or every active org for staff). Combine with `subscriptionStatus` and `services` to narrow (e.g. only paying customers with takedowns enabled). The resolved org set is still capped at " + String(ORGANIZATION_METRICS_MAX_SLUGS) + " and a 413 is returned if exceeded. Mutually exclusive with `organizationSlug`, `slugs`, and `brandSlug`."
11978
+ ),
11979
+ subscriptionStatus: zod.z.array(UserOrgsSubscriptionStatusSchema).min(1).optional().describe(
11980
+ "Only meaningful with `allMyOrgs: true`. Defaults to the same set `/user/orgs` uses (ACTIVE/POC/PROSPECT/INTEGRATION \u2014 INACTIVE is always excluded)."
11981
+ ),
11982
+ services: organizationMetricsServicesFilterSchema.describe(
11983
+ "Only meaningful with `allMyOrgs: true`. Same shape as `/user/orgs`'s `services` filter \u2014 every service accepts `{ active }`, and **only `takedowns` additionally accepts `automated`** (the one service where manual-vs-automated changes real platform behavior). E.g. `{ takedowns: { active: true, automated: false } }` for 'orgs with takedowns enabled but automation off'."
11984
+ ),
11985
+ brandSlug: zod.z.string().optional(),
11986
+ startDate: zod.z.coerce.date().optional(),
11987
+ endDate: zod.z.coerce.date().optional(),
11988
+ include: zod.z.array(organizationMetricsIncludeFieldSchema).optional().describe(
11989
+ "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`."
11990
+ )
11991
+ }).refine(
11992
+ (value) => {
11993
+ const explicitForms = [
11994
+ Boolean(value.organizationSlug),
11995
+ Boolean(value.slugs && value.slugs.length > 0),
11996
+ Boolean(value.allMyOrgs)
11997
+ ].filter(Boolean).length;
11998
+ return explicitForms <= 1;
11999
+ },
12000
+ {
12001
+ message: "Pass at most one of `organizationSlug`, `slugs`, or `allMyOrgs`.",
12002
+ path: ["allMyOrgs"]
12003
+ }
12004
+ ).refine((value) => !(value.brandSlug && value.slugs && value.slugs.length > 1), {
12005
+ message: "`brandSlug` is only valid alongside a single organization, not `slugs`.",
12006
+ path: ["brandSlug"]
12007
+ }).refine((value) => !(value.brandSlug && value.allMyOrgs), {
12008
+ message: "`brandSlug` is only valid for a single org, not `allMyOrgs`.",
12009
+ path: ["brandSlug"]
12010
+ });
12011
+ var metricValue = zod.z.number().nullable();
12012
+ var metricsObjectSchema = zod.z.object({
12013
+ reports: metricValue,
12014
+ newThreats: metricValue,
12015
+ threatsWatchlisted: metricValue,
12016
+ takedownsFiled: metricValue,
12017
+ takedownsCompleted: metricValue,
12018
+ domainThreats: metricValue,
12019
+ twitterThreats: metricValue,
12020
+ telegramThreats: metricValue,
12021
+ otherThreats: metricValue
12022
+ });
12023
+ var blockedByTypeSchema = zod.z.array(
12024
+ zod.z.object({
12025
+ type: zod.z.string(),
12026
+ count: zod.z.number()
12027
+ })
12028
+ ).nullable();
12029
+ var blockedByDaySchema = zod.z.array(
12030
+ zod.z.object({
12031
+ date: zod.z.string(),
12032
+ count: zod.z.number()
12033
+ })
12034
+ ).nullable();
12035
+ zod.z.object({
12036
+ /**
12037
+ * Aggregate metrics. For single-org callers this is just that org's
12038
+ * numbers; for multi-org callers (`slugs.length > 1` or `allMyOrgs`)
12039
+ * it is the sum across all queried orgs.
12040
+ */
12041
+ metrics: metricsObjectSchema,
12042
+ blockedByType: blockedByTypeSchema,
12043
+ blockedByDay: blockedByDaySchema,
12044
+ /**
12045
+ * Derived averages over the time window (and, in multi-org mode,
12046
+ * across orgs). `perDay = metrics / windowDays`. In multi-org mode
12047
+ * `perOrgPerDay = metrics / numOrgs / windowDays`; in single-org
12048
+ * mode it is `null`. Counts are floats here — the underlying
12049
+ * `metrics` fields stay integer counts.
12050
+ */
12051
+ averages: zod.z.object({
12052
+ perDay: metricsObjectSchema.nullable(),
12053
+ perOrgPerDay: metricsObjectSchema.nullable(),
12054
+ windowDays: zod.z.number().nullable()
12055
+ }),
12056
+ /**
12057
+ * Per-org breakdown. Only populated in multi-org mode; `null` for
12058
+ * single-org callers.
12059
+ */
12060
+ perOrg: zod.z.record(
12061
+ zod.z.string(),
12062
+ zod.z.object({
12063
+ metrics: metricsObjectSchema,
12064
+ blockedByType: blockedByTypeSchema,
12065
+ blockedByDay: blockedByDaySchema
12066
+ })
12067
+ ).nullable(),
12068
+ /**
12069
+ * Echoes the actual orgs the response covers, in the order they
12070
+ * were resolved. Single-org responses always have length 1. The
12071
+ * `resolvedFrom` field distinguishes how the caller asked for the
12072
+ * scope (useful for agent reporting).
12073
+ */
12074
+ scope: zod.z.object({
12075
+ mode: zod.z.enum(["single", "multi"]),
12076
+ orgs: zod.z.array(zod.z.string()),
12077
+ resolvedFrom: zod.z.enum(["api-key", "organizationSlug", "slugs", "allMyOrgs"])
12078
+ })
12079
+ });
11879
12080
  var BASE_64_PATTERN = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
11880
12081
  var PHONE_COUNTRY_CODE_ERROR_MESSAGE = "Phone numbers must include a country code in E.164 format (for example, +14155552671).";
11881
12082
  function isPhoneNumberMissingCountryCode(value) {
@@ -13196,20 +13397,20 @@ var convertA98ToXyz65_default = convertA98ToXyz65;
13196
13397
 
13197
13398
  // ../../node_modules/culori/src/a98/convertXyz65ToA98.js
13198
13399
  var gamma = (v) => Math.pow(Math.abs(v), 256 / 563) * Math.sign(v);
13199
- var convertXyz65ToA98 = ({ x, y, z: z50, alpha }) => {
13400
+ var convertXyz65ToA98 = ({ x, y, z: z54, alpha }) => {
13200
13401
  if (x === void 0) x = 0;
13201
13402
  if (y === void 0) y = 0;
13202
- if (z50 === void 0) z50 = 0;
13403
+ if (z54 === void 0) z54 = 0;
13203
13404
  let res = {
13204
13405
  mode: "a98",
13205
13406
  r: gamma(
13206
- x * 2.0415879038107465 - y * 0.5650069742788597 - 0.3447313507783297 * z50
13407
+ x * 2.0415879038107465 - y * 0.5650069742788597 - 0.3447313507783297 * z54
13207
13408
  ),
13208
13409
  g: gamma(
13209
- x * -0.9692436362808798 + y * 1.8759675015077206 + 0.0415550574071756 * z50
13410
+ x * -0.9692436362808798 + y * 1.8759675015077206 + 0.0415550574071756 * z54
13210
13411
  ),
13211
13412
  b: gamma(
13212
- x * 0.0134442806320312 - y * 0.1183623922310184 + 1.0151749943912058 * z50
13413
+ x * 0.0134442806320312 - y * 0.1183623922310184 + 1.0151749943912058 * z54
13213
13414
  )
13214
13415
  };
13215
13416
  if (alpha !== void 0) {
@@ -13276,14 +13477,14 @@ var convertLrgbToRgb = ({ r, g, b, alpha }, mode = "rgb") => {
13276
13477
  var convertLrgbToRgb_default = convertLrgbToRgb;
13277
13478
 
13278
13479
  // ../../node_modules/culori/src/xyz65/convertXyz65ToRgb.js
13279
- var convertXyz65ToRgb = ({ x, y, z: z50, alpha }) => {
13480
+ var convertXyz65ToRgb = ({ x, y, z: z54, alpha }) => {
13280
13481
  if (x === void 0) x = 0;
13281
13482
  if (y === void 0) y = 0;
13282
- if (z50 === void 0) z50 = 0;
13483
+ if (z54 === void 0) z54 = 0;
13283
13484
  let res = convertLrgbToRgb_default({
13284
- r: x * 3.2409699419045226 - y * 1.537383177570094 - 0.4986107602930034 * z50,
13285
- g: x * -0.9692436362808796 + y * 1.8759675015077204 + 0.0415550574071756 * z50,
13286
- b: x * 0.0556300796969936 - y * 0.2039769588889765 + 1.0569715142428784 * z50
13485
+ r: x * 3.2409699419045226 - y * 1.537383177570094 - 0.4986107602930034 * z54,
13486
+ g: x * -0.9692436362808796 + y * 1.8759675015077204 + 0.0415550574071756 * z54,
13487
+ b: x * 0.0556300796969936 - y * 0.2039769588889765 + 1.0569715142428784 * z54
13287
13488
  });
13288
13489
  if (alpha !== void 0) {
13289
13490
  res.alpha = alpha;
@@ -13533,13 +13734,13 @@ var convertLab65ToRgb_default = convertLab65ToRgb;
13533
13734
 
13534
13735
  // ../../node_modules/culori/src/lab65/convertXyz65ToLab65.js
13535
13736
  var f = (value) => value > e ? Math.cbrt(value) : (k * value + 16) / 116;
13536
- var convertXyz65ToLab65 = ({ x, y, z: z50, alpha }) => {
13737
+ var convertXyz65ToLab65 = ({ x, y, z: z54, alpha }) => {
13537
13738
  if (x === void 0) x = 0;
13538
13739
  if (y === void 0) y = 0;
13539
- if (z50 === void 0) z50 = 0;
13740
+ if (z54 === void 0) z54 = 0;
13540
13741
  let f0 = f(x / D65.X);
13541
13742
  let f1 = f(y / D65.Y);
13542
- let f22 = f(z50 / D65.Z);
13743
+ let f22 = f(z54 / D65.Z);
13543
13744
  let res = {
13544
13745
  mode: "lab65",
13545
13746
  l: 116 * f1 - 16,
@@ -14196,10 +14397,10 @@ var convertItpToXyz65_default = convertItpToXyz65;
14196
14397
 
14197
14398
  // ../../node_modules/culori/src/itp/convertXyz65ToItp.js
14198
14399
  var toAbs = (c2 = 0) => Math.max(c2 * YW, 0);
14199
- var convertXyz65ToItp = ({ x, y, z: z50, alpha }) => {
14400
+ var convertXyz65ToItp = ({ x, y, z: z54, alpha }) => {
14200
14401
  const absX = toAbs(x);
14201
14402
  const absY = toAbs(y);
14202
- const absZ = toAbs(z50);
14403
+ const absZ = toAbs(z54);
14203
14404
  const l2 = transferPqEncode(
14204
14405
  0.3592832590121217 * absX + 0.6976051147779502 * absY - 0.0358915932320289 * absZ
14205
14406
  );
@@ -14257,15 +14458,15 @@ var jabPqEncode = (v) => {
14257
14458
  return Math.pow((C1 + C2 * vn3) / (1 + C3 * vn3), p);
14258
14459
  };
14259
14460
  var abs = (v = 0) => Math.max(v * 203, 0);
14260
- var convertXyz65ToJab = ({ x, y, z: z50, alpha }) => {
14461
+ var convertXyz65ToJab = ({ x, y, z: z54, alpha }) => {
14261
14462
  x = abs(x);
14262
14463
  y = abs(y);
14263
- z50 = abs(z50);
14264
- let xp = 1.15 * x - 0.15 * z50;
14464
+ z54 = abs(z54);
14465
+ let xp = 1.15 * x - 0.15 * z54;
14265
14466
  let yp = 0.66 * y + 0.34 * x;
14266
- let l2 = jabPqEncode(0.41478972 * xp + 0.579999 * yp + 0.014648 * z50);
14267
- let m = jabPqEncode(-0.20151 * xp + 1.120649 * yp + 0.0531008 * z50);
14268
- let s2 = jabPqEncode(-0.0166008 * xp + 0.2648 * yp + 0.6684799 * z50);
14467
+ let l2 = jabPqEncode(0.41478972 * xp + 0.579999 * yp + 0.014648 * z54);
14468
+ let m = jabPqEncode(-0.20151 * xp + 1.120649 * yp + 0.0531008 * z54);
14469
+ let s2 = jabPqEncode(-0.0166008 * xp + 0.2648 * yp + 0.6684799 * z54);
14269
14470
  let i = (l2 + m) / 2;
14270
14471
  let res = {
14271
14472
  mode: "jab",
@@ -14451,14 +14652,14 @@ var convertLabToXyz50 = ({ l: l2, a, b, alpha }) => {
14451
14652
  var convertLabToXyz50_default = convertLabToXyz50;
14452
14653
 
14453
14654
  // ../../node_modules/culori/src/xyz50/convertXyz50ToRgb.js
14454
- var convertXyz50ToRgb = ({ x, y, z: z50, alpha }) => {
14655
+ var convertXyz50ToRgb = ({ x, y, z: z54, alpha }) => {
14455
14656
  if (x === void 0) x = 0;
14456
14657
  if (y === void 0) y = 0;
14457
- if (z50 === void 0) z50 = 0;
14658
+ if (z54 === void 0) z54 = 0;
14458
14659
  let res = convertLrgbToRgb_default({
14459
- r: x * 3.1341359569958707 - y * 1.6173863321612538 - 0.4906619460083532 * z50,
14460
- g: x * -0.978795502912089 + y * 1.916254567259524 + 0.03344273116131949 * z50,
14461
- b: x * 0.07195537988411677 - y * 0.2289768264158322 + 1.405386058324125 * z50
14660
+ r: x * 3.1341359569958707 - y * 1.6173863321612538 - 0.4906619460083532 * z54,
14661
+ g: x * -0.978795502912089 + y * 1.916254567259524 + 0.03344273116131949 * z54,
14662
+ b: x * 0.07195537988411677 - y * 0.2289768264158322 + 1.405386058324125 * z54
14462
14663
  });
14463
14664
  if (alpha !== void 0) {
14464
14665
  res.alpha = alpha;
@@ -14489,13 +14690,13 @@ var convertRgbToXyz50_default = convertRgbToXyz50;
14489
14690
 
14490
14691
  // ../../node_modules/culori/src/lab/convertXyz50ToLab.js
14491
14692
  var f2 = (value) => value > e3 ? Math.cbrt(value) : (k3 * value + 16) / 116;
14492
- var convertXyz50ToLab = ({ x, y, z: z50, alpha }) => {
14693
+ var convertXyz50ToLab = ({ x, y, z: z54, alpha }) => {
14493
14694
  if (x === void 0) x = 0;
14494
14695
  if (y === void 0) y = 0;
14495
- if (z50 === void 0) z50 = 0;
14696
+ if (z54 === void 0) z54 = 0;
14496
14697
  let f0 = f2(x / D50.X);
14497
14698
  let f1 = f2(y / D50.Y);
14498
- let f22 = f2(z50 / D50.Z);
14699
+ let f22 = f2(z54 / D50.Z);
14499
14700
  let res = {
14500
14701
  mode: "lab",
14501
14702
  l: 116 * f1 - 16,
@@ -14730,18 +14931,18 @@ var convertLchuvToLuv = ({ l: l2, c: c2, h, alpha }) => {
14730
14931
  var convertLchuvToLuv_default = convertLchuvToLuv;
14731
14932
 
14732
14933
  // ../../node_modules/culori/src/luv/convertXyz50ToLuv.js
14733
- var u_fn = (x, y, z50) => 4 * x / (x + 15 * y + 3 * z50);
14734
- var v_fn = (x, y, z50) => 9 * y / (x + 15 * y + 3 * z50);
14934
+ var u_fn = (x, y, z54) => 4 * x / (x + 15 * y + 3 * z54);
14935
+ var v_fn = (x, y, z54) => 9 * y / (x + 15 * y + 3 * z54);
14735
14936
  var un = u_fn(D50.X, D50.Y, D50.Z);
14736
14937
  var vn = v_fn(D50.X, D50.Y, D50.Z);
14737
14938
  var l_fn = (value) => value <= e3 ? k3 * value : 116 * Math.cbrt(value) - 16;
14738
- var convertXyz50ToLuv = ({ x, y, z: z50, alpha }) => {
14939
+ var convertXyz50ToLuv = ({ x, y, z: z54, alpha }) => {
14739
14940
  if (x === void 0) x = 0;
14740
14941
  if (y === void 0) y = 0;
14741
- if (z50 === void 0) z50 = 0;
14942
+ if (z54 === void 0) z54 = 0;
14742
14943
  let l2 = l_fn(y / D50.Y);
14743
- let u = u_fn(x, y, z50);
14744
- let v = v_fn(x, y, z50);
14944
+ let u = u_fn(x, y, z54);
14945
+ let v = v_fn(x, y, z54);
14745
14946
  if (!isFinite(u) || !isFinite(v)) {
14746
14947
  l2 = u = v = 0;
14747
14948
  } else {
@@ -14762,8 +14963,8 @@ var convertXyz50ToLuv = ({ x, y, z: z50, alpha }) => {
14762
14963
  var convertXyz50ToLuv_default = convertXyz50ToLuv;
14763
14964
 
14764
14965
  // ../../node_modules/culori/src/luv/convertLuvToXyz50.js
14765
- var u_fn2 = (x, y, z50) => 4 * x / (x + 15 * y + 3 * z50);
14766
- var v_fn2 = (x, y, z50) => 9 * y / (x + 15 * y + 3 * z50);
14966
+ var u_fn2 = (x, y, z54) => 4 * x / (x + 15 * y + 3 * z54);
14967
+ var v_fn2 = (x, y, z54) => 9 * y / (x + 15 * y + 3 * z54);
14767
14968
  var un2 = u_fn2(D50.X, D50.Y, D50.Z);
14768
14969
  var vn2 = v_fn2(D50.X, D50.Y, D50.Z);
14769
14970
  var convertLuvToXyz50 = ({ l: l2, u, v, alpha }) => {
@@ -14777,8 +14978,8 @@ var convertLuvToXyz50 = ({ l: l2, u, v, alpha }) => {
14777
14978
  let vp = v / (13 * l2) + vn2;
14778
14979
  let y = D50.Y * (l2 <= 8 ? l2 / k3 : Math.pow((l2 + 16) / 116, 3));
14779
14980
  let x = y * (9 * up) / (4 * vp);
14780
- let z50 = y * (12 - 3 * up - 20 * vp) / (4 * vp);
14781
- let res = { mode: "xyz50", x, y, z: z50 };
14981
+ let z54 = y * (12 - 3 * up - 20 * vp) / (4 * vp);
14982
+ let res = { mode: "xyz50", x, y, z: z54 };
14782
14983
  if (alpha !== void 0) {
14783
14984
  res.alpha = alpha;
14784
14985
  }
@@ -15395,15 +15596,15 @@ var convertP3ToXyz65 = (rgb2) => {
15395
15596
  var convertP3ToXyz65_default = convertP3ToXyz65;
15396
15597
 
15397
15598
  // ../../node_modules/culori/src/p3/convertXyz65ToP3.js
15398
- var convertXyz65ToP3 = ({ x, y, z: z50, alpha }) => {
15599
+ var convertXyz65ToP3 = ({ x, y, z: z54, alpha }) => {
15399
15600
  if (x === void 0) x = 0;
15400
15601
  if (y === void 0) y = 0;
15401
- if (z50 === void 0) z50 = 0;
15602
+ if (z54 === void 0) z54 = 0;
15402
15603
  let res = convertLrgbToRgb_default(
15403
15604
  {
15404
- r: x * 2.4934969119414263 - y * 0.9313836179191242 - 0.402710784450717 * z50,
15405
- g: x * -0.8294889695615749 + y * 1.7626640603183465 + 0.0236246858419436 * z50,
15406
- b: x * 0.0358458302437845 - y * 0.0761723892680418 + 0.9568845240076871 * z50
15605
+ r: x * 2.4934969119414263 - y * 0.9313836179191242 - 0.402710784450717 * z54,
15606
+ g: x * -0.8294889695615749 + y * 1.7626640603183465 + 0.0236246858419436 * z54,
15607
+ b: x * 0.0358458302437845 - y * 0.0761723892680418 + 0.9568845240076871 * z54
15407
15608
  },
15408
15609
  "p3"
15409
15610
  );
@@ -15438,19 +15639,19 @@ var gamma2 = (v) => {
15438
15639
  }
15439
15640
  return 16 * v;
15440
15641
  };
15441
- var convertXyz50ToProphoto = ({ x, y, z: z50, alpha }) => {
15642
+ var convertXyz50ToProphoto = ({ x, y, z: z54, alpha }) => {
15442
15643
  if (x === void 0) x = 0;
15443
15644
  if (y === void 0) y = 0;
15444
- if (z50 === void 0) z50 = 0;
15645
+ if (z54 === void 0) z54 = 0;
15445
15646
  let res = {
15446
15647
  mode: "prophoto",
15447
15648
  r: gamma2(
15448
- x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z50
15649
+ x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z54
15449
15650
  ),
15450
15651
  g: gamma2(
15451
- x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z50
15652
+ x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z54
15452
15653
  ),
15453
- b: gamma2(x * 0 + y * 0 + 1.2119675456389452 * z50)
15654
+ b: gamma2(x * 0 + y * 0 + 1.2119675456389452 * z54)
15454
15655
  };
15455
15656
  if (alpha !== void 0) {
15456
15657
  res.alpha = alpha;
@@ -15510,20 +15711,20 @@ var gamma3 = (v) => {
15510
15711
  }
15511
15712
  return 4.5 * v;
15512
15713
  };
15513
- var convertXyz65ToRec2020 = ({ x, y, z: z50, alpha }) => {
15714
+ var convertXyz65ToRec2020 = ({ x, y, z: z54, alpha }) => {
15514
15715
  if (x === void 0) x = 0;
15515
15716
  if (y === void 0) y = 0;
15516
- if (z50 === void 0) z50 = 0;
15717
+ if (z54 === void 0) z54 = 0;
15517
15718
  let res = {
15518
15719
  mode: "rec2020",
15519
15720
  r: gamma3(
15520
- x * 1.7166511879712683 - y * 0.3556707837763925 - 0.2533662813736599 * z50
15721
+ x * 1.7166511879712683 - y * 0.3556707837763925 - 0.2533662813736599 * z54
15521
15722
  ),
15522
15723
  g: gamma3(
15523
- x * -0.6666843518324893 + y * 1.6164812366349395 + 0.0157685458139111 * z50
15724
+ x * -0.6666843518324893 + y * 1.6164812366349395 + 0.0157685458139111 * z54
15524
15725
  ),
15525
15726
  b: gamma3(
15526
- x * 0.0176398574453108 - y * 0.0427706132578085 + 0.9421031212354739 * z50
15727
+ x * 0.0176398574453108 - y * 0.0427706132578085 + 0.9421031212354739 * z54
15527
15728
  )
15528
15729
  };
15529
15730
  if (alpha !== void 0) {
@@ -15676,15 +15877,15 @@ var definition_default26 = definition26;
15676
15877
 
15677
15878
  // ../../node_modules/culori/src/xyz65/convertXyz65ToXyz50.js
15678
15879
  var convertXyz65ToXyz50 = (xyz652) => {
15679
- let { x, y, z: z50, alpha } = xyz652;
15880
+ let { x, y, z: z54, alpha } = xyz652;
15680
15881
  if (x === void 0) x = 0;
15681
15882
  if (y === void 0) y = 0;
15682
- if (z50 === void 0) z50 = 0;
15883
+ if (z54 === void 0) z54 = 0;
15683
15884
  let res = {
15684
15885
  mode: "xyz50",
15685
- x: 1.0479298208405488 * x + 0.0229467933410191 * y - 0.0501922295431356 * z50,
15686
- y: 0.0296278156881593 * x + 0.990434484573249 * y - 0.0170738250293851 * z50,
15687
- z: -0.0092430581525912 * x + 0.0150551448965779 * y + 0.7518742899580008 * z50
15886
+ x: 1.0479298208405488 * x + 0.0229467933410191 * y - 0.0501922295431356 * z54,
15887
+ y: 0.0296278156881593 * x + 0.990434484573249 * y - 0.0170738250293851 * z54,
15888
+ z: -0.0092430581525912 * x + 0.0150551448965779 * y + 0.7518742899580008 * z54
15688
15889
  };
15689
15890
  if (alpha !== void 0) {
15690
15891
  res.alpha = alpha;
@@ -15695,15 +15896,15 @@ var convertXyz65ToXyz50_default = convertXyz65ToXyz50;
15695
15896
 
15696
15897
  // ../../node_modules/culori/src/xyz65/convertXyz50ToXyz65.js
15697
15898
  var convertXyz50ToXyz65 = (xyz502) => {
15698
- let { x, y, z: z50, alpha } = xyz502;
15899
+ let { x, y, z: z54, alpha } = xyz502;
15699
15900
  if (x === void 0) x = 0;
15700
15901
  if (y === void 0) y = 0;
15701
- if (z50 === void 0) z50 = 0;
15902
+ if (z54 === void 0) z54 = 0;
15702
15903
  let res = {
15703
15904
  mode: "xyz65",
15704
- x: 0.9554734527042182 * x - 0.0230985368742614 * y + 0.0632593086610217 * z50,
15705
- y: -0.0283697069632081 * x + 1.0099954580058226 * y + 0.021041398966943 * z50,
15706
- z: 0.0123140016883199 * x - 0.0205076964334779 * y + 1.3303659366080753 * z50
15905
+ x: 0.9554734527042182 * x - 0.0230985368742614 * y + 0.0632593086610217 * z54,
15906
+ y: -0.0283697069632081 * x + 1.0099954580058226 * y + 0.021041398966943 * z54,
15907
+ z: 0.0123140016883199 * x - 0.0205076964334779 * y + 1.3303659366080753 * z54
15707
15908
  };
15708
15909
  if (alpha !== void 0) {
15709
15910
  res.alpha = alpha;