@serverless/platform-client
Advanced tools
Comparing version 3.2.0 to 3.3.0
{ | ||
"name": "@serverless/platform-client", | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"main": "./src/index.js", | ||
@@ -15,3 +15,2 @@ "jsdelivr": "dist-web/serverless-platform-client.min.js", | ||
"archiver": "^5.0.0", | ||
"fast-glob": "^3.2.4", | ||
"axios": "^0.21.1", | ||
@@ -25,3 +24,2 @@ "https-proxy-agent": "^5.0.0", | ||
"querystring": "^0.2.0", | ||
"run-parallel-limit": "^1.0.6", | ||
"throat": "^5.0.0", | ||
@@ -28,0 +26,0 @@ "traverse": "^0.6.6", |
@@ -7,25 +7,9 @@ 'use strict'; | ||
const crypto = require('crypto'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const Axios = require('axios'); | ||
const { tmpdir } = require('os'); | ||
const axios = require('axios'); | ||
const exec = require('child_process').exec; | ||
const utils = require('./utils'); | ||
const fg = require('fast-glob'); | ||
const AdmZip = require('adm-zip'); | ||
const runParallelLimit = require('run-parallel-limit'); | ||
// Create a new axios instance and make sure we clear the default axios headers | ||
// as they cause a mismatch with the signature provided by aws | ||
const axios = Axios.create(); | ||
axios.defaults.headers.common = {}; | ||
axios.defaults.headers.put = {}; | ||
axios.defaults.headers.get = {}; | ||
// make sure axios handles large packages | ||
const axiosConfig = { | ||
maxContentLength: Infinity, | ||
maxBodyLength: Infinity, | ||
}; | ||
/** | ||
@@ -236,172 +220,49 @@ * Correctly formats an instanceId | ||
const log = (msg = '') => console.log(msg); // eslint-disable-line | ||
const getFilesToUpload = (map = {}, previousMap = {}, options) => { | ||
const filesToUpload = []; | ||
if (options.force) { | ||
return Object.keys(map); | ||
/* | ||
* Uploads the component instance src input reference if available | ||
*/ | ||
const preRunSrcUpload = async (sdk, orgName, inputs) => { | ||
const packagePath = path.join(tmpdir(), `${Math.random().toString(36).substring(6)}.zip`); | ||
const { srcOriginal } = inputs; | ||
let { src } = inputs; | ||
let exclude = []; | ||
if (typeof srcOriginal === 'object' && srcOriginal.exclude) { | ||
exclude = srcOriginal.exclude; | ||
} | ||
Object.keys(map).forEach((filePath) => { | ||
if (!previousMap[filePath] || previousMap[filePath] !== map[filePath]) { | ||
filesToUpload.push(filePath); | ||
} | ||
}); | ||
return filesToUpload; | ||
}; | ||
const getFilesToDelete = (map = {}, previousMap = {}) => { | ||
const filesToDelete = []; | ||
Object.keys(previousMap).forEach((filePath) => { | ||
if (!map[filePath]) { | ||
filesToDelete.push(filePath); | ||
} | ||
}); | ||
return filesToDelete; | ||
}; | ||
const getPreviousMap = async (previousMapDownloadUrl) => { | ||
try { | ||
return (await axios.get(previousMapDownloadUrl, null, axiosConfig)).data; | ||
} catch (e) { | ||
return undefined; | ||
} | ||
}; | ||
const preCache = async (sdk, { orgName, stageName, appName, instanceName }, options) => { | ||
// console.time('preCache'); | ||
const res = await utils.request({ | ||
endpoint: `${sdk.getDomain('engine')}/preCache`, | ||
// Get the package signed urls. This is an object includes both the upload and download urls | ||
// the upload url is used to upload the package to s3 | ||
// while the download url is passed to the component instannce to be downnloaded in the lambda runtime | ||
const packageUrls = await utils.request({ | ||
endpoint: `${sdk.getDomain('engine')}/getUploadUrls`, | ||
accessKey: sdk.accessKey, | ||
method: 'POST', | ||
data: { orgName, stageName, appName, instanceName }, | ||
data: { | ||
orgName, | ||
}, | ||
}); | ||
if (!options.force) { | ||
res.previousMap = await getPreviousMap(res.previousMapDownloadUrl); | ||
} | ||
// Zip source | ||
await utils.zip(src, { outputFilePath: packagePath, exclude }); | ||
// console.timeEnd('preCache'); | ||
// Create a new axios instance and make sure we clear the default axios headers | ||
// as they cause a mismatch with the signature provided by aws | ||
const request = axios.create(); | ||
request.defaults.headers.common = {}; | ||
request.defaults.headers.put = {}; | ||
const body = fs.readFileSync(packagePath); | ||
return res; | ||
}; | ||
// Make sure axios handles large packages | ||
const config = { | ||
maxContentLength: Infinity, | ||
maxBodyLength: Infinity, | ||
}; | ||
const getFilesAndMap = async (inputs) => { | ||
// console.time('getFilesAndMap'); | ||
const { srcOriginal } = inputs; | ||
const { src } = inputs; | ||
let exclude = []; // todo should we add anything here by default? ie. README.md (.git ? -Doug) | ||
if (typeof srcOriginal === 'object' && srcOriginal.exclude) { | ||
exclude = exclude.concat(srcOriginal.exclude); | ||
} | ||
await request.put(packageUrls.upload, body, config); | ||
const files = {}; | ||
const map = {}; | ||
// eslint-disable-next-line | ||
await new Promise(async (resolve, reject) => { | ||
const filesPaths = await fg('**/*', { cwd: src, ignore: exclude }); | ||
const tasks = filesPaths.map((filePath) => { | ||
return (callback) => { | ||
const absoluteFilePath = path.resolve(src, filePath); | ||
fs.readFile(absoluteFilePath, (err, file) => { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
files[filePath] = { | ||
file, | ||
stat: {}, | ||
}; | ||
// this fixes this potential permissions issue: | ||
// https://github.com/serverless/components/issues/687 | ||
// commenting out for now until we actually face it to save on ms | ||
// files[filePath].stat = fs.statSync(absoluteFilePath); | ||
map[filePath] = crypto.createHash('md5').update(file).digest('hex'); | ||
callback(); | ||
}); | ||
}; | ||
}); | ||
runParallelLimit(tasks, 2048, (err) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(); | ||
} | ||
}); | ||
}); | ||
// console.timeEnd('getFilesAndMap'); | ||
return { map, files }; | ||
// replace the src input to point to the download url so that it's download in the lambda runtime | ||
src = packageUrls.download; | ||
return src; | ||
}; | ||
const zipChanges = async (filesToUpload, filesToDelete, map, files) => { | ||
if (filesToUpload.length === 0 && filesToDelete.length === 0) { | ||
return null; | ||
} | ||
const zip = new AdmZip(); | ||
if (filesToDelete.length !== 0) { | ||
const filesToDeleteContent = JSON.stringify(filesToDelete); | ||
zip.addFile('deleted.files', Buffer.alloc(filesToDeleteContent.length, filesToDeleteContent)); | ||
} | ||
const mapContent = JSON.stringify(map); | ||
zip.addFile('src.map', Buffer.alloc(mapContent.length, mapContent)); | ||
for (const filePath of filesToUpload) { | ||
const mode = files[filePath].stat.mode & 0o100 ? 0o755 : 0o644; | ||
zip.addFile(filePath, files[filePath].file, null, mode); | ||
} | ||
return zip.toBuffer(); | ||
}; | ||
const cache = async (sdk, instance, options) => { | ||
// console.time('total'); | ||
const [{ map, files }, { previousMap, changesUploadUrl, srcDownloadUrl }] = await Promise.all([ | ||
getFilesAndMap(instance.inputs), | ||
preCache(sdk, instance, options), | ||
]); | ||
const filesToUpload = getFilesToUpload(map, previousMap, options); | ||
const filesToDelete = getFilesToDelete(map, previousMap, options); | ||
if (filesToUpload.length !== 0 || filesToDelete.length !== 0) { | ||
options.cacheOutdated = true; | ||
// log(`Updating ${filesToUpload.length} files`); | ||
// log(`Deleting ${filesToDelete.length} files`); | ||
// console.time('zipping'); | ||
const zipBuffer = await zipChanges(filesToUpload, filesToDelete, map, files); | ||
// console.timeEnd('zipping'); | ||
// console.time('uploading'); | ||
await axios.put(changesUploadUrl, zipBuffer, axiosConfig); | ||
// console.timeEnd('uploading'); | ||
} else { | ||
options.cacheOutdated = false; | ||
// log('No changes detected.'); | ||
} | ||
// console.timeEnd('total'); | ||
return srcDownloadUrl; | ||
}; | ||
/** | ||
@@ -450,8 +311,4 @@ * Run a method. "inputs" override serverless.yml inputs and should only be provided when using custom methods. | ||
// this should eventually move to the CLI | ||
if (process.argv.includes('--force')) { | ||
options.force = true; | ||
} | ||
instance.inputs.src = await cache(sdk, instance, options); | ||
// Upload the "inputs.src" code | ||
instance.inputs.src = await preRunSrcUpload(sdk, instance.orgName, instance.inputs); | ||
} | ||
@@ -458,0 +315,0 @@ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
13
678604
4934
- Removedfast-glob@^3.2.4
- Removedrun-parallel-limit@^1.0.6
- Removed@nodelib/fs.scandir@2.1.5(transitive)
- Removed@nodelib/fs.stat@2.0.5(transitive)
- Removed@nodelib/fs.walk@1.2.8(transitive)
- Removedbraces@3.0.3(transitive)
- Removedfast-glob@3.3.2(transitive)
- Removedfastq@1.17.1(transitive)
- Removedfill-range@7.1.1(transitive)
- Removedglob-parent@5.1.2(transitive)
- Removedis-extglob@2.1.1(transitive)
- Removedis-glob@4.0.3(transitive)
- Removedis-number@7.0.0(transitive)
- Removedmerge2@1.4.1(transitive)
- Removedmicromatch@4.0.8(transitive)
- Removedpicomatch@2.3.1(transitive)
- Removedqueue-microtask@1.2.3(transitive)
- Removedreusify@1.0.4(transitive)
- Removedrun-parallel@1.2.0(transitive)
- Removedrun-parallel-limit@1.1.0(transitive)
- Removedto-regex-range@5.0.1(transitive)