Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chronicle/node/cloudSessionStoreClient.ts
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { IAuthenticationService } from '../../../platform/authentication/common/authentication';
7
import { ICopilotTokenManager } from '../../../platform/authentication/common/copilotTokenManager';
8
import { INTEGRATION_ID } from '../../../platform/endpoint/common/licenseAgreement';
9
import { IFetcherService } from '../../../platform/networking/common/fetcherService';
10
11
/** Cloud query endpoint path. */
12
const QUERY_PATH = '/agents/analytics/query';
13
14
/** Timeout for cloud query requests (ms). */
15
const REQUEST_TIMEOUT_MS = 30_000;
16
17
/**
18
* Response format from the cloud query API.
19
* Data comes as columnar arrays, not row objects.
20
*/
21
interface CloudQueryResponse {
22
columns: string[];
23
column_types: string[];
24
data: unknown[][];
25
row_count: number;
26
truncated: boolean;
27
}
28
29
/**
30
* Convert a columnar cloud response to an array of record objects.
31
*/
32
function columnarToRecords(response: CloudQueryResponse): Record<string, unknown>[] {
33
const { columns, data } = response;
34
if (!data || !columns) {
35
return [];
36
}
37
return data.map(row => {
38
const record: Record<string, unknown> = {};
39
for (let i = 0; i < columns.length; i++) {
40
record[columns[i]] = row[i];
41
}
42
return record;
43
});
44
}
45
46
/**
47
* HTTP client for querying session data from the cloud.
48
*/
49
export class CloudSessionStoreClient {
50
51
constructor(
52
private readonly _tokenManager: ICopilotTokenManager,
53
private readonly _authService: IAuthenticationService,
54
private readonly _fetcherService: IFetcherService,
55
) { }
56
57
/**
58
* Execute a SQL query against the cloud session store (user-scoped).
59
* Returns an array of row objects on success, or undefined on failure.
60
*/
61
async executeQuery(sql: string): Promise<{ rows: Record<string, unknown>[]; truncated: boolean } | undefined> {
62
try {
63
const copilotToken = await this._tokenManager.getCopilotToken();
64
const baseUrl = copilotToken.endpoints?.api;
65
if (!baseUrl) {
66
return undefined;
67
}
68
69
// The cloud endpoint expects a GitHub OAuth token,
70
// not the Copilot proxy token.
71
const githubToken = this._authService.anyGitHubSession?.accessToken;
72
const bearerToken = githubToken ?? copilotToken.token;
73
74
const url = `${baseUrl.replace(/\/+$/, '')}${QUERY_PATH}`;
75
76
const res = await this._fetcherService.fetch(url, {
77
callSite: 'chronicle.cloudQuery',
78
method: 'POST',
79
headers: {
80
'Authorization': `Bearer ${bearerToken}`,
81
'Copilot-Integration-Id': INTEGRATION_ID,
82
},
83
json: { query: sql },
84
timeout: REQUEST_TIMEOUT_MS,
85
});
86
87
if (!res.ok) {
88
return undefined;
89
}
90
91
const data = await res.json() as CloudQueryResponse;
92
const rows = columnarToRecords(data);
93
return { rows, truncated: data.truncated ?? false };
94
} catch (err) {
95
return undefined;
96
}
97
}
98
}
99
100