From 4fb7398c140d920ccd8bb409735f22688b6a4a54 Mon Sep 17 00:00:00 2001 From: Mark Sujew Date: Mon, 10 Jun 2024 16:44:35 +0200 Subject: [PATCH 1/4] Use V2 API of open-vsx --- dev-packages/cli/src/download-plugins.ts | 15 ++++-- dev-packages/ovsx-client/src/index.ts | 2 +- .../ovsx-client/src/ovsx-api-filter.ts | 48 ++++++++++++++++- .../ovsx-client/src/ovsx-http-client.ts | 4 +- .../ovsx-client/src/ovsx-mock-client.ts | 21 +++++--- .../ovsx-client/src/ovsx-router-client.ts | 7 ++- dev-packages/ovsx-client/src/ovsx-types.ts | 52 +++++++++++++++++-- .../src/node/sample-mock-open-vsx-server.ts | 2 + .../frontend-only-application-module.ts | 1 + .../core/src/common/application-protocol.ts | 1 + packages/core/src/node/application-server.ts | 4 ++ .../browser/vsx-extensions-contribution.ts | 14 +++-- .../src/browser/vsx-extensions-model.ts | 37 ++++++++----- .../src/common/vsx-registry-common-module.ts | 19 ++++++- .../src/node/vsx-extension-resolver.ts | 22 +++++--- 15 files changed, 200 insertions(+), 49 deletions(-) diff --git a/dev-packages/cli/src/download-plugins.ts b/dev-packages/cli/src/download-plugins.ts index 1f4e3208a0900..7aa0abdc5d640 100644 --- a/dev-packages/cli/src/download-plugins.ts +++ b/dev-packages/cli/src/download-plugins.ts @@ -16,7 +16,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { OVSXApiFilterImpl, OVSXClient } from '@theia/ovsx-client'; +import { OVSXApiFilterImpl, OVSXClient, VSXTargetPlatform } from '@theia/ovsx-client'; import * as chalk from 'chalk'; import * as decompress from 'decompress'; import { promises as fs } from 'fs'; @@ -75,7 +75,7 @@ export default async function downloadPlugins(ovsxClient: OVSXClient, requestSer } = options; const rateLimiter = new RateLimiter({ tokensPerInterval: rateLimit, interval: 'second' }); - const apiFilter = new OVSXApiFilterImpl(apiVersion); + const apiFilter = new OVSXApiFilterImpl(ovsxClient, apiVersion); // Collect the list of failures to be appended at the end of the script. const failures: string[] = []; @@ -129,8 +129,11 @@ export default async function downloadPlugins(ovsxClient: OVSXClient, requestSer await parallelOrSequence(Array.from(ids, id => async () => { try { await rateLimiter.removeTokens(1); - const { extensions } = await ovsxClient.query({ extensionId: id, includeAllVersions: true }); - const extension = apiFilter.getLatestCompatibleExtension(extensions); + const extension = await apiFilter.findLatestCompatibleExtension({ + extensionId: id, + includeAllVersions: true, + targetPlatform + }); const version = extension?.version; const downloadUrl = extension?.files.download; if (downloadUrl) { @@ -170,8 +173,10 @@ export default async function downloadPlugins(ovsxClient: OVSXClient, requestSer } } +const targetPlatform = `${process.platform}-${process.arch}` as VSXTargetPlatform; + const placeholders: Record = { - targetPlatform: `${process.platform}-${process.arch}` + targetPlatform }; function resolveDownloadUrlPlaceholders(url: string): string { for (const [name, value] of Object.entries(placeholders)) { diff --git a/dev-packages/ovsx-client/src/index.ts b/dev-packages/ovsx-client/src/index.ts index 8d0d7318fe398..42455e7897de3 100644 --- a/dev-packages/ovsx-client/src/index.ts +++ b/dev-packages/ovsx-client/src/index.ts @@ -14,7 +14,7 @@ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** -export { OVSXApiFilter, OVSXApiFilterImpl } from './ovsx-api-filter'; +export { OVSXApiFilter, OVSXApiFilterImpl, OVSXApiFilterProvider } from './ovsx-api-filter'; export { OVSXHttpClient } from './ovsx-http-client'; export { OVSXMockClient } from './ovsx-mock-client'; export { OVSXRouterClient, OVSXRouterConfig, OVSXRouterFilterFactory as FilterFactory } from './ovsx-router-client'; diff --git a/dev-packages/ovsx-client/src/ovsx-api-filter.ts b/dev-packages/ovsx-client/src/ovsx-api-filter.ts index 0c5c505491713..d61b3f46a5878 100644 --- a/dev-packages/ovsx-client/src/ovsx-api-filter.ts +++ b/dev-packages/ovsx-client/src/ovsx-api-filter.ts @@ -15,7 +15,11 @@ // ***************************************************************************** import * as semver from 'semver'; -import { VSXAllVersions, VSXBuiltinNamespaces, VSXExtensionRaw, VSXSearchEntry } from './ovsx-types'; +import { OVSXClient, VSXAllVersions, VSXBuiltinNamespaces, VSXExtensionRaw, VSXQueryOptions, VSXSearchEntry, VSXTargetPlatform } from './ovsx-types'; + +export const OVSXApiFilterProvider = Symbol('OVSXApiFilterProvider'); + +export type OVSXApiFilterProvider = () => Promise; export const OVSXApiFilter = Symbol('OVSXApiFilter'); /** @@ -23,6 +27,7 @@ export const OVSXApiFilter = Symbol('OVSXApiFilter'); */ export interface OVSXApiFilter { supportedApiVersion: string; + findLatestCompatibleExtension(query: VSXQueryOptions): Promise; /** * Get the latest compatible extension version: * - A builtin extension is fetched based on the extension version which matches the API. @@ -31,16 +36,55 @@ export interface OVSXApiFilter { * @param extensionId the extension id. * @returns the data for the latest compatible extension version if available, else `undefined`. */ - getLatestCompatibleExtension(extensions: VSXExtensionRaw[]): VSXExtensionRaw | undefined; + getLatestCompatibleExtension(extensions: VSXExtensionRaw[], targetPlatform?: VSXTargetPlatform): VSXExtensionRaw | undefined; getLatestCompatibleVersion(searchEntry: VSXSearchEntry): VSXAllVersions | undefined; } export class OVSXApiFilterImpl implements OVSXApiFilter { constructor( + public client: OVSXClient, public supportedApiVersion: string ) { } + async findLatestCompatibleExtension(query: VSXQueryOptions): Promise { + const targetPlatform = query.targetPlatform; + if (!targetPlatform) { + return this.queryLatestCompatibleExtension(query); + } + const latestWithTargetPlatform = await this.queryLatestCompatibleExtension(query); + let latestUniversal: VSXExtensionRaw | undefined; + if (targetPlatform !== 'universal' && targetPlatform !== 'web') { + // Additionally query the universal version, as there might be a newer one available + latestUniversal = await this.queryLatestCompatibleExtension({ ...query, targetPlatform: 'universal' }); + } + if (latestWithTargetPlatform && latestUniversal) { + // Prefer the version with the target platform if it's greater or equal to the universal version + return this.versionGreaterThanOrEqualTo(latestWithTargetPlatform.version, latestUniversal.version) ? latestWithTargetPlatform : latestUniversal; + } + return latestWithTargetPlatform ?? latestUniversal; + } + + protected async queryLatestCompatibleExtension(query: VSXQueryOptions): Promise { + let offset = 0; + const size = 100; + let flag = true; + while (flag) { + const queryOptions = { + ...query, + offset + }; + offset += size; + const results = await this.client.query(queryOptions); + flag = results.totalSize < offset; + const compatibleExtension = this.getLatestCompatibleExtension(results.extensions); + if (compatibleExtension) { + return compatibleExtension; + } + } + return undefined; + } + getLatestCompatibleExtension(extensions: VSXExtensionRaw[]): VSXExtensionRaw | undefined { if (extensions.length === 0) { return; diff --git a/dev-packages/ovsx-client/src/ovsx-http-client.ts b/dev-packages/ovsx-client/src/ovsx-http-client.ts index 84629e61f02df..2f933a51f2219 100644 --- a/dev-packages/ovsx-client/src/ovsx-http-client.ts +++ b/dev-packages/ovsx-client/src/ovsx-http-client.ts @@ -48,10 +48,12 @@ export class OVSXHttpClient implements OVSXClient { async query(queryOptions?: VSXQueryOptions): Promise { try { - return await this.requestJson(this.buildUrl('api/-/query', queryOptions)); + return await this.requestJson(this.buildUrl('api/v2/-/query', queryOptions)); } catch (error) { console.warn(error); return { + offset: 0, + totalSize: 0, extensions: [] }; } diff --git a/dev-packages/ovsx-client/src/ovsx-mock-client.ts b/dev-packages/ovsx-client/src/ovsx-mock-client.ts index f7366f841b62d..05388cce9e24c 100644 --- a/dev-packages/ovsx-client/src/ovsx-mock-client.ts +++ b/dev-packages/ovsx-client/src/ovsx-mock-client.ts @@ -61,21 +61,26 @@ export class OVSXMockClient implements OVSXClient { reviewsUrl: url.extensionReviewsUrl(namespace, name), timestamp: new Date(now - ids.length + i + 1).toISOString(), version, - description: `Mock VS Code Extension for ${id}` + description: `Mock VS Code Extension for ${id}`, + namespaceDisplayName: name, + preRelease: false }; }); return this; } async query(queryOptions?: VSXQueryOptions): Promise { + const extensions = this.extensions + .filter(extension => typeof queryOptions === 'object' && ( + this.compare(queryOptions.extensionId, this.id(extension)) && + this.compare(queryOptions.extensionName, extension.name) && + this.compare(queryOptions.extensionVersion, extension.version) && + this.compare(queryOptions.namespaceName, extension.namespace) + )); return { - extensions: this.extensions - .filter(extension => typeof queryOptions === 'object' && ( - this.compare(queryOptions.extensionId, this.id(extension)) && - this.compare(queryOptions.extensionName, extension.name) && - this.compare(queryOptions.extensionVersion, extension.version) && - this.compare(queryOptions.namespaceName, extension.namespace) - )) + offset: 0, + totalSize: extensions.length, + extensions }; } diff --git a/dev-packages/ovsx-client/src/ovsx-router-client.ts b/dev-packages/ovsx-client/src/ovsx-router-client.ts index f5121b3e18b09..6b524b9491b62 100644 --- a/dev-packages/ovsx-client/src/ovsx-router-client.ts +++ b/dev-packages/ovsx-client/src/ovsx-router-client.ts @@ -152,6 +152,8 @@ export class OVSXRouterClient implements OVSXClient { protected emptyQueryResult(queryOptions?: VSXQueryOptions): VSXQueryResult { return { + offset: 0, + totalSize: 0, extensions: [] }; } @@ -183,8 +185,11 @@ export class OVSXRouterClient implements OVSXClient { results.forEach((result, sourceUri) => { result.extensions.forEach(extension => filtering.push(this.filterExtension(sourceUri, extension))); }); + const extensions = removeNullValues(await Promise.all(filtering)); return { - extensions: removeNullValues(await Promise.all(filtering)) + offset: 0, + totalSize: extensions.length, + extensions }; } diff --git a/dev-packages/ovsx-client/src/ovsx-types.ts b/dev-packages/ovsx-client/src/ovsx-types.ts index 21327fe9aa36b..223e3ef5bea6f 100644 --- a/dev-packages/ovsx-client/src/ovsx-types.ts +++ b/dev-packages/ovsx-client/src/ovsx-types.ts @@ -49,7 +49,7 @@ export interface OVSXClient { */ search(searchOptions?: VSXSearchOptions): Promise; /** - * GET https://openvsx.org/api/-/query + * GET https://openvsx.org/api/v2/-/query * * Fetch one or all versions of an extension. */ @@ -110,8 +110,6 @@ export interface VSXSearchResult { extensions: VSXSearchEntry[]; } -/** @deprecated since 1.31.0 use {@link VSXQueryOptions} instead */ -export type VSXQueryParam = VSXQueryOptions; /** * The possible options when performing a search. * @@ -126,10 +124,25 @@ export interface VSXQueryOptions { extensionId?: string; extensionUuid?: string; namespaceUuid?: string; - includeAllVersions?: boolean; + includeAllVersions?: boolean | 'links'; + targetPlatform?: VSXTargetPlatform; + size?: number; + offset?: number; } +export type VSXTargetPlatform = + 'universal' | 'web' | + 'win32-x64' | 'win32-ia32' | 'win32-arm64' | + 'darwin-x64' | 'darwin-arm64' | + 'linux-x64' | 'linux-arm64' | 'linux-armhf' | + 'alpine-x64' | 'alpine-arm64' | (string & {}); + export interface VSXQueryResult { + success?: string; + warning?: string; + error?: string; + offset: number; + totalSize: number; extensions: VSXExtensionRaw[]; } @@ -199,12 +212,15 @@ export interface VSXExtensionRaw { reviewsUrl: string; name: string; namespace: string; - publishedBy: VSXUser + targetPlatform?: VSXTargetPlatform; + publishedBy: VSXUser; + preRelease: boolean; namespaceAccess: VSXExtensionNamespaceAccess; files: VSXExtensionRawFiles; allVersions: { [version: string]: string; }; + allVersionsUrl?: string; averageRating?: number; downloadCount: number; reviewCount: number; @@ -213,22 +229,48 @@ export interface VSXExtensionRaw { preview?: boolean; verified?: boolean; displayName?: string; + namespaceDisplayName: string; description?: string; categories?: string[]; + extensionKind?: string[]; tags?: string[]; license?: string; homepage?: string; repository?: string; + sponsorLink?: string; bugs?: string; markdown?: string; galleryColor?: string; galleryTheme?: string; + localizedLanguages?: string[]; qna?: string; + badges?: VSXBadge[]; + dependencies?: VSXExtensionReference[]; + bundledExtensions?: VSXExtensionReference[]; + allTargetPlatformVersions?: VSXTargetPlatforms[]; + url?: string; engines?: { [engine: string]: string; }; } +export interface VSXBadge { + url?: string; + href?: string; + description?: string; +} + +export interface VSXExtensionReference { + url: string; + namespace: string; + extension: string; +} + +export interface VSXTargetPlatforms { + version: string; + targetPlatforms: VSXTargetPlatform[]; +} + export interface VSXResponseError extends Error { statusCode: number; } diff --git a/examples/api-samples/src/node/sample-mock-open-vsx-server.ts b/examples/api-samples/src/node/sample-mock-open-vsx-server.ts index 4a60f8cbf47eb..f89f28d7d6785 100644 --- a/examples/api-samples/src/node/sample-mock-open-vsx-server.ts +++ b/examples/api-samples/src/node/sample-mock-open-vsx-server.ts @@ -170,6 +170,8 @@ export class SampleMockOpenVsxServer implements BackendApplicationContribution { reviewsUrl: url.extensionReviewsUrl(namespace, name), timestamp: new Date().toISOString(), version, + namespaceDisplayName: name, + preRelease: false } }); })); diff --git a/packages/core/src/browser-only/frontend-only-application-module.ts b/packages/core/src/browser-only/frontend-only-application-module.ts index 1820adde62504..407f29297fc17 100644 --- a/packages/core/src/browser-only/frontend-only-application-module.ts +++ b/packages/core/src/browser-only/frontend-only-application-module.ts @@ -56,6 +56,7 @@ export const frontendOnlyApplicationModule = new ContainerModule((bind, unbind, getExtensionsInfos: async (): Promise => [], getApplicationInfo: async (): Promise => undefined, getApplicationRoot: async (): Promise => '', + getApplicationPlatform: () => Promise.resolve('web'), getBackendOS: async (): Promise => OS.Type.Linux }; if (isBound(ApplicationServer)) { diff --git a/packages/core/src/common/application-protocol.ts b/packages/core/src/common/application-protocol.ts index d4b4a848d961f..a96361a71bb05 100644 --- a/packages/core/src/common/application-protocol.ts +++ b/packages/core/src/common/application-protocol.ts @@ -24,6 +24,7 @@ export interface ApplicationServer { getExtensionsInfos(): Promise; getApplicationInfo(): Promise; getApplicationRoot(): Promise; + getApplicationPlatform(): Promise; /** * @deprecated since 1.25.0. Use `OS.backend.type()` instead. */ diff --git a/packages/core/src/node/application-server.ts b/packages/core/src/node/application-server.ts index df3996b6bb1b0..80f6bd7055596 100644 --- a/packages/core/src/node/application-server.ts +++ b/packages/core/src/node/application-server.ts @@ -49,6 +49,10 @@ export class ApplicationServerImpl implements ApplicationServer { return Promise.resolve(this.applicationPackage.projectPath); } + getApplicationPlatform(): Promise { + return Promise.resolve(`${process.platform}-${process.arch}`); + } + async getBackendOS(): Promise { return OS.type(); } diff --git a/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts b/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts index bead5c875a3d9..3585f0b40a828 100644 --- a/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts +++ b/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts @@ -29,7 +29,7 @@ import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handl import { inject, injectable, postConstruct } from '@theia/core/shared/inversify'; import { FileDialogService, OpenFileDialogProps } from '@theia/filesystem/lib/browser'; import { NAVIGATOR_CONTEXT_MENU } from '@theia/navigator/lib/browser/navigator-contribution'; -import { OVSXApiFilter, VSXExtensionRaw } from '@theia/ovsx-client'; +import { OVSXApiFilterProvider, VSXExtensionRaw, VSXTargetPlatform } from '@theia/ovsx-client'; import { VscodeCommands } from '@theia/plugin-ext-vscode/lib/browser/plugin-vscode-commands-contribution'; import { DateTime } from 'luxon'; import { OVSXClientProvider } from '../common/ovsx-client-provider'; @@ -39,6 +39,7 @@ import { VSXExtensionsCommands } from './vsx-extension-commands'; import { VSXExtensionsModel } from './vsx-extensions-model'; import { BUILTIN_QUERY, INSTALLED_QUERY, RECOMMENDED_QUERY } from './vsx-extensions-search-model'; import { VSXExtensionsViewContainer } from './vsx-extensions-view-container'; +import { ApplicationServer } from '@theia/core/lib/common/application-protocol'; import debounce = require('@theia/core/shared/lodash.debounce'); export namespace VSXCommands { @@ -58,7 +59,8 @@ export class VSXExtensionsContribution extends AbstractViewContribution { @@ -54,10 +56,23 @@ export default new ContainerModule(bind => { bind(OVSXApiFilter) .toDynamicValue(ctx => { const vsxEnvironment = ctx.container.get(VSXEnvironment); - const apiFilter = new OVSXApiFilterImpl('-- temporary invalid version value --'); + const apiFilter = new OVSXApiFilterImpl(undefined!, '-- temporary invalid version value --'); vsxEnvironment.getVscodeApiVersion() .then(apiVersion => apiFilter.supportedApiVersion = apiVersion); + const clientProvider = ctx.container.get(OVSXClientProvider); + Promise.resolve(clientProvider()).then(client => { + apiFilter.client = client; + }); return apiFilter; }) .inSingletonScope(); + bind(OVSXApiFilterProvider) + .toProvider(ctx => async () => { + const vsxEnvironment = ctx.container.get(VSXEnvironment); + const clientProvider = ctx.container.get(OVSXClientProvider); + const client = await clientProvider(); + const apiVersion = await vsxEnvironment.getVscodeApiVersion(); + const apiFilter = new OVSXApiFilterImpl(client, apiVersion); + return apiFilter; + }); }); diff --git a/packages/vsx-registry/src/node/vsx-extension-resolver.ts b/packages/vsx-registry/src/node/vsx-extension-resolver.ts index cae0e48820850..01f6b5f2173d3 100644 --- a/packages/vsx-registry/src/node/vsx-extension-resolver.ts +++ b/packages/vsx-registry/src/node/vsx-extension-resolver.ts @@ -23,7 +23,7 @@ import { PluginDeployerHandler, PluginDeployerResolver, PluginDeployerResolverCo import { FileUri } from '@theia/core/lib/node'; import { VSCodeExtensionUri } from '@theia/plugin-ext-vscode/lib/common/plugin-vscode-uri'; import { OVSXClientProvider } from '../common/ovsx-client-provider'; -import { OVSXApiFilter, VSXExtensionRaw } from '@theia/ovsx-client'; +import { OVSXApiFilterProvider, VSXExtensionRaw, VSXTargetPlatform } from '@theia/ovsx-client'; import { RequestService } from '@theia/core/shared/@theia/request'; import { PluginVSCodeEnvironment } from '@theia/plugin-ext-vscode/lib/common/plugin-vscode-environment'; import { PluginUninstallationManager } from '@theia/plugin-ext/lib/main/node/plugin-uninstallation-manager'; @@ -36,13 +36,14 @@ export class VSXExtensionResolver implements PluginDeployerResolver { @inject(RequestService) protected requestService: RequestService; @inject(PluginVSCodeEnvironment) protected readonly environment: PluginVSCodeEnvironment; @inject(PluginUninstallationManager) protected readonly uninstallationManager: PluginUninstallationManager; - @inject(OVSXApiFilter) protected vsxApiFilter: OVSXApiFilter; + @inject(OVSXApiFilterProvider) protected vsxApiFilter: OVSXApiFilterProvider; accept(pluginId: string): boolean { return !!VSCodeExtensionUri.toId(new URI(pluginId)); } static readonly TEMP_DIR_PREFIX = 'vscode-download'; + static readonly TARGET_PLATFORM = `${process.platform}-${process.arch}` as VSXTargetPlatform; async resolve(context: PluginDeployerResolverContext, options?: PluginDeployOptions): Promise { const id = VSCodeExtensionUri.toId(new URI(context.getOriginId())); @@ -50,16 +51,23 @@ export class VSXExtensionResolver implements PluginDeployerResolver { return; } let extension: VSXExtensionRaw | undefined; - const client = await this.clientProvider(); + const filter = await this.vsxApiFilter(); const version = options?.version || id.version; if (version) { console.log(`[${id}]: trying to resolve version ${version}...`); - const { extensions } = await client.query({ extensionId: id.id, extensionVersion: version, includeAllVersions: true }); - extension = extensions[0]; + extension = await filter.findLatestCompatibleExtension({ + extensionId: id.id, + extensionVersion: version, + includeAllVersions: true, + targetPlatform: VSXExtensionResolver.TARGET_PLATFORM + }); } else { console.log(`[${id}]: trying to resolve latest version...`); - const { extensions } = await client.query({ extensionId: id.id, includeAllVersions: true }); - extension = this.vsxApiFilter.getLatestCompatibleExtension(extensions); + extension = await filter.findLatestCompatibleExtension({ + extensionId: id.id, + includeAllVersions: true, + targetPlatform: VSXExtensionResolver.TARGET_PLATFORM + }); } if (!extension) { return; From 68554eea5aae65123098b3f2414852d94d7c3a75 Mon Sep 17 00:00:00 2001 From: Mark Sujew Date: Wed, 19 Jun 2024 01:31:31 +0200 Subject: [PATCH 2/4] Fix looping logic --- .vscode/launch.json | 3 ++- dev-packages/ovsx-client/src/ovsx-api-filter.ts | 6 +++--- dev-packages/ovsx-client/src/ovsx-http-client.ts | 1 - .../api-samples/src/node/sample-mock-open-vsx-server.ts | 2 +- .../vsx-registry/src/browser/vsx-extensions-contribution.ts | 2 +- packages/vsx-registry/src/browser/vsx-extensions-model.ts | 5 +++-- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 00e3862ace5e0..3539be4173f25 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -58,12 +58,13 @@ "request": "launch", "name": "Launch Browser Backend", "program": "${workspaceFolder}/examples/browser/lib/backend/main.js", + "cwd": "${workspaceFolder}/examples/browser", "args": [ "--hostname=0.0.0.0", "--port=3000", "--no-cluster", "--app-project-path=${workspaceFolder}/examples/browser", - "--plugins=local-dir:plugins", + "--plugins=local-dir:../../plugins", "--hosted-plugin-inspect=9339", "--ovsx-router-config=${workspaceFolder}/examples/ovsx-router-config.json" ], diff --git a/dev-packages/ovsx-client/src/ovsx-api-filter.ts b/dev-packages/ovsx-client/src/ovsx-api-filter.ts index d61b3f46a5878..d17d3c15ea908 100644 --- a/dev-packages/ovsx-client/src/ovsx-api-filter.ts +++ b/dev-packages/ovsx-client/src/ovsx-api-filter.ts @@ -68,15 +68,15 @@ export class OVSXApiFilterImpl implements OVSXApiFilter { protected async queryLatestCompatibleExtension(query: VSXQueryOptions): Promise { let offset = 0; const size = 100; - let flag = true; - while (flag) { + let loop = true; + while (loop) { const queryOptions = { ...query, offset }; offset += size; const results = await this.client.query(queryOptions); - flag = results.totalSize < offset; + loop = results.totalSize > offset; const compatibleExtension = this.getLatestCompatibleExtension(results.extensions); if (compatibleExtension) { return compatibleExtension; diff --git a/dev-packages/ovsx-client/src/ovsx-http-client.ts b/dev-packages/ovsx-client/src/ovsx-http-client.ts index 2f933a51f2219..f59f9615d7ff6 100644 --- a/dev-packages/ovsx-client/src/ovsx-http-client.ts +++ b/dev-packages/ovsx-client/src/ovsx-http-client.ts @@ -50,7 +50,6 @@ export class OVSXHttpClient implements OVSXClient { try { return await this.requestJson(this.buildUrl('api/v2/-/query', queryOptions)); } catch (error) { - console.warn(error); return { offset: 0, totalSize: 0, diff --git a/examples/api-samples/src/node/sample-mock-open-vsx-server.ts b/examples/api-samples/src/node/sample-mock-open-vsx-server.ts index f89f28d7d6785..4cb4af8616a4c 100644 --- a/examples/api-samples/src/node/sample-mock-open-vsx-server.ts +++ b/examples/api-samples/src/node/sample-mock-open-vsx-server.ts @@ -69,7 +69,7 @@ export class SampleMockOpenVsxServer implements BackendApplicationContribution { app.use( this.mockServerPath + '/api', express.Router() - .get('/-/query', async (req, res) => { + .get('/v2/-/query', async (req, res) => { await this.ready; res.json(await this.mockClient.query(this.sanitizeQuery(req.query))); }) diff --git a/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts b/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts index 3585f0b40a828..f29d92a566a19 100644 --- a/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts +++ b/packages/vsx-registry/src/browser/vsx-extensions-contribution.ts @@ -29,7 +29,7 @@ import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handl import { inject, injectable, postConstruct } from '@theia/core/shared/inversify'; import { FileDialogService, OpenFileDialogProps } from '@theia/filesystem/lib/browser'; import { NAVIGATOR_CONTEXT_MENU } from '@theia/navigator/lib/browser/navigator-contribution'; -import { OVSXApiFilterProvider, VSXExtensionRaw, VSXTargetPlatform } from '@theia/ovsx-client'; +import { OVSXApiFilterProvider, VSXExtensionRaw } from '@theia/ovsx-client'; import { VscodeCommands } from '@theia/plugin-ext-vscode/lib/browser/plugin-vscode-commands-contribution'; import { DateTime } from 'luxon'; import { OVSXClientProvider } from '../common/ovsx-client-provider'; diff --git a/packages/vsx-registry/src/browser/vsx-extensions-model.ts b/packages/vsx-registry/src/browser/vsx-extensions-model.ts index 56b1e332b5236..12649d8a5092e 100644 --- a/packages/vsx-registry/src/browser/vsx-extensions-model.ts +++ b/packages/vsx-registry/src/browser/vsx-extensions-model.ts @@ -262,8 +262,9 @@ export class VSXExtensionsModel { protected async fetchVerifiedStatus(id: string, client: OVSXClient, allVersions: VSXAllVersions): Promise { const res = await client.query({ extensionId: id, extensionVersion: allVersions.version, includeAllVersions: true }); - let verified = res.extensions?.[0].verified; - if (!verified && res.extensions?.[0].publishedBy.loginName === 'open-vsx') { + const extension = res.extensions?.[0]; + let verified = extension?.verified; + if (!verified && extension?.publishedBy.loginName === 'open-vsx') { verified = true; } return verified; From e60d792c9c5944ff84ad378929d3b8738b7d825a Mon Sep 17 00:00:00 2001 From: Mark Sujew Date: Fri, 21 Jun 2024 15:08:21 +0000 Subject: [PATCH 3/4] Review comments --- dev-packages/ovsx-client/src/ovsx-api-filter.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dev-packages/ovsx-client/src/ovsx-api-filter.ts b/dev-packages/ovsx-client/src/ovsx-api-filter.ts index d17d3c15ea908..0a525c06503b1 100644 --- a/dev-packages/ovsx-client/src/ovsx-api-filter.ts +++ b/dev-packages/ovsx-client/src/ovsx-api-filter.ts @@ -15,7 +15,7 @@ // ***************************************************************************** import * as semver from 'semver'; -import { OVSXClient, VSXAllVersions, VSXBuiltinNamespaces, VSXExtensionRaw, VSXQueryOptions, VSXSearchEntry, VSXTargetPlatform } from './ovsx-types'; +import { OVSXClient, VSXAllVersions, VSXBuiltinNamespaces, VSXExtensionRaw, VSXQueryOptions, VSXSearchEntry } from './ovsx-types'; export const OVSXApiFilterProvider = Symbol('OVSXApiFilterProvider'); @@ -36,7 +36,7 @@ export interface OVSXApiFilter { * @param extensionId the extension id. * @returns the data for the latest compatible extension version if available, else `undefined`. */ - getLatestCompatibleExtension(extensions: VSXExtensionRaw[], targetPlatform?: VSXTargetPlatform): VSXExtensionRaw | undefined; + getLatestCompatibleExtension(extensions: VSXExtensionRaw[]): VSXExtensionRaw | undefined; getLatestCompatibleVersion(searchEntry: VSXSearchEntry): VSXAllVersions | undefined; } @@ -67,20 +67,21 @@ export class OVSXApiFilterImpl implements OVSXApiFilter { protected async queryLatestCompatibleExtension(query: VSXQueryOptions): Promise { let offset = 0; - const size = 100; let loop = true; while (loop) { const queryOptions = { ...query, offset }; - offset += size; const results = await this.client.query(queryOptions); - loop = results.totalSize > offset; const compatibleExtension = this.getLatestCompatibleExtension(results.extensions); if (compatibleExtension) { return compatibleExtension; } + // Adjust offset by the amount of returned extensions + offset += results.extensions.length; + // Abort once we have reached the last page + loop = results.totalSize >= offset; } return undefined; } From 802b8f0d0e556250ee8930b574417eb3b025e0d3 Mon Sep 17 00:00:00 2001 From: Mark Sujew Date: Mon, 24 Jun 2024 11:38:28 +0200 Subject: [PATCH 4/4] Fix comparison --- dev-packages/ovsx-client/src/ovsx-api-filter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-packages/ovsx-client/src/ovsx-api-filter.ts b/dev-packages/ovsx-client/src/ovsx-api-filter.ts index 0a525c06503b1..7b5e0bed3190a 100644 --- a/dev-packages/ovsx-client/src/ovsx-api-filter.ts +++ b/dev-packages/ovsx-client/src/ovsx-api-filter.ts @@ -80,8 +80,8 @@ export class OVSXApiFilterImpl implements OVSXApiFilter { } // Adjust offset by the amount of returned extensions offset += results.extensions.length; - // Abort once we have reached the last page - loop = results.totalSize >= offset; + // Continue querying if there are more extensions available + loop = results.totalSize > offset; } return undefined; }