Socket
Socket
Sign inDemoInstall

@ampproject/toolbox-runtime-version

Package Overview
Dependencies
Maintainers
7
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ampproject/toolbox-runtime-version - npm Package Compare versions

Comparing version 2.2.0 to 2.3.0

223

lib/RuntimeVersion.js

@@ -22,29 +22,48 @@ /**

const RUNTIME_METADATA_PATH = '/rtv/metadata';
const VERSION_TXT_PATH = '/version.txt';
/**
* Queries https://cdn.ampproject.org/rtv/metadata for the latest AMP runtime version. Uses a
* @typedef {number} ReleaseType
*/
/**
* Release type "enumeration"
*
* @enum {ReleaseType}
*/
const ReleaseType = {
canary: 0,
prod: 1,
lts: 2,
};
/**
* Queries <host>/rtv/metadata for the latest AMP runtime version. If version is not available from
* this endpoint, falls back to <host>/version.txt and manually prepends config code. Uses a
* stale-while-revalidate caching strategy to avoid refreshing the version.
*
* More details: https://cdn.ampproject.org/rtv/metadata returns the following metadata:
* /rtv/metadata endpoint details:
*
* <pre>
* {
* "ampRuntimeVersion": "CURRENT_PROD",
* "ampCssUrl": "https://cdn.ampproject.org/rtv/CURRENT_PROD/v0.css",
* "canaryPercentage": "0.1",
* "diversions": [
* "CURRENT_OPTIN",
* "CURRENT_1%",
* "CURRENT_CONTROL"
* ]
* }
* </pre>
* "ampRuntimeVersion": "CURRENT_PROD",
* "ampCssUrl": "https://cdn.ampproject.org/rtv/CURRENT_PROD/v0.css",
* "canaryPercentage": "0.1",
* "diversions": [
* "CURRENT_OPTIN",
* "CURRENT_1%",
* "CURRENT_CONTROL"
* ],
* "ltsRuntimeVersion": "CURRENT_LTS",
* "ltsCssUrl": "https://cdn.ampproject.org/rtv/CURRENT_LTS/v0.css"
* }
* </pre>
*
* where:
* where:
*
* <ul>
* <li> CURRENT_OPTIN: is when you go to https://cdn.ampproject.org/experiments.html and toggle "dev-channel". It's the earliest possible time to get new code.</li>
* <li> CURRENT_1%: 1% is the same code as opt-in that we're now comfortable releasing to 1% of the population.</li>
* <li> CURRENT_CONTROL is the same thing as production, but with a different URL. This is to compare experiments against, since prod's immutable caching would affect metrics.</li>
* </ul>
* <ul>
* <li> CURRENT_OPTIN: is when you go to https://cdn.ampproject.org/experiments.html and toggle "dev-channel". It's the earliest possible time to get new code.</li>
* <li> CURRENT_1%: 1% is the same code as opt-in that we're now comfortable releasing to 1% of the population.</li>
* <li> CURRENT_CONTROL is the same thing as production, but with a different URL. This is to compare experiments against, since prod's immutable caching would affect metrics.</li>
* </ul>
*/

@@ -60,4 +79,4 @@ class RuntimeVersion {

*
* @param {Object} options - the options.
* @param {bool} options.canary - true if canary should be returned.
* @param {object} options - the options.
* @param {boolean} options.canary - true if canary should be returned.
* @param {string} options.ampUrlPrefix - the domain & path to an AMP runtime.

@@ -67,39 +86,149 @@ * @returns {Promise<string>} a promise containing the current version.

async currentVersion(options = {}) {
let runtimeMetaUrl = AMP_CACHE_HOST + RUNTIME_METADATA_PATH;
if (options.ampUrlPrefix) {
const customMetaUrl = options.ampUrlPrefix.replace(/\/$/, '') + RUNTIME_METADATA_PATH;
// Check whether ampUrlPrefix is absolute since relative paths are allowed
// by optimizer
if (this.isAbsoluteUrl_(customMetaUrl)) {
runtimeMetaUrl = customMetaUrl;
} else {
log.warn(
'ampUrlPrefix is not an absolute URL. Falling back to https://cdn.ampproject.org.'
);
}
if (options.ampUrlPrefix && !this.isAbsoluteUrl_(options.ampUrlPrefix)) {
throw new Error('host must be an absolute URL');
}
const response = await this.fetch_(runtimeMetaUrl);
const data = await response.json();
let version;
if (options.canary && options.lts) {
throw new Error('lts flag is not compatible with canary flag');
}
let releaseType = ReleaseType.prod;
if (options.canary) {
version = data.diversions[0];
log.debug('canary version', version);
} else {
version = data.ampRuntimeVersion;
log.debug('prod version', version);
releaseType = ReleaseType.canary;
} else if (options.lts) {
releaseType = ReleaseType.lts;
}
return this.padVersionString_(version);
const host = options.ampUrlPrefix ? options.ampUrlPrefix.replace(/\/$/, '') : AMP_CACHE_HOST;
let rtv = await this.getVersionFromRuntimeMetadata_(host, releaseType);
if (!rtv && releaseType === ReleaseType.prod) {
rtv = await this.getVersionFromVersionTxt_(host, releaseType);
}
return rtv;
}
/* PRIVATE */
padVersionString_(version) {
return this.pad_(version, 15, 0);
/**
* Get runtime version from <host>/rtv/metadata
*
* @param {string} host - runtime host.
* @param {ReleaseType} releaseType - release type.
* @returns {Promise<string>} a promise containing the runtime version.
*/
async getVersionFromRuntimeMetadata_(host, releaseType) {
const runtimeMetaUrl = host + RUNTIME_METADATA_PATH;
log.debug(`Fetching version from ${runtimeMetaUrl}`);
let response;
try {
response = await this.fetch_(runtimeMetaUrl);
} catch (ex) {
// Avoid exception to give fallback mechanism getVersionFromVersionTxt_()
// a chance to lookup version, and to gracefully return 'undefined' if no
// version is ultimately found.
}
if (!response || !response.ok) {
log.debug('RTV metadata endpoint did not respond with a successful status code');
return;
}
let data;
try {
data = await response.json();
} catch (ex) {
log.debug('RTV metadata JSON malformed');
return;
}
let rtv;
if (releaseType === ReleaseType.canary) {
if (
Array.isArray(data.diversions) &&
data.diversions[0] &&
data.diversions[0].startsWith(this.getRtvConfigCode_(releaseType))
) {
rtv = data.diversions[0];
}
if (!rtv) {
log.debug('RTV metadata JSON malformed, canary version not in diversions array');
}
} else if (releaseType === ReleaseType.lts) {
rtv = data.ltsRuntimeVersion;
if (!rtv) {
log.debug('RTV metadata JSON malformed, lts version not in ltsRuntimeVersion');
}
} else if (releaseType === ReleaseType.prod) {
rtv = data.ampRuntimeVersion;
if (!rtv) {
log.debug('RTV metadata JSON malformed, production version not in ampRuntimeVersion');
}
}
return rtv;
}
pad_(n, width, z) {
z = z || '0';
n = String(n);
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
/**
* Get runtime version from <host>/version.txt, manually prepending
* production release code '01'. This method cannot be used to detect
* canary or lts releases.
*
* @param {string} host - runtime host.
* @param {ReleaseType} releaseType - release type.
* @returns {Promise<string>} a promise containing the runtime version.
*/
async getVersionFromVersionTxt_(host, releaseType) {
if (releaseType !== ReleaseType.prod) {
log.debug(`version.txt lookup only supported for prod releases`);
return;
}
let versionTxtUrl = host + VERSION_TXT_PATH;
log.debug(`Falling back to ${versionTxtUrl}`);
let response;
try {
response = await this.fetch_(versionTxtUrl);
} catch (ex) {
// Prefer gracefully returning 'undefined' version to throwing.
}
if (!response || !response.ok) {
log.debug('version.txt endpoint did not respond with a successful status code');
return;
}
let version;
try {
version = (await response.text()).trim();
if (version !== encodeURIComponent(version)) {
throw new Error();
}
} catch (ex) {
log.debug('Version string malformed, not URL compatible');
return;
}
return this.getRtvConfigCode_(releaseType) + version;
}
/**
* Get config code corresponding to release type
*
* @param {ReleaseType} releaseType - release type.
* @returns {string}
*/
getRtvConfigCode_(releaseType) {
if (releaseType === ReleaseType.canary) {
return '00';
}
return '01';
}
/**
* Determine whether a URL is absolute.
*
* @param {string} url - URL to test.
* @returns {boolean}
*/
isAbsoluteUrl_(url) {

@@ -106,0 +235,0 @@ try {

{
"name": "@ampproject/toolbox-runtime-version",
"version": "2.2.0",
"version": "2.3.0",
"description": "AMP Runtime versions",

@@ -21,3 +21,3 @@ "main": "index.js",

"dependencies": {
"@ampproject/toolbox-core": "^2.2.0"
"@ampproject/toolbox-core": "^2.3.0"
},

@@ -28,3 +28,3 @@ "bugs": {

"homepage": "https://github.com/ampproject/amp-toolbox/tree/master/packages/runtime-version",
"gitHead": "e2bea7ac7d4cb6a57d196e124ee8a5f818123a02"
"gitHead": "bb7eaa6c720044e84f01c6406f5f0805dc637923"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc