rollup-plugin-playcanvas-uploader
Version:
A lightweight Rollup plugin to automatically upload your bundles to PlayCanvas.
207 lines (197 loc) • 8.49 kB
JavaScript
;
var axios = require('axios');
var FormData = require('form-data');
var fs = require('fs');
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
function __awaiter(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());
});
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
const assetsApiUrl = "https://playcanvas.com/api/assets";
function upload(options) {
return {
name: "playcanvas-uploader",
writeBundle(outputOptions, _bundle) {
return __awaiter(this, void 0, void 0, function* () {
if (!options) {
this.error("No options provided.");
}
const uploader = new Uploader(this, options);
const file = outputOptions.file;
yield (file ? uploader.uploadFile(file) : uploader.uploadFiles());
});
}
};
}
class Uploader {
constructor(context, options) {
this._context = context;
this._options = options;
this.validateOptions();
}
validateOptions() {
const options = this._options;
const projectId = options.projectId;
if (!projectId || !Number.isInteger(projectId)) {
this.error(`Invalid project ID "${projectId}".`);
}
const branchId = options.branchId;
if (!branchId) {
this.error(`Invalid branch ID "${branchId}".`);
}
const accessToken = options.accessToken;
if (!accessToken) {
this.error(`No access token specified.`);
}
const files = options.files;
if (!files || files.length === 0) {
this.error(`No files specified.`);
}
for (let length = files.length, i = 0; i < length; i++) {
const file = files[i];
if (!file.path) {
this.error(`File path not specified.`);
}
if (!file.assetId || !Number.isInteger(file.assetId)) {
this.error(`Invalid asset ID "${file.assetId}" for file "${file.path}".`);
}
}
}
uploadFiles() {
return __awaiter(this, void 0, void 0, function* () {
const fileInfos = this._options.files;
for (let length = fileInfos.length, i = 0; i < length; i++) {
const fileInfo = fileInfos[i];
yield this.uploadFile(fileInfo.path);
}
});
}
uploadFile(filePath) {
return __awaiter(this, void 0, void 0, function* () {
const fileInfo = this.getFileInfo(filePath);
if (!fileInfo) {
this.error(`File "${filePath}" not found in options.`);
}
if (!fs.existsSync(filePath)) {
this.error(`File "${filePath}" does not exist.`);
}
const fileContent = fs.createReadStream(filePath);
const form = new FormData();
form.append("file", fileContent);
form.append("branchId", this._options.branchId);
try {
// Upload the file
this.log(`Uploading file "${fileInfo.path}"...`);
const fileUri = `${assetsApiUrl}/${fileInfo.assetId}`;
const response = yield axios.put(fileUri, form, {
headers: {
Authorization: `Bearer ${this._options.accessToken}`,
"Content-Type": form.getHeaders()["content-type"]
}
});
// Validate the response
const status = response.status;
if (status === 200) {
this.log(`Uploaded file "${fileInfo.path}".`);
}
else {
this.warn(`Encountered unexpected status code ${status} whilst upload file "${fileInfo.path}": `
+ response.statusText);
}
}
catch (error) {
const response = error.response;
if (!this.validateResponse(response)) {
return;
}
switch (response.status) {
case 404:
// The asset is missing. Create a new one.
this.createAsset(fileInfo, filePath);
break;
default:
this.warn(`Failed to update asset "${fileInfo.path}": ${response.statusText} (${response.status})`);
break;
}
}
});
}
createAsset(fileInfo, filePath) {
return __awaiter(this, void 0, void 0, function* () {
const form = new FormData();
form.append("name", fileInfo.path);
form.append("project", this._options.projectId);
form.append("branchId", this._options.branchId);
form.append("preload", "true");
form.append("file", fs.createReadStream(filePath));
try {
// Upload the file
this.log(`Creating asset "${fileInfo.path}"...`);
const response = yield axios.post(assetsApiUrl, form, {
headers: {
Authorization: `Bearer ${this._options.accessToken}`,
"Content-Type": form.getHeaders()["content-type"]
}
});
// Validate the response
if (response.status === 201) {
this.warn(`Created asset "${fileInfo.path}" with asset ID "${response.data.id}". Please make `
+ `sure to add this asset ID to the "files"-section of your PlayCanvas Uploader config.`);
}
else {
this.warn(`Encountered unexpected status code ${response.status} whilst creating a new asset `
+ `for file ${fileInfo.path}: ${response.statusText}`);
}
}
catch (error) {
const response = error.response;
if (!this.validateResponse(response)) {
return;
}
this.warn(`Failed to create asset "${fileInfo.path}" (status code ${response.status}): ` +
response.statusText);
}
});
}
validateResponse(response) {
if (!response) {
this.error(`Failed to get a general network response. Is your internet connection functioning properly?`);
return false;
}
return true;
}
getFileInfo(path) {
return this._options.files.find((file) => file.path === path);
}
log(message) {
console.log(message);
}
warn(message) {
this._context.warn(message);
}
error(message) {
this._context.error(message);
}
}
module.exports = upload;