Skip to content

Latest commit

 

History

History
1565 lines (1150 loc) · 71.6 KB

configuration.md

File metadata and controls

1565 lines (1150 loc) · 71.6 KB

Open VSX Configuration Properties

The configuration properties the Open VSX server understands, beyond the ones Spring Boot itself offers. See Deploying Open VSX for where to put them and how to run a deployment.

This section describes the special configuration properties supported by the Open VSX server.

Registry

Property ovsx.registry.version
Type string
Default
Compatibility Since 0.15.0

The version of the running Open VSX registry instance.

Property ovsx.changes-feed.lag
Type ISO 8601 duration
Default PT30S
Compatibility Since 1.1.0

How far behind the present the changes feed stops. A change is only reported once it is this old, so that a reader polling the feed does not miss entries written while its request was being answered.

Publishing

Property ovsx.publishing.require-license
Type boolean
Default false
Compatibility Since 0.1.0

Whether published extensions are required to have a license. If active, unlicensed extensions are rejected.

Property ovsx.publishing.max-content-size
Type long
Default 512 * 1024 * 1024 = 512MB
Compatibility Since 0.31.0

The maximum content size the server accepts when publishing an extension. This is the fallback default only: once an admin sets the Default max extension size on the admin dashboard's Settings page, the stored value shadows this property on every node and editing the configuration file no longer has any effect. See Extension size limits below.

Property ovsx.publishing.max-override-size
Type long
Default 1024 * 1024 * 1024 = 1GB
Compatibility Since 1.3.0

The hard ceiling on any publish-accepted size. It bounds both the runtime default - the admin API refuses to raise the Default max extension size above it - and any single size override - the admin API refuses to create or update one above it either. Must be greater than zero, and ovsx.publishing.max-content-size must not exceed it: the two bound the same thing, so a content size above this ceiling would make the ceiling meaningless.

Property ovsx.publishing.unsupported-icon-formats
Type string[]
Default svg
Compatibility Since 0.34.1

The list of extensions that are not allowed as icons.

Property ovsx.publishing.max-tags
Type int
Default 30
Compatibility Since 1.1.0

Maximum number of author-declared tags to keep from a published package. Tags beyond the limit are dropped; a negative value keeps all of them.

Property ovsx.publishing.max-internal-tags
Type int
Default 100
Compatibility Since 1.1.0

Maximum number of internal tags - the ones the packaging tool generates, such as __ext_yml - to keep from a published package. Counted separately from the author's own tags; a negative value keeps all of them.

Extension size limits

Four things decide how large a package a publisher may upload. In order of precedence, the first one that applies wins:

  1. An extension override - a limit set for one extension on the admin dashboard's Size overrides page.
  2. A namespace override - a limit set for a whole namespace on the same page, used when the extension has no override of its own.
  3. The runtime default - the Default max extension size field on the admin dashboard's Settings page.
  4. ovsx.publishing.max-content-size - the configured fallback, used until an admin sets the runtime default.

Four consequences worth knowing:

  • The runtime default shadows the configuration file, one way. Once the Settings field is set, that value is stored in the database and used on every node. Editing ovsx.publishing.max-content-size afterwards changes nothing until the stored setting is removed. A registry whose admins never touch the field behaves exactly as it did before overrides existed.

  • Both the runtime default and every override are bounded by ovsx.publishing.max-override-size. The admin API refuses to store either above that ceiling, so no namespace can be granted - and the registry-wide default cannot be raised to - an upload size past it. The bound is checked on write only: lowering the property afterwards leaves a default or override already above it stored and enforced, so bringing those down means editing them on the Settings or Size overrides page.

  • Overrides are only granted to verified namespaces. The admin API refuses to create one for an unverified namespace. An existing override is not revoked if the namespace later loses verification - it stays in force, and is listed on the Size overrides page like any other. The page does not currently distinguish one whose namespace has since become unverified, so reviewing those means checking the namespaces themselves.

  • An override lives and dies with what it is scoped to. Deleting a namespace, or permanently purging an extension, deletes its overrides with it. An ordinary extension deletion does not: that is a soft delete which keeps the row, so the override survives and applies again if the extension is republished. Two things can remove or strand an override without an admin asking for that in so many words:

    • The orphan-namespace cleanup. A namespace that has lost every member and holds no extensions is removed, taking its override along. A namespace later re-created under the same name therefore starts on the default limit rather than inheriting one granted to whoever held the name before.
    • A namespace change. Extension overrides follow their extension to the new namespace. The namespace-wide override moves only when the old namespace is being removed and the new one has none of its own - the new namespace's own setting otherwise stands, exactly as memberships are merged. So renaming into a namespace that already has its own namespace-wide override discards the old one with the old namespace, and renaming without removing the old namespace leaves it behind on a namespace that no longer holds the extensions, where it no longer applies to anything. Check the Size overrides page after a namespace change.

Enforcement happens in two stages, because the request body is streamed before the package has been parsed and the namespace is therefore not yet known:

  1. While the body is still arriving it is capped at the ceiling - the highest of the default and every configured override. A deployment with no overrides has a ceiling equal to its default, so nothing changes.
  2. Once the manifest is read and the namespace and extension are known, the limit that actually applies is resolved and the stored package is rejected with 413 Content Too Large if it exceeds it.

The trade-off: an oversized upload from a namespace with no override is accepted up to the ceiling before being rejected. The namespace is not in the request, so there is nothing earlier to check it against.

What clients can see

Two endpoints report limits, and they answer different questions:

  • GET /api/version reports maxExtensionSize, the default, and maxExtensionSizeCeiling, the ceiling. Both are registry-wide and need no authentication.
  • GET /api/-/size-limit?namespace=…&extension=… reports the limit that would apply to one package. It requires an access token, and — when the namespace already exists — one with publish permission for it. Neither the namespace nor the extension has to exist yet, so a first publish can ask before creating either.

The ovsx CLI reads a package's manifest before uploading, so it knows which namespace it is publishing to and asks the second endpoint for the real limit, refusing an oversized upload locally. Against a registry older than 1.3.0, which cannot answer, it falls back to warning against the default and publishing anyway.

The web UI cannot do the same: the namespace lives inside the package and nothing in the browser parses it, so the publish page checks against the ceiling instead. That never blocks an upload a namespace override would have allowed; anything under the ceiling is sent and answered by the server.

Server URL

Where this registry is reachable, which is what the absolute URLs in a response - download links, icons, an extension's API URLs - are built from.

Distinct from ovsx.webui.url below: that is where the web UI is served, which is the same host in the usual deployment but need not be, and is the upstream registry rather than this one in a mirror.

Deployment What to set
One public hostname, TLS terminated by a reverse proxy ovsx.server.url, e.g. https://openvsx.example
Served under a path, e.g. https://example.com/openvsx ovsx.server.url, including the path
No proxy, the server itself is on the internet ovsx.server.url; ovsx.server.trusted-proxies may be emptied to ignore the forwarded headers outright
The proxy reaches the server from a public address, e.g. a cloud load balancer ovsx.server.url; or add that address to ovsx.server.trusted-proxies
A mirror ovsx.server.url is the mirror's own URL, not ovsx.upstream.url or ovsx.webui.url
Several hostnames answered by one registry Leave ovsx.server.url unset, and make sure the proxy overwrites X-Forwarded-Host rather than passing on what the client sent
Local development Nothing: the server is reached over loopback, which is trusted by default

If the URLs in a response name an internal host or port, the proxy is not in ovsx.server.trusted-proxies and its headers are being ignored; the server logs a warning naming both properties the first time that happens. If they name a host nobody configured, the proxy is passing on the client's X-Forwarded-Host instead of overwriting it, and ovsx.server.url is the answer. Either way the wrong URLs are cached, so flush the caches after fixing it.

Property ovsx.server.url
Type string
Default
Compatibility Since 1.2.0

The absolute URL this registry is served at, e.g. https://openvsx.example, or https://example.com/openvsx when it is served under a path. Setting it takes the base URL out of the request altogether: the X-Forwarded-* headers are ignored, whoever sends them and however the proxies in front are configured, every node in a cluster agrees on what it emits, and the response cache holds one entry per extension rather than one per host that was asked for. Set it on any deployment reachable from the open web.

Empty by default, which derives the base URL from each request and is only as trustworthy as ovsx.server.trusted-proxies is correct for the deployment.

Property ovsx.server.trusted-proxies
Type string[]
Default 127.0.0.0/8,::1/128,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16,fc00::/7,fe80::/10
Compatibility Since 1.2.0

The peers whose X-Forwarded-Host, X-Forwarded-Proto and X-Forwarded-Prefix headers are read at all, as IP addresses or CIDR ranges, comma separated. Only consulted when ovsx.server.url is empty. The default is the loopback and private ranges, the same set Tomcat's RemoteIpValve trusts, because that is where a reverse proxy sits in a container or cluster deployment; a request from anywhere else is a client talking to this server directly and its forwarded headers are ignored.

Needs extending for a proxy that reaches this server from a public address - a cloud load balancer not on the same private network is the usual case - or the registry starts emitting internal-host URLs, and logs a warning naming both properties when it does. * reads the headers from every peer.

This decides whose headers are read, not whether their contents can be believed: a proxy that relays the client's X-Forwarded-Host instead of overwriting it is trusted here and still forwarding a value the client chose, so prefer ovsx.server.url.

Web UI

Property ovsx.webui.url
Type string
Default
Compatibility Since 0.1.0

Base URL of the web UI. This is required only if it's different from the server.

Property ovsx.webui.frontend-routes
Type string[]
Default /extension/**,/namespace/**,/search,/user-settings/**,/publish,/admin-dashboard/**
Compatibility Since 0.1.0

Routes to be forwarded to / because they are handled by the frontend, and served without authentication. Spring reads the camel case spelling ovsx.webui.frontendRoutes just as well.

Property ovsx.webui.additional-routes
Type string[]
Default
Compatibility Since 0.9.0

Further paths, comma separated, that the security configuration serves without authentication. For a customized web UI that adds pages of its own beyond ovsx.webui.frontend-routes.

Search Options

Property ovsx.search.relevance.rating
Type double
Default 1.0
Compatibility Since 0.2.0

Weight of user ratings for computing relevance. This has an impact on the order of search results when sortBy is set to relevance.

Property ovsx.search.relevance.downloads
Type double
Default 1.0
Compatibility Since 0.2.0

Weight of download counts for computing relevance. This has an impact on the order of search results when sortBy is set to relevance.

Property ovsx.search.relevance.timestamp
Type double
Default 1.0
Compatibility Since 0.2.0

Weight of publishing timestamps for computing relevance (newer extensions are ranked higher). This has an impact on the order of search results when sortBy is set to relevance.

Property ovsx.search.relevance.unverified
Type double
Default 0.5
Compatibility Since 0.2.0

Relevance factor for unverified extension versions. The combined relevance from the averageRating, downloadCount and timestamp criteria is multiplied with this value if the publisher of the extension is not a member of the extension's namespace or the namespace has no owner.

Property ovsx.search.relevance.deprecated
Type double
Default 0.5
Compatibility Since 0.17.0

Relevance factor for deprecated extension versions. The combined relevance from the averageRating, downloadCount and timestamp criteria is multiplied with this value if the extension is deprecated.

Elasticsearch

Property ovsx.elasticsearch.enabled
Type boolean
Default true
Compatibility Since 0.1.0

Whether to enable search functionality through Elasticsearch. By switching this off, it is not necessary to deploy Elasticsearch. Cannot be used together with ovsx.databasesearch.enabled.

Property ovsx.elasticsearch.clear-on-start
Type boolean
Default false
Compatibility Since 0.1.0

Whether to clear and rebuild the search index on startup. If disabled, the index is built only if it does not exist yet. Rebuilding the search index may take several minutes if there are many extensions.

Property ovsx.elasticsearch.host
Type string
Default localhost:9200
Compatibility Since 0.1.0

Host and port of the Elasticsearch instance.

Property ovsx.elasticsearch.ssl
Type boolean
Default false
Compatibility Since 0.1.0

Whether to connect with SSL.

Property ovsx.elasticsearch.username
Type string
Default
Compatibility Since 0.1.0

Username for basic authentication.

Property ovsx.elasticsearch.password
Type string
Default
Compatibility Since 0.1.0

Password for basic authentication.

Property ovsx.elasticsearch.truststore
Type string
Default
Compatibility Since 0.1.0

Path to a trust store file for SSL connection.

Property ovsx.elasticsearch.truststoreProtocol
Type string
Default TLSv1.2
Compatibility Since 0.1.0

Protocol for SSL connection.

Property ovsx.elasticsearch.truststorePassword
Type string
Default
Compatibility Since 0.1.0

Password for trust store file.

Property ovsx.elasticsearch.relevance.rating
Type double
Default 1.0
Compatibility Since 0.1.0, deprecated in 0.2.0, removed in 0.18.0 (use ovsx.search.relevance.rating)

Weight of user ratings for computing relevance. This has an impact on the order of search results when sortBy is set to relevance.

Property ovsx.elasticsearch.relevance.downloads
Type double
Default 1.0
Compatibility Since 0.1.0, deprecated in 0.2.0, removed in 0.18.0 (use ovsx.search.relevance.downloads)

Weight of download counts for computing relevance. This has an impact on the order of search results when sortBy is set to relevance.

Property ovsx.elasticsearch.relevance.timestamp
Type double
Default 1.0
Compatibility Since 0.1.0, deprecated in 0.2.0, removed in 0.18.0 (use ovsx.search.relevance.timestamp)

Weight of publishing timestamps for computing relevance (newer extensions are ranked higher). This has an impact on the order of search results when sortBy is set to relevance.

Property ovsx.elasticsearch.relevance.unverified
Type double
Default 0.5
Compatibility Since 0.1.0, deprecated in 0.2.0, removed in 0.18.0 (use ovsx.search.relevance.unverified)

Relevance factor for unverified extension versions. The combined relevance from the averageRating, downloadCount and timestamp criteria is multiplied with this value if the publisher of the extension is not a member of the extension's namespace or the namespace has no owner.

Database Search

Property ovsx.databasesearch.enabled
Type boolean
Default false
Compatibility Since 0.2.0

Whether to enable search functionality though DB queries. Cannot be used together with ovsx.elasticsearch.enabled.

File Storage

Property ovsx.storage.azure.service-endpoint
Type string
Default
Compatibility Since 0.1.0

Azure blob service endpoint URL (without parameters, must end with a slash). This is required in order to enable the Azure storage service. Example: https://openvsx.blob.core.windows.net/.

Property ovsx.storage.azure.sas-token
Type string
Default
Compatibility Since 0.1.0

The full query string containing the Azure SAS (Shared Access Signature) token.

Property ovsx.storage.azure.blob-container
Type string
Default openvsx-resources
Compatibility Since 0.1.0

Name of the Azure blob container.

Property ovsx.storage.gcp.project-id
Type string
Default
Compatibility Since 0.1.0

GCP project id. This can be omitted if the GCP client is able to detect the project from the environment.

Property ovsx.storage.gcp.bucket-id
Type string
Default
Compatibility Since 0.1.0

GCP bucket id. This is required in order to enable the Google Cloud storage service. Note that in order to upload files you need to authenticate with the storage service, e.g. by putting service account credentials into a file and pointing the environment variable GOOGLE_APPLICATION_CREDENTIALS to that file. Unauthenticated access is possible when migrating from GCP to another storage provider.

Property ovsx.storage.aws.access-key-id
Type string
Default
Compatibility Since 0.21.0

AWS Access Key ID used to authenticate the OpenVSX storage client.

Property ovsx.storage.aws.secret-access-key
Type string
Default
Compatibility Since 0.21.0

AWS Secret Access Key paired with the Access Key ID. Must be provided to enable AWS S3 storage.

Property ovsx.storage.aws.session-token
Type string
Default
Compatibility Since 0.21.0

AWS session token to provide access for only a limited amount of time.

Property ovsx.storage.aws.region
Type string
Default
Compatibility Since 0.21.0

AWS region of the S3 bucket. Example: us-east-2.

Property ovsx.storage.aws.bucket
Type string
Default
Compatibility Since 0.21.0

Name of the S3 bucket used to store uploaded VSIX files. The bucket must already exist.

Property ovsx.storage.aws.service-endpoint
Type string
Default
Compatibility Since 0.21.0

S3 service endpoint URL (must not contain query parameters). Required for enabling AWS storage. Example: https://s3.us-east-2.amazonaws.com.

Property ovsx.storage.aws.path-style-access
Type boolean
Default false
Compatibility Since 0.21.0

Whether to use a path-style endpoint where the bucket name is part of the path.

Property ovsx.storage.primary-service
Type string
Default
Compatibility Since 0.1.0

External storage service to use if multiple are active (azure-blob, aws or google-cloud). All files that are not in the primary service are automatically migrated on application startup.

Property ovsx.storage.external-resource-types
Type string[]
Default *
Compatibility Since 0.1.0

Resource types to store in an external storage provider, or * for all types. Possible values are download (i.e. the vsix file), manifest, icon, readme, license, changelog, vsixmanifest, sha256, signature, publicKey, resource and namespace-logo. If only a subset of those types is chosen, the remaining types are stored locally. Up to version 0.17.0 files are stored as byte arrays in the database. From version 0.18.0 files are stored in the local file system. The ovsx.storage.local.directory property must also be configured for this feature to work.

Property ovsx.storage.migration.enabled
Type boolean
Default true
Compatibility Since 0.30.0

Whether to run storage type migration.

Property ovsx.storage.migration-delay
Type long
Default 500
Compatibility Since 0.1.0

Delay in milliseconds between storage type migration of each file. This delay is important to avoid excessive load in the server application, since migration is performed by the server itself on startup. Longer delays decrease server load, but increase the total duration of file migration.

Property ovsx.storage.local.directory
Type string
Default
Compatibility Since 0.18.0

Base directory for local file storage. This is required in order to enable the local storage service.

Property ovsx.storage.cdn.enabled
Type boolean
Default false
Compatibility Since 0.31.0

Whether a CDN front URL shall be used for configured storage providers.

Property ovsx.storage.cdn.services
Type map
Default {}
Compatibility Since 0.31.0

Key/Value Pairs in the format <storage provider>:<CDN front URL> to configure for each storage provider a specific CDN front URL. Example:

ovsx:
  storage:
    cdn:
      services:
        aws: https://my-aws.cdn.url

Supported storage providers: aws, azure, gcp.

Property ovsx.storage.file-cache-duration
Type ISO 8601 duration
Default P7D
Compatibility Since 0.9.0

The max-age of the Cache-Control header on files served from storage. Extension files never change once published, so this can be long.

AWS Download Logs

Property ovsx.logs.aws.bucket
Type string
Default
Compatibility Since 0.31.0

Name of the S3 bucket used to store uploaded log files. The bucket must already exist.

The same credentials as defined in ovsx.storage.aws will be used to access the S3 log bucket.

Property ovsx.logs.aws.log-location-prefix
Type string
Default AWSLogs/
Compatibility Since 0.31.0

The log location prefix to use for searching available logs in the defined bucket.

Property ovsx.logs.aws.format
Type string
Default cloudfront
Compatibility Since 0.32.0

The type of log format to process. Supports cloudfront or fastly.

Property ovsx.logs.aws.cron
Type string
Default 0 10 * * * *
Compatibility Since 0.32.0

The schedule in crontab format to run the AWS download logs job.

Property ovsx.logs.aws.max-keys
Type int
Default 100
Compatibility Since 0.34.0

How many log objects to list per request while reading download logs from the bucket.

Property ovsx.logs.aws.archive-prefix
Type string
Default
Compatibility Since 1.3.0

Where to keep a processed log file instead of only deleting it. When set, the file is copied to this prefix within the same bucket before the original is removed; when empty, the default, a processed file is deleted outright.

Azure Download Logs

Property ovsx.logs.azure.sas-token
Type string
Default
Compatibility Since 0.6.0

The full query string containing the Azure SAS (Shared Access Signature) token to get Azure download logs.

Property ovsx.logs.azure.service-endpoint
Type string
Default
Compatibility Since 0.6.0

Azure download logs blob service endpoint URL. This is required in order to enable the Azure download count service.

Property ovsx.logs.azure.blob-container
Type string
Default insights-logs-storageread
Compatibility Since 0.6.0

Name of the Azure download logs blob container.

Property ovsx.logs.azure.cron
Type string
Default 0 5 * * * *
Compatibility Since 0.32.0

The schedule in crontab format to run the Azure download logs job.

Upstream Registry

Property ovsx.upstream.url
Type string
Default
Compatibility Since 0.1.0

Base URL of the upstream registry instance.

Property ovsx.upstream.proxy.enabled
Type boolean
Default false
Compatibility Since 0.23.0

Whether responses forwarded from the upstream registry have their URLs rewritten to point at this instance. Without it a client following a URL from a forwarded response leaves for the upstream registry.

VS Code

Property ovsx.vscode.upstream.gallery-url
Type string
Default
Compatibility Since 0.1.0

Gallery URL of a registry instance from which to fetch extension UUIDs. These UUIDs are required by VS Code to identify and auto-update installed extensions. If no upstream gallery is set, random UUIDs are generated for all published extensions.

Property ovsx.vscode.upstream.update-on-start
Type boolean
Default false
Compatibility Since 0.14.2

Whether to update public ids on startup from the upstream registry instance.

Property ovsx.extension-query.max-pre-release-versions
Type int
Default -1
Compatibility Since 1.1.1

How many of an extension's pre-release versions an extensionquery response lists. Regular releases are never capped. A negative value, the default, caps nothing.

Migrations

Property ovsx.migrations.delay.seconds
Type boolean
Default false
Compatibility Since 0.9.1

Delay in seconds to run migrations. This delay is important to avoid distributing migration jobs to the old server instance, which prevents server shutdown.

Property ovsx.migrations.once-per-version
Type boolean
Default false
Compatibility Since 0.27.0

Only run migrations once per version. Useful in production where server instances are frequently restarted.

Property ovsx.migrations.cron
Type cron expression
Default 0 */15 * * * *
Compatibility Since 0.32.0

How often due migration items are picked up.

Property ovsx.migrations.batch-size
Type int
Default 200
Compatibility Since 0.32.0

How many migration items one scheduled run may queue, which bounds how much scheduled work can sit ahead of a user-triggered job.

Mirror Mode

Property ovsx.data.mirror.enabled
Type boolean
Default false
Compatibility Since 0.9.0

Whether to enable mirror mode.

Property ovsx.data.mirror.server-url
Type string
Default
Compatibility Since 0.9.0

Base URL of the Open VSX instance to mirror.

Property ovsx.data.mirror.schedule
Type string
Default
Compatibility Since 0.9.0

When to run the mirror job. A CRON expression is expected.

Property ovsx.data.mirror.user-name
Type string
Default
Compatibility Since 0.9.0

A username for the mirror mode user, so that its actions can be identified in the admin logs.

Property ovsx.data.mirror.requests-per-second
Type double
Default Double.MAX_VALUE
Compatibility Since 0.9.0

Limit the amount of requests per second to reduce strain on the mirrored Open VSX instance.

Property ovsx.data.mirror.read-only.disallowed-methods
Type string[]
Default
Compatibility Since 0.9.0

Disallowed HTTP methods (POST, GET, etc.) for server endpoints to limit access in mirror mode, e.g. disallow POST method to block publishing.

Property ovsx.data.mirror.read-only.allowed-endpoints
Type string[]
Default
Compatibility Since 0.9.0

Allowed server endpoints in mirror mode to override disallowed methods, e.g. disallow POST method but allow posting reviews.

Property ovsx.data.mirror.include-extensions
Type string[]
Default
Compatibility Since 0.21.0

The extensions to mirror, as namespace.extension or namespace.* for a whole namespace, comma separated. Empty mirrors everything the upstream registry offers. Every version of a matched extension is mirrored; there is no version selector. See Mirror Mode.

Property ovsx.data.mirror.exclude-extensions
Type string[]
Default
Compatibility Since 0.21.0

The extensions not to mirror, as namespace.extension or namespace.* for a whole namespace, comma separated. Takes precedence over include-extensions wherever both match.

Foreground HTTP Connection Pool

The foreground HTTP connection pool is used to make REST requests (upstream, Eclipse API) while serving requests.

Property ovsx.foregroundHttpConnPool.maxTotal
Type integer
Default 20
Compatibility Since 0.9.0

The maximum total HTTP connections.

Property ovsx.foregroundHttpConnPool.defaultMaxPerRoute
Type integer
Default 20
Compatibility Since 0.9.0

The default maximum HTTP connections per route.

Property ovsx.foregroundHttpConnPool.connectionRequestTimeout
Type integer
Default 10000
Compatibility Since 0.9.0

The time in milliseconds to wait for a connection from the HTTP connection pool.

Property ovsx.foregroundHttpConnPool.connectTimeout
Type integer
Default 10000
Compatibility Since 0.9.0

The time in milliseconds to establish the connection with the remote host.

Property ovsx.foregroundHttpConnPool.socketTimeout
Type integer
Default 10000
Compatibility Since 0.9.0

The maximum time of inactivity in milliseconds between two data packets.

Background HTTP Connection Pool

The background HTTP connection pool is used to download files in background processing (migrations, mirror mode).

Property ovsx.backgroundHttpConnPool.maxTotal
Type integer
Default 20
Compatibility Since 0.9.0

The maximum total HTTP connections.

Property ovsx.backgroundHttpConnPool.defaultMaxPerRoute
Type integer
Default 20
Compatibility Since 0.9.0

The default maximum HTTP connections per route.

Property ovsx.backgroundHttpConnPool.connectionRequestTimeout
Type integer
Default 30000
Compatibility Since 0.9.0

The time in milliseconds to wait for a connection from the HTTP connection pool.

Property ovsx.backgroundHttpConnPool.connectTimeout
Type integer
Default 30000
Compatibility Since 0.9.0

The time in milliseconds to establish the connection with the remote host.

Property ovsx.backgroundHttpConnPool.socketTimeout
Type integer
Default 60000
Compatibility Since 0.9.0

The maximum time of inactivity in milliseconds between two data packets.

Extension Control

Property ovsx.extension-control.enabled
Type boolean
Default true
Compatibility Since 0.22.0

Whether to run a nightly job to check for malicious and deprecated extensions. Cannot be used together with ovsx.mirror.enabled.

Property ovsx.extension-control.update-on-start
Type boolean
Default false
Compatibility Since 0.17.0

Whether to run a job on startup to check for malicious and deprecated extensions. If disabled, the job still runs nightly. Has no effect when ovsx.extension-control.enabled is false.

Property ovsx.extension-control.delete-transitively
Type boolean
Default false
Compatibility Since 0.32.0

Whether removing an extension through the extension control file also removes what depends on it, rather than only the extension named.

Extension Integrity

Property ovsx.integrity.key-pair
Type string
Default
Compatibility Since 0.11.0

Whether to generate a signature archive (sigzip) for published extensions. By default it does nothing. There are 3 modes: create, renew and delete. When renew is specified, then on startup a new keypair is generated and a new signature is generated for each extension version in the background. When create is specified then on startup, if no keypair exists, a keypair is created and a signature is generated for each extension version in the background. A signature is generated for newly published extension versions in both renew and create modes. The delete mode deletes the keypair and all generated signatures.

OAuth2

The ovsx.oauth2.attribute-names.[provider-name].* configuration properties allow mapping a login provider's attributes to Open VSX user data. By default it provides an attribute name configuration for GitHub. It is possible to configure attribute name mappings for multiple login providers. Make sure to also configure Spring Security using its spring.security.oauth2.client.registration.[provider-name].* and spring.security.oauth2.client.provider.[provider-name].* properties.

Property ovsx.oauth2.attribute-names.[provider-name].avatar-url
Type string
Default
Compatibility Since 0.23.0

Avatar URL login provider attribute.

Property ovsx.oauth2.attribute-names.[provider-name].email
Type string
Default
Compatibility Since 0.23.0

Email address login provider attribute.

Property ovsx.oauth2.attribute-names.[provider-name].full-name
Type string
Default
Compatibility Since 0.23.0

Full name login provider attribute.

Property ovsx.oauth2.attribute-names.[provider-name].login-name
Type string
Default
Compatibility Since 0.23.0

Username or another login provider attribute that can be used to uniquely identify users. The registry uses login-name combined with provider-name to retrieve a user from the database.

Property ovsx.oauth2.attribute-names.[provider-name].provider-url
Type string
Default
Compatibility Since 0.23.0

Profile page login provider attribute

Property ovsx.oauth2.attribute-names
Type map
Default
Compatibility Since 0.15.0

The attribute name mappings, keyed by login provider - the family the ovsx.oauth2.attribute-names.[provider-name].* entries above belong to. GitHub is mapped out of the box; any other provider needs an entry here.

CORS

Which browser origins may read this registry's public, unauthenticated surface.

Property ovsx.cors.public-origins
Type string[]
Default *
Compatibility Since 1.2.0

The origins allowed to read the registry API, the VS Code gallery adapter and the static documents from a browser, comma separated; * for any. Any by default, because that surface exists to be consumed by clients that are not this registry's own web UI. Clients that are not browsers never consult it. Worth narrowing, or emptying to register no public CORS mappings at all, on a registry that is not meant to be read from the open web. Never sent with credentials, whatever it names.

Caching

Since v0.28.0 Open VSX uses Spring Data Redis for caching. Previous Open VSX versions used Ehcache.
You can use the standard Spring Data Redis application properties to configure a connection.

Property ovsx.redis.embedded
Type boolean
Default false
Compatibility Since 0.28.0, removed in 0.29.0

Whether to run an embedded Redis server. Useful for development and small deployments.

Property ovsx.redis.enabled
Type boolean
Default false
Compatibility Since 0.29.0

Whether to use Redis for caching. Caffeine (in-memory cache) is used by default.

Property ovsx.caching.statistics.enabled
Type boolean
Default false
Compatibility Since 1.3.0

Whether the caches count hits, misses and evictions, which the admin dashboard's Caches page reports. Off by default: every cache implementation counts on the lookup path, so it is paid on every cache read for numbers nothing consults unless somebody is looking at that page. Changing it takes a restart, since the counting is configured when each cache is built.

With it off, the page still shows each cache and its entry count and can still clear them; only the hit, miss, hit rate and eviction columns are empty. They are shown as absent rather than as zero, so a cache that is not counted cannot be mistaken for one that is never hit.

Property ovsx.caching.files-extension.tti
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.28.0

Time to idle for caching extension files.

Property ovsx.caching.files-extension.max-size
Type long
Default 20
Compatibility Since 0.28.0

Maximum amount of extension files to keep in cache.

Property ovsx.caching.files-webresource.tti
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.28.0

Time to idle for caching webresource files.

Property ovsx.caching.files-webresource.max-size
Type long
Default 150
Compatibility Since 0.28.0

Maximum amount of webresource files to keep in cache.

Property ovsx.caching.files-browse.tti
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.28.0

Time to idle for caching /vscode/unpkg JSON responses.

Property ovsx.caching.files-browse.max-size
Type long
Default 50
Compatibility Since 0.28.0

Maximum amount of /vscode/unpkg JSON responses to keep in cache.

Property ovsx.caching.average-review-rating.ttl
Type ISO 8601 duration
Default P3D
Compatibility Since 0.28.0

Time to live for caching calculated average review rating. The average review rating is calculated and updated every day by a recurring job. The default duration is 3 days to make sure the cached value doesn't expire in between job runs.

Property ovsx.caching.average-review-rating.max-size
Type long
Default 1
Compatibility Since 0.29.0

Cache for calculated average review rating. Does not apply to Redis cache manager.

Property ovsx.caching.namespace-details-json.ttl
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.28.0

Time to live for caching /api/{namespace}/details JSON responses

Property ovsx.caching.namespace-details-json.max-size
Type long
Default 1024
Compatibility Since 0.29.0

Maximum amount of namespace details JSON responses to keep in cache. Does not apply to Redis cache manager.

Property ovsx.caching.database-search.ttl
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.28.0

Time to live for caching search results. Has no effect when ovsx.databasesearch.enabled is false.

Property ovsx.caching.database-search.max-size
Type long
Default 1024
Compatibility Since 0.29.0

Maximum amount of database search results to keep in cache. Does not apply to Redis cache manager.

Property ovsx.caching.extension-json.ttl
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.28.0

Time to live for caching extension JSON responses (i.e. /api/{namespace}/{extension}, /api/{namespace}/{extension}/{version}, /api/{namespace}/{extension}/{target} and /api/{namespace}/{extension}/{target}/{version}).

Property ovsx.caching.extension-json.max-size
Type long
Default 1024
Compatibility Since 0.29.0

Maximum amount of extension JSON responses to keep in cache. Does not apply to Redis cache manager.

Property ovsx.caching.latest-extension-version.ttl
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.28.0

Time to live for caching latest extension version data.

Property ovsx.caching.latest-extension-version.max-size
Type long
Default 1024
Compatibility Since 0.29.0

Maximum amount of latest extension version data to keep in cache. Does not apply to Redis cache manager.

Property ovsx.caching.latest-extension-version-vscode.ttl
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.34.2

Time to live for caching latest extension version data for the vscode adapter api.

Property ovsx.caching.latest-extension-version-vscode.max-size
Type long
Default 1024
Compatibility Since 0.34.2

Maximum amount of latest extension version data for the vscode adapter api to keep in cache. Does not apply to Redis cache manager.

Property ovsx.caching.latest-extension-versions-by-platform.ttl
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.34.2

Time to live for caching latest extension version data grouped by target platform.

Property ovsx.caching.latest-extension-versions-by-platform.max-size
Type long
Default 1024
Compatibility Since 0.34.2

Maximum amount of latest extension version data grouped by target platform to keep in cache. Does not apply to Redis cache manager.

Property ovsx.caching.sitemap.ttl
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.28.0

Time to live for caching /sitemap.xml.

Property ovsx.caching.sitemap.max-size
Type long
Default 1
Compatibility Since 0.29.0

Cache for sitemap. Does not apply to Redis cache manager.

Property ovsx.caching.malicious-extensions.ttl
Type ISO 8601 duration
Default P3D
Compatibility Since 0.28.0

Time to live for caching malicious extension identifiers. The malicious extension identifiers can be updated every day by a recurring job or fetched on demand. The default duration is 3 days to make sure the cached identifiers don't expire in between job runs.

Property ovsx.caching.malicious-extensions.max-size
Type long
Default 1
Compatibility Since 0.29.0

Cache for malicious extensions. Does not apply to Redis cache manager.

Property ovsx.caching.rate-limiting.name
Type string
Default buckets
Compatibility Since 0.29.0

Cache name used for rate-limiting. Does not apply to Redis cache manager.

Property ovsx.caching.rate-limiting.tti
Type ISO 8601 duration
Default PT1H
Compatibility Since 0.29.0

Rate-limiting time to idle duration. Does not apply to Redis cache manager.

Property ovsx.caching.rate-limiting.max-size
Type long
Default 1024
Compatibility Since 0.29.0

Maximum amount of rate-limiting entries to keep in cache. Does not apply to Redis cache manager.

Property ovsx.caching.setting.ttl
Type ISO 8601 duration
Default PT1M
Compatibility Since 1.0.0

Time to live duration for settings read from the database. A short one, because a setting changed in the admin dashboard should take effect promptly. Does not apply to Redis cache manager.

Property ovsx.caching.files-webresource.max-file-size
Type long
Default 10485760
Compatibility Since 1.2.0

Largest web resource file, in bytes, that is cached at all. A file above this is served without being cached, so that one very large resource cannot evict everything else. Does not apply to Redis cache manager.

Property ovsx.caching.files-webresource.max-total-size
Type long
Default 2147483648
Compatibility Since 1.2.0

Total size, in bytes, of the cached web resource files. Each entry weighs its file size rather than counting as one, so this bounds the disk the cache occupies rather than the number of files in it. Does not apply to Redis cache manager.

Publisher Agreement

Requires publishers to sign an agreement before they can publish. Disabled by default. Each signing, revocation and reinstatement is recorded with the agreement version, whichever provider keeps the agreement. Which signatures stay valid is set by the allowed versions: without any, a signature of the configured major version or a higher one stays valid, so raising the major version makes everyone sign again; until they do, they cannot publish, but their extensions stay published. An admin revocation blocks the user from signing again until an admin reinstates them. A deployment that keeps the agreement elsewhere supplies its own PublisherAgreementProvider (a @Primary bean), which replaces the default one; which signed versions still count is decided from ovsx.publisher-agreement.version and ovsx.publisher-agreement.allowed-versions whichever provider is in use, and the rest, such as who may publish, the block after a revocation and the history, is the server's and stays.

Property ovsx.publisher-agreement.version
Type string
Default
Compatibility Since 1.4.0

The current version of the agreement, such as 1, 1.0 or 1.0.0: a semantic version whose minor and patch numbers may be left out. Empty disables agreements: everyone may publish. An invalid value stops the server from starting.

Property ovsx.publisher-agreement.allowed-versions
Type list of strings
Default
Compatibility Since 1.4.0

The versions a signature may have to count as signed, comma separated, such as 1.1,1.2; the version of ovsx.publisher-agreement.version is always one of them. A signature of any other version is outdated, whatever its major version, and its signer has to sign again before publishing. Versions are compared as semantic versions, so 1, 1.0 and 1.0.0 are the same. Empty accepts any signature of the same or a higher major version than the configured one. In YAML the list may be written as a YAML list, and a single version such as 1.10 has to be quoted, or it is read as the number 1.1. A signature whose version cannot be read counts as outdated. An invalid version in the list stops the server from starting.

Property ovsx.publisher-agreement.text
Type string
Default
Compatibility Since 1.4.0

Location of the agreement text, in Markdown, as any Spring resource location such as classpath:agreement.md or file:/etc/openvsx/agreement.md. It is served at /api/publisher-agreement, which the web UI shows by default; the response may be cached for five minutes, so a changed text can take that long to show.

Property ovsx.publisher-agreement.check-compliance-on-start
Type boolean
Default false
Compatibility Since 1.4.0

Whether to check publishers on startup and deactivate the extension versions of those without an agreement. The agreement provider decides who has one: with the default provider a publisher who never signed or was revoked is not compliant, while an outdated signature still is, as it only keeps them from publishing. A publisher whose status cannot be determined, for instance because a remote service is unreachable, is left alone. Has no effect while agreements are disabled.

Trusted Publishing

Publishing with a short-lived token proved by an OIDC ID token from a CI provider, rather than with a long-lived personal access token. Disabled by default.

Property ovsx.trusted-publishing.enabled
Type boolean
Default false
Compatibility Since 1.2.0

Whether trusted publishing is enabled at all.

Property ovsx.trusted-publishing.active-providers
Type string[]
Default github
Compatibility Since 1.2.0

The providers that may be used, comma separated. Each id must be github or one of the configured GitLab instances.

Property ovsx.trusted-publishing.gitlab
Type map
Default
Compatibility Since 1.2.0

The GitLab instances, keyed by provider id, each with a name, a URL and an OIDC issuer. The public instance is configured out of the box; any other one is added here and becomes usable once its id is listed in active-providers. Configuring the id of the default instance replaces it whole rather than patching single fields, so such an entry carries the name and URL itself.

Property ovsx.trusted-publishing.audience
Type string
Default ${ovsx.webui.url}
Compatibility Since 1.2.0

The audience to expect in the OIDC ID token. Defaults to the web UI URL of this instance.

Property ovsx.trusted-publishing.token-expiration
Type ISO 8601 duration
Default PT5M
Compatibility Since 1.2.0

How long an issued publishing token is valid. Must be positive: a token that never expires is the long-lived credential trusted publishing exists to avoid. Ordinary personal access tokens use ovsx.access-token.expiration instead.

Property ovsx.trusted-publishing.forbidden-jwt-headers
Type string[]
Default x5u,x5c,jku,jwk
Compatibility Since 1.2.0

JWT headers rejected in an ID token, comma separated. Each of these points at a key the token itself supplies, which would let a token vouch for its own signature.

Personal Access Token

Property ovsx.token-prefix
Type string
Default
Compatibility Since 0.28.0
Deprecated Since 0.33.0

Add a prefix to a personal access token to make it identifiable for improved security tooling support.

Property ovsx.access-token.prefix
Type string
Default
Compatibility Since 0.33.0

Add a prefix to a personal access token to make it identifiable for improved security tooling support. Replaces ovsx.token-prefix.

Property ovsx.access-token.expiration
Type ISO 8601 duration
Default P90D, 90 days
Compatibility Since 0.33.0

The duration of time a newly created access token is going to be valid. A value of 0 disables expiry of access tokens.

Property ovsx.access-token.notification
Type ISO 8601 duration
Default P7D, 7 days
Compatibility Since 0.33.0

The duration of time before the expiration of a token to send a notification email to the user. A value of 0 disables sending a notification.

Property ovsx.access-token.max-token-notifications
Type string
Default 100
Compatibility Since 0.33.0

The number of token expiry notification emails to be sent out during one execution of the respective job.

Property ovsx.access-token.send-expired-mail
Type boolean
Default false
Compatibility Since 0.33.0

Whether an email shall be sent to the user if a token has expired.

Property ovsx.access-token.expiration-schedule
Type string
Default every 15 min
Compatibility Since 0.33.0

The cron schedule of the job to expire access tokens.

Property ovsx.access-token.notification-schedule
Type string
Default every 15 min
Compatibility Since 0.33.0

The cron schedule of the job to notify about expiring access tokens.

Property ovsx.access-token.token-hash-algorithm
Type string
Default SHA-256
Compatibility Since 1.2.0

The hash algorithm personal access tokens are stored under.

Property ovsx.access-token.token-hash-pepper
Type string
Default
Compatibility Since 1.2.0

A secret mixed into the token hash, so that a leaked personal_access_token.value column is useless on its own. It is a secret, not a salt - the token values are 256 random bits each - so keep it out of anywhere a non-secret would go, and generate it with something like openssl rand -base64 32. The same pepper covers every token, so changing it invalidates all of them at once unless the old one is kept in token-hash-previous-peppers. Empty by default, which mixes in nothing and is not recommended in production.

Property ovsx.access-token.token-hash-previous-peppers
Type string[]
Default
Compatibility Since 1.2.0

Peppers to fall back to, in order, when a token does not match under the current one, so that rotating a pepper does not invalidate every existing token. A token migrates to the current pepper as it is used; when to drop an old one is the operator's call, since a token that is never used never migrates. Comma separated, so a pepper must not contain a comma.

Property ovsx.access-token.token-hash-accept-unpeppered
Type boolean
Default false
Compatibility Since 1.2.0

Whether a token hashed without any pepper is still accepted. This is what lets a pepper be introduced for the first time without invalidating every existing token; it is the unpeppered member of token-hash-previous-peppers, kept separate because an empty entry in a comma separated list cannot be written unambiguously.

Email

The Open VSX server uses Spring mail to send emails. See the common application properties documentation to configure email.

Property ovsx.mail.from
Type string
Default
Compatibility Since 0.30.0

Email address of the mail sender set in the email From header.

Property ovsx.mail.revoked-access-tokens.subject
Type string
Default Open VSX Access Tokens Revoked
Compatibility Since 0.30.0

The Subject header for the revoked access tokens email. This email is sent to a user when an admin has revoked the user's personal access tokens.

Property ovsx.mail.revoked-access-tokens.template
Type string
Default revoked-access-tokens.html
Compatibility Since 0.30.0

Name of the Thymeleaf template to use for the revoked access tokens email. Templates should be put into the mail-templates classpath directory.

Property ovsx.mail.access-token-expiry.subject
Type string
Default Open VSX Access Token Expiry Notification
Compatibility Since 0.33.0

The Subject header for the access token expiry notification email. This email is sent to a user when an access token is going to expire soon.

Property ovsx.mail.access-token-expiry.template
Type string
Default access-token-expiry-notification.html
Compatibility Since 0.33.0

Name of the Thymeleaf template to use for the access token expiry notification email. Templates should be put into the mail-templates classpath directory.

Property ovsx.mail.access-token-expired.subject
Type string
Default Open VSX Access Token Expired
Compatibility Since 0.33.0

The Subject header for the access token expired email. This email is sent to a user when an access token has expired.

Property ovsx.mail.access-token-expired.template
Type string
Default access-token-expired.html
Compatibility Since 0.33.0

Name of the Thymeleaf template to use for the access token expired email. Templates should be put into the mail-templates classpath directory.

Download Analytics

Download analytics keeps its time-series data in a separate database from the registry, migrated on its own and requiring the TimescaleDB extension. Disabled by default; when disabled, none of its beans are created and the registry database is untouched.

Property ovsx.analytics.enabled
Type boolean
Default false
Compatibility Since 1.3.0

Whether to enable download analytics. When false, the time-series datasource, its migrations and its jOOQ context are not created at all, and none of the settings below are read.

Property ovsx.analytics.ingestion.max-decompressed-bytes
Type long
Default 536870912
Compatibility Since 1.3.0

The decompressed-size cap applied while parsing an access-log stream, whether read from the scheduled AWS source or uploaded to the admin backfill endpoint. A highly-compressible gzip file could otherwise grow the in-memory record list without bound; exceeding the limit fails the parse.

Property ovsx.analytics.settled-cache.ttl
Type ISO 8601 duration
Default PT1H
Compatibility Since 1.3.0

How long the settled part of a download series is held in memory before being read again. Settled ranges are older than ovsx.analytics.settling-margin and so do not normally change, which is what makes caching them safe.

Nothing invalidates this cache. A backfill, a replayed log file or a manual refresh of the time-series aggregate therefore stays invisible for up to this long, on the node that cached it — the data is right in the database and stale in the response. Set it to PT0S to bypass the cache entirely, which is what a development setup wants and what the bundled dev configuration does. Zero is the smallest value it accepts: a negative duration is rejected at startup.

It is a per-node, in-memory cache, so in a cluster each node expires on its own schedule.

Property ovsx.analytics.settling-margin
Type ISO 8601 duration
Default PT2H
Compatibility Since 1.3.0

How far back from now a download series is treated as settled. Buckets older than this are answered from a cached query and buckets newer than it are read live, so the margin is the point at which the series stops being re-read on every request.

It exists because the time-series aggregate is materialized on a delay: its refresh policy leaves the most recent hour unmaterialized, and the margin keeps the series from settling on a bucket that has not caught up yet. Raising it holds more of the recent range on the live path; lowering it settles sooner. It must not be negative, which would place the boundary in the future, and startup fails if it is.

Note that the buckets on either side of the boundary carry the same counts — the margin decides how a range is read, not what it contains.

Property ovsx.analytics.availability.probe-interval
Type ISO 8601 duration
Default PT30S
Compatibility Since 1.3.0

How often the time-series database is probed. Analytics is optional: while the database is unreachable the registry keeps serving, the analytics endpoint answers 503 with a Retry-After header, and analytics writes are skipped without waiting on a connection timeout. A probe is also what notices that the database is back, so probing cannot be switched off. Must be at least PT1S; startup fails otherwise.

The server starts without the time-series database being reachable. Its schema is migrated on the first successful probe, and analytics stays unavailable until then. A failure that is not a connectivity problem, such as a migration the database rejects, still fails startup.

Property ovsx.analytics.availability.failure-threshold
Type int
Default 3
Compatibility Since 1.3.0

How many analytics calls in a row may fail to reach the time-series database before it is treated as unavailable without waiting for the next probe. Only connectivity failures count. Must be at least 1.

Property ovsx.analytics.datasource.url
Type string
Default
Compatibility Since 1.3.0

JDBC URL of the time-series database, e.g. jdbc:postgresql://localhost:5433/openvsx_timeseries. Required when analytics are enabled: startup fails if it is not set, because reaching that point means analytics were asked for and a missing URL is a mistake rather than a way to opt out. It must not point at the registry database, whose schema is migrated separately and does not need the timescaledb extension.

Property ovsx.analytics.datasource.username
Type string
Default
Compatibility Since 1.3.0

User name for the time-series database. Optional: when unset, nothing is passed to the pool and the driver resolves it its own way, from a URL parameter, .pgpass or IAM.

Property ovsx.analytics.datasource.password
Type string
Default
Compatibility Since 1.3.0

Password for the time-series database. Optional, on the same terms as the user name above.

Property ovsx.analytics.datasource.maximum-pool-size
Type int
Default 5
Compatibility Since 1.3.0

Maximum size of the time-series connection pool. Must be at least 1. Enabling analytics gives a deployment a second pool, so size this against the time-series server's max_connections together with the registry pool rather than in isolation.

Property ovsx.analytics.datasource.connection-timeout
Type long
Default 2000
Compatibility Since 1.3.0

How long to wait for a connection from the time-series pool, in milliseconds. Deliberately far below Hikari's own 30 seconds, so that an unreachable time-series database fails fast enough for the caller to give up rather than holding a thread; once it is judged unavailable (see ovsx.analytics.availability.probe-interval) calls do not wait at all. Must be greater than 250ms — the validation timeout is derived at half this value with a 250ms floor, and Hikari rejects a validation timeout that is not below the connection timeout.