@builder.io/ai-utils 0.84.0-dev.202607212345.137e4170f → 0.85.0-dev.202607231533.14c8ab346

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builder.io/ai-utils",
3
- "version": "0.84.0-dev.202607212345.137e4170f",
3
+ "version": "0.85.0-dev.202607231533.14c8ab346",
4
4
  "description": "Builder.io AI utils",
5
5
  "files": [
6
6
  "src"
package/src/events.d.ts CHANGED
@@ -598,6 +598,8 @@ export type BotMentionGitHubInternalPrV1 = FusionEventVariant<"bot.mention.githu
598
598
  /** Numeric GitHub comment ID (for reaction / reply threading) */
599
599
  commentNumericId?: number;
600
600
  commentType: "issue" | "pr";
601
+ /** Whether the normal bot-mention pipeline should post successful agent text. */
602
+ postSuccessResultComment?: boolean;
601
603
  /** GitHub Enterprise hostname, if applicable */
602
604
  hostname?: string;
603
605
  /** For review comments: the comment being replied to */
package/src/projects.d.ts CHANGED
@@ -1491,6 +1491,14 @@ export declare const ProjectHostingSchema: z.ZodObject<{
1491
1491
  }>>;
1492
1492
  publishedCommit: z.ZodOptional<z.ZodString>;
1493
1493
  autoDeploy: z.ZodOptional<z.ZodBoolean>;
1494
+ unpublishTrigger: z.ZodOptional<z.ZodEnum<{
1495
+ system: "system";
1496
+ user: "user";
1497
+ }>>;
1498
+ systemUnpublishReason: z.ZodOptional<z.ZodEnum<{
1499
+ "bandwidth-cap": "bandwidth-cap";
1500
+ "web-request-cap": "web-request-cap";
1501
+ }>>;
1494
1502
  domainIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
1495
1503
  }, z.core.$strip>;
1496
1504
  export type ProjectHosting = z.infer<typeof ProjectHostingSchema>;
@@ -1549,6 +1557,36 @@ export declare const HostingSlugSchema: z.ZodObject<{
1549
1557
  createdBy: z.ZodString;
1550
1558
  }, z.core.$strip>;
1551
1559
  export type HostingSlug = z.infer<typeof HostingSlugSchema>;
1560
+ /**
1561
+ * Per-Neon-project charged-through watermarks inside a space's hosting usage
1562
+ * snapshot. Storage folds root + child branch bytes-month into one field.
1563
+ */
1564
+ export declare const HostingNeonProjectUsageSchema: z.ZodObject<{
1565
+ computeUnitSecondsChargedThrough: z.ZodNumber;
1566
+ storageBytesMonthChargedThrough: z.ZodNumber;
1567
+ transferBytesChargedThrough: z.ZodNumber;
1568
+ }, z.core.$strip>;
1569
+ export type HostingNeonProjectUsage = z.infer<typeof HostingNeonProjectUsageSchema>;
1570
+ /**
1571
+ * Reconciler idempotency watermark for a space's Netlify + Neon hosting costs,
1572
+ * stored at `hostingUsageSnapshots/{spaceId}`. Netlify is one account-level
1573
+ * scalar; Neon is a per-project map. `freeDeployCount` gates the free 5/mo
1574
+ * deploy cap (cost itself is inside Netlify's partner_account_usage total).
1575
+ */
1576
+ export declare const HostingUsageSnapshotSchema: z.ZodObject<{
1577
+ ownerId: z.ZodString;
1578
+ periodKey: z.ZodString;
1579
+ netlifyConsumptionCycleStart: z.ZodString;
1580
+ netlifyCreditsChargedThrough: z.ZodNumber;
1581
+ neonByProject: z.ZodRecord<z.ZodString, z.ZodObject<{
1582
+ computeUnitSecondsChargedThrough: z.ZodNumber;
1583
+ storageBytesMonthChargedThrough: z.ZodNumber;
1584
+ transferBytesChargedThrough: z.ZodNumber;
1585
+ }, z.core.$strip>>;
1586
+ freeDeployCount: z.ZodNumber;
1587
+ updatedAt: z.ZodNumber;
1588
+ }, z.core.$strip>;
1589
+ export type HostingUsageSnapshot = z.infer<typeof HostingUsageSnapshotSchema>;
1552
1590
  /**
1553
1591
  * Deploy lease lock with fencing token, stored at
1554
1592
  * `hosting-locks/{projectId}__{checkoutBranch}` (the key uses the resolved ref
@@ -1724,9 +1762,21 @@ export declare const HostingDomainKindSchema: z.ZodEnum<{
1724
1762
  }>;
1725
1763
  export type HostingDomainKind = z.infer<typeof HostingDomainKindSchema>;
1726
1764
  /**
1727
- * Custom domain record, stored at `hosting-domains/{domain}`.
1765
+ * Custom domain record. The same shape backs two Firestore collections:
1766
+ *
1767
+ * - Lock doc `hosting-domains/{domain}` is the single exclusive owner. It
1768
+ * exists only once a project reaches `provisioning`/`active` (cert + route
1769
+ * created, DNS ownership proven) and is the cross-project serialization
1770
+ * point serving/deploy/unpublish read to answer "is this verified?".
1771
+ * `certId`/`certMapEntryName`/`httpRouteName`/`verifiedAt` are only ever
1772
+ * populated here.
1773
+ * - Claim subdoc `hosting-domains/{domain}/claims/{projectId}` is a
1774
+ * non-exclusive, per-project verification attempt (`pending`/`verifying`/
1775
+ * `failed`). Multiple projects can hold a claim on the same domain at once;
1776
+ * whoever proves DNS ownership first wins the lock and the losers are swept
1777
+ * to `failed`.
1778
+ *
1728
1779
  * The normalized domain is the doc key — global uniqueness comes for free.
1729
- * This doc is both the record AND the claim for the domain.
1730
1780
  */
1731
1781
  export declare const HostingDomainSchema: z.ZodObject<{
1732
1782
  domain: z.ZodString;
@@ -1759,6 +1809,8 @@ export declare const HostingDomainSchema: z.ZodObject<{
1759
1809
  dns: "dns";
1760
1810
  https: "https";
1761
1811
  }>>;
1812
+ routeError: z.ZodOptional<z.ZodString>;
1813
+ routeErrorAt: z.ZodOptional<z.ZodNumber>;
1762
1814
  createdBy: z.ZodString;
1763
1815
  }, z.core.$strip>;
1764
1816
  export type HostingDomain = z.infer<typeof HostingDomainSchema>;
@@ -1817,6 +1869,22 @@ export declare const RemoveDomainResponseSchema: z.ZodObject<{
1817
1869
  success: z.ZodLiteral<true>;
1818
1870
  }, z.core.$strip>;
1819
1871
  export type RemoveDomainResponse = z.infer<typeof RemoveDomainResponseSchema>;
1872
+ export declare const RepairDomainRequestSchema: z.ZodObject<{
1873
+ projectId: z.ZodString;
1874
+ domain: z.ZodString;
1875
+ }, z.core.$strip>;
1876
+ export type RepairDomainRequest = z.infer<typeof RepairDomainRequestSchema>;
1877
+ export declare const RepairDomainResponseSchema: z.ZodObject<{
1878
+ status: z.ZodEnum<{
1879
+ active: "active";
1880
+ failed: "failed";
1881
+ pending: "pending";
1882
+ provisioning: "provisioning";
1883
+ verifying: "verifying";
1884
+ }>;
1885
+ routeError: z.ZodOptional<z.ZodString>;
1886
+ }, z.core.$strip>;
1887
+ export type RepairDomainResponse = z.infer<typeof RepairDomainResponseSchema>;
1820
1888
  export declare const CloneProjectOptionsSchema: z.ZodObject<{
1821
1889
  sourceProjectId: z.ZodString;
1822
1890
  sourceBranchName: z.ZodDefault<z.ZodString>;
package/src/projects.js CHANGED
@@ -328,6 +328,26 @@ export const ProjectHostingSchema = z.object({
328
328
  .boolean()
329
329
  .optional()
330
330
  .meta({ description: "auto-deploy on push/merge" }),
331
+ /**
332
+ * Who last drove the site into `publishStatus: "unpublished"`. Absent is
333
+ * treated as `"user"`. `"system"` means free-tier usage-cap enforcement took
334
+ * the site down (deleted the HTTPRoute, kept the Netlify site) and the
335
+ * reconciler **may** auto-restore it — routing-only, no rebuild — once the cap
336
+ * clears. `"user"` (or absent) means the user unpublished, so the reconciler
337
+ * must leave it down. The publish/unpublish hosting lock keeps this honest:
338
+ * whichever operation wins the lock is the one that writes `publishStatus`
339
+ * and this field, so they never disagree.
340
+ */
341
+ unpublishTrigger: z.enum(["system", "user"]).optional().meta({
342
+ description: "Who last unpublished the site. Absent === user. 'system' lets the reconciler auto-restore a usage-cap takedown; 'user' does not.",
343
+ }),
344
+ /**
345
+ * Why the system unpublished the site. Set iff `unpublishTrigger === "system"`;
346
+ * drives the projects-grid "suspended" card and takedown observability.
347
+ */
348
+ systemUnpublishReason: z
349
+ .enum(["bandwidth-cap", "web-request-cap"])
350
+ .optional(),
331
351
  domainIds: z.array(z.string()).optional().meta({
332
352
  description: "Doc keys (normalized domains) in `hosting-domains` attached to this project. The domain docs are the source of truth; this is only the back-pointer.",
333
353
  }),
@@ -411,6 +431,42 @@ export const HostingSlugSchema = z.object({
411
431
  description: "user ID of the user who first clicked Publish on the project",
412
432
  }),
413
433
  });
434
+ /**
435
+ * Per-Neon-project charged-through watermarks inside a space's hosting usage
436
+ * snapshot. Storage folds root + child branch bytes-month into one field.
437
+ */
438
+ export const HostingNeonProjectUsageSchema = z.object({
439
+ computeUnitSecondsChargedThrough: z.number(),
440
+ storageBytesMonthChargedThrough: z.number().meta({
441
+ description: "root + child branch bytes-month already billed",
442
+ }),
443
+ transferBytesChargedThrough: z.number().meta({
444
+ description: "public network transfer bytes already billed",
445
+ }),
446
+ });
447
+ /**
448
+ * Reconciler idempotency watermark for a space's Netlify + Neon hosting costs,
449
+ * stored at `hostingUsageSnapshots/{spaceId}`. Netlify is one account-level
450
+ * scalar; Neon is a per-project map. `freeDeployCount` gates the free 5/mo
451
+ * deploy cap (cost itself is inside Netlify's partner_account_usage total).
452
+ */
453
+ export const HostingUsageSnapshotSchema = z.object({
454
+ ownerId: z.string(),
455
+ periodKey: z.string().meta({
456
+ description: "Builder billing cycle; resets the Neon watermarks",
457
+ }),
458
+ netlifyConsumptionCycleStart: z.string().meta({
459
+ description: "Netlify consumption_cycle_start_date; watermark resets when this advances",
460
+ }),
461
+ netlifyCreditsChargedThrough: z.number().meta({
462
+ description: "Netlify credits already billed this Netlify cycle",
463
+ }),
464
+ neonByProject: z.record(z.string(), HostingNeonProjectUsageSchema),
465
+ freeDeployCount: z.number().meta({
466
+ description: "Deploys this Builder cycle, for the free 5/mo cap",
467
+ }),
468
+ updatedAt: z.number(),
469
+ });
414
470
  /**
415
471
  * Deploy lease lock with fencing token, stored at
416
472
  * `hosting-locks/{projectId}__{checkoutBranch}` (the key uses the resolved ref
@@ -625,9 +681,21 @@ export const HostingDomainStatusSchema = z.enum([
625
681
  ]);
626
682
  export const HostingDomainKindSchema = z.enum(["apex", "subdomain"]);
627
683
  /**
628
- * Custom domain record, stored at `hosting-domains/{domain}`.
684
+ * Custom domain record. The same shape backs two Firestore collections:
685
+ *
686
+ * - Lock doc `hosting-domains/{domain}` is the single exclusive owner. It
687
+ * exists only once a project reaches `provisioning`/`active` (cert + route
688
+ * created, DNS ownership proven) and is the cross-project serialization
689
+ * point serving/deploy/unpublish read to answer "is this verified?".
690
+ * `certId`/`certMapEntryName`/`httpRouteName`/`verifiedAt` are only ever
691
+ * populated here.
692
+ * - Claim subdoc `hosting-domains/{domain}/claims/{projectId}` is a
693
+ * non-exclusive, per-project verification attempt (`pending`/`verifying`/
694
+ * `failed`). Multiple projects can hold a claim on the same domain at once;
695
+ * whoever proves DNS ownership first wins the lock and the losers are swept
696
+ * to `failed`.
697
+ *
629
698
  * The normalized domain is the doc key — global uniqueness comes for free.
630
- * This doc is both the record AND the claim for the domain.
631
699
  */
632
700
  export const HostingDomainSchema = z.object({
633
701
  domain: z
@@ -667,6 +735,12 @@ export const HostingDomainSchema = z.object({
667
735
  failedStep: z.enum(["dns", "https"]).optional().meta({
668
736
  description: "Which setup step failed, set alongside `status: failed` so the UI can attribute the failure. `dns` = delegation verification, `https` = cert/route provisioning.",
669
737
  }),
738
+ routeError: z.string().optional().meta({
739
+ description: "Non-fatal health signal on an otherwise verified (`provisioning`/`active`) domain: set when re-creating the Envoy HTTPRoute failed on republish, so the site's cert is valid but the custom domain has no live route (bare 404). `status` stays `active`; this drives a degraded banner + Fix action. Cleared once the route is recreated.",
740
+ }),
741
+ routeErrorAt: z.number().optional().meta({
742
+ description: "When `routeError` was last set.",
743
+ }),
670
744
  createdBy: z.string(),
671
745
  });
672
746
  export const AddDomainRequestSchema = z.object({
@@ -700,6 +774,14 @@ export const RemoveDomainRequestSchema = z.object({
700
774
  export const RemoveDomainResponseSchema = z.object({
701
775
  success: z.literal(true),
702
776
  });
777
+ export const RepairDomainRequestSchema = z.object({
778
+ projectId: z.string(),
779
+ domain: z.string(),
780
+ });
781
+ export const RepairDomainResponseSchema = z.object({
782
+ status: HostingDomainStatusSchema,
783
+ routeError: z.string().optional(),
784
+ });
703
785
  export const CloneProjectOptionsSchema = z.object({
704
786
  sourceProjectId: z.string().min(1).meta({
705
787
  description: "Project to clone from.",
@@ -1,116 +0,0 @@
1
- import { z } from "zod";
2
- export declare const CURRENT_PERF_REPORT_SCHEMA_VERSION = 1;
3
- export declare const PerfIncidentTypeSchema: z.ZodEnum<{
4
- hang: "hang";
5
- "memory-pressure": "memory-pressure";
6
- "recovered-hang": "recovered-hang";
7
- "recovered-unclean-exit": "recovered-unclean-exit";
8
- "renderer-crash": "renderer-crash";
9
- }>;
10
- export type PerfIncidentType = z.infer<typeof PerfIncidentTypeSchema>;
11
- export declare const PerfProcessSchema: z.ZodObject<{
12
- kind: z.ZodEnum<{
13
- browser: "browser";
14
- child: "child";
15
- gpu: "gpu";
16
- renderer: "renderer";
17
- utility: "utility";
18
- }>;
19
- pid: z.ZodNumber;
20
- memoryKb: z.ZodNumber;
21
- cpuPercent: z.ZodNumber;
22
- tabId: z.ZodOptional<z.ZodString>;
23
- }, z.core.$strip>;
24
- export type PerfProcess = z.infer<typeof PerfProcessSchema>;
25
- export declare const PerfTabSchema: z.ZodObject<{
26
- tabId: z.ZodString;
27
- route: z.ZodOptional<z.ZodString>;
28
- feature: z.ZodOptional<z.ZodString>;
29
- jsHeapUsedKb: z.ZodOptional<z.ZodNumber>;
30
- jsHeapLimitKb: z.ZodOptional<z.ZodNumber>;
31
- subsystems: z.ZodRecord<z.ZodString, z.ZodNumber>;
32
- livenessLatencyMs: z.ZodOptional<z.ZodNumber>;
33
- }, z.core.$strip>;
34
- export type PerfTab = z.infer<typeof PerfTabSchema>;
35
- export declare const PerfSampleSchema: z.ZodObject<{
36
- t: z.ZodNumber;
37
- desktopFootprintKb: z.ZodNumber;
38
- freeMemoryKb: z.ZodNumber;
39
- perTabHeapKb: z.ZodRecord<z.ZodString, z.ZodNumber>;
40
- }, z.core.$strip>;
41
- export type PerfSample = z.infer<typeof PerfSampleSchema>;
42
- export declare const PerfReportSchema: z.ZodObject<{
43
- schemaVersion: z.ZodNumber;
44
- incidentType: z.ZodEnum<{
45
- hang: "hang";
46
- "memory-pressure": "memory-pressure";
47
- "recovered-hang": "recovered-hang";
48
- "recovered-unclean-exit": "recovered-unclean-exit";
49
- "renderer-crash": "renderer-crash";
50
- }>;
51
- sessionId: z.ZodString;
52
- deviceId: z.ZodString;
53
- appVersion: z.ZodString;
54
- platform: z.ZodEnum<{
55
- darwin: "darwin";
56
- linux: "linux";
57
- win32: "win32";
58
- }>;
59
- channel: z.ZodEnum<{
60
- alpha: "alpha";
61
- stable: "stable";
62
- }>;
63
- timestamp: z.ZodNumber;
64
- machine: z.ZodObject<{
65
- totalMemoryKb: z.ZodNumber;
66
- freeMemoryKb: z.ZodNumber;
67
- desktopFootprintKb: z.ZodNumber;
68
- }, z.core.$strip>;
69
- processes: z.ZodArray<z.ZodObject<{
70
- kind: z.ZodEnum<{
71
- browser: "browser";
72
- child: "child";
73
- gpu: "gpu";
74
- renderer: "renderer";
75
- utility: "utility";
76
- }>;
77
- pid: z.ZodNumber;
78
- memoryKb: z.ZodNumber;
79
- cpuPercent: z.ZodNumber;
80
- tabId: z.ZodOptional<z.ZodString>;
81
- }, z.core.$strip>>;
82
- tabs: z.ZodArray<z.ZodObject<{
83
- tabId: z.ZodString;
84
- route: z.ZodOptional<z.ZodString>;
85
- feature: z.ZodOptional<z.ZodString>;
86
- jsHeapUsedKb: z.ZodOptional<z.ZodNumber>;
87
- jsHeapLimitKb: z.ZodOptional<z.ZodNumber>;
88
- subsystems: z.ZodRecord<z.ZodString, z.ZodNumber>;
89
- livenessLatencyMs: z.ZodOptional<z.ZodNumber>;
90
- }, z.core.$strip>>;
91
- crash: z.ZodOptional<z.ZodObject<{
92
- reason: z.ZodString;
93
- exitCode: z.ZodOptional<z.ZodNumber>;
94
- oom: z.ZodOptional<z.ZodBoolean>;
95
- }, z.core.$strip>>;
96
- hang: z.ZodOptional<z.ZodObject<{
97
- startedAt: z.ZodNumber;
98
- durationMs: z.ZodNumber;
99
- recovered: z.ZodBoolean;
100
- surface: z.ZodString;
101
- }, z.core.$strip>>;
102
- samples: z.ZodArray<z.ZodObject<{
103
- t: z.ZodNumber;
104
- desktopFootprintKb: z.ZodNumber;
105
- freeMemoryKb: z.ZodNumber;
106
- perTabHeapKb: z.ZodRecord<z.ZodString, z.ZodNumber>;
107
- }, z.core.$strip>>;
108
- }, z.core.$strip>;
109
- export type PerfReport = z.infer<typeof PerfReportSchema>;
110
- /**
111
- * Collapses opaque identifiers out of a route/URL so a report can't carry a
112
- * project/space id. Keeps the structural shape (which screen was open) while
113
- * masking the specific resource.
114
- */
115
- export declare function redactPerfRoute(route: string | undefined): string | undefined;
116
- export declare function redactPerfReport(report: PerfReport): PerfReport;
@@ -1,122 +0,0 @@
1
- import { z } from "zod";
2
- // ============================================================================
3
- // Desktop performance & crash monitoring wire contract.
4
- //
5
- // Canonical schema. The Electron desktop app lives in a separate workspace and
6
- // cannot import this file, so it keeps a hand-mirrored TypeScript type in
7
- // code/packages/electron-app/src/perf-report.types.ts. Keep the two in sync and
8
- // bump CURRENT_PERF_REPORT_SCHEMA_VERSION on any breaking shape change.
9
- // ============================================================================
10
- export const CURRENT_PERF_REPORT_SCHEMA_VERSION = 1;
11
- export const PerfIncidentTypeSchema = z.enum([
12
- "renderer-crash",
13
- "hang",
14
- "recovered-hang",
15
- "memory-pressure",
16
- "recovered-unclean-exit",
17
- ]);
18
- export const PerfProcessSchema = z.object({
19
- kind: z.enum(["browser", "renderer", "gpu", "utility", "child"]),
20
- pid: z.number(),
21
- memoryKb: z.number(),
22
- cpuPercent: z.number(),
23
- tabId: z.string().optional(),
24
- });
25
- export const PerfTabSchema = z.object({
26
- tabId: z.string(),
27
- route: z.string().optional(),
28
- feature: z.string().optional(),
29
- jsHeapUsedKb: z.number().optional(),
30
- jsHeapLimitKb: z.number().optional(),
31
- subsystems: z.record(z.string(), z.number()),
32
- livenessLatencyMs: z.number().optional(),
33
- });
34
- export const PerfSampleSchema = z.object({
35
- t: z.number(),
36
- desktopFootprintKb: z.number(),
37
- freeMemoryKb: z.number(),
38
- perTabHeapKb: z.record(z.string(), z.number()),
39
- });
40
- export const PerfReportSchema = z.object({
41
- schemaVersion: z.number(),
42
- incidentType: PerfIncidentTypeSchema,
43
- sessionId: z.string(),
44
- deviceId: z.string(),
45
- appVersion: z.string(),
46
- platform: z.enum(["darwin", "win32", "linux"]),
47
- channel: z.enum(["stable", "alpha"]),
48
- timestamp: z.number(),
49
- machine: z.object({
50
- totalMemoryKb: z.number(),
51
- freeMemoryKb: z.number(),
52
- desktopFootprintKb: z.number(),
53
- }),
54
- processes: z.array(PerfProcessSchema),
55
- tabs: z.array(PerfTabSchema),
56
- crash: z
57
- .object({
58
- reason: z.string(),
59
- exitCode: z.number().optional(),
60
- oom: z.boolean().optional(),
61
- })
62
- .optional(),
63
- hang: z
64
- .object({
65
- startedAt: z.number(),
66
- durationMs: z.number(),
67
- recovered: z.boolean(),
68
- surface: z.string(),
69
- })
70
- .optional(),
71
- samples: z.array(PerfSampleSchema),
72
- });
73
- // ---------------------------------------------------------------------------
74
- // Route/URL redaction. The desktop client redacts before sending; this runs
75
- // again at ingest (defense in depth) because the service cannot import the
76
- // renderer's redactSnapshot helper across the workspace boundary.
77
- // ---------------------------------------------------------------------------
78
- const PROJECT_ID_SEGMENTS = new Set([
79
- "projects",
80
- "content",
81
- "fusion",
82
- "space",
83
- "org",
84
- "organization",
85
- ]);
86
- /**
87
- * Collapses opaque identifiers out of a route/URL so a report can't carry a
88
- * project/space id. Keeps the structural shape (which screen was open) while
89
- * masking the specific resource.
90
- */
91
- export function redactPerfRoute(route) {
92
- if (!route) {
93
- return route;
94
- }
95
- const [pathPart] = route.split("?");
96
- const segments = pathPart.split("/");
97
- const redacted = segments.map((segment, index) => {
98
- var _a;
99
- if (!segment) {
100
- return segment;
101
- }
102
- const previous = (_a = segments[index - 1]) === null || _a === void 0 ? void 0 : _a.toLowerCase();
103
- if (previous && PROJECT_ID_SEGMENTS.has(previous)) {
104
- return ":id";
105
- }
106
- // Bare id-looking segments (uuids, long hex/base62 tokens).
107
- if (/^[0-9a-f]{16,}$/i.test(segment) || /^[0-9a-z]{20,}$/i.test(segment)) {
108
- return ":id";
109
- }
110
- return segment;
111
- });
112
- return redacted.join("/");
113
- }
114
- export function redactPerfReport(report) {
115
- return {
116
- ...report,
117
- tabs: report.tabs.map((tab) => ({
118
- ...tab,
119
- route: redactPerfRoute(tab.route),
120
- })),
121
- };
122
- }