] [env: RCC_ENCODING] [default: utf-8]
+ --rcc-telemetry [env: RCC_TELEMETRY] (default: do not track)
+
+ -h, --help
+```
diff --git a/camunda/Dockerfile b/camunda/Dockerfile
new file mode 100644
index 0000000..9bd78a4
--- /dev/null
+++ b/camunda/Dockerfile
@@ -0,0 +1,12 @@
+FROM camunda/camunda-bpm-platform:7.15.0
+USER camunda
+RUN set -xe && \
+ # https://github.com/datakurre/camunda-cockpit-plugins/ OR https://datakurre.pandala.org/2021/01/camunda-cockpit-history-plugin/ installation
+ wget -P /camunda/webapps/camunda/app/cockpit/scripts/ https://raw.githubusercontent.com/datakurre/camunda-cockpit-plugins/master/definition-historic-activities.js && \
+ wget -P /camunda/webapps/camunda/app/cockpit/scripts/ https://raw.githubusercontent.com/datakurre/camunda-cockpit-plugins/master/instance-historic-activities.js && \
+ wget -P /camunda/webapps/camunda/app/cockpit/scripts/ https://raw.githubusercontent.com/datakurre/camunda-cockpit-plugins/master/instance-route-history.js && \
+ # https://github.com/datakurre/camunda-modeler-robot-plugin OR https://forum.robotframework.org/t/integrating-rf-with-camunda/997 installation
+ wget -P /camunda/webapps/camunda/app/cockpit/scripts/ https://raw.githubusercontent.com/datakurre/camunda-modeler-robot-plugin/master/dist/module.js
+COPY --chown=camunda:camunda cockpit/config.js /camunda/webapps/camunda/app/cockpit/scripts/.
+COPY --chown=camunda:camunda deployment /tmp/deployment
+
diff --git a/camunda/cockpit/config.js b/camunda/cockpit/config.js
new file mode 100644
index 0000000..78a3368
--- /dev/null
+++ b/camunda/cockpit/config.js
@@ -0,0 +1,74 @@
+/*
+ * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
+ * under one or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information regarding copyright
+ * ownership. Camunda licenses this file to you under the Apache License,
+ * Version 2.0; you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export default {
+ customScripts: [
+ 'scripts/definition-historic-activities.js',
+ 'scripts/instance-historic-activities.js',
+ 'scripts/instance-route-history.js'
+ //'scripts/instance-tab-modify.js'
+ ],
+ // locales: {
+ // availableLocales: ['en', 'de'],
+ // fallbackLocale: 'en'
+ // },
+ bpmnJs: {
+ additionalModules: [
+ 'scripts/module.js'
+ // // If you have a folder called 'my-custom-module' (in the 'cockpit' folder)
+ // // with a file called 'module.js' in it
+ // // 'my-custom-module/module'
+ ],
+ // moddleExtensions: {
+ // // If you have a folder called 'my-custom-moddle' (in the 'cockpit' folder)
+ // // with a file called 'camunda.json' in it defining the 'camunda' moddle extension
+ // // camunda: 'my-custom-moddle/camunda'
+ // }
+ },
+ // skipCustomListeners: {
+ // default: true,
+ // hidden: false
+ // },
+ // skipIoMappings: {
+ // default: true,
+ // hidden: false
+ // },
+ // runtimeActivityInstanceMetrics: {
+ // display: true
+ // },
+ // historicActivityInstanceMetrics: {
+ // adjustablePeriod: true,
+ // // Select from the default time period: day, week, month, complete
+ // period: {
+ // unit: 'week'
+ // }
+ // },
+ // batchOperation: {
+ // // Select mode of query for process instances or decision instances
+ // // possible values: filter, search
+ // mode: 'filter',
+ // // Select if Historic Batches should be loaded automatically when navigating to #/batch
+ // autoLoadEnded: true
+ // },
+ // defaultFilter: {
+ // historicProcessDefinitionInstancesSearch: {
+ // lastDays: 5,
+ // event: 'started'
+ // }
+ // },
+ disableWelcomeMessage: false,
+ // userOperationLogAnnotationLength: 4000
+};
diff --git a/camunda/deployment/camunda-reset.bpmn b/camunda/deployment/camunda-reset.bpmn
new file mode 100644
index 0000000..302891a
--- /dev/null
+++ b/camunda/deployment/camunda-reset.bpmn
@@ -0,0 +1,90 @@
+
+
+
+
+ Flow_0e57r2k
+
+
+
+
+ Flow_0e57r2k
+ Flow_15rh19q
+ Flow_0auj3hy
+
+
+
+
+ Flow_1329rr6
+ Flow_0xjviwl
+ Flow_1wc9j4m
+
+
+ Flow_1wc9j4m
+
+
+
+
+ Flow_15rh19q
+ Flow_1329rr6
+
+
+ Flow_0auj3hy
+ Flow_0xjviwl
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/camunda/deployment/review.html b/camunda/deployment/review.html
new file mode 100644
index 0000000..8e0c457
--- /dev/null
+++ b/camunda/deployment/review.html
@@ -0,0 +1,27 @@
+
diff --git a/camunda/deployment/xkcd-fetch-review.bpmn b/camunda/deployment/xkcd-fetch-review.bpmn
new file mode 100644
index 0000000..b2aafdd
--- /dev/null
+++ b/camunda/deployment/xkcd-fetch-review.bpmn
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+ Flow_12x9een
+
+
+ Flow_0n7yvtn
+ Flow_0gt19ec
+ Flow_1hs8p8m
+
+
+ ${description}
+ Flow_06mlb8o
+ Flow_0n7yvtn
+
+
+
+
+
+ ${execution.getVariableTyped("alt")}
+ ${execution.getVariableTyped("title")}
+ ${execution.getVariableTyped("comic.png")}
+
+
+ Flow_1jl2vsi
+ Flow_06mlb8o
+
+
+
+
+ Flow_0gt19ec
+
+
+
+ Flow_0z47gg9
+
+
+ Flow_0n92i0a
+
+
+
+ Flow_0n92i0a
+
+
+
+
+
+ ${callerId}
+ ${url}
+
+
+ Flow_0z47gg9
+ Flow_1jl2vsi
+
+
+
+
+ Flow_1hs8p8m
+ Flow_12x9een
+
+
+
+
+ ${accepted == true}
+
+
+ Result to the super process is send as a message to collect parallel instantance output.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/camunda/deployment/xkcd-search.bpmn b/camunda/deployment/xkcd-search.bpmn
new file mode 100644
index 0000000..665b88e
--- /dev/null
+++ b/camunda/deployment/xkcd-search.bpmn
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Flow_1ns3j1t
+
+
+
+
+ Flow_1hs8p8m
+
+
+ Flow_0d4lgiv
+ Flow_1hs8p8m
+ Flow_0nmd3l6
+
+
+ ${execution.hasVariable("accepted") ? execution.getVariable("accepted") > 0 : false}
+
+
+ Flow_1ns3j1t
+ Flow_1hjllec
+ Flow_18mj359
+
+
+
+
+ No results found.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Flow_18u19wj
+ Flow_171pgri
+
+
+ Flow_047wgvk
+
+
+
+ Flow_171pgri
+ Flow_047wgvk
+ Flow_1hjllec
+
+
+
+ ${retry == true}
+
+
+
+
+ ${execution.getVariableTyped("results")}
+
+
+ Flow_18mj359
+ Flow_1g4wnik
+
+
+ Flow_1i36hj7
+
+
+
+
+
+
+
+
+
+ Flow_1g4wnik
+ Flow_0d4lgiv
+
+
+
+
+ Flow_0wz4bix
+
+
+
+
+ Flow_0foonv9
+ Flow_0wz4bix
+
+
+ Flow_0foonv9
+
+
+
+
+ Flow_1i36hj7
+ Flow_0nmd3l6
+ Flow_18u19wj
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/carrot_rcc.py b/carrot_rcc.py
new file mode 100644
index 0000000..5efd5ec
--- /dev/null
+++ b/carrot_rcc.py
@@ -0,0 +1,18 @@
+import os
+import subprocess
+import sys
+
+NODE_JS_EXECUTABLE = os.environ.get("NODE_JS_EXECUTABLE") or "node"
+CAMUNDA_ROBOT_BRIDGE_BUNDLE = os.environ.get(
+ "CAMUNDA_ROBOT_BRIDGE_BUNDLE"
+) or os.path.join(os.path.dirname(__file__), "index.js")
+
+
+def main():
+ print("Hello World!")
+# args = sys.argv[1:]
+# subprocess.run([NODE_JS_EXECUTABLE] + list(args) + [CAMUNDA_ROBOT_BRIDGE_BUNDLE])
+
+
+if __name__ == "__main__":
+ main()
diff --git a/carrot_rcc.ts b/carrot_rcc.ts
new file mode 100644
index 0000000..e374319
--- /dev/null
+++ b/carrot_rcc.ts
@@ -0,0 +1,686 @@
+#!/usr/bin/env node
+
+import { spawn, spawnSync } from "child_process";
+import fs from "fs";
+import os from "os";
+import path from "path";
+
+import Zip from "adm-zip";
+import {
+ Client,
+ Interceptor,
+ Task,
+ TypedValue,
+ logger,
+} from "camunda-external-task-client-js";
+import dotenv from "dotenv";
+import { fdir as FD, PathsOutput } from "fdir";
+import mime from "mime-types";
+import neodoc from "neodoc";
+import * as rest from "typed-rest-client";
+import { IRequestOptions } from "typed-rest-client";
+import YAML from "yaml";
+
+import * as api from "./Camunda";
+
+const crypto = require("crypto");
+
+type PatchVariablesDto = api.components["schemas"]["PatchVariablesDto"];
+
+dotenv.config();
+
+const args = neodoc.run(`
+usage: carrot-rcc [...]
+ [--base-url] [--authorization]
+ [--worker-id] [--max-tasks] [--poll-interval] [--log-level]
+ [--rcc-executable] [--rcc-encoding] [--rcc-telemetry]
+ [-h] [--help]
+
+ could also be passed as a comma separated env RCC_ROBOTS
+
+options:
+
+ --base-url[=] [env: CAMUNDA_API_BASE_URL] [default: http://localhost:8080/engine-rest]
+ --authorization[=] [env: CAMUNDA_API_AUTHORIZATION] [example: Basic ZGVtbzpkZW1v]
+
+ --worker-id[=] [env: CLIENT_WORKER_ID] [default: carrot-rcc]
+ --max-tasks[=] [env: CLIENT_MAX_TASKS] [default: ${
+ os.cpus().length
+ }]
+ --poll-interval[=] [env: CLIENT_POLL_INTERVAL] [default: 10000]
+ --log-level[=] [env: CLIENT_LOG_LEVEL] [default: info]
+
+ --rcc-executable[=] [env: RCC_EXECUTABLE] [default: rcc]
+ --rcc-encoding[=] [env: RCC_ENCODING] [default: utf-8]
+ --rcc-telemetry [env: RCC_TELEMETRY] (default: do not track)
+
+ -h, --help
+`);
+
+const RCC_ROBOTS = (args[""] || []).concat(
+ process.env.RCC_ROBOTS ? process.env.RCC_ROBOTS.split(",") : []
+);
+
+const CAMUNDA_API_BASE_URL = args["--base-url"];
+const CAMUNDA_API_AUTHORIZATION = args["--authorization"];
+
+const CLIENT_LOG_LEVEL = args["--log-level"].toLowerCase();
+const CLIENT_MAX_TASKS = args["--max-tasks"];
+const CLIENT_POLL_INTERVAL = args["--poll-interval"];
+const CLIENT_WORKER_ID = args["--worker-id"];
+
+const RCC_EXECUTABLE = args["--rcc-executable"];
+const RCC_ENCODING = args["--rcc-encoding"];
+const RCC_TELEMETRY = !!args["--rcc-telemetry"];
+
+// Disable telemetry by default
+if (!RCC_TELEMETRY) {
+ spawnSync(RCC_EXECUTABLE, ["configuration", "identity", "-t"], {
+ env: {
+ HOME: process.env.HOME, // for RCC cache at $HOME/.robocloud
+ PATH: process.env.PATH,
+ },
+ });
+}
+
+// Dummy logger
+const LOG = {
+ error: (...args: any[]) => {
+ if (["error", "warn", "info", "debug"].includes(CLIENT_LOG_LEVEL)) {
+ console.error(...args);
+ }
+ },
+ warn: (...args: any[]) => {
+ if (["warn", "info", "debug"].includes(CLIENT_LOG_LEVEL)) {
+ console.warn(...args);
+ }
+ },
+ info: (...args: any[]) => {
+ if (["info", "debug"].includes(CLIENT_LOG_LEVEL)) {
+ console.log(...args);
+ }
+ },
+ debug: (...args: any[]) => {
+ if (["debug"].includes(CLIENT_LOG_LEVEL)) {
+ console.log(...args);
+ }
+ },
+};
+
+const toAbsolute = (p: string): string =>
+ fs.existsSync(p) && !path.isAbsolute(p) ? path.join(process.cwd(), p) : p;
+
+const CAMUNDA_TOPICS: Record = {};
+
+for (const candidate of RCC_ROBOTS) {
+ const robot = toAbsolute(candidate);
+ if (robot && fs.existsSync(robot)) {
+ const zip = new Zip(robot);
+ const entries = zip.getEntries();
+ entries.forEach((entry) => {
+ if (entry.entryName == "robot.yaml") {
+ const data = entry.getData().toString(RCC_ENCODING as BufferEncoding);
+ const yaml = YAML.parse(data);
+ for (const task of Object.keys(yaml.tasks || {})) {
+ CAMUNDA_TOPICS[task] = robot;
+ }
+ }
+ });
+ }
+}
+if (Object.keys(CAMUNDA_TOPICS).length < 1) {
+ LOG.error("RCC_ROBOTS invalid of missing:", RCC_ROBOTS);
+ process.exit(1);
+}
+
+const AuthorizationHeaderInterceptor: Interceptor = (config: any): any => {
+ return CAMUNDA_API_AUTHORIZATION
+ ? {
+ ...config,
+ headers: {
+ ...config.headers,
+ Authorization: CAMUNDA_API_AUTHORIZATION,
+ },
+ }
+ : config;
+};
+
+const client = new Client({
+ baseUrl: CAMUNDA_API_BASE_URL,
+ workerId: CLIENT_WORKER_ID,
+ maxTasks: CLIENT_MAX_TASKS,
+ maxParallelExecutions: CLIENT_MAX_TASKS,
+ interval: CLIENT_POLL_INTERVAL,
+ lockDuration: CLIENT_POLL_INTERVAL,
+ autoPoll: true,
+ interceptors: [AuthorizationHeaderInterceptor],
+ asyncResponseTimeout: CLIENT_POLL_INTERVAL,
+ use: (logger as any).level(CLIENT_LOG_LEVEL),
+});
+
+LOG.debug((client as any).options);
+LOG.debug(CAMUNDA_TOPICS);
+
+const isEqual = async (
+ old: TypedValue | undefined,
+ current: any
+): Promise => {
+ if (old === undefined) {
+ return false;
+ }
+ switch (old.type) {
+ case "File":
+ return false;
+ default:
+ return old.value === current;
+ }
+};
+
+const inferType = async (
+ old: TypedValue | undefined,
+ current: any
+): Promise => {
+ if (old?.type) {
+ return old.type[0].toUpperCase() + old.type.substr(1);
+ } else if (typeof current === "boolean") {
+ return "Boolean";
+ } else if (typeof current === "string") {
+ if (current.match(/^\d{4}-\d{2}-\d{2}T?[0-9:.Z]*$/)) {
+ return "Date";
+ } else {
+ return "String";
+ }
+ } else if (typeof current.getMonth === "function") {
+ return "Date";
+ } else if (typeof current === "number") {
+ if (!`${current}`.match(/\./)) {
+ return "Integer";
+ } else {
+ return "Double";
+ }
+ }
+ return "Json";
+};
+
+const TZ: string = ((): string => {
+ const date = new Date();
+ const offset = date.getTimezoneOffset();
+ const base = Math.floor(offset / 60) * -100 + (offset % 60);
+ if (offset == 0) {
+ return "+0000";
+ } else if (base >= 1000) {
+ return `+${base}`;
+ } else if (base >= 100) {
+ return `+0${base}`;
+ } else if (base >= 10) {
+ return `+00${base}`;
+ } else if (base >= 1) {
+ return `+000${base}`;
+ } else if (base <= -1000) {
+ return `-${base}`;
+ } else if (base <= -100) {
+ return `-0${base}`;
+ } else if (base <= -10) {
+ return `-00${base}`;
+ } else if (base <= -1) {
+ return `-000${base}`;
+ } else {
+ return "+0000";
+ }
+})();
+
+interface File {
+ name: string;
+ hex: string;
+}
+
+const load = async (
+ task: Task,
+ tasksDir: string,
+ itemsDir: string,
+ topic: string
+): Promise> => {
+ const files: Record = {};
+ // Fetch and prepare robot
+ await new Promise((resolve, reject) => {
+ const stdout: string[] = [];
+ const stderr: string[] = [];
+ const exec = spawn(
+ RCC_EXECUTABLE,
+ ["robot", "unwrap", "-d", tasksDir, "-z", CAMUNDA_TOPICS[topic]],
+ {
+ env: {
+ HOME: process.env.HOME, // for RCC cache at $HOME/.robocloud
+ PATH: process.env.PATH,
+ },
+ }
+ );
+ exec.stdout.on("data", (data) => stdout.push(data.toString()));
+ exec.stderr.on("data", (data) => stderr.push(data.toString()));
+ exec.on("close", (code) =>
+ code === 0
+ ? resolve(stdout.join("") + stderr.join(""))
+ : reject(stdout.join("") + stderr.join(""))
+ );
+ });
+ // Fetch and prepare items
+ await new Promise(async (resolve) => {
+ const variables = task.variables.getAll();
+ const typed = task.variables.getAllTyped();
+ // TODO: This could be optimized to make parallel file variable fetch
+ for (const name of Object.keys(typed)) {
+ if (typed[name].type === "file") {
+ delete variables[name];
+ typed[
+ name
+ ].value.remotePath = `/execution/${task.executionId}/localVariables/${name}/data`;
+ const file = await typed[name].value.load();
+ const filename = path.join(itemsDir, file.filename);
+ await new Promise((resolve) => {
+ fs.writeFile(filename, file.content, resolve);
+ });
+ const hashSum = crypto.createHash("sha256");
+ hashSum.update(file.content);
+ files[filename] = {
+ name,
+ hex: hashSum.digest("hex"),
+ };
+ }
+ }
+ const items = {
+ 1: {
+ 1: {
+ variables,
+ },
+ },
+ };
+ fs.writeFile(
+ path.join(itemsDir, "items.json"),
+ JSON.stringify(items),
+ resolve
+ );
+ });
+ return files;
+};
+
+const failReason = async (tasksDir: string): Promise => {
+ let reason = "fail";
+ const taskFiles = new FD().withFullPaths().crawl(tasksDir).sync();
+ for (const file of taskFiles as PathsOutput) {
+ if (path.basename(file) === "output.xml") {
+ const xml = fs.readFileSync(file).toString("utf-8");
+ for (const match of xml.matchAll(/status="FAIL"[^>]*.([^<]*)/g)) {
+ reason = match[1].trim() || reason;
+ }
+ }
+ }
+ return reason;
+};
+
+const inlineScreenshots = async (
+ log: string,
+ dirname: string
+): Promise => {
+ for (const match of log.matchAll(/img src=\\"([^"]+)/g)) {
+ const src = match[1].replace(/\\$/, "");
+ let file: string;
+ if (src.startsWith("data:")) {
+ continue;
+ } else if (path.isAbsolute(src)) {
+ if (fs.existsSync(src)) {
+ file = src;
+ } else {
+ continue;
+ }
+ } else if (fs.existsSync(path.join(dirname, src))) {
+ file = path.join(dirname, src);
+ } else {
+ continue;
+ }
+ const type = mime.lookup(file) || "application/octet-stream";
+ const data = (
+ await new Promise((resolve) =>
+ fs.readFile(file, (err, data) => resolve(data))
+ )
+ ).toString("base64");
+ const uri = `data:${type};base64,${data}`;
+ log = log
+ .replace(new RegExp(`a href=\\\\"${src}\\\\"`, "g"), "a")
+ .replace(
+ new RegExp(`img src=\\\\"${src}\\\\" width=\\\\"800px\\\\"`, "g"),
+ `img src=\\"${uri}\\" style=\\"max-width:800px\\"`
+ )
+ .replace(
+ new RegExp(`img src=\\\\"${src}\\\\"`, "g"),
+ `img src=\\"${uri}\\"`
+ );
+ }
+ return log;
+};
+
+const save = async (
+ task: Task,
+ tasksDir: string,
+ itemsDir: string,
+ files: Record,
+ stdout: string,
+ stderr: string,
+ code: number
+): Promise => {
+ const client = new rest.RestClient(
+ "carrot-executor",
+ CAMUNDA_API_BASE_URL,
+ []
+ );
+
+ const options: IRequestOptions = {
+ additionalHeaders: CAMUNDA_API_AUTHORIZATION
+ ? {
+ Authorization: CAMUNDA_API_AUTHORIZATION,
+ }
+ : {},
+ };
+
+ const old = task.variables.getAllTyped();
+ const current = JSON.parse(
+ fs.readFileSync(path.join(itemsDir, "items.json")) as unknown as string
+ )[1][1].variables;
+ const patch: PatchVariablesDto = {
+ modifications: {},
+ };
+
+ if (patch.modifications) {
+ for (const name of Object.keys(current)) {
+ if (await isEqual(old[name], current[name])) {
+ continue;
+ }
+ switch (await inferType(old[name], current[name])) {
+ case "Boolean":
+ patch.modifications[name] = {
+ value: !!current[name],
+ type: "Boolean",
+ };
+ break;
+ case "Date":
+ patch.modifications[name] = {
+ value: (typeof current[name].getMonth === "function"
+ ? current[name].toISOString()
+ : `${current[name].substring(0, 10)}T${current[name].substring(
+ 11
+ )}${TZ}`
+ ).replace(/Z$/, "+0000"),
+ type: "Date",
+ };
+ break;
+ case "Double":
+ patch.modifications[name] = {
+ value: current[name],
+ type: "Double",
+ };
+ break;
+ case "File":
+ break;
+ case "Integer":
+ patch.modifications[name] = {
+ value: current[name],
+ type: "Integer",
+ };
+ break;
+ case "Json":
+ patch.modifications[name] = {
+ value: JSON.stringify(current[name]) || "null",
+ type: "Json",
+ };
+ break;
+ case "String":
+ patch.modifications[name] = {
+ value: `${current[name]}` || null,
+ type: "String",
+ };
+ break;
+ default:
+ patch.modifications[name] = {
+ value: current[name],
+ type: old?.[name]?.type || "String",
+ valueInfo: old?.[name]?.valueInfo || {},
+ };
+ }
+ }
+
+ const itemsFiles = new FD().withFullPaths().crawl(itemsDir).sync();
+ for (const file of itemsFiles as PathsOutput) {
+ if (path.basename(file) !== "items.json") {
+ const fileBuffer = fs.readFileSync(file);
+
+ // Skip unmodified files
+ if (files[file]) {
+ const hashSum = crypto.createHash("sha256");
+ hashSum.update(fileBuffer);
+ if (files[file].hex === hashSum.digest("hex")) {
+ continue;
+ }
+ }
+
+ // Set to new and changed file variables
+ const type = mime.lookup(file) || "application/octet-stream";
+ patch.modifications[
+ files[file] ? files[file].name : path.basename(file)
+ ] = {
+ value: fileBuffer.toString("base64"),
+ type: "File",
+ valueInfo: {
+ filename: path.basename(file),
+ mimetype: type,
+ mimeType: type,
+ encoding: "utf-8",
+ },
+ };
+ }
+ }
+
+ const taskFiles = new FD().withFullPaths().crawl(tasksDir).sync();
+ for (const file of taskFiles as PathsOutput) {
+ if (path.basename(file) === "log.html") {
+ const dirname = path.dirname(file);
+ const log = fs.readFileSync(file).toString("utf-8");
+ patch.modifications["log"] = {
+ value: Buffer.from(await inlineScreenshots(log, dirname)).toString(
+ "base64"
+ ),
+ type: "File",
+ valueInfo: {
+ filename: "log.html",
+ mimetype: "text/html",
+ mimeType: "text/html",
+ encoding: "utf-8",
+ },
+ };
+ break;
+ }
+ }
+ if ((code > 0 && stdout) || old["stdout"]) {
+ patch.modifications["stdout"] = {
+ value: Buffer.from(stdout, "utf-8").toString("base64"),
+ type: "File",
+ valueInfo: {
+ filename: "stdout.txt",
+ mimetype: "text/plain",
+ mimeType: "text/plain",
+ encoding: "utf-8",
+ },
+ };
+ }
+ if ((code > 0 && stderr) || old["stderr"]) {
+ patch.modifications["stderr"] = {
+ value: Buffer.from(stderr, "utf-8").toString("base64"),
+ type: "File",
+ valueInfo: {
+ filename: "stderr.txt",
+ mimetype: "text/plain",
+ mimeType: "text/plain",
+ encoding: "utf-8",
+ },
+ };
+ }
+
+ if (Object.keys(patch.modifications).length > 0) {
+ await client.create(
+ `execution/${task.executionId}/localVariables`,
+ patch,
+ options
+ );
+ }
+ }
+};
+
+const extendLockError: Map = new Map();
+client.on("extendLock:error", ({ id }, e) => {
+ if (id) {
+ extendLockError.set(id, `${e}`);
+ }
+});
+
+const handleFailureError: Map = new Map();
+client.on("handleFailure:error", ({ id }, e) => {
+ if (id) {
+ handleFailureError.set(id, `${e}`);
+ }
+});
+
+const completeError: Map = new Map();
+// @ts-ignore // outdated @types
+client.on("complete:error", ({ id }, e) => {
+ if (id) {
+ completeError.set(id, `${e}`);
+ }
+});
+
+for (const topic of Object.keys(CAMUNDA_TOPICS)) {
+ client.subscribe(topic, async ({ task, taskService }) => {
+ LOG.debug("Received task", task.topicName, task.id);
+
+ // Resolve lock expiration
+ const lockExpiration =
+ new Date(task.lockExpirationTime as string).getTime() -
+ new Date().getTime();
+
+ // Extend lock expiration
+ const extendLock = async () => {
+ await taskService.extendLock(task, lockExpiration);
+
+ // On error, stop extending lock expiration
+ if (task.id && !extendLockError.has(task.id)) {
+ extendLockTimeout = setTimeout(extendLock, lockExpiration / 2);
+ } else if (task.id) {
+ extendLockError.delete(task.id);
+ }
+ };
+
+ // Schedule initial lock expiration
+ let extendLockTimeout = setTimeout(extendLock, lockExpiration / 2);
+
+ // Execute with temporary working directory
+ const tasksDir = await fs.mkdtempSync(path.join(os.tmpdir(), "rcc-tasks-"));
+ const itemsDir = await fs.mkdtempSync(path.join(os.tmpdir(), "rcc-items-"));
+ try {
+ // Prepare robot
+ const files = await load(task, tasksDir, itemsDir, topic);
+
+ // Execute robot
+ await new Promise((resolve, reject) => {
+ const stdout: string[] = [];
+ const stderr: string[] = [];
+ const exec = spawn(RCC_EXECUTABLE, ["run", "--task", topic], {
+ cwd: tasksDir,
+ env: {
+ RPA_WORKITEMS_ADAPTER: "RPA.Robocloud.Items.FileAdapter",
+ RPA_WORKITEMS_PATH: `${itemsDir}/items.json`,
+ RC_WORKSPACE_ID: "1",
+ RC_WORKITEM_ID: "1",
+ HOME: process.env.HOME, // for RCC cache at $HOME/.robocloud
+ PATH: process.env.PATH,
+ },
+ });
+ exec.stdout.on("data", (data) => {
+ stdout.push(data.toString());
+ LOG.debug(data.toString());
+ });
+ exec.stderr.on("data", (data) => {
+ stderr.push(data.toString());
+ LOG.debug(data.toString());
+ });
+ exec.on("close", async (code) => {
+ LOG.debug("close");
+ let errorMessage = "error";
+ if (code !== null && code > 0 && code < 251) {
+ errorMessage = await failReason(tasksDir);
+ }
+ try {
+ await save(
+ task,
+ tasksDir,
+ itemsDir,
+ files,
+ stdout.join(""),
+ stderr.join(""),
+ code || 0
+ );
+ } catch (e) {
+ LOG.error(`${e}`);
+ stderr.push(`${e}`);
+ code = 255; // Unexpected error
+ }
+ if (code === 0) {
+ try {
+ await taskService.complete(task);
+ } catch (e) {
+ LOG.error(`${e}`);
+ stderr.push(`${e}`);
+ code = 255; // Unexpected error
+ }
+ if (task.id && completeError.has(task.id)) {
+ stderr.push(`${completeError.get(task.id)}`);
+ completeError.delete(task.id);
+ code = 255; // Unexpected error
+ }
+ }
+ return code === 0
+ ? resolve(task)
+ : reject({
+ error: {
+ message: errorMessage,
+ },
+ stack:
+ errorMessage === "error"
+ ? stdout.join("") + stderr.join("")
+ : stdout
+ .join("")
+ .replace(/[a-zA-Z0-9\-.]+==[a-zA-Z0-9\-.]+\n/g, ""),
+ });
+ });
+ });
+ } catch (e: any) {
+ LOG.debug(e);
+ await taskService.handleFailure(task, {
+ errorMessage: `${e?.error?.message ?? e}`,
+ errorDetails: e.stack || JSON.stringify(e),
+ });
+ // TODO: Maybe do something special on handleFailureError
+ if (task.id && handleFailureError.has(task.id)) {
+ handleFailureError.delete(task.id);
+ }
+ } finally {
+ // Cleanup
+ fs.rmdirSync(tasksDir, { recursive: true });
+ fs.rmdirSync(itemsDir, { recursive: true });
+
+ // Stop extending expiration timeout
+ clearTimeout(extendLockTimeout);
+ if (task.id && extendLockError.has(task.id)) {
+ extendLockError.delete(task.id);
+ }
+
+ LOG.debug("Completed task", task.topicName, task.id);
+ }
+ });
+}
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000..5014244
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,65 @@
+{ pkgs ? import ./nix { nixpkgs = sources."nixpkgs-21.05"; }
+, sources ? import ./nix/sources.nix
+}:
+
+let
+
+ dev_node_modules = (import ./nix/node-dev-composition.nix { inherit pkgs; }).package.override {
+ src = builtins.filterSource (path: type:
+ (baseNameOf path) == "package.json" ||
+ (baseNameOf path) == "package-lock.json" ) ./.;
+ preRebuild = ''
+ '';
+ postInstall = ''
+ mv $out/lib/node_modules/*/node_modules /tmp/_; rm -rf $out; mv /tmp/_ $out
+ '';
+ };
+
+ run_node_modules = (import ./nix/node-run-composition.nix { inherit pkgs; }).package.override {
+ src = builtins.filterSource (path: type:
+ (baseNameOf path) == "package.json" ||
+ (baseNameOf path) == "package-lock.json" ) ./.;
+ preRebuild = ''
+ '';
+ postInstall = ''
+ mv $out/lib/node_modules/*/node_modules /tmp/_; rm -rf $out; mv /tmp/_ $out
+ '';
+ };
+
+in
+
+pkgs.stdenv.mkDerivation rec {
+ name = "external-task-client";
+ src = pkgs.gitignoreSource ./.;
+ buildPhase = ''
+ source $stdenv/setup;
+ cp -a ${dev_node_modules} node_modules
+ node_modules/.bin/tsc
+ '';
+ installPhase = ''
+ source $stdenv/setup;
+ mkdir -p $out/bin $out/var/lib/carrot-executor
+ cp -a dist/* $out/var/lib/carrot-executor
+ cat > $out/bin/carrot-executor << EOF
+ #!/usr/bin/env sh
+ cd $out/var/lib/carrot-executor && node .
+ EOF
+ chmod u+x $out/bin/carrot-executor
+ '';
+ postFixup = ''
+ wrapProgram $out/bin/carrot-executor \
+ --prefix PATH : ${pkgs.lib.makeBinPath propagatedBuildInputs} \
+ --suffix NODE_ENV : production \
+ --suffix NODE_PATH : ${run_node_modules}
+ '';
+ buildInputs = with pkgs; [ makeWrapper bindfs ];
+ propagatedBuildInputs = with pkgs; [
+ coreutils findutils gnused nodejs-14_x dev_node_modules
+ ];
+ shellHook = ''
+ fusermount -qu node_modules
+ mkdir -p node_modules
+ bindfs ${dev_node_modules} node_modules -o nonempty
+ export PATH=$(pwd)/node_modules/.bin:$PATH
+ '';
+}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..16a0581
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,12 @@
+version: '3'
+
+services:
+ camunda:
+ build: ./camunda
+ ports:
+ - "8080:8080"
+ restart: unless-stopped
+ deployment:
+ build: ./camunda
+ command: "/usr/bin/curl -X POST http://camunda:8080/engine-rest/deployment/create -F \"deployment-name=Demo\" -F \"deploy-changed-only=true\" -F \"deployment-source=Demo\" -F \"a=@/tmp/deployment/xkcd-fetch-review.bpmn\" -F \"b=@/tmp/deployment/xkcd-search.bpmn\" -F \"c=@/tmp/deployment/review.html\" -F \"d=@/tmp/deployment/camunda-reset.bpmn\""
+ restart: on-failure
diff --git a/nix/default.nix b/nix/default.nix
new file mode 100644
index 0000000..5157b2d
--- /dev/null
+++ b/nix/default.nix
@@ -0,0 +1,48 @@
+# https://github.com/nmattia/niv
+{ sources ? import ./sources.nix
+, nixpkgs ? sources."nixpkgs-21.05"
+}:
+
+let
+
+ overlay = _: pkgs: {
+
+ gitignoreSource = (import sources.gitignore {
+ inherit (pkgs) lib;
+ }).gitignoreSource;
+
+ poetry2nix =
+ import (sources.poetry2nix + "/default.nix") {
+ pkgs = import sources."nixpkgs-21.05" {};
+ poetry = (import sources."nixpkgs-21.05" {}).poetry;
+ };
+
+ rcc = pkgs.buildGoPackage rec {
+ name = "rcc-${version}";
+ version = "v9.16.0";
+ goPackagePath = "github.com/robocorp/rcc";
+ src = sources.rcc;
+ nativeBuildInputs = with pkgs; [ go-bindata rake zip ];
+ goDeps = ./rcc.nix;
+ postPatch = ''
+ source $stdenv/setup
+ substituteInPlace Rakefile --replace "\$HOME/go/bin/" ""
+ rake assets
+ '';
+ };
+
+ # node2nix with nodejs 14 support
+ node2nix = builtins.getAttr builtins.currentSystem(
+ import (sources.node2nix + "/release.nix") {
+ nixpkgs = sources."nixpkgs-20.09";
+ systems = [ builtins.currentSystem ];
+ }).package;
+
+ };
+
+ pkgs = import nixpkgs {
+ overlays = [ overlay ];
+ config = {};
+ };
+
+in pkgs
diff --git a/nix/node-dev-composition.nix b/nix/node-dev-composition.nix
new file mode 100644
index 0000000..f2f89c0
--- /dev/null
+++ b/nix/node-dev-composition.nix
@@ -0,0 +1,17 @@
+# This file has been generated by node2nix 1.9.0. Do not edit!
+
+{pkgs ? import {
+ inherit system;
+ }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-14_x"}:
+
+let
+ nodeEnv = import ./node-dev-env.nix {
+ inherit (pkgs) stdenv lib python2 runCommand writeTextFile;
+ inherit pkgs nodejs;
+ libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
+ };
+in
+import ./node-dev-packages.nix {
+ inherit (pkgs) fetchurl nix-gitignore stdenv lib fetchgit;
+ inherit nodeEnv;
+}
diff --git a/nix/node-dev-env.nix b/nix/node-dev-env.nix
new file mode 100644
index 0000000..2460a41
--- /dev/null
+++ b/nix/node-dev-env.nix
@@ -0,0 +1,573 @@
+# This file originates from node2nix
+
+{lib, stdenv, nodejs, python2, pkgs, libtool, runCommand, writeTextFile}:
+
+let
+ # Workaround to cope with utillinux in Nixpkgs 20.09 and util-linux in Nixpkgs master
+ utillinux = if pkgs ? utillinux then pkgs.utillinux else pkgs.util-linux;
+
+ python = if nodejs ? python then nodejs.python else python2;
+
+ # Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise
+ tarWrapper = runCommand "tarWrapper" {} ''
+ mkdir -p $out/bin
+
+ cat > $out/bin/tar <> $out/nix-support/hydra-build-products
+ '';
+ };
+
+ includeDependencies = {dependencies}:
+ lib.optionalString (dependencies != [])
+ (lib.concatMapStrings (dependency:
+ ''
+ # Bundle the dependencies of the package
+ mkdir -p node_modules
+ cd node_modules
+
+ # Only include dependencies if they don't exist. They may also be bundled in the package.
+ if [ ! -e "${dependency.name}" ]
+ then
+ ${composePackage dependency}
+ fi
+
+ cd ..
+ ''
+ ) dependencies);
+
+ # Recursively composes the dependencies of a package
+ composePackage = { name, packageName, src, dependencies ? [], ... }@args:
+ builtins.addErrorContext "while evaluating node package '${packageName}'" ''
+ DIR=$(pwd)
+ cd $TMPDIR
+
+ unpackFile ${src}
+
+ # Make the base dir in which the target dependency resides first
+ mkdir -p "$(dirname "$DIR/${packageName}")"
+
+ if [ -f "${src}" ]
+ then
+ # Figure out what directory has been unpacked
+ packageDir="$(find . -maxdepth 1 -type d | tail -1)"
+
+ # Restore write permissions to make building work
+ find "$packageDir" -type d -exec chmod u+x {} \;
+ chmod -R u+w "$packageDir"
+
+ # Move the extracted tarball into the output folder
+ mv "$packageDir" "$DIR/${packageName}"
+ elif [ -d "${src}" ]
+ then
+ # Get a stripped name (without hash) of the source directory.
+ # On old nixpkgs it's already set internally.
+ if [ -z "$strippedName" ]
+ then
+ strippedName="$(stripHash ${src})"
+ fi
+
+ # Restore write permissions to make building work
+ chmod -R u+w "$strippedName"
+
+ # Move the extracted directory into the output folder
+ mv "$strippedName" "$DIR/${packageName}"
+ fi
+
+ # Unset the stripped name to not confuse the next unpack step
+ unset strippedName
+
+ # Include the dependencies of the package
+ cd "$DIR/${packageName}"
+ ${includeDependencies { inherit dependencies; }}
+ cd ..
+ ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+ '';
+
+ pinpointDependencies = {dependencies, production}:
+ let
+ pinpointDependenciesFromPackageJSON = writeTextFile {
+ name = "pinpointDependencies.js";
+ text = ''
+ var fs = require('fs');
+ var path = require('path');
+
+ function resolveDependencyVersion(location, name) {
+ if(location == process.env['NIX_STORE']) {
+ return null;
+ } else {
+ var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json");
+
+ if(fs.existsSync(dependencyPackageJSON)) {
+ var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON));
+
+ if(dependencyPackageObj.name == name) {
+ return dependencyPackageObj.version;
+ }
+ } else {
+ return resolveDependencyVersion(path.resolve(location, ".."), name);
+ }
+ }
+ }
+
+ function replaceDependencies(dependencies) {
+ if(typeof dependencies == "object" && dependencies !== null) {
+ for(var dependency in dependencies) {
+ var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency);
+
+ if(resolvedVersion === null) {
+ process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n");
+ } else {
+ dependencies[dependency] = resolvedVersion;
+ }
+ }
+ }
+ }
+
+ /* Read the package.json configuration */
+ var packageObj = JSON.parse(fs.readFileSync('./package.json'));
+
+ /* Pinpoint all dependencies */
+ replaceDependencies(packageObj.dependencies);
+ if(process.argv[2] == "development") {
+ replaceDependencies(packageObj.devDependencies);
+ }
+ replaceDependencies(packageObj.optionalDependencies);
+
+ /* Write the fixed package.json file */
+ fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2));
+ '';
+ };
+ in
+ ''
+ node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"}
+
+ ${lib.optionalString (dependencies != [])
+ ''
+ if [ -d node_modules ]
+ then
+ cd node_modules
+ ${lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies}
+ cd ..
+ fi
+ ''}
+ '';
+
+ # Recursively traverses all dependencies of a package and pinpoints all
+ # dependencies in the package.json file to the versions that are actually
+ # being used.
+
+ pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args:
+ ''
+ if [ -d "${packageName}" ]
+ then
+ cd "${packageName}"
+ ${pinpointDependencies { inherit dependencies production; }}
+ cd ..
+ ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+ fi
+ '';
+
+ # Extract the Node.js source code which is used to compile packages with
+ # native bindings
+ nodeSources = runCommand "node-sources" {} ''
+ tar --no-same-owner --no-same-permissions -xf ${nodejs.src}
+ mv node-* $out
+ '';
+
+ # Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty)
+ addIntegrityFieldsScript = writeTextFile {
+ name = "addintegrityfields.js";
+ text = ''
+ var fs = require('fs');
+ var path = require('path');
+
+ function augmentDependencies(baseDir, dependencies) {
+ for(var dependencyName in dependencies) {
+ var dependency = dependencies[dependencyName];
+
+ // Open package.json and augment metadata fields
+ var packageJSONDir = path.join(baseDir, "node_modules", dependencyName);
+ var packageJSONPath = path.join(packageJSONDir, "package.json");
+
+ if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored
+ console.log("Adding metadata fields to: "+packageJSONPath);
+ var packageObj = JSON.parse(fs.readFileSync(packageJSONPath));
+
+ if(dependency.integrity) {
+ packageObj["_integrity"] = dependency.integrity;
+ } else {
+ packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads.
+ }
+
+ if(dependency.resolved) {
+ packageObj["_resolved"] = dependency.resolved; // Adopt the resolved property if one has been provided
+ } else {
+ packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories.
+ }
+
+ if(dependency.from !== undefined) { // Adopt from property if one has been provided
+ packageObj["_from"] = dependency.from;
+ }
+
+ fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2));
+ }
+
+ // Augment transitive dependencies
+ if(dependency.dependencies !== undefined) {
+ augmentDependencies(packageJSONDir, dependency.dependencies);
+ }
+ }
+ }
+
+ if(fs.existsSync("./package-lock.json")) {
+ var packageLock = JSON.parse(fs.readFileSync("./package-lock.json"));
+
+ if(![1, 2].includes(packageLock.lockfileVersion)) {
+ process.stderr.write("Sorry, I only understand lock file versions 1 and 2!\n");
+ process.exit(1);
+ }
+
+ if(packageLock.dependencies !== undefined) {
+ augmentDependencies(".", packageLock.dependencies);
+ }
+ }
+ '';
+ };
+
+ # Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes
+ reconstructPackageLock = writeTextFile {
+ name = "addintegrityfields.js";
+ text = ''
+ var fs = require('fs');
+ var path = require('path');
+
+ var packageObj = JSON.parse(fs.readFileSync("package.json"));
+
+ var lockObj = {
+ name: packageObj.name,
+ version: packageObj.version,
+ lockfileVersion: 1,
+ requires: true,
+ dependencies: {}
+ };
+
+ function augmentPackageJSON(filePath, dependencies) {
+ var packageJSON = path.join(filePath, "package.json");
+ if(fs.existsSync(packageJSON)) {
+ var packageObj = JSON.parse(fs.readFileSync(packageJSON));
+ dependencies[packageObj.name] = {
+ version: packageObj.version,
+ integrity: "sha1-000000000000000000000000000=",
+ dependencies: {}
+ };
+ processDependencies(path.join(filePath, "node_modules"), dependencies[packageObj.name].dependencies);
+ }
+ }
+
+ function processDependencies(dir, dependencies) {
+ if(fs.existsSync(dir)) {
+ var files = fs.readdirSync(dir);
+
+ files.forEach(function(entry) {
+ var filePath = path.join(dir, entry);
+ var stats = fs.statSync(filePath);
+
+ if(stats.isDirectory()) {
+ if(entry.substr(0, 1) == "@") {
+ // When we encounter a namespace folder, augment all packages belonging to the scope
+ var pkgFiles = fs.readdirSync(filePath);
+
+ pkgFiles.forEach(function(entry) {
+ if(stats.isDirectory()) {
+ var pkgFilePath = path.join(filePath, entry);
+ augmentPackageJSON(pkgFilePath, dependencies);
+ }
+ });
+ } else {
+ augmentPackageJSON(filePath, dependencies);
+ }
+ }
+ });
+ }
+ }
+
+ processDependencies("node_modules", lockObj.dependencies);
+
+ fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2));
+ '';
+ };
+
+ prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}:
+ let
+ forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
+ in
+ ''
+ # Pinpoint the versions of all dependencies to the ones that are actually being used
+ echo "pinpointing versions of dependencies..."
+ source $pinpointDependenciesScriptPath
+
+ # Patch the shebangs of the bundled modules to prevent them from
+ # calling executables outside the Nix store as much as possible
+ patchShebangs .
+
+ # Deploy the Node.js package by running npm install. Since the
+ # dependencies have been provided already by ourselves, it should not
+ # attempt to install them again, which is good, because we want to make
+ # it Nix's responsibility. If it needs to install any dependencies
+ # anyway (e.g. because the dependency parameters are
+ # incomplete/incorrect), it fails.
+ #
+ # The other responsibilities of NPM are kept -- version checks, build
+ # steps, postprocessing etc.
+
+ export HOME=$TMPDIR
+ cd "${packageName}"
+ runHook preRebuild
+
+ ${lib.optionalString bypassCache ''
+ ${lib.optionalString reconstructLock ''
+ if [ -f package-lock.json ]
+ then
+ echo "WARNING: Reconstruct lock option enabled, but a lock file already exists!"
+ echo "This will most likely result in version mismatches! We will remove the lock file and regenerate it!"
+ rm package-lock.json
+ else
+ echo "No package-lock.json file found, reconstructing..."
+ fi
+
+ node ${reconstructPackageLock}
+ ''}
+
+ node ${addIntegrityFieldsScript}
+ ''}
+
+ npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} rebuild
+
+ if [ "''${dontNpmInstall-}" != "1" ]
+ then
+ # NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
+ rm -f npm-shrinkwrap.json
+
+ npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} install
+ fi
+ '';
+
+ # Builds and composes an NPM package including all its dependencies
+ buildNodePackage =
+ { name
+ , packageName
+ , version
+ , dependencies ? []
+ , buildInputs ? []
+ , production ? true
+ , npmFlags ? ""
+ , dontNpmInstall ? false
+ , bypassCache ? false
+ , reconstructLock ? false
+ , preRebuild ? ""
+ , dontStrip ? true
+ , unpackPhase ? "true"
+ , buildPhase ? "true"
+ , meta ? {}
+ , ... }@args:
+
+ let
+ extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" "meta" ];
+ in
+ stdenv.mkDerivation ({
+ name = "node_${name}-${version}";
+ buildInputs = [ tarWrapper python nodejs ]
+ ++ lib.optional (stdenv.isLinux) utillinux
+ ++ lib.optional (stdenv.isDarwin) libtool
+ ++ buildInputs;
+
+ inherit nodejs;
+
+ inherit dontStrip; # Stripping may fail a build for some package deployments
+ inherit dontNpmInstall preRebuild unpackPhase buildPhase;
+
+ compositionScript = composePackage args;
+ pinpointDependenciesScript = pinpointDependenciesOfPackage args;
+
+ passAsFile = [ "compositionScript" "pinpointDependenciesScript" ];
+
+ installPhase = ''
+ # Create and enter a root node_modules/ folder
+ mkdir -p $out/lib/node_modules
+ cd $out/lib/node_modules
+
+ # Compose the package and all its dependencies
+ source $compositionScriptPath
+
+ ${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
+
+ # Create symlink to the deployed executable folder, if applicable
+ if [ -d "$out/lib/node_modules/.bin" ]
+ then
+ ln -s $out/lib/node_modules/.bin $out/bin
+ fi
+
+ # Create symlinks to the deployed manual page folders, if applicable
+ if [ -d "$out/lib/node_modules/${packageName}/man" ]
+ then
+ mkdir -p $out/share
+ for dir in "$out/lib/node_modules/${packageName}/man/"*
+ do
+ mkdir -p $out/share/man/$(basename "$dir")
+ for page in "$dir"/*
+ do
+ ln -s $page $out/share/man/$(basename "$dir")
+ done
+ done
+ fi
+
+ # Run post install hook, if provided
+ runHook postInstall
+ '';
+
+ meta = {
+ # default to Node.js' platforms
+ platforms = nodejs.meta.platforms;
+ } // meta;
+ } // extraArgs);
+
+ # Builds a node environment (a node_modules folder and a set of binaries)
+ buildNodeDependencies =
+ { name
+ , packageName
+ , version
+ , src
+ , dependencies ? []
+ , buildInputs ? []
+ , production ? true
+ , npmFlags ? ""
+ , dontNpmInstall ? false
+ , bypassCache ? false
+ , reconstructLock ? false
+ , dontStrip ? true
+ , unpackPhase ? "true"
+ , buildPhase ? "true"
+ , ... }@args:
+
+ let
+ extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ];
+ in
+ stdenv.mkDerivation ({
+ name = "node-dependencies-${name}-${version}";
+
+ buildInputs = [ tarWrapper python nodejs ]
+ ++ lib.optional (stdenv.isLinux) utillinux
+ ++ lib.optional (stdenv.isDarwin) libtool
+ ++ buildInputs;
+
+ inherit dontStrip; # Stripping may fail a build for some package deployments
+ inherit dontNpmInstall unpackPhase buildPhase;
+
+ includeScript = includeDependencies { inherit dependencies; };
+ pinpointDependenciesScript = pinpointDependenciesOfPackage args;
+
+ passAsFile = [ "includeScript" "pinpointDependenciesScript" ];
+
+ installPhase = ''
+ mkdir -p $out/${packageName}
+ cd $out/${packageName}
+
+ source $includeScriptPath
+
+ # Create fake package.json to make the npm commands work properly
+ cp ${src}/package.json .
+ chmod 644 package.json
+ ${lib.optionalString bypassCache ''
+ if [ -f ${src}/package-lock.json ]
+ then
+ cp ${src}/package-lock.json .
+ fi
+ ''}
+
+ # Go to the parent folder to make sure that all packages are pinpointed
+ cd ..
+ ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+
+ ${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
+
+ # Expose the executables that were installed
+ cd ..
+ ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+
+ mv ${packageName} lib
+ ln -s $out/lib/node_modules/.bin $out/bin
+ '';
+ } // extraArgs);
+
+ # Builds a development shell
+ buildNodeShell =
+ { name
+ , packageName
+ , version
+ , src
+ , dependencies ? []
+ , buildInputs ? []
+ , production ? true
+ , npmFlags ? ""
+ , dontNpmInstall ? false
+ , bypassCache ? false
+ , reconstructLock ? false
+ , dontStrip ? true
+ , unpackPhase ? "true"
+ , buildPhase ? "true"
+ , ... }@args:
+
+ let
+ nodeDependencies = buildNodeDependencies args;
+ in
+ stdenv.mkDerivation {
+ name = "node-shell-${name}-${version}";
+
+ buildInputs = [ python nodejs ] ++ lib.optional (stdenv.isLinux) utillinux ++ buildInputs;
+ buildCommand = ''
+ mkdir -p $out/bin
+ cat > $out/bin/shell < {
+ inherit system;
+ }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-14_x"}:
+
+let
+ nodeEnv = import ./node-run-env.nix {
+ inherit (pkgs) stdenv lib python2 runCommand writeTextFile;
+ inherit pkgs nodejs;
+ libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
+ };
+in
+import ./node-run-packages.nix {
+ inherit (pkgs) fetchurl nix-gitignore stdenv lib fetchgit;
+ inherit nodeEnv;
+}
diff --git a/nix/node-run-env.nix b/nix/node-run-env.nix
new file mode 100644
index 0000000..2460a41
--- /dev/null
+++ b/nix/node-run-env.nix
@@ -0,0 +1,573 @@
+# This file originates from node2nix
+
+{lib, stdenv, nodejs, python2, pkgs, libtool, runCommand, writeTextFile}:
+
+let
+ # Workaround to cope with utillinux in Nixpkgs 20.09 and util-linux in Nixpkgs master
+ utillinux = if pkgs ? utillinux then pkgs.utillinux else pkgs.util-linux;
+
+ python = if nodejs ? python then nodejs.python else python2;
+
+ # Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise
+ tarWrapper = runCommand "tarWrapper" {} ''
+ mkdir -p $out/bin
+
+ cat > $out/bin/tar <> $out/nix-support/hydra-build-products
+ '';
+ };
+
+ includeDependencies = {dependencies}:
+ lib.optionalString (dependencies != [])
+ (lib.concatMapStrings (dependency:
+ ''
+ # Bundle the dependencies of the package
+ mkdir -p node_modules
+ cd node_modules
+
+ # Only include dependencies if they don't exist. They may also be bundled in the package.
+ if [ ! -e "${dependency.name}" ]
+ then
+ ${composePackage dependency}
+ fi
+
+ cd ..
+ ''
+ ) dependencies);
+
+ # Recursively composes the dependencies of a package
+ composePackage = { name, packageName, src, dependencies ? [], ... }@args:
+ builtins.addErrorContext "while evaluating node package '${packageName}'" ''
+ DIR=$(pwd)
+ cd $TMPDIR
+
+ unpackFile ${src}
+
+ # Make the base dir in which the target dependency resides first
+ mkdir -p "$(dirname "$DIR/${packageName}")"
+
+ if [ -f "${src}" ]
+ then
+ # Figure out what directory has been unpacked
+ packageDir="$(find . -maxdepth 1 -type d | tail -1)"
+
+ # Restore write permissions to make building work
+ find "$packageDir" -type d -exec chmod u+x {} \;
+ chmod -R u+w "$packageDir"
+
+ # Move the extracted tarball into the output folder
+ mv "$packageDir" "$DIR/${packageName}"
+ elif [ -d "${src}" ]
+ then
+ # Get a stripped name (without hash) of the source directory.
+ # On old nixpkgs it's already set internally.
+ if [ -z "$strippedName" ]
+ then
+ strippedName="$(stripHash ${src})"
+ fi
+
+ # Restore write permissions to make building work
+ chmod -R u+w "$strippedName"
+
+ # Move the extracted directory into the output folder
+ mv "$strippedName" "$DIR/${packageName}"
+ fi
+
+ # Unset the stripped name to not confuse the next unpack step
+ unset strippedName
+
+ # Include the dependencies of the package
+ cd "$DIR/${packageName}"
+ ${includeDependencies { inherit dependencies; }}
+ cd ..
+ ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+ '';
+
+ pinpointDependencies = {dependencies, production}:
+ let
+ pinpointDependenciesFromPackageJSON = writeTextFile {
+ name = "pinpointDependencies.js";
+ text = ''
+ var fs = require('fs');
+ var path = require('path');
+
+ function resolveDependencyVersion(location, name) {
+ if(location == process.env['NIX_STORE']) {
+ return null;
+ } else {
+ var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json");
+
+ if(fs.existsSync(dependencyPackageJSON)) {
+ var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON));
+
+ if(dependencyPackageObj.name == name) {
+ return dependencyPackageObj.version;
+ }
+ } else {
+ return resolveDependencyVersion(path.resolve(location, ".."), name);
+ }
+ }
+ }
+
+ function replaceDependencies(dependencies) {
+ if(typeof dependencies == "object" && dependencies !== null) {
+ for(var dependency in dependencies) {
+ var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency);
+
+ if(resolvedVersion === null) {
+ process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n");
+ } else {
+ dependencies[dependency] = resolvedVersion;
+ }
+ }
+ }
+ }
+
+ /* Read the package.json configuration */
+ var packageObj = JSON.parse(fs.readFileSync('./package.json'));
+
+ /* Pinpoint all dependencies */
+ replaceDependencies(packageObj.dependencies);
+ if(process.argv[2] == "development") {
+ replaceDependencies(packageObj.devDependencies);
+ }
+ replaceDependencies(packageObj.optionalDependencies);
+
+ /* Write the fixed package.json file */
+ fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2));
+ '';
+ };
+ in
+ ''
+ node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"}
+
+ ${lib.optionalString (dependencies != [])
+ ''
+ if [ -d node_modules ]
+ then
+ cd node_modules
+ ${lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies}
+ cd ..
+ fi
+ ''}
+ '';
+
+ # Recursively traverses all dependencies of a package and pinpoints all
+ # dependencies in the package.json file to the versions that are actually
+ # being used.
+
+ pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args:
+ ''
+ if [ -d "${packageName}" ]
+ then
+ cd "${packageName}"
+ ${pinpointDependencies { inherit dependencies production; }}
+ cd ..
+ ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+ fi
+ '';
+
+ # Extract the Node.js source code which is used to compile packages with
+ # native bindings
+ nodeSources = runCommand "node-sources" {} ''
+ tar --no-same-owner --no-same-permissions -xf ${nodejs.src}
+ mv node-* $out
+ '';
+
+ # Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty)
+ addIntegrityFieldsScript = writeTextFile {
+ name = "addintegrityfields.js";
+ text = ''
+ var fs = require('fs');
+ var path = require('path');
+
+ function augmentDependencies(baseDir, dependencies) {
+ for(var dependencyName in dependencies) {
+ var dependency = dependencies[dependencyName];
+
+ // Open package.json and augment metadata fields
+ var packageJSONDir = path.join(baseDir, "node_modules", dependencyName);
+ var packageJSONPath = path.join(packageJSONDir, "package.json");
+
+ if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored
+ console.log("Adding metadata fields to: "+packageJSONPath);
+ var packageObj = JSON.parse(fs.readFileSync(packageJSONPath));
+
+ if(dependency.integrity) {
+ packageObj["_integrity"] = dependency.integrity;
+ } else {
+ packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads.
+ }
+
+ if(dependency.resolved) {
+ packageObj["_resolved"] = dependency.resolved; // Adopt the resolved property if one has been provided
+ } else {
+ packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories.
+ }
+
+ if(dependency.from !== undefined) { // Adopt from property if one has been provided
+ packageObj["_from"] = dependency.from;
+ }
+
+ fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2));
+ }
+
+ // Augment transitive dependencies
+ if(dependency.dependencies !== undefined) {
+ augmentDependencies(packageJSONDir, dependency.dependencies);
+ }
+ }
+ }
+
+ if(fs.existsSync("./package-lock.json")) {
+ var packageLock = JSON.parse(fs.readFileSync("./package-lock.json"));
+
+ if(![1, 2].includes(packageLock.lockfileVersion)) {
+ process.stderr.write("Sorry, I only understand lock file versions 1 and 2!\n");
+ process.exit(1);
+ }
+
+ if(packageLock.dependencies !== undefined) {
+ augmentDependencies(".", packageLock.dependencies);
+ }
+ }
+ '';
+ };
+
+ # Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes
+ reconstructPackageLock = writeTextFile {
+ name = "addintegrityfields.js";
+ text = ''
+ var fs = require('fs');
+ var path = require('path');
+
+ var packageObj = JSON.parse(fs.readFileSync("package.json"));
+
+ var lockObj = {
+ name: packageObj.name,
+ version: packageObj.version,
+ lockfileVersion: 1,
+ requires: true,
+ dependencies: {}
+ };
+
+ function augmentPackageJSON(filePath, dependencies) {
+ var packageJSON = path.join(filePath, "package.json");
+ if(fs.existsSync(packageJSON)) {
+ var packageObj = JSON.parse(fs.readFileSync(packageJSON));
+ dependencies[packageObj.name] = {
+ version: packageObj.version,
+ integrity: "sha1-000000000000000000000000000=",
+ dependencies: {}
+ };
+ processDependencies(path.join(filePath, "node_modules"), dependencies[packageObj.name].dependencies);
+ }
+ }
+
+ function processDependencies(dir, dependencies) {
+ if(fs.existsSync(dir)) {
+ var files = fs.readdirSync(dir);
+
+ files.forEach(function(entry) {
+ var filePath = path.join(dir, entry);
+ var stats = fs.statSync(filePath);
+
+ if(stats.isDirectory()) {
+ if(entry.substr(0, 1) == "@") {
+ // When we encounter a namespace folder, augment all packages belonging to the scope
+ var pkgFiles = fs.readdirSync(filePath);
+
+ pkgFiles.forEach(function(entry) {
+ if(stats.isDirectory()) {
+ var pkgFilePath = path.join(filePath, entry);
+ augmentPackageJSON(pkgFilePath, dependencies);
+ }
+ });
+ } else {
+ augmentPackageJSON(filePath, dependencies);
+ }
+ }
+ });
+ }
+ }
+
+ processDependencies("node_modules", lockObj.dependencies);
+
+ fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2));
+ '';
+ };
+
+ prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}:
+ let
+ forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
+ in
+ ''
+ # Pinpoint the versions of all dependencies to the ones that are actually being used
+ echo "pinpointing versions of dependencies..."
+ source $pinpointDependenciesScriptPath
+
+ # Patch the shebangs of the bundled modules to prevent them from
+ # calling executables outside the Nix store as much as possible
+ patchShebangs .
+
+ # Deploy the Node.js package by running npm install. Since the
+ # dependencies have been provided already by ourselves, it should not
+ # attempt to install them again, which is good, because we want to make
+ # it Nix's responsibility. If it needs to install any dependencies
+ # anyway (e.g. because the dependency parameters are
+ # incomplete/incorrect), it fails.
+ #
+ # The other responsibilities of NPM are kept -- version checks, build
+ # steps, postprocessing etc.
+
+ export HOME=$TMPDIR
+ cd "${packageName}"
+ runHook preRebuild
+
+ ${lib.optionalString bypassCache ''
+ ${lib.optionalString reconstructLock ''
+ if [ -f package-lock.json ]
+ then
+ echo "WARNING: Reconstruct lock option enabled, but a lock file already exists!"
+ echo "This will most likely result in version mismatches! We will remove the lock file and regenerate it!"
+ rm package-lock.json
+ else
+ echo "No package-lock.json file found, reconstructing..."
+ fi
+
+ node ${reconstructPackageLock}
+ ''}
+
+ node ${addIntegrityFieldsScript}
+ ''}
+
+ npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} rebuild
+
+ if [ "''${dontNpmInstall-}" != "1" ]
+ then
+ # NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
+ rm -f npm-shrinkwrap.json
+
+ npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} install
+ fi
+ '';
+
+ # Builds and composes an NPM package including all its dependencies
+ buildNodePackage =
+ { name
+ , packageName
+ , version
+ , dependencies ? []
+ , buildInputs ? []
+ , production ? true
+ , npmFlags ? ""
+ , dontNpmInstall ? false
+ , bypassCache ? false
+ , reconstructLock ? false
+ , preRebuild ? ""
+ , dontStrip ? true
+ , unpackPhase ? "true"
+ , buildPhase ? "true"
+ , meta ? {}
+ , ... }@args:
+
+ let
+ extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" "meta" ];
+ in
+ stdenv.mkDerivation ({
+ name = "node_${name}-${version}";
+ buildInputs = [ tarWrapper python nodejs ]
+ ++ lib.optional (stdenv.isLinux) utillinux
+ ++ lib.optional (stdenv.isDarwin) libtool
+ ++ buildInputs;
+
+ inherit nodejs;
+
+ inherit dontStrip; # Stripping may fail a build for some package deployments
+ inherit dontNpmInstall preRebuild unpackPhase buildPhase;
+
+ compositionScript = composePackage args;
+ pinpointDependenciesScript = pinpointDependenciesOfPackage args;
+
+ passAsFile = [ "compositionScript" "pinpointDependenciesScript" ];
+
+ installPhase = ''
+ # Create and enter a root node_modules/ folder
+ mkdir -p $out/lib/node_modules
+ cd $out/lib/node_modules
+
+ # Compose the package and all its dependencies
+ source $compositionScriptPath
+
+ ${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
+
+ # Create symlink to the deployed executable folder, if applicable
+ if [ -d "$out/lib/node_modules/.bin" ]
+ then
+ ln -s $out/lib/node_modules/.bin $out/bin
+ fi
+
+ # Create symlinks to the deployed manual page folders, if applicable
+ if [ -d "$out/lib/node_modules/${packageName}/man" ]
+ then
+ mkdir -p $out/share
+ for dir in "$out/lib/node_modules/${packageName}/man/"*
+ do
+ mkdir -p $out/share/man/$(basename "$dir")
+ for page in "$dir"/*
+ do
+ ln -s $page $out/share/man/$(basename "$dir")
+ done
+ done
+ fi
+
+ # Run post install hook, if provided
+ runHook postInstall
+ '';
+
+ meta = {
+ # default to Node.js' platforms
+ platforms = nodejs.meta.platforms;
+ } // meta;
+ } // extraArgs);
+
+ # Builds a node environment (a node_modules folder and a set of binaries)
+ buildNodeDependencies =
+ { name
+ , packageName
+ , version
+ , src
+ , dependencies ? []
+ , buildInputs ? []
+ , production ? true
+ , npmFlags ? ""
+ , dontNpmInstall ? false
+ , bypassCache ? false
+ , reconstructLock ? false
+ , dontStrip ? true
+ , unpackPhase ? "true"
+ , buildPhase ? "true"
+ , ... }@args:
+
+ let
+ extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ];
+ in
+ stdenv.mkDerivation ({
+ name = "node-dependencies-${name}-${version}";
+
+ buildInputs = [ tarWrapper python nodejs ]
+ ++ lib.optional (stdenv.isLinux) utillinux
+ ++ lib.optional (stdenv.isDarwin) libtool
+ ++ buildInputs;
+
+ inherit dontStrip; # Stripping may fail a build for some package deployments
+ inherit dontNpmInstall unpackPhase buildPhase;
+
+ includeScript = includeDependencies { inherit dependencies; };
+ pinpointDependenciesScript = pinpointDependenciesOfPackage args;
+
+ passAsFile = [ "includeScript" "pinpointDependenciesScript" ];
+
+ installPhase = ''
+ mkdir -p $out/${packageName}
+ cd $out/${packageName}
+
+ source $includeScriptPath
+
+ # Create fake package.json to make the npm commands work properly
+ cp ${src}/package.json .
+ chmod 644 package.json
+ ${lib.optionalString bypassCache ''
+ if [ -f ${src}/package-lock.json ]
+ then
+ cp ${src}/package-lock.json .
+ fi
+ ''}
+
+ # Go to the parent folder to make sure that all packages are pinpointed
+ cd ..
+ ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+
+ ${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
+
+ # Expose the executables that were installed
+ cd ..
+ ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+
+ mv ${packageName} lib
+ ln -s $out/lib/node_modules/.bin $out/bin
+ '';
+ } // extraArgs);
+
+ # Builds a development shell
+ buildNodeShell =
+ { name
+ , packageName
+ , version
+ , src
+ , dependencies ? []
+ , buildInputs ? []
+ , production ? true
+ , npmFlags ? ""
+ , dontNpmInstall ? false
+ , bypassCache ? false
+ , reconstructLock ? false
+ , dontStrip ? true
+ , unpackPhase ? "true"
+ , buildPhase ? "true"
+ , ... }@args:
+
+ let
+ nodeDependencies = buildNodeDependencies args;
+ in
+ stdenv.mkDerivation {
+ name = "node-shell-${name}-${version}";
+
+ buildInputs = [ python nodejs ] ++ lib.optional (stdenv.isLinux) utillinux ++ buildInputs;
+ buildCommand = ''
+ mkdir -p $out/bin
+ cat > $out/bin/shell <//archive/.tar.gz"
+ },
+ "niv": {
+ "branch": "master",
+ "description": "Easy dependency management for Nix projects",
+ "homepage": "https://github.com/nmattia/niv",
+ "owner": "nmattia",
+ "repo": "niv",
+ "rev": "e0ca65c81a2d7a4d82a189f1e23a48d59ad42070",
+ "sha256": "1pq9nh1d8nn3xvbdny8fafzw87mj7gsmp6pxkdl65w2g18rmcmzx",
+ "type": "tarball",
+ "url": "https://github.com/nmattia/niv/archive/e0ca65c81a2d7a4d82a189f1e23a48d59ad42070.tar.gz",
+ "url_template": "https://github.com///archive/.tar.gz"
+ },
+ "nixpkgs-20.09": {
+ "branch": "nixos-20.09",
+ "description": "Nix Packages collection",
+ "homepage": "",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "068984c00e0d4e54b6684d98f6ac47c92dcb642e",
+ "sha256": "00j4xv4lhhqwry7jd67brnws4pwb8vn660n43pvxpkalbpxszwfg",
+ "type": "tarball",
+ "url": "https://github.com/nixos/nixpkgs/archive/068984c00e0d4e54b6684d98f6ac47c92dcb642e.tar.gz",
+ "url_template": "https://github.com///archive/.tar.gz"
+ },
+ "nixpkgs-21.05": {
+ "branch": "release-21.05",
+ "description": "Nix Packages collection",
+ "homepage": "",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "1672da0dfdb2e3146f36ffa923aa05d8a5606134",
+ "sha256": "1h103ka8xm82zhdzmrpmhy3fb7chgqr8j76rdmbhqgi365zz9gw7",
+ "type": "tarball",
+ "url": "https://github.com/NixOS/nixpkgs/archive/1672da0dfdb2e3146f36ffa923aa05d8a5606134.tar.gz",
+ "url_template": "https://github.com///archive/.tar.gz"
+ },
+ "nixpkgs-unstable": {
+ "branch": "master",
+ "description": "Nix Packages collection",
+ "homepage": "",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "f47e3311b31cf394d8835574ae928ba1230920d0",
+ "sha256": "0qclvvhyz3x3g0d44h2fdzaqsagbv1m66bl90in57s07g126ychs",
+ "type": "tarball",
+ "url": "https://github.com/NixOS/nixpkgs/archive/f47e3311b31cf394d8835574ae928ba1230920d0.tar.gz",
+ "url_template": "https://github.com///archive/.tar.gz"
+ },
+ "node2nix": {
+ "branch": "master",
+ "description": "Generate Nix expressions to build NPM packages",
+ "homepage": "",
+ "owner": "svanderburg",
+ "repo": "node2nix",
+ "rev": "0c94281ea98f1b17532176106f90f909aa133704",
+ "sha256": "1r677r7sqjp5hg7rs7wall6nipka3pnrglnjdaj098v1xhswzjbx",
+ "type": "tarball",
+ "url": "https://github.com/svanderburg/node2nix/archive/0c94281ea98f1b17532176106f90f909aa133704.tar.gz",
+ "url_template": "https://github.com///archive/.tar.gz"
+ },
+ "poetry2nix": {
+ "branch": "master",
+ "description": "Convert poetry projects to nix automagically [maintainer=@adisbladis] ",
+ "homepage": "",
+ "owner": "nix-community",
+ "repo": "poetry2nix",
+ "rev": "e40e8ed0e8c11e709e4c8c7c20174facd265a021",
+ "sha256": "152cj4w2jdlrj2k4x1vnspa4vbjqa0jrdr7xhmjjlv7ywdl60kfq",
+ "type": "tarball",
+ "url": "https://github.com/nix-community/poetry2nix/archive/e40e8ed0e8c11e709e4c8c7c20174facd265a021.tar.gz",
+ "url_template": "https://github.com///archive/.tar.gz"
+ },
+ "rcc": {
+ "branch": "v9.16.0",
+ "description": "RCC is a set of tooling that allows you to create, manage, and distribute Python-based self-contained automation packages - or 'robots' as we call them.",
+ "homepage": "https://robocorp.com/docs/product-manuals/robocorp-cli",
+ "owner": "robocorp",
+ "repo": "rcc",
+ "rev": "94546d47817347865ffeabbaf1f82bffae2b4f89",
+ "sha256": "1cygw4s9abqknbrggqy8n8rjkjhcanhc0k1qmm29pnw1b8mrx5ps",
+ "type": "tarball",
+ "url": "https://github.com/robocorp/rcc/archive/94546d47817347865ffeabbaf1f82bffae2b4f89.tar.gz",
+ "url_template": "https://github.com///archive/.tar.gz"
+ }
+}
diff --git a/nix/sources.nix b/nix/sources.nix
new file mode 100644
index 0000000..b64b8f8
--- /dev/null
+++ b/nix/sources.nix
@@ -0,0 +1,148 @@
+# This file has been generated by Niv.
+
+let
+
+ #
+ # The fetchers. fetch_ fetches specs of type .
+ #
+
+ fetch_file = pkgs: spec:
+ if spec.builtin or true then
+ builtins_fetchurl { inherit (spec) url sha256; }
+ else
+ pkgs.fetchurl { inherit (spec) url sha256; };
+
+ fetch_tarball = pkgs: name: spec:
+ let
+ ok = str: ! builtins.isNull (builtins.match "[a-zA-Z0-9+-._?=]" str);
+ # sanitize the name, though nix will still fail if name starts with period
+ name' = stringAsChars (x: if ! ok x then "-" else x) "${name}-src";
+ in
+ if spec.builtin or true then
+ builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
+ else
+ pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
+
+ fetch_git = spec:
+ builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };
+
+ fetch_local = spec: spec.path;
+
+ fetch_builtin-tarball = name: throw
+ ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
+ $ niv modify ${name} -a type=tarball -a builtin=true'';
+
+ fetch_builtin-url = name: throw
+ ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
+ $ niv modify ${name} -a type=file -a builtin=true'';
+
+ #
+ # Various helpers
+ #
+
+ # The set of packages used when specs are fetched using non-builtins.
+ mkPkgs = sources:
+ let
+ sourcesNixpkgs =
+ import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {};
+ hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
+ hasThisAsNixpkgsPath = == ./.;
+ in
+ if builtins.hasAttr "nixpkgs" sources
+ then sourcesNixpkgs
+ else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
+ import {}
+ else
+ abort
+ ''
+ Please specify either (through -I or NIX_PATH=nixpkgs=...) or
+ add a package called "nixpkgs" to your sources.json.
+ '';
+
+ # The actual fetching function.
+ fetch = pkgs: name: spec:
+
+ if ! builtins.hasAttr "type" spec then
+ abort "ERROR: niv spec ${name} does not have a 'type' attribute"
+ else if spec.type == "file" then fetch_file pkgs spec
+ else if spec.type == "tarball" then fetch_tarball pkgs name spec
+ else if spec.type == "git" then fetch_git spec
+ else if spec.type == "local" then fetch_local spec
+ else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
+ else if spec.type == "builtin-url" then fetch_builtin-url name
+ else
+ abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
+
+ # If the environment variable NIV_OVERRIDE_${name} is set, then use
+ # the path directly as opposed to the fetched source.
+ replace = name: drv:
+ let
+ saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
+ ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
+ in
+ if ersatz == "" then drv else ersatz;
+
+ # Ports of functions for older nix versions
+
+ # a Nix version of mapAttrs if the built-in doesn't exist
+ mapAttrs = builtins.mapAttrs or (
+ f: set: with builtins;
+ listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
+ );
+
+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
+ range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
+
+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
+ stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
+
+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
+ stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
+ concatStrings = builtins.concatStringsSep "";
+
+ # fetchTarball version that is compatible between all the versions of Nix
+ builtins_fetchTarball = { url, name, sha256 }@attrs:
+ let
+ inherit (builtins) lessThan nixVersion fetchTarball;
+ in
+ if lessThan nixVersion "1.12" then
+ fetchTarball { inherit name url; }
+ else
+ fetchTarball attrs;
+
+ # fetchurl version that is compatible between all the versions of Nix
+ builtins_fetchurl = { url, sha256 }@attrs:
+ let
+ inherit (builtins) lessThan nixVersion fetchurl;
+ in
+ if lessThan nixVersion "1.12" then
+ fetchurl { inherit url; }
+ else
+ fetchurl attrs;
+
+ # Create the final "sources" from the config
+ mkSources = config:
+ mapAttrs (
+ name: spec:
+ if builtins.hasAttr "outPath" spec
+ then abort
+ "The values in sources.json should not have an 'outPath' attribute"
+ else
+ spec // { outPath = replace name (fetch config.pkgs name spec); }
+ ) config.sources;
+
+ # The "config" used by the fetchers
+ mkConfig =
+ { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
+ , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
+ , pkgs ? mkPkgs sources
+ }: rec {
+ # The sources, i.e. the attribute set of spec name to spec
+ inherit sources;
+
+ # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
+ inherit pkgs;
+ };
+
+in
+mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..9e78104
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1395 @@
+{
+ "name": "carrot-rcc",
+ "version": "0.8.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
+ "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.14.5"
+ }
+ },
+ "@babel/compat-data": {
+ "version": "7.14.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz",
+ "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==",
+ "dev": true
+ },
+ "@babel/core": {
+ "version": "7.14.6",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz",
+ "integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.14.5",
+ "@babel/generator": "^7.14.5",
+ "@babel/helper-compilation-targets": "^7.14.5",
+ "@babel/helper-module-transforms": "^7.14.5",
+ "@babel/helpers": "^7.14.6",
+ "@babel/parser": "^7.14.6",
+ "@babel/template": "^7.14.5",
+ "@babel/traverse": "^7.14.5",
+ "@babel/types": "^7.14.5",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.1.2",
+ "semver": "^6.3.0",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/generator": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz",
+ "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.14.5",
+ "jsesc": "^2.5.1",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/helper-compilation-targets": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz",
+ "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==",
+ "dev": true,
+ "requires": {
+ "@babel/compat-data": "^7.14.5",
+ "@babel/helper-validator-option": "^7.14.5",
+ "browserslist": "^4.16.6",
+ "semver": "^6.3.0"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz",
+ "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.14.5",
+ "@babel/template": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz",
+ "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-hoist-variables": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz",
+ "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-member-expression-to-functions": {
+ "version": "7.14.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz",
+ "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-module-imports": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz",
+ "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-module-transforms": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz",
+ "integrity": "sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.14.5",
+ "@babel/helper-replace-supers": "^7.14.5",
+ "@babel/helper-simple-access": "^7.14.5",
+ "@babel/helper-split-export-declaration": "^7.14.5",
+ "@babel/helper-validator-identifier": "^7.14.5",
+ "@babel/template": "^7.14.5",
+ "@babel/traverse": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-optimise-call-expression": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz",
+ "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-replace-supers": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz",
+ "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-member-expression-to-functions": "^7.14.5",
+ "@babel/helper-optimise-call-expression": "^7.14.5",
+ "@babel/traverse": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-simple-access": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz",
+ "integrity": "sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz",
+ "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
+ "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
+ "dev": true
+ },
+ "@babel/helper-validator-option": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz",
+ "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==",
+ "dev": true
+ },
+ "@babel/helpers": {
+ "version": "7.14.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz",
+ "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.14.5",
+ "@babel/traverse": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
+ "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.14.5",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.14.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz",
+ "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==",
+ "dev": true
+ },
+ "@babel/template": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz",
+ "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.14.5",
+ "@babel/parser": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.14.7",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.7.tgz",
+ "integrity": "sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.14.5",
+ "@babel/generator": "^7.14.5",
+ "@babel/helper-function-name": "^7.14.5",
+ "@babel/helper-hoist-variables": "^7.14.5",
+ "@babel/helper-split-export-declaration": "^7.14.5",
+ "@babel/parser": "^7.14.7",
+ "@babel/types": "^7.14.5",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0"
+ }
+ },
+ "@babel/types": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz",
+ "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.14.5",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "@rollup/plugin-commonjs": {
+ "version": "19.0.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-19.0.0.tgz",
+ "integrity": "sha512-adTpD6ATGbehdaQoZQ6ipDFhdjqsTgpOAhFiPwl+dzre4pPshsecptDPyEFb61JMJ1+mGljktaC4jI8ARMSNyw==",
+ "dev": true,
+ "requires": {
+ "@rollup/pluginutils": "^3.1.0",
+ "commondir": "^1.0.1",
+ "estree-walker": "^2.0.1",
+ "glob": "^7.1.6",
+ "is-reference": "^1.2.1",
+ "magic-string": "^0.25.7",
+ "resolve": "^1.17.0"
+ },
+ "dependencies": {
+ "estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true
+ }
+ }
+ },
+ "@rollup/plugin-json": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz",
+ "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==",
+ "dev": true,
+ "requires": {
+ "@rollup/pluginutils": "^3.0.8"
+ }
+ },
+ "@rollup/plugin-node-resolve": {
+ "version": "13.0.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.0.tgz",
+ "integrity": "sha512-41X411HJ3oikIDivT5OKe9EZ6ud6DXudtfNrGbC4nniaxx2esiWjkLOzgnZsWq1IM8YIeL2rzRGLZLBjlhnZtQ==",
+ "dev": true,
+ "requires": {
+ "@rollup/pluginutils": "^3.1.0",
+ "@types/resolve": "1.17.1",
+ "builtin-modules": "^3.1.0",
+ "deepmerge": "^4.2.2",
+ "is-module": "^1.0.0",
+ "resolve": "^1.19.0"
+ }
+ },
+ "@rollup/plugin-replace": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz",
+ "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==",
+ "dev": true,
+ "requires": {
+ "@rollup/pluginutils": "^3.1.0",
+ "magic-string": "^0.25.7"
+ }
+ },
+ "@rollup/plugin-typescript": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.2.1.tgz",
+ "integrity": "sha512-Qd2E1pleDR4bwyFxqbjt4eJf+wB0UKVMLc7/BAFDGVdAXQMCsD4DUv5/7/ww47BZCYxWtJqe1Lo0KVNswBJlRw==",
+ "dev": true,
+ "requires": {
+ "@rollup/pluginutils": "^3.1.0",
+ "resolve": "^1.17.0"
+ }
+ },
+ "@rollup/pluginutils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
+ "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
+ "dev": true,
+ "requires": {
+ "@types/estree": "0.0.39",
+ "estree-walker": "^1.0.1",
+ "picomatch": "^2.2.2"
+ }
+ },
+ "@sindresorhus/is": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz",
+ "integrity": "sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg=="
+ },
+ "@szmarczak/http-timer": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz",
+ "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==",
+ "requires": {
+ "defer-to-connect": "^2.0.0"
+ }
+ },
+ "@types/adm-zip": {
+ "version": "0.4.34",
+ "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.34.tgz",
+ "integrity": "sha512-8ToYLLAYhkRfcmmljrKi22gT2pqu7hGMDtORP1emwIEGmgUTZOsaDjzWFzW5N2frcFRz/50CWt4zA1CxJ73pmQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/cacheable-request": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz",
+ "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==",
+ "requires": {
+ "@types/http-cache-semantics": "*",
+ "@types/keyv": "*",
+ "@types/node": "*",
+ "@types/responselike": "*"
+ }
+ },
+ "@types/camunda-external-task-client-js": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@types/camunda-external-task-client-js/-/camunda-external-task-client-js-1.3.1.tgz",
+ "integrity": "sha512-XWktJOGel1HIIgKB3Y7Y2CQMQrIB0XXFnK4j+zIj5KjqcAxw6p+uXHKCzOVobvBTbsvAYuaVBr2MvXuGRgCiKA==",
+ "dev": true
+ },
+ "@types/dotenv": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-8.2.0.tgz",
+ "integrity": "sha512-ylSC9GhfRH7m1EUXBXofhgx4lUWmFeQDINW5oLuS+gxWdfUeW4zJdeVTYVkexEW+e2VUvlZR2kGnGGipAWR7kw==",
+ "dev": true,
+ "requires": {
+ "dotenv": "*"
+ }
+ },
+ "@types/estree": {
+ "version": "0.0.39",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+ "dev": true
+ },
+ "@types/http-cache-semantics": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz",
+ "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A=="
+ },
+ "@types/keyv": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz",
+ "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/mime-types": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz",
+ "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=",
+ "dev": true
+ },
+ "@types/node": {
+ "version": "15.12.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.5.tgz",
+ "integrity": "sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg=="
+ },
+ "@types/resolve": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
+ "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/responselike": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
+ "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/yaml": {
+ "version": "1.9.7",
+ "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz",
+ "integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==",
+ "dev": true,
+ "requires": {
+ "yaml": "*"
+ }
+ },
+ "adm-zip": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.5.tgz",
+ "integrity": "sha512-IWwXKnCbirdbyXSfUDvCCrmYrOHANRZcc8NcRrvTlIApdl7PwE9oGcsYvNeJPAVY1M+70b4PxXGKIf8AEuiQ6w=="
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "browserslist": {
+ "version": "4.16.6",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
+ "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30001219",
+ "colorette": "^1.2.2",
+ "electron-to-chromium": "^1.3.723",
+ "escalade": "^3.1.1",
+ "node-releases": "^1.1.71"
+ }
+ },
+ "builtin-modules": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
+ "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
+ "dev": true
+ },
+ "cacheable-lookup": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz",
+ "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==",
+ "requires": {
+ "@types/keyv": "^3.1.1",
+ "keyv": "^4.0.0"
+ }
+ },
+ "cacheable-request": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz",
+ "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==",
+ "requires": {
+ "clone-response": "^1.0.2",
+ "get-stream": "^5.1.0",
+ "http-cache-semantics": "^4.0.0",
+ "keyv": "^4.0.0",
+ "lowercase-keys": "^2.0.0",
+ "normalize-url": "^6.0.1",
+ "responselike": "^2.0.0"
+ }
+ },
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
+ "caller-callsite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+ "dev": true,
+ "requires": {
+ "callsites": "^2.0.0"
+ }
+ },
+ "caller-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+ "dev": true,
+ "requires": {
+ "caller-callsite": "^2.0.0"
+ }
+ },
+ "callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
+ "dev": true
+ },
+ "camunda-external-task-client-js": {
+ "version": "git+https://github.com/camunda/camunda-external-task-client-js.git#5923f9a3e98af20aedb3481662f3fdc8f9ef9f81",
+ "from": "git+https://github.com/camunda/camunda-external-task-client-js.git#5923f9a3e98af20aedb3481662f3fdc8f9ef9f81",
+ "requires": {
+ "chalk": "^2.3.2",
+ "got": "^10.6.0"
+ }
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001241",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001241.tgz",
+ "integrity": "sha512-1uoSZ1Pq1VpH0WerIMqwptXHNNGfdl7d1cJUFs80CwQ/lVzdhTvsFZCeNFslze7AjsQnb4C85tzclPa1VShbeQ==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "clone-response": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
+ "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
+ "requires": {
+ "mimic-response": "^1.0.0"
+ },
+ "dependencies": {
+ "mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="
+ }
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+ },
+ "colorette": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
+ "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==",
+ "dev": true
+ },
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "convert-source-map": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
+ "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ }
+ }
+ },
+ "cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dev": true,
+ "requires": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ }
+ },
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "decompress-response": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz",
+ "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==",
+ "requires": {
+ "mimic-response": "^2.0.0"
+ }
+ },
+ "deepmerge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+ "dev": true
+ },
+ "defer-to-connect": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+ "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="
+ },
+ "detect-newline": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
+ "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=",
+ "dev": true
+ },
+ "dotenv": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
+ "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
+ },
+ "duplexer3": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
+ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
+ },
+ "electron-to-chromium": {
+ "version": "1.3.763",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.763.tgz",
+ "integrity": "sha512-UyvEPae0wvzsyNJhVfGeFSOlUkHEze8xSIiExO5tZQ8QTr7obFiJWGk3U4e7afFOJMQJDszqU/3Pk5jtKiaSEg==",
+ "dev": true
+ },
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ },
+ "dependencies": {
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ }
+ }
+ },
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "estree-walker": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
+ "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
+ "dev": true
+ },
+ "fdir": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-5.1.0.tgz",
+ "integrity": "sha512-IgTtZwL52tx2wqWeuGDzXYTnNsEjNLahZpJw30hCQDyVnoHXwY5acNDnjGImTTL1R0z1PCyLw20VAbE5qLic3Q=="
+ },
+ "find-line-column": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/find-line-column/-/find-line-column-0.5.2.tgz",
+ "integrity": "sha1-2wAjj/hoVRoYLnShA0FtKVqYyMo=",
+ "dev": true
+ },
+ "find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "dev": true
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true
+ },
+ "get-intrinsic": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+ "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.7",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+ "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true
+ },
+ "got": {
+ "version": "10.7.0",
+ "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz",
+ "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==",
+ "requires": {
+ "@sindresorhus/is": "^2.0.0",
+ "@szmarczak/http-timer": "^4.0.0",
+ "@types/cacheable-request": "^6.0.1",
+ "cacheable-lookup": "^2.0.0",
+ "cacheable-request": "^7.0.1",
+ "decompress-response": "^5.0.0",
+ "duplexer3": "^0.1.4",
+ "get-stream": "^5.0.0",
+ "lowercase-keys": "^2.0.0",
+ "mimic-response": "^2.1.0",
+ "p-cancelable": "^2.0.0",
+ "p-event": "^4.0.0",
+ "responselike": "^2.0.0",
+ "to-readable-stream": "^2.0.0",
+ "type-fest": "^0.10.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ },
+ "has-symbols": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
+ },
+ "http-cache-semantics": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
+ "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ=="
+ },
+ "import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+ "dev": true,
+ "requires": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ },
+ "dependencies": {
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+ "dev": true
+ }
+ }
+ },
+ "import-sort": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/import-sort/-/import-sort-6.0.0.tgz",
+ "integrity": "sha512-XUwSQMGAGmcW/wfshFE0gXgb1NPF6ibbQD6wDr3KRDykZf/lZj0jf58Bwa02xNb8EE59oz7etFe9OHnJocUW5Q==",
+ "dev": true,
+ "requires": {
+ "detect-newline": "^2.1.0",
+ "import-sort-parser": "^6.0.0",
+ "import-sort-style": "^6.0.0",
+ "is-builtin-module": "^3.0.0",
+ "resolve": "^1.8.1"
+ }
+ },
+ "import-sort-config": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/import-sort-config/-/import-sort-config-6.0.0.tgz",
+ "integrity": "sha512-FJpF2F3+30JXqH1rJKeajxoSCHCueai3/0ntDN4y3GJL5pjnLDt/VjCy5FzjH7u0NHnllL/zVEf1wfmsVxJlPQ==",
+ "dev": true,
+ "requires": {
+ "cosmiconfig": "^5.0.5",
+ "find-root": "^1.0.0",
+ "minimatch": "^3.0.4",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "import-sort-parser": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/import-sort-parser/-/import-sort-parser-6.0.0.tgz",
+ "integrity": "sha512-H5L+d6HnqHvThB0GmAA3/43Sv74oCwL0iMk3/ixOv0LRJ69rCyHXeG/+UadMHrD2FefEmgPIWboEPAG7gsQrkA==",
+ "dev": true
+ },
+ "import-sort-parser-babylon": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/import-sort-parser-babylon/-/import-sort-parser-babylon-6.0.0.tgz",
+ "integrity": "sha512-NyShTiNhTh4Vy7kJUVe6CuvOaQAzzfSIT72wtp3CzGjz8bHjNj59DCAjncuviicmDOgVAgmLuSh1WMcLYAMWGg==",
+ "dev": true,
+ "requires": {
+ "@babel/core": "^7.2.2",
+ "@babel/parser": "^7.0.0-beta.54",
+ "@babel/traverse": "^7.0.0-beta.54",
+ "@babel/types": "^7.0.0-beta.54",
+ "find-line-column": "^0.5.2"
+ }
+ },
+ "import-sort-parser-typescript": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/import-sort-parser-typescript/-/import-sort-parser-typescript-6.0.0.tgz",
+ "integrity": "sha512-pgxnr3I156DonupQriNsgDb2zJN9TxrqCCIN1rwT/6SDO1rkJb+a0fjqshCjlgacTSA92oPAp1eAwmQUeZi3dw==",
+ "dev": true,
+ "requires": {
+ "typescript": "^3.2.4"
+ },
+ "dependencies": {
+ "typescript": {
+ "version": "3.9.10",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz",
+ "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
+ "dev": true
+ }
+ }
+ },
+ "import-sort-style": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/import-sort-style/-/import-sort-style-6.0.0.tgz",
+ "integrity": "sha512-z0H5PKs7YoDeKxNYXv2AA1mjjZFY07fjeNCXUdTM3ymJtWeeEoTm8CQkFm2l+KPZoMczIvdwzJpWkkOamBnsPw==",
+ "dev": true
+ },
+ "import-sort-style-module": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/import-sort-style-module/-/import-sort-style-module-6.0.0.tgz",
+ "integrity": "sha512-Oxd256EVt6TAgawhIDuKnNHWumzHMHFWhVncBBvlHVnx69B4GP/Gu4Xo+gjxtqSEKEvam5ajUkNvnsXLDMDjKg==",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "is-builtin-module": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.1.0.tgz",
+ "integrity": "sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==",
+ "dev": true,
+ "requires": {
+ "builtin-modules": "^3.0.0"
+ }
+ },
+ "is-core-module": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz",
+ "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
+ "dev": true
+ },
+ "is-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+ "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
+ "dev": true
+ },
+ "is-reference": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+ "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
+ "dev": true,
+ "requires": {
+ "@types/estree": "*"
+ }
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true
+ },
+ "json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "json5": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
+ "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "keyv": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz",
+ "integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==",
+ "requires": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "lowercase-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="
+ },
+ "magic-string": {
+ "version": "0.25.7",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
+ "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
+ "dev": true,
+ "requires": {
+ "sourcemap-codec": "^1.4.4"
+ }
+ },
+ "mime-db": {
+ "version": "1.48.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
+ "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
+ },
+ "mime-types": {
+ "version": "2.1.31",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
+ "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
+ "requires": {
+ "mime-db": "1.48.0"
+ }
+ },
+ "mimic-response": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "neodoc": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/neodoc/-/neodoc-2.0.2.tgz",
+ "integrity": "sha512-NAppJ0YecKWdhSXFYCHbo6RutiX8vOt/Jo3l46mUg6pQlpJNaqc5cGxdrW2jITQm5JIYySbFVPDl3RrREXNyPw==",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "node-releases": {
+ "version": "1.1.73",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
+ "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==",
+ "dev": true
+ },
+ "normalize-url": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
+ "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="
+ },
+ "object-inspect": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
+ "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw=="
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "p-cancelable": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
+ "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="
+ },
+ "p-event": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz",
+ "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==",
+ "requires": {
+ "p-timeout": "^3.1.0"
+ }
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+ },
+ "p-timeout": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
+ "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
+ "requires": {
+ "p-finally": "^1.0.0"
+ }
+ },
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
+ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
+ "dev": true
+ },
+ "prettier": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz",
+ "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==",
+ "dev": true
+ },
+ "prettier-plugin-import-sort": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-import-sort/-/prettier-plugin-import-sort-0.0.7.tgz",
+ "integrity": "sha512-O0KlUSq+lwvh+UiN3wZDT6wWkf7TNxTVv2/XXE5KqpRNbFJq3nRg2ftzBYFFO8QGpdWIrOB0uCTCtFjIxmVKQw==",
+ "dev": true,
+ "requires": {
+ "import-sort": "^6.0.0",
+ "import-sort-config": "^6.0.0",
+ "import-sort-parser-babylon": "^6.0.0",
+ "import-sort-parser-typescript": "^6.0.0"
+ }
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "qs": {
+ "version": "6.10.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
+ "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "resolve": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+ "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.2.0",
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "responselike": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz",
+ "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==",
+ "requires": {
+ "lowercase-keys": "^2.0.0"
+ }
+ },
+ "rollup": {
+ "version": "2.52.7",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.7.tgz",
+ "integrity": "sha512-55cSH4CCU6MaPr9TAOyrIC+7qFCHscL7tkNsm1MBfIJRRqRbCEY0mmeFn4Wg8FKsHtEH8r389Fz38r/o+kgXLg==",
+ "dev": true,
+ "requires": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "rollup-plugin-hashbang": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-hashbang/-/rollup-plugin-hashbang-2.2.2.tgz",
+ "integrity": "sha512-Yxw9ogeK3KncG1e4CvK0I0IKVBNeJP+DTZS3bExGTfGjw0WP1C7xxbY7LtRd8IKx4fFf53hz7XR1XG7UV6xqCw==",
+ "requires": {
+ "magic-string": "^0.22.4"
+ },
+ "dependencies": {
+ "magic-string": {
+ "version": "0.22.5",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
+ "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==",
+ "requires": {
+ "vlq": "^0.2.2"
+ }
+ }
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "dev": true
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+ "dev": true
+ },
+ "to-readable-stream": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz",
+ "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w=="
+ },
+ "tslib": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+ "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
+ "dev": true
+ },
+ "tunnel": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
+ },
+ "type-fest": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz",
+ "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw=="
+ },
+ "typed-rest-client": {
+ "version": "1.8.4",
+ "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.4.tgz",
+ "integrity": "sha512-MyfKKYzk3I6/QQp6e1T50py4qg+c+9BzOEl2rBmQIpStwNUoqQ73An+Tkfy9YuV7O+o2mpVVJpe+fH//POZkbg==",
+ "requires": {
+ "qs": "^6.9.1",
+ "tunnel": "0.0.6",
+ "underscore": "^1.12.1"
+ }
+ },
+ "typescript": {
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
+ "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
+ "dev": true
+ },
+ "underscore": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz",
+ "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g=="
+ },
+ "vlq": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
+ "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow=="
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..fd00f0a
--- /dev/null
+++ b/package.json
@@ -0,0 +1,59 @@
+{
+ "name": "carrot-rcc",
+ "version": "0.8.0",
+ "description": "Camunda external task Robot Framework RCC client",
+ "bin": "./carrot-rcc",
+ "scripts": {
+ "build": "rollup -c rollup.config.js",
+ "prettier:check": "prettier --check \"*.ts\"",
+ "prettier:format": "prettier --write \"*.ts\"",
+ "start": "tsc -w",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/datakurre/carrot-rcc.git"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/datakurre/carrot-rcc.git"
+ },
+ "homepage": "https://github.com/datakurre/carrot-rcc#readme",
+ "importSort": {
+ ".js, .ts": {
+ "style": "module",
+ "parser": "typescript"
+ }
+ },
+ "dependencies": {
+ "adm-zip": "^0.5.5",
+ "camunda-external-task-client-js": "git+https://github.com/camunda/camunda-external-task-client-js.git#5923f9a3e98af20aedb3481662f3fdc8f9ef9f81",
+ "dotenv": "^10.0.0",
+ "fdir": "^5.1.0",
+ "mime-types": "^2.1.31",
+ "neodoc": "^2.0.2",
+ "rollup-plugin-hashbang": "^2.2.2",
+ "typed-rest-client": "^1.8.4",
+ "yaml": "^1.10.2"
+ },
+ "devDependencies": {
+ "@rollup/plugin-commonjs": "^19.0.0",
+ "@rollup/plugin-json": "^4.1.0",
+ "@rollup/plugin-node-resolve": "^13.0.0",
+ "@rollup/plugin-replace": "^2.4.2",
+ "@rollup/plugin-typescript": "^8.2.1",
+ "@types/adm-zip": "^0.4.34",
+ "@types/camunda-external-task-client-js": "^1.3.1",
+ "@types/dotenv": "^8.2.0",
+ "@types/mime-types": "^2.1.0",
+ "@types/yaml": "^1.9.7",
+ "import-sort-style-module": "^6.0.0",
+ "prettier": "^2.3.2",
+ "prettier-plugin-import-sort": "0.0.7",
+ "rollup": "^2.52.7",
+ "tslib": "^2.3.0",
+ "typescript": "^4.3.5"
+ }
+}
diff --git a/poetry.lock b/poetry.lock
new file mode 100644
index 0000000..c928128
--- /dev/null
+++ b/poetry.lock
@@ -0,0 +1,158 @@
+[[package]]
+name = "appdirs"
+version = "1.4.4"
+description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "black"
+version = "21.7b0"
+description = "The uncompromising code formatter."
+category = "dev"
+optional = false
+python-versions = ">=3.6.2"
+
+[package.dependencies]
+appdirs = "*"
+click = ">=7.1.2"
+mypy-extensions = ">=0.4.3"
+pathspec = ">=0.8.1,<1"
+regex = ">=2020.1.8"
+tomli = ">=0.2.6,<2.0.0"
+
+[package.extras]
+colorama = ["colorama (>=0.4.3)"]
+d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"]
+python2 = ["typed-ast (>=1.4.2)"]
+uvloop = ["uvloop (>=0.15.2)"]
+
+[[package]]
+name = "click"
+version = "8.0.1"
+description = "Composable command line interface toolkit"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "colorama"
+version = "0.4.4"
+description = "Cross-platform colored terminal text."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "mypy-extensions"
+version = "0.4.3"
+description = "Experimental type system extensions for programs checked with the mypy typechecker."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "pathspec"
+version = "0.9.0"
+description = "Utility library for gitignore style pattern matching of file paths."
+category = "dev"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+
+[[package]]
+name = "regex"
+version = "2021.7.6"
+description = "Alternative regular expression module, to replace re."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "tomli"
+version = "1.0.4"
+description = "A lil' TOML parser"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[metadata]
+lock-version = "1.1"
+python-versions = "^3.8"
+content-hash = "ad5d87d736580d5969d332f6293d5167ac9ee7f8be95761cd478e3b267da6d91"
+
+[metadata.files]
+appdirs = [
+ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
+ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
+]
+black = [
+ {file = "black-21.7b0-py3-none-any.whl", hash = "sha256:1c7aa6ada8ee864db745b22790a32f94b2795c253a75d6d9b5e439ff10d23116"},
+ {file = "black-21.7b0.tar.gz", hash = "sha256:c8373c6491de9362e39271630b65b964607bc5c79c83783547d76c839b3aa219"},
+]
+click = [
+ {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"},
+ {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"},
+]
+colorama = [
+ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
+ {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
+]
+mypy-extensions = [
+ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
+ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
+]
+pathspec = [
+ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
+ {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
+]
+regex = [
+ {file = "regex-2021.7.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874"},
+ {file = "regex-2021.7.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854"},
+ {file = "regex-2021.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2"},
+ {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d"},
+ {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d"},
+ {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa"},
+ {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222"},
+ {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407"},
+ {file = "regex-2021.7.6-cp36-cp36m-win32.whl", hash = "sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b"},
+ {file = "regex-2021.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb"},
+ {file = "regex-2021.7.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d"},
+ {file = "regex-2021.7.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d"},
+ {file = "regex-2021.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0"},
+ {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec"},
+ {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694"},
+ {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a"},
+ {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad"},
+ {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895"},
+ {file = "regex-2021.7.6-cp37-cp37m-win32.whl", hash = "sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5"},
+ {file = "regex-2021.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f"},
+ {file = "regex-2021.7.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c"},
+ {file = "regex-2021.7.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0"},
+ {file = "regex-2021.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26"},
+ {file = "regex-2021.7.6-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f"},
+ {file = "regex-2021.7.6-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf"},
+ {file = "regex-2021.7.6-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd"},
+ {file = "regex-2021.7.6-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761"},
+ {file = "regex-2021.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068"},
+ {file = "regex-2021.7.6-cp38-cp38-win32.whl", hash = "sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0"},
+ {file = "regex-2021.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4"},
+ {file = "regex-2021.7.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026"},
+ {file = "regex-2021.7.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417"},
+ {file = "regex-2021.7.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde"},
+ {file = "regex-2021.7.6-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59"},
+ {file = "regex-2021.7.6-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985"},
+ {file = "regex-2021.7.6-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d"},
+ {file = "regex-2021.7.6-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58"},
+ {file = "regex-2021.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3"},
+ {file = "regex-2021.7.6-cp39-cp39-win32.whl", hash = "sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035"},
+ {file = "regex-2021.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c"},
+ {file = "regex-2021.7.6.tar.gz", hash = "sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d"},
+]
+tomli = [
+ {file = "tomli-1.0.4-py3-none-any.whl", hash = "sha256:0713b16ff91df8638a6a694e295c8159ab35ba93e3424a626dd5226d386057be"},
+ {file = "tomli-1.0.4.tar.gz", hash = "sha256:be670d0d8d7570fd0ea0113bd7bb1ba3ac6706b4de062cc4c952769355c9c268"},
+]
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..466762d
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,25 @@
+[tool.poetry]
+name = "carrot-rcc"
+version = "0.1.0"
+description = "Camunda external task Robot Framework RCC client"
+homepage = "https://github.com/datakurre/carrot-executor/main/rcc"
+authors = ["Asko Soukka "]
+license = "MIT"
+packages = [
+ { include = "carrot_rcc.py" },
+]
+include = [ "CHANGELOG.md", "carrot-rcc" ]
+readme = "README.md"
+
+[tool.poetry.scripts]
+carrot-rcc= "carrot_rcc:main"
+
+[tool.poetry.dependencies]
+python = "^3.8"
+
+[tool.poetry.dev-dependencies]
+black = "^21.6b0"
+
+[build-system]
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
diff --git a/rollup.config.js b/rollup.config.js
new file mode 100644
index 0000000..0c8cd33
--- /dev/null
+++ b/rollup.config.js
@@ -0,0 +1,29 @@
+import commonjs from "@rollup/plugin-commonjs";
+import json from "@rollup/plugin-json";
+import replace from "@rollup/plugin-replace";
+import resolve from "@rollup/plugin-node-resolve";
+import typescript from "@rollup/plugin-typescript";
+import hashbang from 'rollup-plugin-hashbang'
+
+const plugins = [
+ replace({
+ "process.env.NODE_ENV": JSON.stringify("production"),
+ preventAssignment: true
+ }),
+ resolve(),
+ json(),
+ commonjs({ignore: ['original-fs']}),
+ typescript(),
+ hashbang(),
+];
+
+export default [
+ {
+ input: "carrot_rcc.ts",
+ output: {
+ file: "carrot-rcc",
+ format: "cjs"
+ },
+ plugins,
+ },
+];
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000..a9f5044
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,29 @@
+{ pkgs ? import ./nix { nixpkgs = sources."nixpkgs-21.05"; }
+, unstable ? import ./nix { nixpkgs = sources."nixpkgs-unstable"; }
+, sources ? import ./nix/sources.nix
+}:
+
+pkgs.mkShell {
+ buildInputs = with pkgs; [
+ entr
+ gnumake
+ node2nix
+ nodejs-14_x
+ poetry
+ poetry2nix.cli
+ unstable.micromamba
+ (buildFHSUserEnv {
+ name = "rcc";
+ targetPkgs = pkgs: (with pkgs; [
+ rcc
+ firefox
+ geckodriver
+ unstable.micromamba
+ ]);
+ runScript = "rcc";
+ })
+ ];
+ shellHook = ''
+ export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
+ '';
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..763c386
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "esnext",
+ "typeRoots": [
+ "./@types"
+ ],
+ "outDir": ".",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "strict": true,
+ },
+ "include": [
+ "*.ts"
+ ],
+ "exclude": []
+}
diff --git a/xkcd-bot/conda.yaml b/xkcd-bot/conda.yaml
new file mode 100644
index 0000000..ffd5f40
--- /dev/null
+++ b/xkcd-bot/conda.yaml
@@ -0,0 +1,12 @@
+channels:
+ - conda-forge
+
+dependencies:
+ # https://anaconda.org/search
+# - firefox=79.0
+# - geckodriver=0.26.0
+ - python=3.8.8
+ - pip=21.1.3
+ - pip:
+ - rpaframework==10.4.0
+ - robotframework-seleniumtestability==1.1.0
diff --git a/xkcd-bot/robot.yaml b/xkcd-bot/robot.yaml
new file mode 100644
index 0000000..12e10cf
--- /dev/null
+++ b/xkcd-bot/robot.yaml
@@ -0,0 +1,15 @@
+tasks:
+
+ Search for XKCD image:
+ robotTaskName:
+ Search for XKCD image
+
+ Download XKCD image:
+ robotTaskName:
+ Download XKCD image
+
+condaConfigFile:
+ conda.yaml
+
+artifactsDir:
+ output
diff --git a/xkcd-bot/robot.zip b/xkcd-bot/robot.zip
new file mode 100644
index 0000000..840765b
Binary files /dev/null and b/xkcd-bot/robot.zip differ
diff --git a/xkcd-bot/tasks.robot b/xkcd-bot/tasks.robot
new file mode 100644
index 0000000..6590903
--- /dev/null
+++ b/xkcd-bot/tasks.robot
@@ -0,0 +1,77 @@
+*** Settings ***
+
+Library DateTime
+Library RPA.Robocloud.Items
+Library SeleniumLibrary timeout=5s
+... plugins=SeleniumTestability;True;5s;True
+Library Collections
+Library OperatingSystem
+Library requests
+
+Suite teardown Close all browsers
+
+*** Keywords ***
+
+Run Selenium keyword and return status
+ [Documentation]
+ ... Run Selenium keyword (optionally with arguments)
+ ... and return status without screenshots on failure
+ [Arguments] ${keyword} @{arguments}
+ ${tmp}= Register keyword to run on failure No operation
+ ${status}= Run keyword and return status ${keyword} @{arguments}
+ Register keyword to run on failure ${tmp}
+ [Return] ${status}
+
+*** Tasks ***
+
+Search for XKCD image
+ Set task variables from work item
+
+ Open browser about:blank browser=headlessfirefox
+
+ Go to https://www.google.com/search?q=site%3Am.xkcd.com+${query}
+ Capture page screenshot
+
+ ${has results}= Run Selenium keyword and return status
+ ... Page should contain element
+ ... xpath://a[starts-with(@href, "https://m.xkcd.com/")]
+
+ ${count}= Get Element Count xpath://a[starts-with(@href, "https://m.xkcd.com/")]
+ ${results}= Create list
+ FOR ${index} IN RANGE ${count}
+ ${href}= Get Element Attribute
+ ... xpath:(//a[starts-with(@href, "https://m.xkcd.com/")])[${{${index} + 1}}]
+ ... href
+ IF "${href}" != "https://m.xkcd.com/archive/"
+ Append to list ${results} ${href}
+ END
+ END
+ Set work item variable results ${results}
+ Save work item
+
+ Close browser
+
+Download XKCD image
+ Set task variables from work item
+
+ Open browser about:blank browser=headlessfirefox
+ Go to ${url}
+ Capture page screenshot
+
+ ${has image}= Run Selenium keyword and return status
+ ... Page should contain element
+ ... css:#comic img
+
+ ${alt}= Get Element Attribute css:#comic img alt
+ ${title}= Get Element Attribute css:#comic img title
+ ${src}= Get Element Attribute css:#comic img src
+ Set work item variable imageUrl ${src}
+
+ ${response} Get ${src}
+ Create binary file comic.png ${response.content}
+ Add work item file comic.png
+ Set work item variable alt ${alt}
+ Set work item variable title ${title}
+ Save work item
+
+ Close browser