extensionGalleryService.ts ×69

Frontier kind: Code frontier

unlabeled · c_d7e9ed0a0bce

29 tests · 17319 LOC · 79 files · introduces 0 tests · 504 LOC · 4 files

Introduces — evidence that enters the hierarchy at this concept

Code
74 ranges504 lines · 4 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
2349 ranges17319 lines · 79 files · Browse complete extent
All tests (intent)
29 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

4 files ranked by introduced lines: 504 introduced LOC across 74 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/extensionManagement/common/extensionGalleryService.ts 429 introduced LOC · 69 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionGalleryService.ts
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 { distinct } from '../../../base/common/arrays.js';
7 > import { CancellationToken } from '../../../base/common/cancellation.js';
8 > import * as semver from '../../../base/common/semver/semver.js';
9 > import { IStringDictionary } from '../../../base/common/collections.js';
10 > import { CancellationError, getErrorMessage, isCancellationError } from '../../../base/common/errors.js';
11 > import { IPager } from '../../../base/common/paging.js';
12 > import { isWeb, platform } from '../../../base/common/platform.js';
13 > import { arch } from '../../../base/common/process.js';
14 > import { isBoolean, isNumber, isString } from '../../../base/common/types.js';
15 > import { URI } from '../../../base/common/uri.js';
16 > import { IHeaders, IRequestContext, IRequestOptions, isOfflineError } from '../../../base/parts/request/common/request.js';
17 > import { IConfigurationService } from '../../configuration/common/configuration.js';
18 > import { IEnvironmentService } from '../../environment/common/environment.js';
19 > import { getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionInfo, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortOrder, StatisticType, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionQueryOptions, IDeprecationInfo, ISearchPrefferedResults, ExtensionGalleryError, ExtensionGalleryErrorCode, IProductVersion, IAllowedExtensionsService, EXTENSION_IDENTIFIER_REGEX, SortBy, FilterType, MaliciousExtensionInfo, ExtensionRequestsTimeoutConfigKey } from './extensionManagement.js';
20 > import { adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId, getGalleryExtensionTelemetryData } from './extensionManagementUtil.js';
21 > import { IExtensionManifest, TargetPlatform } from '../../extensions/common/extensions.js';
22 > import { isEngineValid } from '../../extensions/common/extensionValidator.js';
23 > import { IFileService } from '../../files/common/files.js';
24 > import { ILogService } from '../../log/common/log.js';
25 > import { IProductService } from '../../product/common/productService.js';
26 > import { asJson, asTextOrError, IRequestService, isClientError, isServerError, isSuccess } from '../../request/common/request.js';
27 > import { resolveMarketplaceHeaders } from '../../externalServices/common/marketplace.js';
28 > import { IStorageService } from '../../storage/common/storage.js';
29 > import { ITelemetryService } from '../../telemetry/common/telemetry.js';
30 > import { StopWatch } from '../../../base/common/stopwatch.js';
31 > import { format2 } from '../../../base/common/strings.js';
32 > import { ExtensionGalleryResourceType, Flag, getExtensionGalleryManifestResourceUri, IExtensionGalleryManifest, IExtensionGalleryManifestService, ExtensionGalleryManifestStatus } from './extensionGalleryManifest.js';
33 > import { TelemetryTrustedValue } from '../../telemetry/common/telemetryUtils.js';
34 >
35 > const CURRENT_TARGET_PLATFORM = isWeb ? TargetPlatform.WEB : getTargetPlatform(platform, arch);
36 > const SEARCH_ACTIVITY_HEADER_NAME = 'X-Market-Search-Activity-Id';
37 > const ACTIVITY_HEADER_NAME = 'Activityid';
38 > const SERVER_HEADER_NAME = 'Server';
39 > const END_END_ID_HEADER_NAME = 'X-Vss-E2eid';
40 >
41 > interface IRawGalleryExtensionFile {
42 > readonly assetType: string;
43 > readonly source: string;
44 > }
45 >
46 > interface IRawGalleryExtensionProperty {
47 > readonly key: string;
48 > readonly value: string;
49 > }
50 >
51 > export interface IRawGalleryExtensionVersion {
52 > readonly version: string;
53 > readonly lastUpdated: string;
54 > readonly assetUri: string;
55 > readonly fallbackAssetUri: string;
56 > readonly files: IRawGalleryExtensionFile[];
57 > properties?: IRawGalleryExtensionProperty[];
58 > readonly targetPlatform?: string;
59 > }
60 >
61 > interface IRawGalleryExtensionStatistics {
62 > readonly statisticName: string;
63 > readonly value: number;
64 > }
65 >
66 > interface IRawGalleryExtensionPublisher {
67 > readonly displayName: string;
68 > readonly publisherId: string;
69 > readonly publisherName: string;
70 > readonly domain?: string | null;
71 > readonly isDomainVerified?: boolean;
72 > readonly linkType?: string;
73 > }
74 >
75 > interface IRawGalleryExtension {
76 > readonly extensionId: string;
77 > readonly extensionName: string;
78 > readonly displayName: string;
79 > readonly shortDescription?: string;
80 > readonly publisher: IRawGalleryExtensionPublisher;
81 > readonly versions: IRawGalleryExtensionVersion[];
82 > readonly statistics: IRawGalleryExtensionStatistics[];
83 > readonly tags: string[] | undefined;
84 > readonly releaseDate: string;
85 > readonly publishedDate: string;
86 > readonly lastUpdated: string;
87 > readonly categories: string[] | undefined;
88 > readonly flags: string;
89 > readonly linkType?: string;
90 > readonly ratingLinkType?: string;
91 > }
92 >
93 > interface IRawGalleryExtensionsResult {
94 > readonly galleryExtensions: IRawGalleryExtension[];
95 > readonly total: number;
96 > readonly context?: IStringDictionary<string>;
97 > }
98 >
99 > interface IRawGalleryQueryResult {
100 > readonly results: {
101 > readonly extensions: IRawGalleryExtension[];
102 > readonly resultMetadata: {
103 > readonly metadataType: string;
104 > readonly metadataItems: {
105 > readonly name: string;
106 > readonly count: number;
107 > }[];
108 > }[];
109 > }[];
110 > }
111 >
112 > const AssetType = {
113 > Icon: 'Microsoft.VisualStudio.Services.Icons.Default',
114 > Details: 'Microsoft.VisualStudio.Services.Content.Details',
115 > Changelog: 'Microsoft.VisualStudio.Services.Content.Changelog',
116 > Manifest: 'Microsoft.VisualStudio.Code.Manifest',
117 > VSIX: 'Microsoft.VisualStudio.Services.VSIXPackage',
118 > License: 'Microsoft.VisualStudio.Services.Content.License',
119 > Repository: 'Microsoft.VisualStudio.Services.Links.Source',
120 > Signature: 'Microsoft.VisualStudio.Services.VsixSignature'
121 > };
122 >
123 > const PropertyType = {
124 > Dependency: 'Microsoft.VisualStudio.Code.ExtensionDependencies',
125 > ExtensionPack: 'Microsoft.VisualStudio.Code.ExtensionPack',
126 > Engine: 'Microsoft.VisualStudio.Code.Engine',
127 > PreRelease: 'Microsoft.VisualStudio.Code.PreRelease',
128 > EnabledApiProposals: 'Microsoft.VisualStudio.Code.EnabledApiProposals',
129 > LocalizedLanguages: 'Microsoft.VisualStudio.Code.LocalizedLanguages',
130 > WebExtension: 'Microsoft.VisualStudio.Code.WebExtension',
131 > SponsorLink: 'Microsoft.VisualStudio.Code.SponsorLink',
132 > SupportLink: 'Microsoft.VisualStudio.Services.Links.Support',
133 > ExecutesCode: 'Microsoft.VisualStudio.Code.ExecutesCode',
134 > Private: 'PrivateMarketplace',
135 > };
136 >
137 > interface ICriterium {
138 > readonly filterType: FilterType;
139 > readonly value?: string;
140 > }
141 >
142 > const DefaultPageSize = 10;
143 >
144 > interface IQueryState {
145 > readonly pageNumber: number;
146 > readonly pageSize: number;
147 > readonly sortBy: SortBy;
148 > readonly sortOrder: SortOrder;
149 > readonly flags: Flag[];
150 > readonly criteria: ICriterium[];
151 > readonly assetTypes: string[];
152 > readonly source?: string;
153 > }
154 >
155 > const DefaultQueryState: IQueryState = {
156 > pageNumber: 1,
157 > pageSize: DefaultPageSize,
158 > sortBy: SortBy.NoneOrRelevance,
159 > sortOrder: SortOrder.Default,
160 > flags: [],
161 > criteria: [],
162 > assetTypes: []
163 > };
164 >
165 > type GalleryServiceQueryClassification = {
166 > owner: 'sandy081';
167 > comment: 'Information about Marketplace query and its response';
168 > readonly filterTypes: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Filter types used in the query.' };
169 > readonly flags: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Flags passed in the query.' };
170 > readonly sortBy: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'sorted by option passed in the query' };
171 > readonly sortOrder: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'sort order option passed in the query' };
172 > readonly pageNumber: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'requested page number in the query' };
173 > readonly duration: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; 'isMeasurement': true; comment: 'amount of time taken by the query request' };
174 > readonly success: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'whether the query request is success or not' };
175 > readonly requestBodySize: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'size of the request body' };
176 > readonly responseBodySize?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'size of the response body' };
177 > readonly statusCode?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'status code of the response' };
178 > readonly errorCode?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'error code of the response' };
179 > readonly count?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'total number of extensions matching the query' };
180 > readonly source?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'source that requested this query, eg., recommendations, viewlet' };
181 > readonly searchTextLength?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'length of the search text in the query' };
182 > readonly server?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'server that handled the query' };
183 > readonly endToEndId?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'end to end operation id' };
184 > readonly activityId?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'activity id' };
185 > };
186 >
187 > type QueryTelemetryData = {
188 > readonly filterTypes: string[];
189 > readonly flags: string[];
190 > readonly sortBy: string;
191 > readonly sortOrder: string;
192 > readonly pageNumber: string;
193 > readonly source?: string;
194 > readonly searchTextLength?: number;
195 > };
196 >
197 > type GalleryServiceQueryEvent = QueryTelemetryData & {
198 > readonly duration: number;
199 > readonly success: boolean;
200 > readonly requestBodySize: string;
201 > readonly responseBodySize?: string;
202 > readonly statusCode?: string;
203 > readonly errorCode?: string;
204 > readonly count?: string;
205 > readonly server?: TelemetryTrustedValue<string>;
206 > readonly endToEndId?: TelemetryTrustedValue<string>;
207 > readonly activityId?: TelemetryTrustedValue<string>;
208 > };
209 >
210 > type GalleryServiceAdditionalQueryClassification = {
211 > owner: 'sandy081';
212 > comment: 'Response information about the additional query to the Marketplace for fetching all versions to get release version';
213 > readonly duration: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; 'isMeasurement': true; comment: 'Amount of time taken by the additional query' };
214 > readonly count: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Total number of extensions returned by this additional query' };
215 > };
216 >
217 > type GalleryServiceAdditionalQueryEvent = {
218 > readonly duration: number;
219 > readonly count: number;
220 > };
221 >
222 > type ExtensionsCriteria = {
223 > readonly productVersion: IProductVersion;
224 > readonly targetPlatform: TargetPlatform;
225 > readonly compatible: boolean;
226 > readonly includePreRelease: boolean | (IExtensionIdentifier & { includePreRelease: boolean })[];
227 > readonly versions?: (IExtensionIdentifier & { version: string })[];
228 > readonly isQueryForReleaseVersionFromPreReleaseVersion?: boolean;
229 > };
230 >
231 > const enum VersionKind {
232 > Release,
233 > Prerelease,
234 > Latest
235 > }
236 >
237 > type ExtensionVersionCriteria = {
238 > readonly productVersion: IProductVersion;
239 > readonly targetPlatform: TargetPlatform;
240 > readonly compatible: boolean;
241 > readonly version: VersionKind | string;
242 > };
243 >
244 > class Query {
245 >
246 > constructor(private state = DefaultQueryState) { }
247 >
248 > get pageNumber(): number { return this.state.pageNumber; }
249 > get pageSize(): number { return this.state.pageSize; }
250 > get sortBy(): SortBy { return this.state.sortBy; }
251 > get sortOrder(): number { return this.state.sortOrder; }
252 > get flags(): Flag[] { return this.state.flags; }
253 > get criteria(): ICriterium[] { return this.state.criteria; }
254 > get assetTypes(): string[] { return this.state.assetTypes; }
255 > get source(): string | undefined { return this.state.source; }
256 > get searchText(): string {
257 const criterium = this.state.criteria.filter(criterium => criterium.filterType === FilterType.SearchText)[0];
258 return criterium && criterium.value ? criterium.value : '';
259 }
261 >
262 > withPage(pageNumber: number, pageSize: number = this.state.pageSize): Query {
263 return new Query({ ...this.state, pageNumber, pageSize });
264 }
266 > withFilter(filterType: FilterType, ...values: string[]): Query {
267 const criteria = [
268 ...this.state.criteria,
272 return new Query({ ...this.state, criteria });
273 }
275 > withSortBy(sortBy: SortBy): Query {
276 return new Query({ ...this.state, sortBy });
277 }
279 > withSortOrder(sortOrder: SortOrder): Query {
280 return new Query({ ...this.state, sortOrder });
281 }
283 > withFlags(...flags: Flag[]): Query {
284 return new Query({ ...this.state, flags: distinct(flags) });
285 }
287 > withAssetTypes(...assetTypes: string[]): Query {
288 return new Query({ ...this.state, assetTypes });
289 }
291 > withSource(source: string): Query {
292 return new Query({ ...this.state, source });
293 }
295 >
296 function getStatistic(statistics: IRawGalleryExtensionStatistics[], name: string): number {
297 const result = (statistics || []).filter(s => s.statisticName === name)[0];
298 return result ? result.value : 0;
299 }
301 function getCoreTranslationAssets(version: IRawGalleryExtensionVersion): [string, IGalleryExtensionAsset][] {
302 const coreTranslationAssetPrefix = 'Microsoft.VisualStudio.Code.Translation.';
310 }, []);
311 }
313 function getRepositoryAsset(version: IRawGalleryExtensionVersion): IGalleryExtensionAsset | null {
314 if (version.properties) {
321 return getVersionAsset(version, AssetType.Repository);
322 }
324 function getDownloadAsset(version: IRawGalleryExtensionVersion): IGalleryExtensionAsset {
325 return {
329 };
330 }
332 function getVersionAsset(version: IRawGalleryExtensionVersion, type: string): IGalleryExtensionAsset | null {
333 const result = version.files.filter(f => f.assetType === type)[0];
337 } : null;
338 }
340 function getExtensions(version: IRawGalleryExtensionVersion, property: string): string[] {
341 const values = version.properties ? version.properties.filter(p => p.key === property) : [];
343 return value ? value.split(',').map(v => adoptToGalleryExtensionId(v)) : [];
344 }
346 function getEngine(version: IRawGalleryExtensionVersion): string {
347 const values = version.properties ? version.properties.filter(p => p.key === PropertyType.Engine) : [];
348 return (values.length > 0 && values[0].value) || '';
349 }
351 function setEngine(version: IRawGalleryExtensionVersion, engine: string): void {
352 version.properties = version.properties ?? [];
353 version.properties.push({ key: PropertyType.Engine, value: engine });
354 }
356 function isPreReleaseVersion(version: IRawGalleryExtensionVersion): boolean {
357 const values = version.properties ? version.properties.filter(p => p.key === PropertyType.PreRelease) : [];
358 return values.length > 0 && values[0].value === 'true';
359 }
361 function hasPreReleaseForExtension(id: string, productService: IProductService): boolean | undefined {
362 return productService.extensionProperties?.[id.toLowerCase()]?.hasPrereleaseVersion;
363 }
365 function getExcludeVersionRangeForExtension(id: string, productService: IProductService): string | undefined {
366 return productService.extensionProperties?.[id.toLowerCase()]?.excludeVersionRange;
367 }
369 function isPrivateExtension(version: IRawGalleryExtensionVersion): boolean {
370 const values = version.properties ? version.properties.filter(p => p.key === PropertyType.Private) : [];
371 return values.length > 0 && values[0].value === 'true';
372 }
374 function executesCode(version: IRawGalleryExtensionVersion): boolean | undefined {
375 const values = version.properties ? version.properties.filter(p => p.key === PropertyType.ExecutesCode) : [];
376 return values.length > 0 ? values[0].value === 'true' : undefined;
377 }
379 function getEnabledApiProposals(version: IRawGalleryExtensionVersion): string[] {
380 const values = version.properties ? version.properties.filter(p => p.key === PropertyType.EnabledApiProposals) : [];
382 return value ? value.split(',') : [];
383 }
385 function getLocalizedLanguages(version: IRawGalleryExtensionVersion): string[] {
386 const values = version.properties ? version.properties.filter(p => p.key === PropertyType.LocalizedLanguages) : [];
388 return value ? value.split(',') : [];
389 }
391 function getSponsorLink(version: IRawGalleryExtensionVersion): string | undefined {
392 return version.properties?.find(p => p.key === PropertyType.SponsorLink)?.value;
393 }
395 function getSupportLink(version: IRawGalleryExtensionVersion): string | undefined {
396 return version.properties?.find(p => p.key === PropertyType.SupportLink)?.value;
397 }
399 function getIsPreview(flags: string): boolean {
400 return flags.indexOf('preview') !== -1;
401 }
403 function getTargetPlatformForExtensionVersion(version: IRawGalleryExtensionVersion): TargetPlatform {
404 return version.targetPlatform ? toTargetPlatform(version.targetPlatform) : TargetPlatform.UNDEFINED;
405 }
407 function getAllTargetPlatforms(rawGalleryExtension: IRawGalleryExtension): TargetPlatform[] {
408 const allTargetPlatforms = distinct(rawGalleryExtension.versions.map(getTargetPlatformForExtensionVersion));
427 return allTargetPlatforms;
428 }
430 > export function sortExtensionVersions(versions: IRawGalleryExtensionVersion[], preferredTargetPlatform: TargetPlatform): IRawGalleryExtensionVersion[] {
431 /* It is expected that versions from Marketplace are sorted by version. So we are just sorting by preferred targetPlatform */
432 for (let index = 0; index < versions.length; index++) {
447 return versions;
448 }
450 > /**
451 > * Filters extension versions to return only the relevant versions for a given target platform.
452 > *
453 > * This function processes a list of extension versions (expected to be sorted by version descending)
454 > * and returns a filtered list containing:
455 > * 1. All versions that are NOT compatible with the target platform (for other platforms)
456 > * 2. At most one compatible release version (the first/latest one encountered)
457 > * 3. At most one compatible pre-release version (the first/latest one encountered)
458 > *
459 > * When a platform-specific version (exactly matching targetPlatform) is encountered with the same
460 > * version number as a previously stored universal/undefined version, it replaces that version.
461 > * This ensures platform-specific builds are preferred over universal builds for the same version.
462 > *
463 > * @param versions - Array of extension versions, expected to be sorted by version number descending
464 > * @param targetPlatform - The target platform to filter for (e.g., LINUX_X64, WIN32_X64)
465 > * @param allTargetPlatforms - All target platforms the extension supports
466 > * @returns Filtered array of versions relevant for the target platform
467 > */
468 > export function filterLatestExtensionVersionsForTargetPlatform(versions: IRawGalleryExtensionVersion[], targetPlatform: TargetPlatform, allTargetPlatforms: TargetPlatform[]): IRawGalleryExtensionVersion[] {
469 const latestVersions: IRawGalleryExtensionVersion[] = [];
470
502 return latestVersions;
503 }
505 function setTelemetry(extension: IGalleryExtension, index: number, querySource?: string): void {
506 /* __GDPR__FRAGMENT__
513 extension.telemetryData = { index, querySource, queryActivityId: extension.queryContext?.[SEARCH_ACTIVITY_HEADER_NAME] };
514 }
516 function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGalleryExtensionVersion, allTargetPlatforms: TargetPlatform[], extensionGalleryManifest: IExtensionGalleryManifest, productService: IProductService, queryContext?: IStringDictionary<unknown>): IGalleryExtension {
517 const latestVersion = galleryExtension.versions[0];
579 };
580 }
582 > interface IRawExtensionsControlManifest {
583 > malicious: string[];
584 > learnMoreLinks?: IStringDictionary<string>;
585 > migrateToPreRelease?: IStringDictionary<{
586 > id: string;
587 > displayName: string;
588 > migrateStorage?: boolean;
589 > engine?: string;
590 > }>;
591 > deprecated?: IStringDictionary<boolean | {
592 > disallowInstall?: boolean;
593 > extension?: {
594 > id: string;
595 > displayName: string;
596 > };
597 > settings?: string[];
598 > additionalInfo?: string;
599 > }>;
600 > search?: ISearchPrefferedResults[];
601 > autoUpdate?: IStringDictionary<string>;
602 > }
603 >
604 > export abstract class AbstractExtensionGalleryService implements IExtensionGalleryService {
605 >
606 > declare readonly _serviceBrand: undefined;
607 >
608 > private readonly extensionsControlUrl: string | undefined;
609 > private readonly unpkgResourceApi: string | undefined;
610 >
611 > private readonly commonHeadersPromise: Promise<IHeaders>;
612 >
613 > constructor(
614 storageService: IStorageService | undefined,
615 @IRequestService private readonly requestService: IRequestService,
634 this.telemetryService);
635 }
637 > isEnabled(): boolean {
638 return this.extensionGalleryManifestService.extensionGalleryManifestStatus === ExtensionGalleryManifestStatus.Available;
639 }
641 > getExtensions(extensionInfos: ReadonlyArray<IExtensionInfo>, token: CancellationToken): Promise<IGalleryExtension[]>;
642 > getExtensions(extensionInfos: ReadonlyArray<IExtensionInfo>, options: IExtensionQueryOptions, token: CancellationToken): Promise<IGalleryExtension[]>;
643 > async getExtensions(extensionInfos: ReadonlyArray<IExtensionInfo>, arg1: CancellationToken | IExtensionQueryOptions, arg2?: CancellationToken): Promise<IGalleryExtension[]> {
644 const extensionGalleryManifest = await this.extensionGalleryManifestService.getExtensionGalleryManifest();
645 if (!extensionGalleryManifest) {
681 return result;
682 }
684 > private getResourceApi(extensionGalleryManifest: IExtensionGalleryManifest): { uri: string; fallback?: string } | undefined {
685 const latestVersionResource = getExtensionGalleryManifestResourceUri(extensionGalleryManifest, ExtensionGalleryResourceType.ExtensionLatestVersionUri);
686 if (latestVersionResource) {
692 return undefined;
693 }
695 > private async getExtensionsUsingQueryApi(extensionInfos: ReadonlyArray<IExtensionInfo>, options: IExtensionQueryOptions, extensionGalleryManifest: IExtensionGalleryManifest, token: CancellationToken): Promise<IGalleryExtension[]> {
696 const names: string[] = [],
697 ids: string[] = [],
751 return extensions;
752 }
754 > private async getExtensionsUsingResourceApi(extensionInfos: ReadonlyArray<IExtensionInfo>, options: IExtensionQueryOptions, resourceApi: { uri: string; fallback?: string }, extensionGalleryManifest: IExtensionGalleryManifest, token: CancellationToken): Promise<IGalleryExtension[]> {
755
756 const result: IGalleryExtension[] = [];
847 return result;
848 }
850 > private async getLatestGalleryExtension(extensionInfo: IExtensionInfo, options: IExtensionQueryOptions, resourceApi: { uri: string; fallback?: string }, extensionGalleryManifest: IExtensionGalleryManifest, token: CancellationToken): Promise<IGalleryExtension | string> {
851 const rawGalleryExtension = await this.getLatestRawGalleryExtensionWithFallback(extensionInfo, resourceApi, token);
852
870 return toExtension(rawGalleryExtension, rawGalleryExtensionVersion, allTargetPlatforms, extensionGalleryManifest, this.productService);
871 }
873 > private async getValidRawGalleryExtensionVersionFromLatestVersions(rawGalleryExtension: IRawGalleryExtension, latestVersions: IRawGalleryExtensionVersion[], extensionInfo: IExtensionInfo, options: IExtensionQueryOptions, allTargetPlatforms: TargetPlatform[]): Promise<IRawGalleryExtensionVersion | null> {
874 const targetPlatform = options.targetPlatform ?? CURRENT_TARGET_PLATFORM;
875 const latestExtensionVersionsForTargetPlatform = filterLatestExtensionVersionsForTargetPlatform(latestVersions, targetPlatform, allTargetPlatforms);
944 return prereleaseVersion ?? releaseVersion ?? null;
945 }
947 > async getCompatibleExtension(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion: IProductVersion = { version: this.productService.version, date: this.productService.date }): Promise<IGalleryExtension | null> {
948 if (isNotWebExtensionInWebTargetPlatform(extension.allTargetPlatforms, targetPlatform)) {
949 return null;
968 return result[0] ?? null;
969 }
971 > async isExtensionCompatible(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion: IProductVersion = { version: this.productService.version, date: this.productService.date }): Promise<boolean> {
972 return this.isValidVersion(
973 {
990 );
991 }
993 > private async isValidVersion(
994 extension: { id: string; version: string; isPreReleaseVersion: boolean; targetPlatform: TargetPlatform; manifestAsset: IGalleryExtensionAsset | null; engine: string | undefined; enabledApiProposals: string[] | undefined },
995 { targetPlatform, compatible, productVersion, version }: Omit<ExtensionVersionCriteria, 'targetPlatform'> & { targetPlatform: TargetPlatform | undefined },
1039 return true;
1040 }
1042 > private async isEngineValid(extensionId: string, version: string, engine: string | undefined, manifestAsset: IGalleryExtensionAsset | null, productVersion: IProductVersion): Promise<boolean> {
1043 if (!engine) {
1044 try {
1057 return isEngineValid(engine, productVersion.version, productVersion.date);
1058 }
1060 > private async getEngine(extensionId: string, version: string, manifestAsset: IGalleryExtensionAsset | null): Promise<string | undefined> {
1061 if (!manifestAsset) {
1062 this.logService.error(`Missing engine and manifest asset for the extension ${extensionId} with version ${version}`);
1089 }
1090 }
1092 > async query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>> {
1093 const extensionGalleryManifest = await this.extensionGalleryManifestService.getExtensionGalleryManifest();
1094
1181 return { firstPage: extensions, total, pageSize: query.pageSize, getPage };
1182 }
1184 > private async queryGalleryExtensions(query: Query, criteria: ExtensionsCriteria, extensionGalleryManifest: IExtensionGalleryManifest, token: CancellationToken): Promise<{ extensions: IGalleryExtension[]; total: number }> {
1185 const flags = query.flags;
1186
1307 return { extensions: result.sort((a, b) => a[0] - b[0]).map(([, extension]) => extension), total };
1308 }
1310 > private async getValidRawGalleryExtensionVersion(rawGalleryExtension: IRawGalleryExtension, versions: IRawGalleryExtensionVersion[], criteria: ExtensionVersionCriteria, allTargetPlatforms: TargetPlatform[]): Promise<IRawGalleryExtensionVersion | null> {
1311 const extensionIdentifier = { id: getGalleryExtensionId(rawGalleryExtension.publisher.publisherName, rawGalleryExtension.extensionName), uuid: rawGalleryExtension.extensionId };
1312 const rawGalleryExtensionVersions = sortExtensionVersions(versions, criteria.targetPlatform);
1354 return rawGalleryExtension.versions[0];
1355 }
1357 > private async setEngineIfNotExists(extensionId: string, rawGalleryExtensionVersion: IRawGalleryExtensionVersion): Promise<void> {
1358 if (getEngine(rawGalleryExtensionVersion)) {
1359 return;
1369 }
1370 }
1372 > private async queryRawGalleryExtensions(query: Query, extensionGalleryManifest: IExtensionGalleryManifest, token: CancellationToken): Promise<IRawGalleryExtensionsResult> {
1373 const extensionsQueryApi = getExtensionGalleryManifestResourceUri(extensionGalleryManifest, ExtensionGalleryResourceType.ExtensionQueryService);
1374
1494 }
1495 }
1497 > private getHeaderValue(headers: IHeaders | undefined, name: string): TelemetryTrustedValue<string> | undefined {
1498 const headerValue = headers?.[name.toLowerCase()];
1499 const value = Array.isArray(headerValue) ? headerValue[0] : headerValue;
1500 return value ? new TelemetryTrustedValue(value) : undefined;
1501 }
1503 > private async getLatestRawGalleryExtensionWithFallback(extensionInfo: IExtensionInfo, resourceApi: { uri: string; fallback?: string }, token: CancellationToken): Promise<IRawGalleryExtension | null> {
1504 const [publisher, name] = extensionInfo.id.split('.');
1505 let errorCode: string | undefined;
1565 }
1566 }
1568 > private async getLatestRawGalleryExtension(extension: string, uri: URI, token: CancellationToken): Promise<IRawGalleryExtension | null> {
1569 let context;
1570 let errorCode: string | undefined;
1658 }
1659 }
1661 > async reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void> {
1662 if (isWeb) {
1663 this.logService.info('ExtensionGalleryService#reportStatistic: Skipped in web');
1688 } catch (error) { /* Ignore */ }
1689 }
1691 > async download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise<void> {
1692 this.logService.trace('ExtensionGalleryService#download', extension.identifier.id);
1693 const data = getGalleryExtensionTelemetryData(extension);
1727 this.telemetryService.publicLog('galleryService:downloadVSIX', { ...data, duration: new Date().getTime() - startTime });
1728 }
1730 > async downloadSignatureArchive(extension: IGalleryExtension, location: URI): Promise<void> {
1731 if (!extension.assets.signature) {
1732 throw new Error('No signature asset found');
1749
1750 }
1752 > async getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string> {
1753 if (extension.assets.readme) {
1754 const context = await this.getAsset(extension.identifier.id, extension.assets.readme, AssetType.Details, extension.version, 'extensionGalleryService.readme', {}, token);
1758 return '';
1759 }
1761 > async getManifest(extension: IGalleryExtension, token: CancellationToken): Promise<IExtensionManifest | null> {
1762 if (extension.assets.manifest) {
1763 const context = await this.getAsset(extension.identifier.id, extension.assets.manifest, AssetType.Manifest, extension.version, 'extensionGalleryService.manifest', {}, token);
1767 return null;
1768 }
1770 > async getCoreTranslation(extension: IGalleryExtension, languageId: string): Promise<ITranslation | null> {
1771 const asset = extension.assets.coreTranslations.filter(t => t[0] === languageId.toUpperCase())[0];
1772 if (asset) {
1777 return null;
1778 }
1780 > async getChangelog(extension: IGalleryExtension, token: CancellationToken): Promise<string> {
1781 if (extension.assets.changelog) {
1782 const context = await this.getAsset(extension.identifier.id, extension.assets.changelog, AssetType.Changelog, extension.version, 'extensionGalleryService.changelog', {}, token);
1786 return '';
1787 }
1789 > async getAllVersions(extensionIdentifier: IExtensionIdentifier): Promise<IGalleryExtensionVersion[]> {
1790 return this.getVersions(extensionIdentifier);
1791 }
1793 > async getAllCompatibleVersions(extensionIdentifier: IExtensionIdentifier, includePreRelease: boolean, targetPlatform: TargetPlatform): Promise<IGalleryExtensionVersion[]> {
1794 return this.getVersions(extensionIdentifier, { version: includePreRelease ? VersionKind.Latest : VersionKind.Release, targetPlatform });
1795 }
1797 > private async getVersions(extensionIdentifier: IExtensionIdentifier, onlyCompatible?: { version: VersionKind; targetPlatform: TargetPlatform }): Promise<IGalleryExtensionVersion[]> {
1798 const extensionGalleryManifest = await this.extensionGalleryManifestService.getExtensionGalleryManifest();
1799 if (!extensionGalleryManifest) {
1866 return result;
1867 }
1869 > private async getAsset(extension: string, asset: IGalleryExtensionAsset, assetType: string, extensionVersion: string, callSite: string, options: Omit<IRequestOptions, 'callSite'> = {}, token: CancellationToken = CancellationToken.None): Promise<IRequestContext> {
1870 const commonHeaders = await this.commonHeadersPromise;
1871 const baseOptions = { type: 'GET' };
1925 }
1926 }
1928 > async getExtensionsControlManifest(): Promise<IExtensionsControlManifest> {
1929 const manifest = await this.extensionGalleryManifestService.getExtensionGalleryManifest();
1930 if (!manifest) {
2002 return { malicious, deprecated, search, autoUpdate };
2003 }
2005 > private getRequestTimeout(): number {
2006 const configuredTimeout = this.configurationService.getValue<number>(ExtensionRequestsTimeoutConfigKey);
2007 return isNumber(configuredTimeout) && configuredTimeout >= 0 ? configuredTimeout : 60_000;
2008 }
2010 > }
2011 >
2012 > export class ExtensionGalleryService extends AbstractExtensionGalleryService {
2013 >
2014 > constructor(
2015 @IStorageService storageService: IStorageService,
2016 @IRequestService requestService: IRequestService,
2026 super(storageService, requestService, logService, environmentService, telemetryService, fileService, productService, configurationService, allowedExtensionsService, extensionGalleryManifestService);
2027 }
2029 >
2030 > export class ExtensionGalleryServiceWithNoStorageService extends AbstractExtensionGalleryService {
2031 >
2032 > constructor(
2033 @IRequestService requestService: IRequestService,
2034 @ILogService logService: ILogService,
2043 super(undefined, requestService, logService, environmentService, telemetryService, fileService, productService, configurationService, allowedExtensionsService, extensionGalleryManifestService);
2044 }
src/vs/base/parts/request/common/request.ts 58 introduced LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- request.ts
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 { VSBufferReadableStream } from '../../../common/buffer.js';
7 >
8 > const offlineName = 'Offline';
9 >
10 > /**
11 > * Checks if the given error is offline error
12 > */
13 > export function isOfflineError(error: unknown): boolean {
14 if (error instanceof OfflineError) {
15 return true;
17 return error instanceof Error && error.name === offlineName && error.message === offlineName;
18 }
19 > request.ts
20 > export class OfflineError extends Error {
21 > constructor() {
22 super(offlineName);
23 this.name = this.message;
24 }
25 > } request.ts
26 >
27 > export interface IHeaders {
28 > 'Proxy-Authorization'?: string;
29 > 'x-operation-id'?: string;
30 > 'retry-after'?: string;
31 > etag?: string;
32 > 'Content-Length'?: string;
33 > 'activityid'?: string;
34 > 'X-Market-User-Id'?: string;
35 > [header: string]: string | string[] | undefined;
36 > }
37 >
38 > export interface IRequestOptions {
39 > type?: string;
40 > url?: string;
41 > user?: string;
42 > password?: string;
43 > headers?: IHeaders;
44 > timeout?: number;
45 > data?: string;
46 > followRedirects?: number;
47 > proxyAuthorization?: string;
48 > /**
49 > * A signal to not cache the response. This may not
50 > * be supported in all implementations.
51 > */
52 > disableCache?: boolean;
53 > /**
54 > * Identifies the call site making this request, used for telemetry.
55 > * Use "NO_FETCH_TELEMETRY" to opt out of request telemetry.
56 > */
57 > callSite: string;
58 > }
59 >
60 > export interface IRequestContext {
61 > res: {
62 > headers: IHeaders;
63 > statusCode?: number;
64 > };
65 > stream: VSBufferReadableStream;
66 > }
src/vs/platform/externalServices/common/marketplace.ts 15 introduced LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- marketplace.ts
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 { IHeaders } from '../../../base/parts/request/common/request.js';
7 > import { IConfigurationService } from '../../configuration/common/configuration.js';
8 > import { IEnvironmentService } from '../../environment/common/environment.js';
9 > import { getServiceMachineId } from './serviceMachineId.js';
10 > import { IFileService } from '../../files/common/files.js';
11 > import { IProductService } from '../../product/common/productService.js';
12 > import { IStorageService } from '../../storage/common/storage.js';
13 > import { ITelemetryService, TelemetryLevel } from '../../telemetry/common/telemetry.js';
14 > import { getTelemetryLevel, supportsTelemetry } from '../../telemetry/common/telemetryUtils.js';
15 >
16 export async function resolveMarketplaceHeaders(version: string,
17 productService: IProductService,
src/vs/platform/configuration/test/common/testConfigurationService.ts 2 introduced LOC · 1 range

Open complete file

44
45 public updateValue(key: string, value: unknown): Promise<void> {
46 > return Promise.resolve(undefined); testConfigurationService.ts
47 > }
48
49 public setUserConfiguration(key: string, value: unknown, root?: URI): Promise<void> {