Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/networking/common/capiClientFetchedValue.ts
13401 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 type { MakeRequestOptions, RequestMetadata } from '@vscode/copilot-api';
7
import { createAdvancedFetch } from '../../../shared-fetch-utils/common/advancedFetcher';
8
import type { HttpResponse } from '../../../shared-fetch-utils/common/fetchTypes';
9
import { FetchedValue } from '../../../shared-fetch-utils/common/fetchedValue';
10
import { authBlockedMiddleware } from '../../../shared-fetch-utils/common/middleware/authBlockedMiddleware';
11
import { etagMiddleware } from '../../../shared-fetch-utils/common/middleware/etagMiddleware';
12
import { serverErrorBackoffMiddleware } from '../../../shared-fetch-utils/common/middleware/serverErrorBackoffMiddleware';
13
import type { ICAPIClientService } from '../../endpoint/common/capiClient';
14
import type { IEnvService } from '../../env/common/envService';
15
16
export interface CapiClientFetchedValueOptions<T> {
17
/**
18
* The request options passed to {@link ICAPIClientService.makeRequest}.
19
*/
20
readonly request: (() => MakeRequestOptions | Promise<MakeRequestOptions>);
21
22
/**
23
* Metadata for the CAPI request (e.g. {@link RequestType}).
24
*/
25
readonly requestMetadata: RequestMetadata;
26
27
/**
28
* Extracts the domain value `T` from the HTTP response.
29
*
30
* `body` is the JSON-parsed object on success, the raw response text
31
* when the body is not valid JSON (e.g. error pages), or `undefined`
32
* when the response has no body (e.g. 204, 304 handled by etag cache).
33
*/
34
readonly parseResponse: (response: HttpResponse) => Promise<T>;
35
36
/**
37
* Determines whether the current cached value is stale and should be
38
* re-fetched. Passed through to {@link FetchedValueOptions.isStale}.
39
*/
40
readonly isStale: (value: T) => boolean;
41
42
/**
43
* When `true`, automatically resolves once per minute to keep the cache
44
* hot. Passed through to {@link FetchedValueOptions.keepCacheHot}.
45
*/
46
readonly keepCacheHot?: boolean;
47
}
48
49
/**
50
* Creates a {@link FetchedValue} that fetches via
51
* {@link ICAPIClientService.makeRequest} with the full advanced-fetcher
52
* middleware stack applied.
53
*
54
* This is the recommended way to create periodically-refreshed cached
55
* values backed by CAPI endpoints.
56
*
57
* @example
58
* ```ts
59
* const config = createCapiClientFetchedValue(capiClientService, envService, {
60
* request: async () => ({
61
* headers: { Authorization: `Bearer ${await getToken()}` },
62
* method: 'POST',
63
* json: { key: 'value' },
64
* }),
65
* requestMetadata: { type: RequestType.CopilotToken },
66
* isStale: (c) => c.expiresAt < Date.now(),
67
* });
68
*
69
* const fresh = await config.resolve();
70
* ```
71
*/
72
export function createCapiClientFetchedValue<T>(
73
capiClientService: ICAPIClientService,
74
envService: IEnvService,
75
options: CapiClientFetchedValueOptions<T>,
76
): FetchedValue<T> {
77
const {
78
request,
79
requestMetadata,
80
parseResponse,
81
isStale,
82
keepCacheHot,
83
} = options;
84
85
const fetch = createAdvancedFetch<T>({
86
request: async () => {
87
const currentRequestOpts = await request();
88
return {
89
url: `capi:${requestMetadata.type}`,
90
headers: currentRequestOpts.headers ?? {},
91
method: currentRequestOpts.method ?? 'GET',
92
state: currentRequestOpts
93
};
94
},
95
httpFetch: async (httpRequest) => {
96
const response = await capiClientService.makeRequest<Response>({
97
...(httpRequest.state ?? {}),
98
method: httpRequest.method,
99
// Use the headers from the middleware pipeline (may include
100
// If-None-Match, If-Modified-Since, etc.)
101
headers: httpRequest.headers,
102
}, requestMetadata);
103
104
return response;
105
},
106
parseResponse,
107
middleware: [
108
etagMiddleware(),
109
authBlockedMiddleware(),
110
serverErrorBackoffMiddleware(),
111
],
112
});
113
114
return new FetchedValue<T>({
115
fetch,
116
isStale,
117
keepCacheHot,
118
});
119
}
120
121