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,