diff --git a/dist/setup/index.js b/dist/setup/index.js
index 522ca2a3..b78ec288 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -73180,6 +73180,727 @@ var Outputs;
 })(Outputs = exports.Outputs || (exports.Outputs = {}));
 
 
+/***/ }),
+
+/***/ 8653:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
+    result["default"] = mod;
+    return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+const tc = __importStar(__nccwpck_require__(7784));
+const hc = __importStar(__nccwpck_require__(9925));
+const core = __importStar(__nccwpck_require__(2186));
+const io = __importStar(__nccwpck_require__(7436));
+const semver_1 = __importDefault(__nccwpck_require__(5911));
+const assert = __importStar(__nccwpck_require__(9491));
+const path = __importStar(__nccwpck_require__(1017));
+const os = __importStar(__nccwpck_require__(2037));
+const fs_1 = __importDefault(__nccwpck_require__(7147));
+class BaseDistribution {
+    constructor(nodeInfo) {
+        this.nodeInfo = nodeInfo;
+        this.osPlat = os.platform();
+        this.httpClient = new hc.HttpClient('setup-node', [], {
+            allowRetries: true,
+            maxRetries: 3
+        });
+    }
+    getNodeJsInfo() {
+        return __awaiter(this, void 0, void 0, function* () {
+            let toolPath = this.findVersionInHoostedToolCacheDirectory();
+            if (!toolPath) {
+                const versions = yield this.getNodejsVersions();
+                const evaluatedVersion = this.evaluateVersions(versions);
+                const toolName = this.getNodejsDistInfo(evaluatedVersion, this.osPlat);
+                toolPath = yield this.downloadNodejs(toolName);
+            }
+            core.addPath(toolPath);
+        });
+    }
+    findVersionInHoostedToolCacheDirectory() {
+        return tc.find('node', this.nodeInfo.versionSpec, this.nodeInfo.arch);
+    }
+    getNodejsDistInfo(version, osPlat) {
+        let osArch = this.translateArchToDistUrl(this.nodeInfo.arch);
+        version = semver_1.default.clean(version) || '';
+        let fileName = osPlat == 'win32'
+            ? `node-v${version}-win-${osArch}`
+            : `node-v${version}-${osPlat}-${osArch}`;
+        let urlFileName = osPlat == 'win32' ? `${fileName}.7z` : `${fileName}.tar.gz`;
+        const initialUrl = this.getDistributionUrl();
+        const url = `${initialUrl}/v${version}/${urlFileName}`;
+        return {
+            downloadUrl: url,
+            resolvedVersion: version,
+            arch: osArch,
+            fileName: fileName
+        };
+    }
+    downloadNodejs(info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let osPlat = os.platform();
+            let downloadPath = '';
+            try {
+                downloadPath = yield tc.downloadTool(info.downloadUrl);
+            }
+            catch (err) {
+                if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
+                    return yield this.acquireNodeFromFallbackLocation(info.resolvedVersion, info.arch);
+                }
+                throw err;
+            }
+            let toolPath = yield this.extractArchive(downloadPath, info);
+            core.info('Done');
+            if (osPlat != 'win32') {
+                toolPath = path.join(toolPath, 'bin');
+            }
+            return toolPath;
+        });
+    }
+    acquireNodeFromFallbackLocation(version, arch = os.arch()) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const initialUrl = this.getDistributionUrl();
+            let osArch = this.translateArchToDistUrl(arch);
+            // Create temporary folder to download in to
+            const tempDownloadFolder = 'temp_' + Math.floor(Math.random() * 2000000000);
+            const tempDirectory = process.env['RUNNER_TEMP'] || '';
+            assert.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined');
+            const tempDir = path.join(tempDirectory, tempDownloadFolder);
+            yield io.mkdirP(tempDir);
+            let exeUrl;
+            let libUrl;
+            try {
+                exeUrl = `${initialUrl}/v${version}/win-${osArch}/node.exe`;
+                libUrl = `${initialUrl}/v${version}/win-${osArch}/node.lib`;
+                core.info(`Downloading only node binary from ${exeUrl}`);
+                const exePath = yield tc.downloadTool(exeUrl);
+                yield io.cp(exePath, path.join(tempDir, 'node.exe'));
+                const libPath = yield tc.downloadTool(libUrl);
+                yield io.cp(libPath, path.join(tempDir, 'node.lib'));
+            }
+            catch (err) {
+                if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
+                    exeUrl = `${initialUrl}/v${version}/node.exe`;
+                    libUrl = `${initialUrl}/v${version}/node.lib`;
+                    const exePath = yield tc.downloadTool(exeUrl);
+                    yield io.cp(exePath, path.join(tempDir, 'node.exe'));
+                    const libPath = yield tc.downloadTool(libUrl);
+                    yield io.cp(libPath, path.join(tempDir, 'node.lib'));
+                }
+                else {
+                    throw err;
+                }
+            }
+            const toolPath = yield tc.cacheDir(tempDir, 'node', version, arch);
+            return toolPath;
+        });
+    }
+    extractArchive(downloadPath, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //
+            // Extract
+            //
+            core.info('Extracting ...');
+            let extPath;
+            info = info || {}; // satisfy compiler, never null when reaches here
+            if (this.osPlat == 'win32') {
+                let _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe');
+                extPath = yield tc.extract7z(downloadPath, undefined, _7zPath);
+                // 7z extracts to folder matching file name
+                let nestedPath = path.join(extPath, path.basename(info.fileName, '.7z'));
+                if (fs_1.default.existsSync(nestedPath)) {
+                    extPath = nestedPath;
+                }
+            }
+            else {
+                extPath = yield tc.extractTar(downloadPath, undefined, [
+                    'xz',
+                    '--strip',
+                    '1'
+                ]);
+            }
+            //
+            // Install into the local tool cache - node extracts with a root folder that matches the fileName downloaded
+            //
+            core.info('Adding to the cache ...');
+            const toolPath = yield tc.cacheDir(extPath, 'node', info.resolvedVersion, info.arch);
+            return toolPath;
+        });
+    }
+    getDistFileName(arch = os.arch()) {
+        let osPlat = os.platform();
+        let osArch = this.translateArchToDistUrl(arch);
+        // node offers a json list of versions
+        let dataFileName;
+        switch (osPlat) {
+            case 'linux':
+                dataFileName = `linux-${osArch}`;
+                break;
+            case 'darwin':
+                dataFileName = `osx-${osArch}-tar`;
+                break;
+            case 'win32':
+                dataFileName = `win-${osArch}-exe`;
+                break;
+            default:
+                throw new Error(`Unexpected OS '${osPlat}'`);
+        }
+        return dataFileName;
+    }
+    filterVersions(nodeVersions) {
+        let versions = [];
+        const dataFileName = this.getDistFileName(this.nodeInfo.arch);
+        nodeVersions.forEach((nodeVersion) => {
+            // ensure this version supports your os and platform
+            if (nodeVersion.files.indexOf(dataFileName) >= 0) {
+                versions.push(nodeVersion.version);
+            }
+        });
+        return versions.sort(semver_1.default.rcompare);
+    }
+    translateArchToDistUrl(arch) {
+        switch (arch) {
+            case 'arm':
+                return 'armv7l';
+            default:
+                return arch;
+        }
+    }
+}
+exports["default"] = BaseDistribution;
+
+
+/***/ }),
+
+/***/ 1260:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+const nightly_builds_1 = __importDefault(__nccwpck_require__(1002));
+const official_builds_1 = __importDefault(__nccwpck_require__(9856));
+const rc_builds_1 = __importDefault(__nccwpck_require__(6235));
+const canary_builds_1 = __importDefault(__nccwpck_require__(4833));
+var Distributions;
+(function (Distributions) {
+    Distributions["DEFAULT"] = "";
+    Distributions["CANARY"] = "v8-canary";
+    Distributions["NIGHTLY"] = "nightly";
+    Distributions["RC"] = "rc";
+})(Distributions || (Distributions = {}));
+function identifyDistribution(versionSpec) {
+    let distribution = '';
+    if (versionSpec.includes(Distributions.NIGHTLY)) {
+        distribution = Distributions.NIGHTLY;
+    }
+    else if (versionSpec.includes(Distributions.CANARY)) {
+        distribution = Distributions.CANARY;
+    }
+    else if (versionSpec.includes(Distributions.RC)) {
+        distribution = Distributions.RC;
+    }
+    else {
+        distribution = Distributions.DEFAULT;
+    }
+    return distribution;
+}
+function getNodejsDistribution(installerOptions) {
+    const distributionName = identifyDistribution(installerOptions.versionSpec);
+    switch (distributionName) {
+        case Distributions.NIGHTLY:
+            return new nightly_builds_1.default(installerOptions);
+        case Distributions.CANARY:
+            return new canary_builds_1.default(installerOptions);
+        case Distributions.RC:
+            return new rc_builds_1.default(installerOptions);
+        case Distributions.DEFAULT:
+            return new official_builds_1.default(installerOptions);
+        default:
+            return null;
+    }
+}
+exports.getNodejsDistribution = getNodejsDistribution;
+
+
+/***/ }),
+
+/***/ 1002:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
+    result["default"] = mod;
+    return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+const core = __importStar(__nccwpck_require__(2186));
+const semver_1 = __importDefault(__nccwpck_require__(5911));
+const base_distribution_1 = __importDefault(__nccwpck_require__(8653));
+class NightlyNodejs extends base_distribution_1.default {
+    constructor(nodeInfo) {
+        super(nodeInfo);
+    }
+    evaluateVersions(nodeVersions) {
+        let version = '';
+        const versions = this.filterVersions(nodeVersions);
+        core.debug(`evaluating ${versions.length} versions`);
+        const { includePrerelease, range } = this.createRangePreRelease(this.nodeInfo.versionSpec, '-nightly');
+        for (let i = versions.length - 1; i >= 0; i--) {
+            const potential = versions[i];
+            const satisfied = semver_1.default.satisfies(potential, range, {
+                includePrerelease: includePrerelease
+            });
+            if (satisfied) {
+                version = potential;
+                break;
+            }
+        }
+        if (version) {
+            core.debug(`matched: ${version}`);
+        }
+        else {
+            core.debug('match not found');
+        }
+        return version;
+    }
+    getDistributionUrl() {
+        return 'https://nodejs.org/download/nightly';
+    }
+    getNodejsVersions() {
+        return __awaiter(this, void 0, void 0, function* () {
+            const initialUrl = this.getDistributionUrl();
+            const dataUrl = `${initialUrl}/index.json`;
+            let response = yield this.httpClient.getJson(dataUrl);
+            return response.result || [];
+        });
+    }
+    createRangePreRelease(versionSpec, distribution = '') {
+        let range;
+        const [raw, prerelease] = this.splitVersionSpec(versionSpec);
+        const isValidVersion = semver_1.default.valid(raw);
+        const rawVersion = (isValidVersion ? raw : semver_1.default.coerce(raw));
+        if (`-${prerelease}` !== distribution) {
+            range = `${rawVersion}${`-${prerelease}`.replace(distribution, `${distribution}.`)}`;
+        }
+        else {
+            range = `${semver_1.default.validRange(`^${rawVersion}${distribution}`)}-0`;
+        }
+        return { range, includePrerelease: !isValidVersion };
+    }
+    splitVersionSpec(versionSpec) {
+        return versionSpec.split(/-(.*)/s);
+    }
+}
+exports["default"] = NightlyNodejs;
+
+
+/***/ }),
+
+/***/ 9856:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
+    result["default"] = mod;
+    return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+const core = __importStar(__nccwpck_require__(2186));
+const tc = __importStar(__nccwpck_require__(7784));
+const semver = __importStar(__nccwpck_require__(5911));
+const os_1 = __importDefault(__nccwpck_require__(2037));
+const base_distribution_1 = __importDefault(__nccwpck_require__(8653));
+class OfficialBuilds extends base_distribution_1.default {
+    constructor(nodeInfo) {
+        super(nodeInfo);
+    }
+    queryDistForMatch(versionSpec, arch = os_1.default.arch(), nodeVersions) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let osPlat = os_1.default.platform();
+            let osArch = this.translateArchToDistUrl(arch);
+            // node offers a json list of versions
+            let dataFileName;
+            switch (osPlat) {
+                case 'linux':
+                    dataFileName = `linux-${osArch}`;
+                    break;
+                case 'darwin':
+                    dataFileName = `osx-${osArch}-tar`;
+                    break;
+                case 'win32':
+                    dataFileName = `win-${osArch}-exe`;
+                    break;
+                default:
+                    throw new Error(`Unexpected OS '${osPlat}'`);
+            }
+            if (this.isLatestSyntax(versionSpec)) {
+                core.info(`getting latest node version...`);
+                return nodeVersions[0].version;
+            }
+            const versions = [];
+            nodeVersions.forEach((nodeVersion) => {
+                // ensure this version supports your os and platform
+                if (nodeVersion.files.indexOf(dataFileName) >= 0) {
+                    versions.push(nodeVersion.version);
+                }
+            });
+            // get the latest version that matches the version spec
+            const version = this.evaluateVersions(nodeVersions);
+            return version;
+        });
+    }
+    getNodeJsInfo() {
+        return __awaiter(this, void 0, void 0, function* () {
+            let manifest = [];
+            let nodeVersions = [];
+            if (this.isLtsAlias(this.nodeInfo.versionSpec)) {
+                core.info('Attempt to resolve LTS alias from manifest...');
+                // No try-catch since it's not possible to resolve LTS alias without manifest
+                manifest = yield this.getManifest();
+                this.nodeInfo.versionSpec = this.resolveLtsAliasFromManifest(this.nodeInfo.versionSpec, true, manifest);
+            }
+            if (this.isLatestSyntax(this.nodeInfo.versionSpec)) {
+                nodeVersions = yield this.getNodejsVersions();
+                this.nodeInfo.versionSpec = yield this.queryDistForMatch(this.nodeInfo.versionSpec, this.nodeInfo.arch, nodeVersions);
+                core.info(`getting latest node version...`);
+            }
+            let toolPath = this.findVersionInHoostedToolCacheDirectory();
+            if (!toolPath) {
+                try {
+                    const versionInfo = yield this.getInfoFromManifest(this.nodeInfo.versionSpec, true, this.nodeInfo.auth, this.nodeInfo.arch, undefined);
+                    if (versionInfo) {
+                        core.info(`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`);
+                        toolPath = yield tc.downloadTool(versionInfo.downloadUrl, undefined, this.nodeInfo.auth);
+                    }
+                    else {
+                        core.info('Not found in manifest.  Falling back to download directly from Node');
+                    }
+                }
+                catch (err) {
+                    // Rate limit?
+                    if (err instanceof tc.HTTPError &&
+                        (err.httpStatusCode === 403 || err.httpStatusCode === 429)) {
+                        core.info(`Received HTTP status code ${err.httpStatusCode}.  This usually indicates the rate limit has been exceeded`);
+                    }
+                    else {
+                        core.info(err.message);
+                    }
+                    core.debug(err.stack);
+                    core.info('Falling back to download directly from Node');
+                }
+                const versions = yield this.getNodejsVersions();
+                const evaluatedVersion = this.evaluateVersions(versions);
+                const toolName = this.getNodejsDistInfo(evaluatedVersion, this.osPlat);
+                toolPath = yield this.downloadNodejs(toolName);
+            }
+            core.addPath(toolPath);
+        });
+    }
+    evaluateVersions(nodeVersions) {
+        let version = '';
+        const versions = this.filterVersions(nodeVersions);
+        if (this.isLatestSyntax(this.nodeInfo.versionSpec)) {
+            core.info(`getting latest node version...`);
+            return versions[0];
+        }
+        core.debug(`evaluating ${versions.length} versions`);
+        for (let i = versions.length - 1; i >= 0; i--) {
+            const potential = versions[i];
+            const satisfied = semver.satisfies(potential, this.nodeInfo.versionSpec);
+            if (satisfied) {
+                version = potential;
+                break;
+            }
+        }
+        if (version) {
+            core.debug(`matched: ${version}`);
+        }
+        else {
+            core.debug('match not found');
+        }
+        return version;
+    }
+    getDistributionUrl() {
+        return `https://nodejs.org/dist`;
+    }
+    getNodejsVersions() {
+        return __awaiter(this, void 0, void 0, function* () {
+            const initialUrl = this.getDistributionUrl();
+            const dataUrl = `${initialUrl}/index.json`;
+            let response = yield this.httpClient.getJson(dataUrl);
+            return response.result || [];
+        });
+    }
+    getManifest() {
+        core.debug('Getting manifest from actions/node-versions@main');
+        return tc.getManifestFromRepo('actions', 'node-versions', this.nodeInfo.auth, 'main');
+    }
+    resolveLtsAliasFromManifest(versionSpec, stable, manifest) {
+        var _a;
+        const alias = (_a = versionSpec.split('lts/')[1]) === null || _a === void 0 ? void 0 : _a.toLowerCase();
+        if (!alias) {
+            throw new Error(`Unable to parse LTS alias for Node version '${versionSpec}'`);
+        }
+        core.debug(`LTS alias '${alias}' for Node version '${versionSpec}'`);
+        // Supported formats are `lts/<alias>`, `lts/*`, and `lts/-n`. Where asterisk means highest possible LTS and -n means the nth-highest.
+        const n = Number(alias);
+        const aliases = Object.fromEntries(manifest
+            .filter(x => x.lts && x.stable === stable)
+            .map(x => [x.lts.toLowerCase(), x])
+            .reverse());
+        const numbered = Object.values(aliases);
+        const release = alias === '*'
+            ? numbered[numbered.length - 1]
+            : n < 0
+                ? numbered[numbered.length - 1 + n]
+                : aliases[alias];
+        if (!release) {
+            throw new Error(`Unable to find LTS release '${alias}' for Node version '${versionSpec}'.`);
+        }
+        core.debug(`Found LTS release '${release.version}' for Node version '${versionSpec}'`);
+        return release.version.split('.')[0];
+    }
+    getInfoFromManifest(versionSpec, stable, auth, osArch = this.translateArchToDistUrl(os_1.default.arch()), manifest) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let info = null;
+            if (!manifest) {
+                core.debug('No manifest cached');
+                manifest = yield this.getManifest();
+            }
+            const rel = yield tc.findFromManifest(versionSpec, stable, manifest, osArch);
+            if (rel && rel.files.length > 0) {
+                info = {};
+                info.resolvedVersion = rel.version;
+                info.arch = rel.files[0].arch;
+                info.downloadUrl = rel.files[0].download_url;
+                info.fileName = rel.files[0].filename;
+            }
+            return info;
+        });
+    }
+    isLtsAlias(versionSpec) {
+        return versionSpec.startsWith('lts/');
+    }
+    isLatestSyntax(versionSpec) {
+        return ['current', 'latest', 'node'].includes(versionSpec);
+    }
+}
+exports["default"] = OfficialBuilds;
+
+
+/***/ }),
+
+/***/ 6235:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
+    result["default"] = mod;
+    return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+const core = __importStar(__nccwpck_require__(2186));
+const semver = __importStar(__nccwpck_require__(5911));
+const base_distribution_1 = __importDefault(__nccwpck_require__(8653));
+class RcBuild extends base_distribution_1.default {
+    constructor(nodeInfo) {
+        super(nodeInfo);
+    }
+    getNodejsVersions() {
+        return __awaiter(this, void 0, void 0, function* () {
+            const initialUrl = this.getDistributionUrl();
+            const dataUrl = `${initialUrl}/index.json`;
+            let response = yield this.httpClient.getJson(dataUrl);
+            return response.result || [];
+        });
+    }
+    evaluateVersions(nodeVersions) {
+        let version = '';
+        const versions = this.filterVersions(nodeVersions);
+        core.debug(`evaluating ${versions.length} versions`);
+        for (let i = versions.length - 1; i >= 0; i--) {
+            const potential = versions[i];
+            const satisfied = semver.satisfies(potential, this.nodeInfo.versionSpec);
+            if (satisfied) {
+                version = potential;
+                break;
+            }
+        }
+        if (version) {
+            core.debug(`matched: ${version}`);
+        }
+        else {
+            core.debug('match not found');
+        }
+        return version;
+    }
+    getDistributionUrl() {
+        return 'https://nodejs.org/download/rc';
+    }
+}
+exports["default"] = RcBuild;
+
+
+/***/ }),
+
+/***/ 4833:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
+    result["default"] = mod;
+    return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+const core = __importStar(__nccwpck_require__(2186));
+const semver_1 = __importDefault(__nccwpck_require__(5911));
+const base_distribution_1 = __importDefault(__nccwpck_require__(8653));
+class CanaryBuild extends base_distribution_1.default {
+    evaluateVersions(nodeVersions) {
+        let version = '';
+        const versions = this.filterVersions(nodeVersions);
+        core.debug(`evaluating ${versions.length} versions`);
+        const { includePrerelease, range } = this.createRangePreRelease(this.nodeInfo.versionSpec, '-v8-canary');
+        for (let i = versions.length - 1; i >= 0; i--) {
+            const potential = versions[i];
+            const satisfied = semver_1.default.satisfies(potential, range, {
+                includePrerelease: includePrerelease
+            });
+            if (satisfied) {
+                version = potential;
+                break;
+            }
+        }
+        if (version) {
+            core.debug(`matched: ${version}`);
+        }
+        else {
+            core.debug('match not found');
+        }
+        return version;
+    }
+    constructor(nodeInfo) {
+        super(nodeInfo);
+    }
+    getDistributionUrl() {
+        return 'https://nodejs.org/download/v8-canary';
+    }
+    getNodejsVersions() {
+        return __awaiter(this, void 0, void 0, function* () {
+            const initialUrl = this.getDistributionUrl();
+            const dataUrl = `${initialUrl}/index.json`;
+            let response = yield this.httpClient.getJson(dataUrl);
+            return response.result || [];
+        });
+    }
+    createRangePreRelease(versionSpec, distribution = '') {
+        let range;
+        const [raw, prerelease] = this.splitVersionSpec(versionSpec);
+        const isValidVersion = semver_1.default.valid(raw);
+        const rawVersion = (isValidVersion ? raw : semver_1.default.coerce(raw));
+        if (`-${prerelease}` !== distribution) {
+            range = `${rawVersion}${`-${prerelease}`.replace(distribution, `${distribution}.`)}`;
+        }
+        else {
+            range = `${semver_1.default.validRange(`^${rawVersion}${distribution}`)}-0`;
+        }
+        return { range, includePrerelease: !isValidVersion };
+    }
+    splitVersionSpec(versionSpec) {
+        return versionSpec.split(/-(.*)/s);
+    }
+}
+exports["default"] = CanaryBuild;
+
+
 /***/ }),
 
 /***/ 2574:
@@ -73724,6 +74445,7 @@ const path = __importStar(__nccwpck_require__(1017));
 const cache_restore_1 = __nccwpck_require__(9517);
 const cache_utils_1 = __nccwpck_require__(1678);
 const os_1 = __importDefault(__nccwpck_require__(2037));
+const installer_factory_1 = __nccwpck_require__(1260);
 function run() {
     return __awaiter(this, void 0, void 0, function* () {
         try {
@@ -73747,7 +74469,17 @@ function run() {
                 const auth = !token ? undefined : `token ${token}`;
                 const stable = (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
                 const checkLatest = (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
-                yield installer.getNode(version, stable, checkLatest, auth, arch);
+                const nodejsInfo = {
+                    versionSpec: version,
+                    checkLatest: checkLatest,
+                    auth,
+                    arch: arch
+                };
+                const nodeDistribution = installer_factory_1.getNodejsDistribution(nodejsInfo);
+                if (nodeDistribution) {
+                    yield (nodeDistribution === null || nodeDistribution === void 0 ? void 0 : nodeDistribution.getNodeJsInfo());
+                }
+                // await installer.getNode(version, stable, checkLatest, auth, arch);
             }
             yield printEnvDetailsAndSetOutput();
             const registryUrl = core.getInput('registry-url');
diff --git a/src/distibutions/base-distribution.ts b/src/distibutions/base-distribution.ts
new file mode 100644
index 00000000..f61e6831
--- /dev/null
+++ b/src/distibutions/base-distribution.ts
@@ -0,0 +1,221 @@
+import * as tc from '@actions/tool-cache';
+import * as hc from '@actions/http-client';
+import * as core from '@actions/core';
+import * as io from '@actions/io';
+
+import semver from 'semver';
+import * as assert from 'assert';
+
+import * as path from 'path';
+import * as os from 'os';
+import fs from 'fs';
+
+import {INodejs, INodeVersion, INodeVersionInfo} from './base-models';
+
+export default abstract class BaseDistribution {
+  protected httpClient: hc.HttpClient;
+  protected osPlat = os.platform();
+
+  constructor(protected nodeInfo: INodejs) {
+    this.httpClient = new hc.HttpClient('setup-node', [], {
+      allowRetries: true,
+      maxRetries: 3
+    });
+  }
+
+  protected abstract getDistributionUrl(): string;
+  protected abstract getNodejsVersions(): Promise<INodeVersion[]>;
+  protected abstract evaluateVersions(nodeVersions: INodeVersion[]): string;
+
+  public async getNodeJsInfo() {
+    let toolPath = this.findVersionInHoostedToolCacheDirectory();
+    if (!toolPath) {
+      const versions = await this.getNodejsVersions();
+      const evaluatedVersion = this.evaluateVersions(versions);
+      const toolName = this.getNodejsDistInfo(evaluatedVersion, this.osPlat);
+      toolPath = await this.downloadNodejs(toolName);
+    }
+
+    core.addPath(toolPath);
+  }
+
+  protected findVersionInHoostedToolCacheDirectory() {
+    return tc.find('node', this.nodeInfo.versionSpec, this.nodeInfo.arch);
+  }
+
+  protected getNodejsDistInfo(version: string, osPlat: string) {
+    let osArch: string = this.translateArchToDistUrl(this.nodeInfo.arch);
+    version = semver.clean(version) || '';
+    let fileName: string =
+      osPlat == 'win32'
+        ? `node-v${version}-win-${osArch}`
+        : `node-v${version}-${osPlat}-${osArch}`;
+    let urlFileName: string =
+      osPlat == 'win32' ? `${fileName}.7z` : `${fileName}.tar.gz`;
+    const initialUrl = this.getDistributionUrl();
+    const url = `${initialUrl}/v${version}/${urlFileName}`;
+
+    return <INodeVersionInfo>{
+      downloadUrl: url,
+      resolvedVersion: version,
+      arch: osArch, // have to be arch but not osArch,
+      fileName: fileName
+    };
+  }
+
+  protected async downloadNodejs(info: INodeVersionInfo) {
+    let osPlat: string = os.platform();
+    let downloadPath = '';
+    try {
+      downloadPath = await tc.downloadTool(info.downloadUrl);
+    } catch (err) {
+      if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
+        return await this.acquireNodeFromFallbackLocation(
+          info.resolvedVersion,
+          info.arch
+        );
+      }
+
+      throw err;
+    }
+
+    let toolPath = await this.extractArchive(downloadPath, info);
+    core.info('Done');
+
+    if (osPlat != 'win32') {
+      toolPath = path.join(toolPath, 'bin');
+    }
+
+    return toolPath;
+  }
+
+  protected async acquireNodeFromFallbackLocation(
+    version: string,
+    arch: string = os.arch()
+  ): Promise<string> {
+    const initialUrl = this.getDistributionUrl();
+    let osArch: string = this.translateArchToDistUrl(arch);
+
+    // Create temporary folder to download in to
+    const tempDownloadFolder: string =
+      'temp_' + Math.floor(Math.random() * 2000000000);
+    const tempDirectory = process.env['RUNNER_TEMP'] || '';
+    assert.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined');
+    const tempDir: string = path.join(tempDirectory, tempDownloadFolder);
+    await io.mkdirP(tempDir);
+    let exeUrl: string;
+    let libUrl: string;
+    try {
+      exeUrl = `${initialUrl}/v${version}/win-${osArch}/node.exe`;
+      libUrl = `${initialUrl}/v${version}/win-${osArch}/node.lib`;
+
+      core.info(`Downloading only node binary from ${exeUrl}`);
+
+      const exePath = await tc.downloadTool(exeUrl);
+      await io.cp(exePath, path.join(tempDir, 'node.exe'));
+      const libPath = await tc.downloadTool(libUrl);
+      await io.cp(libPath, path.join(tempDir, 'node.lib'));
+    } catch (err) {
+      if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
+        exeUrl = `${initialUrl}/v${version}/node.exe`;
+        libUrl = `${initialUrl}/v${version}/node.lib`;
+
+        const exePath = await tc.downloadTool(exeUrl);
+        await io.cp(exePath, path.join(tempDir, 'node.exe'));
+        const libPath = await tc.downloadTool(libUrl);
+        await io.cp(libPath, path.join(tempDir, 'node.lib'));
+      } else {
+        throw err;
+      }
+    }
+    const toolPath = await tc.cacheDir(tempDir, 'node', version, arch);
+    return toolPath;
+  }
+
+  protected async extractArchive(
+    downloadPath: string,
+    info: INodeVersionInfo | null
+  ) {
+    //
+    // Extract
+    //
+    core.info('Extracting ...');
+    let extPath: string;
+    info = info || ({} as INodeVersionInfo); // satisfy compiler, never null when reaches here
+    if (this.osPlat == 'win32') {
+      let _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe');
+      extPath = await tc.extract7z(downloadPath, undefined, _7zPath);
+      // 7z extracts to folder matching file name
+      let nestedPath = path.join(extPath, path.basename(info.fileName, '.7z'));
+      if (fs.existsSync(nestedPath)) {
+        extPath = nestedPath;
+      }
+    } else {
+      extPath = await tc.extractTar(downloadPath, undefined, [
+        'xz',
+        '--strip',
+        '1'
+      ]);
+    }
+
+    //
+    // Install into the local tool cache - node extracts with a root folder that matches the fileName downloaded
+    //
+    core.info('Adding to the cache ...');
+    const toolPath = await tc.cacheDir(
+      extPath,
+      'node',
+      info.resolvedVersion,
+      info.arch
+    );
+
+    return toolPath;
+  }
+
+  protected getDistFileName(arch: string = os.arch()): string {
+    let osPlat: string = os.platform();
+    let osArch: string = this.translateArchToDistUrl(arch);
+
+    // node offers a json list of versions
+    let dataFileName: string;
+    switch (osPlat) {
+      case 'linux':
+        dataFileName = `linux-${osArch}`;
+        break;
+      case 'darwin':
+        dataFileName = `osx-${osArch}-tar`;
+        break;
+      case 'win32':
+        dataFileName = `win-${osArch}-exe`;
+        break;
+      default:
+        throw new Error(`Unexpected OS '${osPlat}'`);
+    }
+
+    return dataFileName;
+  }
+
+  protected filterVersions(nodeVersions: INodeVersion[]) {
+    let versions: string[] = [];
+
+    const dataFileName = this.getDistFileName(this.nodeInfo.arch);
+
+    nodeVersions.forEach((nodeVersion: INodeVersion) => {
+      // ensure this version supports your os and platform
+      if (nodeVersion.files.indexOf(dataFileName) >= 0) {
+        versions.push(nodeVersion.version);
+      }
+    });
+
+    return versions.sort(semver.rcompare);
+  }
+
+  protected translateArchToDistUrl(arch: string): string {
+    switch (arch) {
+      case 'arm':
+        return 'armv7l';
+      default:
+        return arch;
+    }
+  }
+}
diff --git a/src/distibutions/base-models.ts b/src/distibutions/base-models.ts
new file mode 100644
index 00000000..300461bb
--- /dev/null
+++ b/src/distibutions/base-models.ts
@@ -0,0 +1,18 @@
+export interface INodejs {
+  versionSpec: string;
+  arch: string;
+  auth?: string;
+  checkLatest: boolean;
+}
+
+export interface INodeVersionInfo {
+  downloadUrl: string;
+  resolvedVersion: string;
+  arch: string;
+  fileName: string;
+}
+
+export interface INodeVersion {
+  version: string;
+  files: string[];
+}
diff --git a/src/distibutions/installer-factory.ts b/src/distibutions/installer-factory.ts
new file mode 100644
index 00000000..4e694c05
--- /dev/null
+++ b/src/distibutions/installer-factory.ts
@@ -0,0 +1,46 @@
+import BaseDistribution from './base-distribution';
+import {INodejs} from './base-models';
+import NightlyNodejs from './nightly/nightly_builds';
+import OfficialBuilds from './official_builds/official_builds';
+import RcBuild from './official_builds/rc/rc_builds';
+import CanaryBuild from './v8-canary/canary_builds';
+
+enum Distributions {
+  DEFAULT = '',
+  CANARY = 'v8-canary',
+  NIGHTLY = 'nightly',
+  RC = 'rc'
+}
+
+function identifyDistribution(versionSpec: string) {
+  let distribution = '';
+  if (versionSpec.includes(Distributions.NIGHTLY)) {
+    distribution = Distributions.NIGHTLY;
+  } else if (versionSpec.includes(Distributions.CANARY)) {
+    distribution = Distributions.CANARY;
+  } else if (versionSpec.includes(Distributions.RC)) {
+    distribution = Distributions.RC;
+  } else {
+    distribution = Distributions.DEFAULT;
+  }
+
+  return distribution;
+}
+
+export function getNodejsDistribution(
+  installerOptions: INodejs
+): BaseDistribution | null {
+  const distributionName = identifyDistribution(installerOptions.versionSpec);
+  switch (distributionName) {
+    case Distributions.NIGHTLY:
+      return new NightlyNodejs(installerOptions);
+    case Distributions.CANARY:
+      return new CanaryBuild(installerOptions);
+    case Distributions.RC:
+      return new RcBuild(installerOptions);
+    case Distributions.DEFAULT:
+      return new OfficialBuilds(installerOptions);
+    default:
+      return null;
+  }
+}
diff --git a/src/distibutions/nightly/nightly_builds.ts b/src/distibutions/nightly/nightly_builds.ts
new file mode 100644
index 00000000..d3abb125
--- /dev/null
+++ b/src/distibutions/nightly/nightly_builds.ts
@@ -0,0 +1,77 @@
+import * as core from '@actions/core';
+
+import semver from 'semver';
+
+import BaseDistribution from '../base-distribution';
+import {INodejs, INodeVersion} from '../base-models';
+
+export default class NightlyNodejs extends BaseDistribution {
+  constructor(nodeInfo: INodejs) {
+    super(nodeInfo);
+  }
+
+  protected evaluateVersions(nodeVersions: INodeVersion[]): string {
+    let version = '';
+    const versions = this.filterVersions(nodeVersions);
+
+    core.debug(`evaluating ${versions.length} versions`);
+
+    const {includePrerelease, range} = this.createRangePreRelease(
+      this.nodeInfo.versionSpec,
+      '-nightly'
+    );
+
+    for (let i = versions.length - 1; i >= 0; i--) {
+      const potential: string = versions[i];
+      const satisfied: boolean = semver.satisfies(potential, range, {
+        includePrerelease: includePrerelease
+      });
+      if (satisfied) {
+        version = potential;
+        break;
+      }
+    }
+
+    if (version) {
+      core.debug(`matched: ${version}`);
+    } else {
+      core.debug('match not found');
+    }
+
+    return version;
+  }
+
+  protected getDistributionUrl(): string {
+    return 'https://nodejs.org/download/nightly';
+  }
+
+  async getNodejsVersions(): Promise<INodeVersion[]> {
+    const initialUrl = this.getDistributionUrl();
+    const dataUrl = `${initialUrl}/index.json`;
+
+    let response = await this.httpClient.getJson<INodeVersion[]>(dataUrl);
+    return response.result || [];
+  }
+
+  createRangePreRelease(versionSpec: string, distribution: string = '') {
+    let range: string | undefined;
+    const [raw, prerelease] = this.splitVersionSpec(versionSpec);
+    const isValidVersion = semver.valid(raw);
+    const rawVersion = (isValidVersion ? raw : semver.coerce(raw))!;
+
+    if (`-${prerelease}` !== distribution) {
+      range = `${rawVersion}${`-${prerelease}`.replace(
+        distribution,
+        `${distribution}.`
+      )}`;
+    } else {
+      range = `${semver.validRange(`^${rawVersion}${distribution}`)}-0`;
+    }
+
+    return {range, includePrerelease: !isValidVersion};
+  }
+
+  splitVersionSpec(versionSpec: string) {
+    return versionSpec.split(/-(.*)/s);
+  }
+}
diff --git a/src/distibutions/official_builds/official_builds.ts b/src/distibutions/official_builds/official_builds.ts
new file mode 100644
index 00000000..34304e9f
--- /dev/null
+++ b/src/distibutions/official_builds/official_builds.ts
@@ -0,0 +1,273 @@
+import * as core from '@actions/core';
+import * as tc from '@actions/tool-cache';
+import * as semver from 'semver';
+import os from 'os';
+
+import {INodeVersion} from '../../installer';
+import BaseDistribution from '../base-distribution';
+import {INodejs, INodeVersionInfo} from '../base-models';
+
+interface INodeRelease extends tc.IToolRelease {
+  lts?: string;
+}
+
+export default class OfficialBuilds extends BaseDistribution {
+  constructor(nodeInfo: INodejs) {
+    super(nodeInfo);
+  }
+
+  protected async queryDistForMatch(
+    versionSpec: string,
+    arch: string = os.arch(),
+    nodeVersions: INodeVersion[]
+  ): Promise<string> {
+    let osPlat: string = os.platform();
+    let osArch: string = this.translateArchToDistUrl(arch);
+
+    // node offers a json list of versions
+    let dataFileName: string;
+    switch (osPlat) {
+      case 'linux':
+        dataFileName = `linux-${osArch}`;
+        break;
+      case 'darwin':
+        dataFileName = `osx-${osArch}-tar`;
+        break;
+      case 'win32':
+        dataFileName = `win-${osArch}-exe`;
+        break;
+      default:
+        throw new Error(`Unexpected OS '${osPlat}'`);
+    }
+
+    if (this.isLatestSyntax(versionSpec)) {
+      core.info(`getting latest node version...`);
+      return nodeVersions[0].version;
+    }
+
+    const versions: string[] = [];
+    nodeVersions.forEach((nodeVersion: INodeVersion) => {
+      // ensure this version supports your os and platform
+      if (nodeVersion.files.indexOf(dataFileName) >= 0) {
+        versions.push(nodeVersion.version);
+      }
+    });
+
+    // get the latest version that matches the version spec
+    const version = this.evaluateVersions(nodeVersions);
+    return version;
+  }
+
+  public async getNodeJsInfo() {
+    let manifest: tc.IToolRelease[] = [];
+    let nodeVersions: INodeVersion[] = [];
+    if (this.isLtsAlias(this.nodeInfo.versionSpec)) {
+      core.info('Attempt to resolve LTS alias from manifest...');
+
+      // No try-catch since it's not possible to resolve LTS alias without manifest
+      manifest = await this.getManifest();
+
+      this.nodeInfo.versionSpec = this.resolveLtsAliasFromManifest(
+        this.nodeInfo.versionSpec,
+        true,
+        manifest
+      );
+    }
+
+    if (this.isLatestSyntax(this.nodeInfo.versionSpec)) {
+      nodeVersions = await this.getNodejsVersions();
+      this.nodeInfo.versionSpec = await this.queryDistForMatch(
+        this.nodeInfo.versionSpec,
+        this.nodeInfo.arch,
+        nodeVersions
+      );
+      core.info(`getting latest node version...`);
+    }
+
+    let toolPath = this.findVersionInHoostedToolCacheDirectory();
+
+    if (!toolPath) {
+      try {
+        const versionInfo = await this.getInfoFromManifest(
+          this.nodeInfo.versionSpec,
+          true,
+          this.nodeInfo.auth,
+          this.nodeInfo.arch,
+          undefined
+        );
+        if (versionInfo) {
+          core.info(
+            `Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`
+          );
+          toolPath = await tc.downloadTool(
+            versionInfo.downloadUrl,
+            undefined,
+            this.nodeInfo.auth
+          );
+        } else {
+          core.info(
+            'Not found in manifest.  Falling back to download directly from Node'
+          );
+        }
+      } catch (err) {
+        // Rate limit?
+        if (
+          err instanceof tc.HTTPError &&
+          (err.httpStatusCode === 403 || err.httpStatusCode === 429)
+        ) {
+          core.info(
+            `Received HTTP status code ${err.httpStatusCode}.  This usually indicates the rate limit has been exceeded`
+          );
+        } else {
+          core.info(err.message);
+        }
+        core.debug(err.stack);
+        core.info('Falling back to download directly from Node');
+      }
+
+      const versions = await this.getNodejsVersions();
+      const evaluatedVersion = this.evaluateVersions(versions);
+      const toolName = this.getNodejsDistInfo(evaluatedVersion, this.osPlat);
+      toolPath = await this.downloadNodejs(toolName);
+    }
+
+    core.addPath(toolPath);
+  }
+
+  protected evaluateVersions(nodeVersions: INodeVersion[]): string {
+    let version = '';
+    const versions = this.filterVersions(nodeVersions);
+
+    if (this.isLatestSyntax(this.nodeInfo.versionSpec)) {
+      core.info(`getting latest node version...`);
+      return versions[0];
+    }
+
+    core.debug(`evaluating ${versions.length} versions`);
+
+    for (let i = versions.length - 1; i >= 0; i--) {
+      const potential: string = versions[i];
+      const satisfied: boolean = semver.satisfies(
+        potential,
+        this.nodeInfo.versionSpec
+      );
+      if (satisfied) {
+        version = potential;
+        break;
+      }
+    }
+
+    if (version) {
+      core.debug(`matched: ${version}`);
+    } else {
+      core.debug('match not found');
+    }
+
+    return version;
+  }
+
+  protected getDistributionUrl(): string {
+    return `https://nodejs.org/dist`;
+  }
+
+  protected async getNodejsVersions(): Promise<INodeVersion[]> {
+    const initialUrl = this.getDistributionUrl();
+    const dataUrl = `${initialUrl}/index.json`;
+
+    let response = await this.httpClient.getJson<INodeVersion[]>(dataUrl);
+    return response.result || [];
+  }
+
+  private getManifest(): Promise<tc.IToolRelease[]> {
+    core.debug('Getting manifest from actions/node-versions@main');
+    return tc.getManifestFromRepo(
+      'actions',
+      'node-versions',
+      this.nodeInfo.auth,
+      'main'
+    );
+  }
+
+  private resolveLtsAliasFromManifest(
+    versionSpec: string,
+    stable: boolean,
+    manifest: INodeRelease[]
+  ): string {
+    const alias = versionSpec.split('lts/')[1]?.toLowerCase();
+
+    if (!alias) {
+      throw new Error(
+        `Unable to parse LTS alias for Node version '${versionSpec}'`
+      );
+    }
+
+    core.debug(`LTS alias '${alias}' for Node version '${versionSpec}'`);
+
+    // Supported formats are `lts/<alias>`, `lts/*`, and `lts/-n`. Where asterisk means highest possible LTS and -n means the nth-highest.
+    const n = Number(alias);
+    const aliases = Object.fromEntries(
+      manifest
+        .filter(x => x.lts && x.stable === stable)
+        .map(x => [x.lts!.toLowerCase(), x])
+        .reverse()
+    );
+    const numbered = Object.values(aliases);
+    const release =
+      alias === '*'
+        ? numbered[numbered.length - 1]
+        : n < 0
+        ? numbered[numbered.length - 1 + n]
+        : aliases[alias];
+
+    if (!release) {
+      throw new Error(
+        `Unable to find LTS release '${alias}' for Node version '${versionSpec}'.`
+      );
+    }
+
+    core.debug(
+      `Found LTS release '${release.version}' for Node version '${versionSpec}'`
+    );
+
+    return release.version.split('.')[0];
+  }
+
+  private async getInfoFromManifest(
+    versionSpec: string,
+    stable: boolean,
+    auth: string | undefined,
+    osArch: string = this.translateArchToDistUrl(os.arch()),
+    manifest: tc.IToolRelease[] | undefined
+  ): Promise<INodeVersionInfo | null> {
+    let info: INodeVersionInfo | null = null;
+    if (!manifest) {
+      core.debug('No manifest cached');
+      manifest = await this.getManifest();
+    }
+
+    const rel = await tc.findFromManifest(
+      versionSpec,
+      stable,
+      manifest,
+      osArch
+    );
+
+    if (rel && rel.files.length > 0) {
+      info = <INodeVersionInfo>{};
+      info.resolvedVersion = rel.version;
+      info.arch = rel.files[0].arch;
+      info.downloadUrl = rel.files[0].download_url;
+      info.fileName = rel.files[0].filename;
+    }
+
+    return info;
+  }
+
+  private isLtsAlias(versionSpec: string): boolean {
+    return versionSpec.startsWith('lts/');
+  }
+
+  private isLatestSyntax(versionSpec): boolean {
+    return ['current', 'latest', 'node'].includes(versionSpec);
+  }
+}
diff --git a/src/distibutions/official_builds/rc/rc_builds.ts b/src/distibutions/official_builds/rc/rc_builds.ts
new file mode 100644
index 00000000..8822a1bd
--- /dev/null
+++ b/src/distibutions/official_builds/rc/rc_builds.ts
@@ -0,0 +1,50 @@
+import * as core from '@actions/core';
+
+import * as semver from 'semver';
+
+import BaseDistribution from '../../base-distribution';
+import {INodejs, INodeVersion} from '../../base-models';
+
+export default class RcBuild extends BaseDistribution {
+  constructor(nodeInfo: INodejs) {
+    super(nodeInfo);
+  }
+
+  protected async getNodejsVersions(): Promise<INodeVersion[]> {
+    const initialUrl = this.getDistributionUrl();
+    const dataUrl = `${initialUrl}/index.json`;
+
+    let response = await this.httpClient.getJson<INodeVersion[]>(dataUrl);
+    return response.result || [];
+  }
+
+  protected evaluateVersions(nodeVersions: INodeVersion[]): string {
+    let version = '';
+    const versions = this.filterVersions(nodeVersions);
+    core.debug(`evaluating ${versions.length} versions`);
+
+    for (let i = versions.length - 1; i >= 0; i--) {
+      const potential: string = versions[i];
+      const satisfied: boolean = semver.satisfies(
+        potential,
+        this.nodeInfo.versionSpec
+      );
+      if (satisfied) {
+        version = potential;
+        break;
+      }
+    }
+
+    if (version) {
+      core.debug(`matched: ${version}`);
+    } else {
+      core.debug('match not found');
+    }
+
+    return version;
+  }
+
+  getDistributionUrl(): string {
+    return 'https://nodejs.org/download/rc';
+  }
+}
diff --git a/src/distibutions/v8-canary/canary_builds.ts b/src/distibutions/v8-canary/canary_builds.ts
new file mode 100644
index 00000000..f929c035
--- /dev/null
+++ b/src/distibutions/v8-canary/canary_builds.ts
@@ -0,0 +1,75 @@
+import * as core from '@actions/core';
+
+import semver from 'semver';
+
+import BaseDistribution from '../base-distribution';
+import {INodejs, INodeVersion} from '../base-models';
+
+export default class CanaryBuild extends BaseDistribution {
+  protected evaluateVersions(nodeVersions: INodeVersion[]): string {
+    let version = '';
+    const versions = this.filterVersions(nodeVersions);
+
+    core.debug(`evaluating ${versions.length} versions`);
+
+    const {includePrerelease, range} = this.createRangePreRelease(
+      this.nodeInfo.versionSpec,
+      '-v8-canary'
+    );
+
+    for (let i = versions.length - 1; i >= 0; i--) {
+      const potential: string = versions[i];
+      const satisfied: boolean = semver.satisfies(potential, range, {
+        includePrerelease: includePrerelease
+      });
+      if (satisfied) {
+        version = potential;
+        break;
+      }
+    }
+
+    if (version) {
+      core.debug(`matched: ${version}`);
+    } else {
+      core.debug('match not found');
+    }
+
+    return version;
+  }
+  constructor(nodeInfo: INodejs) {
+    super(nodeInfo);
+  }
+  protected getDistributionUrl(): string {
+    return 'https://nodejs.org/download/v8-canary';
+  }
+
+  async getNodejsVersions(): Promise<INodeVersion[]> {
+    const initialUrl = this.getDistributionUrl();
+    const dataUrl = `${initialUrl}/index.json`;
+
+    let response = await this.httpClient.getJson<INodeVersion[]>(dataUrl);
+    return response.result || [];
+  }
+
+  createRangePreRelease(versionSpec: string, distribution: string = '') {
+    let range: string | undefined;
+    const [raw, prerelease] = this.splitVersionSpec(versionSpec);
+    const isValidVersion = semver.valid(raw);
+    const rawVersion = (isValidVersion ? raw : semver.coerce(raw))!;
+
+    if (`-${prerelease}` !== distribution) {
+      range = `${rawVersion}${`-${prerelease}`.replace(
+        distribution,
+        `${distribution}.`
+      )}`;
+    } else {
+      range = `${semver.validRange(`^${rawVersion}${distribution}`)}-0`;
+    }
+
+    return {range, includePrerelease: !isValidVersion};
+  }
+
+  splitVersionSpec(versionSpec: string) {
+    return versionSpec.split(/-(.*)/s);
+  }
+}
diff --git a/src/main.ts b/src/main.ts
index 2a846b06..b250085c 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -7,6 +7,7 @@ import * as path from 'path';
 import {restoreCache} from './cache-restore';
 import {isGhes, isCacheFeatureAvailable} from './cache-utils';
 import os from 'os';
+import {getNodejsDistribution} from './distibutions/installer-factory';
 
 export async function run() {
   try {
@@ -38,7 +39,18 @@ export async function run() {
         (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
       const checkLatest =
         (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
-      await installer.getNode(version, stable, checkLatest, auth, arch);
+      const nodejsInfo = {
+        versionSpec: version,
+        checkLatest: checkLatest,
+        auth,
+        arch: arch
+      };
+      const nodeDistribution = getNodejsDistribution(nodejsInfo);
+      if (nodeDistribution) {
+        await nodeDistribution?.getNodeJsInfo();
+      }
+
+      // await installer.getNode(version, stable, checkLatest, auth, arch);
     }
 
     await printEnvDetailsAndSetOutput();