42.2 KB1317 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {TypeaheadResult} from 'isl-components/Types';
9import type {TrackEventName} from 'isl-server/src/analytics/eventNames';
10import type {TrackDataWithEventName} from 'isl-server/src/analytics/types';
11import type {GitHubDiffSummary} from 'isl-server/src/github/githubCodeReviewProvider';
12import type {GroveDiffSummary} from 'isl-server/src/grove/groveCodeReviewProvider';
13import type {Comparison} from 'shared/Comparison';
14import type {ParsedDiff} from 'shared/patch/types';
15import type {AllUndefined, Json} from 'shared/typeUtils';
16import type {Hash} from 'shared/types/common';
17import type {ExportStack, ImportedStack, ImportStack} from 'shared/types/stack';
18import type {TypeaheadKind} from './CommitInfoView/types';
19import type {InternalTypes} from './InternalTypes';
20import type {CodeReviewIssue} from './firstPassCodeReview/types';
21import type {Serializable} from './serialize';
22import type {Args, DiffCommit, PartiallySelectedDiffCommit} from './stackEdit/diffSplitTypes';
23
24export type Result<T> = {value: T; error?: undefined} | {value?: undefined; error: Error};
25
26/** known supported "Platforms" in which ISL may be embedded */
27export type PlatformName =
28 | 'browser'
29 | 'androidStudio'
30 | 'androidStudioRemote'
31 | 'vscode'
32 | 'webview'
33 | 'chromelike_app'
34 | 'visualStudio'
35 | 'obsidian';
36
37export type AbsolutePath = string;
38/**
39 * Path relative to repository root dir. Generally, most paths should be RepoRelativePaths,
40 * and only convert to CwdRelativePath or basenames or AbsolutePath when needed.
41 */
42export type RepoRelativePath = string;
43
44/**
45 * cwd may be a subdirectory of the repository root.
46 * Some commands expect cwd-relative paths,
47 * but we generally prefer {@link RepoRelativePaths} when possible. */
48export type CwdRelativePath = string;
49
50export type {Hash};
51
52/** Revsets are an eden concept that let you specify commits.
53 * This could be a Hash, '.' for HEAD, .^ for parent of head, etc. See `eden help revset` */
54export type Revset = string;
55
56/**
57 * Diff identifier according to the current repo's remote repository provider (e.g. GitHub)
58 * For Github, this is a PR number, like "7" (for PR #7)
59 * For Phabricator, this is a Diff number, like "D12345"
60 */
61export type DiffId = string;
62/**
63 * "Diff" means a unit of Code Review according to your remote repo provider
64 * For GitHub, this is a "Pull Request"
65 * For Phabricator, this is a "Diff"
66 */
67
68/**
69 * Short info about a Diff fetched in bulk for all diffs to render an overview
70 */
71export type DiffSummary = GitHubDiffSummary | GroveDiffSummary | InternalTypes['PhabricatorDiffSummary'];
72
73export type DiffCommentReaction = {
74 name: string;
75 reaction:
76 | 'ANGER'
77 | 'HAHA'
78 | 'LIKE'
79 | 'LOVE'
80 | 'WOW'
81 | 'SORRY'
82 | 'SAD'
83 | 'CONFUSED'
84 | 'EYES'
85 | 'HEART'
86 | 'HOORAY'
87 | 'LAUGH'
88 | 'ROCKET'
89 | 'THUMBS_DOWN'
90 | 'THUMBS_UP';
91};
92
93export type InternalCommitMessageFields = InternalTypes['InternalCommitMessageFields'];
94
95export enum CodePatchSuggestionStatus {
96 Accepted = 'ACCEPTED',
97 Declined = 'DECLINED',
98 Unset = 'UNSET',
99}
100
101export enum SuggestedChangeType {
102 HUMAN_SUGGESTION = 'HUMAN_SUGGESTION',
103 METAMATE_SUGGESTION = 'METAMATE_SUGGESTION',
104 CI_SIGNAL = 'CI_SIGNAL',
105}
106
107export enum ArchivedStateType {
108 ARCHIVED = 'ARCHIVED',
109 NOT_ARCHIVED = 'NOT_ARCHIVED',
110}
111
112export enum ArchivedReasonType {
113 APPLIED_IN_EDITOR = 'APPLIED_IN_EDITOR',
114 APPLIED_MERGED = 'APPLIED_MERGED',
115 APPLIED_STACKED_DIFF = 'APPLIED_STACKED_DIFF',
116 AUTHOR_DISCARDED = 'AUTHOR_DISCARDED',
117 STALE_DIFF_CLOSED = 'STALE_DIFF_CLOSED',
118 STALE_FILE_CHANGED = 'STALE_FILE_CHANGED',
119}
120
121export enum WarningCheckResult {
122 PASS = 'PASS',
123 FAIL = 'FAIL',
124 BYPASS = 'BYPASS',
125}
126
127export type CodeChange = {
128 oldContent?: string;
129 newContent?: string;
130 oldLineNumber?: number;
131 trimmedLineNumber?: number;
132 trimmedLength?: number;
133 adjustedLineNumber?: number;
134 patch?: ParsedDiff;
135};
136
137export type SuggestedChange = {
138 id?: string;
139 type?: SuggestedChangeType;
140 codePatchSuggestionID?: string;
141 codePatchID?: string;
142 status?: CodePatchSuggestionStatus;
143 archivedState?: ArchivedStateType;
144 archivedReason?: ArchivedReasonType;
145 commitHashBefore?: string;
146 patch?: ParsedDiff;
147 oldPath?: string;
148 currentPath?: string;
149 codeChange?: CodeChange[];
150};
151
152export type DiffComment = {
153 id?: string;
154 author: string;
155 authorName?: string;
156 authorAvatarUri?: string;
157 html: string;
158 content?: string;
159 created: Date;
160 commitHash?: string;
161 /** If it's an inline comment, this is the file path with the comment */
162 filename?: string;
163 /** If it's an inline comment, this is the line it was added */
164 line?: number;
165 reactions: Array<DiffCommentReaction>;
166 /** Suggestion for how to change the code, as a patch */
167 suggestedChange?: SuggestedChange;
168 replies: Array<DiffComment>;
169 /** If this comment has been resolved. true => "resolved", false => "unresolved", null => the comment is not resolvable, don't show any UI for it */
170 isResolved?: boolean;
171};
172
173/**
174 * Summary of CI test results for a Diff.
175 * 'pass' if ALL signals succeed and not still running.
176 * 'failed' if ANY signal doesn't succeed, even if some are still running.
177 * 'deferred' if tests are deferred and waiting to be started.
178 */
179export type DiffSignalSummary =
180 | 'running'
181 | 'pass'
182 | 'failed'
183 | 'warning'
184 | 'no-signal'
185 | 'land-cancelled'
186 | 'deferred';
187
188/**
189 * Information about a land request, specific to each Code Review Provider.
190 */
191export type LandInfo = undefined | InternalTypes['PhabricatorLandInfo'];
192
193/**
194 * Information used to confirm a land from a given initiation LandInfo.
195 */
196export type LandConfirmationInfo = undefined | InternalTypes['PhabricatorLandConfirmationInfo'];
197
198/** An error causing the entire Repository to not be accessible */
199export type RepositoryError =
200 | {
201 type: 'invalidCommand';
202 command: string;
203 path: string | undefined;
204 }
205 | {type: 'edenFsUnhealthy'; cwd: string}
206 | {type: 'cwdNotARepository'; cwd: string}
207 | {type: 'cwdDoesNotExist'; cwd: string}
208 | {
209 type: 'unknownError';
210 error: Error;
211 };
212
213export type CwdInfo = {
214 /** Full cwd path, like /Users/username/repoRoot/some/subfolder */
215 cwd: AbsolutePath;
216 /** Full real path to the repository root, like /Users/username/repoRoot
217 * Undefined for cwds that are not valid repositories */
218 repoRoot?: AbsolutePath;
219 /** Label for a cwd, which is <repoBasename>/<cwd>, like 'sapling/addons'.
220 * Intended for display. Undefined for cwds that are not valid repositories */
221 repoRelativeCwdLabel?: string;
222};
223
224export type RepoInfo = RepositoryError | ValidatedRepoInfo;
225
226/** Proven valid repositories with valid repoRoot / dotdir */
227export type ValidatedRepoInfo = {
228 type: 'success';
229 /** Which cli command name this repository should use for sapling, e.g. `sl` */
230 command: string;
231 /**
232 * Direct repo root that is the closest to the cwd.
233 */
234 repoRoot: AbsolutePath;
235 /**
236 * All the nested repo roots up to the system root,
237 * in the order of furthest to closest to the cwd.
238 *
239 * For instance, ['/repo', '/repo/submodule', '/repo/submodule/nested_submodule']
240 *
241 * The repoRoot above is not simply replaced with this because of different error conditions -
242 * Sapling may refuse to return the list when it's nested illegally, while repoRoot can still be valid.
243 */
244 repoRoots?: AbsolutePath[];
245 /**
246 * Directory containing sl internal information for this repo, usually `${repoRoot}/.sl`.
247 */
248 dotdir: AbsolutePath;
249 codeReviewSystem: CodeReviewSystem;
250 pullRequestDomain: string | undefined;
251 preferredSubmitCommand?: PreferredSubmitCommand;
252 isEdenFs: boolean;
253};
254
255export type ApplicationInfo = {
256 platformName: string;
257 version: string;
258 logFilePath: string;
259 readOnly?: boolean;
260};
261
262/**
263 * Which "mode" for the App to run. Controls the basic rendering.
264 * Useful to render full-screen alternate views.
265 * isl => normal, full ISL
266 * comparison => just the comparison viewer is rendered, set to some specific comparison
267 */
268export type AppMode =
269 | {
270 mode: 'isl';
271 }
272 | {
273 mode: 'comparison';
274 comparison: Comparison;
275 };
276
277export type CodeReviewSystem =
278 | {
279 type: 'github';
280 owner: string;
281 repo: string;
282 /** github enterprise may use a different hostname than 'github.com' */
283 hostname: string;
284 }
285 | {
286 type: 'phabricator';
287 repo: string;
288 callsign?: string;
289 }
290 | {
291 type: 'grove';
292 /** Grove API base URL, e.g. https://grove.host/api */
293 apiUrl: string;
294 /** Repository owner (username or org) */
295 owner: string;
296 /** Repository name */
297 repo: string;
298 /** Whether pushes should automatically create diffs for code review */
299 requireDiffs?: boolean;
300 }
301 | {
302 type: 'none';
303 }
304 | {
305 type: 'unknown';
306 path?: string;
307 };
308
309export type PreferredSubmitCommand = 'pr' | 'ghstack' | 'push';
310
311export type StableCommitMetadata = {
312 value: string;
313 description: string;
314 isRecommended?: boolean;
315};
316
317export type StableCommitFetchConfig = {
318 template: string;
319 parse: (data: string) => Array<StableCommitMetadata>;
320};
321
322export type StableLocationData = {
323 /** Stables found automatically from recent builds */
324 stables: Array<Result<StableInfo>>;
325 /** Stables that enabled automatically for certain users */
326 special: Array<Result<StableInfo>>;
327 /** Stables entered in the UI. Map of provided name to a Result. null means the stable is loading. */
328 manual: Record<string, Result<StableInfo> | null>;
329 /** Whether this repo supports entering custom stables via input. */
330 repoSupportsCustomStables: boolean;
331};
332export type StableInfo = {
333 hash: string;
334 name: string;
335 /** If present, this is informational text, like the reason it's been added */
336 byline?: string;
337 /** If present, this is extra details that might be shown in a tooltip */
338 info?: string;
339 date: Date;
340};
341
342export type SlocInfo = {
343 /** Significant lines of code for commit */
344 sloc: number | undefined;
345};
346
347export type CommitInfo = {
348 title: string;
349 hash: Hash;
350 /**
351 * This matches the "parents" information from source control without the
352 * "null" hash. Most of the time a commit has 1 parent. For merges there
353 * could be 2 or more parents. The initial commit (and initial commits of
354 * other merged-in repos) have no parents.
355 */
356 parents: ReadonlyArray<Hash>;
357 /**
358 * Grandparents are the closest but indirect ancestors in a set of commits .
359 * In ISL, this is used for connecting nodes whose direct parents are NOT present.
360 * Note that this field will be empty by design when direct parents are already present in the set.
361 * See eden/scm/tests/test-template-grandparents.t for examples.
362 */
363 grandparents: ReadonlyArray<Hash>;
364 phase: CommitPhaseType;
365 /**
366 * Whether this commit is the "." (working directory parent).
367 * It is the parent of "wdir()" or the "You are here" virtual commit.
368 */
369 isDot: boolean;
370 author: string;
371 date: Date;
372 description: string;
373 bookmarks: ReadonlyArray<string>;
374 remoteBookmarks: ReadonlyArray<string>;
375 /** if this commit is obsolete, it is succeeded by another commit */
376 successorInfo?: Readonly<SuccessorInfo>;
377 /**
378 * Closest predecessors (not all recursive predecessors, which can be a long
379 * chain and hurt performance). Useful to deal with optimistic states where
380 * we know the hashes of predecessors (commits being rewritten) but not their
381 * successors (rewritten result).
382 *
383 * Most of the time a commit only has one predecessor. In case of a fold
384 * there are multiple predecessors.
385 */
386 closestPredecessors?: ReadonlyArray<Hash>;
387 /**
388 * If this is a fake optimistic commit created by a running Operation,
389 * this is the revset that can be used by sl to find the real commit.
390 * This is only valid after the operation which creates this commit has completed.
391 */
392 optimisticRevset?: Revset;
393 /** only a subset of the total changed file paths for this commit.
394 * File statuses must be fetched separately for performance.
395 */
396 filePathsSample: ReadonlyArray<RepoRelativePath>;
397 totalFileCount: number;
398 /** @see {@link DiffId} */
399 diffId?: DiffId;
400 isFollower?: boolean;
401 stableCommitMetadata?: ReadonlyArray<StableCommitMetadata>;
402 /**
403 * Longest path prefix shared by all files in this commit.
404 * For example, if a commit changes files like `a/b/c` and `a/b/d`, this is `a/b/`.
405 * Note: this always acts on `/` delimited paths, and is done on complete subdir names,
406 * never on matching prefixes of directories. For example, `a/dir1/a` and `a/dir2/a`
407 * have `a/` as the common prefix, not `a/dir`.
408 * If no commonality is found (due to edits to top level files or multiple subdirs), this is empty string.
409 * This can be useful to determine if a commit is relevant to your cwd.
410 */
411 maxCommonPathPrefix: RepoRelativePath;
412
413 fullRepoBranch?: InternalTypes['FullRepoBranch'];
414};
415export type SuccessorInfo = {
416 hash: string;
417 type: string;
418};
419export type CommitPhaseType = 'public' | 'draft';
420export type ChangedFileStatus = 'A' | 'M' | 'R' | '?' | '!' | 'U' | 'Resolved';
421export type ChangedFile = {
422 path: RepoRelativePath;
423 status: ChangedFileStatus;
424 /**
425 * If this file is copied from another, this is the path of the original file
426 * If this file is renamed from another, this is the path of the original file, and another change of type 'R' will exist.
427 * */
428 copy?: RepoRelativePath;
429};
430export enum ChangedFileMode {
431 // "Regular" is from the perspective of the ISL - it's a file that's not a submodule.
432 // This can be different from more granular categorizations in the underlying
433 // source control system, such as symlinks, executables, and gitlinks.
434 Regular = 'regular',
435 Submodule = 'submodule',
436}
437
438export type FilesSample = {
439 filesSample: Array<ChangedFile>;
440 totalFileCount: number;
441};
442
443/** A revset that selects for a commit which we only have a fake optimistic preview of */
444export type OptimisticRevset = {type: 'optimistic-revset'; revset: Revset; fake: string};
445/** A revset that selects for the latest version of a commit hash */
446export type SucceedableRevset = {type: 'succeedable-revset'; revset: Revset};
447/** A revset that selects for a specific commit, without considering any successors */
448export type ExactRevset = {type: 'exact-revset'; revset: Revset};
449
450/**
451 * Most arguments to eden commands are literal `string`s, except:
452 * - When specifying file paths, the server needs to know which args are files to convert them to be cwd-relative.
453 * - For long file lists, we pass them in a single bulk arg, which will be passed via stdin instead
454 * to avoid command line length limits.
455 * - When specifying commit hashes, you may be acting on optimistic version of those hashes.
456 * The server can re-write hashes using a revset that transforms into the latest successor instead.
457 * This allows you to act on the optimistic versions of commits in queued commands,
458 * without a race with the server telling you new versions of those hashes.
459 * - If you want an exact commit that's already obsolete or should never be replaced with a succeeded version,
460 * you can use an exact revset.
461 * - Specifying config values to override for just this command, so they can be processed separately.
462 */
463export type CommandArg =
464 | string
465 | {type: 'repo-relative-file'; path: RepoRelativePath}
466 | {type: 'repo-relative-file-list'; paths: Array<RepoRelativePath>}
467 | {type: 'config'; key: string; value: string}
468 | ExactRevset
469 | SucceedableRevset
470 | OptimisticRevset;
471
472/**
473 * What process to execute a given operation in, such as `sl`
474 */
475export enum CommandRunner {
476 Sapling = 'sl',
477 /**
478 * Use the configured Code Review provider to run this command,
479 * such as a non-sapling external submit command
480 */
481 CodeReviewProvider = 'codeReviewProvider',
482 /** Internal arcanist commands */
483 InternalArcanist = 'arc',
484 /** Configerator conf commands */
485 Conf = 'conf',
486}
487
488/**
489 * {@link CommandArg} representing a hash or revset which should be re-written
490 * to the latest successor of that revset when being run.
491 * This enables queued commands to act on optimistic state without knowing
492 * the optimistic commit's hashes directly.
493 */
494export function succeedableRevset(revset: Revset): SucceedableRevset {
495 return {type: 'succeedable-revset', revset};
496}
497
498/**
499 * {@link CommandArg} representing a hash or revset for a fake optimistic commit.
500 * This enables queued commands to act on optimistic state without knowing
501 * the optimistic commit's hashes directly, and without knowing a predecessor hash at all.
502 * The fake optimistic commit hash is also stored to know what the revset refers to.
503 */
504export function optimisticRevset(revset: Revset, fake: string): OptimisticRevset {
505 return {type: 'optimistic-revset', revset, fake};
506}
507
508/**
509 * {@link CommandArg} representing a hash or revset which should *not* be re-written
510 * to the latest successor of that revset when being run.
511 * This uses the revset directly in the command run. Useful if you want to specifically
512 * use an obsolete commit in an operation.
513 */
514export function exactRevset(revset: Revset): ExactRevset {
515 return {type: 'exact-revset', revset};
516}
517
518/* Subscriptions */
519
520/**
521 * A subscription allows the client to ask for a stream of events from the server.
522 * The client may send subscribe and corresponding unsubscribe messages.
523 * Subscriptions are indexed by a subscriptionId field.
524 * Responses to subscriptions are of type Fetched<T>
525 */
526export type Subscribe<K extends string> =
527 | {type: `subscribe${K}`; subscriptionID: string}
528 | {type: `unsubscribe${K}`; subscriptionID: string};
529
530/** Responses to subscriptions, including data and the time duration the fetch lasted */
531export type Fetched<K extends string, V> = {
532 type: `fetched${K}`;
533 subscriptionID: string;
534} & V;
535
536export type UncommittedChanges = Array<ChangedFile>;
537export type FetchedUncommittedChanges = {
538 files: Result<UncommittedChanges>;
539 fetchStartTimestamp: number;
540 fetchCompletedTimestamp: number;
541};
542
543export type BeganFetchingUncommittedChangesEvent = {
544 type: 'beganFetchingUncommittedChangesEvent';
545};
546
547export type SmartlogCommits = Array<CommitInfo>;
548export type FetchedCommits = {
549 commits: Result<SmartlogCommits>;
550 fetchStartTimestamp: number;
551 fetchCompletedTimestamp: number;
552};
553
554export type BeganFetchingSmartlogCommitsEvent = {
555 type: 'beganFetchingSmartlogCommitsEvent';
556};
557
558export type ShelvedChange = {
559 hash: Hash;
560 name: string;
561 date: Date;
562 filesSample: Array<ChangedFile>;
563 totalFileCount: number;
564 description: string;
565};
566
567export enum CommitCloudBackupStatus {
568 InProgress = 'IN_PROGRESS',
569 Pending = 'PENDING',
570 Failed = 'FAILED',
571}
572export type CommitCloudSyncState = {
573 isFetching?: boolean;
574 /** Last time we ran commands to check the cloud status */
575 lastChecked: Date;
576 /** Last time there was an actual sync */
577 lastBackup?: Date;
578 currentWorkspace?: string;
579 workspaceChoices?: Array<string>;
580 commitStatuses?: Map<Hash, CommitCloudBackupStatus>;
581 fetchError?: Error;
582 syncError?: Error;
583 workspaceError?: Error;
584 // if true, commit cloud is disabled in this repo
585 isDisabled?: boolean;
586};
587
588export type Submodule = {
589 name: string;
590 path: RepoRelativePath;
591 url: string;
592 ref?: string;
593 active: boolean;
594};
595/**
596 * An undefined value if git submodules are not supported by the repo.
597 * An error if unexpected errors occurred during the fetch process.
598 */
599export type FetchedSubmodules = Result<Submodule[] | undefined>;
600export type SubmodulesByRoot = Map<AbsolutePath, FetchedSubmodules>;
601
602export type AlertSeverity = 'SEV 0' | 'SEV 1' | 'SEV 2' | 'SEV 3' | 'SEV 4' | 'UBN';
603export type Alert = {
604 key: string;
605 title: string;
606 description: string;
607 url: string;
608 severity: AlertSeverity;
609 ['show-in-isl']: boolean;
610 ['isl-version-regex']?: string;
611};
612
613/**
614 * A file can be auto-generated, partially auto-generated, or not generated (manual).
615 * Numbered according to expected visual sort order.
616 */
617export enum GeneratedStatus {
618 Manual = 0,
619 PartiallyGenerated = 1,
620 Generated = 2,
621}
622
623export enum ConflictType {
624 BothChanged = 'both_changed',
625 DeletedInDest = 'dest_deleted',
626 DeletedInSource = 'source_deleted',
627}
628
629type ConflictInfo = {
630 command: string;
631 toContinue: string;
632 toAbort: string;
633 files: Array<ChangedFile & {conflictType: ConflictType}>;
634 fetchStartTimestamp: number;
635 fetchCompletedTimestamp: number;
636 hashes?: {local?: string; other?: string};
637};
638export type MergeConflicts =
639 | ({state: 'loading'} & AllUndefined<ConflictInfo>)
640 | ({
641 state: 'loaded';
642 } & ConflictInfo);
643
644/* Operations */
645
646export type RunnableOperation = {
647 args: Array<CommandArg>;
648 id: string;
649 stdin?: string | undefined;
650 runner: CommandRunner;
651 trackEventName: TrackEventName;
652};
653
654export type OperationProgress =
655 // another operation is running, so this one has been queued to run. Also include full state of the queue.
656 | {id: string; kind: 'queue'; queue: Array<string>}
657 // the server has started the process. This also servers as a "dequeue" notification. Also include full state of the queue.
658 | {id: string; kind: 'spawn'; queue: Array<string>}
659 | {id: string; kind: 'stderr'; message: string}
660 | {id: string; kind: 'stdout'; message: string}
661 // overally progress information, typically for a progress bar or progress not found directly in the stdout
662 | {id: string; kind: 'progress'; progress: ProgressStep}
663 // progress information for a specific commit, shown inline. Null hash means to apply the message to all hashes. Null message means to clear the message.
664 | {id: string; kind: 'inlineProgress'; hash?: string; message?: string}
665 | {id: string; kind: 'exit'; exitCode: number; timestamp: number}
666 | {id: string; kind: 'error'; error: string}
667 | {id: string; kind: 'warning'; warning: string}
668 // used by requestMissedOperationProgress, client thinks this operation is running but server no longer knows about it.
669 | {id: string; kind: 'forgot'};
670
671export type ProgressStep = {
672 message: string;
673 progress?: number;
674 progressTotal?: number;
675 unit?: string;
676};
677
678export type OperationCommandProgressReporter = (
679 ...args:
680 | ['spawn']
681 | ['stdout', string]
682 | ['stderr', string]
683 // null message -> clear inline progress for this hash. Null hash -> apply to all affected hashes (set message or clear)
684 | [type: 'inlineProgress', hash?: string, message?: string]
685 | ['progress', ProgressStep]
686 | ['warning', string]
687 | ['exit', number]
688) => void;
689
690export type OperationProgressEvent = {type: 'operationProgress'} & OperationProgress;
691
692/** A line number starting from 1 */
693export type OneIndexedLineNumber = Exclude<number, 0>;
694
695export type DiagnosticSeverity = 'error' | 'warning' | 'info' | 'hint';
696
697export type Diagnostic = {
698 range: {startLine: number; startCol: number; endLine: number; endCol: number};
699 message: string;
700 severity: DiagnosticSeverity;
701 /** LSP providing this diagnostic, like "typescript" or "eslint" */
702 source?: string;
703 /** Code or name for this kind of diagnostic */
704 code?: string;
705};
706
707export type DiagnosticAllowlistValue =
708 | {block: Set<string>; allow?: undefined}
709 | {allow: Set<string>; block?: undefined};
710export type DiagnosticAllowlist = Map<'warning' | 'error', Map<string, DiagnosticAllowlistValue>>;
711
712export type CodeReviewScope =
713 | 'uncommitted changes'
714 | 'current commit'
715 | 'current commit and uncommitted changes';
716
717/* protocol */
718
719/**
720 * messages sent by platform-specific (browser, vscode, electron) implementations
721 * to be handled uniquely per server type.
722 */
723export type PlatformSpecificClientToServerMessages =
724 | {type: 'platform/openFile'; path: RepoRelativePath; options?: {line?: OneIndexedLineNumber}}
725 | {
726 type: 'platform/openFiles';
727 paths: ReadonlyArray<RepoRelativePath>;
728 options?: {line?: OneIndexedLineNumber};
729 }
730 | {type: 'platform/openContainingFolder'; path: RepoRelativePath}
731 | {type: 'platform/openDiff'; path: RepoRelativePath; comparison: Comparison}
732 | {type: 'platform/openExternal'; url: string}
733 | {type: 'platform/changeTitle'; title: string}
734 | {type: 'platform/confirm'; message: string; details?: string | undefined}
735 | {type: 'platform/subscribeToAvailableCwds'}
736 | {type: 'platform/subscribeToUnsavedFiles'}
737 | {type: 'platform/saveAllUnsavedFiles'}
738 | {type: 'platform/setPersistedState'; key: string; data?: string}
739 | {type: 'platform/subscribeToSuggestedEdits'}
740 | {
741 type: 'platform/resolveSuggestedEdits';
742 action: 'accept' | 'reject';
743 files: Array<AbsolutePath>;
744 }
745 | {
746 type: 'platform/setVSCodeConfig';
747 config: string;
748 value: Json | undefined;
749 scope: 'workspace' | 'global';
750 }
751 | {type: 'platform/checkForDiagnostics'; paths: Array<RepoRelativePath>}
752 | {type: 'platform/executeVSCodeCommand'; command: string; args: Array<Json>}
753 | {type: 'platform/subscribeToVSCodeConfig'; config: string}
754 | {
755 type: 'platform/resolveAllCommentsWithAI';
756 diffId: string;
757 comments: Array<DiffComment>;
758 filePaths: Array<RepoRelativePath>;
759 repoPath?: string;
760 userContext?: string;
761 }
762 | {
763 type: 'platform/resolveFailedSignalsWithAI';
764 diffId: string;
765 diffVersionNumber: number;
766 repoPath?: string;
767 userContext?: string;
768 }
769 | {
770 type: 'platform/fillCommitMessageWithAI';
771 id: string;
772 source: 'commitInfoView' | 'smartAction';
773 userContext?: string;
774 }
775 | {
776 type: 'platform/splitCommitWithAI';
777 diffCommit: string;
778 args?: string;
779 repoPath?: string;
780 userContext?: string;
781 }
782 | {
783 type: 'platform/createTestForModifiedCodeWithAI';
784 }
785 | {
786 type: 'platform/recommendTestPlanWithAI';
787 commitHash?: string;
788 userContext?: string;
789 }
790 | {
791 type: 'platform/generateSummaryWithAI';
792 commitHash?: string;
793 userContext?: string;
794 }
795 | {
796 type: 'platform/validateChangesWithAI';
797 userContext?: string;
798 }
799 | {
800 type: 'platform/resolveAllConflictsWithAI';
801 conflicts: MergeConflicts;
802 userContext?: string;
803 }
804 | {
805 type: 'platform/runAICodeReviewPlatform';
806 cwd: string;
807 }
808 | {
809 type: 'platform/runAICodeReviewChat';
810 source: 'commitInfoView' | 'smartAction';
811 reviewScope: CodeReviewScope;
812 userContext?: string;
813 }
814 | {
815 type: 'platform/subscribeToAIReviewComments';
816 };
817
818/**
819 * messages returned by platform-specific (browser, vscode, electron) server implementation,
820 * usually in response to a platform-specific ClientToServer message
821 */
822export type PlatformSpecificServerToClientMessages =
823 | {
824 type: 'platform/confirmResult';
825 result: boolean;
826 }
827 | {
828 type: 'platform/availableCwds';
829 options: Array<CwdInfo>;
830 }
831 | {type: 'platform/unsavedFiles'; unsaved: Array<{path: RepoRelativePath; uri: string}>}
832 | {type: 'platform/savedAllUnsavedFiles'; success: boolean}
833 | {
834 type: 'platform/gotDiagnostics';
835 diagnostics: Map<RepoRelativePath, Array<Diagnostic>>;
836 }
837 | {type: 'platform/onDidChangeSuggestedEdits'; files: Array<AbsolutePath>}
838 | {
839 type: 'platform/vscodeConfigChanged';
840 config: string;
841 value: Json | undefined;
842 }
843 | {
844 type: 'platform/gotAIReviewComments';
845 comments: Result<CodeReviewIssue[]>;
846 };
847
848export type CodeReviewProviderSpecificClientToServerMessages =
849 | never
850 | InternalTypes['PhabricatorClientToServerMessages'];
851
852export type CodeReviewProviderSpecificServerToClientMessages =
853 | never
854 | InternalTypes['PhabricatorServerToClientMessages'];
855
856export type PageVisibility = 'focused' | 'visible' | 'hidden';
857
858export type FileABugFields = {title: string; description: string; repro: string};
859export type FileABugProgress =
860 | {status: 'starting'}
861 | {
862 status: 'inProgress';
863 currentSteps: Record<string, 'blocked' | 'loading' | 'finished'>;
864 }
865 | {status: 'success'; taskNumber: string; taskLink: string}
866 | {status: 'error'; error: Error};
867export type FileABugProgressMessage = {type: 'fileBugReportProgress'} & FileABugProgress;
868
869export type SubscriptionKind =
870 | 'uncommittedChanges'
871 | 'smartlogCommits'
872 | 'mergeConflicts'
873 | 'submodules'
874 | 'subscribedFullRepoBranches';
875
876export const allConfigNames = [
877 // these config names are for compatibility.
878 'isl.submitAsDraft',
879 'isl.publishWhenReady',
880 'isl.changedFilesDisplayType',
881 // sapling config prefers foo-bar naming.
882 'isl.pull-button-choice',
883 'isl.show-stack-submit-confirmation',
884 'isl.show-diff-number',
885 'isl.render-compact',
886 'isl.download-commit-should-goto',
887 'isl.download-commit-rebase-type',
888 'isl.experimental-features',
889 'isl.hold-off-refresh-ms',
890 'isl.sl-progress-enabled',
891 'isl.use-sl-graphql',
892 'github.preferred_submit_command',
893 'isl.open-file-cmd',
894 'isl.generated-files-regex',
895 'ui.username',
896 'ui.merge',
897 'fbcodereview.code-browser-url',
898 'extensions.commitcloud',
899] as const;
900
901/** sl configs read by ISL */
902export type ConfigName = (typeof allConfigNames)[number];
903
904/**
905 * Not all configs should be set-able from the UI, for security.
906 * Only configs which could not possibly allow code execution should be allowed.
907 * This also includes values allowed to be passed in the args for Operations.
908 * Most ISL configs are OK.
909 */
910export const settableConfigNames = [
911 'isl.submitAsDraft',
912 'isl.publishWhenReady',
913 'isl.changedFilesDisplayType',
914 'isl.pull-button-choice',
915 'isl.show-stack-submit-confirmation',
916 'isl.show-diff-number',
917 'isl.render-compact',
918 'isl.download-commit-should-goto',
919 'isl.download-commit-rebase-type',
920 'isl.experimental-features',
921 'isl.hold-off-refresh-ms',
922 'isl.use-sl-graphql',
923 'isl.experimental-graph-renderer',
924 'isl.generated-files-regex',
925 'github.preferred_submit_command',
926 'ui.allowemptycommit',
927 'ui.merge',
928 'amend.autorestack',
929] as const;
930
931/** sl configs written to by ISL */
932export type SettableConfigName = (typeof settableConfigNames)[number];
933
934/** local storage keys written by ISL */
935export type LocalStorageName =
936 | 'isl.drawer-state'
937 | 'isl.bookmarks'
938 | 'isl.recommended-bookmarks-reminder'
939 | 'isl.recommended-bookmarks-onboarding'
940 | 'isl.ui-zoom'
941 | 'isl.has-shown-getting-started'
942 | 'isl.dismissed-split-suggestion'
943 | 'isl.amend-autorestack'
944 | 'isl.dismissed-alerts'
945 | 'isl.debug-react-tools'
946 | 'isl.debug-redux-tools'
947 | 'isl.condense-obsolete-stacks'
948 | 'isl.deemphasize-cwd-irrelevant-commits'
949 | 'isl.hide-cwd-irrelevant-stacks'
950 | 'isl.split-suggestion-enabled'
951 | 'isl.comparison-display-mode'
952 | 'isl.expand-generated-files'
953 | 'isl-color-theme'
954 | 'isl.auto-resolve-before-continue'
955 | 'isl.warn-about-diagnostics'
956 | 'isl.hide-non-blocking-diagnostics'
957 | 'isl.rebase-off-warm-warning-enabled'
958 | 'isl.distant-rebase-warning-enabled'
959 | 'isl.rebase-onto-master-warning-enabled'
960 | 'isl.experimental-features-local-override'
961 | 'isl.partial-abort'
962 | 'isl.smart-actions-order'
963 // The keys below are prefixes, with further dynamic keys appended afterwards
964 | 'isl.edited-commit-messages:'
965 | 'isl.first-pass-comments:';
966
967export type ClientToServerMessage =
968 | {type: 'heartbeat'; id: string}
969 | {type: 'stress'; id: number; time: number; message: string}
970 | {type: 'refresh'}
971 | {type: 'clientReady'}
972 | {type: 'getConfig'; name: ConfigName}
973 | {type: 'setConfig'; name: SettableConfigName; value: string}
974 | {type: 'setDebugLogging'; name: 'debug' | 'verbose'; enabled: boolean}
975 | {type: 'changeCwd'; cwd: string}
976 | {type: 'track'; data: TrackDataWithEventName}
977 | {type: 'fileBugReport'; data: FileABugFields; uiState?: Json; collectRage: boolean}
978 | {type: 'runOperation'; operation: RunnableOperation}
979 | {type: 'abortRunningOperation'; operationId: string}
980 | {type: 'fetchActiveAlerts'}
981 | {type: 'fetchGeneratedStatuses'; paths: Array<RepoRelativePath>}
982 | {type: 'fetchCommitMessageTemplate'}
983 | {type: 'fetchShelvedChanges'}
984 | {type: 'fetchLatestCommit'; revset: string}
985 | {type: 'fetchCommitChangedFiles'; hash: Hash; limit?: number}
986 | {
987 type: 'uploadFile';
988 filename: string;
989 id: string;
990 b64Content: string;
991 }
992 | {type: 'renderMarkup'; markup: string; id: number}
993 | {type: 'typeahead'; kind: TypeaheadKind; query: string; id: string}
994 | {type: 'requestRepoInfo'}
995 | {type: 'requestApplicationInfo'}
996 | {type: 'requestMissedOperationProgress'; operationId: string}
997 | {type: 'fetchAvatars'; authors: Array<string>}
998 | {type: 'fetchCommitCloudState'}
999 | {type: 'fetchDiffSummaries'; diffIds?: Array<DiffId>}
1000 | {type: 'fetchCanopySignals'}
1001 | {type: 'fetchDiffComments'; diffId: DiffId}
1002 | {type: 'fetchLandInfo'; topOfStack: DiffId}
1003 | {type: 'fetchAndSetStables'; additionalStables: Array<string>}
1004 | {type: 'fetchStableLocationAutocompleteOptions'}
1005 | {type: 'confirmLand'; landConfirmationInfo: LandConfirmationInfo}
1006 | {type: 'getSuggestedReviewers'; context: {paths: Array<string>}; key: string}
1007 | {type: 'getConfiguredMergeTool'}
1008 | {type: 'updateRemoteDiffMessage'; diffId: DiffId; title: string; description: string}
1009 | {type: 'pageVisibility'; state: PageVisibility}
1010 | {type: 'getRepoUrlAtHash'; revset: Revset; path?: string}
1011 | {type: 'requestComparison'; comparison: Comparison}
1012 | {
1013 type: 'requestComparisonContextLines';
1014 id: {
1015 comparison: Comparison;
1016 path: RepoRelativePath;
1017 };
1018 start: number;
1019 numLines: number;
1020 }
1021 | {type: 'loadMoreCommits'}
1022 | {type: 'subscribe'; kind: SubscriptionKind; subscriptionID: string}
1023 | {type: 'unsubscribe'; kind: SubscriptionKind; subscriptionID: string}
1024 | {type: 'exportStack'; revs: string; assumeTracked?: Array<string>}
1025 | {type: 'importStack'; stack: ImportStack}
1026 | {type: 'fetchQeFlag'; name: string}
1027 | {type: 'fetchFeatureFlag'; name: string}
1028 | {type: 'bulkFetchFeatureFlags'; id: string; names: Array<string>}
1029 | {type: 'fetchInternalUserInfo'}
1030 | {type: 'fetchDevEnvType'; id: string}
1031 | {type: 'splitCommitWithAI'; id: string; diffCommit: DiffCommit; args: Args}
1032 | {type: 'gotUiState'; state: string}
1033 | {type: 'fetchGroveOwners'}
1034 | {type: 'createGroveRepo'; name: string; owner?: string}
1035 | CodeReviewProviderSpecificClientToServerMessages
1036 | PlatformSpecificClientToServerMessages
1037 | {type: 'fetchSignificantLinesOfCode'; hash: Hash; excludedFiles: string[]}
1038 | {
1039 type: 'fetchPendingSignificantLinesOfCode';
1040 requestId: number;
1041 hash: Hash;
1042 includedFiles: string[];
1043 }
1044 | {
1045 type: 'fetchPendingAmendSignificantLinesOfCode';
1046 requestId: number;
1047 hash: Hash;
1048 includedFiles: string[];
1049 }
1050 | {
1051 type: 'fetchGkDetails';
1052 id: string;
1053 name: string;
1054 }
1055 | {
1056 type: 'fetchJkDetails';
1057 id: string;
1058 names: string[];
1059 }
1060 | {
1061 type: 'fetchKnobsetDetails';
1062 id: string;
1063 configPath: string;
1064 }
1065 | {
1066 type: 'fetchQeDetails';
1067 id: string;
1068 name: string;
1069 }
1070 | {
1071 type: 'fetchTaskDetails';
1072 id: string;
1073 taskNumber: number;
1074 }
1075 | {
1076 type: 'fetchABPropDetails';
1077 id: string;
1078 name: string;
1079 }
1080 | {
1081 type: 'runDevmateCommand';
1082 args: Array<string>;
1083 cwd: string;
1084 requestId: string;
1085 }
1086 | {
1087 type: 'fetchSubscribedFullRepoBranches';
1088 id: string;
1089 }
1090 | {
1091 type: 'fetchFullRepoBranchAllChangedFiles';
1092 id: string;
1093 fullRepoBranch: InternalTypes['FullRepoBranch'];
1094 }
1095 | {
1096 type: 'fetchFullRepoBranchMergeSubtreePaths';
1097 id: string;
1098 fullRepoBranch: InternalTypes['FullRepoBranch'];
1099 paths: Array<RepoRelativePath>;
1100 }
1101 | {
1102 type: 'subscribeToFullRepoBranch';
1103 id: string;
1104 fullRepoBranch: InternalTypes['FullRepoBranch'];
1105 }
1106 | {
1107 type: 'unsubscribeToFullRepoBranch';
1108 id: string;
1109 fullRepoBranch: InternalTypes['FullRepoBranch'];
1110 };
1111
1112export type SubscriptionResultsData = {
1113 uncommittedChanges: FetchedUncommittedChanges;
1114 smartlogCommits: FetchedCommits;
1115 mergeConflicts: MergeConflicts | undefined;
1116 submodules: SubmodulesByRoot;
1117 subscribedFullRepoBranches: Array<InternalTypes['FullRepoBranch']>;
1118};
1119
1120export type SubscriptionResult<K extends SubscriptionKind> = {
1121 type: 'subscriptionResult';
1122 subscriptionID: string;
1123 kind: K;
1124 data: SubscriptionResultsData[K];
1125};
1126
1127export type ServerToClientMessage =
1128 | SubscriptionResult<'smartlogCommits'>
1129 | SubscriptionResult<'uncommittedChanges'>
1130 | SubscriptionResult<'mergeConflicts'>
1131 | SubscriptionResult<'submodules'>
1132 | SubscriptionResult<'subscribedFullRepoBranches'>
1133 | BeganFetchingUncommittedChangesEvent
1134 | BeganFetchingSmartlogCommitsEvent
1135 | {
1136 type: 'beganFetchingSubscribedFullRepoBranchesEvent';
1137 }
1138 | FileABugProgressMessage
1139 | {type: 'heartbeat'; id: string}
1140 | {type: 'stress'; id: number; time: number; message: string}
1141 | {type: 'gotConfig'; name: ConfigName; value: string | undefined}
1142 | {
1143 type: 'fetchedGeneratedStatuses';
1144 results: Record<RepoRelativePath, GeneratedStatus>;
1145 }
1146 | {type: 'fetchedActiveAlerts'; alerts: Array<Alert>}
1147 | {type: 'fetchedCommitMessageTemplate'; template: string}
1148 | {type: 'fetchedShelvedChanges'; shelvedChanges: Result<Array<ShelvedChange>>}
1149 | {type: 'fetchedLatestCommit'; info: Result<CommitInfo>; revset: string}
1150 | {
1151 type: 'fetchedCommitChangedFiles';
1152 hash: Hash;
1153 result: Result<FilesSample>;
1154 }
1155 | {type: 'typeaheadResult'; id: string; result: Array<TypeaheadResult>}
1156 | {type: 'applicationInfo'; info: ApplicationInfo}
1157 | {type: 'repoInfo'; info: RepoInfo; cwd?: string}
1158 | {type: 'repoError'; error: RepositoryError | undefined}
1159 | {type: 'fetchedAvatars'; avatars: Map<string, string>; authors: Array<string>}
1160 | {type: 'fetchedDiffSummaries'; summaries: Result<Map<DiffId, DiffSummary>>}
1161 | {type: 'fetchedCanopySignals'; runs: Array<{commitMessage: string; signal: DiffSignalSummary; runId?: number; commitId?: string}>}
1162 | {type: 'fetchedDiffComments'; diffId: DiffId; comments: Result<Array<DiffComment>>}
1163 | {type: 'fetchedLandInfo'; topOfStack: DiffId; landInfo: Result<LandInfo>}
1164 | {type: 'confirmedLand'; result: Result<undefined>}
1165 | {type: 'fetchedCommitCloudState'; state: Result<CommitCloudSyncState>}
1166 | {type: 'fetchedStables'; stables: StableLocationData}
1167 | {type: 'fetchedRecommendedBookmarks'; bookmarks: Array<string>}
1168 | {
1169 type: 'fetchedHiddenMasterBranchConfig';
1170 config: Record<string, Array<string>> | null;
1171 odType: string | null;
1172 cwd: string;
1173 }
1174 | {type: 'fetchedStableLocationAutocompleteOptions'; result: Result<Array<TypeaheadResult>>}
1175 | {type: 'renderedMarkup'; html: string; id: number}
1176 | {type: 'gotSuggestedReviewers'; reviewers: Array<string>; key: string}
1177 | {type: 'gotConfiguredMergeTool'; tool: string | undefined}
1178 | {type: 'updatedRemoteDiffMessage'; diffId: DiffId; error?: string}
1179 | {
1180 type: 'updateDraftCommitMessage';
1181 title: string;
1182 description: string;
1183 mode?: 'commit' | 'amend';
1184 hash?: string;
1185 }
1186 | {type: 'uploadFileResult'; id: string; result: Result<string>}
1187 | {type: 'watchmanStatus'; status: 'initializing' | 'reconnecting' | 'healthy' | 'ended' | 'errored' | 'unavailable'}
1188 | {type: 'gotRepoUrlAtHash'; url: Result<string>}
1189 | {type: 'comparison'; comparison: Comparison; data: ComparisonData}
1190 | {type: 'comparisonContextLines'; path: RepoRelativePath; lines: Result<Array<string>>}
1191 | {type: 'beganLoadingMoreCommits'}
1192 | {type: 'commitsShownRange'; rangeInDays: number | undefined}
1193 | {type: 'additionalCommitAvailability'; moreAvailable: boolean}
1194 | {
1195 type: 'exportedStack';
1196 revs: string;
1197 assumeTracked: Array<string>;
1198 stack: ExportStack;
1199 error: string | undefined;
1200 }
1201 | {type: 'importedStack'; imported: ImportedStack; error: string | undefined}
1202 | {type: 'fetchedQeFlag'; name: string; passes: boolean}
1203 | {type: 'fetchedFeatureFlag'; name: string; passes: boolean}
1204 | {type: 'bulkFetchedFeatureFlags'; id: string; result: Record<string, boolean>}
1205 | {type: 'fetchedInternalUserInfo'; info: Serializable}
1206 | {type: 'fetchedDevEnvType'; envType: string; id: string}
1207 | {
1208 type: 'splitCommitWithAI';
1209 id: string;
1210 result: Result<ReadonlyArray<PartiallySelectedDiffCommit>>;
1211 }
1212 | {type: 'getUiState'}
1213 | OperationProgressEvent
1214 | {type: 'fetchedGroveOwners'; owners: Array<{name: string; type: 'user' | 'org'}>}
1215 | {type: 'createdGroveRepo'; result: Result<{owner: string; repo: string}>}
1216 | PlatformSpecificServerToClientMessages
1217 | CodeReviewProviderSpecificServerToClientMessages
1218 | {
1219 type: 'fetchedSignificantLinesOfCode';
1220 hash: Hash;
1221 result: Result<number>;
1222 }
1223 | {
1224 type: 'fetchedPendingSignificantLinesOfCode';
1225 requestId: number;
1226 hash: Hash;
1227 result: Result<number>;
1228 }
1229 | {
1230 type: 'fetchedPendingAmendSignificantLinesOfCode';
1231 requestId: number;
1232 hash: Hash;
1233 result: Result<number>;
1234 }
1235 | {
1236 type: 'fetchedGkDetails';
1237 id: string;
1238 result: Result<InternalTypes['InternalGatekeeper']>;
1239 }
1240 | {
1241 type: 'fetchedJkDetails';
1242 id: string;
1243 result: Result<InternalTypes['InternalJustknob']>;
1244 }
1245 | {
1246 type: 'fetchedKnobsetDetails';
1247 id: string;
1248 result: Result<InternalTypes['InternalKnobset']>;
1249 }
1250 | {
1251 type: 'fetchedQeDetails';
1252 id: string;
1253 result: Result<InternalTypes['InternalQuickExperiment']>;
1254 }
1255 | {
1256 type: 'fetchedABPropDetails';
1257 id: string;
1258 result: Result<InternalTypes['InternalMetaConfig']>;
1259 }
1260 | {
1261 type: 'fetchedTaskDetails';
1262 id: string;
1263 result: Result<InternalTypes['InternalTaskDetails']>;
1264 }
1265 | {
1266 type: 'devmateCommandResult';
1267 result: (
1268 | {
1269 type: 'value';
1270 stdout: string;
1271 }
1272 | {
1273 type: 'error';
1274 stderr: string;
1275 }
1276 ) & {requestId: string};
1277 }
1278 | {
1279 type: 'fetchedSubscribedFullRepoBranches';
1280 result: Result<Array<InternalTypes['FullRepoBranch']>>;
1281 }
1282 | {
1283 type: 'fetchedFullRepoBranchAllChangedFiles';
1284 id: string;
1285 result: Result<Array<ChangedFile>>;
1286 }
1287 | {
1288 type: 'fetchedFullRepoBranchMergeSubtreePaths';
1289 id: string;
1290 result: Result<Array<string>>;
1291 }
1292 | {
1293 type: 'openSplitViewForCommit';
1294 commitHash: string;
1295 commits?: Array<PartiallySelectedDiffCommit>;
1296 };
1297
1298export type Disposable = {
1299 dispose(): void;
1300};
1301
1302export type ComparisonData = {
1303 diff: Result<string>;
1304};
1305
1306export type MessageBusStatus =
1307 | {type: 'initializing'}
1308 | {type: 'open'}
1309 | {type: 'reconnecting'}
1310 | {type: 'error'; error?: string};
1311
1312export type ArcStableGKInfo = {
1313 gk: string;
1314 id: string;
1315 label: string;
1316};
1317