@opengeni/api-router 0.26.1 → 0.30.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.
Files changed (87) hide show
  1. package/dist/app.d.ts +1 -0
  2. package/dist/app.js +5 -3
  3. package/dist/auth/canonical-human-session-admission.d.ts +27 -0
  4. package/dist/browser-auth-broker.d.ts +20 -0
  5. package/dist/browser-controller-authority.d.ts +19 -1
  6. package/dist/browser-network-route.d.ts +8 -0
  7. package/dist/{chunk-JIKNR5YL.js → chunk-2PQMSRCB.js} +15518 -6863
  8. package/dist/chunk-2PQMSRCB.js.map +1 -0
  9. package/dist/controller-data-plane.d.ts +12 -0
  10. package/dist/http/auth.d.ts +1 -1
  11. package/dist/http/sse.d.ts +18 -1
  12. package/dist/index.js +1 -1
  13. package/dist/integrations/api-integrations.d.ts +2 -2
  14. package/dist/integrations/fiken.d.ts +233 -0
  15. package/dist/integrations/google-drive.d.ts +6 -6
  16. package/dist/integrations/provider-oauth.d.ts +0 -2
  17. package/dist/integrations/slack-bot.d.ts +171 -1
  18. package/dist/integrations/slack-interactions.d.ts +17 -5
  19. package/dist/interaction-holder-heartbeat.d.ts +17 -0
  20. package/dist/interaction-metrics.d.ts +11 -0
  21. package/dist/mcp/server.d.ts +3 -2
  22. package/dist/model-catalog.d.ts +1 -0
  23. package/dist/routes/canonical-human-identities.d.ts +3 -0
  24. package/dist/routes/channels.d.ts +3 -0
  25. package/dist/routes/integration-facets.d.ts +3 -0
  26. package/dist/routes/interaction-resources.d.ts +5 -0
  27. package/dist/routes/organization-memberships.d.ts +3 -0
  28. package/dist/routes/sessions.d.ts +2 -1
  29. package/dist/routes/slack-task-policy.d.ts +3 -0
  30. package/dist/routes/supergrok.d.ts +3 -0
  31. package/dist/sandbox/channel-a.d.ts +8 -1
  32. package/dist/sandbox/machines.d.ts +2 -2
  33. package/dist/sandbox/viewer.d.ts +3 -1
  34. package/dist/slack-reaction-files.d.ts +27 -0
  35. package/dist/transcription/providers/xai-subscription.d.ts +8 -0
  36. package/dist/xai-realtime.d.ts +26 -0
  37. package/dist/xai-subscription-auth.d.ts +23 -0
  38. package/package.json +17 -16
  39. package/src/app.ts +352 -49
  40. package/src/auth/canonical-human-session-admission.ts +116 -0
  41. package/src/auth/managed-auth.ts +101 -0
  42. package/src/browser-auth-broker.ts +155 -0
  43. package/src/browser-controller-authority.ts +50 -1
  44. package/src/browser-network-route.ts +34 -0
  45. package/src/controller-data-plane.ts +35 -0
  46. package/src/http/auth.ts +27 -9
  47. package/src/http/sse.ts +229 -5
  48. package/src/integrations/api-integrations.ts +57 -42
  49. package/src/integrations/fiken.ts +1230 -0
  50. package/src/integrations/google-drive.ts +31 -26
  51. package/src/integrations/provider-oauth.ts +70 -91
  52. package/src/integrations/slack-bot.ts +638 -9
  53. package/src/integrations/slack-interactions.ts +1583 -73
  54. package/src/interaction-holder-heartbeat.ts +95 -0
  55. package/src/interaction-metrics.ts +159 -0
  56. package/src/mcp/documents.ts +115 -6
  57. package/src/mcp/server.ts +865 -242
  58. package/src/model-catalog.ts +19 -6
  59. package/src/routes/api-integrations.ts +32 -29
  60. package/src/routes/browser-identities.ts +24 -0
  61. package/src/routes/browser-sessions.ts +2122 -183
  62. package/src/routes/canonical-human-identities.ts +156 -0
  63. package/src/routes/channels.ts +90 -0
  64. package/src/routes/computer-sessions.ts +441 -86
  65. package/src/routes/connections.ts +141 -4
  66. package/src/routes/{integration-features.ts → integration-facets.ts} +63 -63
  67. package/src/routes/interaction-resources.ts +595 -0
  68. package/src/routes/organization-memberships.ts +53 -0
  69. package/src/routes/plugins.ts +2 -1
  70. package/src/routes/sessions.ts +419 -43
  71. package/src/routes/skills.ts +92 -10
  72. package/src/routes/slack-task-policy.ts +115 -0
  73. package/src/routes/supergrok.ts +717 -0
  74. package/src/routes/transcription-recordings.ts +9 -2
  75. package/src/routes/transcriptions.ts +2 -1
  76. package/src/routes/video-generation.ts +34 -4
  77. package/src/routes/workspaces.ts +22 -4
  78. package/src/sandbox/channel-a.ts +29 -2
  79. package/src/sandbox/machines.ts +5 -5
  80. package/src/sandbox/viewer.ts +10 -3
  81. package/src/slack-reaction-files.ts +181 -0
  82. package/src/transcription/providers/xai-subscription.ts +110 -0
  83. package/src/transcription/service.ts +17 -2
  84. package/src/xai-realtime.ts +216 -0
  85. package/src/xai-subscription-auth.ts +132 -0
  86. package/dist/chunk-JIKNR5YL.js.map +0 -1
  87. package/dist/routes/integration-features.d.ts +0 -3
package/src/app.ts CHANGED
@@ -3,7 +3,9 @@ import {
3
3
  configuredAllowedModels,
4
4
  configuredAllowedReasoningEfforts,
5
5
  configuredModels,
6
+ resolveFirstPartyMcpToolPolicy,
6
7
  withCodexCatalogProvider,
8
+ withXaiSubscriptionCatalogProvider,
7
9
  } from "@opengeni/config";
8
10
  import {
9
11
  ClientConfig,
@@ -13,6 +15,7 @@ import {
13
15
  OPENGENI_API_CONTRACT_REVISION,
14
16
  OPENGENI_CORRELATION_HEADER,
15
17
  resolveWorkspaceMemoryEnabled,
18
+ resolveWorkspaceMemoryPromptMode,
16
19
  VOICE_INPUT_ACCEPTED_MIME_TYPES,
17
20
  TRANSCRIPTION_RECORDING_PROVIDER_SEGMENT_SECONDS,
18
21
  type AccessGrant,
@@ -34,6 +37,7 @@ import {
34
37
  dbSql,
35
38
  getWorkspace,
36
39
  rlsContextForWorkspace,
40
+ withSessionRlsActorContext,
37
41
  } from "@opengeni/db";
38
42
  import { createObservability } from "@opengeni/observability";
39
43
  import { createObjectStorage } from "@opengeni/storage";
@@ -50,6 +54,7 @@ import {
50
54
  CodexCompactionV2ProviderLockedError,
51
55
  hasPermission,
52
56
  requireAccessGrant,
57
+ requireLiveAgentAttemptAuthorization,
53
58
  requirePermission,
54
59
  requireSessionAuthorization,
55
60
  SessionAuthorizationDeniedError,
@@ -67,11 +72,16 @@ import {
67
72
  submitAndDispatchCodemodeCall,
68
73
  } from "./codemode";
69
74
  import { boundedMcpRequest, McpPayloadTooLargeError } from "@opengeni/runtime/mcp-network";
75
+ import {
76
+ BrowserControlProtocolError,
77
+ BrowserControlTransportError,
78
+ } from "@opengeni/runtime/sandbox";
70
79
  import { requireAccessKey } from "./http/auth";
71
80
  import { allowedCorsOrigin } from "./http/cors";
72
81
  import { registerCapabilityRoutes } from "./routes/capabilities";
73
82
  import { registerCatalogAssetRoutes } from "./routes/catalog-assets";
74
83
  import { registerCodexRoutes } from "./routes/codex";
84
+ import { registerSuperGrokRoutes } from "./routes/supergrok";
75
85
  import { registerConnectionRoutes } from "./routes/connections";
76
86
  import { registerDocumentRoutes } from "./routes/documents";
77
87
  import { registerEnrollmentRoutes } from "./routes/enrollments";
@@ -87,10 +97,12 @@ import { registerComputerSessionRoutes } from "./routes/computer-sessions";
87
97
  import { registerGitHubRoutes } from "./routes/github";
88
98
  import { registerInstallRoutes } from "./routes/install";
89
99
  import { registerApiIntegrationRoutes } from "./routes/api-integrations";
90
- import { registerIntegrationFeatureRoutes } from "./routes/integration-features";
100
+ import { registerIntegrationFacetRoutes } from "./routes/integration-facets";
101
+ import { registerInteractionResourceRoutes } from "./routes/interaction-resources";
91
102
  import { registerPackRoutes } from "./routes/packs";
92
103
  import { registerPluginRoutes } from "./routes/plugins";
93
104
  import { registerSkillRoutes } from "./routes/skills";
105
+ import { registerChannelRoutes } from "./routes/channels";
94
106
  import { registerRigRoutes } from "./routes/rigs";
95
107
  import { registerScheduledTaskRoutes } from "./routes/scheduled-tasks";
96
108
  import { registerSessionRoutes } from "./routes/sessions";
@@ -98,6 +110,7 @@ import { registerSocialRoutes } from "./routes/social";
98
110
  import { registerWorkspaceRoutes } from "./routes/workspaces";
99
111
  import { registerWorkspaceInstructionPolicyRoutes } from "./routes/workspace-instruction-policies";
100
112
  import { registerCompanyProfileRoutes } from "./routes/company-profile";
113
+ import { registerSlackTaskPolicyRoutes } from "./routes/slack-task-policy";
101
114
  import { registerWorkspaceStateRoutes } from "./routes/workspace-state";
102
115
  import { registerWorkspaceArtifactRoutes } from "./routes/workspace-artifacts";
103
116
  import { registerPreferenceRegistryRoutes } from "./routes/preference-registry";
@@ -105,6 +118,8 @@ import { registerInsightsRoutes } from "./routes/insights";
105
118
  import { registerTranscriptionRoutes } from "./routes/transcriptions";
106
119
  import { registerEditableArtifactRoutes } from "./routes/editable-artifacts";
107
120
  import { registerVideoGenerationRoutes } from "./routes/video-generation";
121
+ import { registerCanonicalHumanIdentityRoutes } from "./routes/canonical-human-identities";
122
+ import { registerOrganizationMembershipRoutes } from "./routes/organization-memberships";
108
123
  import { projectClientModel } from "./model-catalog";
109
124
  import { createTranscriptionService } from "./transcription/service";
110
125
  import { createFfmpegTranscriptionSegmenter } from "./transcription/segmenter";
@@ -133,7 +148,7 @@ export {
133
148
  export { workflowIdForSession } from "@opengeni/core";
134
149
  export { replaySessionEvents, sseSessionStream, sseWorkspaceControlStream } from "./http/sse";
135
150
 
136
- export const API_MAX_REQUEST_BODY_BYTES = 8 * 1024 * 1024;
151
+ export const API_MAX_REQUEST_BODY_BYTES = 32 * 1024 * 1024;
137
152
 
138
153
  /** Effective Hono bodyLimit — API JSON ceiling or voice multipart + multipart overhead. */
139
154
  export function apiRequestBodyLimitBytes(settings: {
@@ -462,9 +477,12 @@ export function createAppComposition(deps: AppDependencies): {
462
477
 
463
478
  app.get("/v1/config/client", async (c) => {
464
479
  c.header("cache-control", "no-store");
465
- const catalogSettings = deps.settings.codexSubscriptionEnabled
480
+ const codexCatalogSettings = deps.settings.codexSubscriptionEnabled
466
481
  ? withCodexCatalogProvider(deps.settings)
467
482
  : deps.settings;
483
+ const catalogSettings = deps.settings.supergrokSubscriptionEnabled
484
+ ? withXaiSubscriptionCatalogProvider(codexCatalogSettings)
485
+ : codexCatalogSettings;
468
486
  return c.json(
469
487
  ClientConfig.parse({
470
488
  deploymentRevision: deps.settings.deploymentRevision,
@@ -483,6 +501,7 @@ export function createAppComposition(deps: AppDependencies): {
483
501
  id: server.id,
484
502
  name: server.name ?? server.id,
485
503
  })),
504
+ firstPartyMcpTools: resolveFirstPartyMcpToolPolicy(deps.settings),
486
505
  fileUploads: {
487
506
  enabled: objectStorage !== null,
488
507
  maxSizeBytes: objectStorage?.maxSinglePutSizeBytes ?? 5_000_000_000,
@@ -522,6 +541,22 @@ export function createAppComposition(deps: AppDependencies): {
522
541
  );
523
542
  });
524
543
 
544
+ app.use("/v1/workspaces/:workspaceId/*", async (c, next) => {
545
+ const workspaceId = c.req.param("workspaceId");
546
+ if (workspaceRequestRequiresCodexAccountPrevalidation(c.req.raw)) {
547
+ const grant = await requireAccessGrant(c, routeDeps, workspaceId);
548
+ await validateCodexAccountTarget(c.req.raw);
549
+ await withAccessGrantSessionRlsContext(routeDeps, grant, next);
550
+ return;
551
+ }
552
+ if (workspaceActorContextExempt(c.req.method, new URL(c.req.url).pathname)) {
553
+ await next();
554
+ return;
555
+ }
556
+ const grant = await requireAccessGrant(c, routeDeps, workspaceId);
557
+ await withAccessGrantSessionRlsContext(routeDeps, grant, next);
558
+ });
559
+
525
560
  app.all("/v1/workspaces/:workspaceId/mcp", async (c) => {
526
561
  const workspaceId = c.req.param("workspaceId");
527
562
  let boundedRequest: Request;
@@ -536,37 +571,41 @@ export function createAppComposition(deps: AppDependencies): {
536
571
  throw error;
537
572
  }
538
573
  const grant = await requireMcpAccessGrant(c, routeDeps, workspaceId);
539
- const boundSessionId = grant.metadata?.sessionId;
540
- if (typeof boundSessionId === "string") {
541
- try {
542
- await requireSessionAuthorization(routeDeps, grant, {
543
- sessionId: boundSessionId,
544
- operation: "session.first_party_mcp.call",
545
- surface: "first_party_mcp",
546
- });
547
- } catch (error) {
548
- if (error instanceof SessionAuthorizationDeniedError) {
549
- throw new HTTPException(404, { message: "session not found" });
550
- }
551
- if (error instanceof SessionAuthorizationUnavailableError) {
552
- throw new HTTPException(503, {
553
- message: "session authorization is unavailable",
574
+ return await withAccessGrantSessionRlsContext(routeDeps, grant, async () => {
575
+ const boundSessionId = grant.metadata?.sessionId;
576
+ if (typeof boundSessionId === "string") {
577
+ try {
578
+ await requireSessionAuthorization(routeDeps, grant, {
579
+ sessionId: boundSessionId,
580
+ operation: "session.first_party_mcp.call",
581
+ surface: "first_party_mcp",
554
582
  });
583
+ } catch (error) {
584
+ if (error instanceof SessionAuthorizationDeniedError) {
585
+ throw new HTTPException(404, { message: "session not found" });
586
+ }
587
+ if (error instanceof SessionAuthorizationUnavailableError) {
588
+ throw new HTTPException(503, {
589
+ message: "session authorization is unavailable",
590
+ });
591
+ }
592
+ throw error;
555
593
  }
556
- throw error;
557
594
  }
558
- }
559
- const workspace = await getWorkspace(routeDeps.db, workspaceId);
560
- const workspaceMemoryEnabled = resolveWorkspaceMemoryEnabled(workspace?.settings);
561
- const transport = new WebStandardStreamableHTTPServerTransport({
562
- enableJsonResponse: true,
563
- });
564
- const mcp = buildOpenGeniMcpServer(routeDeps, grant, {
565
- requestOrigin: new URL(c.req.url).origin,
566
- workspaceMemoryEnabled,
595
+ const workspace = await getWorkspace(routeDeps.db, workspaceId);
596
+ const workspaceMemoryEnabled = resolveWorkspaceMemoryEnabled(workspace?.settings);
597
+ const workspaceMemoryPromptMode = resolveWorkspaceMemoryPromptMode(workspace?.settings);
598
+ const transport = new WebStandardStreamableHTTPServerTransport({
599
+ enableJsonResponse: true,
600
+ });
601
+ const mcp = buildOpenGeniMcpServer(routeDeps, grant, {
602
+ requestOrigin: new URL(c.req.url).origin,
603
+ workspaceMemoryEnabled,
604
+ workspaceMemoryPromptMode,
605
+ });
606
+ await mcp.connect(transport);
607
+ return await transport.handleRequest(boundedRequest);
567
608
  });
568
- await mcp.connect(transport);
569
- return await transport.handleRequest(boundedRequest);
570
609
  });
571
610
 
572
611
  app.get("/v1/workspaces/:workspaceId/codemode/catalog", async (c) => {
@@ -631,10 +670,12 @@ export function createAppComposition(deps: AppDependencies): {
631
670
  registerDocumentRoutes(app, routeDeps);
632
671
  registerGitHubRoutes(app, routeDeps);
633
672
  registerInstallRoutes(app, routeDeps);
673
+ registerInteractionResourceRoutes(app, routeDeps);
634
674
  registerWorkspaceRoutes(app, routeDeps);
635
675
  registerInsightsRoutes(app, routeDeps);
636
676
  registerWorkspaceInstructionPolicyRoutes(app, routeDeps);
637
677
  registerCompanyProfileRoutes(app, routeDeps);
678
+ registerSlackTaskPolicyRoutes(app, routeDeps);
638
679
  registerWorkspaceStateRoutes(app, routeDeps);
639
680
  registerMemorySlackPublicationRoutes(app, routeDeps);
640
681
  registerWorkspaceArtifactRoutes(app, routeDeps);
@@ -643,11 +684,12 @@ export function createAppComposition(deps: AppDependencies): {
643
684
  registerConnectionRoutes(app, routeDeps);
644
685
  registerCapabilityRoutes(app, routeDeps);
645
686
  registerApiIntegrationRoutes(app, routeDeps);
646
- registerIntegrationFeatureRoutes(app, routeDeps);
687
+ registerIntegrationFacetRoutes(app, routeDeps);
647
688
  registerCatalogAssetRoutes(app, routeDeps);
648
689
  registerEnrollmentRoutes(app, routeDeps);
649
690
  registerMachineRoutes(app, routeDeps);
650
691
  registerEnvironmentRoutes(app, routeDeps);
692
+ registerChannelRoutes(app, routeDeps);
651
693
  registerRigRoutes(app, routeDeps);
652
694
  registerPackRoutes(app, routeDeps);
653
695
  registerPluginRoutes(app, routeDeps);
@@ -655,9 +697,12 @@ export function createAppComposition(deps: AppDependencies): {
655
697
  registerSessionRoutes(app, routeDeps);
656
698
  registerScheduledTaskRoutes(app, routeDeps);
657
699
  registerCodexRoutes(app, routeDeps);
700
+ registerSuperGrokRoutes(app, routeDeps);
658
701
  registerTranscriptionRoutes(app, routeDeps);
659
702
  registerEditableArtifactRoutes(app, routeDeps);
660
703
  registerVideoGenerationRoutes(app, routeDeps);
704
+ registerCanonicalHumanIdentityRoutes(app, routeDeps);
705
+ registerOrganizationMembershipRoutes(app, routeDeps);
661
706
  registerSlackInteractionRoutes(app, routeDeps);
662
707
 
663
708
  app.notFound((c) => {
@@ -699,6 +744,7 @@ export function createAppComposition(deps: AppDependencies): {
699
744
  ? (boundedPublicMessage(apiError.message) ?? "Request failed.")
700
745
  : publicErrorMessage(error, status),
701
746
  retryable: apiError?.retryable ?? retryableHttpStatus(status),
747
+ ...(mutationOutcomeUnknown(error, c.req.method) ? { outcomeUnknown: true } : {}),
702
748
  requestId,
703
749
  ...(apiError?.details ? { details: apiError.details } : {}),
704
750
  },
@@ -709,6 +755,14 @@ export function createAppComposition(deps: AppDependencies): {
709
755
  return { app, routeDeps };
710
756
  }
711
757
 
758
+ function mutationOutcomeUnknown(error: unknown, method: string): boolean {
759
+ if (method === "GET" || method === "HEAD" || method === "OPTIONS") return false;
760
+ const cause = error instanceof HTTPException ? error.cause : error;
761
+ return (
762
+ cause instanceof BrowserControlTransportError || cause instanceof BrowserControlProtocolError
763
+ );
764
+ }
765
+
712
766
  export function appendVary(current: string | null, value: string): string {
713
767
  const values = (current ?? "")
714
768
  .split(",")
@@ -720,6 +774,74 @@ export function appendVary(current: string | null, value: string): string {
720
774
  return values.join(", ");
721
775
  }
722
776
 
777
+ const publicWorkspaceBrowserRoutePatterns = [
778
+ /^\/v1\/workspaces\/[^/]+\/github\/connect$/,
779
+ /^\/v1\/workspaces\/[^/]+\/github\/installations\/[^/]+\/configure$/,
780
+ /^\/v1\/workspaces\/[^/]+\/github\/installations\/select$/,
781
+ ] as const;
782
+
783
+ export function workspaceActorContextExempt(method: string, pathname: string): boolean {
784
+ if (/^\/v1\/workspaces\/[^/]+\/mcp$/.test(pathname)) return true;
785
+ if (
786
+ method === "GET" &&
787
+ publicWorkspaceBrowserRoutePatterns.some((route) => route.test(pathname))
788
+ ) {
789
+ return true;
790
+ }
791
+ return method === "POST" && /^\/v1\/workspaces\/[^/]+\/github\/installations$/.test(pathname);
792
+ }
793
+
794
+ function workspaceRequestRequiresCodexAccountPrevalidation(request: Request): boolean {
795
+ return (
796
+ request.method === "POST" &&
797
+ /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/codex-account$/.test(new URL(request.url).pathname)
798
+ );
799
+ }
800
+
801
+ async function validateCodexAccountTarget(request: Request): Promise<void> {
802
+ const body = (await request
803
+ .clone()
804
+ .json()
805
+ .catch(() => null)) as { target?: unknown } | null;
806
+ if (typeof body?.target !== "string" || body.target.length === 0) {
807
+ throw new HTTPException(400, {
808
+ message: 'target is required ("auto" or an account id)',
809
+ });
810
+ }
811
+ }
812
+
813
+ async function withAccessGrantSessionRlsContext<T>(
814
+ deps: ApiRouteDeps,
815
+ grant: AccessGrant,
816
+ fn: () => Promise<T>,
817
+ ): Promise<T> {
818
+ if (grant.principalKind !== "agent_attempt") {
819
+ return await withSessionRlsActorContext({ subjectId: grant.subjectId }, fn);
820
+ }
821
+ const callerSessionId = grant.metadata?.sessionId;
822
+ if (typeof callerSessionId !== "string") {
823
+ throw new HTTPException(403, { message: "agent attempt authority is invalid" });
824
+ }
825
+ try {
826
+ const actor = await requireLiveAgentAttemptAuthorization(deps.db, grant, callerSessionId);
827
+ return await withSessionRlsActorContext(
828
+ {
829
+ subjectId: actor.subjectId,
830
+ initiatingHumanSubjectId: actor.initiatingHumanSubjectId,
831
+ },
832
+ fn,
833
+ );
834
+ } catch (error) {
835
+ if (error instanceof SessionAuthorizationDeniedError) {
836
+ throw new HTTPException(403, {
837
+ message: "agent attempt authority is invalid",
838
+ cause: error,
839
+ });
840
+ }
841
+ throw error;
842
+ }
843
+ }
844
+
723
845
  async function requireMcpAccessGrant(
724
846
  c: Parameters<typeof requireAccessGrant>[0],
725
847
  deps: ApiRouteDeps,
@@ -989,7 +1111,10 @@ async function withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T
989
1111
  }
990
1112
  }
991
1113
 
992
- const routeLabelPatterns: Array<{ pattern: RegExp; label: string }> = [
1114
+ const routeLabelPatterns: Array<{
1115
+ pattern: RegExp;
1116
+ label: string | ((match: RegExpMatchArray) => string);
1117
+ }> = [
993
1118
  { pattern: /^\/healthz$/, label: "/healthz" },
994
1119
  { pattern: /^\/readyz$/, label: "/readyz" },
995
1120
  { pattern: /^\/traffic-readyz$/, label: "/traffic-readyz" },
@@ -1005,6 +1130,22 @@ const routeLabelPatterns: Array<{ pattern: RegExp; label: string }> = [
1005
1130
  pattern: /^\/v1\/workspaces\/[^/]+\/codex\/status$/,
1006
1131
  label: "/v1/workspaces/:workspaceId/codex/status",
1007
1132
  },
1133
+ {
1134
+ pattern: /^\/v1\/workspaces\/[^/]+\/supergrok\/connect\/(start|poll)$/,
1135
+ label: (match) => `/v1/workspaces/:workspaceId/supergrok/connect/${match[1]}`,
1136
+ },
1137
+ {
1138
+ pattern: /^\/v1\/workspaces\/[^/]+\/supergrok\/(status|accounts|settings)$/,
1139
+ label: (match) => `/v1/workspaces/:workspaceId/supergrok/${match[1]}`,
1140
+ },
1141
+ {
1142
+ pattern: /^\/v1\/workspaces\/[^/]+\/supergrok\/accounts\/[^/]+\/(activate|allocator)$/,
1143
+ label: (match) => `/v1/workspaces/:workspaceId/supergrok/accounts/:accountId/${match[1]}`,
1144
+ },
1145
+ {
1146
+ pattern: /^\/v1\/workspaces\/[^/]+\/supergrok\/accounts\/[^/]+$/,
1147
+ label: "/v1/workspaces/:workspaceId/supergrok/accounts/:accountId",
1148
+ },
1008
1149
  {
1009
1150
  pattern: /^\/v1\/workspaces\/[^/]+\/codex\/usage$/,
1010
1151
  label: "/v1/workspaces/:workspaceId/codex/usage",
@@ -1051,6 +1192,154 @@ const routeLabelPatterns: Array<{ pattern: RegExp; label: string }> = [
1051
1192
  pattern: /^\/v1\/workspaces\/[^/]+\/control-events\/stream$/,
1052
1193
  label: "/v1/workspaces/:workspaceId/control-events/stream",
1053
1194
  },
1195
+ {
1196
+ pattern: /^\/v1\/workspaces\/[^/]+\/live-events\/stream$/,
1197
+ label: "/v1/workspaces/:workspaceId/live-events/stream",
1198
+ },
1199
+ {
1200
+ pattern: /^\/v1\/workspaces\/[^/]+\/interaction-events\/stream$/,
1201
+ label: "/v1/workspaces/:workspaceId/interaction-events/stream",
1202
+ },
1203
+ {
1204
+ pattern: /^\/v1\/workspaces\/[^/]+\/attached-browsers\/[^/]+$/,
1205
+ label: "/v1/workspaces/:workspaceId/attached-browsers/:deviceId",
1206
+ },
1207
+ {
1208
+ pattern: /^\/v1\/workspaces\/[^/]+\/attached-browsers$/,
1209
+ label: "/v1/workspaces/:workspaceId/attached-browsers",
1210
+ },
1211
+ {
1212
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-identities\/[^/]+\/revisions$/,
1213
+ label: "/v1/workspaces/:workspaceId/browser-identities/:identityId/revisions",
1214
+ },
1215
+ {
1216
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-identities\/[^/]+$/,
1217
+ label: "/v1/workspaces/:workspaceId/browser-identities/:identityId",
1218
+ },
1219
+ {
1220
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-identities$/,
1221
+ label: "/v1/workspaces/:workspaceId/browser-identities",
1222
+ },
1223
+ {
1224
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/downloads\/[^/]+\/save$/,
1225
+ label:
1226
+ "/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/downloads/:downloadId/save",
1227
+ },
1228
+ {
1229
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/downloads\/[^/]+$/,
1230
+ label: "/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/downloads/:downloadId",
1231
+ },
1232
+ {
1233
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/downloads$/,
1234
+ label: "/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/downloads",
1235
+ },
1236
+ {
1237
+ pattern:
1238
+ /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/auth-runs\/[^/]+\/external-auth\/interactive$/,
1239
+ label:
1240
+ "/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/auth-runs/:authRunId/external-auth/interactive",
1241
+ },
1242
+ {
1243
+ pattern:
1244
+ /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/auth-runs\/[^/]+\/(external-auth|protected-fill|report|verify)$/,
1245
+ label: (match) =>
1246
+ `/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/auth-runs/:authRunId/${match[1]}`,
1247
+ },
1248
+ {
1249
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/auth-runs\/[^/]+$/,
1250
+ label: "/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/auth-runs/:authRunId",
1251
+ },
1252
+ {
1253
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/auth-runs$/,
1254
+ label: "/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/auth-runs",
1255
+ },
1256
+ {
1257
+ pattern:
1258
+ /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/targets\/[^/]+\/(diagnostics|observation|select)$/,
1259
+ label: (match) =>
1260
+ `/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/targets/:targetId/${match[1]}`,
1261
+ },
1262
+ {
1263
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/targets\/[^/]+$/,
1264
+ label: "/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/targets/:targetId",
1265
+ },
1266
+ {
1267
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/operations\/[^/]+$/,
1268
+ label: "/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/operations/:operationId",
1269
+ },
1270
+ {
1271
+ pattern:
1272
+ /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+\/(actions|attachments|clipboard|end|heartbeat|resume|revisions|suspend|targets)$/,
1273
+ label: (match) => `/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/${match[1]}`,
1274
+ },
1275
+ {
1276
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-sessions\/[^/]+$/,
1277
+ label: "/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId",
1278
+ },
1279
+ {
1280
+ pattern: /^\/v1\/workspaces\/[^/]+\/browser-sessions$/,
1281
+ label: "/v1/workspaces/:workspaceId/browser-sessions",
1282
+ },
1283
+ {
1284
+ pattern: /^\/v1\/workspaces\/[^/]+\/computer-sessions\/[^/]+\/targets\/[^/]+\/observation$/,
1285
+ label:
1286
+ "/v1/workspaces/:workspaceId/computer-sessions/:computerSessionId/targets/:targetId/observation",
1287
+ },
1288
+ {
1289
+ pattern: /^\/v1\/workspaces\/[^/]+\/computer-sessions\/[^/]+\/operations\/[^/]+$/,
1290
+ label:
1291
+ "/v1/workspaces/:workspaceId/computer-sessions/:computerSessionId/operations/:operationId",
1292
+ },
1293
+ {
1294
+ pattern:
1295
+ /^\/v1\/workspaces\/[^/]+\/computer-sessions\/[^/]+\/(actions|attachments|clipboard|end|heartbeat|targets)$/,
1296
+ label: (match) =>
1297
+ `/v1/workspaces/:workspaceId/computer-sessions/:computerSessionId/${match[1]}`,
1298
+ },
1299
+ {
1300
+ pattern: /^\/v1\/workspaces\/[^/]+\/computer-sessions\/[^/]+$/,
1301
+ label: "/v1/workspaces/:workspaceId/computer-sessions/:computerSessionId",
1302
+ },
1303
+ {
1304
+ pattern: /^\/v1\/workspaces\/[^/]+\/computer-sessions$/,
1305
+ label: "/v1/workspaces/:workspaceId/computer-sessions",
1306
+ },
1307
+ {
1308
+ pattern: /^\/v1\/workspaces\/[^/]+\/network-routes\/[^/]+$/,
1309
+ label: "/v1/workspaces/:workspaceId/network-routes/:networkRouteId",
1310
+ },
1311
+ {
1312
+ pattern: /^\/v1\/workspaces\/[^/]+\/network-routes$/,
1313
+ label: "/v1/workspaces/:workspaceId/network-routes",
1314
+ },
1315
+ {
1316
+ pattern: /^\/v1\/workspaces\/[^/]+\/site-auth-connections\/[^/]+$/,
1317
+ label: "/v1/workspaces/:workspaceId/site-auth-connections/:siteAuthConnectionId",
1318
+ },
1319
+ {
1320
+ pattern: /^\/v1\/workspaces\/[^/]+\/site-auth-connections$/,
1321
+ label: "/v1/workspaces/:workspaceId/site-auth-connections",
1322
+ },
1323
+ {
1324
+ pattern: /^\/v1\/workspaces\/[^/]+\/auth-runs\/[^/]+$/,
1325
+ label: "/v1/workspaces/:workspaceId/auth-runs/:authRunId",
1326
+ },
1327
+ {
1328
+ pattern: /^\/v1\/workspaces\/[^/]+\/auth-runs$/,
1329
+ label: "/v1/workspaces/:workspaceId/auth-runs",
1330
+ },
1331
+ {
1332
+ pattern: /^\/v1\/workspaces\/[^/]+\/interaction-interventions\/[^/]+\/resolve$/,
1333
+ label: "/v1/workspaces/:workspaceId/interaction-interventions/:interventionId/resolve",
1334
+ },
1335
+ {
1336
+ pattern: /^\/v1\/workspaces\/[^/]+\/interaction-interventions\/[^/]+$/,
1337
+ label: "/v1/workspaces/:workspaceId/interaction-interventions/:interventionId",
1338
+ },
1339
+ {
1340
+ pattern: /^\/v1\/workspaces\/[^/]+\/interaction-interventions$/,
1341
+ label: "/v1/workspaces/:workspaceId/interaction-interventions",
1342
+ },
1054
1343
  {
1055
1344
  pattern: /^\/v1\/workspaces\/[^/]+\/control-events$/,
1056
1345
  label: "/v1/workspaces/:workspaceId/control-events",
@@ -1281,8 +1570,8 @@ const routeLabelPatterns: Array<{ pattern: RegExp; label: string }> = [
1281
1570
  label: "/v1/workspaces/:workspaceId/integrations/install",
1282
1571
  },
1283
1572
  {
1284
- pattern: /^\/v1\/workspaces\/[^/]+\/integrations\/presets$/,
1285
- label: "/v1/workspaces/:workspaceId/integrations/presets",
1573
+ pattern: /^\/v1\/workspaces\/[^/]+\/integrations\/definitions$/,
1574
+ label: "/v1/workspaces/:workspaceId/integrations/definitions",
1286
1575
  },
1287
1576
  {
1288
1577
  pattern: /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/uninstall-preview$/,
@@ -1291,36 +1580,36 @@ const routeLabelPatterns: Array<{ pattern: RegExp; label: string }> = [
1291
1580
  },
1292
1581
  {
1293
1582
  pattern:
1294
- /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/features\/[^/]+\/browse$/,
1583
+ /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/facets\/[^/]+\/browse$/,
1295
1584
  label:
1296
- "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/features/:featureKey/browse",
1585
+ "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/facets/:facetKey/browse",
1297
1586
  },
1298
1587
  {
1299
1588
  pattern:
1300
- /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/features\/[^/]+\/source$/,
1589
+ /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/facets\/[^/]+\/source$/,
1301
1590
  label:
1302
- "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/features/:featureKey/source",
1591
+ "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/facets/:facetKey/source",
1303
1592
  },
1304
1593
  {
1305
1594
  pattern:
1306
- /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/features\/[^/]+\/pause$/,
1595
+ /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/facets\/[^/]+\/pause$/,
1307
1596
  label:
1308
- "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/features/:featureKey/pause",
1597
+ "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/facets/:facetKey/pause",
1309
1598
  },
1310
1599
  {
1311
1600
  pattern:
1312
- /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/features\/[^/]+\/resume$/,
1601
+ /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/facets\/[^/]+\/resume$/,
1313
1602
  label:
1314
- "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/features/:featureKey/resume",
1603
+ "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/facets/:facetKey/resume",
1315
1604
  },
1316
1605
  {
1317
- pattern: /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/features\/[^/]+$/,
1606
+ pattern: /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/facets\/[^/]+$/,
1318
1607
  label:
1319
- "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/features/:featureKey",
1608
+ "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/facets/:facetKey",
1320
1609
  },
1321
1610
  {
1322
- pattern: /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/features$/,
1323
- label: "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/features",
1611
+ pattern: /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+\/facets$/,
1612
+ label: "/v1/workspaces/:workspaceId/integrations/:capabilityId/instances/:instanceKey/facets",
1324
1613
  },
1325
1614
  {
1326
1615
  pattern: /^\/v1\/workspaces\/[^/]+\/integrations\/[^/]+\/instances\/[^/]+$/,
@@ -1422,6 +1711,18 @@ const routeLabelPatterns: Array<{ pattern: RegExp; label: string }> = [
1422
1711
  pattern: /^\/v1\/workspaces\/[^/]+\/connections\/slack-bot\/install$/,
1423
1712
  label: "/v1/workspaces/:workspaceId/connections/slack-bot/install",
1424
1713
  },
1714
+ {
1715
+ pattern: /^\/v1\/workspaces\/[^/]+\/connections\/fiken\/install$/,
1716
+ label: "/v1/workspaces/:workspaceId/connections/fiken/install",
1717
+ },
1718
+ {
1719
+ pattern: /^\/v1\/workspaces\/[^/]+\/connections\/fiken\/oauth\/start$/,
1720
+ label: "/v1/workspaces/:workspaceId/connections/fiken/oauth/start",
1721
+ },
1722
+ {
1723
+ pattern: /^\/v1\/integrations\/fiken\/callback$/,
1724
+ label: "/v1/integrations/fiken/callback",
1725
+ },
1425
1726
  {
1426
1727
  pattern: /^\/v1\/workspaces\/[^/]+\/connections\/[^/]+$/,
1427
1728
  label: "/v1/workspaces/:workspaceId/connections/:connectionId",
@@ -1495,9 +1796,11 @@ const routeLabelPatterns: Array<{ pattern: RegExp; label: string }> = [
1495
1796
  ];
1496
1797
 
1497
1798
  export function routeLabel(pathname: string): string {
1498
- const match = routeLabelPatterns.find(({ pattern }) => pattern.test(pathname));
1499
- if (match) {
1500
- return match.label;
1799
+ for (const candidate of routeLabelPatterns) {
1800
+ const match = pathname.match(candidate.pattern);
1801
+ if (match) {
1802
+ return typeof candidate.label === "string" ? candidate.label : candidate.label(match);
1803
+ }
1501
1804
  }
1502
1805
  return pathname.startsWith("/v1/") ? "/v1/unknown" : "/unknown";
1503
1806
  }